@@ -25,6 +25,7 @@ import 'module/reference_source.dart';
2525import 'module/references.dart' ;
2626import 'module/unreferencable_members.dart' ;
2727import 'module/unreferencable_type.dart' ;
28+ import 'module/use_allowed.dart' ;
2829
2930/// Migrates stylesheets to the new module system.
3031class ModuleMigrator extends Migrator {
@@ -99,17 +100,19 @@ class ModuleMigrator extends Migrator {
99100 'You must provide --remove-prefix with --forward=prefixed so we know '
100101 'which prefixed members to forward.' );
101102 }
103+ var safeAtRules = (argResults! ['safe-at-rule' ] as List <String >).toSet ();
102104
103- var references = References (importCache, stylesheet, importer,
104- safeAtRules : argResults ! [ 'safe-at-rule' ] as List < String > );
105+ var references =
106+ References (importCache, stylesheet, importer, safeAtRules : safeAtRules );
105107 var visitor = _ModuleMigrationVisitor (
106108 importCache, references, globalResults! ['load-path' ] as List <String >,
107109 migrateDependencies: migrateDependencies,
108110 builtInOnly: builtInOnly,
109111 prefixesToRemove: (argResults! ['remove-prefix' ] as List <String >)
110112 .map ((prefix) => prefix.replaceAll ('_' , '-' )),
111113 forwards: forwards,
112- unsafeHoist: argResults! ['unsafe-hoist' ] as bool );
114+ unsafeHoist: argResults! ['unsafe-hoist' ] as bool ,
115+ safeAtRules: safeAtRules);
113116 var migrated = visitor.run (stylesheet, importer);
114117 _filesWithRenamedDeclarations.addAll (
115118 {for (var member in visitor.renamedMembers.keys) member.sourceUrl});
@@ -188,8 +191,9 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
188191 /// or `@forward` rule, or null if none has been visited yet.
189192 FileLocation ? _afterLastImport;
190193
191- /// Whether @use and @forward are allowed in the current context.
192- var _useAllowed = true ;
194+ /// The state of whether `@use` and `@forward` are allowed at the current
195+ /// point in the file.
196+ var _useAllowed = UseAllowed .allowed;
193197
194198 /// Whether an import-only stylesheet should be generated.
195199 ///
@@ -231,6 +235,10 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
231235 /// emit CSS.
232236 final bool unsafeHoist;
233237
238+ /// CSS at rules that should be considered to not emit CSS for the purpose
239+ /// of hoisting late `@import` rules.
240+ final Set <String > safeAtRules;
241+
234242 /// Constructs a new module migration visitor.
235243 ///
236244 /// [importCache] must be the same one used by [references] .
@@ -248,7 +256,8 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
248256 required this .builtInOnly,
249257 required this .unsafeHoist,
250258 Iterable <String > prefixesToRemove = const [],
251- this .forwards = const {}})
259+ this .forwards = const {},
260+ this .safeAtRules = const {}})
252261 : loadPaths = List .unmodifiable (
253262 loadPaths.map ((path) => p.toUri (p.absolute (path)).path)),
254263 prefixesToRemove = UnmodifiableSetView (prefixesToRemove.toSet ());
@@ -470,7 +479,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
470479 __additionalRelativeUseRules = {};
471480 _beforeFirstImport = null ;
472481 _afterLastImport = null ;
473- _useAllowed = true ;
482+ _useAllowed = UseAllowed .allowed ;
474483 super .visitStylesheet (node);
475484 __namespaces = oldNamespaces;
476485 __forwardedUrls = oldForwardedUrls;
@@ -804,7 +813,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
804813 /// Visits a `@function` rule, renaming if necessary.
805814 @override
806815 void visitFunctionRule (FunctionRule node) {
807- _useAllowed = false ;
816+ _useAllowed = UseAllowed .notAllowed ;
808817 _renameReference (nameSpan (node), MemberDeclaration (node));
809818 super .visitFunctionRule (node);
810819 }
@@ -816,7 +825,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
816825 var (staticImports, dynamicImports) =
817826 partitionOnType <Import , StaticImport , DynamicImport >(node.imports);
818827 if (dynamicImports.isEmpty) {
819- _useAllowed = false ;
828+ _useAllowed = _useAllowed. lowerToRequiresHoist () ;
820829 return ;
821830 }
822831 String rulesText;
@@ -853,10 +862,11 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
853862 visitDependency (ruleUrl, import.span);
854863 _upstreamStylesheets.remove (currentUrl);
855864 }
856- } else if (_useAllowed) {
865+ } else if (_useAllowed.canMigrateInPlace ) {
857866 inPlaceUseRules.addAll (_migrateImportToRules (ruleUrl, import.span));
858867 } else if (! isNested &&
859- (! (references.fileEmitsCss[canonicalUrl] ?? true ) ||
868+ (_useAllowed.canAlwaysSafelyHoist ||
869+ ! (references.fileEmitsCss[canonicalUrl] ?? true ) ||
860870 (unsafeHoist &&
861871 references.anyMemberReferenced (
862872 canonicalUrl, currentUrl)))) {
@@ -878,14 +888,14 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
878888 } else {
879889 addPatch (Patch (node.span, rulesText));
880890 }
881- if (_useAllowed) {
891+ if (_useAllowed.canMigrateInPlace ) {
882892 _beforeFirstImport ?? = node.span.start;
883893 _afterLastImport = afterImport (node,
884894 shouldHaveSemicolon: ! currentUrl.path.endsWith ('.sass' ));
885895 }
886896
887897 if (staticImports.isNotEmpty) {
888- _useAllowed = false ;
898+ _useAllowed = _useAllowed. lowerToRequiresHoist () ;
889899 addPatch (Patch .insert (
890900 _afterLastImport ?? node.span.file.location (0 ),
891901 '$indent @import ' +
@@ -906,7 +916,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
906916 /// redirect to a different path to be migrated in-place.
907917 List <String > _migrateImportToRules (Uri ruleUrl, FileSpan context) {
908918 var (canonicalUrl, config, forwardForConfig) =
909- _migrateImportCommon (ruleUrl, context);
919+ _migrateImportCommon (ruleUrl, context, toLoadCss : false );
910920
911921 var asClause = '' ;
912922 var defaultNamespace = namespaceForPath (ruleUrl.path);
@@ -955,7 +965,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
955965 }
956966
957967 var (canonicalUrl, config, forwardForConfig) =
958- _migrateImportCommon (ruleUrl, context);
968+ _migrateImportCommon (ruleUrl, context, toLoadCss : true );
959969 if (forwardForConfig != null ) {
960970 throw MigrationSourceSpanException (
961971 "This declaration attempts to override a default value in an "
@@ -990,7 +1000,12 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
9901000 /// `meta.load-css` . The third is a string of variables that should be added
9911001 /// to a `show` clause of a `@forward` rule so that they can be configured by
9921002 /// an upstream file.
993- (Uri , String ? , String ? ) _migrateImportCommon (Uri ruleUrl, FileSpan context) {
1003+ ///
1004+ /// When [toLoadCss] is false, this uses the variable syntax for configuration
1005+ /// used by `@use` . When it is true, it instead uses the map syntax used by
1006+ /// `meta.load-css()` .
1007+ (Uri , String ? , String ? ) _migrateImportCommon (Uri ruleUrl, FileSpan context,
1008+ {required bool toLoadCss}) {
9941009 var oldConfiguredVariables = __configuredVariables;
9951010 __configuredVariables = {};
9961011 _upstreamStylesheets.add (currentUrl);
@@ -1057,7 +1072,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
10571072 var end = start + semicolon.length;
10581073 if (span.file.span (end, end + 1 ).text == '\n ' ) end++ ;
10591074 addPatch (patchDelete (span.file.span (start, end)));
1060- var nameFormat = _useAllowed ? '\$ $ name ' : '"$ name " ' ;
1075+ var nameFormat = toLoadCss ? '"$ name " ' : '\$ $ name ' ;
10611076 configured.add ("$nameFormat : ${variable .member .expression }" );
10621077 }
10631078 });
@@ -1157,7 +1172,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
11571172 /// Adds a namespace to any mixin include that requires it.
11581173 @override
11591174 void visitIncludeRule (IncludeRule node) {
1160- _useAllowed = false ;
1175+ _useAllowed = UseAllowed .notAllowed ;
11611176 super .visitIncludeRule (node);
11621177 if (node.namespace != null ) return ;
11631178 if (builtInOnly && references.sources[node] is ! BuiltInSource ) return ;
@@ -1178,7 +1193,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
11781193 /// Visits a `@mixin` rule, renaming it if necessary.
11791194 @override
11801195 void visitMixinRule (MixinRule node) {
1181- _useAllowed = false ;
1196+ _useAllowed = UseAllowed .notAllowed ;
11821197 if (! builtInOnly) _renameReference (nameSpan (node), MemberDeclaration (node));
11831198 super .visitMixinRule (node);
11841199 }
@@ -1421,84 +1436,88 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
14211436 /// Disallows `@use` after `@at-root` rules.
14221437 @override
14231438 void visitAtRootRule (AtRootRule node) {
1424- _useAllowed = false ;
1439+ _useAllowed = UseAllowed .notAllowed ;
14251440 super .visitAtRootRule (node);
14261441 }
14271442
1428- /// Disallows `@use` after at-rules.
1443+ /// Disallows `@use` after at-rules depending on [safeAtRules] .
14291444 @override
14301445 void visitAtRule (AtRule node) {
1431- _useAllowed = false ;
1446+ var oldUseAllowed = _useAllowed;
1447+ _useAllowed = UseAllowed .notAllowed;
14321448 super .visitAtRule (node);
1449+ if (safeAtRules.contains (node.name.asPlain)) {
1450+ _useAllowed = oldUseAllowed.lowerToRequiresHoist ();
1451+ }
14331452 }
14341453
1435- /// Disallows `@use` after `@debug` rules.
1454+ /// Requires hoisting `@use` after `@debug` rules.
14361455 @override
14371456 void visitDebugRule (DebugRule node) {
1438- _useAllowed = false ;
1457+ _useAllowed = _useAllowed. lowerToRequiresHoist () ;
14391458 super .visitDebugRule (node);
14401459 }
14411460
14421461 /// Disallows `@use` after `@each` rules.
14431462 @override
14441463 void visitEachRule (EachRule node) {
1445- _useAllowed = false ;
1464+ _useAllowed = UseAllowed .notAllowed ;
14461465 super .visitEachRule (node);
14471466 }
14481467
14491468 /// Disallows `@use` after `@error` rules.
14501469 @override
14511470 void visitErrorRule (ErrorRule node) {
1452- _useAllowed = false ;
1471+ _useAllowed = UseAllowed .notAllowed ;
14531472 super .visitErrorRule (node);
14541473 }
14551474
14561475 /// Disallows `@use` after `@for` rules.
14571476 @override
14581477 void visitForRule (ForRule node) {
1459- _useAllowed = false ;
1478+ _useAllowed = UseAllowed .notAllowed ;
14601479 super .visitForRule (node);
14611480 }
14621481
14631482 /// Disallows `@use` after `@if` rules.
14641483 @override
14651484 void visitIfRule (IfRule node) {
1466- _useAllowed = false ;
1485+ _useAllowed = UseAllowed .notAllowed ;
14671486 super .visitIfRule (node);
14681487 }
14691488
14701489 /// Disallows `@use` after `@media` rules.
14711490 @override
14721491 void visitMediaRule (MediaRule node) {
1473- _useAllowed = false ;
1492+ _useAllowed = UseAllowed .notAllowed ;
14741493 super .visitMediaRule (node);
14751494 }
14761495
14771496 /// Disallows `@use` after style rules.
14781497 @override
14791498 void visitStyleRule (StyleRule node) {
1480- _useAllowed = false ;
1499+ _useAllowed = UseAllowed .notAllowed ;
14811500 super .visitStyleRule (node);
14821501 }
14831502
14841503 /// Disallows `@use` after `@supports` rules.
14851504 @override
14861505 void visitSupportsRule (SupportsRule node) {
1487- _useAllowed = false ;
1506+ _useAllowed = UseAllowed .notAllowed ;
14881507 super .visitSupportsRule (node);
14891508 }
14901509
1491- /// Disallows `@use` after `@warn` rules.
1510+ /// Requires hoisting `@use` after `@warn` rules.
14921511 @override
14931512 void visitWarnRule (WarnRule node) {
1494- _useAllowed = false ;
1513+ _useAllowed = _useAllowed. lowerToRequiresHoist () ;
14951514 super .visitWarnRule (node);
14961515 }
14971516
14981517 /// Disallows `@use` after `@while` rules.
14991518 @override
15001519 void visitWhileRule (WhileRule node) {
1501- _useAllowed = false ;
1520+ _useAllowed = UseAllowed .notAllowed ;
15021521 super .visitWhileRule (node);
15031522 }
15041523}
0 commit comments