diff --git a/CHANGELOG.md b/CHANGELOG.md index c932688b4..9d64f38c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## 1.77.2 +* Don't emit deprecation warnings for functions and mixins beginning with `__`. + +* Allow user-defined functions whose names begin with `_` and otherwise look + like vendor-prefixed functions with special CSS syntax. + ### Command-Line Interface * Properly handle the `--silence-deprecation` flag. diff --git a/lib/src/ast/sass/expression/function.dart b/lib/src/ast/sass/expression/function.dart index 398a2ff03..64c508c19 100644 --- a/lib/src/ast/sass/expression/function.dart +++ b/lib/src/ast/sass/expression/function.dart @@ -23,6 +23,12 @@ final class FunctionExpression /// without a namespace. final String? namespace; + /// The name of the function being invoked, with underscores converted to + /// hyphens. + /// + /// If this function is a plain CSS function, use [originalName] instead. + final String name; + /// The name of the function being invoked, with underscores left as-is. final String originalName; @@ -31,12 +37,6 @@ final class FunctionExpression final FileSpan span; - /// The name of the function being invoked, with underscores converted to - /// hyphens. - /// - /// If this function is a plain CSS function, use [originalName] instead. - String get name => originalName.replaceAll('_', '-'); - FileSpan get nameSpan { if (namespace == null) return span.initialIdentifier(); return span.withoutNamespace().initialIdentifier(); @@ -46,7 +46,8 @@ final class FunctionExpression namespace == null ? null : span.initialIdentifier(); FunctionExpression(this.originalName, this.arguments, this.span, - {this.namespace}); + {this.namespace}) + : name = originalName.replaceAll('_', '-'); T accept(ExpressionVisitor visitor) => visitor.visitFunctionExpression(this); diff --git a/lib/src/ast/sass/statement/callable_declaration.dart b/lib/src/ast/sass/statement/callable_declaration.dart index e39b9c035..3ce0ec9a0 100644 --- a/lib/src/ast/sass/statement/callable_declaration.dart +++ b/lib/src/ast/sass/statement/callable_declaration.dart @@ -18,6 +18,9 @@ abstract base class CallableDeclaration /// The name of this callable, with underscores converted to hyphens. final String name; + /// The callable's original name, without underscores converted to hyphens. + final String originalName; + /// The comment immediately preceding this declaration. final SilentComment? comment; @@ -26,8 +29,9 @@ abstract base class CallableDeclaration final FileSpan span; - CallableDeclaration( - this.name, this.arguments, Iterable children, this.span, + CallableDeclaration(this.originalName, this.arguments, + Iterable children, this.span, {this.comment}) - : super(List.unmodifiable(children)); + : name = originalName.replaceAll('_', '-'), + super(List.unmodifiable(children)); } diff --git a/lib/src/ast/sass/statement/include_rule.dart b/lib/src/ast/sass/statement/include_rule.dart index d3c9ceba6..940716cac 100644 --- a/lib/src/ast/sass/statement/include_rule.dart +++ b/lib/src/ast/sass/statement/include_rule.dart @@ -25,6 +25,10 @@ final class IncludeRule /// hyphens. final String name; + /// The original name of the mixin being invoked, without underscores + /// converted to hyphens. + final String originalName; + /// The arguments to pass to the mixin. final ArgumentInvocation arguments; @@ -55,8 +59,9 @@ final class IncludeRule return startSpan.initialIdentifier(); } - IncludeRule(this.name, this.arguments, this.span, - {this.namespace, this.content}); + IncludeRule(this.originalName, this.arguments, this.span, + {this.namespace, this.content}) + : name = originalName.replaceAll('_', '-'); T accept(StatementVisitor visitor) => visitor.visitIncludeRule(this); diff --git a/lib/src/parse/stylesheet.dart b/lib/src/parse/stylesheet.dart index fb1f1b614..e72e2527b 100644 --- a/lib/src/parse/stylesheet.dart +++ b/lib/src/parse/stylesheet.dart @@ -847,7 +847,7 @@ abstract class StylesheetParser extends Parser { var precedingComment = lastSilentComment; lastSilentComment = null; var beforeName = scanner.state; - var name = identifier(normalize: true); + var name = identifier(); if (name.startsWith('--')) { logger.warnForDeprecation( @@ -1221,8 +1221,6 @@ abstract class StylesheetParser extends Parser { if (scanner.scanChar($dot)) { namespace = name; name = _publicIdentifier(); - } else { - name = name.replaceAll("_", "-"); } whitespace(); @@ -1274,7 +1272,7 @@ abstract class StylesheetParser extends Parser { var precedingComment = lastSilentComment; lastSilentComment = null; var beforeName = scanner.state; - var name = identifier(normalize: true); + var name = identifier(); if (name.startsWith('--')) { logger.warnForDeprecation( @@ -3457,7 +3455,7 @@ abstract class StylesheetParser extends Parser { /// Like [identifier], but rejects identifiers that begin with `_` or `-`. String _publicIdentifier() { var start = scanner.state; - var result = identifier(normalize: true); + var result = identifier(); _assertPublic(result, () => scanner.spanFrom(start)); return result; } diff --git a/lib/src/visitor/async_evaluate.dart b/lib/src/visitor/async_evaluate.dart index b564b8323..b8434ff47 100644 --- a/lib/src/visitor/async_evaluate.dart +++ b/lib/src/visitor/async_evaluate.dart @@ -1853,6 +1853,18 @@ final class _EvaluateVisitor Future visitIncludeRule(IncludeRule node) async { var mixin = _addExceptionSpan(node, () => _environment.getMixin(node.name, namespace: node.namespace)); + if (node.originalName.startsWith('--') && + mixin is UserDefinedCallable && + !mixin.declaration.originalName.startsWith('--')) { + _warn( + 'Sass @mixin names beginning with -- are deprecated for forward-' + 'compatibility with plain CSS mixins.\n' + '\n' + 'For details, see https://sass-lang.com/d/css-function-mixin', + node.nameSpan, + Deprecation.cssFunctionMixin); + } + var contentCallable = node.content.andThen((content) => UserDefinedCallable( content, _environment.closure(), inDependency: _inDependency)); @@ -2510,6 +2522,19 @@ final class _EvaluateVisitor PlainCssCallable(node.originalName); } + if (node.originalName.startsWith('--') && + function is UserDefinedCallable && + !function.declaration.originalName.startsWith('--')) { + _warn( + 'Sass @function names beginning with -- are deprecated for forward-' + 'compatibility with plain CSS functions.\n' + '\n' + 'For details, see https://sass-lang.com/d/css-function-mixin', + node.nameSpan, + Deprecation.cssFunctionMixin, + ); + } + var oldInFunction = _inFunction; _inFunction = true; var result = await _addErrorSpan( diff --git a/lib/src/visitor/evaluate.dart b/lib/src/visitor/evaluate.dart index 473728c1c..1680be88e 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: 7788c21fd8c721992490ac01d0ef4783dddf3f1f +// Checksum: 116b8079719577ac6e4dad4aebe403282136e611 // // ignore_for_file: unused_import @@ -1845,6 +1845,18 @@ final class _EvaluateVisitor Value? visitIncludeRule(IncludeRule node) { var mixin = _addExceptionSpan(node, () => _environment.getMixin(node.name, namespace: node.namespace)); + if (node.originalName.startsWith('--') && + mixin is UserDefinedCallable && + !mixin.declaration.originalName.startsWith('--')) { + _warn( + 'Sass @mixin names beginning with -- are deprecated for forward-' + 'compatibility with plain CSS mixins.\n' + '\n' + 'For details, see https://sass-lang.com/d/css-function-mixin', + node.nameSpan, + Deprecation.cssFunctionMixin); + } + var contentCallable = node.content.andThen((content) => UserDefinedCallable( content, _environment.closure(), inDependency: _inDependency)); @@ -2486,6 +2498,19 @@ final class _EvaluateVisitor PlainCssCallable(node.originalName); } + if (node.originalName.startsWith('--') && + function is UserDefinedCallable && + !function.declaration.originalName.startsWith('--')) { + _warn( + 'Sass @function names beginning with -- are deprecated for forward-' + 'compatibility with plain CSS functions.\n' + '\n' + 'For details, see https://sass-lang.com/d/css-function-mixin', + node.nameSpan, + Deprecation.cssFunctionMixin, + ); + } + var oldInFunction = _inFunction; _inFunction = true; var result = _addErrorSpan(