more robustly handle import paths

This commit is contained in:
ConnorSkees 2020-04-24 21:38:25 -04:00
parent f88c22f360
commit cc881db254
3 changed files with 48 additions and 4 deletions

View File

@ -7,10 +7,13 @@ use crate::error::SassResult;
use crate::scope::Scope;
use crate::{Stmt, StyleSheet};
pub(crate) fn import<P: AsRef<Path>>(path: P) -> SassResult<(Vec<Spanned<Stmt>>, Scope)> {
pub(crate) fn import(ctx: &Path, path: &Path) -> SassResult<(Vec<Spanned<Stmt>>, Scope)> {
let mut rules = Vec::new();
let mut scope = Scope::new();
let path_buf = path.as_ref().to_path_buf();
if path.is_absolute() {
todo!("absolute import")
}
let path_buf = ctx.parent().unwrap_or(Path::new("")).join(path);
let name = path_buf.file_name().expect("todo! path ended in `..`");
if path_buf.extension() == Some(OsStr::new(".css")) {
// || name.starts_with("http://") || name.starts_with("https://") {

View File

@ -204,6 +204,7 @@ impl StyleSheet {
lexer: Lexer::new(&file).peekmore(),
nesting: 0,
map: &map,
path: Path::new(""),
}
.parse_toplevel()
.map_err(|e| raw_to_parse_error(&map, e).to_string())?
@ -237,6 +238,7 @@ impl StyleSheet {
lexer: Lexer::new(&file).peekmore(),
nesting: 0,
map: &map,
path: Path::new(""),
}
.parse_toplevel()
.map_err(|e| raw_to_parse_error(&map, e))?
@ -261,12 +263,13 @@ impl StyleSheet {
#[cfg(not(feature = "wasm"))]
pub fn from_path<P: AsRef<Path> + Into<String> + Clone>(p: P) -> SassResult<String> {
let mut map = CodeMap::new();
let file = map.add_file(p.clone().into(), String::from_utf8(fs::read(p)?)?);
let file = map.add_file(p.clone().into(), String::from_utf8(fs::read(p.clone())?)?);
Css::from_stylesheet(StyleSheet(
StyleSheetParser {
lexer: Lexer::new(&file).peekmore(),
nesting: 0,
map: &map,
path: p.as_ref(),
}
.parse_toplevel()
.map_err(|e| raw_to_parse_error(&map, e))?
@ -286,6 +289,7 @@ impl StyleSheet {
lexer: Lexer::new(&file).peekmore(),
nesting: 0,
map: &map,
path: p.as_ref(),
}
.parse_toplevel()?)
}
@ -299,6 +303,7 @@ struct StyleSheetParser<'a> {
lexer: PeekMoreIterator<Lexer<'a>>,
nesting: u32,
map: &'a CodeMap,
path: &'a Path,
}
impl<'a> StyleSheetParser<'a> {
@ -382,7 +387,7 @@ impl<'a> StyleSheetParser<'a> {
devour_whitespace(&mut self.lexer);
let (new_rules, new_scope) = import(file_name)?;
let (new_rules, new_scope) = import(self.path, file_name.as_ref())?;
rules.extend(new_rules);
GLOBAL_SCOPE.with(|s| {
s.borrow_mut().extend(new_scope);

View File

@ -19,6 +19,21 @@ macro_rules! tempfile {
.unwrap();
write!(f, "{}", $content).unwrap();
};
($name:literal, $content:literal, dir=$dir:literal) => {
let _d = Builder::new()
.rand_bytes(0)
.prefix("")
.suffix($dir)
.tempdir_in("")
.unwrap();
let mut f = dbg!(Builder::new()
.rand_bytes(0)
.prefix("")
.suffix($name)
.tempfile_in($dir)
.unwrap());
write!(f, "{}", $content).unwrap();
};
}
#[test]
@ -99,3 +114,24 @@ fn chained_imports() {
&StyleSheet::new(input.to_string()).expect(input)
);
}
#[test]
fn chained_imports_in_directory() {
let input = "@import \"chained_imports_in_directory__a\";\na {\n color: $a;\n}";
tempfile!(
"chained_imports_in_directory__a.scss",
"@import \"chained_imports_in_directory__b\";"
);
tempfile!(
"index.scss",
"@import \"../chained_imports_in_directory__c\";",
dir = "chained_imports_in_directory__b"
);
tempfile!("chained_imports_in_directory__c.scss", "$a: red;");
assert_eq!(
"a {\n color: red;\n}\n",
&StyleSheet::new(input.to_string()).expect(input)
);
}
// todo: test for calling paths, e.g. `grass b\index.scss`