mirror of
https://github.com/danog/sass-site.git
synced 2024-12-04 02:17:57 +01:00
142 lines
4.6 KiB
Markdown
142 lines
4.6 KiB
Markdown
|
---
|
||
|
title: 'Request for Comments: Nested Map Functions'
|
||
|
author: Natalie Weizenbaum
|
||
|
tags: blog
|
||
|
#date: 2020-9-16 14:40 PST
|
||
|
---
|
||
|
|
||
|
As Sass libraries and design systems get more complex and have more users with
|
||
|
different needs, they tend to develop the need to share and override
|
||
|
configuration and design tokens. This configuration is often hierarchical, and
|
||
|
ends up being represented as maps that contain maps that contain still more
|
||
|
maps. Up until now, Sass's map functions haven't really made it easy to work
|
||
|
with this sort of nested map structure. But that's changing with the latest
|
||
|
language proposal, written by Sass core team member [Miriam Suzanne].
|
||
|
|
||
|
[Miriam Suzanne]: https://www.miriamsuzanne.com/
|
||
|
|
||
|
This proposal expands the existing map functions and adds a few new ones to make
|
||
|
working with nested maps much easier than it was before. It's based on helper
|
||
|
functions that pop up in all sorts of Sass projects around the web,
|
||
|
incorporating best practices back into the language itself.
|
||
|
|
||
|
## The Functions
|
||
|
|
||
|
Here are the new and improved functions this proposal adds:
|
||
|
|
||
|
### `map.get()` and `map.has-key()`
|
||
|
|
||
|
The [`map.get()`] and [`map.has-key()`] functions both now take any number of
|
||
|
keys as arguments. Each key drills deeper into a nested map, allowing you to
|
||
|
easily inspect nested values without needing to chain a bunch of function calls
|
||
|
together.
|
||
|
|
||
|
[`map.get()`]: https://sass-lang.com/documentation/modules/map#get
|
||
|
[`map.has-key()`]: https://sass-lang.com/documentation/modules/map#has-key
|
||
|
|
||
|
For example, let's take the following simplified configuration map:
|
||
|
|
||
|
```scss
|
||
|
$config: (
|
||
|
'colors': (
|
||
|
'primary': red,
|
||
|
'secondary': blue,
|
||
|
),
|
||
|
);
|
||
|
```
|
||
|
|
||
|
For this map, `map.get($config, "colors", "primary")` gets the value of the
|
||
|
`"colors"` key (`("primary": red)`) then the value of the `"primary"` key and
|
||
|
returns `red`.
|
||
|
|
||
|
Similarly, `map.has-key($config, "colors", "primary")` returns `true` while
|
||
|
`map.has-key($config, "colors", "tertiary")` returns `false`.
|
||
|
|
||
|
### `map.merge()`
|
||
|
|
||
|
The [`map.merge()`] function can now be called as `map.merge($map1, $keys...,
|
||
|
$map2)`. This will merge `$map2` with a child of `$map1` at the location given
|
||
|
by the keys, updating the parent maps as it goes.
|
||
|
|
||
|
[`map.merge()`]: https://sass-lang.com/documentation/modules/map#merge
|
||
|
|
||
|
For example, using the configuration map [defined above] `map.merge($config,
|
||
|
"colors", ("primary": green))` will return
|
||
|
|
||
|
[defined above]: #map-get-and-map-has-key
|
||
|
|
||
|
```
|
||
|
(
|
||
|
"colors": (
|
||
|
"primary": green,
|
||
|
"secondary": blue
|
||
|
)
|
||
|
)
|
||
|
```
|
||
|
|
||
|
### `map.set()`
|
||
|
|
||
|
The `map.set($map, $keys..., $value)` function is all-new. Although updating
|
||
|
individual values in maps was always possible with `map.merge()`, we've found
|
||
|
that users get confused by the absence of a dedicated `set()` function. This
|
||
|
function not only fills that role, but makes it possible to set values within
|
||
|
nested maps as well.
|
||
|
|
||
|
You can use `map.set()` for normal single-layer maps by just passing one key.
|
||
|
For example, `map.set(("wide": 200px, "narrow": 70px), "wide", 180px)` will
|
||
|
return `("wide": 180px, "narrow": 70px)`.
|
||
|
|
||
|
But you can also use it for nested maps. For example, `map.set($config,
|
||
|
"colors", "tertiary", yellow)` will return
|
||
|
|
||
|
```
|
||
|
(
|
||
|
"colors": (
|
||
|
"primary": red,
|
||
|
"secondary": blue,
|
||
|
"tertiary": yellow
|
||
|
)
|
||
|
)
|
||
|
```
|
||
|
|
||
|
### `map.deep-remove()`
|
||
|
|
||
|
Because the existing [`map.remove()`] function already takes any number of
|
||
|
arguments, we couldn't just update it to work with nested maps. Instead, we
|
||
|
chose to add a new function just for nested maps, called `map.deep-remove($map,
|
||
|
$keys...)`. This function removes the value at the final key in the list, and
|
||
|
updates all the parent maps accordingly.
|
||
|
|
||
|
[`map.remove()`]: https://sass-lang.com/documentation/modules/map#remove
|
||
|
|
||
|
For example, `map.deep-remove($config, "colors", "secondary")` will return
|
||
|
`("colors": ("primary": red))`.
|
||
|
|
||
|
### `map.deep-merge()`
|
||
|
|
||
|
The final new function may be the most exciting. `map.deep-merge($map1, $map2)`
|
||
|
works just like `map.merge()`, except that any nested maps are _also_ merged,
|
||
|
including maps within those maps and so on. This makes it easy to combine two
|
||
|
configuration maps that have the same structure without having to manually merge
|
||
|
each level by hand.
|
||
|
|
||
|
For example, `map.deep-merge($config, ("colors": ("secondary": teal)))` returns
|
||
|
|
||
|
```
|
||
|
(
|
||
|
"colors": (
|
||
|
"primary": red,
|
||
|
"secondary": teal
|
||
|
)
|
||
|
)
|
||
|
```
|
||
|
|
||
|
## Let us know what you think!
|
||
|
|
||
|
If you're interested in learning more about this proposal, [read it in full] on
|
||
|
GitHub. It's open for comments and revisions for the next month, so if you'd
|
||
|
like to see something change please [file an issue] and we can discuss it!
|
||
|
|
||
|
[read it in full]: https://github.com/sass/sass/tree/main/accepted/nested-map-functions.md
|
||
|
[file an issue]: https://github.com/sass/sass/issues/new
|