From 92d899acdce8af9b83f5b58c2334aedc199c8d60 Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Fri, 23 Feb 2024 21:07:43 +0000 Subject: [PATCH 01/10] wip merged into main --- bin/sass.dart | 1 + lib/sass.dart | 12 ++++- lib/src/async_compile.dart | 4 ++ lib/src/compile.dart | 6 ++- lib/src/deprecation.dart | 14 ++++++ lib/src/exception.dart | 7 +++ lib/src/executable/options.dart | 22 ++++++--- lib/src/js.dart | 4 ++ lib/src/js/deprecations.dart | 61 ++++++++++++++++++++++++ lib/src/js/exports.dart | 1 + lib/src/logger/deprecation_handling.dart | 45 ++++++++++++++++- 11 files changed, 166 insertions(+), 11 deletions(-) create mode 100644 lib/src/js/deprecations.dart diff --git a/bin/sass.dart b/bin/sass.dart index 67b1782ed..046286f33 100644 --- a/bin/sass.dart +++ b/bin/sass.dart @@ -53,6 +53,7 @@ Future main(List args) async { // each compilation, which will limit repetition if verbose is not // passed in addition to handling fatal/future deprecations. logger: DeprecationHandlingLogger(options.logger, + silenceDeprecations: options.silenceDeprecations, fatalDeprecations: options.fatalDeprecations, futureDeprecations: options.futureDeprecations, limitRepetition: false))); diff --git a/lib/sass.dart b/lib/sass.dart index dc94a90fd..eb58adc4f 100644 --- a/lib/sass.dart +++ b/lib/sass.dart @@ -108,6 +108,7 @@ CompileResult compileToResult(String path, bool verbose = false, bool sourceMap = false, bool charset = true, + Iterable? silenceDeprecations, Iterable? fatalDeprecations, Iterable? futureDeprecations}) => c.compile(path, @@ -123,6 +124,7 @@ CompileResult compileToResult(String path, verbose: verbose, sourceMap: sourceMap, charset: charset, + silenceDeprecations: silenceDeprecations, fatalDeprecations: fatalDeprecations, futureDeprecations: futureDeprecations); @@ -207,6 +209,7 @@ CompileResult compileStringToResult(String source, bool verbose = false, bool sourceMap = false, bool charset = true, + Iterable? silenceDeprecations, Iterable? fatalDeprecations, Iterable? futureDeprecations}) => c.compileString(source, @@ -225,6 +228,7 @@ CompileResult compileStringToResult(String source, verbose: verbose, sourceMap: sourceMap, charset: charset, + silenceDeprecations: silenceDeprecations, fatalDeprecations: fatalDeprecations, futureDeprecations: futureDeprecations); @@ -245,6 +249,7 @@ Future compileToResultAsync(String path, bool verbose = false, bool sourceMap = false, bool charset = true, + Iterable? silenceDeprecations, Iterable? fatalDeprecations, Iterable? futureDeprecations}) => c.compileAsync(path, @@ -260,6 +265,7 @@ Future compileToResultAsync(String path, verbose: verbose, sourceMap: sourceMap, charset: charset, + silenceDeprecations: silenceDeprecations, fatalDeprecations: fatalDeprecations, futureDeprecations: futureDeprecations); @@ -285,6 +291,7 @@ Future compileStringToResultAsync(String source, bool verbose = false, bool sourceMap = false, bool charset = true, + Iterable? silenceDeprecations, Iterable? fatalDeprecations, Iterable? futureDeprecations}) => c.compileStringAsync(source, @@ -302,7 +309,10 @@ Future compileStringToResultAsync(String source, quietDeps: quietDeps, verbose: verbose, sourceMap: sourceMap, - charset: charset); + charset: charset, + silenceDeprecations: silenceDeprecations, + fatalDeprecations: fatalDeprecations, + futureDeprecations: futureDeprecations); /// Like [compileToResult], but returns [CompileResult.css] rather than /// returning [CompileResult] directly. diff --git a/lib/src/async_compile.dart b/lib/src/async_compile.dart index a940d3f26..e6a86a0f0 100644 --- a/lib/src/async_compile.dart +++ b/lib/src/async_compile.dart @@ -42,10 +42,12 @@ Future compileAsync(String path, bool verbose = false, bool sourceMap = false, bool charset = true, + Iterable? silenceDeprecations, Iterable? fatalDeprecations, Iterable? futureDeprecations}) async { DeprecationHandlingLogger deprecationLogger = logger = DeprecationHandlingLogger(logger ?? Logger.stderr(), + silenceDeprecations: {...?silenceDeprecations}, fatalDeprecations: {...?fatalDeprecations}, futureDeprecations: {...?futureDeprecations}, limitRepetition: !verbose); @@ -106,10 +108,12 @@ Future compileStringAsync(String source, bool verbose = false, bool sourceMap = false, bool charset = true, + Iterable? silenceDeprecations, Iterable? fatalDeprecations, Iterable? futureDeprecations}) async { DeprecationHandlingLogger deprecationLogger = logger = DeprecationHandlingLogger(logger ?? Logger.stderr(), + silenceDeprecations: {...?silenceDeprecations}, fatalDeprecations: {...?fatalDeprecations}, futureDeprecations: {...?futureDeprecations}, limitRepetition: !verbose); diff --git a/lib/src/compile.dart b/lib/src/compile.dart index 94221405d..7aa946e70 100644 --- a/lib/src/compile.dart +++ b/lib/src/compile.dart @@ -5,7 +5,7 @@ // DO NOT EDIT. This file was generated from async_compile.dart. // See tool/grind/synchronize.dart for details. // -// Checksum: a9421a2975e79ad591ae32474cd076e1379d0e75 +// Checksum: 9d2d66aa8a5b5613cbae25c448356526aebbadbf // // ignore_for_file: unused_import @@ -51,10 +51,12 @@ CompileResult compile(String path, bool verbose = false, bool sourceMap = false, bool charset = true, + Iterable? silenceDeprecations, Iterable? fatalDeprecations, Iterable? futureDeprecations}) { DeprecationHandlingLogger deprecationLogger = logger = DeprecationHandlingLogger(logger ?? Logger.stderr(), + silenceDeprecations: {...?silenceDeprecations}, fatalDeprecations: {...?fatalDeprecations}, futureDeprecations: {...?futureDeprecations}, limitRepetition: !verbose); @@ -115,10 +117,12 @@ CompileResult compileString(String source, bool verbose = false, bool sourceMap = false, bool charset = true, + Iterable? silenceDeprecations, Iterable? fatalDeprecations, Iterable? futureDeprecations}) { DeprecationHandlingLogger deprecationLogger = logger = DeprecationHandlingLogger(logger ?? Logger.stderr(), + silenceDeprecations: {...?silenceDeprecations}, fatalDeprecations: {...?fatalDeprecations}, futureDeprecations: {...?futureDeprecations}, limitRepetition: !verbose); diff --git a/lib/src/deprecation.dart b/lib/src/deprecation.dart index 2724d0afe..8245665fb 100644 --- a/lib/src/deprecation.dart +++ b/lib/src/deprecation.dart @@ -107,14 +107,28 @@ enum Deprecation { /// what version of Dart Sass this deprecation will be live in. final bool isFuture; + /// Underlying version string used by [obsoleteIn]. + /// + /// This is necessary because [Version] doesn't have a constant constructor, + /// so we can't use it directly as an enum property. + final String? _obsoleteIn; + + /// The Dart Sass version this feature was fully removed in, making the + /// deprecation obsolete. + /// + /// For deprecations that are not yet obsolete, this should be null. + Version? get obsoleteIn => _obsoleteIn?.andThen(Version.parse); + /// Constructs a regular deprecation. const Deprecation(this.id, {required String? deprecatedIn, this.description}) : _deprecatedIn = deprecatedIn, + _obsoleteIn = null, isFuture = false; /// Constructs a future deprecation. const Deprecation.future(this.id, {this.description}) : _deprecatedIn = null, + _obsoleteIn = null, isFuture = true; @override diff --git a/lib/src/exception.dart b/lib/src/exception.dart index 898258c88..dca089b11 100644 --- a/lib/src/exception.dart +++ b/lib/src/exception.dart @@ -290,3 +290,10 @@ class MultiSpanSassScriptException extends SassScriptException { MultiSpanSassException withSpan(FileSpan span) => MultiSpanSassException(message, span, primaryLabel, secondarySpans); } + +/// An exception indicating that invalid arguments were passed. +class UsageException implements Exception { + final String message; + + UsageException(this.message); +} diff --git a/lib/src/executable/options.dart b/lib/src/executable/options.dart index 876b55814..6b508fb5f 100644 --- a/lib/src/executable/options.dart +++ b/lib/src/executable/options.dart @@ -10,6 +10,7 @@ import 'package:pub_semver/pub_semver.dart'; import 'package:term_glyph/term_glyph.dart' as term_glyph; import '../../sass.dart'; +import '../exception.dart'; import '../importer/node_package.dart'; import '../io.dart'; import '../util/character.dart'; @@ -91,6 +92,14 @@ final class ExecutableOptions { "Stylesheets imported through load paths count as dependencies.") ..addFlag('verbose', help: "Print all deprecation warnings even when they're repetitive.") + ..addMultiOption('silence-deprecation', + help: 'Deprecations to ignore.', + allowedHelp: { + for (var deprecation in Deprecation.values) + if (deprecation.deprecatedIn != null && + deprecation.description != null) + deprecation.id: deprecation.description!, + }) ..addMultiOption('fatal-deprecation', help: 'Deprecations to treat as errors. You may also pass a Sass\n' 'version to include any behavior deprecated in or before it.\n' @@ -521,6 +530,12 @@ final class ExecutableOptions { : p.absolute(path)); } + /// The set of deprecations whose warnings should be silenced. + Set get silenceDeprecations => { + for (var id in _options['silence-deprecation'] as List) + Deprecation.fromId(id) ?? _fail('Invalid deprecation "$id".') + }; + /// The set of deprecations that cause errors. Set get fatalDeprecations => _fatalDeprecations ??= () { var deprecations = {}; @@ -563,10 +578,3 @@ final class ExecutableOptions { Object? _ifParsed(String name) => _options.wasParsed(name) ? _options[name] : null; } - -/// An exception indicating that invalid arguments were passed. -class UsageException implements Exception { - final String message; - - UsageException(this.message); -} diff --git a/lib/src/js.dart b/lib/src/js.dart index 3246fc743..a8cbf9474 100644 --- a/lib/src/js.dart +++ b/lib/src/js.dart @@ -2,7 +2,10 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +import 'package:js/js_util.dart'; + import 'js/exception.dart'; +import 'js/deprecations.dart'; import 'js/exports.dart'; import 'js/compile.dart'; import 'js/compiler.dart'; @@ -46,6 +49,7 @@ void main() { exports.sassNull = sassNull; exports.sassTrue = sassTrue; exports.sassFalse = sassFalse; + exports.deprecations = jsify(deprecations); exports.Exception = exceptionClass; exports.Logger = LoggerNamespace( silent: JSLogger( diff --git a/lib/src/js/deprecations.dart b/lib/src/js/deprecations.dart new file mode 100644 index 000000000..0894306cd --- /dev/null +++ b/lib/src/js/deprecations.dart @@ -0,0 +1,61 @@ +// Copyright 2023 Google LLC. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:js/js.dart'; +import 'package:pub_semver/pub_semver.dart'; + +import '../deprecation.dart' as dart show Deprecation; +import 'reflection.dart'; + +@JS() +@anonymous +class Deprecation { + external String get id; + external String get status; + external String? get description; + external Version? get deprecatedIn; + external Version? get obsoleteIn; + + external factory Deprecation( + {required String id, + required String status, + String? description, + Version? deprecatedIn, + Version? obsoleteIn}); +} + +final Map deprecations = { + for (var deprecation in dart.Deprecation.values) + deprecation.id: Deprecation( + id: deprecation.id, + status: (() => switch (deprecation) { + dart.Deprecation(isFuture: true) => 'future', + dart.Deprecation(deprecatedIn: null, obsoleteIn: null) => 'user', + dart.Deprecation(obsoleteIn: null) => 'active', + _ => 'obsolete' + })(), + description: deprecation.description, + deprecatedIn: deprecation.deprecatedIn, + obsoleteIn: deprecation.deprecatedIn), +}; + +/// The JavaScript `Version` class. +final JSClass versionClass = () { + var jsClass = createJSClass('sass.Version', + (Object self, int major, int minor, int patch) { + return Version(major, minor, patch); + }); + + jsClass.defineGetters({ + 'major': (Version self) => self.major, + 'minor': (Version self) => self.minor, + 'patch': (Version self) => self.patch, + }); + + jsClass.defineStaticMethod( + 'parse', (String version) => Version.parse(version)); + + getJSClass(Version(0, 0, 0)).injectSuperclass(jsClass); + return jsClass; +}(); diff --git a/lib/src/js/exports.dart b/lib/src/js/exports.dart index 9a45268a8..d924f5556 100644 --- a/lib/src/js/exports.dart +++ b/lib/src/js/exports.dart @@ -27,6 +27,7 @@ class Exports { external set Exception(JSClass function); external set Logger(LoggerNamespace namespace); external set NodePackageImporter(JSClass function); + external set deprecations(Object? object); // Value APIs external set Value(JSClass function); diff --git a/lib/src/logger/deprecation_handling.dart b/lib/src/logger/deprecation_handling.dart index 4b185651b..40d8a0600 100644 --- a/lib/src/logger/deprecation_handling.dart +++ b/lib/src/logger/deprecation_handling.dart @@ -22,6 +22,9 @@ final class DeprecationHandlingLogger implements Logger { final Logger _inner; + /// Deprecation warnings of these types will be ignored. + final Set silenceDeprecations; + /// Deprecation warnings of one of these types will cause an error to be /// thrown. /// @@ -37,9 +40,45 @@ final class DeprecationHandlingLogger implements Logger { final bool limitRepetition; DeprecationHandlingLogger(this._inner, - {required this.fatalDeprecations, + {required this.silenceDeprecations, + required this.fatalDeprecations, required this.futureDeprecations, - this.limitRepetition = true}); + this.limitRepetition = true}) { + for (var deprecation in fatalDeprecations) { + if (deprecation.isFuture && !futureDeprecations.contains(deprecation)) { + warn('Future $deprecation deprecation must be enabled before it can be ' + 'made fatal.'); + } else if (deprecation.obsoleteIn != null) { + warn('$deprecation deprecation is obsolete, so does not need to be ' + 'made fatal.'); + } else if (silenceDeprecations.contains(deprecation)) { + warn('Ignoring setting to silence $deprecation deprecation, since it ' + 'has also been made fatal.'); + } + } + for (var deprecation in silenceDeprecations) { + if (deprecation == Deprecation.userAuthored) { + warn('User-authored deprecations should not be silenced.'); + } else if (deprecation.obsoleteIn != null) { + warn('$deprecation deprecation is obsolete. If you were previously ' + 'silencing it, your code may now behave in unexpected ways.'); + } else if (deprecation.isFuture) { + if (futureDeprecations.contains(deprecation)) { + warn('Conflicting options for future $deprecation deprecation cancel ' + 'each other out.'); + } else { + warn('Future $deprecation deprecation is not yet active, so ' + 'silencing it is unnecessary.'); + } + } + } + for (var deprecation in futureDeprecations) { + if (!deprecation.isFuture) { + warn('$deprecation is not a future deprecation, so it does not need to ' + 'be explicitly enabled.'); + } + } + } void warn(String message, {FileSpan? span, Trace? trace, bool deprecation = false}) { @@ -72,6 +111,8 @@ final class DeprecationHandlingLogger implements Logger { return; } + if (silenceDeprecations.contains(deprecation)) return; + if (limitRepetition) { var count = _warningCounts[deprecation] = (_warningCounts[deprecation] ?? 0) + 1; From ded1a32d6119c9d27f4958c2358eef638cc89f9f Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Fri, 23 Feb 2024 21:14:08 +0000 Subject: [PATCH 02/10] Revert moving UsageException --- lib/src/exception.dart | 7 ------- lib/src/executable/options.dart | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/src/exception.dart b/lib/src/exception.dart index dca089b11..898258c88 100644 --- a/lib/src/exception.dart +++ b/lib/src/exception.dart @@ -290,10 +290,3 @@ class MultiSpanSassScriptException extends SassScriptException { MultiSpanSassException withSpan(FileSpan span) => MultiSpanSassException(message, span, primaryLabel, secondarySpans); } - -/// An exception indicating that invalid arguments were passed. -class UsageException implements Exception { - final String message; - - UsageException(this.message); -} diff --git a/lib/src/executable/options.dart b/lib/src/executable/options.dart index 6b508fb5f..fb79db4c2 100644 --- a/lib/src/executable/options.dart +++ b/lib/src/executable/options.dart @@ -578,3 +578,10 @@ final class ExecutableOptions { Object? _ifParsed(String name) => _options.wasParsed(name) ? _options[name] : null; } + +/// An exception indicating that invalid arguments were passed. +class UsageException implements Exception { + final String message; + + UsageException(this.message); +} From bff24d8f5d56f6d87d215ca29786b5176ec83cde Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Fri, 22 Mar 2024 00:24:54 +0000 Subject: [PATCH 03/10] Implement Deprecations API for JS and embedded --- lib/src/embedded/compilation_dispatcher.dart | 22 ++++++ lib/src/executable/options.dart | 1 - lib/src/js.dart | 3 +- lib/src/js/compile.dart | 82 +++++++++++++++++--- lib/src/js/compile_options.dart | 3 + lib/src/js/exports.dart | 1 + tool/grind.dart | 2 + 7 files changed, 100 insertions(+), 14 deletions(-) diff --git a/lib/src/embedded/compilation_dispatcher.dart b/lib/src/embedded/compilation_dispatcher.dart index 356130d84..675216022 100644 --- a/lib/src/embedded/compilation_dispatcher.dart +++ b/lib/src/embedded/compilation_dispatcher.dart @@ -7,6 +7,7 @@ import 'dart:io'; import 'dart:isolate'; import 'dart:typed_data'; +import 'package:collection/collection.dart'; import 'package:native_synchronization/mailbox.dart'; import 'package:path/path.dart' as p; import 'package:protobuf/protobuf.dart'; @@ -124,6 +125,21 @@ final class CompilationDispatcher { : EmbeddedLogger(this, color: request.alertColor, ascii: request.alertAscii); + sass.Deprecation? deprecationOrWarn(String id) { + var deprecation = sass.Deprecation.fromId(id); + if (deprecation == null) { + logger.warn('Invalid deprecation "$id".'); + } + return deprecation; + } + + var fatalDeprecations = + request.fatalDeprecation.map(deprecationOrWarn).whereNotNull(); + var silenceDeprecations = + request.silenceDeprecation.map(deprecationOrWarn).whereNotNull(); + var futureDeprecations = + request.futureDeprecation.map(deprecationOrWarn).whereNotNull(); + try { var importers = request.importers.map((importer) => _decodeImporter(request, importer) ?? @@ -148,6 +164,9 @@ final class CompilationDispatcher { url: input.url.isEmpty ? null : input.url, quietDeps: request.quietDeps, verbose: request.verbose, + fatalDeprecations: fatalDeprecations, + silenceDeprecations: silenceDeprecations, + futureDeprecations: futureDeprecations, sourceMap: request.sourceMap, charset: request.charset); @@ -165,6 +184,9 @@ final class CompilationDispatcher { style: style, quietDeps: request.quietDeps, verbose: request.verbose, + fatalDeprecations: fatalDeprecations, + silenceDeprecations: silenceDeprecations, + futureDeprecations: futureDeprecations, sourceMap: request.sourceMap, charset: request.charset); } on FileSystemException catch (error) { diff --git a/lib/src/executable/options.dart b/lib/src/executable/options.dart index fb79db4c2..c120d0300 100644 --- a/lib/src/executable/options.dart +++ b/lib/src/executable/options.dart @@ -10,7 +10,6 @@ import 'package:pub_semver/pub_semver.dart'; import 'package:term_glyph/term_glyph.dart' as term_glyph; import '../../sass.dart'; -import '../exception.dart'; import '../importer/node_package.dart'; import '../io.dart'; import '../util/character.dart'; diff --git a/lib/src/js.dart b/lib/src/js.dart index a8cbf9474..79bf90180 100644 --- a/lib/src/js.dart +++ b/lib/src/js.dart @@ -49,13 +49,14 @@ void main() { exports.sassNull = sassNull; exports.sassTrue = sassTrue; exports.sassFalse = sassFalse; - exports.deprecations = jsify(deprecations); exports.Exception = exceptionClass; exports.Logger = LoggerNamespace( silent: JSLogger( warn: allowInteropNamed('sass.Logger.silent.warn', (_, __) {}), debug: allowInteropNamed('sass.Logger.silent.debug', (_, __) {}))); exports.NodePackageImporter = nodePackageImporterClass; + exports.deprecations = jsify(deprecations); + exports.Version = versionClass; exports.info = "dart-sass\t${const String.fromEnvironment('version')}\t(Sass Compiler)\t" diff --git a/lib/src/js/compile.dart b/lib/src/js/compile.dart index a08806975..97cff0704 100644 --- a/lib/src/js/compile.dart +++ b/lib/src/js/compile.dart @@ -7,6 +7,7 @@ import 'package:node_interop/js.dart'; import 'package:node_interop/util.dart' hide futureToPromise; import 'package:term_glyph/term_glyph.dart' as glyph; import 'package:path/path.dart' as p; +import 'package:pub_semver/pub_semver.dart'; import '../../sass.dart'; import '../importer/no_op.dart'; @@ -20,6 +21,7 @@ import '../logger/js_to_dart.dart'; import '../util/nullable.dart'; import 'compile_options.dart'; import 'compile_result.dart'; +import 'deprecations.dart' as js show Deprecation; import 'exception.dart'; import 'importer.dart'; import 'reflection.dart'; @@ -35,6 +37,8 @@ NodeCompileResult compile(String path, [CompileOptions? options]) { } var color = options?.alertColor ?? hasTerminal; var ascii = options?.alertAscii ?? glyph.ascii; + var logger = JSToDartLogger(options?.logger, Logger.stderr(color: color), + ascii: ascii); try { var result = compileToResult(path, color: color, @@ -44,10 +48,15 @@ NodeCompileResult compile(String path, [CompileOptions? options]) { verbose: options?.verbose ?? false, charset: options?.charset ?? true, sourceMap: options?.sourceMap ?? false, - logger: JSToDartLogger(options?.logger, Logger.stderr(color: color), - ascii: ascii), + logger: logger, importers: options?.importers?.map(_parseImporter), - functions: _parseFunctions(options?.functions).cast()); + functions: _parseFunctions(options?.functions).cast(), + fatalDeprecations: _parseDeprecations( + logger, options?.fatalDeprecations, supportVersions: true), + silenceDeprecations: + _parseDeprecations(logger, options?.silenceDeprecations), + futureDeprecations: + _parseDeprecations(logger, options?.futureDeprecations)); return _convertResult(result, includeSourceContents: options?.sourceMapIncludeSources ?? false); } on SassException catch (error, stackTrace) { @@ -62,6 +71,8 @@ NodeCompileResult compile(String path, [CompileOptions? options]) { NodeCompileResult compileString(String text, [CompileStringOptions? options]) { var color = options?.alertColor ?? hasTerminal; var ascii = options?.alertAscii ?? glyph.ascii; + var logger = JSToDartLogger(options?.logger, Logger.stderr(color: color), + ascii: ascii); try { var result = compileStringToResult(text, syntax: parseSyntax(options?.syntax), @@ -73,12 +84,17 @@ NodeCompileResult compileString(String text, [CompileStringOptions? options]) { verbose: options?.verbose ?? false, charset: options?.charset ?? true, sourceMap: options?.sourceMap ?? false, - logger: JSToDartLogger(options?.logger, Logger.stderr(color: color), - ascii: ascii), + logger: logger, importers: options?.importers?.map(_parseImporter), importer: options?.importer.andThen(_parseImporter) ?? (options?.url == null ? NoOpImporter() : null), - functions: _parseFunctions(options?.functions).cast()); + functions: _parseFunctions(options?.functions).cast(), + fatalDeprecations: _parseDeprecations( + logger, options?.fatalDeprecations, supportVersions: true), + silenceDeprecations: + _parseDeprecations(logger, options?.silenceDeprecations), + futureDeprecations: + _parseDeprecations(logger, options?.futureDeprecations)); return _convertResult(result, includeSourceContents: options?.sourceMapIncludeSources ?? false); } on SassException catch (error, stackTrace) { @@ -96,6 +112,8 @@ Promise compileAsync(String path, [CompileOptions? options]) { } var color = options?.alertColor ?? hasTerminal; var ascii = options?.alertAscii ?? glyph.ascii; + var logger = JSToDartLogger(options?.logger, Logger.stderr(color: color), + ascii: ascii); return _wrapAsyncSassExceptions(futureToPromise(() async { var result = await compileToResultAsync(path, color: color, @@ -105,11 +123,16 @@ Promise compileAsync(String path, [CompileOptions? options]) { verbose: options?.verbose ?? false, charset: options?.charset ?? true, sourceMap: options?.sourceMap ?? false, - logger: JSToDartLogger(options?.logger, Logger.stderr(color: color), - ascii: ascii), + logger: logger, importers: options?.importers ?.map((importer) => _parseAsyncImporter(importer)), - functions: _parseFunctions(options?.functions, asynch: true)); + functions: _parseFunctions(options?.functions, asynch: true), + fatalDeprecations: _parseDeprecations( + logger, options?.fatalDeprecations, supportVersions: true), + silenceDeprecations: + _parseDeprecations(logger, options?.silenceDeprecations), + futureDeprecations: + _parseDeprecations(logger, options?.futureDeprecations)); return _convertResult(result, includeSourceContents: options?.sourceMapIncludeSources ?? false); }()), color: color, ascii: ascii); @@ -122,6 +145,8 @@ Promise compileAsync(String path, [CompileOptions? options]) { Promise compileStringAsync(String text, [CompileStringOptions? options]) { var color = options?.alertColor ?? hasTerminal; var ascii = options?.alertAscii ?? glyph.ascii; + var logger = JSToDartLogger(options?.logger, Logger.stderr(color: color), + ascii: ascii); return _wrapAsyncSassExceptions(futureToPromise(() async { var result = await compileStringToResultAsync(text, syntax: parseSyntax(options?.syntax), @@ -133,14 +158,19 @@ Promise compileStringAsync(String text, [CompileStringOptions? options]) { verbose: options?.verbose ?? false, charset: options?.charset ?? true, sourceMap: options?.sourceMap ?? false, - logger: JSToDartLogger(options?.logger, Logger.stderr(color: color), - ascii: ascii), + logger: logger, importers: options?.importers ?.map((importer) => _parseAsyncImporter(importer)), importer: options?.importer .andThen((importer) => _parseAsyncImporter(importer)) ?? (options?.url == null ? NoOpImporter() : null), - functions: _parseFunctions(options?.functions, asynch: true)); + functions: _parseFunctions(options?.functions, asynch: true), + fatalDeprecations: _parseDeprecations( + logger, options?.fatalDeprecations, supportVersions: true), + silenceDeprecations: + _parseDeprecations(logger, options?.silenceDeprecations), + futureDeprecations: + _parseDeprecations(logger, options?.futureDeprecations)); return _convertResult(result, includeSourceContents: options?.sourceMapIncludeSources ?? false); }()), color: color, ascii: ascii); @@ -329,6 +359,34 @@ List _parseFunctions(Object? functions, {bool asynch = false}) { return result; } +Iterable? _parseDeprecations( + JSToDartLogger logger, List? deprecations, + {bool supportVersions = false}) { + if (deprecations == null) return null; + return () sync* { + for (var item in deprecations) { + switch (item) { + case String id: + var deprecation = Deprecation.fromId(id); + if (deprecation == null) { + logger.warn('Invalid deprecation "$id".'); + } else { + yield deprecation; + } + case js.Deprecation(:var id): + var deprecation = Deprecation.fromId(id); + if (deprecation == null) { + logger.warn('Invalid deprecation "$id".'); + } else { + yield deprecation; + } + case Version version when supportVersions: + yield* Deprecation.forVersion(version); + } + } + }(); +} + /// The exported `NodePackageImporter` class that can be added to the /// `importers` option to enable loading `pkg:` URLs from `node_modules`. final JSClass nodePackageImporterClass = () { diff --git a/lib/src/js/compile_options.dart b/lib/src/js/compile_options.dart index 1789539d5..c53a1893d 100644 --- a/lib/src/js/compile_options.dart +++ b/lib/src/js/compile_options.dart @@ -23,6 +23,9 @@ class CompileOptions { external JSLogger? get logger; external List? get importers; external Object? get functions; + external List? get fatalDeprecations; + external List? get silenceDeprecations; + external List? get futureDeprecations; } @JS() diff --git a/lib/src/js/exports.dart b/lib/src/js/exports.dart index d924f5556..e106ad610 100644 --- a/lib/src/js/exports.dart +++ b/lib/src/js/exports.dart @@ -28,6 +28,7 @@ class Exports { external set Logger(LoggerNamespace namespace); external set NodePackageImporter(JSClass function); external set deprecations(Object? object); + external set Version(JSClass version); // Value APIs external set Value(JSClass function); diff --git a/tool/grind.dart b/tool/grind.dart index 95d9b3cc8..33b56ff2e 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -87,6 +87,8 @@ void main(List args) { 'NULL', 'types', 'NodePackageImporter', + 'deprecations', + 'Version', }; pkg.githubReleaseNotes.fn = () => From 3efd6e7d506cce31b8f5e127e419c96e47ae1e72 Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Mon, 1 Apr 2024 17:49:49 +0000 Subject: [PATCH 04/10] Fix deprecations API implementation --- lib/src/embedded/logger.dart | 9 +++++-- lib/src/js/deprecations.dart | 6 ----- lib/src/js/logger.dart | 8 ++++++- lib/src/logger.dart | 30 +++++++++++++++++++++--- lib/src/logger/deprecation_handling.dart | 26 ++++++++++++-------- lib/src/logger/js_to_dart.dart | 12 +++++++--- 6 files changed, 66 insertions(+), 25 deletions(-) diff --git a/lib/src/embedded/logger.dart b/lib/src/embedded/logger.dart index 331acdf2b..8166db5fc 100644 --- a/lib/src/embedded/logger.dart +++ b/lib/src/embedded/logger.dart @@ -6,6 +6,7 @@ import 'package:path/path.dart' as p; import 'package:source_span/source_span.dart'; import 'package:stack_trace/stack_trace.dart'; +import '../deprecation.dart'; import '../logger.dart'; import '../util/nullable.dart'; import '../utils.dart'; @@ -14,7 +15,7 @@ import 'embedded_sass.pb.dart' hide SourceSpan; import 'utils.dart'; /// A Sass logger that sends log messages as `LogEvent`s. -final class EmbeddedLogger implements Logger { +final class EmbeddedLogger implements DeprecationLogger { /// The [CompilationDispatcher] to which to send events. final CompilationDispatcher _dispatcher; @@ -40,7 +41,10 @@ final class EmbeddedLogger implements Logger { } void warn(String message, - {FileSpan? span, Trace? trace, bool deprecation = false}) { + {FileSpan? span, + Trace? trace, + bool deprecation = false, + Deprecation? deprecationType}) { var formatted = withGlyphs(() { var buffer = StringBuffer(); if (_color) { @@ -71,6 +75,7 @@ final class EmbeddedLogger implements Logger { ..formatted = formatted; if (span != null) event.span = protofySpan(span); if (trace != null) event.stackTrace = trace.toString(); + if (deprecationType != null) event.deprecationType = deprecationType.id; _dispatcher.sendLog(event); } } diff --git a/lib/src/js/deprecations.dart b/lib/src/js/deprecations.dart index 0894306cd..c48b5548c 100644 --- a/lib/src/js/deprecations.dart +++ b/lib/src/js/deprecations.dart @@ -47,12 +47,6 @@ final JSClass versionClass = () { return Version(major, minor, patch); }); - jsClass.defineGetters({ - 'major': (Version self) => self.major, - 'minor': (Version self) => self.minor, - 'patch': (Version self) => self.patch, - }); - jsClass.defineStaticMethod( 'parse', (String version) => Version.parse(version)); diff --git a/lib/src/js/logger.dart b/lib/src/js/logger.dart index fb28030d5..2e6fd6fc0 100644 --- a/lib/src/js/logger.dart +++ b/lib/src/js/logger.dart @@ -5,6 +5,8 @@ import 'package:js/js.dart'; import 'package:source_span/source_span.dart'; +import 'deprecations.dart'; + @JS() @anonymous class JSLogger { @@ -20,11 +22,15 @@ class JSLogger { @anonymous class WarnOptions { external bool get deprecation; + external Deprecation? get deprecationType; external SourceSpan? get span; external String? get stack; external factory WarnOptions( - {required bool deprecation, SourceSpan? span, String? stack}); + {required bool deprecation, + Deprecation? deprecationType, + SourceSpan? span, + String? stack}); } @JS() diff --git a/lib/src/logger.dart b/lib/src/logger.dart index a329b3b79..1d8c31848 100644 --- a/lib/src/logger.dart +++ b/lib/src/logger.dart @@ -7,7 +7,6 @@ import 'package:source_span/source_span.dart'; import 'package:stack_trace/stack_trace.dart'; import 'deprecation.dart'; -import 'logger/deprecation_handling.dart'; import 'logger/stderr.dart'; /// An interface for loggers that print messages produced by Sass stylesheets. @@ -37,6 +36,27 @@ abstract class Logger { void debug(String message, SourceSpan span); } +/// A logger interface that also handles deprecation types. +/// +/// This is only used internally by [DeprecationHandlingLogger] and +/// [JSToDartLogger]. In Dart Sass 2.0, we can get rid of this and just add +/// it as a breaking change to [Logger]. +@internal +abstract class DeprecationLogger implements Logger { + /// Emits a warning with the given [message]. + /// + /// If [span] is passed, it's the location in the Sass source that generated + /// the warning. If [trace] is passed, it's the Sass stack trace when the + /// warning was issued. If [deprecation] is `true`, it indicates that this is + /// a deprecation warning with type [deprecationType]. Implementations should + /// surface all this information to the end user. + void warn(String message, + {FileSpan? span, + Trace? trace, + bool deprecation = false, + Deprecation? deprecationType}); +} + /// An extension to add a `warnForDeprecation` method to loggers without /// making a breaking API change. @internal @@ -44,8 +64,12 @@ extension WarnForDeprecation on Logger { /// Emits a deprecation warning for [deprecation] with the given [message]. void warnForDeprecation(Deprecation deprecation, String message, {FileSpan? span, Trace? trace}) { - if (this case DeprecationHandlingLogger self) { - self.warnForDeprecation(deprecation, message, span: span, trace: trace); + if (this case DeprecationLogger self) { + self.warn(message, + span: span, + trace: trace, + deprecation: true, + deprecationType: deprecation); } else if (!deprecation.isFuture) { warn(message, span: span, trace: trace, deprecation: true); } diff --git a/lib/src/logger/deprecation_handling.dart b/lib/src/logger/deprecation_handling.dart index 40d8a0600..77030d367 100644 --- a/lib/src/logger/deprecation_handling.dart +++ b/lib/src/logger/deprecation_handling.dart @@ -16,7 +16,7 @@ const _maxRepetitions = 5; /// A logger that wraps an inner logger to have special handling for /// deprecation warnings. -final class DeprecationHandlingLogger implements Logger { +final class DeprecationHandlingLogger implements DeprecationLogger { /// A map of how many times each deprecation has been emitted by this logger. final _warningCounts = {}; @@ -81,21 +81,32 @@ final class DeprecationHandlingLogger implements Logger { } void warn(String message, - {FileSpan? span, Trace? trace, bool deprecation = false}) { - _inner.warn(message, span: span, trace: trace, deprecation: deprecation); + {FileSpan? span, + Trace? trace, + bool deprecation = false, + Deprecation? deprecationType}) { + if (deprecation && deprecationType != null) { + warnForDeprecation(deprecationType, message, span: span, trace: trace); + } else { + _inner.warn(message, span: span, trace: trace); + } } /// Processes a deprecation warning. /// /// If [deprecation] is in [fatalDeprecations], this shows an error. /// - /// If it's a future deprecation that hasn't been opted into or its a + /// If it's a future deprecation that hasn't been opted into or it's a /// deprecation that's already been warned for [_maxReptitions] times and /// [limitRepetitions] is true, the warning is dropped. /// /// Otherwise, this is passed on to [warn]. void warnForDeprecation(Deprecation deprecation, String message, {FileSpan? span, Trace? trace}) { + if (deprecation.isFuture && !futureDeprecations.contains(deprecation)) { + return; + } + if (fatalDeprecations.contains(deprecation)) { message += "\n\nThis is only an error because you've set the " '$deprecation deprecation to be fatal.\n' @@ -106,11 +117,6 @@ final class DeprecationHandlingLogger implements Logger { _ => SassScriptException(message) }; } - - if (deprecation.isFuture && !futureDeprecations.contains(deprecation)) { - return; - } - if (silenceDeprecations.contains(deprecation)) return; if (limitRepetition) { @@ -119,7 +125,7 @@ final class DeprecationHandlingLogger implements Logger { if (count > _maxRepetitions) return; } - warn(message, span: span, trace: trace, deprecation: true); + _inner.warnForDeprecation(deprecation, message, span: span, trace: trace); } void debug(String message, SourceSpan span) => _inner.debug(message, span); diff --git a/lib/src/logger/js_to_dart.dart b/lib/src/logger/js_to_dart.dart index aa58a243d..415352c13 100644 --- a/lib/src/logger/js_to_dart.dart +++ b/lib/src/logger/js_to_dart.dart @@ -7,11 +7,13 @@ import 'package:source_span/source_span.dart'; import 'package:stack_trace/stack_trace.dart'; import 'package:term_glyph/term_glyph.dart' as glyph; +import '../deprecation.dart'; import '../logger.dart'; +import '../js/deprecations.dart' show deprecations; import '../js/logger.dart'; /// A wrapper around a [JSLogger] that exposes it as a Dart [Logger]. -final class JSToDartLogger implements Logger { +final class JSToDartLogger implements DeprecationLogger { /// The wrapped logger object. final JSLogger? _node; @@ -28,14 +30,18 @@ final class JSToDartLogger implements Logger { : _ascii = ascii ?? glyph.ascii; void warn(String message, - {FileSpan? span, Trace? trace, bool deprecation = false}) { + {FileSpan? span, + Trace? trace, + bool deprecation = false, + Deprecation? deprecationType}) { if (_node?.warn case var warn?) { warn( message, WarnOptions( span: span ?? (undefined as SourceSpan?), stack: trace.toString(), - deprecation: deprecation)); + deprecation: deprecation, + deprecationType: deprecations[deprecationType?.id])); } else { _withAscii(() { _fallback.warn(message, From 69b003a95af9cd8eff555533f880c9cbf26ee19f Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Mon, 1 Apr 2024 18:04:32 +0000 Subject: [PATCH 05/10] Add changelog --- CHANGELOG.md | 19 +++++++++++++++++++ pubspec.yaml | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5ae69c7c..98e18b3c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +## 1.74.0 + +### JS API + +* The deprecations API is now available in the JS API! The `compile` methods + support the same `fatalDeprecations` and `futureDeprecations` options that + were already available in the Dart API and the CLI, as well as a new + `silenceDeprecations` option that allows you to silence deprecation warnings + of a given type. + +### Command-Line Interface + +* Add a new `--silence-deprecation` flag to match the new JS API. + +### Dart API + +* The `compile` methods now take in a `silenceDeprecations` parameter to match + the JS API. + ## 1.73.0 * Add support for nesting in plain CSS files. This is not processed by Sass at diff --git a/pubspec.yaml b/pubspec.yaml index 52c8c58df..9fada08e3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.73.0 +version: 1.74.0 description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass From b679a4a74d37fa5e88227e78b2571cfa5ad46265 Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Mon, 1 Apr 2024 18:31:30 +0000 Subject: [PATCH 06/10] Update changelog --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98e18b3c5..157ea01d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,11 +12,27 @@ * Add a new `--silence-deprecation` flag to match the new JS API. +* Previously, if a future deprecation was passed to `--fatal-deprecation` but + not `--future-deprecation`, it would be treated as fatal despite not being + enabled. Both flags are now required to treat a future deprecation as fatal + with a warning emitted if `--fatal-deprecation` is passed without + `--future-deprecation`, matching the JS API's behavior. + ### Dart API * The `compile` methods now take in a `silenceDeprecations` parameter to match the JS API. +* Add `Deprecation.obsoleteIn` to match the JS API. This is currently null for + all deprecations, but will be used once some deprecations become obsolete in + Dart Sass 2.0.0. + +* Fix a bug where `compileStringToResultAsync` ignored `fatalDeprecations` and + `futureDeprecations`. + +* The behavior around making future deprecations fatal mentioned in the CLI + section above has also been changed in the Dart API. + ## 1.73.0 * Add support for nesting in plain CSS files. This is not processed by Sass at From 1f445a5084477ba4cc96657f02999b26cdb16ba5 Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Mon, 1 Apr 2024 20:31:46 +0000 Subject: [PATCH 07/10] Make sure future deprecations are only propagated through the deprecation handling logger --- lib/src/logger.dart | 4 ++- lib/src/logger/deprecation_handling.dart | 14 +++++++-- pkg/sass_api/CHANGELOG.md | 6 +++- pkg/sass_api/pubspec.yaml | 4 +-- test/embedded/utils.dart | 39 ++++++++++++++++-------- 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/lib/src/logger.dart b/lib/src/logger.dart index 1d8c31848..99cb5e10b 100644 --- a/lib/src/logger.dart +++ b/lib/src/logger.dart @@ -7,6 +7,7 @@ import 'package:source_span/source_span.dart'; import 'package:stack_trace/stack_trace.dart'; import 'deprecation.dart'; +import 'logger/deprecation_handling.dart'; import 'logger/stderr.dart'; /// An interface for loggers that print messages produced by Sass stylesheets. @@ -64,13 +65,14 @@ extension WarnForDeprecation on Logger { /// Emits a deprecation warning for [deprecation] with the given [message]. void warnForDeprecation(Deprecation deprecation, String message, {FileSpan? span, Trace? trace}) { + if (deprecation.isFuture && this is! DeprecationHandlingLogger) return; if (this case DeprecationLogger self) { self.warn(message, span: span, trace: trace, deprecation: true, deprecationType: deprecation); - } else if (!deprecation.isFuture) { + } else { warn(message, span: span, trace: trace, deprecation: true); } } diff --git a/lib/src/logger/deprecation_handling.dart b/lib/src/logger/deprecation_handling.dart index 77030d367..488212f58 100644 --- a/lib/src/logger/deprecation_handling.dart +++ b/lib/src/logger/deprecation_handling.dart @@ -86,7 +86,7 @@ final class DeprecationHandlingLogger implements DeprecationLogger { bool deprecation = false, Deprecation? deprecationType}) { if (deprecation && deprecationType != null) { - warnForDeprecation(deprecationType, message, span: span, trace: trace); + _handleDeprecation(deprecationType, message, span: span, trace: trace); } else { _inner.warn(message, span: span, trace: trace); } @@ -101,7 +101,7 @@ final class DeprecationHandlingLogger implements DeprecationLogger { /// [limitRepetitions] is true, the warning is dropped. /// /// Otherwise, this is passed on to [warn]. - void warnForDeprecation(Deprecation deprecation, String message, + void _handleDeprecation(Deprecation deprecation, String message, {FileSpan? span, Trace? trace}) { if (deprecation.isFuture && !futureDeprecations.contains(deprecation)) { return; @@ -125,7 +125,15 @@ final class DeprecationHandlingLogger implements DeprecationLogger { if (count > _maxRepetitions) return; } - _inner.warnForDeprecation(deprecation, message, span: span, trace: trace); + if (_inner case DeprecationLogger inner) { + inner.warn(message, + span: span, + trace: trace, + deprecation: true, + deprecationType: deprecation); + } else { + _inner.warn(message, span: span, trace: trace, deprecation: true); + } } void debug(String message, SourceSpan span) => _inner.debug(message, span); diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index 6e8d05390..32421eb86 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,3 +1,7 @@ +## 10.1.0 + +* No user-visible changes. + ## 10.0.0 * Remove the `allowPlaceholders` argument from `SelectorList.parse()`. Instead, @@ -95,7 +99,7 @@ * All uses of classes from the `tuple` package have been replaced by record types. - + ## 7.2.2 * No user-visible changes. diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index 4780522de..c6b9f287b 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: 10.0.0 +version: 10.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.73.0 + sass: 1.74.0 dev_dependencies: dartdoc: ^6.0.0 diff --git a/test/embedded/utils.dart b/test/embedded/utils.dart index 68c1e2f83..eae637a92 100644 --- a/test/embedded/utils.dart +++ b/test/embedded/utils.dart @@ -16,18 +16,23 @@ const defaultCompilationId = 4321; /// Returns a (compilation ID, [InboundMessage]) pair that compiles the given /// plain CSS string. -InboundMessage compileString(String css, - {int? id, - bool? alertColor, - bool? alertAscii, - Syntax? syntax, - OutputStyle? style, - String? url, - bool? sourceMap, - bool? sourceMapIncludeSources, - Iterable? importers, - InboundMessage_CompileRequest_Importer? importer, - Iterable? functions}) { +InboundMessage compileString( + String css, { + int? id, + bool? alertColor, + bool? alertAscii, + Syntax? syntax, + OutputStyle? style, + String? url, + bool? sourceMap, + bool? sourceMapIncludeSources, + Iterable? importers, + InboundMessage_CompileRequest_Importer? importer, + Iterable? functions, + Iterable? fatalDeprecations, + Iterable? futureDeprecations, + Iterable? silenceDeprecations, +}) { var input = InboundMessage_CompileRequest_StringInput()..source = css; if (syntax != null) input.syntax = syntax; if (url != null) input.url = url; @@ -43,7 +48,15 @@ InboundMessage compileString(String css, if (functions != null) request.globalFunctions.addAll(functions); if (alertColor != null) request.alertColor = alertColor; if (alertAscii != null) request.alertAscii = alertAscii; - + if (fatalDeprecations != null) { + request.fatalDeprecation.addAll(fatalDeprecations); + } + if (futureDeprecations != null) { + request.futureDeprecation.addAll(futureDeprecations); + } + if (silenceDeprecations != null) { + request.silenceDeprecation.addAll(silenceDeprecations); + } return InboundMessage()..compileRequest = request; } From 5cb6bc05755ff7291b81ad0265f2e64a42c648c9 Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Wed, 3 Apr 2024 01:51:17 +0000 Subject: [PATCH 08/10] Code review --- CHANGELOG.md | 30 +++++--- bin/sass.dart | 4 +- lib/src/async_compile.dart | 10 +-- lib/src/compile.dart | 10 +-- lib/src/embedded/logger.dart | 20 +++-- lib/src/executable/options.dart | 10 ++- lib/src/js/compile.dart | 5 ++ lib/src/js/deprecations.dart | 26 ++++--- lib/src/logger.dart | 55 ++++++++------ ...dling.dart => deprecation_processing.dart} | 74 ++++++++++--------- lib/src/logger/js_to_dart.dart | 15 ++-- test/embedded/utils.dart | 45 +++++------ 12 files changed, 164 insertions(+), 140 deletions(-) rename lib/src/logger/{deprecation_handling.dart => deprecation_processing.dart} (69%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 157ea01d6..98eaad010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,15 +2,25 @@ ### JS API -* The deprecations API is now available in the JS API! The `compile` methods - support the same `fatalDeprecations` and `futureDeprecations` options that - were already available in the Dart API and the CLI, as well as a new - `silenceDeprecations` option that allows you to silence deprecation warnings - of a given type. +* Add a new top-level `deprecations` object, which contains various + `Deprecation` objects that define the different types of deprecation used by + the Sass compiler and can be passed to the options below. + +* Add a new `fatalDeprecations` compiler option that causes the compiler to + error if any deprecation warnings of the provided types are encountered. You + can also pass in a `Version` object to treat all deprecations that were active + in that Dart Sass version as fatal. + +* Add a new `futureDeprecations` compiler option that allows you to opt-in to + certain deprecations early (currently just `import`). + +* Add a new `silenceDeprecations` compiler option to ignore any deprecation + warnings of the provided types. ### Command-Line Interface -* Add a new `--silence-deprecation` flag to match the new JS API. +* Add a new `--silence-deprecation` flag, which causes the compiler to ignore + any deprecation warnings of the provided types. * Previously, if a future deprecation was passed to `--fatal-deprecation` but not `--future-deprecation`, it would be treated as fatal despite not being @@ -20,15 +30,15 @@ ### Dart API -* The `compile` methods now take in a `silenceDeprecations` parameter to match - the JS API. +* The `compile` methods now take in a `silenceDeprecations` parameter, which + causes the compiler to ignore any deprecation warnings of the provided types. * Add `Deprecation.obsoleteIn` to match the JS API. This is currently null for all deprecations, but will be used once some deprecations become obsolete in Dart Sass 2.0.0. -* Fix a bug where `compileStringToResultAsync` ignored `fatalDeprecations` and - `futureDeprecations`. +* **Potentially breaking bug fix:** Fix a bug where `compileStringToResultAsync` + ignored `fatalDeprecations` and `futureDeprecations`. * The behavior around making future deprecations fatal mentioned in the CLI section above has also been changed in the Dart API. diff --git a/bin/sass.dart b/bin/sass.dart index d241ab03d..cc912d041 100644 --- a/bin/sass.dart +++ b/bin/sass.dart @@ -15,7 +15,7 @@ import 'package:sass/src/executable/watch.dart'; import 'package:sass/src/import_cache.dart'; import 'package:sass/src/importer/filesystem.dart'; import 'package:sass/src/io.dart'; -import 'package:sass/src/logger/deprecation_handling.dart'; +import 'package:sass/src/logger/deprecation_processing.dart'; import 'package:sass/src/stylesheet_graph.dart'; import 'package:sass/src/utils.dart'; import 'package:sass/src/embedded/executable.dart' @@ -53,7 +53,7 @@ Future main(List args) async { // limit repetition. A separate DeprecationHandlingLogger is created for // each compilation, which will limit repetition if verbose is not // passed in addition to handling fatal/future deprecations. - logger: DeprecationHandlingLogger(options.logger, + logger: DeprecationProcessingLogger(options.logger, silenceDeprecations: options.silenceDeprecations, fatalDeprecations: options.fatalDeprecations, futureDeprecations: options.futureDeprecations, diff --git a/lib/src/async_compile.dart b/lib/src/async_compile.dart index e6a86a0f0..063f3d2dc 100644 --- a/lib/src/async_compile.dart +++ b/lib/src/async_compile.dart @@ -17,7 +17,7 @@ import 'importer/legacy_node.dart'; import 'importer/no_op.dart'; import 'io.dart'; import 'logger.dart'; -import 'logger/deprecation_handling.dart'; +import 'logger/deprecation_processing.dart'; import 'syntax.dart'; import 'utils.dart'; import 'visitor/async_evaluate.dart'; @@ -45,8 +45,8 @@ Future compileAsync(String path, Iterable? silenceDeprecations, Iterable? fatalDeprecations, Iterable? futureDeprecations}) async { - DeprecationHandlingLogger deprecationLogger = logger = - DeprecationHandlingLogger(logger ?? Logger.stderr(), + DeprecationProcessingLogger deprecationLogger = logger = + DeprecationProcessingLogger(logger ?? Logger.stderr(), silenceDeprecations: {...?silenceDeprecations}, fatalDeprecations: {...?fatalDeprecations}, futureDeprecations: {...?futureDeprecations}, @@ -111,8 +111,8 @@ Future compileStringAsync(String source, Iterable? silenceDeprecations, Iterable? fatalDeprecations, Iterable? futureDeprecations}) async { - DeprecationHandlingLogger deprecationLogger = logger = - DeprecationHandlingLogger(logger ?? Logger.stderr(), + DeprecationProcessingLogger deprecationLogger = logger = + DeprecationProcessingLogger(logger ?? Logger.stderr(), silenceDeprecations: {...?silenceDeprecations}, fatalDeprecations: {...?fatalDeprecations}, futureDeprecations: {...?futureDeprecations}, diff --git a/lib/src/compile.dart b/lib/src/compile.dart index 7aa946e70..594532200 100644 --- a/lib/src/compile.dart +++ b/lib/src/compile.dart @@ -26,7 +26,7 @@ import 'importer/legacy_node.dart'; import 'importer/no_op.dart'; import 'io.dart'; import 'logger.dart'; -import 'logger/deprecation_handling.dart'; +import 'logger/deprecation_processing.dart'; import 'syntax.dart'; import 'utils.dart'; import 'visitor/evaluate.dart'; @@ -54,8 +54,8 @@ CompileResult compile(String path, Iterable? silenceDeprecations, Iterable? fatalDeprecations, Iterable? futureDeprecations}) { - DeprecationHandlingLogger deprecationLogger = logger = - DeprecationHandlingLogger(logger ?? Logger.stderr(), + DeprecationProcessingLogger deprecationLogger = logger = + DeprecationProcessingLogger(logger ?? Logger.stderr(), silenceDeprecations: {...?silenceDeprecations}, fatalDeprecations: {...?fatalDeprecations}, futureDeprecations: {...?futureDeprecations}, @@ -120,8 +120,8 @@ CompileResult compileString(String source, Iterable? silenceDeprecations, Iterable? fatalDeprecations, Iterable? futureDeprecations}) { - DeprecationHandlingLogger deprecationLogger = logger = - DeprecationHandlingLogger(logger ?? Logger.stderr(), + DeprecationProcessingLogger deprecationLogger = logger = + DeprecationProcessingLogger(logger ?? Logger.stderr(), silenceDeprecations: {...?silenceDeprecations}, fatalDeprecations: {...?fatalDeprecations}, futureDeprecations: {...?futureDeprecations}, diff --git a/lib/src/embedded/logger.dart b/lib/src/embedded/logger.dart index 8166db5fc..dd1f2a223 100644 --- a/lib/src/embedded/logger.dart +++ b/lib/src/embedded/logger.dart @@ -15,7 +15,7 @@ import 'embedded_sass.pb.dart' hide SourceSpan; import 'utils.dart'; /// A Sass logger that sends log messages as `LogEvent`s. -final class EmbeddedLogger implements DeprecationLogger { +final class EmbeddedLogger extends LoggerWithDeprecationType { /// The [CompilationDispatcher] to which to send events. final CompilationDispatcher _dispatcher; @@ -40,19 +40,16 @@ final class EmbeddedLogger implements DeprecationLogger { ': $message\n'); } - void warn(String message, - {FileSpan? span, - Trace? trace, - bool deprecation = false, - Deprecation? deprecationType}) { + void internalWarn(String message, + {FileSpan? span, Trace? trace, Deprecation? deprecation}) { var formatted = withGlyphs(() { var buffer = StringBuffer(); if (_color) { buffer.write('\u001b[33m\u001b[1m'); - if (deprecation) buffer.write('Deprecation '); + if (deprecation != null) buffer.write('Deprecation '); buffer.write('Warning\u001b[0m'); } else { - if (deprecation) buffer.write('DEPRECATION '); + if (deprecation != null) buffer.write('DEPRECATION '); buffer.write('WARNING'); } if (span == null) { @@ -69,13 +66,14 @@ final class EmbeddedLogger implements DeprecationLogger { }, ascii: _ascii); var event = OutboundMessage_LogEvent() - ..type = - deprecation ? LogEventType.DEPRECATION_WARNING : LogEventType.WARNING + ..type = deprecation != null + ? LogEventType.DEPRECATION_WARNING + : LogEventType.WARNING ..message = message ..formatted = formatted; if (span != null) event.span = protofySpan(span); if (trace != null) event.stackTrace = trace.toString(); - if (deprecationType != null) event.deprecationType = deprecationType.id; + if (deprecation != null) event.deprecationType = deprecation.id; _dispatcher.sendLog(event); } } diff --git a/lib/src/executable/options.dart b/lib/src/executable/options.dart index c120d0300..155d456a0 100644 --- a/lib/src/executable/options.dart +++ b/lib/src/executable/options.dart @@ -95,9 +95,13 @@ final class ExecutableOptions { help: 'Deprecations to ignore.', allowedHelp: { for (var deprecation in Deprecation.values) - if (deprecation.deprecatedIn != null && - deprecation.description != null) - deprecation.id: deprecation.description!, + if (deprecation + case Deprecation( + deprecatedIn: Version(), + obsoleteIn: null, + :var description? + )) + deprecation.id: description, }) ..addMultiOption('fatal-deprecation', help: 'Deprecations to treat as errors. You may also pass a Sass\n' diff --git a/lib/src/js/compile.dart b/lib/src/js/compile.dart index 97cff0704..ab5c57cc0 100644 --- a/lib/src/js/compile.dart +++ b/lib/src/js/compile.dart @@ -359,6 +359,11 @@ List _parseFunctions(Object? functions, {bool asynch = false}) { return result; } +/// Parses a list of [deprecations] from JS into an list of Dart [Deprecation] +/// objects. +/// +/// [deprecations] can contain deprecation IDs, JS Deprecation objects, and +/// (if [supportVersions] is true) [Version]s. Iterable? _parseDeprecations( JSToDartLogger logger, List? deprecations, {bool supportVersions = false}) { diff --git a/lib/src/js/deprecations.dart b/lib/src/js/deprecations.dart index c48b5548c..db63720f9 100644 --- a/lib/src/js/deprecations.dart +++ b/lib/src/js/deprecations.dart @@ -27,17 +27,21 @@ class Deprecation { final Map deprecations = { for (var deprecation in dart.Deprecation.values) - deprecation.id: Deprecation( - id: deprecation.id, - status: (() => switch (deprecation) { - dart.Deprecation(isFuture: true) => 'future', - dart.Deprecation(deprecatedIn: null, obsoleteIn: null) => 'user', - dart.Deprecation(obsoleteIn: null) => 'active', - _ => 'obsolete' - })(), - description: deprecation.description, - deprecatedIn: deprecation.deprecatedIn, - obsoleteIn: deprecation.deprecatedIn), + // `calc-interp` was never actually used, so we don't want to expose it + // in the JS API. + if (deprecation != dart.Deprecation.calcInterp) + deprecation.id: Deprecation( + id: deprecation.id, + status: (() => switch (deprecation) { + dart.Deprecation(isFuture: true) => 'future', + dart.Deprecation(deprecatedIn: null, obsoleteIn: null) => + 'user', + dart.Deprecation(obsoleteIn: null) => 'active', + _ => 'obsolete' + })(), + description: deprecation.description, + deprecatedIn: deprecation.deprecatedIn, + obsoleteIn: deprecation.deprecatedIn), }; /// The JavaScript `Version` class. diff --git a/lib/src/logger.dart b/lib/src/logger.dart index 99cb5e10b..7569b6e7c 100644 --- a/lib/src/logger.dart +++ b/lib/src/logger.dart @@ -7,7 +7,7 @@ import 'package:source_span/source_span.dart'; import 'package:stack_trace/stack_trace.dart'; import 'deprecation.dart'; -import 'logger/deprecation_handling.dart'; +import 'logger/deprecation_processing.dart'; import 'logger/stderr.dart'; /// An interface for loggers that print messages produced by Sass stylesheets. @@ -37,25 +37,37 @@ abstract class Logger { void debug(String message, SourceSpan span); } -/// A logger interface that also handles deprecation types. +/// A base class for loggers that support the [Deprecation] object, rather than +/// just a boolean flag for whether a warnings is a deprecation warning or not. /// -/// This is only used internally by [DeprecationHandlingLogger] and -/// [JSToDartLogger]. In Dart Sass 2.0, we can get rid of this and just add -/// it as a breaking change to [Logger]. +/// In Dart Sass 2.0.0, we will eliminate this interface and change +/// [Logger.warn]'s signature to match that of [internalWarn]. This is used +/// in the meantime to provide access to the [Deprecation] object to internal +/// loggers. +/// +/// Implementers should override the protected [internalWarn] method instead of +/// [warn]. @internal -abstract class DeprecationLogger implements Logger { - /// Emits a warning with the given [message]. +abstract class LoggerWithDeprecationType implements Logger { + /// This forwards all calls to [internalWarn]. /// - /// If [span] is passed, it's the location in the Sass source that generated - /// the warning. If [trace] is passed, it's the Sass stack trace when the - /// warning was issued. If [deprecation] is `true`, it indicates that this is - /// a deprecation warning with type [deprecationType]. Implementations should - /// surface all this information to the end user. + /// For non-user deprecation warnings, the [warnForDeprecation] extension + /// method should be called instead. void warn(String message, - {FileSpan? span, - Trace? trace, - bool deprecation = false, - Deprecation? deprecationType}); + {FileSpan? span, Trace? trace, bool deprecation = false}) { + internalWarn(message, + span: span, + trace: trace, + deprecation: deprecation ? Deprecation.userAuthored : null); + } + + /// Equivalent to [Logger.warn], but for internal loggers that support + /// the [Deprecation] object. + /// + /// Subclasses of this logger should override this method instead of [warn]. + @protected + void internalWarn(String message, + {FileSpan? span, Trace? trace, Deprecation? deprecation}); } /// An extension to add a `warnForDeprecation` method to loggers without @@ -65,13 +77,10 @@ extension WarnForDeprecation on Logger { /// Emits a deprecation warning for [deprecation] with the given [message]. void warnForDeprecation(Deprecation deprecation, String message, {FileSpan? span, Trace? trace}) { - if (deprecation.isFuture && this is! DeprecationHandlingLogger) return; - if (this case DeprecationLogger self) { - self.warn(message, - span: span, - trace: trace, - deprecation: true, - deprecationType: deprecation); + if (deprecation.isFuture && this is! DeprecationProcessingLogger) return; + if (this case LoggerWithDeprecationType self) { + self.internalWarn(message, + span: span, trace: trace, deprecation: deprecation); } else { warn(message, span: span, trace: trace, deprecation: true); } diff --git a/lib/src/logger/deprecation_handling.dart b/lib/src/logger/deprecation_processing.dart similarity index 69% rename from lib/src/logger/deprecation_handling.dart rename to lib/src/logger/deprecation_processing.dart index 488212f58..37bd4464f 100644 --- a/lib/src/logger/deprecation_handling.dart +++ b/lib/src/logger/deprecation_processing.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. import 'package:collection/collection.dart'; +import 'package:pub_semver/pub_semver.dart'; import 'package:source_span/source_span.dart'; import 'package:stack_trace/stack_trace.dart'; @@ -11,12 +12,13 @@ import '../exception.dart'; import '../logger.dart'; /// The maximum number of repetitions of the same warning -/// [DeprecationHandlingLogger] will emit before hiding the rest. +/// [DeprecationProcessingLogger] will emit before hiding the rest. const _maxRepetitions = 5; /// A logger that wraps an inner logger to have special handling for -/// deprecation warnings. -final class DeprecationHandlingLogger implements DeprecationLogger { +/// deprecation warnings, silencing, making fatal, enabling future, and/or +/// limiting repetition based on its inputs. +final class DeprecationProcessingLogger extends LoggerWithDeprecationType { /// A map of how many times each deprecation has been emitted by this logger. final _warningCounts = {}; @@ -39,39 +41,47 @@ final class DeprecationHandlingLogger implements DeprecationLogger { /// [_maxRepetitions]. final bool limitRepetition; - DeprecationHandlingLogger(this._inner, + DeprecationProcessingLogger(this._inner, {required this.silenceDeprecations, required this.fatalDeprecations, required this.futureDeprecations, this.limitRepetition = true}) { for (var deprecation in fatalDeprecations) { - if (deprecation.isFuture && !futureDeprecations.contains(deprecation)) { - warn('Future $deprecation deprecation must be enabled before it can be ' - 'made fatal.'); - } else if (deprecation.obsoleteIn != null) { - warn('$deprecation deprecation is obsolete, so does not need to be ' - 'made fatal.'); - } else if (silenceDeprecations.contains(deprecation)) { - warn('Ignoring setting to silence $deprecation deprecation, since it ' - 'has also been made fatal.'); + switch (deprecation) { + case Deprecation(isFuture: true) + when !futureDeprecations.contains(deprecation): + warn('Future $deprecation deprecation must be enabled before it can ' + 'be made fatal.'); + case Deprecation(obsoleteIn: Version()): + warn('$deprecation deprecation is obsolete, so does not need to be ' + 'made fatal.'); + case _ when silenceDeprecations.contains(deprecation): + warn('Ignoring setting to silence $deprecation deprecation, since it ' + 'has also been made fatal.'); + default: + // No warning. } } + for (var deprecation in silenceDeprecations) { - if (deprecation == Deprecation.userAuthored) { - warn('User-authored deprecations should not be silenced.'); - } else if (deprecation.obsoleteIn != null) { - warn('$deprecation deprecation is obsolete. If you were previously ' - 'silencing it, your code may now behave in unexpected ways.'); - } else if (deprecation.isFuture) { - if (futureDeprecations.contains(deprecation)) { + switch (deprecation) { + case Deprecation.userAuthored: + warn('User-authored deprecations should not be silenced.'); + case Deprecation(obsoleteIn: Version()): + warn('$deprecation deprecation is obsolete. If you were previously ' + 'silencing it, your code may now behave in unexpected ways.'); + case Deprecation(isFuture: true) + when futureDeprecations.contains(deprecation): warn('Conflicting options for future $deprecation deprecation cancel ' 'each other out.'); - } else { + case Deprecation(isFuture: true): warn('Future $deprecation deprecation is not yet active, so ' 'silencing it is unnecessary.'); - } + default: + // No warning. } } + for (var deprecation in futureDeprecations) { if (!deprecation.isFuture) { warn('$deprecation is not a future deprecation, so it does not need to ' @@ -80,13 +90,10 @@ final class DeprecationHandlingLogger implements DeprecationLogger { } } - void warn(String message, - {FileSpan? span, - Trace? trace, - bool deprecation = false, - Deprecation? deprecationType}) { - if (deprecation && deprecationType != null) { - _handleDeprecation(deprecationType, message, span: span, trace: trace); + void internalWarn(String message, + {FileSpan? span, Trace? trace, Deprecation? deprecation}) { + if (deprecation != null) { + _handleDeprecation(deprecation, message, span: span, trace: trace); } else { _inner.warn(message, span: span, trace: trace); } @@ -125,12 +132,9 @@ final class DeprecationHandlingLogger implements DeprecationLogger { if (count > _maxRepetitions) return; } - if (_inner case DeprecationLogger inner) { - inner.warn(message, - span: span, - trace: trace, - deprecation: true, - deprecationType: deprecation); + if (_inner case LoggerWithDeprecationType inner) { + inner.internalWarn(message, + span: span, trace: trace, deprecation: deprecation); } else { _inner.warn(message, span: span, trace: trace, deprecation: true); } diff --git a/lib/src/logger/js_to_dart.dart b/lib/src/logger/js_to_dart.dart index 415352c13..4a11bf546 100644 --- a/lib/src/logger/js_to_dart.dart +++ b/lib/src/logger/js_to_dart.dart @@ -13,7 +13,7 @@ import '../js/deprecations.dart' show deprecations; import '../js/logger.dart'; /// A wrapper around a [JSLogger] that exposes it as a Dart [Logger]. -final class JSToDartLogger implements DeprecationLogger { +final class JSToDartLogger extends LoggerWithDeprecationType { /// The wrapped logger object. final JSLogger? _node; @@ -29,23 +29,20 @@ final class JSToDartLogger implements DeprecationLogger { JSToDartLogger(this._node, this._fallback, {bool? ascii}) : _ascii = ascii ?? glyph.ascii; - void warn(String message, - {FileSpan? span, - Trace? trace, - bool deprecation = false, - Deprecation? deprecationType}) { + void internalWarn(String message, + {FileSpan? span, Trace? trace, Deprecation? deprecation}) { if (_node?.warn case var warn?) { warn( message, WarnOptions( span: span ?? (undefined as SourceSpan?), stack: trace.toString(), - deprecation: deprecation, - deprecationType: deprecations[deprecationType?.id])); + deprecation: deprecation != null, + deprecationType: deprecations[deprecation?.id])); } else { _withAscii(() { _fallback.warn(message, - span: span, trace: trace, deprecation: deprecation); + span: span, trace: trace, deprecation: deprecation != null); }); } } diff --git a/test/embedded/utils.dart b/test/embedded/utils.dart index eae637a92..7741706d6 100644 --- a/test/embedded/utils.dart +++ b/test/embedded/utils.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:sass/src/embedded/embedded_sass.pb.dart'; import 'package:sass/src/embedded/utils.dart'; +import 'package:sass/src/util/nullable.dart'; import 'embedded_process.dart'; @@ -16,23 +17,21 @@ const defaultCompilationId = 4321; /// Returns a (compilation ID, [InboundMessage]) pair that compiles the given /// plain CSS string. -InboundMessage compileString( - String css, { - int? id, - bool? alertColor, - bool? alertAscii, - Syntax? syntax, - OutputStyle? style, - String? url, - bool? sourceMap, - bool? sourceMapIncludeSources, - Iterable? importers, - InboundMessage_CompileRequest_Importer? importer, - Iterable? functions, - Iterable? fatalDeprecations, - Iterable? futureDeprecations, - Iterable? silenceDeprecations, -}) { +InboundMessage compileString(String css, + {int? id, + bool? alertColor, + bool? alertAscii, + Syntax? syntax, + OutputStyle? style, + String? url, + bool? sourceMap, + bool? sourceMapIncludeSources, + Iterable? importers, + InboundMessage_CompileRequest_Importer? importer, + Iterable? functions, + Iterable? fatalDeprecations, + Iterable? futureDeprecations, + Iterable? silenceDeprecations}) { var input = InboundMessage_CompileRequest_StringInput()..source = css; if (syntax != null) input.syntax = syntax; if (url != null) input.url = url; @@ -48,15 +47,9 @@ InboundMessage compileString( if (functions != null) request.globalFunctions.addAll(functions); if (alertColor != null) request.alertColor = alertColor; if (alertAscii != null) request.alertAscii = alertAscii; - if (fatalDeprecations != null) { - request.fatalDeprecation.addAll(fatalDeprecations); - } - if (futureDeprecations != null) { - request.futureDeprecation.addAll(futureDeprecations); - } - if (silenceDeprecations != null) { - request.silenceDeprecation.addAll(silenceDeprecations); - } + fatalDeprecations.andThen(request.fatalDeprecation.addAll); + futureDeprecations.andThen(request.futureDeprecation.addAll); + silenceDeprecations.andThen(request.silenceDeprecation.addAll); return InboundMessage()..compileRequest = request; } From aa37f3f4bf2796fb17a8f0fdc010fbbea0a6d9f3 Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Wed, 3 Apr 2024 02:01:18 +0000 Subject: [PATCH 09/10] synchronize --- lib/src/compile.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/compile.dart b/lib/src/compile.dart index 594532200..5a7fe54f2 100644 --- a/lib/src/compile.dart +++ b/lib/src/compile.dart @@ -5,7 +5,7 @@ // DO NOT EDIT. This file was generated from async_compile.dart. // See tool/grind/synchronize.dart for details. // -// Checksum: 9d2d66aa8a5b5613cbae25c448356526aebbadbf +// Checksum: ab2c6fa2588988a86abdbe87512134098e01b39e // // ignore_for_file: unused_import From ae664f76296c4b585ede8831e7ace6f7b7c3cb4f Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Wed, 3 Apr 2024 20:58:53 +0000 Subject: [PATCH 10/10] Shorten help text --- lib/src/executable/options.dart | 37 +++------------------------------ lib/src/js/deprecations.dart | 10 +++++++-- 2 files changed, 11 insertions(+), 36 deletions(-) diff --git a/lib/src/executable/options.dart b/lib/src/executable/options.dart index 155d456a0..c0aeaa077 100644 --- a/lib/src/executable/options.dart +++ b/lib/src/executable/options.dart @@ -91,45 +91,14 @@ final class ExecutableOptions { "Stylesheets imported through load paths count as dependencies.") ..addFlag('verbose', help: "Print all deprecation warnings even when they're repetitive.") - ..addMultiOption('silence-deprecation', - help: 'Deprecations to ignore.', - allowedHelp: { - for (var deprecation in Deprecation.values) - if (deprecation - case Deprecation( - deprecatedIn: Version(), - obsoleteIn: null, - :var description? - )) - deprecation.id: description, - }) ..addMultiOption('fatal-deprecation', help: 'Deprecations to treat as errors. You may also pass a Sass\n' 'version to include any behavior deprecated in or before it.\n' 'See https://sass-lang.com/documentation/breaking-changes for \n' - 'a complete list.', - allowedHelp: { - for (var deprecation in Deprecation.values) - if (deprecation - case Deprecation( - deprecatedIn: _?, - :var id, - :var description? - )) - id: description - }) + 'a complete list.') + ..addMultiOption('silence-deprecation', help: 'Deprecations to ignore.') ..addMultiOption('future-deprecation', - help: 'Opt in to a deprecation early.', - allowedHelp: { - for (var deprecation in Deprecation.values) - if (deprecation - case Deprecation( - deprecatedIn: null, - :var id, - :var description? - )) - id: description - }); + help: 'Opt in to a deprecation early.'); parser ..addSeparator(_separator('Other')) diff --git a/lib/src/js/deprecations.dart b/lib/src/js/deprecations.dart index db63720f9..51e3aec1a 100644 --- a/lib/src/js/deprecations.dart +++ b/lib/src/js/deprecations.dart @@ -51,8 +51,14 @@ final JSClass versionClass = () { return Version(major, minor, patch); }); - jsClass.defineStaticMethod( - 'parse', (String version) => Version.parse(version)); + jsClass.defineStaticMethod('parse', (String version) { + var v = Version.parse(version); + if (v.isPreRelease || v.build.isNotEmpty) { + throw FormatException( + 'Build identifiers and prerelease versions not supported.'); + } + return v; + }); getJSClass(Version(0, 0, 0)).injectSuperclass(jsClass); return jsClass;