diff --git a/.travis.yml b/.travis.yml index 1a91e2e19..9d3976022 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,11 +35,16 @@ jobs: - &specs name: sass-spec | Dart stable | synchronous language: ruby + # Work around an issue where bundler isn't installed correctly on Ruby 2.5. + # We should remove this, and the explicit "gem install bundler" line, once + # Travis uses Ruby 2.6 by default. + rvm: 2.6 install: - export sass_spec_ref=`tool/travis/sass-spec-ref.sh` - git init sass-spec - git -C sass-spec fetch git://github.com/sass/sass-spec "$sass_spec_ref" --depth 1 - git -C sass-spec checkout FETCH_HEAD + - gem install bundler - bundle install --gemfile=sass-spec/Gemfile --jobs=3 --retry=3 script: tool/travis/task/specs.sh - <<: *specs @@ -77,6 +82,9 @@ jobs: node_js: stable install: pub run grinder before-test script: tool/travis/task/node_tests.sh + - <<: *node-tests + name: Node tests | Dart stable | Node Carbon + node_js: lts/carbon - <<: *node-tests name: Node tests | Dart stable | Node Dubnium node_js: lts/dubnium @@ -218,6 +226,7 @@ jobs: if: *deploy-if env: *github-env script: skip + os: osx deploy: provider: script script: pub run grinder github-mac-os diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d4112387..ae5181a66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## 1.22.11 + +* Don't try to load unquoted plain-CSS indented-syntax imports. + +* Fix a couple edge cases in `@extend` logic and related selector functions: + + * Recognize `:matches()` and similar pseudo-selectors as superselectors of + matching complex selectors. + + * Recognize `::slotted()` as a superselector of other `::slotted()` selectors. + + * Regonize `:current()` with a vendor prefix as a superselector. + +## 1.22.10 + +* Fix a bug in which `get-function()` would fail to find a dash-separated + function when passed a function name with underscores. + ## 1.22.9 * Include argument names when reporting range errors and selector parse errors. @@ -7,6 +25,10 @@ * Clarify the error message when the wrong number of positional arguments are passed along with a named argument. +### JavaScript API + +* Re-add support for Node Carbon (8.x). + ## 1.22.8 ### JavaScript API diff --git a/lib/src/extend/functions.dart b/lib/src/extend/functions.dart index 0e222178e..c9a0fb217 100644 --- a/lib/src/extend/functions.dart +++ b/lib/src/extend/functions.dart @@ -598,7 +598,7 @@ bool complexIsSuperselector(List complex1, if (remaining1 == 1) { return compoundIsSuperselector( compound1, complex2.last as CompoundSelector, - parents: complex2.skip(i2 + 1)); + parents: complex2.take(complex2.length - 1).skip(i2)); } // Find the first index where `complex2.sublist(i2, afterSuperselector)` is @@ -673,11 +673,12 @@ bool compoundIsSuperselector( } } - // [compound1] can't be a superselector of a selector with pseudo-elements - // that [compound2] doesn't share. + // [compound1] can't be a superselector of a selector with non-selector + // pseudo-elements that [compound2] doesn't share. for (var simple2 in compound2.components) { if (simple2 is PseudoSelector && simple2.isElement && + simple2.selector == null && !_simpleIsSuperselectorOfCompound(simple2, compound1)) { return false; } @@ -736,10 +737,13 @@ bool _selectorPseudoIsSuperselector( case 'has': case 'host': case 'host-context': - case 'slotted': return _selectorPseudosNamed(compound2, pseudo1.name) .any((pseudo2) => pseudo1.selector.isSuperselector(pseudo2.selector)); + case 'slotted': + return _selectorPseudosNamed(compound2, pseudo1.name, isClass: false) + .any((pseudo2) => pseudo1.selector.isSuperselector(pseudo2.selector)); + case 'not': return pseudo1.selector.components.every((complex) { return compound2.components.any((simple2) { @@ -764,7 +768,7 @@ bool _selectorPseudoIsSuperselector( }); case 'current': - return _selectorPseudosNamed(compound2, 'current') + return _selectorPseudosNamed(compound2, pseudo1.name) .any((pseudo2) => pseudo1.selector == pseudo2.selector); case 'nth-child': @@ -783,6 +787,8 @@ bool _selectorPseudoIsSuperselector( /// Returns all pseudo selectors in [compound] that have a selector argument, /// and that have the given [name]. Iterable _selectorPseudosNamed( - CompoundSelector compound, String name) => + CompoundSelector compound, String name, {bool isClass = true}) => compound.components.whereType().where((pseudo) => - pseudo.isClass && pseudo.selector != null && pseudo.name == name); + pseudo.isClass == isClass && + pseudo.selector != null && + pseudo.name == name); diff --git a/lib/src/parse/sass.dart b/lib/src/parse/sass.dart index 8bc81ce2c..bd2b89f4d 100644 --- a/lib/src/parse/sass.dart +++ b/lib/src/parse/sass.dart @@ -9,6 +9,7 @@ import '../ast/sass.dart'; import '../interpolation_buffer.dart'; import '../logger.dart'; import '../util/character.dart'; +import '../value.dart'; import 'stylesheet.dart'; /// A parser for the indented syntax. @@ -98,9 +99,21 @@ class SassParser extends StylesheetParser { scanner.readChar(); next = scanner.peekChar(); } - - return DynamicImport(parseImportUrl(scanner.substring(start.position)), - scanner.spanFrom(start)); + var url = scanner.substring(start.position); + var span = scanner.spanFrom(start); + + if (isPlainImportUrl(url)) { + // Serialize [url] as a Sass string because [StaticImport] expects it to + // include quotes. + return StaticImport( + Interpolation([SassString(url).toString()], span), span); + } else { + try { + return DynamicImport(parseImportUrl(url), span); + } on FormatException catch (innerError) { + error("Invalid URL: ${innerError.message}", span); + } + } } bool scanElse(int ifIndentation) { diff --git a/lib/src/parse/stylesheet.dart b/lib/src/parse/stylesheet.dart index e27cbbe45..0444143a6 100644 --- a/lib/src/parse/stylesheet.dart +++ b/lib/src/parse/stylesheet.dart @@ -1091,7 +1091,7 @@ abstract class StylesheetParser extends Parser { var urlSpan = scanner.spanFrom(start); whitespace(); var queries = tryImportQueries(); - if (_isPlainImportUrl(url) || queries != null) { + if (isPlainImportUrl(url) || queries != null) { return StaticImport( Interpolation([urlSpan.text], urlSpan), scanner.spanFrom(start), supports: queries?.item1, media: queries?.item2); @@ -1117,7 +1117,8 @@ abstract class StylesheetParser extends Parser { } /// Returns whether [url] indicates that an `@import` is a plain CSS import. - bool _isPlainImportUrl(String url) { + @protected + bool isPlainImportUrl(String url) { if (url.length < 5) return false; if (url.endsWith(".css")) return true; diff --git a/lib/src/visitor/async_evaluate.dart b/lib/src/visitor/async_evaluate.dart index f958e691b..594d3dc45 100644 --- a/lib/src/visitor/async_evaluate.dart +++ b/lib/src/visitor/async_evaluate.dart @@ -354,8 +354,10 @@ class _EvaluateVisitor var callable = css ? PlainCssCallable(name.text) - : _addExceptionSpan(_callableNode, - () => _getFunction(name.text, namespace: module?.text)); + : _addExceptionSpan( + _callableNode, + () => _getFunction(name.text.replaceAll("_", "-"), + namespace: module?.text)); if (callable != null) return SassFunction(callable); throw "Function not found: $name"; diff --git a/lib/src/visitor/evaluate.dart b/lib/src/visitor/evaluate.dart index 8c8652267..b38158188 100644 --- a/lib/src/visitor/evaluate.dart +++ b/lib/src/visitor/evaluate.dart @@ -5,7 +5,7 @@ // DO NOT EDIT. This file was generated from async_evaluate.dart. // See tool/grind/synchronize.dart for details. // -// Checksum: c802b1e7bc9ad79b81112445c94d43a514741b8c +// Checksum: 5c9f270ef574f9c6062421ed1866af3d07672b46 // // ignore_for_file: unused_import @@ -362,8 +362,10 @@ class _EvaluateVisitor var callable = css ? PlainCssCallable(name.text) - : _addExceptionSpan(_callableNode, - () => _getFunction(name.text, namespace: module?.text)); + : _addExceptionSpan( + _callableNode, + () => _getFunction(name.text.replaceAll("_", "-"), + namespace: module?.text)); if (callable != null) return SassFunction(callable); throw "Function not found: $name"; diff --git a/package/package.json b/package/package.json index f6f8fb0dd..0231c3f62 100644 --- a/package/package.json +++ b/package/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/nex3" }, "engines": { - "node": ">=10.0.0" + "node": ">=8.9.0" }, "dependencies": { "chokidar": ">=2.0.0 <4.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index c53ff476d..5053af775 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: sass -version: 1.22.9-dev +version: 1.22.11 description: A Sass implementation in Dart. -author: Dart Team +author: Sass Team homepage: https://github.com/sass/dart-sass executables: