diff --git a/lib/src/async_import_cache.dart b/lib/src/async_import_cache.dart index cdf650350..94bc45ac3 100644 --- a/lib/src/async_import_cache.dart +++ b/lib/src/async_import_cache.dart @@ -141,12 +141,9 @@ class AsyncImportCache { /// returns a relative URL. Future _canonicalize( AsyncImporter importer, Uri url, bool forImport) async { - Uri result; - if (forImport) { - result = await inImportRule(() => importer.canonicalize(url)); - } else { - result = await importer.canonicalize(url); - } + var result = await (forImport + ? inImportRule(() => importer.canonicalize(url)) + : importer.canonicalize(url)); if (result?.scheme == '') { _logger.warn(""" Importer $importer canonicalized $url to $result. diff --git a/lib/src/executable/watch.dart b/lib/src/executable/watch.dart index 140145890..f596c0d5e 100644 --- a/lib/src/executable/watch.dart +++ b/lib/src/executable/watch.dart @@ -288,9 +288,9 @@ class _Watcher { var changed = []; for (var node in _graph.nodes.values) { var importChanged = false; - for (var tuple in node.upstream.keys) { - var url = tuple.item1; - if (_name(p.url.basename(url.path)) != name) continue; + var forImport = false; + void recanonicalize(Uri url, StylesheetNode node) { + if (_name(p.url.basename(url.path)) != name) return; _graph.clearCanonicalize(url); // If the import produces a different canonicalized URL than it did @@ -302,15 +302,19 @@ class _Watcher { .canonicalize(url, baseImporter: node.importer, baseUrl: node.canonicalUrl, - forImport: tuple.item2) + forImport: forImport) ?.item2; } catch (_) { - // If the call to canonicalize failed, do nothing. We'll surface the - // error more nicely when we try to recompile the file. + // If the call to canonicalize failed, do nothing. We'll surface + // the error more nicely when we try to recompile the file. } - importChanged = newCanonicalUrl != node.upstream[tuple]?.canonicalUrl; + importChanged = newCanonicalUrl != node?.canonicalUrl; } } + + node.upstream.forEach(recanonicalize); + forImport = true; + node.upstreamImports.forEach(recanonicalize); if (importChanged) changed.add(node); } diff --git a/lib/src/import_cache.dart b/lib/src/import_cache.dart index 0ed9bca89..9613dafbd 100644 --- a/lib/src/import_cache.dart +++ b/lib/src/import_cache.dart @@ -5,7 +5,7 @@ // DO NOT EDIT. This file was generated from async_import_cache.dart. // See tool/grind/synchronize.dart for details. // -// Checksum: e3bcbb88321ab00d5c7341fabd792633be874f07 +// Checksum: 3ca2f221c3c1503c688be49d4f7501bd9be8031a // // ignore_for_file: unused_import @@ -142,12 +142,9 @@ class ImportCache { /// Calls [importer.canonicalize] and prints a deprecation warning if it /// returns a relative URL. Uri _canonicalize(Importer importer, Uri url, bool forImport) { - Uri result; - if (forImport) { - result = inImportRule(() => importer.canonicalize(url)); - } else { - result = importer.canonicalize(url); - } + var result = (forImport + ? inImportRule(() => importer.canonicalize(url)) + : importer.canonicalize(url)); if (result?.scheme == '') { _logger.warn(""" Importer $importer canonicalized $url to $result. diff --git a/lib/src/importer/utils.dart b/lib/src/importer/utils.dart index fa6569378..8bf19a736 100644 --- a/lib/src/importer/utils.dart +++ b/lib/src/importer/utils.dart @@ -40,7 +40,7 @@ Future inImportRuleAsync(Future callback()) async { /// Resolves an imported path using the same logic as the filesystem importer. /// -/// This tries to fill in extensions and partial prefixes and check if a +/// This tries to fill in extensions and partial prefixes and check for a /// directory default. If no file can be found, it returns `null`. String resolveImportPath(String path) { var extension = p.extension(path); diff --git a/lib/src/stylesheet_graph.dart b/lib/src/stylesheet_graph.dart index 989538776..f4b9a6190 100644 --- a/lib/src/stylesheet_graph.dart +++ b/lib/src/stylesheet_graph.dart @@ -40,7 +40,10 @@ class StylesheetGraph { DateTime transitiveModificationTime(StylesheetNode node) { return _transitiveModificationTimes.putIfAbsent(node.canonicalUrl, () { var latest = node.importer.modificationTime(node.canonicalUrl); - for (var upstream in node.upstream.values) { + for (var upstream in { + ...node.upstream.values, + ...node.upstreamImports.values + }) { // If an import is missing, always recompile so we show the user the // error. var upstreamTime = upstream == null @@ -93,18 +96,18 @@ class StylesheetGraph { /// Returns a map from non-canonicalized imported URLs in [stylesheet], which /// appears within [baseUrl] imported by [baseImporter]. - Map, StylesheetNode> _upstreamNodes( + Tuple2, Map> _upstreamNodes( Stylesheet stylesheet, Importer baseImporter, Uri baseUrl) { var active = {baseUrl}; var tuple = findDependencies(stylesheet); var importUrls = tuple.item2.map((import) => Uri.parse(import.url)); - return { + return Tuple2({ for (var url in tuple.item1) - Tuple2(url, false): _nodeFor(url, baseImporter, baseUrl, active), + url: _nodeFor(url, baseImporter, baseUrl, active) + }, { for (var url in importUrls) - Tuple2(url, true): - _nodeFor(url, baseImporter, baseUrl, active, forImport: true) - }; + url: _nodeFor(url, baseImporter, baseUrl, active, forImport: true) + }); } /// Re-parses the stylesheet at [canonicalUrl] and updates the dependency graph @@ -238,30 +241,45 @@ class StylesheetNode { /// The canonical URL of [stylesheet]. final Uri canonicalUrl; - /// A map from non-canonicalized import URLs in [stylesheet] to the + /// A map from non-canonicalized `@use` and `@forward` URLs in [stylesheet] to + /// the stylesheets those rules refer to. + /// + /// This may have `null` values, which indicate failed imports. + Map get upstream => UnmodifiableMapView(_upstream); + Map _upstream; + + /// A map from non-canonicalized `@import` URLs in [stylesheet] to the /// stylesheets those imports refer to. /// /// This may have `null` values, which indicate failed imports. - Map, StylesheetNode> get upstream => - UnmodifiableMapView(_upstream); - Map, StylesheetNode> _upstream; + Map get upstreamImports => + UnmodifiableMapView(_upstreamImports); + Map _upstreamImports; /// The stylesheets that import [stylesheet]. Set get downstream => UnmodifiableSetView(_downstream); final _downstream = {}; - StylesheetNode._( - this._stylesheet, this.importer, this.canonicalUrl, this._upstream) { - for (var node in upstream.values) { + StylesheetNode._(this._stylesheet, this.importer, this.canonicalUrl, + Tuple2, Map> allUpstream) + : _upstream = allUpstream.item1, + _upstreamImports = allUpstream.item2 { + for (var node in {...upstream.values, ...upstreamImports.values}) { if (node != null) node._downstream.add(this); } } - /// Sets [newUpstream] as the new value of [upstream] and adjusts upstream - /// nodes' [downstream] fields accordingly. - void _replaceUpstream(Map, StylesheetNode> newUpstream) { - var oldUpstream = Set.of(upstream.values)..remove(null); - var newUpstreamSet = Set.of(newUpstream.values)..remove(null); + /// Sets [newUpstream] as the new value of [upstream] and [newUpstreamImports] + /// as the new value of [upstreamImports], and adjusts upstream nodes' + /// [downstream] fields accordingly. + void _replaceUpstream( + Tuple2, Map> allUpstream) { + var oldUpstream = {...upstream.values, ...upstreamImports.values} + ..remove(null); + var newUpstreamSet = { + ...allUpstream.item1.values, + ...allUpstream.item2.values + }..remove(null); for (var removed in oldUpstream.difference(newUpstreamSet)) { var wasRemoved = removed._downstream.remove(this); @@ -273,13 +291,14 @@ class StylesheetNode { assert(wasAdded); } - _upstream = newUpstream; + _upstream = allUpstream.item1; + _upstreamImports = allUpstream.item2; } /// Removes [this] as an upstream and downstream node from all the nodes that /// import it and that it imports. void _remove() { - for (var node in upstream.values) { + for (var node in {...upstream.values, ...upstreamImports.values}) { if (node == null) continue; var wasRemoved = node._downstream.remove(this); assert(wasRemoved); @@ -292,6 +311,12 @@ class StylesheetNode { break; } } + for (var url in node._upstreamImports.keys.toList()) { + if (node._upstreamImports[url] == this) { + node._upstreamImports[url] = null; + break; + } + } } } }