allow !global in mixins and functions

This commit is contained in:
ConnorSkees 2020-04-04 14:53:08 -04:00
parent dee4462cc7
commit ece0f5afde
3 changed files with 54 additions and 22 deletions

View File

@ -91,7 +91,7 @@ pub use crate::error::{SassError, SassResult};
use crate::format::PrettyPrinter;
use crate::imports::import;
use crate::lexer::Lexer;
use crate::scope::{insert_global_var, Scope, GLOBAL_SCOPE};
use crate::scope::{insert_global_fn, insert_global_mixin, insert_global_var, Scope, GLOBAL_SCOPE};
use crate::selector::Selector;
use crate::style::Style;
pub(crate) use crate::token::Token;
@ -284,7 +284,7 @@ impl<'a> StyleSheetParser<'a> {
match kind {
'a'..='z' | 'A'..='Z' | '_' | '-'
| '[' | '#' | ':' | '*' | '%' | '.' | '>' => rules
.extend(self.eat_rules(&Selector::new(), &mut GLOBAL_SCOPE.with(|s| s.borrow().clone()))?),
.extend(self.eat_rules(&Selector::new(), &mut Scope::new())?),
&'\t' | &'\n' | ' ' => {
self.lexer.next();
continue;
@ -303,7 +303,7 @@ impl<'a> StyleSheetParser<'a> {
return Err("expected \":\".".into());
}
let VariableDecl { val, default, .. } =
eat_variable_value(&mut self.lexer, &GLOBAL_SCOPE.with(|s| s.borrow().clone()), &Selector::new())?;
eat_variable_value(&mut self.lexer, &Scope::new(), &Selector::new())?;
GLOBAL_SCOPE.with(|s| {
if !default || s.borrow().get_var(&name).is_err() {
match s.borrow_mut().insert_var(&name, val) {
@ -336,7 +336,7 @@ impl<'a> StyleSheetParser<'a> {
match AtRuleKind::from(at_rule_kind.as_str()) {
AtRuleKind::Include => rules.extend(eat_include(
&mut self.lexer,
&GLOBAL_SCOPE.with(|s| s.borrow().clone()),
&Scope::new(),
&Selector::new(),
)?),
AtRuleKind::Import => {
@ -364,16 +364,12 @@ impl<'a> StyleSheetParser<'a> {
});
}
v => {
match AtRule::from_tokens(&v, Pos::new(), &mut self.lexer, &mut GLOBAL_SCOPE.with(|s| s.borrow().clone()), &Selector::new())? {
match AtRule::from_tokens(&v, Pos::new(), &mut self.lexer, &mut Scope::new(), &Selector::new())? {
AtRule::Mixin(name, mixin) => {
GLOBAL_SCOPE.with(|s| {
s.borrow_mut().insert_mixin(&name, *mixin);
});
insert_global_mixin(&name, *mixin);
}
AtRule::Function(name, func) => {
GLOBAL_SCOPE.with(|s| {
s.borrow_mut().insert_fn(&name, *func);
});
insert_global_fn(&name, *func);
}
AtRule::Charset => continue,
AtRule::Error(pos, message) => self.error(pos, &message),

View File

@ -14,8 +14,12 @@ pub(crate) fn get_global_var(s: &str) -> SassResult<Value> {
})
}
pub fn global_var_exists(v: &str) -> bool {
GLOBAL_SCOPE.with(|scope| scope.borrow().var_exists(v))
pub(crate) fn global_var_exists(v: &str) -> bool {
GLOBAL_SCOPE.with(|scope| scope.borrow().vars().contains_key(v))
}
pub(crate) fn insert_global_var(s: &str, v: Value) -> SassResult<Option<Value>> {
GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_var(s, v))
}
pub(crate) fn get_global_fn(s: &str) -> SassResult<Function> {
@ -25,8 +29,27 @@ pub(crate) fn get_global_fn(s: &str) -> SassResult<Function> {
})
}
pub(crate) fn insert_global_var(s: &str, v: Value) -> SassResult<Option<Value>> {
GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_var(s, v))
pub(crate) fn global_fn_exists(v: &str) -> bool {
GLOBAL_SCOPE.with(|scope| scope.borrow().functions().contains_key(v))
}
pub(crate) fn insert_global_fn(s: &str, v: Function) -> Option<Function> {
GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_fn(s, v))
}
pub(crate) fn get_global_mixin(s: &str) -> SassResult<Mixin> {
GLOBAL_SCOPE.with(|scope| match scope.borrow().mixins().get(s) {
Some(v) => Ok(v.clone()),
None => Err("Undefined mixin.".into()),
})
}
pub(crate) fn global_mixin_exists(v: &str) -> bool {
GLOBAL_SCOPE.with(|scope| scope.borrow().mixins().contains_key(v))
}
pub(crate) fn insert_global_mixin(s: &str, v: Mixin) -> Option<Mixin> {
GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_mixin(s, v))
}
#[derive(Debug, Clone)]
@ -54,6 +77,10 @@ impl Scope {
&self.functions
}
pub const fn mixins(&self) -> &HashMap<String, Mixin> {
&self.mixins
}
pub fn get_var(&self, v: &str) -> SassResult<Value> {
let name = &v.replace('_', "-");
match self.vars.get(name) {
@ -67,13 +94,15 @@ impl Scope {
}
pub fn var_exists(&self, v: &str) -> bool {
self.vars.contains_key(&v.replace('_', "-"))
let name = &v.replace('_', "-");
self.vars.contains_key(name) || global_var_exists(name)
}
pub fn get_mixin(&self, v: &str) -> SassResult<&Mixin> {
match self.mixins.get(&v.replace('_', "-")) {
Some(v) => Ok(v),
None => Err("Undefined mixin.".into()),
pub fn get_mixin(&self, v: &str) -> SassResult<Mixin> {
let name = &v.replace('_', "-");
match self.mixins.get(name) {
Some(v) => Ok(v.clone()),
None => get_global_mixin(name),
}
}
@ -82,7 +111,8 @@ impl Scope {
}
pub fn mixin_exists(&self, v: &str) -> bool {
self.mixins.contains_key(&v.replace('_', "-"))
let name = &v.replace('_', "-");
self.mixins.contains_key(name) || global_mixin_exists(name)
}
pub fn get_fn(&self, v: &str) -> SassResult<Function> {
@ -98,7 +128,8 @@ impl Scope {
}
pub fn fn_exists(&self, v: &str) -> bool {
self.functions.contains_key(&v.replace('_', "-"))
let name = &v.replace('_', "-");
self.functions.contains_key(name) || global_fn_exists(name)
}
pub fn extend(&mut self, other: Scope) {

View File

@ -18,3 +18,8 @@ test!(
"$foo: 42;\n\n.foo {\n content: $foo;\n $foo: 1337 !global;\n content: $foo;\n}\n\n.bar {\n content: $foo;\n}\n",
".foo {\n content: 42;\n content: 1337;\n}\n\n.bar {\n content: 1337;\n}\n"
);
test!(
global_in_mixin,
"$y: a;\n@mixin foo {\n $y: b !global;\n}\na {\n @include foo;\n color: $y;\n}\n",
"a {\n color: b;\n}\n"
);