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
This commit is contained in:
Natalie Weizenbaum 2021-08-11 16:19:24 -07:00
parent 000173c132
commit 707db69de8
3 changed files with 22 additions and 10 deletions

View File

@ -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

View File

@ -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.
@ -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;
}
});
}

View File

@ -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;
}