Open Undistraction opened 10 years ago
I'd recommend using Toolkit's Settings functionality to do what you're requesting. Otherwise, map-set-deep
exists and should allow for that.
@Snugug I think it would be a really useful bit of functionality in Sassy Maps and would nicely complement map-get-deep
and map-set-deep
. In case you change your mind, here is a function that deep merges two maps:
@function map-merge-deep($map-old, $map-new, $overwrite: true){
// Iterate through each value of the new map
@each $key, $new-value in $map-new {
// Check if that value already exists on the old map
@if map-has-key($map-old, $key) {
// There is an existing key
$old-value: map-get($map-old, $key);
@if type-of($new-value) == map and type-of($old-value) == map {
// If both are maps, recurse regardless of $overwrite
$merged-value: map-merge-deep($old-value, $new-value);
$map-old: map-set($map-old, $key, $merged-value);
}@else{
// Otherwise check $overwrite
@if $overwrite{
$map-old: map-set($map-old, $key, $new-value);
}
}
}@else{
// There is no existing key so add
$map-old: map-set($map-old, $key, $new-value);
}
}
@return $map-old
}
Sassmeister Gist here
I guess I'm not sure what you're looking for exactly. What's the difference in output between set-deep and merge-deep? Also, if you'd like code to be considered, as a PR please.
I'm looking for a way to take two maps and combine them into a new map that contains all the values from the first map and all all the values from the second, overwriting the values from the first if they are already present.
The problem with map-merge is that it won't recurse into values that are themselves maps. The problem with map-set-deep is that I need to know the path into the map to change the value; to change all values I need to recurse through the map and call map-set-deep for each value to avoid blowing away existing values. The function above recurses through the map as deep as is needed and either creates or replaces values, ultimately returning the merged map.
If you look at the Sassmeister you will see the output is a merging of map-1 and map-2.
I would be more than happy to submit a pull request if this functionality is something you would find useful.
Here are two maps and the resulting merged map
$map-1:(
alpha: 1,
beta: 1,
charlie:(
delta: 1,
echo: 1,
foxtrot:(
gamma: 1,
hotel: 1
)
)
);
$map-2:(
alpha: 2,
charlie: (
echo: 2,
foxtrot: (
hotel: 2,
yankee:(
omega: 2
)
)
),
indigo: (
juliette: 2
)
);
$result:(
alpha: 2,
beta: 1,
charlie: (
delta: 1,
echo: 2,
foxtrot: (
gamma: 1,
hotel: 2,
yankee: (
omega: 2
),
indigo: (
juliette: 2
)
)
)
+1!!
@cibulka There is a PR open with the function or you can grab it here
Thanks for an awesomely quick response! And about my question I've just deleted - everything works, I've just, well, forgot to include sassy-maps
to my configuration. :) Thanks again, this helps me a lot!
@cibulka No problem. Glad it's helpful.
Gentle bump.
The following works for me
@function spire-map-extend($map, $maps.../*, $deep */) {
$last: nth($maps, -1);
$deep: $last == true;
$max: if($deep, length($maps) - 1, length($maps));
// Loop through all maps in $maps...
@for $i from 1 through $max {
// Store current map
$current: nth($maps, $i);
// If not in deep mode, simply merge current map with map
@if not $deep {
$map: map-merge($map, $current);
} @else {
// If in deep mode, loop through all tuples in current map
@each $key, $value in $current {
// If value is a nested map and same key from map is a nested map as well
@if type-of($value) == "map" and type-of(map-get($map, $key)) == "map" {
// Recursive extend
$value: spire-map-extend(map-get($map, $key), $value, true);
}
// Merge current tuple with map
$map: map-merge($map, ($key: $value));
}
}
}
@return $map;
}
There is not going to be a recursive/deep-merge added to Sass core anytime soon, so I would like to suggest you add it to Sassy-maps.
Example use: I keep all my colour-refs inside a nested map structure. I would like to merge project-specific colour-values into defaults, overriding anything that is already present.