2021-07-03 23:17:31 -04:00
|
|
|
use std::mem;
|
|
|
|
|
2020-05-18 11:50:40 -04:00
|
|
|
use super::{Builtin, GlobalFunctionMap};
|
2020-02-02 21:09:29 -05:00
|
|
|
|
2020-06-16 20:00:11 -04:00
|
|
|
use crate::{
|
|
|
|
args::CallArgs,
|
|
|
|
common::{Brackets, ListSeparator},
|
|
|
|
error::SassResult,
|
|
|
|
parse::Parser,
|
|
|
|
value::{SassMap, Value},
|
|
|
|
};
|
2020-03-30 15:43:15 -04:00
|
|
|
|
2020-07-26 00:22:44 -04:00
|
|
|
pub(crate) fn map_get(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
|
2020-04-30 19:36:34 -04:00
|
|
|
args.max_args(2)?;
|
2020-07-10 21:42:10 -04:00
|
|
|
let key = args.get_err(1, "key")?;
|
|
|
|
let map = match args.get_err(0, "map")? {
|
2020-04-30 19:36:34 -04:00
|
|
|
Value::Map(m) => m,
|
|
|
|
Value::List(v, ..) if v.is_empty() => SassMap::new(),
|
2020-07-06 21:35:54 -04:00
|
|
|
Value::ArgList(v) if v.is_empty() => SassMap::new(),
|
2020-04-30 19:36:34 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
2020-07-06 21:26:57 -04:00
|
|
|
format!("$map: {} is not a map.", v.inspect(args.span())?),
|
2020-04-30 19:36:34 -04:00
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
};
|
2020-07-07 00:01:34 -04:00
|
|
|
Ok(map.get(&key)?.unwrap_or(Value::Null))
|
2020-04-30 19:36:34 -04:00
|
|
|
}
|
2020-04-30 15:18:54 -04:00
|
|
|
|
2020-07-26 00:22:44 -04:00
|
|
|
pub(crate) fn map_has_key(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
|
2020-04-30 19:36:34 -04:00
|
|
|
args.max_args(2)?;
|
2020-07-10 21:42:10 -04:00
|
|
|
let key = args.get_err(1, "key")?;
|
|
|
|
let map = match args.get_err(0, "map")? {
|
2020-04-30 19:36:34 -04:00
|
|
|
Value::Map(m) => m,
|
|
|
|
Value::List(v, ..) if v.is_empty() => SassMap::new(),
|
2020-07-06 21:35:54 -04:00
|
|
|
Value::ArgList(v) if v.is_empty() => SassMap::new(),
|
2020-04-30 19:36:34 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
2020-07-06 21:26:57 -04:00
|
|
|
format!("$map: {} is not a map.", v.inspect(args.span())?),
|
2020-04-30 19:36:34 -04:00
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
};
|
2020-07-07 00:01:34 -04:00
|
|
|
Ok(Value::bool(map.get(&key)?.is_some()))
|
2020-04-30 19:36:34 -04:00
|
|
|
}
|
2020-04-30 15:18:54 -04:00
|
|
|
|
2020-07-26 00:22:44 -04:00
|
|
|
pub(crate) fn map_keys(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
|
2020-04-30 19:36:34 -04:00
|
|
|
args.max_args(1)?;
|
2020-07-10 21:42:10 -04:00
|
|
|
let map = match args.get_err(0, "map")? {
|
2020-04-30 19:36:34 -04:00
|
|
|
Value::Map(m) => m,
|
|
|
|
Value::List(v, ..) if v.is_empty() => SassMap::new(),
|
2020-07-06 21:35:54 -04:00
|
|
|
Value::ArgList(v) if v.is_empty() => SassMap::new(),
|
2020-04-30 19:36:34 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
2020-07-06 21:26:57 -04:00
|
|
|
format!("$map: {} is not a map.", v.inspect(args.span())?),
|
2020-04-30 19:36:34 -04:00
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Ok(Value::List(
|
|
|
|
map.keys(),
|
|
|
|
ListSeparator::Comma,
|
|
|
|
Brackets::None,
|
|
|
|
))
|
|
|
|
}
|
2020-04-30 15:18:54 -04:00
|
|
|
|
2020-07-26 00:22:44 -04:00
|
|
|
pub(crate) fn map_values(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
|
2020-04-30 19:36:34 -04:00
|
|
|
args.max_args(1)?;
|
2020-07-10 21:42:10 -04:00
|
|
|
let map = match args.get_err(0, "map")? {
|
2020-04-30 19:36:34 -04:00
|
|
|
Value::Map(m) => m,
|
|
|
|
Value::List(v, ..) if v.is_empty() => SassMap::new(),
|
2020-07-06 21:35:54 -04:00
|
|
|
Value::ArgList(v) if v.is_empty() => SassMap::new(),
|
2020-04-30 19:36:34 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
2020-07-06 21:26:57 -04:00
|
|
|
format!("$map: {} is not a map.", v.inspect(args.span())?),
|
2020-04-30 19:36:34 -04:00
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Ok(Value::List(
|
|
|
|
map.values(),
|
|
|
|
ListSeparator::Comma,
|
|
|
|
Brackets::None,
|
|
|
|
))
|
|
|
|
}
|
2020-04-30 15:18:54 -04:00
|
|
|
|
2020-07-26 00:22:44 -04:00
|
|
|
pub(crate) fn map_merge(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
|
2021-07-03 23:17:31 -04:00
|
|
|
if args.len() == 1 {
|
|
|
|
return Err(("Expected $args to contain a key.", args.span()).into());
|
|
|
|
}
|
|
|
|
|
|
|
|
let last_position = args.len().saturating_sub(1);
|
|
|
|
|
2020-07-10 21:42:10 -04:00
|
|
|
let mut map1 = match args.get_err(0, "map1")? {
|
2020-04-30 19:36:34 -04:00
|
|
|
Value::Map(m) => m,
|
|
|
|
Value::List(v, ..) if v.is_empty() => SassMap::new(),
|
2020-07-06 21:35:54 -04:00
|
|
|
Value::ArgList(v) if v.is_empty() => SassMap::new(),
|
2020-04-30 19:36:34 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
2020-07-06 21:26:57 -04:00
|
|
|
format!("$map1: {} is not a map.", v.inspect(args.span())?),
|
2020-04-30 19:36:34 -04:00
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
};
|
2021-07-03 23:17:31 -04:00
|
|
|
|
|
|
|
let mut map2 = match args.get_err(last_position, "map2")? {
|
2020-04-30 19:36:34 -04:00
|
|
|
Value::Map(m) => m,
|
|
|
|
Value::List(v, ..) if v.is_empty() => SassMap::new(),
|
2020-07-06 21:35:54 -04:00
|
|
|
Value::ArgList(v) if v.is_empty() => SassMap::new(),
|
2020-04-30 19:36:34 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
2020-07-06 21:26:57 -04:00
|
|
|
format!("$map2: {} is not a map.", v.inspect(args.span())?),
|
2020-04-30 19:36:34 -04:00
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
};
|
2021-07-03 23:17:31 -04:00
|
|
|
|
|
|
|
let mut keys = args.get_variadic()?;
|
|
|
|
|
|
|
|
if keys.is_empty() {
|
|
|
|
map1.merge(map2);
|
|
|
|
} else {
|
|
|
|
while let Some(key) = keys.pop() {
|
|
|
|
let mut new_map = SassMap::new();
|
|
|
|
new_map.insert(key.node, Value::Map(mem::take(&mut map2)));
|
|
|
|
map2 = new_map;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (key, value) in map2 {
|
|
|
|
// if they are two maps sharing a key, merge the keys
|
|
|
|
if let (Some(Value::Map(map1)), Value::Map(map2)) = (map1.get_mut(&key), &value) {
|
|
|
|
map1.merge(map2.clone());
|
|
|
|
} else {
|
|
|
|
map1.insert(key, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 19:36:34 -04:00
|
|
|
Ok(Value::Map(map1))
|
|
|
|
}
|
2020-04-30 15:18:54 -04:00
|
|
|
|
2020-07-26 00:22:44 -04:00
|
|
|
pub(crate) fn map_remove(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
|
2020-07-10 21:42:10 -04:00
|
|
|
let mut map = match args.get_err(0, "map")? {
|
2020-04-30 19:36:34 -04:00
|
|
|
Value::Map(m) => m,
|
|
|
|
Value::List(v, ..) if v.is_empty() => SassMap::new(),
|
2020-07-06 21:35:54 -04:00
|
|
|
Value::ArgList(v) if v.is_empty() => SassMap::new(),
|
2020-04-30 19:36:34 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
2020-07-06 21:26:57 -04:00
|
|
|
format!("$map: {} is not a map.", v.inspect(args.span())?),
|
2020-04-30 19:36:34 -04:00
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
2020-04-30 15:18:54 -04:00
|
|
|
}
|
2020-04-30 19:36:34 -04:00
|
|
|
};
|
2020-07-10 21:42:10 -04:00
|
|
|
let keys = args.get_variadic()?;
|
2020-04-30 19:36:34 -04:00
|
|
|
for key in keys {
|
|
|
|
map.remove(&key);
|
2020-04-30 15:18:54 -04:00
|
|
|
}
|
2020-04-30 19:36:34 -04:00
|
|
|
Ok(Value::Map(map))
|
|
|
|
}
|
2020-04-30 15:18:54 -04:00
|
|
|
|
2020-05-16 18:01:06 -04:00
|
|
|
pub(crate) fn declare(f: &mut GlobalFunctionMap) {
|
2020-04-30 15:18:54 -04:00
|
|
|
f.insert("map-get", Builtin::new(map_get));
|
|
|
|
f.insert("map-has-key", Builtin::new(map_has_key));
|
|
|
|
f.insert("map-keys", Builtin::new(map_keys));
|
|
|
|
f.insert("map-values", Builtin::new(map_values));
|
|
|
|
f.insert("map-merge", Builtin::new(map_merge));
|
|
|
|
f.insert("map-remove", Builtin::new(map_remove));
|
2020-03-30 15:43:15 -04:00
|
|
|
}
|