mirror of
https://github.com/danog/dart-sass.git
synced 2025-01-23 06:12:00 +01:00
Emit CSS for used modules (#620)
This commit is contained in:
parent
b66e1bad28
commit
c98cfd53b0
@ -29,6 +29,10 @@ class AsyncEnvironment {
|
|||||||
/// This is `null` if there are no namespaceless modules.
|
/// This is `null` if there are no namespaceless modules.
|
||||||
Set<AsyncModule> _globalModules;
|
Set<AsyncModule> _globalModules;
|
||||||
|
|
||||||
|
/// Modules from both [_modules] and [_global], in the order in which they
|
||||||
|
/// were `@use`d.
|
||||||
|
final List<AsyncModule> _allModules;
|
||||||
|
|
||||||
/// A list of variables defined at each lexical scope level.
|
/// A list of variables defined at each lexical scope level.
|
||||||
///
|
///
|
||||||
/// Each scope maps the names of declared variables to their values. These
|
/// Each scope maps the names of declared variables to their values. These
|
||||||
@ -122,6 +126,7 @@ class AsyncEnvironment {
|
|||||||
AsyncEnvironment({bool sourceMap = false})
|
AsyncEnvironment({bool sourceMap = false})
|
||||||
: _modules = {},
|
: _modules = {},
|
||||||
_globalModules = null,
|
_globalModules = null,
|
||||||
|
_allModules = [],
|
||||||
_variables = [normalizedMap()],
|
_variables = [normalizedMap()],
|
||||||
_variableNodes = sourceMap ? [normalizedMap()] : null,
|
_variableNodes = sourceMap ? [normalizedMap()] : null,
|
||||||
_variableIndices = normalizedMap(),
|
_variableIndices = normalizedMap(),
|
||||||
@ -132,8 +137,15 @@ class AsyncEnvironment {
|
|||||||
coreFunctions.forEach(setFunction);
|
coreFunctions.forEach(setFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncEnvironment._(this._modules, this._globalModules, this._variables,
|
AsyncEnvironment._(
|
||||||
this._variableNodes, this._functions, this._mixins, this._content)
|
this._modules,
|
||||||
|
this._globalModules,
|
||||||
|
this._allModules,
|
||||||
|
this._variables,
|
||||||
|
this._variableNodes,
|
||||||
|
this._functions,
|
||||||
|
this._mixins,
|
||||||
|
this._content)
|
||||||
// Lazily fill in the indices rather than eagerly copying them from the
|
// Lazily fill in the indices rather than eagerly copying them from the
|
||||||
// existing environment in closure() because the copying took a lot of
|
// existing environment in closure() because the copying took a lot of
|
||||||
// time and was rarely helpful. This saves a bunch of time on Susy's
|
// time and was rarely helpful. This saves a bunch of time on Susy's
|
||||||
@ -150,6 +162,7 @@ class AsyncEnvironment {
|
|||||||
AsyncEnvironment closure() => AsyncEnvironment._(
|
AsyncEnvironment closure() => AsyncEnvironment._(
|
||||||
_modules,
|
_modules,
|
||||||
_globalModules,
|
_globalModules,
|
||||||
|
_allModules,
|
||||||
_variables.toList(),
|
_variables.toList(),
|
||||||
_variableNodes?.toList(),
|
_variableNodes?.toList(),
|
||||||
_functions.toList(),
|
_functions.toList(),
|
||||||
@ -160,8 +173,10 @@ class AsyncEnvironment {
|
|||||||
///
|
///
|
||||||
/// The returned environment shares this environment's global variables,
|
/// The returned environment shares this environment's global variables,
|
||||||
/// functions, and mixins, but not its modules.
|
/// functions, and mixins, but not its modules.
|
||||||
AsyncEnvironment global() => AsyncEnvironment._({},
|
AsyncEnvironment global() => AsyncEnvironment._(
|
||||||
|
{},
|
||||||
null,
|
null,
|
||||||
|
[],
|
||||||
_variables.toList(),
|
_variables.toList(),
|
||||||
_variableNodes?.toList(),
|
_variableNodes?.toList(),
|
||||||
_functions.toList(),
|
_functions.toList(),
|
||||||
@ -180,6 +195,7 @@ class AsyncEnvironment {
|
|||||||
if (namespace == null) {
|
if (namespace == null) {
|
||||||
_globalModules ??= Set();
|
_globalModules ??= Set();
|
||||||
_globalModules.add(module);
|
_globalModules.add(module);
|
||||||
|
_allModules.add(module);
|
||||||
|
|
||||||
for (var name in _variables.first.keys) {
|
for (var name in _variables.first.keys) {
|
||||||
if (module.variables.containsKey(name)) {
|
if (module.variables.containsKey(name)) {
|
||||||
@ -195,6 +211,7 @@ class AsyncEnvironment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_modules[namespace] = module;
|
_modules[namespace] = module;
|
||||||
|
_allModules.add(module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,6 +617,7 @@ class AsyncEnvironment {
|
|||||||
|
|
||||||
/// A module that represents the top-level members defined in an [Environment].
|
/// A module that represents the top-level members defined in an [Environment].
|
||||||
class _EnvironmentModule implements AsyncModule {
|
class _EnvironmentModule implements AsyncModule {
|
||||||
|
final List<AsyncModule> upstream;
|
||||||
final Map<String, Value> variables;
|
final Map<String, Value> variables;
|
||||||
final Map<String, AstNode> variableNodes;
|
final Map<String, AstNode> variableNodes;
|
||||||
final Map<String, AsyncCallable> functions;
|
final Map<String, AsyncCallable> functions;
|
||||||
@ -612,7 +630,8 @@ class _EnvironmentModule implements AsyncModule {
|
|||||||
// TODO(nweiz): Use custom [UnmodifiableMapView]s that forbid access to
|
// TODO(nweiz): Use custom [UnmodifiableMapView]s that forbid access to
|
||||||
// private members.
|
// private members.
|
||||||
_EnvironmentModule(this._environment, this.css)
|
_EnvironmentModule(this._environment, this.css)
|
||||||
: variables = PublicMemberMap(_environment._variables.first),
|
: upstream = _environment._allModules,
|
||||||
|
variables = PublicMemberMap(_environment._variables.first),
|
||||||
variableNodes = _environment._variableNodes == null
|
variableNodes = _environment._variableNodes == null
|
||||||
? null
|
? null
|
||||||
: PublicMemberMap(_environment._variableNodes.first),
|
: PublicMemberMap(_environment._variableNodes.first),
|
||||||
|
@ -11,6 +11,9 @@ import 'value.dart';
|
|||||||
|
|
||||||
/// The interface for a Sass module.
|
/// The interface for a Sass module.
|
||||||
abstract class AsyncModule {
|
abstract class AsyncModule {
|
||||||
|
/// Modules that this module uses.
|
||||||
|
List<AsyncModule> get upstream;
|
||||||
|
|
||||||
/// The module's variables.
|
/// The module's variables.
|
||||||
Map<String, Value> get variables;
|
Map<String, Value> get variables;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
// 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: 77b03257b1770270e2d1f269281bdaab3f9f1ae9
|
// Checksum: e1d3693a4ede6e31d259efb13148a669be01e98c
|
||||||
//
|
//
|
||||||
// ignore_for_file: unused_import
|
// ignore_for_file: unused_import
|
||||||
|
|
||||||
@ -34,6 +34,10 @@ class Environment {
|
|||||||
/// This is `null` if there are no namespaceless modules.
|
/// This is `null` if there are no namespaceless modules.
|
||||||
Set<Module> _globalModules;
|
Set<Module> _globalModules;
|
||||||
|
|
||||||
|
/// Modules from both [_modules] and [_global], in the order in which they
|
||||||
|
/// were `@use`d.
|
||||||
|
final List<Module> _allModules;
|
||||||
|
|
||||||
/// A list of variables defined at each lexical scope level.
|
/// A list of variables defined at each lexical scope level.
|
||||||
///
|
///
|
||||||
/// Each scope maps the names of declared variables to their values. These
|
/// Each scope maps the names of declared variables to their values. These
|
||||||
@ -127,6 +131,7 @@ class Environment {
|
|||||||
Environment({bool sourceMap = false})
|
Environment({bool sourceMap = false})
|
||||||
: _modules = {},
|
: _modules = {},
|
||||||
_globalModules = null,
|
_globalModules = null,
|
||||||
|
_allModules = [],
|
||||||
_variables = [normalizedMap()],
|
_variables = [normalizedMap()],
|
||||||
_variableNodes = sourceMap ? [normalizedMap()] : null,
|
_variableNodes = sourceMap ? [normalizedMap()] : null,
|
||||||
_variableIndices = normalizedMap(),
|
_variableIndices = normalizedMap(),
|
||||||
@ -137,8 +142,15 @@ class Environment {
|
|||||||
coreFunctions.forEach(setFunction);
|
coreFunctions.forEach(setFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment._(this._modules, this._globalModules, this._variables,
|
Environment._(
|
||||||
this._variableNodes, this._functions, this._mixins, this._content)
|
this._modules,
|
||||||
|
this._globalModules,
|
||||||
|
this._allModules,
|
||||||
|
this._variables,
|
||||||
|
this._variableNodes,
|
||||||
|
this._functions,
|
||||||
|
this._mixins,
|
||||||
|
this._content)
|
||||||
// Lazily fill in the indices rather than eagerly copying them from the
|
// Lazily fill in the indices rather than eagerly copying them from the
|
||||||
// existing environment in closure() because the copying took a lot of
|
// existing environment in closure() because the copying took a lot of
|
||||||
// time and was rarely helpful. This saves a bunch of time on Susy's
|
// time and was rarely helpful. This saves a bunch of time on Susy's
|
||||||
@ -155,6 +167,7 @@ class Environment {
|
|||||||
Environment closure() => Environment._(
|
Environment closure() => Environment._(
|
||||||
_modules,
|
_modules,
|
||||||
_globalModules,
|
_globalModules,
|
||||||
|
_allModules,
|
||||||
_variables.toList(),
|
_variables.toList(),
|
||||||
_variableNodes?.toList(),
|
_variableNodes?.toList(),
|
||||||
_functions.toList(),
|
_functions.toList(),
|
||||||
@ -165,8 +178,10 @@ class Environment {
|
|||||||
///
|
///
|
||||||
/// The returned environment shares this environment's global variables,
|
/// The returned environment shares this environment's global variables,
|
||||||
/// functions, and mixins, but not its modules.
|
/// functions, and mixins, but not its modules.
|
||||||
Environment global() => Environment._({},
|
Environment global() => Environment._(
|
||||||
|
{},
|
||||||
null,
|
null,
|
||||||
|
[],
|
||||||
_variables.toList(),
|
_variables.toList(),
|
||||||
_variableNodes?.toList(),
|
_variableNodes?.toList(),
|
||||||
_functions.toList(),
|
_functions.toList(),
|
||||||
@ -185,6 +200,7 @@ class Environment {
|
|||||||
if (namespace == null) {
|
if (namespace == null) {
|
||||||
_globalModules ??= Set();
|
_globalModules ??= Set();
|
||||||
_globalModules.add(module);
|
_globalModules.add(module);
|
||||||
|
_allModules.add(module);
|
||||||
|
|
||||||
for (var name in _variables.first.keys) {
|
for (var name in _variables.first.keys) {
|
||||||
if (module.variables.containsKey(name)) {
|
if (module.variables.containsKey(name)) {
|
||||||
@ -200,6 +216,7 @@ class Environment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_modules[namespace] = module;
|
_modules[namespace] = module;
|
||||||
|
_allModules.add(module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -602,6 +619,7 @@ class Environment {
|
|||||||
|
|
||||||
/// A module that represents the top-level members defined in an [Environment].
|
/// A module that represents the top-level members defined in an [Environment].
|
||||||
class _EnvironmentModule implements Module {
|
class _EnvironmentModule implements Module {
|
||||||
|
final List<Module> upstream;
|
||||||
final Map<String, Value> variables;
|
final Map<String, Value> variables;
|
||||||
final Map<String, AstNode> variableNodes;
|
final Map<String, AstNode> variableNodes;
|
||||||
final Map<String, Callable> functions;
|
final Map<String, Callable> functions;
|
||||||
@ -614,7 +632,8 @@ class _EnvironmentModule implements Module {
|
|||||||
// TODO(nweiz): Use custom [UnmodifiableMapView]s that forbid access to
|
// TODO(nweiz): Use custom [UnmodifiableMapView]s that forbid access to
|
||||||
// private members.
|
// private members.
|
||||||
_EnvironmentModule(this._environment, this.css)
|
_EnvironmentModule(this._environment, this.css)
|
||||||
: variables = PublicMemberMap(_environment._variables.first),
|
: upstream = _environment._allModules,
|
||||||
|
variables = PublicMemberMap(_environment._variables.first),
|
||||||
variableNodes = _environment._variableNodes == null
|
variableNodes = _environment._variableNodes == null
|
||||||
? null
|
? null
|
||||||
: PublicMemberMap(_environment._variableNodes.first),
|
: PublicMemberMap(_environment._variableNodes.first),
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
// DO NOT EDIT. This file was generated from async_module.dart.
|
// DO NOT EDIT. This file was generated from async_module.dart.
|
||||||
// See tool/synchronize.dart for details.
|
// See tool/synchronize.dart for details.
|
||||||
//
|
//
|
||||||
// Checksum: 5608be0fdb1bff974611b75d1bbcb364a15d4df2
|
// Checksum: 759037174212e69cd0d9a7ebf55f6ee9f66072e8
|
||||||
//
|
//
|
||||||
// ignore_for_file: unused_import
|
// ignore_for_file: unused_import
|
||||||
|
|
||||||
@ -18,6 +18,9 @@ import 'value.dart';
|
|||||||
|
|
||||||
/// The interface for a Sass module.
|
/// The interface for a Sass module.
|
||||||
abstract class Module {
|
abstract class Module {
|
||||||
|
/// Modules that this module uses.
|
||||||
|
List<Module> get upstream;
|
||||||
|
|
||||||
/// The module's variables.
|
/// The module's variables.
|
||||||
Map<String, Value> get variables;
|
Map<String, Value> get variables;
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ class _EvaluateVisitor
|
|||||||
var module = await _execute(importer, node);
|
var module = await _execute(importer, node);
|
||||||
_extender.finalize();
|
_extender.finalize();
|
||||||
|
|
||||||
return EvaluateResult(module.css, _includedFiles);
|
return EvaluateResult(_combineCss(module), _includedFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Value> runExpression(Expression expression,
|
Future<Value> runExpression(Expression expression,
|
||||||
@ -406,6 +406,47 @@ class _EvaluateVisitor
|
|||||||
return CssStylesheet(statements.build(), _root.span);
|
return CssStylesheet(statements.build(), _root.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a new stylesheet containing [root]'s CSS as well as the CSS of all
|
||||||
|
/// modules transitively used by [root].
|
||||||
|
CssStylesheet _combineCss(AsyncModule root) {
|
||||||
|
if (root.upstream.isEmpty) return root.css;
|
||||||
|
|
||||||
|
var seen = Set<AsyncModule>();
|
||||||
|
var imports = <CssNode>[];
|
||||||
|
var css = <CssNode>[];
|
||||||
|
|
||||||
|
void visitModule(AsyncModule module) {
|
||||||
|
if (!seen.add(module)) return;
|
||||||
|
for (var module in module.upstream) {
|
||||||
|
visitModule(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
var statements = module.css.children;
|
||||||
|
var index = _indexAfterImports(statements);
|
||||||
|
imports.addAll(statements.getRange(0, index));
|
||||||
|
css.addAll(statements.getRange(index, statements.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
visitModule(root);
|
||||||
|
|
||||||
|
return CssStylesheet(imports + css, root.css.span);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the index of the first node in [statements] that comes after all
|
||||||
|
/// static imports.
|
||||||
|
int _indexAfterImports(List<CssNode> statements) {
|
||||||
|
var lastImport = -1;
|
||||||
|
for (var i = 0; i < statements.length; i++) {
|
||||||
|
var statement = statements[i];
|
||||||
|
if (statement is CssImport) {
|
||||||
|
lastImport = i;
|
||||||
|
} else if (statement is! CssComment) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lastImport + 1;
|
||||||
|
}
|
||||||
|
|
||||||
// ## Statements
|
// ## Statements
|
||||||
|
|
||||||
Future<Value> visitStylesheet(Stylesheet node) async {
|
Future<Value> visitStylesheet(Stylesheet node) async {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
// DO NOT EDIT. This file was generated from async_evaluate.dart.
|
// DO NOT EDIT. This file was generated from async_evaluate.dart.
|
||||||
// See tool/synchronize.dart for details.
|
// See tool/synchronize.dart for details.
|
||||||
//
|
//
|
||||||
// Checksum: ae0454752ee85a9094d0f0d0e6e8a252364b70a1
|
// Checksum: da6068544fd58007ee2d44c2688063cbe4543e73
|
||||||
//
|
//
|
||||||
// ignore_for_file: unused_import
|
// ignore_for_file: unused_import
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ class _EvaluateVisitor
|
|||||||
var module = _execute(importer, node);
|
var module = _execute(importer, node);
|
||||||
_extender.finalize();
|
_extender.finalize();
|
||||||
|
|
||||||
return EvaluateResult(module.css, _includedFiles);
|
return EvaluateResult(_combineCss(module), _includedFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value runExpression(Expression expression, {Map<String, Value> variables}) {
|
Value runExpression(Expression expression, {Map<String, Value> variables}) {
|
||||||
@ -412,6 +412,47 @@ class _EvaluateVisitor
|
|||||||
return CssStylesheet(statements.build(), _root.span);
|
return CssStylesheet(statements.build(), _root.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a new stylesheet containing [root]'s CSS as well as the CSS of all
|
||||||
|
/// modules transitively used by [root].
|
||||||
|
CssStylesheet _combineCss(Module root) {
|
||||||
|
if (root.upstream.isEmpty) return root.css;
|
||||||
|
|
||||||
|
var seen = Set<Module>();
|
||||||
|
var imports = <CssNode>[];
|
||||||
|
var css = <CssNode>[];
|
||||||
|
|
||||||
|
void visitModule(Module module) {
|
||||||
|
if (!seen.add(module)) return;
|
||||||
|
for (var module in module.upstream) {
|
||||||
|
visitModule(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
var statements = module.css.children;
|
||||||
|
var index = _indexAfterImports(statements);
|
||||||
|
imports.addAll(statements.getRange(0, index));
|
||||||
|
css.addAll(statements.getRange(index, statements.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
visitModule(root);
|
||||||
|
|
||||||
|
return CssStylesheet(imports + css, root.css.span);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the index of the first node in [statements] that comes after all
|
||||||
|
/// static imports.
|
||||||
|
int _indexAfterImports(List<CssNode> statements) {
|
||||||
|
var lastImport = -1;
|
||||||
|
for (var i = 0; i < statements.length; i++) {
|
||||||
|
var statement = statements[i];
|
||||||
|
if (statement is CssImport) {
|
||||||
|
lastImport = i;
|
||||||
|
} else if (statement is! CssComment) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lastImport + 1;
|
||||||
|
}
|
||||||
|
|
||||||
// ## Statements
|
// ## Statements
|
||||||
|
|
||||||
Value visitStylesheet(Stylesheet node) {
|
Value visitStylesheet(Stylesheet node) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user