Skip to content

Commit

Permalink
Properly clear relative url cache
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 committed Apr 12, 2024
1 parent b1f777e commit ab21fb7
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 9 deletions.
19 changes: 15 additions & 4 deletions lib/src/async_import_cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ final class AsyncImportCache {
final _perImporterCanonicalizeCache =
<(AsyncImporter, Uri, {bool forImport}), AsyncCanonicalizeResult?>{};

/// A map from the keys in [_perImporterCanonicalizeCache] that are generated
/// for relative URL loads agains the base importer to the original relative
/// URLs what were loaded.
///
/// This is used to invalidate the cache when files are changed.
final _nonCanonicalRelativeUrls =
<(AsyncImporter, Uri, {bool forImport}), Uri>{};

/// The parsed stylesheets for each canonicalized import URL.
final _importCache = <Uri, Stylesheet?>{};

Expand Down Expand Up @@ -146,14 +154,16 @@ final class AsyncImportCache {

if (baseImporter != null && url.scheme == '') {
var resolvedUrl = baseUrl?.resolveUri(url) ?? url;
var relativeResult = await putIfAbsentAsync(_perImporterCanonicalizeCache,
(baseImporter, resolvedUrl, forImport: forImport), () async {
var key = (baseImporter, resolvedUrl, forImport: forImport);
var relativeResult =
await putIfAbsentAsync(_perImporterCanonicalizeCache, key, () async {
var (result, cacheable) =
await _canonicalize(baseImporter, resolvedUrl, baseUrl, forImport);
assert(
cacheable,
"Relative loads should always be cacheable because they never "
"provide access to the containing URL.");
if (baseUrl != null) _nonCanonicalRelativeUrls[key] = url;
return result;
});
if (relativeResult != null) return relativeResult;
Expand Down Expand Up @@ -327,7 +337,7 @@ final class AsyncImportCache {
Uri sourceMapUrl(Uri canonicalUrl) =>
_resultsCache[canonicalUrl]?.sourceMapUrl ?? canonicalUrl;

/// Clears the cached canonical version of the given [url].
/// Clears the cached canonical version of the given non-canonical [url].
///
/// Has no effect if the canonical version of [url] has not been cached.
///
Expand All @@ -336,7 +346,8 @@ final class AsyncImportCache {
void clearCanonicalize(Uri url) {
_canonicalizeCache.remove((url, forImport: false));
_canonicalizeCache.remove((url, forImport: true));
_perImporterCanonicalizeCache.removeWhere((key, _) => key.$2 == url);
_perImporterCanonicalizeCache.removeWhere(
(key, _) => key.$2 == url || _nonCanonicalRelativeUrls[key] == url);
}

/// Clears the cached parse tree for the stylesheet with the given
Expand Down
19 changes: 14 additions & 5 deletions lib/src/import_cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// DO NOT EDIT. This file was generated from async_import_cache.dart.
// See tool/grind/synchronize.dart for details.
//
// Checksum: 38c8e9f5ef4b26236b7ea3cbbfdde71738bdb7ea
// Checksum: f35ebb343f6ab31ebbb09ecfd27b203045735f83
//
// ignore_for_file: unused_import

Expand Down Expand Up @@ -61,6 +61,13 @@ final class ImportCache {
final _perImporterCanonicalizeCache =
<(Importer, Uri, {bool forImport}), CanonicalizeResult?>{};

/// A map from the keys in [_perImporterCanonicalizeCache] that are generated
/// for relative URL loads agains the base importer to the original relative
/// URLs what were loaded.
///
/// This is used to invalidate the cache when files are changed.
final _nonCanonicalRelativeUrls = <(Importer, Uri, {bool forImport}), Uri>{};

/// The parsed stylesheets for each canonicalized import URL.
final _importCache = <Uri, Stylesheet?>{};

Expand Down Expand Up @@ -146,14 +153,15 @@ final class ImportCache {

if (baseImporter != null && url.scheme == '') {
var resolvedUrl = baseUrl?.resolveUri(url) ?? url;
var relativeResult = _perImporterCanonicalizeCache
.putIfAbsent((baseImporter, resolvedUrl, forImport: forImport), () {
var key = (baseImporter, resolvedUrl, forImport: forImport);
var relativeResult = _perImporterCanonicalizeCache.putIfAbsent(key, () {
var (result, cacheable) =
_canonicalize(baseImporter, resolvedUrl, baseUrl, forImport);
assert(
cacheable,
"Relative loads should always be cacheable because they never "
"provide access to the containing URL.");
if (baseUrl != null) _nonCanonicalRelativeUrls[key] = url;
return result;
});
if (relativeResult != null) return relativeResult;
Expand Down Expand Up @@ -324,7 +332,7 @@ final class ImportCache {
Uri sourceMapUrl(Uri canonicalUrl) =>
_resultsCache[canonicalUrl]?.sourceMapUrl ?? canonicalUrl;

/// Clears the cached canonical version of the given [url].
/// Clears the cached canonical version of the given non-canonical [url].
///
/// Has no effect if the canonical version of [url] has not been cached.
///
Expand All @@ -333,7 +341,8 @@ final class ImportCache {
void clearCanonicalize(Uri url) {
_canonicalizeCache.remove((url, forImport: false));
_canonicalizeCache.remove((url, forImport: true));
_perImporterCanonicalizeCache.removeWhere((key, _) => key.$2 == url);
_perImporterCanonicalizeCache.removeWhere(
(key, _) => key.$2 == url || _nonCanonicalRelativeUrls[key] == url);
}

/// Clears the cached parse tree for the stylesheet with the given
Expand Down

0 comments on commit ab21fb7

Please sign in to comment.