respect $with argument to load-css

This commit is contained in:
Connor Skees 2020-08-06 21:58:53 -04:00
parent 0254517095
commit cacf605af8
2 changed files with 100 additions and 64 deletions

View File

@ -1,3 +1,5 @@
use codemap::Spanned;
use crate::{
args::CallArgs,
builtin::{
@ -5,7 +7,7 @@ use crate::{
call, content_exists, feature_exists, function_exists, get_function,
global_variable_exists, inspect, keywords, mixin_exists, type_of, variable_exists,
},
modules::Module,
modules::{Module, ModuleConfig},
},
error::SassResult,
parse::{Parser, Stmt},
@ -15,13 +17,15 @@ use crate::{
fn load_css(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Vec<Stmt>> {
args.max_args(2)?;
let span = args.span();
// todo: https://github.com/sass/dart-sass/issues/1054
let url = match args.get_err(0, "module")? {
Value::String(s, ..) => s,
v => {
return Err((
format!("$module: {} is not a string.", v.inspect(args.span())?),
args.span(),
format!("$module: {} is not a string.", v.inspect(span)?),
span,
)
.into())
}
@ -30,19 +34,39 @@ fn load_css(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Vec<Stmt>
let with = match args.default_arg(1, "with", Value::Null)? {
Value::Map(map) => Some(map),
Value::Null => None,
v => {
return Err((
format!("$with: {} is not a map.", v.inspect(args.span())?),
args.span(),
)
.into())
}
v => return Err((format!("$with: {} is not a map.", v.inspect(span)?), span).into()),
};
if let Some(..) = with {
todo!("`$with` to `load-css` not yet implemented")
// todo: tests for `with`
if let Some(with) = with {
let mut config = ModuleConfig::default();
for (key, value) in with {
let key = match key {
Value::String(s, ..) => s,
v => {
return Err((
format!("$with key: {} is not a string.", v.inspect(span)?),
span,
)
.into())
}
};
config.insert(
Spanned {
node: key.into(),
span,
},
value.span(span),
)?;
}
let (_, stmts) = parser.load_module(&url, &mut config)?;
Ok(stmts)
} else {
parser.parse_single_import(&url, args.span())
parser.parse_single_import(&url, span)
}
}

View File

@ -208,6 +208,66 @@ impl<'a> Parser<'a> {
Ok(config)
}
pub fn load_module(
&mut self,
name: &str,
config: &mut ModuleConfig,
) -> SassResult<(Module, Vec<Stmt>)> {
Ok(match name {
"sass:color" => (declare_module_color(), Vec::new()),
"sass:list" => (declare_module_list(), Vec::new()),
"sass:map" => (declare_module_map(), Vec::new()),
"sass:math" => (declare_module_math(), Vec::new()),
"sass:meta" => (declare_module_meta(), Vec::new()),
"sass:selector" => (declare_module_selector(), Vec::new()),
"sass:string" => (declare_module_string(), Vec::new()),
_ => {
if let Some(import) = self.find_import(name.as_ref()) {
let mut global_scope = Scope::new();
let file = self
.map
.add_file(name.to_owned(), String::from_utf8(fs::read(&import)?)?);
let stmts = Parser {
toks: &mut Lexer::new(&file)
.collect::<Vec<Token>>()
.into_iter()
.peekmore(),
map: self.map,
path: &import,
scopes: self.scopes,
global_scope: &mut global_scope,
super_selectors: self.super_selectors,
span_before: file.span.subspan(0, 0),
content: self.content,
flags: self.flags,
at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector,
extender: self.extender,
content_scopes: self.content_scopes,
options: self.options,
modules: self.modules,
module_config: config,
}
.parse()?;
if !config.is_empty() {
return Err((
"This variable was not declared with !default in the @used module.",
self.span_before,
)
.into());
}
(Module::new_from_scope(global_scope), stmts)
} else {
return Err(("Can't find stylesheet to import.", self.span_before).into());
}
}
})
}
/// Returns any multiline comments that may have been found
/// while loading modules
#[allow(clippy::eval_order_dependence)]
@ -260,58 +320,10 @@ impl<'a> Parser<'a> {
self.whitespace_or_comment();
self.expect_char(';')?;
let module = match module_name.as_ref() {
"sass:color" => declare_module_color(),
"sass:list" => declare_module_list(),
"sass:map" => declare_module_map(),
"sass:math" => declare_module_math(),
"sass:meta" => declare_module_meta(),
"sass:selector" => declare_module_selector(),
"sass:string" => declare_module_string(),
_ => {
if let Some(import) = self.find_import(module_name.as_ref().as_ref()) {
let mut global_scope = Scope::new();
let (module, mut stmts) =
self.load_module(module_name.as_ref(), &mut config)?;
let file = self.map.add_file(
module_name.clone().into_owned(),
String::from_utf8(fs::read(&import)?)?,
);
comments.append(
&mut Parser {
toks: &mut Lexer::new(&file)
.collect::<Vec<Token>>()
.into_iter()
.peekmore(),
map: self.map,
path: &import,
scopes: self.scopes,
global_scope: &mut global_scope,
super_selectors: self.super_selectors,
span_before: file.span.subspan(0, 0),
content: self.content,
flags: self.flags,
at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector,
extender: self.extender,
content_scopes: self.content_scopes,
options: self.options,
modules: self.modules,
module_config: &mut config,
}
.parse()?,
);
if !config.is_empty() {
return Err(("This variable was not declared with !default in the @used module.", span).into());
}
Module::new_from_scope(global_scope)
} else {
return Err(("Can't find stylesheet to import.", span).into());
}
}
};
comments.append(&mut stmts);
// if the config isn't empty here, that means
// variables were passed to a builtin module