Add a module class and a way to create it from an Environment

This commit is contained in:
Natalie Weizenbaum 2019-01-18 04:21:54 -05:00
parent 5d4db9eb17
commit 7a7aea95b3
7 changed files with 216 additions and 4 deletions

View File

@ -6,11 +6,14 @@ import 'dart:async';
import 'package:source_span/source_span.dart'; import 'package:source_span/source_span.dart';
import 'ast/css.dart';
import 'ast/node.dart'; import 'ast/node.dart';
import 'async_module.dart';
import 'callable.dart'; import 'callable.dart';
import 'functions.dart'; import 'functions.dart';
import 'value.dart'; import 'util/public_member_map.dart';
import 'utils.dart'; import 'utils.dart';
import 'value.dart';
/// The lexical environment in which Sass is executed. /// The lexical environment in which Sass is executed.
/// ///
@ -399,4 +402,34 @@ class AsyncEnvironment {
} }
} }
} }
/// Returns a module that represents the top-level members defined in [this],
/// and that contains [css] as its CSS tree.
AsyncModule toModule(CssStylesheet css) => _EnvironmentModule(this, css);
}
/// A module that represents the top-level members defined in an [Environment].
class _EnvironmentModule implements AsyncModule {
final Map<String, Value> variables;
final Map<String, AstNode> variableNodes;
final Map<String, AsyncCallable> functions;
final Map<String, AsyncCallable> mixins;
final CssStylesheet css;
/// The environment that defines this module's members.
final AsyncEnvironment _environment;
// TODO(nweiz): Use custom [UnmodifiableMapView]s that forbid access to
// private members.
_EnvironmentModule(this._environment, this.css)
: variables = PublicMemberMap(_environment._variables.first),
variableNodes = _environment._variableNodes == null
? null
: PublicMemberMap(_environment._variableNodes.first),
functions = PublicMemberMap(_environment._functions.first),
mixins = PublicMemberMap(_environment._mixins.first);
void setVariable(String name, Value value, AstNode nodeWithSpan) {
_environment.setVariable(name, value, nodeWithSpan, global: true);
}
} }

51
lib/src/async_module.dart Normal file
View File

@ -0,0 +1,51 @@
// 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 'value.dart';
/// The interface for a Sass module.
abstract class AsyncModule {
/// 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 module's CSS tree.
CssStylesheet get css;
/// 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.
void setVariable(String name, Value value, AstNode nodeWithSpan);
}

View File

@ -5,17 +5,20 @@
// DO NOT EDIT. This file was generated from async_environment.dart. // DO NOT EDIT. This file was generated from async_environment.dart.
// See tool/synchronize.dart for details. // See tool/synchronize.dart for details.
// //
// Checksum: 449ed8a8ad29fe107656a666e6e6005ef539b834 // Checksum: e8d50e36818b44b30e9ff78b6c22b4eceb7a7607
// //
// ignore_for_file: unused_import // ignore_for_file: unused_import
import 'package:source_span/source_span.dart'; import 'package:source_span/source_span.dart';
import 'ast/css.dart';
import 'ast/node.dart'; import 'ast/node.dart';
import 'module.dart';
import 'callable.dart'; import 'callable.dart';
import 'functions.dart'; import 'functions.dart';
import 'value.dart'; import 'util/public_member_map.dart';
import 'utils.dart'; import 'utils.dart';
import 'value.dart';
/// The lexical environment in which Sass is executed. /// The lexical environment in which Sass is executed.
/// ///
@ -402,4 +405,34 @@ class Environment {
} }
} }
} }
/// Returns a module that represents the top-level members defined in [this],
/// and that contains [css] as its CSS tree.
Module toModule(CssStylesheet css) => _EnvironmentModule(this, css);
}
/// A module that represents the top-level members defined in an [Environment].
class _EnvironmentModule implements Module {
final Map<String, Value> variables;
final Map<String, AstNode> variableNodes;
final Map<String, Callable> functions;
final Map<String, Callable> mixins;
final CssStylesheet css;
/// The environment that defines this module's members.
final Environment _environment;
// TODO(nweiz): Use custom [UnmodifiableMapView]s that forbid access to
// private members.
_EnvironmentModule(this._environment, this.css)
: variables = PublicMemberMap(_environment._variables.first),
variableNodes = _environment._variableNodes == null
? null
: PublicMemberMap(_environment._variableNodes.first),
functions = PublicMemberMap(_environment._functions.first),
mixins = PublicMemberMap(_environment._mixins.first);
void setVariable(String name, Value value, AstNode nodeWithSpan) {
_environment.setVariable(name, value, nodeWithSpan, global: true);
}
} }

58
lib/src/module.dart Normal file
View File

@ -0,0 +1,58 @@
// 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.
// DO NOT EDIT. This file was generated from async_module.dart.
// See tool/synchronize.dart for details.
//
// Checksum: 6cb2d5ca89346a8deddb51bd8b4bee7d5620d870
//
// ignore_for_file: unused_import
import 'package:source_span/source_span.dart';
import 'ast/css.dart';
import 'ast/node.dart';
import 'callable.dart';
import 'value.dart';
/// The interface for a Sass module.
abstract class Module {
/// 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, Callable> get functions;
/// The module's mixins.
///
/// Implementations must ensure that each [Callable] is stored under its own
/// name.
Map<String, Callable> get mixins;
/// The module's CSS tree.
CssStylesheet get css;
/// 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.
void setVariable(String name, Value value, AstNode nodeWithSpan);
}

View File

@ -0,0 +1,28 @@
// 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 'dart:collection';
import '../utils.dart';
/// An unmodifiable map view that hides keys from the original map whose names
/// begin with `_` or `-`.
///
/// Note that [PublicMemberMap.length] is *not* `O(1)`.
class PublicMemberMap<V> extends UnmodifiableMapBase<String, V> {
/// The wrapped map.
final Map<String, V> _inner;
Iterable<String> get keys => _inner.keys.where(isPublic);
PublicMemberMap(this._inner);
bool containsKey(Object key) =>
key is String && isPublic(key) && _inner.containsKey(key);
V operator [](Object key) {
if (key is String && isPublic(key)) return _inner[key];
return null;
}
}

View File

@ -105,6 +105,14 @@ int _lastNonWhitespace(String string, {bool excludeEscape = false}) {
return null; return null;
} }
/// Returns whether [member] is a public member name.
///
/// Assumes that [member] is a valid Sass identifier.
bool isPublic(String member) {
var start = member.codeUnitAt(0);
return start != $dash && start != $underscore;
}
/// Flattens the first level of nested arrays in [iterable]. /// Flattens the first level of nested arrays in [iterable].
/// ///
/// The return value is ordered first by index in the nested iterable, then by /// The return value is ordered first by index in the nested iterable, then by

View File

@ -17,7 +17,8 @@ final sources = const {
'lib/src/visitor/async_evaluate.dart': 'lib/src/visitor/evaluate.dart', 'lib/src/visitor/async_evaluate.dart': 'lib/src/visitor/evaluate.dart',
'lib/src/async_compile.dart': 'lib/src/compile.dart', 'lib/src/async_compile.dart': 'lib/src/compile.dart',
'lib/src/async_environment.dart': 'lib/src/environment.dart', 'lib/src/async_environment.dart': 'lib/src/environment.dart',
'lib/src/async_import_cache.dart': 'lib/src/import_cache.dart' 'lib/src/async_import_cache.dart': 'lib/src/import_cache.dart',
'lib/src/async_module.dart': 'lib/src/module.dart'
}; };
/// Classes that are defined in the async version of a file and used as-is in /// Classes that are defined in the async version of a file and used as-is in