@@ -17,6 +17,7 @@ import 'exception.dart';
17
17
import 'extend/extender.dart' ;
18
18
import 'module.dart' ;
19
19
import 'module/forwarded_view.dart' ;
20
+ import 'module/shadowed_view.dart' ;
20
21
import 'util/merged_map_view.dart' ;
21
22
import 'util/public_member_map_view.dart' ;
22
23
import 'utils.dart' ;
@@ -42,6 +43,13 @@ class AsyncEnvironment {
42
43
/// This is `null` if there are no forwarded modules.
43
44
List <Module > _forwardedModules;
44
45
46
+ /// Modules forwarded by nested imports at each lexical scope level *beneath
47
+ /// the global scope*.
48
+ ///
49
+ /// This is `null` until it's needed, since most environments won't ever use
50
+ /// this.
51
+ List <List <Module >> _nestedForwardedModules;
52
+
45
53
/// Modules from [_modules] , [_globalModules] , and [_forwardedModules] , in the
46
54
/// order in which they were `@use` d.
47
55
final List <Module > _allModules;
@@ -128,6 +136,7 @@ class AsyncEnvironment {
128
136
: _modules = {},
129
137
_globalModules = null ,
130
138
_forwardedModules = null ,
139
+ _nestedForwardedModules = null ,
131
140
_allModules = [],
132
141
_variables = [{}],
133
142
_variableNodes = sourceMap ? [{}] : null ,
@@ -141,6 +150,7 @@ class AsyncEnvironment {
141
150
this ._modules,
142
151
this ._globalModules,
143
152
this ._forwardedModules,
153
+ this ._nestedForwardedModules,
144
154
this ._allModules,
145
155
this ._variables,
146
156
this ._variableNodes,
@@ -164,6 +174,7 @@ class AsyncEnvironment {
164
174
_modules,
165
175
_globalModules,
166
176
_forwardedModules,
177
+ _nestedForwardedModules,
167
178
_allModules,
168
179
_variables.toList (),
169
180
_variableNodes? .toList (),
@@ -179,6 +190,7 @@ class AsyncEnvironment {
179
190
{},
180
191
null ,
181
192
null ,
193
+ null ,
182
194
[],
183
195
_variables.toList (),
184
196
_variableNodes? .toList (),
@@ -270,30 +282,63 @@ class AsyncEnvironment {
270
282
/// This is called when [module] is `@import` ed.
271
283
void importForwards (Module module) {
272
284
if (module is _EnvironmentModule ) {
273
- for (var forwarded
274
- in module._environment._forwardedModules ?? const < Module > []) {
275
- _globalModules ?? = {};
276
- _globalModules.add (forwarded);
277
-
278
- // Remove existing definitions that the forwarded members are now
279
- // shadowing.
280
- for (var variable in forwarded.variables.keys) {
281
- var index =
282
- _variableIndices.remove (variable) ?? _variableIndex (variable);
283
- if (index != null ) {
284
- _variables[index].remove (variable);
285
- if (_variableNodes != null ) _variableNodes[index].remove (variable);
285
+ var forwarded = module._environment._forwardedModules;
286
+ if (forwarded == null ) return ;
287
+
288
+ _globalModules ?? = {};
289
+ _forwardedModules ?? = [];
290
+
291
+ var forwardedVariableNames =
292
+ forwarded.expand ((module) => module.variables.keys).toSet ();
293
+ var forwardedFunctionNames =
294
+ forwarded.expand ((module) => module.functions.keys).toSet ();
295
+ var forwardedMixinNames =
296
+ forwarded.expand ((module) => module.mixins.keys).toSet ();
297
+
298
+ if (atRoot) {
299
+ // Hide members from modules that have already been imported or
300
+ // forwarded that would otherwise conflict with the @imported members.
301
+ for (var module in _globalModules.toList ()) {
302
+ var shadowed = ShadowedModuleView .ifNecessary (module,
303
+ variables: forwardedVariableNames,
304
+ mixins: forwardedMixinNames,
305
+ functions: forwardedFunctionNames);
306
+ if (shadowed != null ) {
307
+ _globalModules.remove (module);
308
+ _globalModules.add (shadowed);
286
309
}
287
310
}
288
- for (var function in forwarded.functions.keys) {
289
- var index =
290
- _functionIndices.remove (function) ?? _functionIndex (function);
291
- if (index != null ) _functions[index].remove (function);
292
- }
293
- for (var mixin in forwarded.mixins.keys) {
294
- var index = _mixinIndices.remove (mixin ) ?? _mixinIndex (mixin );
295
- if (index != null ) _mixins[index].remove (mixin );
311
+ for (var i = 0 ; i < _forwardedModules.length; i++ ) {
312
+ var module = _forwardedModules[i];
313
+ var shadowed = ShadowedModuleView .ifNecessary (module,
314
+ variables: forwardedVariableNames,
315
+ mixins: forwardedMixinNames,
316
+ functions: forwardedFunctionNames);
317
+ if (shadowed != null ) _forwardedModules[i] = shadowed;
296
318
}
319
+
320
+ _globalModules.addAll (forwarded);
321
+ _forwardedModules.addAll (forwarded);
322
+ } else {
323
+ _nestedForwardedModules ?? =
324
+ List .generate (_variables.length - 1 , (_) => []);
325
+ _nestedForwardedModules.last.addAll (forwarded);
326
+ }
327
+
328
+ // Remove existing member definitions that are now shadowed by the
329
+ // forwarded modules.
330
+ for (var variable in forwardedVariableNames) {
331
+ _variableIndices.remove (variable);
332
+ _variables.last.remove (variable);
333
+ if (_variableNodes != null ) _variableNodes.last.remove (variable);
334
+ }
335
+ for (var function in forwardedFunctionNames) {
336
+ _functionIndices.remove (function);
337
+ _functions.last.remove (function);
338
+ }
339
+ for (var mixin in forwardedMixinNames) {
340
+ _mixinIndices.remove (mixin );
341
+ _mixins.last.remove (mixin );
297
342
}
298
343
}
299
344
}
@@ -467,6 +512,19 @@ class AsyncEnvironment {
467
512
return ;
468
513
}
469
514
515
+ if (_nestedForwardedModules != null &&
516
+ ! _variableIndices.containsKey (name) &&
517
+ _variableIndex (name) == null ) {
518
+ for (var modules in _nestedForwardedModules.reversed) {
519
+ for (var module in modules.reversed) {
520
+ if (module.variables.containsKey (name)) {
521
+ module.setVariable (name, value, nodeWithSpan);
522
+ return ;
523
+ }
524
+ }
525
+ }
526
+ }
527
+
470
528
var index = _lastVariableName == name
471
529
? _lastVariableIndex
472
530
: _variableIndices.putIfAbsent (
@@ -652,6 +710,7 @@ class AsyncEnvironment {
652
710
_variableNodes? .add ({});
653
711
_functions.add ({});
654
712
_mixins.add ({});
713
+ _nestedForwardedModules? .add ([]);
655
714
try {
656
715
return await callback ();
657
716
} finally {
@@ -667,14 +726,18 @@ class AsyncEnvironment {
667
726
for (var name in _mixins.removeLast ().keys) {
668
727
_mixinIndices.remove (name);
669
728
}
729
+ _nestedForwardedModules? .removeLast ();
670
730
}
671
731
}
672
732
673
733
/// Returns a module that represents the top-level members defined in [this] ,
674
734
/// that contains [css] as its CSS tree, which can be extended using
675
735
/// [extender] .
676
- Module toModule (CssStylesheet css, Extender extender) =>
677
- _EnvironmentModule (this , css, extender, forwarded: _forwardedModules);
736
+ Module toModule (CssStylesheet css, Extender extender) {
737
+ assert (atRoot);
738
+ return _EnvironmentModule (this , css, extender,
739
+ forwarded: _forwardedModules);
740
+ }
678
741
679
742
/// Returns the module with the given [namespace] , or throws a
680
743
/// [SassScriptException] if none exists.
@@ -687,14 +750,24 @@ class AsyncEnvironment {
687
750
}
688
751
689
752
/// Returns the result of [callback] if it returns non-`null` for exactly one
690
- /// module in [_globalModules] .
753
+ /// module in [_globalModules] *or* for any module in
754
+ /// [_nestedForwardedModules] .
691
755
///
692
756
/// Returns `null` if [callback] returns `null` for all modules. Throws an
693
757
/// error if [callback] returns non-`null` for more than one module.
694
758
///
695
759
/// The [type] should be the singular name of the value type being returned.
696
760
/// It's used to format an appropriate error message.
697
761
T _fromOneModule <T >(String type, T callback (Module module)) {
762
+ if (_nestedForwardedModules != null ) {
763
+ for (var modules in _nestedForwardedModules.reversed) {
764
+ for (var module in modules.reversed) {
765
+ var value = callback (module);
766
+ if (value != null ) return value;
767
+ }
768
+ }
769
+ }
770
+
698
771
if (_globalModules == null ) return null ;
699
772
700
773
T value;
0 commit comments