Skip to content

Commit 3849165

Browse files
authored
Merge pull request #1306 from sass/slash-separator
Deprecate /-as-division and add replacements
2 parents 9caa0f3 + 3a5d28f commit 3849165

19 files changed

+557
-331
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
## 1.33.0
22

3+
* Deprecate the use of `/` for division. The new `math.div()` function should be
4+
used instead. See [this page][] for details.
5+
6+
[this page]: https://sass-lang.com/documentation/breaking-changes/slash-div
7+
8+
* Add a `list.slash()` function that returns a slash-separated list.
9+
10+
* **Potentially breaking bug fix:** The heuristics around when potentially
11+
slash-separated numbers are converted to slash-free numbers—for example, when
12+
`1/2` will be printed as `0.5` rather than `1/2`—have been slightly expanded.
13+
Previously, a number would be made slash-free if it was passed as an argument
14+
to a *user-defined function*, but not to a *built-in function*. Now it will be
15+
made slash-free in both cases. This is a behavioral change, but it's unlikely
16+
to affect any real-world stylesheets.
17+
318
### JS API
419

520
* The `this` context for importers now has a `fromImport` field, which is `true`

lib/src/async_environment.dart

Lines changed: 30 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ import 'utils.dart';
2525
import 'value.dart';
2626
import 'visitor/clone_css.dart';
2727

