@@ -172,6 +172,12 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
172172 assertInStylesheet (__hoistedUseRules, '_hoistedUseRules' );
173173 Set <String >? __hoistedUseRules;
174174
175+ /// Set of `@include` rules from import-only files that need to be added after
176+ /// all `@use` and `@forward` rules.
177+ Set <String > get _postUseIncludeRules =>
178+ assertInStylesheet (__postUseIncludeRules, '_postUseIncludeRules' );
179+ Set <String >? __postUseIncludeRules;
180+
175181 /// Set of additional `@use` rules for stylesheets at a load path.
176182 Set <String > get _additionalLoadPathUseRules => assertInStylesheet (
177183 __additionalLoadPathUseRules, '_additionalLoadPathUseRules' );
@@ -457,6 +463,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
457463 var oldUsedUrls = __usedUrls;
458464 var oldBuiltInUseRules = __builtInUseRules;
459465 var oldHoistedUseRules = __hoistedUseRules;
466+ var oldPostUseIncludeRules = __postUseIncludeRules;
460467 var oldLoadPathUseRules = __additionalLoadPathUseRules;
461468 var oldRelativeUseRules = __additionalRelativeUseRules;
462469 var oldBeforeFirstImport = _beforeFirstImport;
@@ -475,6 +482,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
475482 __forwardedUrls = {};
476483 __builtInUseRules = {};
477484 __hoistedUseRules = {};
485+ __postUseIncludeRules = {};
478486 __additionalLoadPathUseRules = {};
479487 __additionalRelativeUseRules = {};
480488 _beforeFirstImport = null ;
@@ -486,6 +494,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
486494 __usedUrls = oldUsedUrls;
487495 __builtInUseRules = oldBuiltInUseRules;
488496 __hoistedUseRules = oldHoistedUseRules;
497+ __postUseIncludeRules = oldPostUseIncludeRules;
489498 __additionalLoadPathUseRules = oldLoadPathUseRules;
490499 __additionalRelativeUseRules = oldRelativeUseRules;
491500 _beforeFirstImport = oldBeforeFirstImport;
@@ -496,22 +505,23 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
496505 /// Adds additional patches for extra `@use` and `@forward` rules.
497506 @override
498507 void beforePatch (Stylesheet node) {
499- useRulesToString (Set <String > useRules ) =>
500- (useRules .toList ()..sort ()).map ((use ) => '$use $semicolon \n ' ).join ();
508+ rulesToString (Set <String > rules ) =>
509+ (rules .toList ()..sort ()).map ((rule ) => '$rule $semicolon \n ' ).join ();
501510
502511 if (_builtInUseRules.isNotEmpty) {
503512 // This is added before existing patches to ensure that this patch is
504513 // inserted before a patch converting an existing `@import` rule to a
505514 // `@use` rule.
506515 addPatch (
507516 Patch .insert (_beforeFirstImport ?? node.span.start,
508- useRulesToString (_builtInUseRules)),
517+ rulesToString (_builtInUseRules)),
509518 beforeExisting: true );
510519 }
511- var extras = useRulesToString (_hoistedUseRules) +
512- useRulesToString (_additionalLoadPathUseRules) +
513- useRulesToString (_additionalRelativeUseRules) +
514- _getAdditionalForwardRules ();
520+ var extras = rulesToString (_hoistedUseRules) +
521+ rulesToString (_additionalLoadPathUseRules) +
522+ rulesToString (_additionalRelativeUseRules) +
523+ _getAdditionalForwardRules () +
524+ rulesToString (_postUseIncludeRules);
515525 if (extras == '' ) return ;
516526 var insertionPoint = _afterLastImport ?? node.span.start;
517527 // If the insertion point is in the middle of a line, add a line break
@@ -831,7 +841,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
831841 String rulesText;
832842
833843 var inPlaceUseRules = < String > [];
834- var loadCssRules = < String > [];
844+ var includeRules = < String > [];
835845
836846 var indent = ' ' * node.span.start.column;
837847
@@ -855,6 +865,11 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
855865 var canonicalUrl = importCache
856866 .canonicalize (ruleUrl, baseImporter: importer, baseUrl: currentUrl)!
857867 .$2;
868+ var canonicalImport = importCache
869+ .canonicalize (ruleUrl,
870+ baseImporter: importer, baseUrl: currentUrl, forImport: true )!
871+ .$2;
872+ var importOnlyInclude = references.importOnlyIncludes[canonicalImport];
858873 var isNested = ! _currentStylesheet.children.contains (node);
859874 if (builtInOnly) {
860875 if (migrateDependencies) {
@@ -864,15 +879,23 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
864879 }
865880 } else if (_useAllowed.canMigrateInPlace) {
866881 inPlaceUseRules.addAll (_migrateImportToRules (ruleUrl, import.span));
867- } else if (! isNested &&
882+ if (importOnlyInclude != null ) {
883+ _postUseIncludeRules
884+ .add (_makeIncludeFromImportOnly (import, importOnlyInclude));
885+ }
886+ } else if ((! isNested || importOnlyInclude != null ) &&
868887 (_useAllowed.canAlwaysSafelyHoist ||
869888 ! (references.fileEmitsCss[canonicalUrl] ?? true ) ||
870889 (unsafeHoist &&
871890 references.anyMemberReferenced (
872891 canonicalUrl, currentUrl)))) {
873892 _hoistedUseRules.addAll (_migrateImportToRules (ruleUrl, import.span));
893+ if (importOnlyInclude != null ) {
894+ includeRules
895+ .add (_makeIncludeFromImportOnly (import, importOnlyInclude));
896+ }
874897 } else {
875- loadCssRules .add (
898+ includeRules .add (
876899 _migrateImportToLoadCss (ruleUrl, import.span, isNested)
877900 .replaceAll ('\n ' , '\n $indent ' ));
878901 }
@@ -881,7 +904,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
881904 if (builtInOnly) return ;
882905
883906 rulesText =
884- [...inPlaceUseRules, ...loadCssRules ].join ('$semicolon \n $indent ' );
907+ [...inPlaceUseRules, ...includeRules ].join ('$semicolon \n $indent ' );
885908 if (rulesText.isEmpty) {
886909 var span = node.span.extendIfMatches (RegExp (' *$semicolon \n ?' ));
887910 addPatch (patchDelete (span));
@@ -990,6 +1013,41 @@ class _ModuleMigrationVisitor extends MigrationVisitor {
9901013 return '@include $meta .load-css($quotedUrl $configuration )' ;
9911014 }
9921015
1016+ /// Creates an `@include` rule for the current file based on the `@include`
1017+ /// rule in an import-only file, adding any additional `@use` rules as
1018+ /// necessary.
1019+ String _makeIncludeFromImportOnly (DynamicImport import, IncludeRule rule) {
1020+ var declaration = references.mixins[rule];
1021+ if (declaration == null ) {
1022+ throw MigrationSourceSpanException (
1023+ "Couldn't find mixin referenced by import-only file." , import.span);
1024+ }
1025+ var namespace = _namespaceForDeclaration (declaration);
1026+ var args = [
1027+ for (var arg in rule.arguments.positional)
1028+ switch (arg) {
1029+ VariableExpression (: var name, namespace: _? ) =>
1030+ '${_namespaceForDeclaration (references .variables [arg ]!)}.\$ $name ' ,
1031+ VariableExpression (: var name) => '\$ $name ' ,
1032+ _ => throw MigrationSourceSpanException (
1033+ 'Import-only @include rules may only pass variables as arguments.' ,
1034+ arg.span),
1035+ },
1036+ for (var MapEntry (key: parameter, value: arg)
1037+ in rule.arguments.named.entries)
1038+ switch (arg) {
1039+ VariableExpression (: var name, namespace: _? ) => '\$ $parameter : '
1040+ '${_namespaceForDeclaration (references .variables [arg ]!)}.\$ $name ' ,
1041+ VariableExpression (: var name) => '\$ $parameter : \$ $name ' ,
1042+ _ => throw MigrationSourceSpanException (
1043+ 'Import-only @include rules may only pass variables as arguments.' ,
1044+ arg.span),
1045+ }
1046+ ];
1047+ var argString = args.isEmpty ? '' : '(${args .join (', ' )})' ;
1048+ return '@include $namespace .${rule .name }$argString ' ;
1049+ }
1050+
9931051 /// Common logic for migrating imports shared by both the normal migration to
9941052 /// `@use` /`@forward` rules and the migration to `meta.load-css` .
9951053 ///
0 commit comments