mirror of
https://github.com/danog/dart-sass.git
synced 2024-11-26 20:24:42 +01:00
Always track variables' source spans
This is necessary for generating useful error messages for /-as-division.
This commit is contained in:
parent
be2d3e848a
commit
742023a877
@ -25,6 +25,11 @@ import 'utils.dart';
|
||||
import 'value.dart';
|
||||
import 'visitor/clone_css.dart';
|
||||
|
||||
// TODO(nweiz): This used to avoid tracking source spans for variables if source
|
||||
// map generation was disabled. We always have to track them now to produce
|
||||
// better warnings for /-as-division, but once those warnings are gone we should
|
||||
// go back to tracking conditionally.
|
||||
|
||||
/// The lexical environment in which Sass is executed.
|
||||
///
|
||||
/// This tracks lexically-scoped information, such as variables, functions, and
|
||||
@ -77,12 +82,10 @@ class AsyncEnvironment {
|
||||
|
||||
/// 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.
|
||||
final List<Map<String, AstNode>>? _variableNodes;
|
||||
final List<Map<String, AstNode>> _variableNodes;
|
||||
|
||||
/// A map of variable names to their indices in [_variables].
|
||||
///
|
||||
@ -145,7 +148,7 @@ class AsyncEnvironment {
|
||||
/// Creates an [AsyncEnvironment].
|
||||
///
|
||||
/// If [sourceMap] is `true`, this tracks variables' source locations
|
||||
AsyncEnvironment({bool sourceMap = false})
|
||||
AsyncEnvironment()
|
||||
: _modules = {},
|
||||
_namespaceNodes = {},
|
||||
_globalModules = {},
|
||||
@ -155,7 +158,7 @@ class AsyncEnvironment {
|
||||
_nestedForwardedModules = null,
|
||||
_allModules = [],
|
||||
_variables = [{}],
|
||||
_variableNodes = sourceMap ? [{}] : null,
|
||||
_variableNodes = [{}],
|
||||
_variableIndices = {},
|
||||
_functions = [{}],
|
||||
_functionIndices = {},
|
||||
@ -199,7 +202,7 @@ class AsyncEnvironment {
|
||||
_nestedForwardedModules,
|
||||
_allModules,
|
||||
_variables.toList(),
|
||||
_variableNodes?.toList(),
|
||||
_variableNodes.toList(),
|
||||
_functions.toList(),
|
||||
_mixins.toList(),
|
||||
_content);
|
||||
@ -218,7 +221,7 @@ class AsyncEnvironment {
|
||||
null,
|
||||
[],
|
||||
_variables.toList(),
|
||||
_variableNodes?.toList(),
|
||||
_variableNodes.toList(),
|
||||
_functions.toList(),
|
||||
_mixins.toList(),
|
||||
_content);
|
||||
@ -406,7 +409,7 @@ class AsyncEnvironment {
|
||||
for (var variable in forwardedVariableNames) {
|
||||
_variableIndices.remove(variable);
|
||||
_variables.last.remove(variable);
|
||||
_variableNodes?.last.remove(variable);
|
||||
_variableNodes.last.remove(variable);
|
||||
}
|
||||
for (var function in forwardedFunctionNames) {
|
||||
_functionIndices.remove(function);
|
||||
@ -468,17 +471,10 @@ class AsyncEnvironment {
|
||||
/// required, since some nodes need to do real work to manufacture a source
|
||||
/// span.
|
||||
AstNode? getVariableNode(String name, {String? namespace}) {
|
||||
var variableNodes = _variableNodes;
|
||||
if (variableNodes == null) {
|
||||
throw StateError(
|
||||
"getVariableNodes() should only be called if sourceMap = true was "
|
||||
"passed in.");
|
||||
}
|
||||
|
||||
if (namespace != null) return _getModule(namespace).variableNodes![name];
|
||||
if (namespace != null) return _getModule(namespace).variableNodes[name];
|
||||
|
||||
if (_lastVariableName == name) {
|
||||
return variableNodes[_lastVariableIndex!][name] ??
|
||||
return _variableNodes[_lastVariableIndex!][name] ??
|
||||
_getVariableNodeFromGlobalModule(name);
|
||||
}
|
||||
|
||||
@ -486,7 +482,7 @@ class AsyncEnvironment {
|
||||
if (index != null) {
|
||||
_lastVariableName = name;
|
||||
_lastVariableIndex = index;
|
||||
return variableNodes[index][name] ??
|
||||
return _variableNodes[index][name] ??
|
||||
_getVariableNodeFromGlobalModule(name);
|
||||
}
|
||||
|
||||
@ -496,7 +492,8 @@ class AsyncEnvironment {
|
||||
_lastVariableName = name;
|
||||
_lastVariableIndex = index;
|
||||
_variableIndices[name] = index;
|
||||
return variableNodes[index][name] ?? _getVariableNodeFromGlobalModule(name);
|
||||
return _variableNodes[index][name] ??
|
||||
_getVariableNodeFromGlobalModule(name);
|
||||
}
|
||||
|
||||
/// Returns the node for the variable named [name] from a namespaceless
|
||||
@ -511,7 +508,7 @@ class AsyncEnvironment {
|
||||
// We don't need to worry about multiple modules defining the same variable,
|
||||
// because that's already been checked by [getVariable].
|
||||
for (var module in _globalModules) {
|
||||
var value = module.variableNodes![name];
|
||||
var value = module.variableNodes[name];
|
||||
if (value != null) return value;
|
||||
}
|
||||
return null;
|
||||
@ -559,7 +556,7 @@ class AsyncEnvironment {
|
||||
/// defined with the given namespace, if no variable with the given [name] is
|
||||
/// defined in module with the given namespace, or if no [namespace] is passed
|
||||
/// and multiple global modules define variables named [name].
|
||||
void setVariable(String name, Value value, AstNode? nodeWithSpan,
|
||||
void setVariable(String name, Value value, AstNode nodeWithSpan,
|
||||
{String? namespace, bool global = false}) {
|
||||
if (namespace != null) {
|
||||
_getModule(namespace).setVariable(name, value, nodeWithSpan);
|
||||
@ -587,7 +584,7 @@ class AsyncEnvironment {
|
||||
}
|
||||
|
||||
_variables.first[name] = value;
|
||||
if (nodeWithSpan != null) _variableNodes?.first[name] = nodeWithSpan;
|
||||
_variableNodes.first[name] = nodeWithSpan;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -617,7 +614,7 @@ class AsyncEnvironment {
|
||||
_lastVariableName = name;
|
||||
_lastVariableIndex = index;
|
||||
_variables[index][name] = value;
|
||||
_variableNodes?[index][name] = nodeWithSpan!;
|
||||
_variableNodes[index][name] = nodeWithSpan;
|
||||
}
|
||||
|
||||
/// Sets the variable named [name] to [value], associated with
|
||||
@ -629,15 +626,13 @@ class AsyncEnvironment {
|
||||
/// 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 setLocalVariable(String name, Value value, AstNode? nodeWithSpan) {
|
||||
void setLocalVariable(String name, Value value, AstNode nodeWithSpan) {
|
||||
var index = _variables.length - 1;
|
||||
_lastVariableName = name;
|
||||
_lastVariableIndex = index;
|
||||
_variableIndices[name] = index;
|
||||
_variables[index][name] = value;
|
||||
if (nodeWithSpan != null) {
|
||||
_variableNodes?[index][name] = nodeWithSpan;
|
||||
}
|
||||
_variableNodes[index][name] = nodeWithSpan;
|
||||
}
|
||||
|
||||
/// Returns the value of the function named [name], optionally with the given
|
||||
@ -789,7 +784,7 @@ class AsyncEnvironment {
|
||||
_inSemiGlobalScope = semiGlobal;
|
||||
|
||||
_variables.add({});
|
||||
_variableNodes?.add({});
|
||||
_variableNodes.add({});
|
||||
_functions.add({});
|
||||
_mixins.add({});
|
||||
_nestedForwardedModules?.add([]);
|
||||
@ -818,12 +813,12 @@ class AsyncEnvironment {
|
||||
var configuration = <String, ConfiguredValue>{};
|
||||
for (var i = 0; i < _variables.length; i++) {
|
||||
var values = _variables[i];
|
||||
var nodes = _variableNodes?[i] ?? <String, AstNode>{};
|
||||
var nodes = _variableNodes[i];
|
||||
for (var entry in values.entries) {
|
||||
// Implicit configurations are never invalid, making [configurationSpan]
|
||||
// unnecessary, so we pass null here to avoid having to compute it.
|
||||
configuration[entry.key] =
|
||||
ConfiguredValue.implicit(entry.value, nodes[entry.key]);
|
||||
ConfiguredValue.implicit(entry.value, nodes[entry.key]!);
|
||||
}
|
||||
}
|
||||
return Configuration.implicit(configuration);
|
||||
@ -921,7 +916,7 @@ class _EnvironmentModule implements Module {
|
||||
|
||||
final List<Module> upstream;
|
||||
final Map<String, Value> variables;
|
||||
final Map<String, AstNode>? variableNodes;
|
||||
final Map<String, AstNode> variableNodes;
|
||||
final Map<String, AsyncCallable> functions;
|
||||
final Map<String, AsyncCallable> mixins;
|
||||
final ExtensionStore extensionStore;
|
||||
@ -951,10 +946,8 @@ class _EnvironmentModule implements Module {
|
||||
_makeModulesByVariable(forwarded),
|
||||
_memberMap(environment._variables.first,
|
||||
forwarded.map((module) => module.variables)),
|
||||
environment._variableNodes.andThen((nodes) => _memberMap(
|
||||
nodes.first,
|
||||
// dart-lang/sdk#45348
|
||||
forwarded!.map((module) => module.variableNodes!))),
|
||||
_memberMap(environment._variableNodes.first,
|
||||
forwarded.map((module) => module.variableNodes)),
|
||||
_memberMap(environment._functions.first,
|
||||
forwarded.map((module) => module.functions)),
|
||||
_memberMap(environment._mixins.first,
|
||||
@ -1017,7 +1010,7 @@ class _EnvironmentModule implements Module {
|
||||
required this.transitivelyContainsExtensions})
|
||||
: upstream = _environment._allModules;
|
||||
|
||||
void setVariable(String name, Value value, AstNode? nodeWithSpan) {
|
||||
void setVariable(String name, Value value, AstNode nodeWithSpan) {
|
||||
var module = _modulesByVariable[name];
|
||||
if (module != null) {
|
||||
module.setVariable(name, value, nodeWithSpan);
|
||||
@ -1029,9 +1022,7 @@ class _EnvironmentModule implements Module {
|
||||
}
|
||||
|
||||
_environment._variables.first[name] = value;
|
||||
if (nodeWithSpan != null) {
|
||||
_environment._variableNodes?.first[name] = nodeWithSpan;
|
||||
}
|
||||
_environment._variableNodes.first[name] = nodeWithSpan;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,7 @@ class ConfiguredValue {
|
||||
final FileSpan? configurationSpan;
|
||||
|
||||
/// The [AstNode] where the variable's value originated.
|
||||
///
|
||||
/// This is used to generate source maps.
|
||||
final AstNode? assignmentNode;
|
||||
final AstNode assignmentNode;
|
||||
|
||||
/// Creates a variable value that's been configured explicitly with a `with`
|
||||
/// clause.
|
||||
|
@ -5,7 +5,7 @@
|
||||
// DO NOT EDIT. This file was generated from async_environment.dart.
|
||||
// See tool/grind/synchronize.dart for details.
|
||||
//
|
||||
// Checksum: bb0b47fc04e32f36a0f87dc73bdfe3f89dc51aa4
|
||||
// Checksum: 588f0864bb1f889586178c799d91696341ecf218
|
||||
//
|
||||
// ignore_for_file: unused_import
|
||||
|
||||
@ -32,6 +32,11 @@ import 'utils.dart';
|
||||
import 'value.dart';
|
||||
import 'visitor/clone_css.dart';
|
||||
|
||||
// TODO(nweiz): This used to avoid tracking source spans for variables if source
|
||||
// map generation was disabled. We always have to track them now to produce
|
||||
// better warnings for /-as-division, but once those warnings are gone we should
|
||||
// go back to tracking conditionally.
|
||||
|
||||
/// The lexical environment in which Sass is executed.
|
||||
///
|
||||
/// This tracks lexically-scoped information, such as variables, functions, and
|
||||
@ -84,12 +89,10 @@ class Environment {
|
||||
|
||||
/// 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.
|
||||
final List<Map<String, AstNode>>? _variableNodes;
|
||||
final List<Map<String, AstNode>> _variableNodes;
|
||||
|
||||
/// A map of variable names to their indices in [_variables].
|
||||
///
|
||||
@ -152,7 +155,7 @@ class Environment {
|
||||
/// Creates an [Environment].
|
||||
///
|
||||
/// If [sourceMap] is `true`, this tracks variables' source locations
|
||||
Environment({bool sourceMap = false})
|
||||
Environment()
|
||||
: _modules = {},
|
||||
_namespaceNodes = {},
|
||||
_globalModules = {},
|
||||
@ -162,7 +165,7 @@ class Environment {
|
||||
_nestedForwardedModules = null,
|
||||
_allModules = [],
|
||||
_variables = [{}],
|
||||
_variableNodes = sourceMap ? [{}] : null,
|
||||
_variableNodes = [{}],
|
||||
_variableIndices = {},
|
||||
_functions = [{}],
|
||||
_functionIndices = {},
|
||||
@ -206,7 +209,7 @@ class Environment {
|
||||
_nestedForwardedModules,
|
||||
_allModules,
|
||||
_variables.toList(),
|
||||
_variableNodes?.toList(),
|
||||
_variableNodes.toList(),
|
||||
_functions.toList(),
|
||||
_mixins.toList(),
|
||||
_content);
|
||||
@ -225,7 +228,7 @@ class Environment {
|
||||
null,
|
||||
[],
|
||||
_variables.toList(),
|
||||
_variableNodes?.toList(),
|
||||
_variableNodes.toList(),
|
||||
_functions.toList(),
|
||||
_mixins.toList(),
|
||||
_content);
|
||||
@ -414,7 +417,7 @@ class Environment {
|
||||
for (var variable in forwardedVariableNames) {
|
||||
_variableIndices.remove(variable);
|
||||
_variables.last.remove(variable);
|
||||
_variableNodes?.last.remove(variable);
|
||||
_variableNodes.last.remove(variable);
|
||||
}
|
||||
for (var function in forwardedFunctionNames) {
|
||||
_functionIndices.remove(function);
|
||||
@ -476,17 +479,10 @@ class Environment {
|
||||
/// required, since some nodes need to do real work to manufacture a source
|
||||
/// span.
|
||||
AstNode? getVariableNode(String name, {String? namespace}) {
|
||||
var variableNodes = _variableNodes;
|
||||
if (variableNodes == null) {
|
||||
throw StateError(
|
||||
"getVariableNodes() should only be called if sourceMap = true was "
|
||||
"passed in.");
|
||||
}
|
||||
|
||||
if (namespace != null) return _getModule(namespace).variableNodes![name];
|
||||
if (namespace != null) return _getModule(namespace).variableNodes[name];
|
||||
|
||||
if (_lastVariableName == name) {
|
||||
return variableNodes[_lastVariableIndex!][name] ??
|
||||
return _variableNodes[_lastVariableIndex!][name] ??
|
||||
_getVariableNodeFromGlobalModule(name);
|
||||
}
|
||||
|
||||
@ -494,7 +490,7 @@ class Environment {
|
||||
if (index != null) {
|
||||
_lastVariableName = name;
|
||||
_lastVariableIndex = index;
|
||||
return variableNodes[index][name] ??
|
||||
return _variableNodes[index][name] ??
|
||||
_getVariableNodeFromGlobalModule(name);
|
||||
}
|
||||
|
||||
@ -504,7 +500,8 @@ class Environment {
|
||||
_lastVariableName = name;
|
||||
_lastVariableIndex = index;
|
||||
_variableIndices[name] = index;
|
||||
return variableNodes[index][name] ?? _getVariableNodeFromGlobalModule(name);
|
||||
return _variableNodes[index][name] ??
|
||||
_getVariableNodeFromGlobalModule(name);
|
||||
}
|
||||
|
||||
/// Returns the node for the variable named [name] from a namespaceless
|
||||
@ -519,7 +516,7 @@ class Environment {
|
||||
// We don't need to worry about multiple modules defining the same variable,
|
||||
// because that's already been checked by [getVariable].
|
||||
for (var module in _globalModules) {
|
||||
var value = module.variableNodes![name];
|
||||
var value = module.variableNodes[name];
|
||||
if (value != null) return value;
|
||||
}
|
||||
return null;
|
||||
@ -567,7 +564,7 @@ class Environment {
|
||||
/// defined with the given namespace, if no variable with the given [name] is
|
||||
/// defined in module with the given namespace, or if no [namespace] is passed
|
||||
/// and multiple global modules define variables named [name].
|
||||
void setVariable(String name, Value value, AstNode? nodeWithSpan,
|
||||
void setVariable(String name, Value value, AstNode nodeWithSpan,
|
||||
{String? namespace, bool global = false}) {
|
||||
if (namespace != null) {
|
||||
_getModule(namespace).setVariable(name, value, nodeWithSpan);
|
||||
@ -595,7 +592,7 @@ class Environment {
|
||||
}
|
||||
|
||||
_variables.first[name] = value;
|
||||
if (nodeWithSpan != null) _variableNodes?.first[name] = nodeWithSpan;
|
||||
_variableNodes.first[name] = nodeWithSpan;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -625,7 +622,7 @@ class Environment {
|
||||
_lastVariableName = name;
|
||||
_lastVariableIndex = index;
|
||||
_variables[index][name] = value;
|
||||
_variableNodes?[index][name] = nodeWithSpan!;
|
||||
_variableNodes[index][name] = nodeWithSpan;
|
||||
}
|
||||
|
||||
/// Sets the variable named [name] to [value], associated with
|
||||
@ -637,15 +634,13 @@ class Environment {
|
||||
/// 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 setLocalVariable(String name, Value value, AstNode? nodeWithSpan) {
|
||||
void setLocalVariable(String name, Value value, AstNode nodeWithSpan) {
|
||||
var index = _variables.length - 1;
|
||||
_lastVariableName = name;
|
||||
_lastVariableIndex = index;
|
||||
_variableIndices[name] = index;
|
||||
_variables[index][name] = value;
|
||||
if (nodeWithSpan != null) {
|
||||
_variableNodes?[index][name] = nodeWithSpan;
|
||||
}
|
||||
_variableNodes[index][name] = nodeWithSpan;
|
||||
}
|
||||
|
||||
/// Returns the value of the function named [name], optionally with the given
|
||||
@ -795,7 +790,7 @@ class Environment {
|
||||
_inSemiGlobalScope = semiGlobal;
|
||||
|
||||
_variables.add({});
|
||||
_variableNodes?.add({});
|
||||
_variableNodes.add({});
|
||||
_functions.add({});
|
||||
_mixins.add({});
|
||||
_nestedForwardedModules?.add([]);
|
||||
@ -824,12 +819,12 @@ class Environment {
|
||||
var configuration = <String, ConfiguredValue>{};
|
||||
for (var i = 0; i < _variables.length; i++) {
|
||||
var values = _variables[i];
|
||||
var nodes = _variableNodes?[i] ?? <String, AstNode>{};
|
||||
var nodes = _variableNodes[i];
|
||||
for (var entry in values.entries) {
|
||||
// Implicit configurations are never invalid, making [configurationSpan]
|
||||
// unnecessary, so we pass null here to avoid having to compute it.
|
||||
configuration[entry.key] =
|
||||
ConfiguredValue.implicit(entry.value, nodes[entry.key]);
|
||||
ConfiguredValue.implicit(entry.value, nodes[entry.key]!);
|
||||
}
|
||||
}
|
||||
return Configuration.implicit(configuration);
|
||||
@ -928,7 +923,7 @@ class _EnvironmentModule implements Module<Callable> {
|
||||
|
||||
final List<Module<Callable>> upstream;
|
||||
final Map<String, Value> variables;
|
||||
final Map<String, AstNode>? variableNodes;
|
||||
final Map<String, AstNode> variableNodes;
|
||||
final Map<String, Callable> functions;
|
||||
final Map<String, Callable> mixins;
|
||||
final ExtensionStore extensionStore;
|
||||
@ -958,10 +953,8 @@ class _EnvironmentModule implements Module<Callable> {
|
||||
_makeModulesByVariable(forwarded),
|
||||
_memberMap(environment._variables.first,
|
||||
forwarded.map((module) => module.variables)),
|
||||
environment._variableNodes.andThen((nodes) => _memberMap(
|
||||
nodes.first,
|
||||
// dart-lang/sdk#45348
|
||||
forwarded!.map((module) => module.variableNodes!))),
|
||||
_memberMap(environment._variableNodes.first,
|
||||
forwarded.map((module) => module.variableNodes)),
|
||||
_memberMap(environment._functions.first,
|
||||
forwarded.map((module) => module.functions)),
|
||||
_memberMap(environment._mixins.first,
|
||||
@ -1025,7 +1018,7 @@ class _EnvironmentModule implements Module<Callable> {
|
||||
required this.transitivelyContainsExtensions})
|
||||
: upstream = _environment._allModules;
|
||||
|
||||
void setVariable(String name, Value value, AstNode? nodeWithSpan) {
|
||||
void setVariable(String name, Value value, AstNode nodeWithSpan) {
|
||||
var module = _modulesByVariable[name];
|
||||
if (module != null) {
|
||||
module.setVariable(name, value, nodeWithSpan);
|
||||
@ -1037,9 +1030,7 @@ class _EnvironmentModule implements Module<Callable> {
|
||||
}
|
||||
|
||||
_environment._variables.first[name] = value;
|
||||
if (nodeWithSpan != null) {
|
||||
_environment._variableNodes?.first[name] = nodeWithSpan;
|
||||
}
|
||||
_environment._variableNodes.first[name] = nodeWithSpan;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -26,15 +26,13 @@ abstract class Module<T extends AsyncCallable> {
|
||||
|
||||
/// 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;
|
||||
Map<String, AstNode> get variableNodes;
|
||||
|
||||
/// The module's functions.
|
||||
///
|
||||
@ -71,7 +69,7 @@ abstract class Module<T extends AsyncCallable> {
|
||||
///
|
||||
/// Throws a [SassScriptException] if this module doesn't define a variable
|
||||
/// named [name].
|
||||
void setVariable(String name, Value value, AstNode? nodeWithSpan);
|
||||
void setVariable(String name, Value value, AstNode nodeWithSpan);
|
||||
|
||||
/// Returns an opaque object that will be equal to another
|
||||
/// `variableIdentity()` return value for the same name in another module if
|
||||
|
@ -44,7 +44,7 @@ class BuiltInModule<T extends AsyncCallable> implements Module<T> {
|
||||
: UnmodifiableMapView(
|
||||
{for (var callable in callables) callable.name: callable}));
|
||||
|
||||
void setVariable(String name, Value value, AstNode? nodeWithSpan) {
|
||||
void setVariable(String name, Value value, AstNode nodeWithSpan) {
|
||||
if (!variables.containsKey(name)) {
|
||||
throw SassScriptException("Undefined variable.");
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import '../exception.dart';
|
||||
import '../extend/extension_store.dart';
|
||||
import '../module.dart';
|
||||
import '../util/limited_map_view.dart';
|
||||
import '../util/nullable.dart';
|
||||
import '../util/prefixed_map_view.dart';
|
||||
import '../value.dart';
|
||||
|
||||
@ -31,7 +30,7 @@ class ForwardedModuleView<T extends AsyncCallable> implements Module<T> {
|
||||
_inner.transitivelyContainsExtensions;
|
||||
|
||||
final Map<String, Value> variables;
|
||||
final Map<String, AstNode>? variableNodes;
|
||||
final Map<String, AstNode> variableNodes;
|
||||
final Map<String, T> functions;
|
||||
final Map<String, T> mixins;
|
||||
|
||||
@ -53,8 +52,8 @@ class ForwardedModuleView<T extends AsyncCallable> implements Module<T> {
|
||||
ForwardedModuleView(this._inner, this._rule)
|
||||
: variables = _forwardedMap(_inner.variables, _rule.prefix,
|
||||
_rule.shownVariables, _rule.hiddenVariables),
|
||||
variableNodes = _inner.variableNodes.andThen((inner) => _forwardedMap(
|
||||
inner, _rule.prefix, _rule.shownVariables, _rule.hiddenVariables)),
|
||||
variableNodes = _forwardedMap(_inner.variableNodes, _rule.prefix,
|
||||
_rule.shownVariables, _rule.hiddenVariables),
|
||||
functions = _forwardedMap(_inner.functions, _rule.prefix,
|
||||
_rule.shownMixinsAndFunctions, _rule.hiddenMixinsAndFunctions),
|
||||
mixins = _forwardedMap(_inner.mixins, _rule.prefix,
|
||||
@ -86,7 +85,7 @@ class ForwardedModuleView<T extends AsyncCallable> implements Module<T> {
|
||||
return map;
|
||||
}
|
||||
|
||||
void setVariable(String name, Value value, AstNode? nodeWithSpan) {
|
||||
void setVariable(String name, Value value, AstNode nodeWithSpan) {
|
||||
var shownVariables = _rule.shownVariables;
|
||||
var hiddenVariables = _rule.hiddenVariables;
|
||||
if (shownVariables != null && !shownVariables.contains(name)) {
|
||||
|
@ -9,7 +9,6 @@ import '../exception.dart';
|
||||
import '../extend/extension_store.dart';
|
||||
import '../module.dart';
|
||||
import '../util/limited_map_view.dart';
|
||||
import '../util/nullable.dart';
|
||||
import '../utils.dart';
|
||||
import '../value.dart';
|
||||
|
||||
@ -28,7 +27,7 @@ class ShadowedModuleView<T extends AsyncCallable> implements Module<T> {
|
||||
_inner.transitivelyContainsExtensions;
|
||||
|
||||
final Map<String, Value> variables;
|
||||
final Map<String, AstNode>? variableNodes;
|
||||
final Map<String, AstNode> variableNodes;
|
||||
final Map<String, T> functions;
|
||||
final Map<String, T> mixins;
|
||||
|
||||
@ -57,8 +56,7 @@ class ShadowedModuleView<T extends AsyncCallable> implements Module<T> {
|
||||
ShadowedModuleView(this._inner,
|
||||
{Set<String>? variables, Set<String>? functions, Set<String>? mixins})
|
||||
: variables = _shadowedMap(_inner.variables, variables),
|
||||
variableNodes =
|
||||
_inner.variableNodes.andThen((map) => _shadowedMap(map, variables)),
|
||||
variableNodes = _shadowedMap(_inner.variableNodes, variables),
|
||||
functions = _shadowedMap(_inner.functions, functions),
|
||||
mixins = _shadowedMap(_inner.mixins, mixins);
|
||||
|
||||
@ -77,7 +75,7 @@ class ShadowedModuleView<T extends AsyncCallable> implements Module<T> {
|
||||
Map<String, Object?> map, Set<String>? blocklist) =>
|
||||
blocklist != null && map.isNotEmpty && blocklist.any(map.containsKey);
|
||||
|
||||
void setVariable(String name, Value value, AstNode? nodeWithSpan) {
|
||||
void setVariable(String name, Value value, AstNode nodeWithSpan) {
|
||||
if (!variables.containsKey(name)) {
|
||||
throw SassScriptException("Undefined variable.");
|
||||
} else {
|
||||
|
@ -298,7 +298,7 @@ class _EvaluateVisitor
|
||||
_sourceMap = sourceMap,
|
||||
// The default environment is overridden in [_execute] for full
|
||||
// stylesheets, but for [AsyncEvaluator] this environment is used.
|
||||
_environment = AsyncEnvironment(sourceMap: sourceMap) {
|
||||
_environment = AsyncEnvironment() {
|
||||
var metaFunctions = [
|
||||
// These functions are defined in the context of the evaluator because
|
||||
// they need access to the [_environment] or other local state.
|
||||
@ -677,7 +677,7 @@ class _EvaluateVisitor
|
||||
return alreadyLoaded;
|
||||
}
|
||||
|
||||
var environment = AsyncEnvironment(sourceMap: _sourceMap);
|
||||
var environment = AsyncEnvironment();
|
||||
late CssStylesheet css;
|
||||
var extensionStore = ExtensionStore();
|
||||
await _withEnvironment(environment, () async {
|
||||
@ -2219,7 +2219,7 @@ class _EvaluateVisitor
|
||||
_environment.setLocalVariable(
|
||||
declaredArguments[i].name,
|
||||
evaluated.positional[i].withoutSlash(),
|
||||
evaluated.positionalNodes?[i]);
|
||||
evaluated.positionalNodes[i]);
|
||||
}
|
||||
|
||||
for (var i = evaluated.positional.length;
|
||||
@ -2231,8 +2231,8 @@ class _EvaluateVisitor
|
||||
_environment.setLocalVariable(
|
||||
argument.name,
|
||||
value.withoutSlash(),
|
||||
evaluated.namedNodes?[argument.name] ??
|
||||
argument.defaultValue.andThen(_expressionNode));
|
||||
evaluated.namedNodes[argument.name] ??
|
||||
_expressionNode(argument.defaultValue!));
|
||||
}
|
||||
|
||||
SassArgumentList? argumentList;
|
||||
@ -2325,7 +2325,7 @@ class _EvaluateVisitor
|
||||
/// body.
|
||||
Future<Value> _runBuiltInCallable(ArgumentInvocation arguments,
|
||||
AsyncBuiltInCallable callable, AstNode nodeWithSpan) async {
|
||||
var evaluated = await _evaluateArguments(arguments, trackSpans: false);
|
||||
var evaluated = await _evaluateArguments(arguments);
|
||||
|
||||
var oldCallableNode = _callableNode;
|
||||
_callableNode = nodeWithSpan;
|
||||
@ -2405,12 +2405,13 @@ class _EvaluateVisitor
|
||||
}
|
||||
|
||||
/// Returns the evaluated values of the given [arguments].
|
||||
///
|
||||
/// If [trackSpans] is `true`, this tracks the source spans of the arguments
|
||||
/// being passed in. It defaults to [_sourceMap].
|
||||
Future<_ArgumentResults> _evaluateArguments(ArgumentInvocation arguments,
|
||||
{bool? trackSpans}) async {
|
||||
trackSpans ??= _sourceMap;
|
||||
Future<_ArgumentResults> _evaluateArguments(
|
||||
ArgumentInvocation arguments) async {
|
||||
// TODO(nweiz): This used to avoid tracking source spans for arguments if
|
||||
// [_sourceMap]s was false or it was being called from
|
||||
// [_runBuiltInCallable]. We always have to track them now to produce better
|
||||
// warnings for /-as-division, but once those warnings are gone we should go
|
||||
// back to tracking conditionally.
|
||||
|
||||
var positional = [
|
||||
for (var expression in arguments.positional) await expression.accept(this)
|
||||
@ -2420,23 +2421,18 @@ class _EvaluateVisitor
|
||||
entry.key: await entry.value.accept(this)
|
||||
};
|
||||
|
||||
var positionalNodes = trackSpans
|
||||
? [
|
||||
for (var expression in arguments.positional)
|
||||
_expressionNode(expression)
|
||||
]
|
||||
: null;
|
||||
var namedNodes = trackSpans
|
||||
? {
|
||||
var positionalNodes = [
|
||||
for (var expression in arguments.positional) _expressionNode(expression)
|
||||
];
|
||||
var namedNodes = {
|
||||
for (var entry in arguments.named.entries)
|
||||
entry.key: _expressionNode(entry.value)
|
||||
}
|
||||
: null;
|
||||
};
|
||||
|
||||
var restArgs = arguments.rest;
|
||||
if (restArgs == null) {
|
||||
return _ArgumentResults(positional, named, ListSeparator.undecided,
|
||||
positionalNodes: positionalNodes, namedNodes: namedNodes);
|
||||
return _ArgumentResults(positional, positionalNodes, named, namedNodes,
|
||||
ListSeparator.undecided);
|
||||
}
|
||||
|
||||
var rest = await restArgs.accept(this);
|
||||
@ -2444,42 +2440,42 @@ class _EvaluateVisitor
|
||||
var separator = ListSeparator.undecided;
|
||||
if (rest is SassMap) {
|
||||
_addRestMap(named, rest, restArgs, (value) => value);
|
||||
namedNodes?.addAll({
|
||||
namedNodes.addAll({
|
||||
for (var key in rest.contents.keys)
|
||||
(key as SassString).text: restNodeForSpan
|
||||
});
|
||||
} else if (rest is SassList) {
|
||||
positional.addAll(rest.asList);
|
||||
positionalNodes?.addAll(List.filled(rest.lengthAsList, restNodeForSpan));
|
||||
positionalNodes.addAll(List.filled(rest.lengthAsList, restNodeForSpan));
|
||||
separator = rest.separator;
|
||||
|
||||
if (rest is SassArgumentList) {
|
||||
rest.keywords.forEach((key, value) {
|
||||
named[key] = value;
|
||||
if (namedNodes != null) namedNodes[key] = restNodeForSpan;
|
||||
namedNodes[key] = restNodeForSpan;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
positional.add(rest);
|
||||
positionalNodes?.add(restNodeForSpan);
|
||||
positionalNodes.add(restNodeForSpan);
|
||||
}
|
||||
|
||||
var keywordRestArgs = arguments.keywordRest;
|
||||
if (keywordRestArgs == null) {
|
||||
return _ArgumentResults(positional, named, separator,
|
||||
positionalNodes: positionalNodes, namedNodes: namedNodes);
|
||||
return _ArgumentResults(
|
||||
positional, positionalNodes, named, namedNodes, separator);
|
||||
}
|
||||
|
||||
var keywordRest = await keywordRestArgs.accept(this);
|
||||
var keywordRestNodeForSpan = _expressionNode(keywordRestArgs);
|
||||
if (keywordRest is SassMap) {
|
||||
_addRestMap(named, keywordRest, keywordRestArgs, (value) => value);
|
||||
namedNodes?.addAll({
|
||||
namedNodes.addAll({
|
||||
for (var key in keywordRest.contents.keys)
|
||||
(key as SassString).text: keywordRestNodeForSpan
|
||||
});
|
||||
return _ArgumentResults(positional, named, separator,
|
||||
positionalNodes: positionalNodes, namedNodes: namedNodes);
|
||||
return _ArgumentResults(
|
||||
positional, positionalNodes, named, namedNodes, separator);
|
||||
} else {
|
||||
throw _exception(
|
||||
"Variable keyword arguments must be a map (was $keywordRest).",
|
||||
@ -2892,10 +2888,10 @@ class _EvaluateVisitor
|
||||
/// [AstNode.span] if the span isn't required, since some nodes need to do
|
||||
/// real work to manufacture a source span.
|
||||
AstNode _expressionNode(Expression expression) {
|
||||
// If we aren't making a source map this doesn't matter, but we still return
|
||||
// the expression so we don't have to make the type (and everything
|
||||
// downstream of it) nullable.
|
||||
if (!_sourceMap) return expression;
|
||||
// TODO(nweiz): This used to return [expression] as-is if source map
|
||||
// generation was disabled. We always have to track the original location
|
||||
// now to produce better warnings for /-as-division, but once those warnings
|
||||
// are gone we should go back to short-circuiting.
|
||||
|
||||
if (expression is VariableExpression) {
|
||||
return _environment.getVariableNode(expression.name,
|
||||
@ -3205,28 +3201,26 @@ class _ArgumentResults {
|
||||
/// Arguments passed by position.
|
||||
final List<Value> positional;
|
||||
|
||||
/// The [AstNode]s that hold the spans for each [positional] argument, or
|
||||
/// `null` if source span tracking is disabled.
|
||||
/// The [AstNode]s that hold the spans for each [positional] argument.
|
||||
///
|
||||
/// 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.
|
||||
final List<AstNode>? positionalNodes;
|
||||
final List<AstNode> positionalNodes;
|
||||
|
||||
/// Arguments passed by name.
|
||||
final Map<String, Value> named;
|
||||
|
||||
/// The [AstNode]s that hold the spans for each [named] argument, or `null` if
|
||||
/// source span tracking is disabled.
|
||||
/// The [AstNode]s that hold the spans for each [named] argument.
|
||||
///
|
||||
/// 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.
|
||||
final Map<String, AstNode>? namedNodes;
|
||||
final Map<String, AstNode> namedNodes;
|
||||
|
||||
/// The separator used for the rest argument list, if any.
|
||||
final ListSeparator separator;
|
||||
|
||||
_ArgumentResults(this.positional, this.named, this.separator,
|
||||
{this.positionalNodes, this.namedNodes});
|
||||
_ArgumentResults(this.positional, this.positionalNodes, this.named,
|
||||
this.namedNodes, this.separator);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
// DO NOT EDIT. This file was generated from async_evaluate.dart.
|
||||
// See tool/grind/synchronize.dart for details.
|
||||
//
|
||||
// Checksum: acaafcfe17e8cb582fb01ea8b95afaf871af4eed
|
||||
// Checksum: 6351ed2d303a58943ce6be39dc794fb46286fd64
|
||||
//
|
||||
// ignore_for_file: unused_import
|
||||
|
||||
@ -306,7 +306,7 @@ class _EvaluateVisitor
|
||||
_sourceMap = sourceMap,
|
||||
// The default environment is overridden in [_execute] for full
|
||||
// stylesheets, but for [AsyncEvaluator] this environment is used.
|
||||
_environment = Environment(sourceMap: sourceMap) {
|
||||
_environment = Environment() {
|
||||
var metaFunctions = [
|
||||
// These functions are defined in the context of the evaluator because
|
||||
// they need access to the [_environment] or other local state.
|
||||
@ -682,7 +682,7 @@ class _EvaluateVisitor
|
||||
return alreadyLoaded;
|
||||
}
|
||||
|
||||
var environment = Environment(sourceMap: _sourceMap);
|
||||
var environment = Environment();
|
||||
late CssStylesheet css;
|
||||
var extensionStore = ExtensionStore();
|
||||
_withEnvironment(environment, () {
|
||||
@ -2206,7 +2206,7 @@ class _EvaluateVisitor
|
||||
_environment.setLocalVariable(
|
||||
declaredArguments[i].name,
|
||||
evaluated.positional[i].withoutSlash(),
|
||||
evaluated.positionalNodes?[i]);
|
||||
evaluated.positionalNodes[i]);
|
||||
}
|
||||
|
||||
for (var i = evaluated.positional.length;
|
||||
@ -2218,8 +2218,8 @@ class _EvaluateVisitor
|
||||
_environment.setLocalVariable(
|
||||
argument.name,
|
||||
value.withoutSlash(),
|
||||
evaluated.namedNodes?[argument.name] ??
|
||||
argument.defaultValue.andThen(_expressionNode));
|
||||
evaluated.namedNodes[argument.name] ??
|
||||
_expressionNode(argument.defaultValue!));
|
||||
}
|
||||
|
||||
SassArgumentList? argumentList;
|
||||
@ -2310,7 +2310,7 @@ class _EvaluateVisitor
|
||||
/// body.
|
||||
Value _runBuiltInCallable(ArgumentInvocation arguments,
|
||||
BuiltInCallable callable, AstNode nodeWithSpan) {
|
||||
var evaluated = _evaluateArguments(arguments, trackSpans: false);
|
||||
var evaluated = _evaluateArguments(arguments);
|
||||
|
||||
var oldCallableNode = _callableNode;
|
||||
_callableNode = nodeWithSpan;
|
||||
@ -2390,12 +2390,12 @@ class _EvaluateVisitor
|
||||
}
|
||||
|
||||
/// Returns the evaluated values of the given [arguments].
|
||||
///
|
||||
/// If [trackSpans] is `true`, this tracks the source spans of the arguments
|
||||
/// being passed in. It defaults to [_sourceMap].
|
||||
_ArgumentResults _evaluateArguments(ArgumentInvocation arguments,
|
||||
{bool? trackSpans}) {
|
||||
trackSpans ??= _sourceMap;
|
||||
_ArgumentResults _evaluateArguments(ArgumentInvocation arguments) {
|
||||
// TODO(nweiz): This used to avoid tracking source spans for arguments if
|
||||
// [_sourceMap]s was false or it was being called from
|
||||
// [_runBuiltInCallable]. We always have to track them now to produce better
|
||||
// warnings for /-as-division, but once those warnings are gone we should go
|
||||
// back to tracking conditionally.
|
||||
|
||||
var positional = [
|
||||
for (var expression in arguments.positional) expression.accept(this)
|
||||
@ -2405,23 +2405,18 @@ class _EvaluateVisitor
|
||||
entry.key: entry.value.accept(this)
|
||||
};
|
||||
|
||||
var positionalNodes = trackSpans
|
||||
? [
|
||||
for (var expression in arguments.positional)
|
||||
_expressionNode(expression)
|
||||
]
|
||||
: null;
|
||||
var namedNodes = trackSpans
|
||||
? {
|
||||
var positionalNodes = [
|
||||
for (var expression in arguments.positional) _expressionNode(expression)
|
||||
];
|
||||
var namedNodes = {
|
||||
for (var entry in arguments.named.entries)
|
||||
entry.key: _expressionNode(entry.value)
|
||||
}
|
||||
: null;
|
||||
};
|
||||
|
||||
var restArgs = arguments.rest;
|
||||
if (restArgs == null) {
|
||||
return _ArgumentResults(positional, named, ListSeparator.undecided,
|
||||
positionalNodes: positionalNodes, namedNodes: namedNodes);
|
||||
return _ArgumentResults(positional, positionalNodes, named, namedNodes,
|
||||
ListSeparator.undecided);
|
||||
}
|
||||
|
||||
var rest = restArgs.accept(this);
|
||||
@ -2429,42 +2424,42 @@ class _EvaluateVisitor
|
||||
var separator = ListSeparator.undecided;
|
||||
if (rest is SassMap) {
|
||||
_addRestMap(named, rest, restArgs, (value) => value);
|
||||
namedNodes?.addAll({
|
||||
namedNodes.addAll({
|
||||
for (var key in rest.contents.keys)
|
||||
(key as SassString).text: restNodeForSpan
|
||||
});
|
||||
} else if (rest is SassList) {
|
||||
positional.addAll(rest.asList);
|
||||
positionalNodes?.addAll(List.filled(rest.lengthAsList, restNodeForSpan));
|
||||
positionalNodes.addAll(List.filled(rest.lengthAsList, restNodeForSpan));
|
||||
separator = rest.separator;
|
||||
|
||||
if (rest is SassArgumentList) {
|
||||
rest.keywords.forEach((key, value) {
|
||||
named[key] = value;
|
||||
if (namedNodes != null) namedNodes[key] = restNodeForSpan;
|
||||
namedNodes[key] = restNodeForSpan;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
positional.add(rest);
|
||||
positionalNodes?.add(restNodeForSpan);
|
||||
positionalNodes.add(restNodeForSpan);
|
||||
}
|
||||
|
||||
var keywordRestArgs = arguments.keywordRest;
|
||||
if (keywordRestArgs == null) {
|
||||
return _ArgumentResults(positional, named, separator,
|
||||
positionalNodes: positionalNodes, namedNodes: namedNodes);
|
||||
return _ArgumentResults(
|
||||
positional, positionalNodes, named, namedNodes, separator);
|
||||
}
|
||||
|
||||
var keywordRest = keywordRestArgs.accept(this);
|
||||
var keywordRestNodeForSpan = _expressionNode(keywordRestArgs);
|
||||
if (keywordRest is SassMap) {
|
||||
_addRestMap(named, keywordRest, keywordRestArgs, (value) => value);
|
||||
namedNodes?.addAll({
|
||||
namedNodes.addAll({
|
||||
for (var key in keywordRest.contents.keys)
|
||||
(key as SassString).text: keywordRestNodeForSpan
|
||||
});
|
||||
return _ArgumentResults(positional, named, separator,
|
||||
positionalNodes: positionalNodes, namedNodes: namedNodes);
|
||||
return _ArgumentResults(
|
||||
positional, positionalNodes, named, namedNodes, separator);
|
||||
} else {
|
||||
throw _exception(
|
||||
"Variable keyword arguments must be a map (was $keywordRest).",
|
||||
@ -2870,10 +2865,10 @@ class _EvaluateVisitor
|
||||
/// [AstNode.span] if the span isn't required, since some nodes need to do
|
||||
/// real work to manufacture a source span.
|
||||
AstNode _expressionNode(Expression expression) {
|
||||
// If we aren't making a source map this doesn't matter, but we still return
|
||||
// the expression so we don't have to make the type (and everything
|
||||
// downstream of it) nullable.
|
||||
if (!_sourceMap) return expression;
|
||||
// TODO(nweiz): This used to return [expression] as-is if source map
|
||||
// generation was disabled. We always have to track the original location
|
||||
// now to produce better warnings for /-as-division, but once those warnings
|
||||
// are gone we should go back to short-circuiting.
|
||||
|
||||
if (expression is VariableExpression) {
|
||||
return _environment.getVariableNode(expression.name,
|
||||
@ -3146,28 +3141,26 @@ class _ArgumentResults {
|
||||
/// Arguments passed by position.
|
||||
final List<Value> positional;
|
||||
|
||||
/// The [AstNode]s that hold the spans for each [positional] argument, or
|
||||
/// `null` if source span tracking is disabled.
|
||||
/// The [AstNode]s that hold the spans for each [positional] argument.
|
||||
///
|
||||
/// 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.
|
||||
final List<AstNode>? positionalNodes;
|
||||
final List<AstNode> positionalNodes;
|
||||
|
||||
/// Arguments passed by name.
|
||||
final Map<String, Value> named;
|
||||
|
||||
/// The [AstNode]s that hold the spans for each [named] argument, or `null` if
|
||||
/// source span tracking is disabled.
|
||||
/// The [AstNode]s that hold the spans for each [named] argument.
|
||||
///
|
||||
/// 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.
|
||||
final Map<String, AstNode>? namedNodes;
|
||||
final Map<String, AstNode> namedNodes;
|
||||
|
||||
/// The separator used for the rest argument list, if any.
|
||||
final ListSeparator separator;
|
||||
|
||||
_ArgumentResults(this.positional, this.named, this.separator,
|
||||
{this.positionalNodes, this.namedNodes});
|
||||
_ArgumentResults(this.positional, this.positionalNodes, this.named,
|
||||
this.namedNodes, this.separator);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user