From 15b1b897aafbc6b19ac72154bf7950d6b465a9a1 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 22 Apr 2022 17:40:01 -0700 Subject: [PATCH] Update the order of maps returned by map.deep-merge() Closes sass/sass#3092 --- CHANGELOG.md | 7 +++++++ lib/src/functions/map.dart | 33 ++++++++++----------------------- pkg/sass_api/CHANGELOG.md | 4 ++++ pkg/sass_api/pubspec.yaml | 4 ++-- pubspec.yaml | 2 +- 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53e6dfaeb..6a98473aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.51.0 + +* **Potentially breaking change**: Change the order of maps returned by + `map.deep-merge()` to match those returned by `map.merge()`. All keys that + appeared in the first map will now be listed first in the same order they + appeared in that map, followed by any new keys added from the second map. + ## 1.50.1 ### Embedded Sass diff --git a/lib/src/functions/map.dart b/lib/src/functions/map.dart index f3fd5b007..7eb4843b1 100644 --- a/lib/src/functions/map.dart +++ b/lib/src/functions/map.dart @@ -193,41 +193,28 @@ Value _modify(SassMap map, Iterable keys, Value modify(Value old), /// If both [map1] and [map2] have a map value associated with the same key, /// this recursively merges those maps as well. SassMap _deepMergeImpl(SassMap map1, SassMap map2) { + if (map1.contents.isEmpty) return map2; if (map2.contents.isEmpty) return map1; - // Avoid making a mutable copy of `map2` if it would totally overwrite `map1` - // anyway. - var mutable = false; - var result = map2.contents; - void _ensureMutable() { - if (mutable) return; - mutable = true; - result = Map.of(result); - } + var result = Map.of(map1.contents); - // Because values in `map2` take precedence over `map1`, we just check if any - // entries in `map1` don't have corresponding keys in `map2`, or if they're - // maps that need to be merged in their own right. - map1.contents.forEach((key, value) { - var resultValue = result[key]; - if (resultValue == null) { - _ensureMutable(); + map2.contents.forEach((key, value) { + var resultMap = result[key]?.tryMap(); + if (resultMap == null) { result[key] = value; } else { - var resultMap = resultValue.tryMap(); var valueMap = value.tryMap(); - - if (resultMap != null && valueMap != null) { - var merged = _deepMergeImpl(valueMap, resultMap); + if (valueMap != null) { + var merged = _deepMergeImpl(resultMap, valueMap); if (identical(merged, resultMap)) return; - - _ensureMutable(); result[key] = merged; + } else { + result[key] = value; } } }); - return mutable ? SassMap(result) : map2; + return SassMap(result); } /// Like [new BuiltInCallable.function], but always sets the URL to `sass:map`. diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index 2a72cbe42..205ac9a3a 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0-beta.43 + +* No user-visible changes. + ## 1.0.0-beta.42 * No user-visible changes. diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index 7d00cde1b..612a4e92d 100644 --- a/pkg/sass_api/pubspec.yaml +++ b/pkg/sass_api/pubspec.yaml @@ -2,7 +2,7 @@ name: sass_api # Note: Every time we add a new Sass AST node, we need to bump the *major* # version because it's a breaking change for anyone who's implementing the # visitor interface(s). -version: 1.0.0-beta.42 +version: 1.0.0-beta.43 description: Additional APIs for Dart Sass. homepage: https://github.com/sass/dart-sass @@ -10,7 +10,7 @@ environment: sdk: '>=2.12.0 <3.0.0' dependencies: - sass: 1.50.1 + sass: 1.51.0 dependency_overrides: sass: {path: ../..} diff --git a/pubspec.yaml b/pubspec.yaml index 4d5a38985..8b50d8de3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.50.1 +version: 1.51.0 description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass