Skip to content

Commit

Permalink
Fix a couple bugs with @extend
Browse files Browse the repository at this point in the history
We weren't properly merging multiple @extend rules that were added to
an upstream module at the same time, so some of them weren't being
marked as satisfied.

Closes #1393
  • Loading branch information
nex3 committed Aug 12, 2021
1 parent 000173c commit 707db69
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 10 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

* Properly parse backslash escapes within `url()` expressions.

* Fix a couple bugs where `@extend`s could be marked as unsatisfied when
multiple identical `@extend`s extended selectors across `@use` rules.

### Command Line Interface

* Strip CRLF newlines from snippets of the original stylesheet that are included
Expand Down
17 changes: 7 additions & 10 deletions lib/src/extend/extension_store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ class ExtensionStore {
/// Extends [this] with all the extensions in [extensions].
///
/// These extensions will extend all selectors already in [this], but they
/// will *not* extend other extensions from [extenders].
/// will *not* extend other extensions from [extensionStores].
void addExtensions(Iterable<ExtensionStore> extensionStores) {
// Extensions already in [this] whose extenders are extended by
// [extensions], and thus which need to be updated.
Expand Down Expand Up @@ -445,21 +445,18 @@ class ExtensionStore {
// Add [newSources] to [_extensions].
var existingSources = _extensions[target];
if (existingSources == null) {
_extensions[target] = newSources;
_extensions[target] = Map.of(newSources);
if (extensionsForTarget != null || selectorsForTarget != null) {
(newExtensions ??= {})[target] = newSources;
(newExtensions ??= {})[target] = Map.of(newSources);
}
} else {
newSources.forEach((extender, extension) {
// If [extender] already extends [target] in [_extensions], we don't
// need to re-run the extension.
if (existingSources.containsKey(extender)) return;
existingSources[extender] = extension;
extension = existingSources.putOrMerge(
extender, extension, MergedExtension.merge);

if (extensionsForTarget != null || selectorsForTarget != null) {
(newExtensions ??= {})
.putIfAbsent(target, () => {})
.putIfAbsent(extender, () => extension);
(newExtensions ??= {}).putIfAbsent(target, () => {})[extender] =
extension;
}
});
}
Expand Down
12 changes: 12 additions & 0 deletions lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -403,3 +403,15 @@ extension SpanExtensions on FileSpan {
: file.span(this.start.offset + start, this.start.offset + end + 1);
}
}

extension MapExtension<K, V> on Map<K, V> {
/// If [this] doesn't contain the given [key], sets that key to [value] and
/// returns it.
///
/// Otherwise, calls [merge] with the existing value and [value] and sets
/// [key] to the result.
V putOrMerge(K key, V value, V Function(V oldValue, V newValue) merge) =>
containsKey(key)
? this[key] = merge(this[key]!, value)
: this[key] = value;
}

0 comments on commit 707db69

Please sign in to comment.