Skip to content

Commit 707db69

Browse files
committed
Fix a couple bugs with @extend
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
1 parent 000173c commit 707db69

File tree

3 files changed

+22
-10
lines changed

3 files changed

+22
-10
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

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

10+
* Fix a couple bugs where `@extend`s could be marked as unsatisfied when
11+
multiple identical `@extend`s extended selectors across `@use` rules.
12+
1013
### Command Line Interface
1114

1215
* Strip CRLF newlines from snippets of the original stylesheet that are included

lib/src/extend/extension_store.dart

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ class ExtensionStore {
409409
/// Extends [this] with all the extensions in [extensions].
410410
///
411411
/// These extensions will extend all selectors already in [this], but they
412-
/// will *not* extend other extensions from [extenders].
412+
/// will *not* extend other extensions from [extensionStores].
413413
void addExtensions(Iterable<ExtensionStore> extensionStores) {
414414
// Extensions already in [this] whose extenders are extended by
415415
// [extensions], and thus which need to be updated.
@@ -445,21 +445,18 @@ class ExtensionStore {
445445
// Add [newSources] to [_extensions].
446446
var existingSources = _extensions[target];
447447
if (existingSources == null) {
448-
_extensions[target] = newSources;
448+
_extensions[target] = Map.of(newSources);
449449
if (extensionsForTarget != null || selectorsForTarget != null) {
450-
(newExtensions ??= {})[target] = newSources;
450+
(newExtensions ??= {})[target] = Map.of(newSources);
451451
}
452452
} else {
453453
newSources.forEach((extender, extension) {
454-
// If [extender] already extends [target] in [_extensions], we don't
455-
// need to re-run the extension.
456-
if (existingSources.containsKey(extender)) return;
457-
existingSources[extender] = extension;
454+
extension = existingSources.putOrMerge(
455+
extender, extension, MergedExtension.merge);
458456

459457
if (extensionsForTarget != null || selectorsForTarget != null) {
460-
(newExtensions ??= {})
461-
.putIfAbsent(target, () => {})
462-
.putIfAbsent(extender, () => extension);
458+
(newExtensions ??= {}).putIfAbsent(target, () => {})[extender] =
459+
extension;
463460
}
464461
});
465462
}

lib/src/utils.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,3 +403,15 @@ extension SpanExtensions on FileSpan {
403403
: file.span(this.start.offset + start, this.start.offset + end + 1);
404404
}
405405
}
406+
407+
extension MapExtension<K, V> on Map<K, V> {
408+
/// If [this] doesn't contain the given [key], sets that key to [value] and
409+
/// returns it.
410+
///
411+
/// Otherwise, calls [merge] with the existing value and [value] and sets
412+
/// [key] to the result.
413+
V putOrMerge(K key, V value, V Function(V oldValue, V newValue) merge) =>
414+
containsKey(key)
415+
? this[key] = merge(this[key]!, value)
416+
: this[key] = value;
417+
}

0 commit comments

Comments
 (0)