mirror of
https://github.com/danog/dart-sass.git
synced 2025-01-21 21:31:11 +01:00
Give Module a type parameter rather than making it synchronized (#686)
This allows us to have one fewer synchronized file, which reduces complexity, and also lets us just write "Module" in async code rather than "AsyncModule".
This commit is contained in:
parent
2fca9e32f4
commit
2317be8812
@ -9,11 +9,11 @@ import 'package:source_span/source_span.dart';
|
||||
|
||||
import 'ast/css.dart';
|
||||
import 'ast/node.dart';
|
||||
import 'async_module.dart';
|
||||
import 'callable.dart';
|
||||
import 'exception.dart';
|
||||
import 'extend/extender.dart';
|
||||
import 'functions.dart';
|
||||
import 'module.dart';
|
||||
import 'util/public_member_map.dart';
|
||||
import 'utils.dart';
|
||||
import 'value.dart';
|
||||
@ -25,16 +25,16 @@ import 'visitor/clone_css.dart';
|
||||
/// mixins.
|
||||
class AsyncEnvironment {
|
||||
/// The modules used in the current scope, indexed by their namespaces.
|
||||
final Map<String, AsyncModule> _modules;
|
||||
final Map<String, Module> _modules;
|
||||
|
||||
/// The namespaceless modules used in the current scope.
|
||||
///
|
||||
/// This is `null` if there are no namespaceless modules.
|
||||
Set<AsyncModule> _globalModules;
|
||||
Set<Module> _globalModules;
|
||||
|
||||
/// Modules from both [_modules] and [_global], in the order in which they
|
||||
/// were `@use`d.
|
||||
final List<AsyncModule> _allModules;
|
||||
final List<Module> _allModules;
|
||||
|
||||
/// A list of variables defined at each lexical scope level.
|
||||
///
|
||||
@ -194,7 +194,7 @@ class AsyncEnvironment {
|
||||
/// Throws a [SassScriptException] if there's already a module with the given
|
||||
/// [namespace], or if [namespace] is `null` and [module] defines a variable
|
||||
/// with the same name as a variable defined in this environment.
|
||||
void addModule(AsyncModule module, {String namespace}) {
|
||||
void addModule(Module module, {String namespace}) {
|
||||
if (namespace == null) {
|
||||
_globalModules ??= Set();
|
||||
_globalModules.add(module);
|
||||
@ -579,12 +579,12 @@ class AsyncEnvironment {
|
||||
/// Returns a module that represents the top-level members defined in [this],
|
||||
/// that contains [css] as its CSS tree, which can be extended using
|
||||
/// [extender].
|
||||
AsyncModule toModule(CssStylesheet css, Extender extender) =>
|
||||
Module toModule(CssStylesheet css, Extender extender) =>
|
||||
_EnvironmentModule(this, css, extender);
|
||||
|
||||
/// Returns the module with the given [namespace], or throws a
|
||||
/// [SassScriptException] if none exists.
|
||||
AsyncModule _getModule(String namespace) {
|
||||
Module _getModule(String namespace) {
|
||||
var module = _modules[namespace];
|
||||
if (module != null) return module;
|
||||
|
||||
@ -601,8 +601,7 @@ class AsyncEnvironment {
|
||||
/// The [type] should be the singular name of the value type being returned.
|
||||
/// The [name] should be the specific name being looked up. These are's used
|
||||
/// to format an appropriate error message.
|
||||
T _fromOneModule<T>(
|
||||
String type, String name, T callback(AsyncModule module)) {
|
||||
T _fromOneModule<T>(String type, String name, T callback(Module module)) {
|
||||
if (_globalModules == null) return null;
|
||||
|
||||
T value;
|
||||
@ -621,10 +620,10 @@ class AsyncEnvironment {
|
||||
}
|
||||
|
||||
/// A module that represents the top-level members defined in an [Environment].
|
||||
class _EnvironmentModule implements AsyncModule {
|
||||
class _EnvironmentModule implements Module {
|
||||
Uri get url => css.span.sourceUrl;
|
||||
|
||||
final List<AsyncModule> upstream;
|
||||
final List<Module> upstream;
|
||||
final Map<String, Value> variables;
|
||||
final Map<String, AstNode> variableNodes;
|
||||
final Map<String, AsyncCallable> functions;
|
||||
@ -666,7 +665,7 @@ class _EnvironmentModule implements AsyncModule {
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncModule cloneCss() {
|
||||
Module cloneCss() {
|
||||
if (css.children.isEmpty) return this;
|
||||
|
||||
var newCssAndExtender = cloneCssStylesheet(css, extender);
|
||||
|
@ -1,78 +0,0 @@
|
||||
// Copyright 2019 Google Inc. 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:source_span/source_span.dart';
|
||||
|
||||
import 'ast/css.dart';
|
||||
import 'ast/node.dart';
|
||||
import 'callable.dart';
|
||||
import 'extend/extender.dart';
|
||||
import 'value.dart';
|
||||
|
||||
/// The interface for a Sass module.
|
||||
abstract class AsyncModule {
|
||||
/// The canonical URL for this module's source file.
|
||||
///
|
||||
/// This may be `null` if the module was loaded from a string without a URL
|
||||
/// provided.
|
||||
Uri get url;
|
||||
|
||||
/// Modules that this module uses.
|
||||
List<AsyncModule> get upstream;
|
||||
|
||||
/// The module's variables.
|
||||
Map<String, Value> get variables;
|
||||
|
||||
/// The nodes where each variable in [_variables] was defined.
|
||||
///
|
||||
/// This is `null` if source mapping is disabled.
|
||||
///
|
||||
/// This stores [AstNode]s rather than [FileSpan]s so it can avoid calling
|
||||
/// [AstNode.span] if the span isn't required, since some nodes need to do
|
||||
/// real work to manufacture a source span.
|
||||
///
|
||||
/// Implementations must ensure that this has the same keys as [variables] if
|
||||
/// it's not `null`.
|
||||
Map<String, AstNode> get variableNodes;
|
||||
|
||||
/// The module's functions.
|
||||
///
|
||||
/// Implementations must ensure that each [Callable] is stored under its own
|
||||
/// name.
|
||||
Map<String, AsyncCallable> get functions;
|
||||
|
||||
/// The module's mixins.
|
||||
///
|
||||
/// Implementations must ensure that each [Callable] is stored under its own
|
||||
/// name.
|
||||
Map<String, AsyncCallable> get mixins;
|
||||
|
||||
/// The extensions defined in this module, which is also able to update
|
||||
/// [css]'s style rules in-place based on downstream extensions.
|
||||
Extender get extender;
|
||||
|
||||
/// The module's CSS tree.
|
||||
CssStylesheet get css;
|
||||
|
||||
/// Whether this module *or* any modules in [upstream] contain any CSS.
|
||||
bool get transitivelyContainsCss;
|
||||
|
||||
/// Whether this module *or* any modules in [upstream] contain `@extend`
|
||||
/// rules..
|
||||
bool get transitivelyContainsExtensions;
|
||||
|
||||
/// Sets the variable named [name] to [value], associated with
|
||||
/// [nodeWithSpan]'s source span.
|
||||
///
|
||||
/// This takes an [AstNode] rather than a [FileSpan] so it can avoid calling
|
||||
/// [AstNode.span] if the span isn't required, since some nodes need to do
|
||||
/// real work to manufacture a source span.
|
||||
///
|
||||
/// Throws a [SassScriptException] if this module doesn't define a variable
|
||||
/// named [name].
|
||||
void setVariable(String name, Value value, AstNode nodeWithSpan);
|
||||
|
||||
/// Creates a copy of this module with new [css] and [extender].
|
||||
AsyncModule cloneCss();
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
// DO NOT EDIT. This file was generated from async_environment.dart.
|
||||
// See tool/synchronize.dart for details.
|
||||
//
|
||||
// Checksum: 3210a5c0528eac456ae8ca7827b65f3976f6b29d
|
||||
// Checksum: a7e4f09ccb8a4997500abfe34e712b9c2ad212c6
|
||||
//
|
||||
// ignore_for_file: unused_import
|
||||
|
||||
@ -14,11 +14,11 @@ import 'package:source_span/source_span.dart';
|
||||
|
||||
import 'ast/css.dart';
|
||||
import 'ast/node.dart';
|
||||
import 'module.dart';
|
||||
import 'callable.dart';
|
||||
import 'exception.dart';
|
||||
import 'extend/extender.dart';
|
||||
import 'functions.dart';
|
||||
import 'module.dart';
|
||||
import 'util/public_member_map.dart';
|
||||
import 'utils.dart';
|
||||
import 'value.dart';
|
||||
@ -30,16 +30,16 @@ import 'visitor/clone_css.dart';
|
||||
/// mixins.
|
||||
class Environment {
|
||||
/// The modules used in the current scope, indexed by their namespaces.
|
||||
final Map<String, Module> _modules;
|
||||
final Map<String, Module<Callable>> _modules;
|
||||
|
||||
/// The namespaceless modules used in the current scope.
|
||||
///
|
||||
/// This is `null` if there are no namespaceless modules.
|
||||
Set<Module> _globalModules;
|
||||
Set<Module<Callable>> _globalModules;
|
||||
|
||||
/// Modules from both [_modules] and [_global], in the order in which they
|
||||
/// were `@use`d.
|
||||
final List<Module> _allModules;
|
||||
final List<Module<Callable>> _allModules;
|
||||
|
||||
/// A list of variables defined at each lexical scope level.
|
||||
///
|
||||
@ -199,7 +199,7 @@ class Environment {
|
||||
/// Throws a [SassScriptException] if there's already a module with the given
|
||||
/// [namespace], or if [namespace] is `null` and [module] defines a variable
|
||||
/// with the same name as a variable defined in this environment.
|
||||
void addModule(Module module, {String namespace}) {
|
||||
void addModule(Module<Callable> module, {String namespace}) {
|
||||
if (namespace == null) {
|
||||
_globalModules ??= Set();
|
||||
_globalModules.add(module);
|
||||
@ -582,12 +582,12 @@ class Environment {
|
||||
/// Returns a module that represents the top-level members defined in [this],
|
||||
/// that contains [css] as its CSS tree, which can be extended using
|
||||
/// [extender].
|
||||
Module toModule(CssStylesheet css, Extender extender) =>
|
||||
Module<Callable> toModule(CssStylesheet css, Extender extender) =>
|
||||
_EnvironmentModule(this, css, extender);
|
||||
|
||||
/// Returns the module with the given [namespace], or throws a
|
||||
/// [SassScriptException] if none exists.
|
||||
Module _getModule(String namespace) {
|
||||
Module<Callable> _getModule(String namespace) {
|
||||
var module = _modules[namespace];
|
||||
if (module != null) return module;
|
||||
|
||||
@ -604,7 +604,8 @@ class Environment {
|
||||
/// The [type] should be the singular name of the value type being returned.
|
||||
/// The [name] should be the specific name being looked up. These are's used
|
||||
/// to format an appropriate error message.
|
||||
T _fromOneModule<T>(String type, String name, T callback(Module module)) {
|
||||
T _fromOneModule<T>(
|
||||
String type, String name, T callback(Module<Callable> module)) {
|
||||
if (_globalModules == null) return null;
|
||||
|
||||
T value;
|
||||
@ -623,10 +624,10 @@ class Environment {
|
||||
}
|
||||
|
||||
/// A module that represents the top-level members defined in an [Environment].
|
||||
class _EnvironmentModule implements Module {
|
||||
class _EnvironmentModule implements Module<Callable> {
|
||||
Uri get url => css.span.sourceUrl;
|
||||
|
||||
final List<Module> upstream;
|
||||
final List<Module<Callable>> upstream;
|
||||
final Map<String, Value> variables;
|
||||
final Map<String, AstNode> variableNodes;
|
||||
final Map<String, Callable> functions;
|
||||
@ -668,7 +669,7 @@ class _EnvironmentModule implements Module {
|
||||
return;
|
||||
}
|
||||
|
||||
Module cloneCss() {
|
||||
Module<Callable> cloneCss() {
|
||||
if (css.children.isEmpty) return this;
|
||||
|
||||
var newCssAndExtender = cloneCssStylesheet(css, extender);
|
||||
|
@ -2,13 +2,6 @@
|
||||
// MIT-style license that can be found in the LICENSE file or at
|
||||
// https://opensource.org/licenses/MIT.
|
||||
|
||||
// DO NOT EDIT. This file was generated from async_module.dart.
|
||||
// See tool/synchronize.dart for details.
|
||||
//
|
||||
// Checksum: d996840504b080c2c4e6b34136562b8152bb2e97
|
||||
//
|
||||
// ignore_for_file: unused_import
|
||||
|
||||
import 'package:source_span/source_span.dart';
|
||||
|
||||
import 'ast/css.dart';
|
||||
@ -18,7 +11,7 @@ import 'extend/extender.dart';
|
||||
import 'value.dart';
|
||||
|
||||
/// The interface for a Sass module.
|
||||
abstract class Module {
|
||||
abstract class Module<T extends AsyncCallable> {
|
||||
/// The canonical URL for this module's source file.
|
||||
///
|
||||
/// This may be `null` if the module was loaded from a string without a URL
|
||||
@ -26,7 +19,7 @@ abstract class Module {
|
||||
Uri get url;
|
||||
|
||||
/// Modules that this module uses.
|
||||
List<Module> get upstream;
|
||||
List<Module<T>> get upstream;
|
||||
|
||||
/// The module's variables.
|
||||
Map<String, Value> get variables;
|
||||
@ -45,15 +38,15 @@ abstract class Module {
|
||||
|
||||
/// The module's functions.
|
||||
///
|
||||
/// Implementations must ensure that each [Callable] is stored under its own
|
||||
/// name.
|
||||
Map<String, Callable> get functions;
|
||||
/// Implementations must ensure that each [AsyncCallable] is stored under its
|
||||
/// own name.
|
||||
Map<String, T> get functions;
|
||||
|
||||
/// The module's mixins.
|
||||
///
|
||||
/// Implementations must ensure that each [Callable] is stored under its own
|
||||
/// name.
|
||||
Map<String, Callable> get mixins;
|
||||
/// Implementations must ensure that each [AsyncCallable] is stored under its
|
||||
/// own name.
|
||||
Map<String, T> get mixins;
|
||||
|
||||
/// The extensions defined in this module, which is also able to update
|
||||
/// [css]'s style rules in-place based on downstream extensions.
|
||||
@ -81,5 +74,5 @@ abstract class Module {
|
||||
void setVariable(String name, Value value, AstNode nodeWithSpan);
|
||||
|
||||
/// Creates a copy of this module with new [css] and [extender].
|
||||
Module cloneCss();
|
||||
Module<T> cloneCss();
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import '../ast/sass.dart';
|
||||
import '../ast/selector.dart';
|
||||
import '../async_environment.dart';
|
||||
import '../async_import_cache.dart';
|
||||
import '../async_module.dart';
|
||||
import '../callable.dart';
|
||||
import '../color_names.dart';
|
||||
import '../exception.dart';
|
||||
@ -31,6 +30,7 @@ import '../importer/node.dart';
|
||||
import '../importer/utils.dart';
|
||||
import '../io.dart';
|
||||
import '../logger.dart';
|
||||
import '../module.dart';
|
||||
import '../parse/keyframe_selector.dart';
|
||||
import '../syntax.dart';
|
||||
import '../util/fixed_length_list_builder.dart';
|
||||
@ -116,7 +116,7 @@ class _EvaluateVisitor
|
||||
final List<AsyncCallable> _functions;
|
||||
|
||||
/// All modules that have been loaded and evaluated so far.
|
||||
final _modules = <Uri, AsyncModule>{};
|
||||
final _modules = <Uri, Module>{};
|
||||
|
||||
/// The logger to use to print warnings.
|
||||
final Logger _logger;
|
||||
@ -263,7 +263,7 @@ class _EvaluateVisitor
|
||||
}
|
||||
|
||||
/// Executes [stylesheet], loaded by [importer], to produce a module.
|
||||
Future<AsyncModule> _execute(AsyncImporter importer, Stylesheet stylesheet) {
|
||||
Future<Module> _execute(AsyncImporter importer, Stylesheet stylesheet) {
|
||||
var url = stylesheet.span.sourceUrl;
|
||||
return putIfAbsentAsync(_modules, url, () async {
|
||||
var environment = _newEnvironment();
|
||||
@ -443,7 +443,7 @@ class _EvaluateVisitor
|
||||
///
|
||||
/// If [clone] is `true`, this will copy the modules before extending them so
|
||||
/// that they don't modify [root] or its dependencies.
|
||||
CssStylesheet _combineCss(AsyncModule root, {bool clone = false}) {
|
||||
CssStylesheet _combineCss(Module root, {bool clone = false}) {
|
||||
// TODO(nweiz): short-circuit if no upstream modules (transitively) include
|
||||
// any CSS.
|
||||
if (root.upstream.isEmpty) {
|
||||
@ -482,7 +482,7 @@ class _EvaluateVisitor
|
||||
|
||||
/// Extends the selectors in each module with the extensions defined in
|
||||
/// downstream modules.
|
||||
void _extendModules(List<AsyncModule> sortedModules) {
|
||||
void _extendModules(List<Module> sortedModules) {
|
||||
// All the extenders directly downstream of a given module (indexed by its
|
||||
// canonical URL). It's important that we create this in topological order,
|
||||
// so that by the time we're processing a module we've already filled in all
|
||||
@ -538,13 +538,13 @@ class _EvaluateVisitor
|
||||
|
||||
/// Returns all modules transitively used by [root] in topological order,
|
||||
/// ignoring modules that contain no CSS.
|
||||
List<AsyncModule> _topologicalModules(AsyncModule root) {
|
||||
List<Module> _topologicalModules(Module root) {
|
||||
// Construct a topological ordering using depth-first traversal, as in
|
||||
// https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search.
|
||||
var seen = Set<AsyncModule>();
|
||||
var sorted = QueueList<AsyncModule>();
|
||||
var seen = Set<Module>();
|
||||
var sorted = QueueList<Module>();
|
||||
|
||||
void visitModule(AsyncModule module) {
|
||||
void visitModule(Module module) {
|
||||
// Each module is added to the beginning of [sorted], which means the
|
||||
// returned list contains sibling modules in the opposite order of how
|
||||
// they appear in the document. Then when the list is reversed to generate
|
||||
|
@ -5,7 +5,7 @@
|
||||
// DO NOT EDIT. This file was generated from async_evaluate.dart.
|
||||
// See tool/synchronize.dart for details.
|
||||
//
|
||||
// Checksum: ef520a902171c8d105ece12e7c84889e34f95d80
|
||||
// Checksum: d52c30611ad55bb7764f570381b6d739e39e6f98
|
||||
//
|
||||
// ignore_for_file: unused_import
|
||||
|
||||
@ -29,7 +29,6 @@ import '../ast/sass.dart';
|
||||
import '../ast/selector.dart';
|
||||
import '../environment.dart';
|
||||
import '../import_cache.dart';
|
||||
import '../module.dart';
|
||||
import '../callable.dart';
|
||||
import '../color_names.dart';
|
||||
import '../exception.dart';
|
||||
@ -40,6 +39,7 @@ import '../importer/node.dart';
|
||||
import '../importer/utils.dart';
|
||||
import '../io.dart';
|
||||
import '../logger.dart';
|
||||
import '../module.dart';
|
||||
import '../parse/keyframe_selector.dart';
|
||||
import '../syntax.dart';
|
||||
import '../util/fixed_length_list_builder.dart';
|
||||
@ -125,7 +125,7 @@ class _EvaluateVisitor
|
||||
final List<Callable> _functions;
|
||||
|
||||
/// All modules that have been loaded and evaluated so far.
|
||||
final _modules = <Uri, Module>{};
|
||||
final _modules = <Uri, Module<Callable>>{};
|
||||
|
||||
/// The logger to use to print warnings.
|
||||
final Logger _logger;
|
||||
@ -271,7 +271,7 @@ class _EvaluateVisitor
|
||||
}
|
||||
|
||||
/// Executes [stylesheet], loaded by [importer], to produce a module.
|
||||
Module _execute(Importer importer, Stylesheet stylesheet) {
|
||||
Module<Callable> _execute(Importer importer, Stylesheet stylesheet) {
|
||||
var url = stylesheet.span.sourceUrl;
|
||||
return _modules.putIfAbsent(url, () {
|
||||
var environment = _newEnvironment();
|
||||
@ -451,7 +451,7 @@ class _EvaluateVisitor
|
||||
///
|
||||
/// If [clone] is `true`, this will copy the modules before extending them so
|
||||
/// that they don't modify [root] or its dependencies.
|
||||
CssStylesheet _combineCss(Module root, {bool clone = false}) {
|
||||
CssStylesheet _combineCss(Module<Callable> root, {bool clone = false}) {
|
||||
// TODO(nweiz): short-circuit if no upstream modules (transitively) include
|
||||
// any CSS.
|
||||
if (root.upstream.isEmpty) {
|
||||
@ -490,7 +490,7 @@ class _EvaluateVisitor
|
||||
|
||||
/// Extends the selectors in each module with the extensions defined in
|
||||
/// downstream modules.
|
||||
void _extendModules(List<Module> sortedModules) {
|
||||
void _extendModules(List<Module<Callable>> sortedModules) {
|
||||
// All the extenders directly downstream of a given module (indexed by its
|
||||
// canonical URL). It's important that we create this in topological order,
|
||||
// so that by the time we're processing a module we've already filled in all
|
||||
@ -546,13 +546,13 @@ class _EvaluateVisitor
|
||||
|
||||
/// Returns all modules transitively used by [root] in topological order,
|
||||
/// ignoring modules that contain no CSS.
|
||||
List<Module> _topologicalModules(Module root) {
|
||||
List<Module<Callable>> _topologicalModules(Module<Callable> root) {
|
||||
// Construct a topological ordering using depth-first traversal, as in
|
||||
// https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search.
|
||||
var seen = Set<Module>();
|
||||
var sorted = QueueList<Module>();
|
||||
var seen = Set<Module<Callable>>();
|
||||
var sorted = QueueList<Module<Callable>>();
|
||||
|
||||
void visitModule(Module module) {
|
||||
void visitModule(Module<Callable> module) {
|
||||
// Each module is added to the beginning of [sorted], which means the
|
||||
// returned list contains sibling modules in the opposite order of how
|
||||
// they appear in the document. Then when the list is reversed to generate
|
||||
|
@ -17,8 +17,7 @@ final sources = const {
|
||||
'lib/src/visitor/async_evaluate.dart': 'lib/src/visitor/evaluate.dart',
|
||||
'lib/src/async_compile.dart': 'lib/src/compile.dart',
|
||||
'lib/src/async_environment.dart': 'lib/src/environment.dart',
|
||||
'lib/src/async_import_cache.dart': 'lib/src/import_cache.dart',
|
||||
'lib/src/async_module.dart': 'lib/src/module.dart'
|
||||
'lib/src/async_import_cache.dart': 'lib/src/import_cache.dart'
|
||||
};
|
||||
|
||||
/// Classes that are defined in the async version of a file and used as-is in
|
||||
@ -188,6 +187,9 @@ class _Visitor extends RecursiveAstVisitor {
|
||||
} else {
|
||||
_buffer.write("void");
|
||||
}
|
||||
} else if (node.name.name == "Module") {
|
||||
_skip(node.name.beginToken);
|
||||
_buffer.write("Module<Callable>");
|
||||
} else {
|
||||
super.visitTypeName(node);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user