implement builtin fn map.deep-remove
This commit is contained in:
parent
f811b243c7
commit
eecff6d58a
1
.gitignore
vendored
1
.gitignore
vendored
@ -36,3 +36,4 @@ dart-sass
|
|||||||
sass-fairy
|
sass-fairy
|
||||||
duomo
|
duomo
|
||||||
ibm-cloud-cognitive
|
ibm-cloud-cognitive
|
||||||
|
pico
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
# TBD
|
# TBD
|
||||||
|
|
||||||
- implement builtin map-module function `map.deep-merge(..)`
|
- implement builtin map-module functions `map.deep-merge(..)` and `map.deep-remove(..)`
|
||||||
|
|
||||||
# 0.12.3
|
# 0.12.3
|
||||||
|
|
||||||
|
@ -84,10 +84,10 @@ The spec runner does not work on Windows.
|
|||||||
Using a modified version of the spec runner that ignores warnings and error spans (but does include error messages), `grass` achieves the following results:
|
Using a modified version of the spec runner that ignores warnings and error spans (but does include error messages), `grass` achieves the following results:
|
||||||
|
|
||||||
```
|
```
|
||||||
2022-01-31
|
2022-05-11
|
||||||
PASSING: 6248
|
PASSING: 6277
|
||||||
FAILING: 624
|
FAILING: 596
|
||||||
TOTAL: 6892
|
TOTAL: 6905
|
||||||
```
|
```
|
||||||
|
|
||||||
The majority of the failing tests are purely aesthetic, relating to whitespace
|
The majority of the failing tests are purely aesthetic, relating to whitespace
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::iter::Peekable;
|
||||||
|
|
||||||
use crate::builtin::builtin_imports::*;
|
use crate::builtin::builtin_imports::*;
|
||||||
|
|
||||||
use crate::builtin::{
|
use crate::builtin::{
|
||||||
@ -16,9 +18,7 @@ fn deep_merge_impl(map1: SassMap, map2: SassMap) -> SassMap {
|
|||||||
let mut result = map1;
|
let mut result = map1;
|
||||||
|
|
||||||
for (key, value) in map2 {
|
for (key, value) in map2 {
|
||||||
let result_map = result.get_ref(&key.node).and_then(Value::try_map);
|
match result.get_ref(&key.node).and_then(Value::try_map) {
|
||||||
|
|
||||||
match result_map {
|
|
||||||
Some(result_map) => match value.try_map() {
|
Some(result_map) => match value.try_map() {
|
||||||
Some(value_map) => {
|
Some(value_map) => {
|
||||||
let merged = deep_merge_impl(result_map, value_map);
|
let merged = deep_merge_impl(result_map, value_map);
|
||||||
@ -53,6 +53,92 @@ fn deep_merge(mut args: ArgumentResult, _: &mut Visitor) -> SassResult<Value> {
|
|||||||
Ok(Value::Map(deep_merge_impl(map1, map2)))
|
Ok(Value::Map(deep_merge_impl(map1, map2)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deep_remove(mut args: ArgumentResult, _: &mut Visitor) -> SassResult<Value> {
|
||||||
|
let span = args.span();
|
||||||
|
|
||||||
|
let map = args.get_err(0, "map")?.assert_map_with_name("map", span)?;
|
||||||
|
|
||||||
|
let key = args.get_err(1, "key")?;
|
||||||
|
let keys = args.get_variadic()?.into_iter().map(|arg| arg.node);
|
||||||
|
let mut keys = std::iter::once(key).chain(keys).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let last = keys.pop();
|
||||||
|
|
||||||
|
let map = modify_map(
|
||||||
|
map,
|
||||||
|
keys.into_iter(),
|
||||||
|
|value| {
|
||||||
|
let last = match last.as_ref() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return value,
|
||||||
|
};
|
||||||
|
|
||||||
|
match value.try_map() {
|
||||||
|
Some(mut nested_map) if nested_map.contains(last) => {
|
||||||
|
nested_map.remove(last);
|
||||||
|
Value::Map(nested_map)
|
||||||
|
}
|
||||||
|
Some(..) | None => value,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
span,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modify_map(
|
||||||
|
map: SassMap,
|
||||||
|
keys: impl Iterator<Item = Value>,
|
||||||
|
modify: impl Fn(Value) -> Value,
|
||||||
|
// default=true
|
||||||
|
add_nesting: bool,
|
||||||
|
span: Span,
|
||||||
|
) -> Value {
|
||||||
|
let mut keys = keys.peekable();
|
||||||
|
fn modify_nested_map(
|
||||||
|
mut mutable_map: SassMap,
|
||||||
|
mut keys: Peekable<impl Iterator<Item = Value>>,
|
||||||
|
add_nesting: bool,
|
||||||
|
span: Span,
|
||||||
|
modify: impl Fn(Value) -> Value,
|
||||||
|
) -> SassMap {
|
||||||
|
let key = keys.next().unwrap();
|
||||||
|
|
||||||
|
if keys.peek().is_none() {
|
||||||
|
let value = modify(mutable_map.get_ref(&key).cloned().unwrap_or(Value::Null));
|
||||||
|
mutable_map.insert(key.span(span), value);
|
||||||
|
return mutable_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nested_map = mutable_map.get_ref(&key).and_then(|v| v.try_map());
|
||||||
|
|
||||||
|
if nested_map.is_none() && !add_nesting {
|
||||||
|
return mutable_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutable_map.insert(
|
||||||
|
key.span(span),
|
||||||
|
Value::Map(modify_nested_map(
|
||||||
|
nested_map.unwrap_or_default(),
|
||||||
|
keys,
|
||||||
|
add_nesting,
|
||||||
|
span,
|
||||||
|
modify,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
mutable_map
|
||||||
|
}
|
||||||
|
|
||||||
|
if keys.peek().is_some() {
|
||||||
|
Value::Map(modify_nested_map(map, keys, add_nesting, span, modify))
|
||||||
|
} else {
|
||||||
|
modify(Value::Map(map))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn declare(f: &mut Module) {
|
pub(crate) fn declare(f: &mut Module) {
|
||||||
f.insert_builtin("get", map_get);
|
f.insert_builtin("get", map_get);
|
||||||
f.insert_builtin("has-key", map_has_key);
|
f.insert_builtin("has-key", map_has_key);
|
||||||
@ -62,4 +148,5 @@ pub(crate) fn declare(f: &mut Module) {
|
|||||||
f.insert_builtin("values", map_values);
|
f.insert_builtin("values", map_values);
|
||||||
f.insert_builtin("set", map_set);
|
f.insert_builtin("set", map_set);
|
||||||
f.insert_builtin("deep-merge", deep_merge);
|
f.insert_builtin("deep-merge", deep_merge);
|
||||||
|
f.insert_builtin("deep-remove", deep_remove);
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,10 @@ impl SassMap {
|
|||||||
self.0.into_iter().map(|(.., v)| v).collect()
|
self.0.into_iter().map(|(.., v)| v).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, key: &Value) -> bool {
|
||||||
|
self.0.iter().any(|(k, ..)| &k.node == key)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_list(self) -> Vec<Value> {
|
pub fn as_list(self) -> Vec<Value> {
|
||||||
self.0
|
self.0
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -133,3 +133,30 @@ test!(
|
|||||||
}"#,
|
}"#,
|
||||||
"a {\n color: (c: (d: e));\n}\n"
|
"a {\n color: (c: (d: e));\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
deep_remove_key_dne,
|
||||||
|
r#"@use "sass:map";
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inspect(map.deep-remove((a: b), 1));
|
||||||
|
}"#,
|
||||||
|
"a {\n color: (a: b);\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
deep_remove_nested_remove,
|
||||||
|
r#"@use "sass:map";
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inspect(map.deep-remove((c: (d: e)), c, d));
|
||||||
|
}"#,
|
||||||
|
"a {\n color: (c: ());\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
deep_remove_nested_keys_dne,
|
||||||
|
r#"@use "sass:map";
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inspect(map.deep-remove((c: (d: e)), c, d, e, f, g));
|
||||||
|
}"#,
|
||||||
|
"a {\n color: (c: (d: e));\n}\n"
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user