more robustly handle import paths
This commit is contained in:
parent
f88c22f360
commit
cc881db254
@ -7,10 +7,13 @@ use crate::error::SassResult;
|
|||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::{Stmt, StyleSheet};
|
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 rules = Vec::new();
|
||||||
let mut scope = Scope::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 `..`");
|
let name = path_buf.file_name().expect("todo! path ended in `..`");
|
||||||
if path_buf.extension() == Some(OsStr::new(".css")) {
|
if path_buf.extension() == Some(OsStr::new(".css")) {
|
||||||
// || name.starts_with("http://") || name.starts_with("https://") {
|
// || name.starts_with("http://") || name.starts_with("https://") {
|
||||||
|
@ -204,6 +204,7 @@ impl StyleSheet {
|
|||||||
lexer: Lexer::new(&file).peekmore(),
|
lexer: Lexer::new(&file).peekmore(),
|
||||||
nesting: 0,
|
nesting: 0,
|
||||||
map: &map,
|
map: &map,
|
||||||
|
path: Path::new(""),
|
||||||
}
|
}
|
||||||
.parse_toplevel()
|
.parse_toplevel()
|
||||||
.map_err(|e| raw_to_parse_error(&map, e).to_string())?
|
.map_err(|e| raw_to_parse_error(&map, e).to_string())?
|
||||||
@ -237,6 +238,7 @@ impl StyleSheet {
|
|||||||
lexer: Lexer::new(&file).peekmore(),
|
lexer: Lexer::new(&file).peekmore(),
|
||||||
nesting: 0,
|
nesting: 0,
|
||||||
map: &map,
|
map: &map,
|
||||||
|
path: Path::new(""),
|
||||||
}
|
}
|
||||||
.parse_toplevel()
|
.parse_toplevel()
|
||||||
.map_err(|e| raw_to_parse_error(&map, e))?
|
.map_err(|e| raw_to_parse_error(&map, e))?
|
||||||
@ -261,12 +263,13 @@ impl StyleSheet {
|
|||||||
#[cfg(not(feature = "wasm"))]
|
#[cfg(not(feature = "wasm"))]
|
||||||
pub fn from_path<P: AsRef<Path> + Into<String> + Clone>(p: P) -> SassResult<String> {
|
pub fn from_path<P: AsRef<Path> + Into<String> + Clone>(p: P) -> SassResult<String> {
|
||||||
let mut map = CodeMap::new();
|
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(
|
Css::from_stylesheet(StyleSheet(
|
||||||
StyleSheetParser {
|
StyleSheetParser {
|
||||||
lexer: Lexer::new(&file).peekmore(),
|
lexer: Lexer::new(&file).peekmore(),
|
||||||
nesting: 0,
|
nesting: 0,
|
||||||
map: &map,
|
map: &map,
|
||||||
|
path: p.as_ref(),
|
||||||
}
|
}
|
||||||
.parse_toplevel()
|
.parse_toplevel()
|
||||||
.map_err(|e| raw_to_parse_error(&map, e))?
|
.map_err(|e| raw_to_parse_error(&map, e))?
|
||||||
@ -286,6 +289,7 @@ impl StyleSheet {
|
|||||||
lexer: Lexer::new(&file).peekmore(),
|
lexer: Lexer::new(&file).peekmore(),
|
||||||
nesting: 0,
|
nesting: 0,
|
||||||
map: &map,
|
map: &map,
|
||||||
|
path: p.as_ref(),
|
||||||
}
|
}
|
||||||
.parse_toplevel()?)
|
.parse_toplevel()?)
|
||||||
}
|
}
|
||||||
@ -299,6 +303,7 @@ struct StyleSheetParser<'a> {
|
|||||||
lexer: PeekMoreIterator<Lexer<'a>>,
|
lexer: PeekMoreIterator<Lexer<'a>>,
|
||||||
nesting: u32,
|
nesting: u32,
|
||||||
map: &'a CodeMap,
|
map: &'a CodeMap,
|
||||||
|
path: &'a Path,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StyleSheetParser<'a> {
|
impl<'a> StyleSheetParser<'a> {
|
||||||
@ -382,7 +387,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
|
|
||||||
devour_whitespace(&mut self.lexer);
|
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);
|
rules.extend(new_rules);
|
||||||
GLOBAL_SCOPE.with(|s| {
|
GLOBAL_SCOPE.with(|s| {
|
||||||
s.borrow_mut().extend(new_scope);
|
s.borrow_mut().extend(new_scope);
|
||||||
|
@ -19,6 +19,21 @@ macro_rules! tempfile {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
write!(f, "{}", $content).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]
|
#[test]
|
||||||
@ -99,3 +114,24 @@ fn chained_imports() {
|
|||||||
&StyleSheet::new(input.to_string()).expect(input)
|
&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`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user