diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c1bc6a70..147f4bcec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 1.79.0 + +* Add a `global-builtin` future deprecation, which can be opted-into with the + `--future-deprecation` flag or the `futureDeprecations` option in the JS or + Dart API. This emits warnings when any global built-in functions that are + now available in `sass:` modules are called. It will become active by default + in an upcoming release alongside the `@import` deprecation. + ## 1.78.0 * The `meta.feature-exists` function is now deprecated. This deprecation is diff --git a/lib/src/callable.dart b/lib/src/callable.dart index 2d2ed1e26..1fda63247 100644 --- a/lib/src/callable.dart +++ b/lib/src/callable.dart @@ -11,7 +11,8 @@ import 'utils.dart'; import 'value.dart'; export 'callable/async.dart'; -export 'callable/async_built_in.dart' show AsyncBuiltInCallable; +export 'callable/async_built_in.dart' + show AsyncBuiltInCallable, warnForGlobalBuiltIn; export 'callable/built_in.dart' show BuiltInCallable; export 'callable/plain_css.dart'; export 'callable/user_defined.dart'; diff --git a/lib/src/callable/async_built_in.dart b/lib/src/callable/async_built_in.dart index 7dba7e1cd..2c764ee0c 100644 --- a/lib/src/callable/async_built_in.dart +++ b/lib/src/callable/async_built_in.dart @@ -5,6 +5,8 @@ import 'dart:async'; import '../ast/sass.dart'; +import '../deprecation.dart'; +import '../evaluation_context.dart'; import '../value.dart'; import 'async.dart'; @@ -83,4 +85,22 @@ class AsyncBuiltInCallable implements AsyncCallable { (ArgumentDeclaration, Callback) callbackFor( int positional, Set names) => (_arguments, _callback); + + /// Returns a copy of this callable that emits a deprecation warning. + AsyncBuiltInCallable withDeprecationWarning(String module, + [String? newName]) => + AsyncBuiltInCallable.parsed(name, _arguments, (args) { + warnForGlobalBuiltIn(module, newName ?? name); + return _callback(args); + }, acceptsContent: acceptsContent); +} + +/// Emits a deprecation warning for a global built-in function that is now +/// available as function [name] in built-in module [module]. +void warnForGlobalBuiltIn(String module, String name) { + warnForDeprecation( + 'Global built-in functions will be deprecated in the future.\n' + 'Remove the --future-deprecation=global-builtin flag to silence this ' + 'warning for now.', + Deprecation.globalBuiltin); } diff --git a/lib/src/callable/built_in.dart b/lib/src/callable/built_in.dart index a52662fa0..1d58df9fe 100644 --- a/lib/src/callable/built_in.dart +++ b/lib/src/callable/built_in.dart @@ -123,4 +123,20 @@ final class BuiltInCallable implements Callable, AsyncBuiltInCallable { /// Returns a copy of this callable with the given [name]. BuiltInCallable withName(String name) => BuiltInCallable._(name, _overloads, acceptsContent); + + /// Returns a copy of this callable that emits a deprecation warning. + BuiltInCallable withDeprecationWarning(String module, [String? newName]) => + BuiltInCallable._( + name, + [ + for (var (declaration, function) in _overloads) + ( + declaration, + (args) { + warnForGlobalBuiltIn(module, newName ?? name); + return function(args); + } + ) + ], + acceptsContent); } diff --git a/lib/src/deprecation.dart b/lib/src/deprecation.dart index 77891a13f..b1626db5a 100644 --- a/lib/src/deprecation.dart +++ b/lib/src/deprecation.dart @@ -15,7 +15,7 @@ enum Deprecation { // DO NOT EDIT. This section was generated from the language repo. // See tool/grind/generate_deprecations.dart for details. // - // Checksum: dd5c6aa0f1431fa9fc88bb71a96f832adbc165f5 + // Checksum: bf841a728263bf7efc2a85a091330a1f8074e067 /// Deprecation for passing a string directly to meta.call(). callString('call-string', @@ -102,6 +102,11 @@ enum Deprecation { /// Deprecation for @import rules. import.future('import', description: '@import rules.'), + /// Deprecation for global built-in functions that are available in sass: modules. + globalBuiltin.future('global-builtin', + description: + 'Global built-in functions that are available in sass: modules.'), + // END AUTOGENERATED CODE /// Used for deprecations coming from user-authored code. diff --git a/lib/src/functions/color.dart b/lib/src/functions/color.dart index f71c8080f..f3d05fdac 100644 --- a/lib/src/functions/color.dart +++ b/lib/src/functions/color.dart @@ -23,7 +23,8 @@ final _microsoftFilterStart = RegExp(r'^[a-zA-Z]+\s*='); /// The global definitions of Sass color functions. final global = UnmodifiableListView([ // ### RGB - _red, _green, _blue, _mix, + _red.withDeprecationWarning('color'), _green.withDeprecationWarning('color'), + _blue.withDeprecationWarning('color'), _mix.withDeprecationWarning('color'), BuiltInCallable.overloadedFunction("rgb", { r"$red, $green, $blue, $alpha": (arguments) => _rgb("rgb", arguments), @@ -66,10 +67,13 @@ final global = UnmodifiableListView([ red: 255 - color.red, green: 255 - color.green, blue: 255 - color.blue); return _mixColors(inverse, color, weight); - }), + }).withDeprecationWarning('color'), // ### HSL - _hue, _saturation, _lightness, _complement, + _hue.withDeprecationWarning('color'), + _saturation.withDeprecationWarning('color'), + _lightness.withDeprecationWarning('color'), + _complement.withDeprecationWarning('color'), BuiltInCallable.overloadedFunction("hsl", { r"$hue, $saturation, $lightness, $alpha": (arguments) => @@ -116,7 +120,7 @@ final global = UnmodifiableListView([ // Use the native CSS `grayscale` filter function. return _functionString('grayscale', arguments); } - + warnForGlobalBuiltIn('color', 'grayscale'); var color = arguments[0].assertColor("color"); return color.changeHsl(saturation: 0); }), @@ -125,7 +129,7 @@ final global = UnmodifiableListView([ var color = arguments[0].assertColor("color"); var degrees = _angleValue(arguments[1], "degrees"); return color.changeHsl(hue: color.hue + degrees); - }), + }).withDeprecationWarning('color', 'adjust'), _function("lighten", r"$color, $amount", (arguments) { var color = arguments[0].assertColor("color"); @@ -133,7 +137,7 @@ final global = UnmodifiableListView([ return color.changeHsl( lightness: (color.lightness + amount.valueInRange(0, 100, "amount")) .clamp(0, 100)); - }), + }).withDeprecationWarning('color', 'adjust'), _function("darken", r"$color, $amount", (arguments) { var color = arguments[0].assertColor("color"); @@ -141,7 +145,7 @@ final global = UnmodifiableListView([ return color.changeHsl( lightness: (color.lightness - amount.valueInRange(0, 100, "amount")) .clamp(0, 100)); - }), + }).withDeprecationWarning('color', 'adjust'), BuiltInCallable.overloadedFunction("saturate", { r"$amount": (arguments) { @@ -153,6 +157,7 @@ final global = UnmodifiableListView([ return SassString("saturate(${number.toCssString()})", quotes: false); }, r"$color, $amount": (arguments) { + warnForGlobalBuiltIn('color', 'adjust'); var color = arguments[0].assertColor("color"); var amount = arguments[1].assertNumber("amount"); return color.changeHsl( @@ -167,13 +172,17 @@ final global = UnmodifiableListView([ return color.changeHsl( saturation: (color.saturation - amount.valueInRange(0, 100, "amount")) .clamp(0, 100)); - }), + }).withDeprecationWarning('color', 'adjust'), // ### Opacity - _function("opacify", r"$color, $amount", _opacify), - _function("fade-in", r"$color, $amount", _opacify), - _function("transparentize", r"$color, $amount", _transparentize), - _function("fade-out", r"$color, $amount", _transparentize), + _function("opacify", r"$color, $amount", _opacify) + .withDeprecationWarning('color', 'adjust'), + _function("fade-in", r"$color, $amount", _opacify) + .withDeprecationWarning('color', 'adjust'), + _function("transparentize", r"$color, $amount", _transparentize) + .withDeprecationWarning('color', 'adjust'), + _function("fade-out", r"$color, $amount", _transparentize) + .withDeprecationWarning('color', 'adjust'), BuiltInCallable.overloadedFunction("alpha", { r"$color": (arguments) { @@ -185,6 +194,7 @@ final global = UnmodifiableListView([ return _functionString("alpha", arguments); } + warnForGlobalBuiltIn('color', 'alpha'); var color = argument.assertColor("color"); return SassNumber(color.alpha); }, @@ -215,15 +225,16 @@ final global = UnmodifiableListView([ return _functionString("opacity", arguments); } + warnForGlobalBuiltIn('color', 'opacity'); var color = arguments[0].assertColor("color"); return SassNumber(color.alpha); }), // ### Miscellaneous _ieHexStr, - _adjust.withName("adjust-color"), - _scale.withName("scale-color"), - _change.withName("change-color") + _adjust.withDeprecationWarning('color').withName("adjust-color"), + _scale.withDeprecationWarning('color').withName("scale-color"), + _change.withDeprecationWarning('color').withName("change-color") ]); /// The Sass color module. diff --git a/lib/src/functions/list.dart b/lib/src/functions/list.dart index 1d911a88d..c0fd0ac2c 100644 --- a/lib/src/functions/list.dart +++ b/lib/src/functions/list.dart @@ -13,8 +13,15 @@ import '../value.dart'; /// The global definitions of Sass list functions. final global = UnmodifiableListView([ - _length, _nth, _setNth, _join, _append, _zip, _index, _isBracketed, // - _separator.withName("list-separator") + _length.withDeprecationWarning('list'), + _nth.withDeprecationWarning('list'), + _setNth.withDeprecationWarning('list'), + _join.withDeprecationWarning('list'), + _append.withDeprecationWarning('list'), + _zip.withDeprecationWarning('list'), + _index.withDeprecationWarning('list'), + _isBracketed.withDeprecationWarning('list'), + _separator.withDeprecationWarning('list').withName("list-separator") ]); /// The Sass list module. diff --git a/lib/src/functions/map.dart b/lib/src/functions/map.dart index 123c75d68..099f20a72 100644 --- a/lib/src/functions/map.dart +++ b/lib/src/functions/map.dart @@ -15,12 +15,12 @@ import '../value.dart'; /// The global definitions of Sass map functions. final global = UnmodifiableListView([ - _get.withName("map-get"), - _merge.withName("map-merge"), - _remove.withName("map-remove"), - _keys.withName("map-keys"), - _values.withName("map-values"), - _hasKey.withName("map-has-key") + _get.withDeprecationWarning('map').withName("map-get"), + _merge.withDeprecationWarning('map').withName("map-merge"), + _remove.withDeprecationWarning('map').withName("map-remove"), + _keys.withDeprecationWarning('map').withName("map-keys"), + _values.withDeprecationWarning('map').withName("map-values"), + _hasKey.withDeprecationWarning('map').withName("map-has-key") ]); /// The Sass map module. diff --git a/lib/src/functions/math.dart b/lib/src/functions/math.dart index bca609d0d..3f3e3bbbe 100644 --- a/lib/src/functions/math.dart +++ b/lib/src/functions/math.dart @@ -30,15 +30,23 @@ final global = UnmodifiableListView([ "To emit a CSS abs() now: abs(#{$number})\n" "More info: https://sass-lang.com/d/abs-percent", Deprecation.absPercent); + } else { + warnForGlobalBuiltIn('math', 'abs'); } return SassNumber.withUnits(number.value.abs(), numeratorUnits: number.numeratorUnits, denominatorUnits: number.denominatorUnits); }), - - _ceil, _floor, _max, _min, _percentage, _randomFunction, _round, _unit, // - _compatible.withName("comparable"), - _isUnitless.withName("unitless"), + _ceil.withDeprecationWarning('math'), + _floor.withDeprecationWarning('math'), + _max.withDeprecationWarning('math'), + _min.withDeprecationWarning('math'), + _percentage.withDeprecationWarning('math'), + _randomFunction.withDeprecationWarning('math'), + _round.withDeprecationWarning('math'), + _unit.withDeprecationWarning('math'), + _compatible.withDeprecationWarning('math').withName("comparable"), + _isUnitless.withDeprecationWarning('math').withName("unitless"), ]); /// The Sass math module. diff --git a/lib/src/functions/meta.dart b/lib/src/functions/meta.dart index f88dce83e..1f0a473b6 100644 --- a/lib/src/functions/meta.dart +++ b/lib/src/functions/meta.dart @@ -22,8 +22,12 @@ final _features = { "custom-property" }; -/// The global definitions of Sass introspection functions. -final global = UnmodifiableListView([ +/// Sass introspection functions that exist as both global functions and in the +/// `sass:meta` module that do not require access to context that's only +/// available at runtime. +/// +/// Additional functions are defined in the evaluator. +final _shared = UnmodifiableListView([ // This is only a partial list of meta functions. The rest are defined in the // evaluator, because they need access to context that's only available at // runtime. @@ -35,10 +39,8 @@ final global = UnmodifiableListView([ var feature = arguments[0].assertString("feature"); return SassBoolean(_features.contains(feature.text)); }), - _function("inspect", r"$value", (arguments) => SassString(arguments.first.toString(), quotes: false)), - _function( "type-of", r"$value", @@ -58,7 +60,6 @@ final global = UnmodifiableListView([ _ => throw "[BUG] Unknown value type ${arguments[0]}" }, quotes: false)), - _function("keywords", r"$args", (arguments) { if (arguments[0] case SassArgumentList(:var keywords)) { return SassMap({ @@ -71,9 +72,14 @@ final global = UnmodifiableListView([ }) ]); -/// The definitions of Sass introspection functions that are only available from -/// the `sass:meta` module, not as global functions. -final local = UnmodifiableListView([ +/// The global definitions of Sass introspection functions. +final global = UnmodifiableListView( + [for (var function in _shared) function.withDeprecationWarning('meta')]); + +/// The versions of Sass introspection functions defined in the `sass:meta` +/// module. +final moduleFunctions = UnmodifiableListView([ + ..._shared, _function("calc-name", r"$calc", (arguments) { var calculation = arguments[0].assertCalculation("calc"); return SassString(calculation.name); diff --git a/lib/src/functions/selector.dart b/lib/src/functions/selector.dart index 08e133dbf..7a32af1a2 100644 --- a/lib/src/functions/selector.dart +++ b/lib/src/functions/selector.dart @@ -16,14 +16,14 @@ import '../value.dart'; /// The global definitions of Sass selector functions. final global = UnmodifiableListView([ - _isSuperselector, - _simpleSelectors, - _parse.withName("selector-parse"), - _nest.withName("selector-nest"), - _append.withName("selector-append"), - _extend.withName("selector-extend"), - _replace.withName("selector-replace"), - _unify.withName("selector-unify") + _isSuperselector.withDeprecationWarning('selector'), + _simpleSelectors.withDeprecationWarning('selector'), + _parse.withDeprecationWarning('selector').withName("selector-parse"), + _nest.withDeprecationWarning('selector').withName("selector-nest"), + _append.withDeprecationWarning('selector').withName("selector-append"), + _extend.withDeprecationWarning('selector').withName("selector-extend"), + _replace.withDeprecationWarning('selector').withName("selector-replace"), + _unify.withDeprecationWarning('selector').withName("selector-unify") ]); /// The Sass selector module. diff --git a/lib/src/functions/string.dart b/lib/src/functions/string.dart index 99d1ee6d2..100337de9 100644 --- a/lib/src/functions/string.dart +++ b/lib/src/functions/string.dart @@ -22,11 +22,15 @@ var _previousUniqueId = _random.nextInt(math.pow(36, 6) as int); /// The global definitions of Sass string functions. final global = UnmodifiableListView([ - _unquote, _quote, _toUpperCase, _toLowerCase, _uniqueId, // - _length.withName("str-length"), - _insert.withName("str-insert"), - _index.withName("str-index"), - _slice.withName("str-slice") + _unquote.withDeprecationWarning('string'), + _quote.withDeprecationWarning('string'), + _toUpperCase.withDeprecationWarning('string'), + _toLowerCase.withDeprecationWarning('string'), + _uniqueId.withDeprecationWarning('string'), + _length.withDeprecationWarning('string').withName("str-length"), + _insert.withDeprecationWarning('string').withName("str-insert"), + _index.withDeprecationWarning('string').withName("str-index"), + _slice.withDeprecationWarning('string').withName("str-slice") ]); /// The Sass string module. diff --git a/lib/src/visitor/async_evaluate.dart b/lib/src/visitor/async_evaluate.dart index 1c838b8ac..5a2b5901a 100644 --- a/lib/src/visitor/async_evaluate.dart +++ b/lib/src/visitor/async_evaluate.dart @@ -575,14 +575,21 @@ final class _EvaluateVisitor ]; var metaModule = BuiltInModule("meta", - functions: [...meta.global, ...meta.local, ...metaFunctions], + functions: [...meta.moduleFunctions, ...metaFunctions], mixins: metaMixins); for (var module in [...coreModules, metaModule]) { _builtInModules[module.url] = module; } - functions = [...?functions, ...globalFunctions, ...metaFunctions]; + functions = [ + ...?functions, + ...globalFunctions, + ...[ + for (var function in metaFunctions) + function.withDeprecationWarning('meta') + ] + ]; for (var function in functions) { _builtInFunctions[function.name.replaceAll("_", "-")] = function; } diff --git a/lib/src/visitor/evaluate.dart b/lib/src/visitor/evaluate.dart index e3552506c..505e91ab5 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: 2ab69d23a3b34cb54ddd74e2e854614dda582174 +// Checksum: 548c4265a8e0aecca7a24fd52561ef17f29f34d2 // // ignore_for_file: unused_import @@ -577,14 +577,21 @@ final class _EvaluateVisitor ]; var metaModule = BuiltInModule("meta", - functions: [...meta.global, ...meta.local, ...metaFunctions], + functions: [...meta.moduleFunctions, ...metaFunctions], mixins: metaMixins); for (var module in [...coreModules, metaModule]) { _builtInModules[module.url] = module; } - functions = [...?functions, ...globalFunctions, ...metaFunctions]; + functions = [ + ...?functions, + ...globalFunctions, + ...[ + for (var function in metaFunctions) + function.withDeprecationWarning('meta') + ] + ]; for (var function in functions) { _builtInFunctions[function.name.replaceAll("_", "-")] = function; } diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index 4ce4a1375..1b46987a4 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,10 +1,12 @@ -## 11.0.0 - -* Remove the `CallableDeclaration()` constructor. +## 11.1.0 * Loud comments in the Sass syntax no longer automatically inject ` */` to the end when parsed. +## 11.0.0 + +* Remove the `CallableDeclaration()` constructor. + ## 10.4.8 * No user-visible changes. diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index a8af9ed63..9e0c5d977 100644 --- a/pkg/sass_api/pubspec.yaml +++ b/pkg/sass_api/pubspec.yaml @@ -2,7 +2,7 @@ name: sass_api # Note: Every time we add a new Sass AST node, we need to bump the *major* # version because it's a breaking change for anyone who's implementing the # visitor interface(s). -version: 11.0.0 +version: 11.1.0 description: Additional APIs for Dart Sass. homepage: https://github.com/sass/dart-sass @@ -10,7 +10,7 @@ environment: sdk: ">=3.0.0 <4.0.0" dependencies: - sass: 1.78.0 + sass: 1.79.0 dev_dependencies: dartdoc: ^8.0.14 diff --git a/pubspec.yaml b/pubspec.yaml index 5d30c25c6..44853687b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.78.0 +version: 1.79.0-dev description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass