diff --git a/.gitignore b/.gitignore index 2c61888e5..0abc5ef70 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,6 @@ node_modules/ /doc/api /pkg/*/doc/api -# Generated protocol buffer files. +# Generated Dart files. *.pb*.dart +*.g.dart diff --git a/.pubignore b/.pubignore index 2fbab300a..08992ce75 100644 --- a/.pubignore +++ b/.pubignore @@ -1,5 +1,5 @@ # This should be identical to .gitignore except that it doesn't exclude -# generated protobuf files. +# generated Dart files. .buildlog .DS_Store diff --git a/lib/sass.dart b/lib/sass.dart index eb58adc4f..b9aaa0a1c 100644 --- a/lib/sass.dart +++ b/lib/sass.dart @@ -13,7 +13,7 @@ import 'src/async_import_cache.dart'; import 'src/callable.dart'; import 'src/compile.dart' as c; import 'src/compile_result.dart'; -import 'src/deprecation.dart'; +import 'src/deprecation.g.dart'; import 'src/exception.dart'; import 'src/import_cache.dart'; import 'src/importer.dart'; @@ -25,7 +25,7 @@ import 'src/visitor/serialize.dart'; export 'src/callable.dart' show Callable, AsyncCallable; export 'src/compile_result.dart'; -export 'src/deprecation.dart'; +export 'src/deprecation.g.dart'; export 'src/exception.dart' show SassException; export 'src/importer.dart'; export 'src/logger.dart' show Logger; diff --git a/lib/src/ast/selector.dart b/lib/src/ast/selector.dart index 953ccf7aa..05f44fcdc 100644 --- a/lib/src/ast/selector.dart +++ b/lib/src/ast/selector.dart @@ -5,7 +5,7 @@ import 'package:meta/meta.dart'; import 'package:source_span/source_span.dart'; -import '../deprecation.dart'; +import '../deprecation.g.dart'; import '../evaluation_context.dart'; import '../exception.dart'; import '../visitor/any_selector.dart'; diff --git a/lib/src/async_compile.dart b/lib/src/async_compile.dart index 063f3d2dc..b7e96f97e 100644 --- a/lib/src/async_compile.dart +++ b/lib/src/async_compile.dart @@ -11,7 +11,7 @@ import 'ast/sass.dart'; import 'async_import_cache.dart'; import 'callable.dart'; import 'compile_result.dart'; -import 'deprecation.dart'; +import 'deprecation.g.dart'; import 'importer.dart'; import 'importer/legacy_node.dart'; import 'importer/no_op.dart'; diff --git a/lib/src/async_import_cache.dart b/lib/src/async_import_cache.dart index 6d6e4fa8c..1513cb2e6 100644 --- a/lib/src/async_import_cache.dart +++ b/lib/src/async_import_cache.dart @@ -9,7 +9,7 @@ import 'package:package_config/package_config_types.dart'; import 'package:path/path.dart' as p; import 'ast/sass.dart'; -import 'deprecation.dart'; +import 'deprecation.g.dart'; import 'importer.dart'; import 'importer/canonicalize_context.dart'; import 'importer/no_op.dart'; diff --git a/lib/src/compile.dart b/lib/src/compile.dart index 5a7fe54f2..58e20b773 100644 --- a/lib/src/compile.dart +++ b/lib/src/compile.dart @@ -20,7 +20,7 @@ import 'ast/sass.dart'; import 'import_cache.dart'; import 'callable.dart'; import 'compile_result.dart'; -import 'deprecation.dart'; +import 'deprecation.g.dart'; import 'importer.dart'; import 'importer/legacy_node.dart'; import 'importer/no_op.dart'; diff --git a/lib/src/embedded/logger.dart b/lib/src/embedded/logger.dart index dd1f2a223..fff3c5128 100644 --- a/lib/src/embedded/logger.dart +++ b/lib/src/embedded/logger.dart @@ -6,7 +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 '../deprecation.g.dart'; import '../logger.dart'; import '../util/nullable.dart'; import '../utils.dart'; diff --git a/lib/src/evaluation_context.dart b/lib/src/evaluation_context.dart index 30b3852f9..fe957707d 100644 --- a/lib/src/evaluation_context.dart +++ b/lib/src/evaluation_context.dart @@ -6,7 +6,7 @@ import 'dart:async'; import 'package:source_span/source_span.dart'; -import 'deprecation.dart'; +import 'deprecation.g.dart'; import 'logger.dart'; /// An interface that exposes information about the current Sass evaluation. diff --git a/lib/src/functions/color.dart b/lib/src/functions/color.dart index f71c8080f..85923db89 100644 --- a/lib/src/functions/color.dart +++ b/lib/src/functions/color.dart @@ -7,7 +7,7 @@ import 'dart:collection'; import 'package:collection/collection.dart'; import '../callable.dart'; -import '../deprecation.dart'; +import '../deprecation.g.dart'; import '../evaluation_context.dart'; import '../exception.dart'; import '../module/built_in.dart'; diff --git a/lib/src/functions/math.dart b/lib/src/functions/math.dart index bca609d0d..fc9df438a 100644 --- a/lib/src/functions/math.dart +++ b/lib/src/functions/math.dart @@ -8,7 +8,7 @@ import 'dart:math' as math; import 'package:collection/collection.dart'; import '../callable.dart'; -import '../deprecation.dart'; +import '../deprecation.g.dart'; import '../evaluation_context.dart'; import '../exception.dart'; import '../module/built_in.dart'; diff --git a/lib/src/import_cache.dart b/lib/src/import_cache.dart index 9590b0e5a..8c27cae90 100644 --- a/lib/src/import_cache.dart +++ b/lib/src/import_cache.dart @@ -16,7 +16,7 @@ import 'package:package_config/package_config_types.dart'; import 'package:path/path.dart' as p; import 'ast/sass.dart'; -import 'deprecation.dart'; +import 'deprecation.g.dart'; import 'importer.dart'; import 'importer/canonicalize_context.dart'; import 'importer/no_op.dart'; diff --git a/lib/src/importer/filesystem.dart b/lib/src/importer/filesystem.dart index cb23d3095..ae5f71797 100644 --- a/lib/src/importer/filesystem.dart +++ b/lib/src/importer/filesystem.dart @@ -5,7 +5,7 @@ import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; -import '../deprecation.dart'; +import '../deprecation.g.dart'; import '../evaluation_context.dart'; import '../importer.dart'; import '../io.dart' as io; diff --git a/lib/src/js/deprecations.dart b/lib/src/js/deprecations.dart index 51e3aec1a..ac665a9e1 100644 --- a/lib/src/js/deprecations.dart +++ b/lib/src/js/deprecations.dart @@ -5,7 +5,7 @@ import 'package:js/js.dart'; import 'package:pub_semver/pub_semver.dart'; -import '../deprecation.dart' as dart show Deprecation; +import '../deprecation.g.dart' as dart show Deprecation; import 'reflection.dart'; @JS() diff --git a/lib/src/logger.dart b/lib/src/logger.dart index 7569b6e7c..d387931ac 100644 --- a/lib/src/logger.dart +++ b/lib/src/logger.dart @@ -6,7 +6,7 @@ import 'package:meta/meta.dart'; import 'package:source_span/source_span.dart'; import 'package:stack_trace/stack_trace.dart'; -import 'deprecation.dart'; +import 'deprecation.g.dart'; import 'logger/deprecation_processing.dart'; import 'logger/stderr.dart'; diff --git a/lib/src/logger/deprecation_processing.dart b/lib/src/logger/deprecation_processing.dart index 37bd4464f..8d3199bdc 100644 --- a/lib/src/logger/deprecation_processing.dart +++ b/lib/src/logger/deprecation_processing.dart @@ -7,7 +7,7 @@ import 'package:pub_semver/pub_semver.dart'; import 'package:source_span/source_span.dart'; import 'package:stack_trace/stack_trace.dart'; -import '../deprecation.dart'; +import '../deprecation.g.dart'; import '../exception.dart'; import '../logger.dart'; diff --git a/lib/src/logger/js_to_dart.dart b/lib/src/logger/js_to_dart.dart index 4a11bf546..eae14972d 100644 --- a/lib/src/logger/js_to_dart.dart +++ b/lib/src/logger/js_to_dart.dart @@ -7,7 +7,7 @@ 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 '../deprecation.g.dart'; import '../logger.dart'; import '../js/deprecations.dart' show deprecations; import '../js/logger.dart'; diff --git a/lib/src/parse/scss.dart b/lib/src/parse/scss.dart index 67b5c0f4b..bce0416b5 100644 --- a/lib/src/parse/scss.dart +++ b/lib/src/parse/scss.dart @@ -5,7 +5,7 @@ import 'package:charcode/charcode.dart'; import '../ast/sass.dart'; -import '../deprecation.dart'; +import '../deprecation.g.dart'; import '../interpolation_buffer.dart'; import '../logger.dart'; import '../util/character.dart'; diff --git a/lib/src/parse/stylesheet.dart b/lib/src/parse/stylesheet.dart index e72e2527b..1d88aaf5c 100644 --- a/lib/src/parse/stylesheet.dart +++ b/lib/src/parse/stylesheet.dart @@ -10,7 +10,7 @@ import 'package:string_scanner/string_scanner.dart'; import '../ast/sass.dart'; import '../color_names.dart'; -import '../deprecation.dart'; +import '../deprecation.g.dart'; import '../exception.dart'; import '../interpolation_buffer.dart'; import '../logger.dart'; @@ -235,7 +235,7 @@ abstract class StylesheetParser extends Parser { case 'default': if (guarded) { logger.warnForDeprecation( - Deprecation.duplicateVariableFlags, + Deprecation.duplicateVarFlags, '!default should only be written once for each variable.\n' 'This will be an error in Dart Sass 2.0.0.', span: scanner.spanFrom(flagStart)); @@ -248,7 +248,7 @@ abstract class StylesheetParser extends Parser { scanner.spanFrom(flagStart)); } else if (global) { logger.warnForDeprecation( - Deprecation.duplicateVariableFlags, + Deprecation.duplicateVarFlags, '!global should only be written once for each variable.\n' 'This will be an error in Dart Sass 2.0.0.', span: scanner.spanFrom(flagStart)); diff --git a/lib/src/value.dart b/lib/src/value.dart index 3149435a0..43f9d721d 100644 --- a/lib/src/value.dart +++ b/lib/src/value.dart @@ -5,7 +5,7 @@ import 'package:meta/meta.dart'; import 'ast/selector.dart'; -import 'deprecation.dart'; +import 'deprecation.g.dart'; import 'evaluation_context.dart'; import 'exception.dart'; import 'utils.dart'; diff --git a/lib/src/value/calculation.dart b/lib/src/value/calculation.dart index cbb8b92e6..46efe32ca 100644 --- a/lib/src/value/calculation.dart +++ b/lib/src/value/calculation.dart @@ -7,7 +7,7 @@ import 'dart:math' as math; import 'package:charcode/charcode.dart'; import 'package:meta/meta.dart'; -import '../deprecation.dart'; +import '../deprecation.g.dart'; import '../evaluation_context.dart'; import '../exception.dart'; import '../callable.dart'; diff --git a/lib/src/value/color.dart b/lib/src/value/color.dart index 8df328564..0b31a174b 100644 --- a/lib/src/value/color.dart +++ b/lib/src/value/color.dart @@ -8,7 +8,7 @@ import 'package:cli_pkg/js.dart'; import 'package:meta/meta.dart'; import 'package:source_span/source_span.dart'; -import '../deprecation.dart'; +import '../deprecation.g.dart'; import '../evaluation_context.dart'; import '../exception.dart'; import '../util/number.dart'; diff --git a/lib/src/visitor/async_evaluate.dart b/lib/src/visitor/async_evaluate.dart index b8434ff47..5ee6f7099 100644 --- a/lib/src/visitor/async_evaluate.dart +++ b/lib/src/visitor/async_evaluate.dart @@ -24,7 +24,7 @@ import '../callable.dart'; import '../color_names.dart'; import '../configuration.dart'; import '../configured_value.dart'; -import '../deprecation.dart'; +import '../deprecation.g.dart'; import '../evaluation_context.dart'; import '../exception.dart'; import '../extend/extension_store.dart'; diff --git a/lib/src/visitor/evaluate.dart b/lib/src/visitor/evaluate.dart index 1680be88e..4c31212fd 100644 --- a/lib/src/visitor/evaluate.dart +++ b/lib/src/visitor/evaluate.dart @@ -33,7 +33,7 @@ import '../callable.dart'; import '../color_names.dart'; import '../configuration.dart'; import '../configured_value.dart'; -import '../deprecation.dart'; +import '../deprecation.g.dart'; import '../evaluation_context.dart'; import '../exception.dart'; import '../extend/extension_store.dart'; diff --git a/tool/grind.dart b/tool/grind.dart index 631bdebdf..11a8023bf 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -11,6 +11,7 @@ import 'package:grinder/grinder.dart'; import 'package:path/path.dart' as p; import 'package:source_span/source_span.dart'; +import 'grind/generate_deprecations.dart'; import 'grind/synchronize.dart'; import 'grind/utils.dart'; @@ -140,7 +141,7 @@ void npmInstall() => run(Platform.isWindows ? "npm.cmd" : "npm", arguments: ["install"]); @Task('Runs the tasks that are required for running tests.') -@Depends(format, synchronize, protobuf, "pkg-npm-dev", npmInstall, +@Depends(format, synchronize, protobuf, deprecations, "pkg-npm-dev", npmInstall, "pkg-standalone-dev") void beforeTest() {} @@ -213,9 +214,9 @@ String _readAndResolveMarkdown(String path) => File(path) /// Returns a map from JS type declaration file names to their contnets. Map _fetchJSTypes() { - var languageRepo = _updateLanguageRepo(); + updateLanguageRepo(); - var typeRoot = p.join(languageRepo, 'js-api-doc'); + var typeRoot = p.join('build/language', 'js-api-doc'); return { for (var entry in Directory(typeRoot).listSync(recursive: true)) if (entry is File && entry.path.endsWith('.d.ts')) @@ -231,6 +232,7 @@ void _matchError(Match match, String message, {Object? url}) { } @Task('Compile the protocol buffer definition to a Dart library.') +@Depends(updateLanguageRepo) Future protobuf() async { Directory('build').createSync(recursive: true); @@ -250,8 +252,6 @@ dart run protoc_plugin "\$@" run('chmod', arguments: ['a+x', 'build/protoc-gen-dart']); } - _updateLanguageRepo(); - await runAsync("buf", arguments: ["generate"], runOptions: RunOptions(environment: { @@ -261,6 +261,12 @@ dart run protoc_plugin "\$@" })); } +@Task('Generate deprecation.g.dart from the list in the language repo.') +@Depends(updateLanguageRepo) +Future deprecations() async { + updateDeprecationFile(File('build/language/spec/deprecations.yaml')); +} + /// After building the NPM package, add default exports to /// `build/npm/sass.node.mjs`. /// @@ -322,18 +328,19 @@ String _updateHomebrewLanguageRevision(String formula) { formula.substring(match.end); } -/// Clones the main branch of `github.com/sass/sass` and returns the path to the -/// clone. +/// Clones the main branch of `github.com/sass/sass`. /// /// If the `UPDATE_SASS_SASS_REPO` environment variable is `false`, this instead /// assumes the repo that already exists at `build/language/sass`. /// `UPDATE_SASS_PROTOCOL` is also checked as a deprecated alias for /// `UPDATE_SASS_SASS_REPO`. -String _updateLanguageRepo() => - // UPDATE_SASS_PROTOCOL is considered deprecated, because it doesn't apply as - // generically to other tasks. - Platform.environment['UPDATE_SASS_SASS_REPO'] != 'false' && - Platform.environment['UPDATE_SASS_PROTOCOL'] != 'false' - ? cloneOrCheckout("https://github.com/sass/sass.git", "main", - name: 'language') - : 'build/language'; +@Task('Clones the main branch of `github.com/sass/sass` if necessary.') +void updateLanguageRepo() { + // UPDATE_SASS_PROTOCOL is considered deprecated, because it doesn't apply as + // generically to other tasks. + if (Platform.environment['UPDATE_SASS_SASS_REPO'] != 'false' && + Platform.environment['UPDATE_SASS_PROTOCOL'] != 'false') { + cloneOrCheckout("https://github.com/sass/sass.git", "main", + name: 'language'); + } +} diff --git a/lib/src/deprecation.dart b/tool/grind/deprecation.dart.template similarity index 51% rename from lib/src/deprecation.dart rename to tool/grind/deprecation.dart.template index b13180e10..d05da5f9a 100644 --- a/lib/src/deprecation.dart +++ b/tool/grind/deprecation.dart.template @@ -1,7 +1,9 @@ -// Copyright 2022 Google LLC. Use of this source code is governed by an +// Copyright 2024 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. +// CHECKSUM + import 'package:cli_pkg/js.dart'; import 'package:collection/collection.dart'; import 'package:pub_semver/pub_semver.dart'; @@ -10,82 +12,17 @@ import 'util/nullable.dart'; /// A deprecated feature in the language. enum Deprecation { - /// Deprecation for passing a string to `call` instead of `get-function`. - callString('call-string', - deprecatedIn: '0.0.0', - description: 'Passing a string directly to meta.call().'), - - /// Deprecation for `@elseif`. - elseif('elseif', deprecatedIn: '1.3.2', description: '@elseif.'), - - /// Deprecation for parsing `@-moz-document`. - mozDocument('moz-document', - deprecatedIn: '1.7.2', description: '@-moz-document.'), - - /// Deprecation for importers using relative canonical URLs. - relativeCanonical('relative-canonical', deprecatedIn: '1.14.2'), - - /// Deprecation for declaring new variables with `!global`. - newGlobal('new-global', - deprecatedIn: '1.17.2', - description: 'Declaring new variables with !global.'), - - /// Deprecation for certain functions in the color module matching the - /// behavior of their global counterparts for compatiblity reasons. - colorModuleCompat('color-module-compat', - deprecatedIn: '1.23.0', - description: - 'Using color module functions in place of plain CSS functions.'), - - /// Deprecation for treating `/` as division. - slashDiv('slash-div', - deprecatedIn: '1.33.0', description: '/ operator for division.'), - - /// Deprecation for leading, trailing, and repeated combinators. - bogusCombinators('bogus-combinators', - deprecatedIn: '1.54.0', - description: 'Leading, trailing, and repeated combinators.'), - - /// Deprecation for ambiguous `+` and `-` operators. - strictUnary('strict-unary', - deprecatedIn: '1.55.0', description: 'Ambiguous + and - operators.'), - - /// Deprecation for passing invalid units to certain built-in functions. - functionUnits('function-units', - deprecatedIn: '1.56.0', - description: 'Passing invalid units to built-in functions.'), - - /// Deprecation for passing percentages to the Sass abs() function. - absPercent('abs-percent', - deprecatedIn: '1.65.0', - description: 'Passing percentages to the Sass abs() function.'), - - duplicateVariableFlags('duplicate-var-flags', - deprecatedIn: '1.62.0', - description: - 'Using !default or !global multiple times for one variable.'), - - nullAlpha('null-alpha', - deprecatedIn: '1.62.3', - description: 'Passing null as alpha in the ${isJS ? 'JS' : 'Dart'} API.'), - - fsImporterCwd('fs-importer-cwd', - deprecatedIn: '1.73.0', - description: - 'Using the current working directory as an implicit load path.'), - - cssFunctionMixin('css-function-mixin', - deprecatedIn: '1.76.0', - description: 'Function and mixin names beginning with --.'), + // REPLACE WITH AUTOGENERATED LIST + + /// Used for deprecations coming from user-authored code. + userAuthored('user-authored', deprecatedIn: null), @Deprecated('This deprecation name was never actually used.') - calcInterp('calc-interp', deprecatedIn: null), + calcInterp('calc-interp', deprecatedIn: null); - /// Deprecation for `@import` rules. - import.future('import', description: '@import rules.'), + @Deprecated('Use duplicateVarFlags instead.') + static const duplicateVariableFlags = duplicateVarFlags; - /// Used for deprecations coming from user-authored code. - userAuthored('user-authored', deprecatedIn: null); /// A unique ID for this deprecation in kebab case. /// diff --git a/tool/grind/generate_deprecations.dart b/tool/grind/generate_deprecations.dart new file mode 100644 index 000000000..c3f416889 --- /dev/null +++ b/tool/grind/generate_deprecations.dart @@ -0,0 +1,66 @@ +// Copyright 2024 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 'dart:convert'; +import 'dart:io'; + +import 'package:crypto/crypto.dart'; +import 'package:dart_style/dart_style.dart'; +import 'package:yaml/yaml.dart'; + +void updateDeprecationFile(File yamlFile) { + var yamlText = yamlFile.readAsStringSync(); + var data = loadYaml(yamlText) as Map; + var template = + File('tool/grind/deprecation.dart.template').readAsStringSync(); + var buffer = StringBuffer(); + for (var MapEntry(:String key, :value) in data.entries) { + var camelCase = key.replaceAllMapped( + RegExp(r'-(.)'), (match) => match.group(1)!.toUpperCase()); + var (description, deprecatedIn, obsoleteIn) = switch (value) { + { + 'description': String description, + 'dart-sass': {'status': 'future'}, + } => + (description, null, null), + { + 'description': String description, + 'dart-sass': {'status': 'active', 'deprecated': String deprecatedIn}, + } => + (description, deprecatedIn, null), + { + 'description': String description, + 'dart-sass': { + 'status': 'obsolete', + 'deprecated': String deprecatedIn, + 'obsolete': String obsoleteIn + }, + } => + (description, deprecatedIn, obsoleteIn), + _ => throw Exception('Invalid deprecation $key: $value') + }; + description = + description.replaceAll(r'$PLATFORM', r"${isJS ? 'JS': 'Dart'}"); + var constructorName = deprecatedIn == null ? '.future' : ''; + var deprecatedClause = + deprecatedIn == null ? '' : "deprecatedIn: '$deprecatedIn', "; + var obsoleteClause = + obsoleteIn == null ? '' : "obsoleteIn: '$obsoleteIn', "; + var comment = 'Deprecation for ${description.substring(0, 1).toLowerCase()}' + '${description.substring(1)}'; + buffer.writeln('/// $comment'); + buffer.writeln( + "$camelCase$constructorName('$key', $deprecatedClause$obsoleteClause" + "description: '$description'),"); + } + var code = template + .replaceFirst('// REPLACE WITH AUTOGENERATED LIST', buffer.toString()) + .replaceFirst('// CHECKSUM', + '''// DO NOT EDIT. This file was generated from the spec repo. +// See tool/grind/generate_deprecations.dart for details. +// +// Checksum: ${sha1.convert(utf8.encode(yamlText))}'''); + File('lib/src/deprecation.g.dart') + .writeAsStringSync(DartFormatter().format(code)); +}