From 28a0a33d85c0278116203b58d3cb0a811c52d89f Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Sun, 16 Aug 2020 19:47:18 -0400 Subject: [PATCH] respect `$module` argument passed to `function-exists` --- src/builtin/functions/meta.rs | 42 ++++++++++++++++++++++++++--------- src/builtin/modules/mod.rs | 4 ++++ src/scope.rs | 2 +- tests/meta-module.rs | 10 +++++++++ 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/builtin/functions/meta.rs b/src/builtin/functions/meta.rs index 1bdc1b9..b3c569c 100644 --- a/src/builtin/functions/meta.rs +++ b/src/builtin/functions/meta.rs @@ -173,16 +173,38 @@ pub(crate) fn mixin_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassR pub(crate) fn function_exists(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult { args.max_args(2)?; - match args.get_err(0, "name")? { - Value::String(s, _) => Ok(Value::bool( - parser.scopes.fn_exists(s.into(), parser.global_scope), - )), - v => Err(( - format!("$name: {} is not a string.", v.inspect(args.span())?), - args.span(), - ) - .into()), - } + + let name: Identifier = match args.get_err(0, "name")? { + Value::String(s, _) => s.into(), + v => { + return Err(( + format!("$name: {} is not a string.", v.inspect(args.span())?), + args.span(), + ) + .into()) + } + }; + + let module = match args.default_arg(1, "module", Value::Null)? { + Value::String(s, _) => Some(s), + Value::Null => None, + v => { + return Err(( + format!("$module: {} is not a string.", v.inspect(args.span())?), + args.span(), + ) + .into()) + } + }; + + Ok(Value::bool(if let Some(module_name) = module { + parser + .modules + .get(module_name.into(), args.span())? + .fn_exists(name) + } else { + parser.scopes.fn_exists(name, parser.global_scope) + })) } pub(crate) fn get_function(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult { diff --git a/src/builtin/modules/mod.rs b/src/builtin/modules/mod.rs index f9da0c6..62bc9c1 100644 --- a/src/builtin/modules/mod.rs +++ b/src/builtin/modules/mod.rs @@ -191,6 +191,10 @@ impl Module { !name.as_str().starts_with('-') && self.scope.mixin_exists(name) } + pub fn fn_exists(&self, name: Identifier) -> bool { + !name.as_str().starts_with('-') && self.scope.fn_exists(name) + } + pub fn insert_builtin( &mut self, name: &'static str, diff --git a/src/scope.rs b/src/scope.rs index dc968e2..435937c 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -67,7 +67,7 @@ impl Scope { self.functions.insert(s, v) } - fn fn_exists(&self, name: Identifier) -> bool { + pub fn fn_exists(&self, name: Identifier) -> bool { if self.functions.is_empty() { return false; } diff --git a/tests/meta-module.rs b/tests/meta-module.rs index 5981e7e..bcba8d0 100644 --- a/tests/meta-module.rs +++ b/tests/meta-module.rs @@ -18,6 +18,16 @@ test!( "@use 'sass:math';\na {\n color: global-variable-exists(pi, $module: math);\n}\n", "a {\n color: true;\n}\n" ); +test!( + fn_exists_builtin, + "@use 'sass:math';\na {\n color: function-exists(acos, $module: math);\n}\n", + "a {\n color: true;\n}\n" +); +error!( + fn_exists_module_dne, + "a {\n color: function-exists(c, d);\n}\n", + "Error: There is no module with the namespace \"d\"." +); #[test] fn mixin_exists_module() {