22// MIT-style license that can be found in the LICENSE file or at
33// https://opensource.org/licenses/MIT.
44
5- import 'package:tuple/tuple .dart' ;
5+ import 'package:collection/collection .dart' ;
66
77import '../ast/sass.dart' ;
88import 'recursive_statement.dart' ;
99
10- /// Returns two lists of dependencies for [stylesheet] .
11- ///
12- /// The first is a list of URLs from all `@use` and `@forward` rules in
13- /// [stylesheet] (excluding built-in modules). The second is a list of all
14- /// imports in [stylesheet] .
10+ /// Returns [stylesheet] 's statically-declared dependencies.
1511///
1612/// {@category Dependencies}
17- Tuple2 < List < Uri >, List < Uri >> findDependencies (Stylesheet stylesheet) =>
13+ DependencyReport findDependencies (Stylesheet stylesheet) =>
1814 _FindDependenciesVisitor ().run (stylesheet);
1915
20- /// A visitor that traverses a stylesheet and records, all `@import` , `@use` ,
21- /// and `@forward` rules (excluding built-in modules) it contains .
16+ /// A visitor that traverses a stylesheet and records all its dependencies on
17+ /// other stylesheets .
2218class _FindDependenciesVisitor with RecursiveStatementVisitor {
23- final _usesAndForwards = < Uri > [];
24- final _imports = < Uri > [];
19+ final _uses = < Uri > {};
20+ final _forwards = < Uri > {};
21+ final _metaLoadCss = < Uri > {};
22+ final _imports = < Uri > {};
23+
24+ /// The namespaces under which `sass:meta` has been `@use` d in this stylesheet.
25+ ///
26+ /// If this contains `null` , it means `sass:meta` was loaded without a
27+ /// namespace.
28+ final _metaNamespaces = < String ? > {};
2529
26- Tuple2 < List < Uri >, List < Uri >> run (Stylesheet stylesheet) {
30+ DependencyReport run (Stylesheet stylesheet) {
2731 visitStylesheet (stylesheet);
28- return Tuple2 (_usesAndForwards, _imports);
32+ return DependencyReport ._(
33+ uses: UnmodifiableSetView (_uses),
34+ forwards: UnmodifiableSetView (_forwards),
35+ metaLoadCss: UnmodifiableSetView (_metaLoadCss),
36+ imports: UnmodifiableSetView (_imports));
2937 }
3038
3139 // These can never contain imports.
@@ -38,16 +46,63 @@ class _FindDependenciesVisitor with RecursiveStatementVisitor {
3846 void visitSupportsCondition (SupportsCondition condition) {}
3947
4048 void visitUseRule (UseRule node) {
41- if (node.url.scheme != 'sass' ) _usesAndForwards.add (node.url);
49+ if (node.url.scheme != 'sass' ) {
50+ _uses.add (node.url);
51+ } else if (node.url.toString () == 'sass:meta' ) {
52+ _metaNamespaces.add (node.namespace);
53+ }
4254 }
4355
4456 void visitForwardRule (ForwardRule node) {
45- if (node.url.scheme != 'sass' ) _usesAndForwards .add (node.url);
57+ if (node.url.scheme != 'sass' ) _forwards .add (node.url);
4658 }
4759
4860 void visitImportRule (ImportRule node) {
4961 for (var import in node.imports) {
5062 if (import is DynamicImport ) _imports.add (import.url);
5163 }
5264 }
65+
66+ void visitIncludeRule (IncludeRule node) {
67+ if (node.name != 'load-css' ) return ;
68+ if (! _metaNamespaces.contains (node.namespace)) return ;
69+ if (node.arguments.positional.isEmpty) return ;
70+ var argument = node.arguments.positional.first;
71+ if (argument is ! StringExpression ) return ;
72+ var url = argument.text.asPlain;
73+ try {
74+ if (url != null ) _metaLoadCss.add (Uri .parse (url));
75+ } on FormatException {
76+ // Ignore invalid URLs.
77+ }
78+ }
79+ }
80+
81+ /// A struct of different types of dependencies a Sass stylesheet can contain.
82+ class DependencyReport {
83+ /// An unmodifiable set of all `@use` d URLs in the stylesheet (exluding
84+ /// built-in modules).
85+ final Set <Uri > uses;
86+
87+ /// An unmodifiable set of all `@forward` ed URLs in the stylesheet (excluding
88+ /// built-in modules).
89+ final Set <Uri > forwards;
90+
91+ /// An unmodifiable set of all URLs loaded by `meta.load-css()` calls with
92+ /// static string arguments outside of mixins.
93+ final Set <Uri > metaLoadCss;
94+
95+ /// An unmodifiable set of all dynamically `@import` ed URLs in the
96+ /// stylesheet.
97+ final Set <Uri > imports;
98+
99+ /// An unmodifiable set of all URLs in [uses] , [forwards] , and [metaLoadCss] .
100+ Set <Uri > get modules => UnionSet ({uses, forwards, metaLoadCss});
101+
102+ /// An unmodifiable set of all URLs in [uses] , [forwards] , [metaLoadCss] , and
103+ /// [imports] .
104+ Set <Uri > get all => UnionSet ({uses, forwards, metaLoadCss, imports});
105+
106+ DependencyReport ._(
107+ {required this .uses, required this .forwards, required this .metaLoadCss, required this .imports});
53108}
0 commit comments