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:
Natalie Weizenbaum 2019-05-20 15:34:14 -07:00 committed by GitHub
parent 2fca9e32f4
commit 2317be8812
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 56 additions and 139 deletions

View File

@ -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);

View File

@ -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();
}

View File

@ -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);

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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);
}