Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: sass/dart-sass
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1.34.1
Choose a base ref
...
head repository: sass/dart-sass
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1.35.0
Choose a head ref
  • 5 commits
  • 15 files changed
  • 3 contributors

Commits on Jun 8, 2021

  1. Fix a bug with implicit dependencies (#1348)

    Encountered this while migrating internal code to math.div
    jathak authored Jun 8, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    7545011 View commit details

Commits on Jun 11, 2021

  1. Update compressed_test.dart (#1350)

    Delete duplicate test cases
    aimuz authored Jun 11, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    8557ce0 View commit details
  2. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    f1d36a1 View commit details

Commits on Jun 14, 2021

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    a077094 View commit details

Commits on Jun 15, 2021

  1. Add quietDeps and verbose to the JS API (#1353)

    To support this, we now run Node-Sass-style relative loads outside of
    the Node importer. This allows the evaluator to check whether a
    relative load succeeded and use that to determine whether the
    stylesheet counts as a dependency.
    
    See sass/sass#3065
    nex3 authored Jun 15, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    7e37166 View commit details
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## 1.35.0

* Fix a couple bugs that could prevent some members from being found in certain
files that use a mix of imports and the module system.

* Fix incorrect recommendation for migrating division expressions that reference
namespaced variables.

### JS API

* Add a `quietDeps` option which silences compiler warnings from stylesheets
loaded through importers and load paths.

* Add a `verbose` option which causes the compiler to emit all deprecation
warnings, not just 5 per feature.

## 1.34.1

* Fix a bug where `--update` would always compile any file that depends on a
7 changes: 1 addition & 6 deletions lib/src/ast/sass/expression/variable.dart
Original file line number Diff line number Diff line change
@@ -23,10 +23,5 @@ class VariableExpression implements Expression {
T accept<T>(ExpressionVisitor<T> visitor) =>
visitor.visitVariableExpression(this);

String toString() {
var buffer = StringBuffer("\$");
if (namespace != null) buffer.write("$namespace.");
buffer.write(name);
return buffer.toString();
}
String toString() => namespace == null ? '\$$name' : '$namespace.\$$name';
}
110 changes: 47 additions & 63 deletions lib/src/async_environment.dart
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@

import 'dart:collection';

import 'package:collection/collection.dart';
import 'package:path/path.dart' as p;
import 'package:source_span/source_span.dart';

@@ -43,23 +44,21 @@ class AsyncEnvironment {
/// modules were originally loaded.
final Map<String, AstNode> _namespaceNodes;

/// The namespaceless modules used in the current scope.
final Set<Module> _globalModules;

/// A map from modules in [_globalModules] to the nodes whose spans
/// indicate where those modules were originally loaded.
final Map<Module, AstNode> _globalModuleNodes;

/// The modules forwarded by this module.
/// A map from namespaceless modules to the `@use` rules whose spans indicate
/// where those modules were originally loaded.
///
/// This is `null` if there are no forwarded modules.
Set<Module>? _forwardedModules;
/// This does not include modules that were imported into the current scope.
final Map<Module, AstNode> _globalModules;

/// A map from modules in [_forwardedModules] to the nodes whose spans
/// A map from modules that were imported into the current scope to the nodes
/// whose spans indicate where those modules were originally loaded.
final Map<Module, AstNode> _importedModules;

/// A map from modules forwarded by this module to the nodes whose spans
/// indicate where those modules were originally forwarded.
///
/// This is `null` if there are no forwarded modules.
Map<Module, AstNode>? _forwardedModuleNodes;
Map<Module, AstNode>? _forwardedModules;

/// Modules forwarded by nested imports at each lexical scope level *beneath
/// the global scope*.
@@ -152,9 +151,8 @@ class AsyncEnvironment {
: _modules = {},
_namespaceNodes = {},
_globalModules = {},
_globalModuleNodes = {},
_importedModules = {},
_forwardedModules = null,
_forwardedModuleNodes = null,
_nestedForwardedModules = null,
_allModules = [],
_variables = [{}],
@@ -169,9 +167,8 @@ class AsyncEnvironment {
this._modules,
this._namespaceNodes,
this._globalModules,
this._globalModuleNodes,
this._importedModules,
this._forwardedModules,
this._forwardedModuleNodes,
this._nestedForwardedModules,
this._allModules,
this._variables,
@@ -196,9 +193,8 @@ class AsyncEnvironment {
_modules,
_namespaceNodes,
_globalModules,
_globalModuleNodes,
_importedModules,
_forwardedModules,
_forwardedModuleNodes,
_nestedForwardedModules,
_allModules,
_variables.toList(),
@@ -210,13 +206,13 @@ class AsyncEnvironment {
/// Returns a new environment to use for an imported file.
///
/// The returned environment shares this environment's variables, functions,
/// and mixins, but not its modules.
/// and mixins, but excludes most modules (except for global modules that
/// result from importing a file with forwards).
AsyncEnvironment forImport() => AsyncEnvironment._(
{},
{},
{},
{},
null,
_importedModules,
null,
null,
[],
@@ -238,8 +234,7 @@ class AsyncEnvironment {
/// with the same name as a variable defined in this environment.
void addModule(Module module, AstNode nodeWithSpan, {String? namespace}) {
if (namespace == null) {
_globalModules.add(module);
_globalModuleNodes[module] = nodeWithSpan;
_globalModules[module] = nodeWithSpan;
_allModules.add(module);

for (var name in _variables.first.keys) {
@@ -268,10 +263,9 @@ class AsyncEnvironment {
/// defined in this module, according to the modifications defined by [rule].
void forwardModule(Module module, ForwardRule rule) {
var forwardedModules = (_forwardedModules ??= {});
var forwardedModuleNodes = (_forwardedModuleNodes ??= {});

var view = ForwardedModuleView.ifNecessary(module, rule);
for (var other in forwardedModules) {
for (var other in forwardedModules.keys) {
_assertNoConflicts(
view.variables, other.variables, view, other, "variable");
_assertNoConflicts(
@@ -284,8 +278,7 @@ class AsyncEnvironment {
// `==`. This is safe because upstream modules are only used for collating
// CSS, not for the members they expose.
_allModules.add(module);
forwardedModules.add(view);
forwardedModuleNodes[view] = rule;
forwardedModules[view] = rule;
}

/// Throws a [SassScriptException] if [newMembers] from [newModule] has any
@@ -317,7 +310,7 @@ class AsyncEnvironment {
}

if (type == "variable") name = "\$$name";
var span = _forwardedModuleNodes?[oldModule]?.span;
var span = _forwardedModules?[oldModule]?.span;
throw MultiSpanSassScriptException(
'Two forwarded modules both define a $type named $name.',
"new @forward",
@@ -339,69 +332,56 @@ class AsyncEnvironment {
var forwardedModules = _forwardedModules;
if (forwardedModules != null) {
forwarded = {
for (var module in forwarded)
if (!forwardedModules.contains(module) ||
!_globalModules.contains(module))
module
for (var entry in forwarded.entries)
if (!forwardedModules.containsKey(entry.key) ||
!_globalModules.containsKey(entry.key))
entry.key: entry.value,
};
} else {
forwardedModules = _forwardedModules ??= {};
}

var forwardedModuleNodes = _forwardedModuleNodes ??= {};

var forwardedVariableNames =
forwarded.expand((module) => module.variables.keys).toSet();
forwarded.keys.expand((module) => module.variables.keys).toSet();
var forwardedFunctionNames =
forwarded.expand((module) => module.functions.keys).toSet();
forwarded.keys.expand((module) => module.functions.keys).toSet();
var forwardedMixinNames =
forwarded.expand((module) => module.mixins.keys).toSet();
forwarded.keys.expand((module) => module.mixins.keys).toSet();

if (atRoot) {
// Hide members from modules that have already been imported or
// forwarded that would otherwise conflict with the @imported members.
for (var module in _globalModules.toList()) {
for (var entry in _importedModules.entries.toList()) {
var module = entry.key;
var shadowed = ShadowedModuleView.ifNecessary(module,
variables: forwardedVariableNames,
mixins: forwardedMixinNames,
functions: forwardedFunctionNames);
if (shadowed != null) {
_globalModules.remove(module);

if (!shadowed.isEmpty) {
_globalModules.add(shadowed);
_globalModuleNodes[shadowed] = _globalModuleNodes.remove(module)!;
}
_importedModules.remove(module);
if (!shadowed.isEmpty) _importedModules[shadowed] = entry.value;
}
}

for (var module in forwardedModules.toList()) {
for (var entry in forwardedModules.entries.toList()) {
var module = entry.key;
var shadowed = ShadowedModuleView.ifNecessary(module,
variables: forwardedVariableNames,
mixins: forwardedMixinNames,
functions: forwardedFunctionNames);
if (shadowed != null) {
forwardedModules.remove(module);

if (!shadowed.isEmpty) {
forwardedModules.add(shadowed);
forwardedModuleNodes[shadowed] =
forwardedModuleNodes.remove(module)!;
}
if (!shadowed.isEmpty) forwardedModules[shadowed] = entry.value;
}
}

_globalModules.addAll(forwarded);
_globalModuleNodes
.addAll(module._environment._forwardedModuleNodes ?? const {});
_importedModules.addAll(forwarded);
forwardedModules.addAll(forwarded);
forwardedModuleNodes
.addAll(module._environment._forwardedModuleNodes ?? const {});
} else {
(_nestedForwardedModules ??=
List.generate(_variables.length - 1, (_) => []))
.last
.addAll(forwarded);
.addAll(forwarded.keys);
}

// Remove existing member definitions that are now shadowed by the
@@ -507,7 +487,7 @@ class AsyncEnvironment {
AstNode? _getVariableNodeFromGlobalModule(String name) {
// 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) {
for (var module in _importedModules.keys.followedBy(_globalModules.keys)) {
var value = module.variableNodes[name];
if (value != null) return value;
}
@@ -830,7 +810,7 @@ class AsyncEnvironment {
Module toModule(CssStylesheet css, ExtensionStore extensionStore) {
assert(atRoot);
return _EnvironmentModule(this, css, extensionStore,
forwarded: _forwardedModules);
forwarded: _forwardedModules.andThen((modules) => MapKeySet(modules)));
}

/// Returns a module with the same members and upstream modules as [this], but
@@ -845,7 +825,7 @@ class AsyncEnvironment {
CssStylesheet(const [],
SourceFile.decoded(const [], url: "<dummy module>").span(0)),
ExtensionStore.empty,
forwarded: _forwardedModules);
forwarded: _forwardedModules.andThen((modules) => MapKeySet(modules)));
}

/// Returns the module with the given [namespace], or throws a
@@ -859,7 +839,7 @@ class AsyncEnvironment {
}

/// Returns the result of [callback] if it returns non-`null` for exactly one
/// module in [_globalModules] *or* for any module in
/// module in [_globalModules] *or* for any module in [_importedModules] or
/// [_nestedForwardedModules].
///
/// Returns `null` if [callback] returns `null` for all modules. Throws an
@@ -879,10 +859,14 @@ class AsyncEnvironment {
}
}
}
for (var module in _importedModules.keys) {
var value = callback(module);
if (value != null) return value;
}

T? value;
Object? identity;
for (var module in _globalModules) {
for (var module in _globalModules.keys) {
var valueInModule = callback(module);
if (valueInModule == null) continue;

@@ -892,7 +876,7 @@ class AsyncEnvironment {
if (identityFromModule == identity) continue;

if (value != null) {
var spans = _globalModuleNodes.entries.map(
var spans = _globalModules.entries.map(
(entry) => callback(entry.key).andThen((_) => entry.value.span));

throw MultiSpanSassScriptException(
4 changes: 2 additions & 2 deletions lib/src/async_import_cache.dart
Original file line number Diff line number Diff line change
@@ -102,8 +102,8 @@ class AsyncImportCache {
/// canonicalize [url] (resolved relative to [baseUrl] if it's passed).
///
/// If any importers understand [url], returns that importer as well as the
/// canonicalized URL and the original URL resolved relative to [baseUrl] if
/// applicable. Otherwise, returns `null`.
/// canonicalized URL and the original URL (resolved relative to [baseUrl] if
/// applicable). Otherwise, returns `null`.
Future<Tuple3<AsyncImporter, Uri, Uri>?> canonicalize(Uri url,
{AsyncImporter? baseImporter,
Uri? baseUrl,
Loading