28+
// TODO(nweiz): This used to avoid tracking source spans for variables if source
29+
// map generation was disabled. We always have to track them now to produce
30+
// better warnings for /-as-division, but once those warnings are gone we should
31+
// go back to tracking conditionally.
32+
2833
/// The lexical environment in which Sass is executed.
2934
///
3035
/// This tracks lexically-scoped information, such as variables, functions, and
@@ -77,12 +82,10 @@ class AsyncEnvironment {
7782

7883
/// The nodes where each variable in [_variables] was defined.
7984
///
80-
/// This is `null` if source mapping is disabled.
81-
///
8285
/// This stores [AstNode]s rather than [FileSpan]s so it can avoid calling
8386
/// [AstNode.span] if the span isn't required, since some nodes need to do
8487
/// real work to manufacture a source span.
85-
final List<Map<String, AstNode>>? _variableNodes;
88+
final List<Map<String, AstNode>> _variableNodes;
8689

8790
/// A map of variable names to their indices in [_variables].
8891
///
@@ -145,7 +148,7 @@ class AsyncEnvironment {
145148
/// Creates an [AsyncEnvironment].
146149
///
147150
/// If [sourceMap] is `true`, this tracks variables' source locations
148-
AsyncEnvironment({bool sourceMap = false})
151+
AsyncEnvironment()
149152
: _modules = {},
150153
_namespaceNodes = {},
151154
_globalModules = {},
@@ -155,7 +158,7 @@ class AsyncEnvironment {
155158
_nestedForwardedModules = null,
156159
_allModules = [],
157160
_variables = [{}],
158-
_variableNodes = sourceMap ? [{}] : null,
161+
_variableNodes = [{}],
159162
_variableIndices = {},
160163
_functions = [{}],
161164
_functionIndices = {},
@@ -199,7 +202,7 @@ class AsyncEnvironment {
199202
_nestedForwardedModules,
200203
_allModules,
201204
_variables.toList(),
202-
_variableNodes?.toList(),
205+
_variableNodes.toList(),
203206
_functions.toList(),
204207
_mixins.toList(),
205208
_content);
@@ -218,7 +221,7 @@ class AsyncEnvironment {
218221
null,
219222
[],
220223
_variables.toList(),
221-
_variableNodes?.toList(),
224+
_variableNodes.toList(),
222225
_functions.toList(),
223226
_mixins.toList(),
224227
_content);
@@ -406,7 +409,7 @@ class AsyncEnvironment {
406409
for (var variable in forwardedVariableNames) {
407410
_variableIndices.remove(variable);
408411
_variables.last.remove(variable);
409-
_variableNodes?.last.remove(variable);
412+
_variableNodes.last.remove(variable);
410413
}
411414
for (var function in forwardedFunctionNames) {
412415
_functionIndices.remove(function);
@@ -468,25 +471,18 @@ class AsyncEnvironment {
468471
/// required, since some nodes need to do real work to manufacture a source
469472
/// span.
470473
AstNode? getVariableNode(String name, {String? namespace}) {
471-
var variableNodes = _variableNodes;
472-
if (variableNodes == null) {
473-
throw StateError(
474-
"getVariableNodes() should only be called if sourceMap = true was "
475-
"passed in.");
476-
}
477-
478-
if (namespace != null) return _getModule(namespace).variableNodes![name];
474+
if (namespace != null) return _getModule(namespace).variableNodes[name];
479475

480476
if (_lastVariableName == name) {
481-
return variableNodes[_lastVariableIndex!][name] ??
477+
return _variableNodes[_lastVariableIndex!][name] ??
482478
_getVariableNodeFromGlobalModule(name);
483479
}
484480

485481
var index = _variableIndices[name];
486482
if (index != null) {
487483
_lastVariableName = name;
488484
_lastVariableIndex = index;
489-
return variableNodes[index][name] ??
485+
return _variableNodes[index][name] ??
490486
_getVariableNodeFromGlobalModule(name);
491487
}
492488

@@ -496,7 +492,8 @@ class AsyncEnvironment {
496492
_lastVariableName = name;
497493
_lastVariableIndex = index;
498494
_variableIndices[name] = index;
499-
return variableNodes[index][name] ?? _getVariableNodeFromGlobalModule(name);
495+
return _variableNodes[index][name] ??
496+
_getVariableNodeFromGlobalModule(name);
500497
}
501498

502499
/// Returns the node for the variable named [name] from a namespaceless
@@ -511,7 +508,7 @@ class AsyncEnvironment {
511508
// We don't need to worry about multiple modules defining the same variable,
512509
// because that's already been checked by [getVariable].
513510
for (var module in _globalModules) {
514-
var value = module.variableNodes![name];
511+
var value = module.variableNodes[name];
515512
if (value != null) return value;
516513
}
517514
return null;
@@ -559,7 +556,7 @@ class AsyncEnvironment {
559556
/// defined with the given namespace, if no variable with the given [name] is
560557
/// defined in module with the given namespace, or if no [namespace] is passed
561558
/// and multiple global modules define variables named [name].
562-
void setVariable(String name, Value value, AstNode? nodeWithSpan,
559+
void setVariable(String name, Value value, AstNode nodeWithSpan,
563560
{String? namespace, bool global = false}) {
564561
if (namespace != null) {
565562
_getModule(namespace).setVariable(name, value, nodeWithSpan);
@@ -587,7 +584,7 @@ class AsyncEnvironment {
587584
}
588585

589586
_variables.first[name] = value;
590-
if (nodeWithSpan != null) _variableNodes?.first[name] = nodeWithSpan;
587+
_variableNodes.first[name] = nodeWithSpan;
591588
return;
592589
}
593590

@@ -617,7 +614,7 @@ class AsyncEnvironment {
617614
_lastVariableName = name;
618615
_lastVariableIndex = index;
619616
_variables[index][name] = value;
620-
_variableNodes?[index][name] = nodeWithSpan!;
617+
_variableNodes[index][name] = nodeWithSpan;
621618
}
622619

623620
/// Sets the variable named [name] to [value], associated with
@@ -629,15 +626,13 @@ class AsyncEnvironment {
629626
/// This takes an [AstNode] rather than a [FileSpan] so it can avoid calling
630627
/// [AstNode.span] if the span isn't required, since some nodes need to do
631628
/// real work to manufacture a source span.
632-
void setLocalVariable(String name, Value value, AstNode? nodeWithSpan) {
629+
void setLocalVariable(String name, Value value, AstNode nodeWithSpan) {
633630
var index = _variables.length - 1;
634631
_lastVariableName = name;
635632
_lastVariableIndex = index;
636633
_variableIndices[name] = index;
637634
_variables[index][name] = value;
638-
if (nodeWithSpan != null) {
639-
_variableNodes?[index][name] = nodeWithSpan;
640-
}
635+
_variableNodes[index][name] = nodeWithSpan;
641636
}
642637

643638
/// Returns the value of the function named [name], optionally with the given
@@ -789,7 +784,7 @@ class AsyncEnvironment {
789784
_inSemiGlobalScope = semiGlobal;
790785

791786
_variables.add({});
792-
_variableNodes?.add({});
787+
_variableNodes.add({});
793788
_functions.add({});
794789
_mixins.add({});
795790
_nestedForwardedModules?.add([]);
@@ -818,12 +813,12 @@ class AsyncEnvironment {
818813
var configuration = <String, ConfiguredValue>{};
819814
for (var i = 0; i < _variables.length; i++) {
820815
var values = _variables[i];
821-
var nodes = _variableNodes?[i] ?? <String, AstNode>{};
816+
var nodes = _variableNodes[i];
822817
for (var entry in values.entries) {
823818
// Implicit configurations are never invalid, making [configurationSpan]
824819
// unnecessary, so we pass null here to avoid having to compute it.
825820
configuration[entry.key] =
826-
ConfiguredValue.implicit(entry.value, nodes[entry.key]);
821+
ConfiguredValue.implicit(entry.value, nodes[entry.key]!);
827822
}
828823
}
829824
return Configuration.implicit(configuration);
@@ -921,7 +916,7 @@ class _EnvironmentModule implements Module {
921916

922917
final List<Module> upstream;
923918
final Map<String, Value> variables;
924-
final Map<String, AstNode>? variableNodes;
919+
final Map<String, AstNode> variableNodes;
925920
final Map<String, AsyncCallable> functions;
926921
final Map<String, AsyncCallable> mixins;
927922
final ExtensionStore extensionStore;
@@ -951,10 +946,8 @@ class _EnvironmentModule implements Module {
951946
_makeModulesByVariable(forwarded),
952947
_memberMap(environment._variables.first,
953948
forwarded.map((module) => module.variables)),
954-
environment._variableNodes.andThen((nodes) => _memberMap(
955-
nodes.first,
956-
// dart-lang/sdk#45348
957-
forwarded!.map((module) => module.variableNodes!))),
949+
_memberMap(environment._variableNodes.first,
950+
forwarded.map((module) => module.variableNodes)),
958951
_memberMap(environment._functions.first,
959952
forwarded.map((module) => module.functions)),
960953
_memberMap(environment._mixins.first,
@@ -1017,7 +1010,7 @@ class _EnvironmentModule implements Module {
10171010
required this.transitivelyContainsExtensions})
10181011
: upstream = _environment._allModules;
10191012

1020-
void setVariable(String name, Value value, AstNode? nodeWithSpan) {
1013+
void setVariable(String name, Value value, AstNode nodeWithSpan) {
10211014
var module = _modulesByVariable[name];
10221015
if (module != null) {
10231016
module.setVariable(name, value, nodeWithSpan);
@@ -1029,9 +1022,7 @@ class _EnvironmentModule implements Module {
10291022
}
10301023

10311024
_environment._variables.first[name] = value;
1032-
if (nodeWithSpan != null) {
1033-
_environment._variableNodes?.first[name] = nodeWithSpan;
1034-
}
1025+
_environment._variableNodes.first[name] = nodeWithSpan;
10351026
return;
10361027
}
10371028

lib/src/configured_value.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ class ConfiguredValue {
1717
final FileSpan? configurationSpan;
1818

1919
/// The [AstNode] where the variable's value originated.
20-
///
21-
/// This is used to generate source maps.
22-
final AstNode? assignmentNode;
20+
final AstNode assignmentNode;
2321

2422
/// Creates a variable value that's been configured explicitly with a `with`
2523
/// clause.

0 commit comments

Comments
 (0)