From be4d02490c2740978227220b3b3300f07ba01b39 Mon Sep 17 00:00:00 2001 From: Joe Ling - uni laptop Date: Thu, 16 Jul 2020 09:00:39 +0100 Subject: [PATCH] added comma separated imports --- src/parse/import.rs | 108 ++++++++++++++++++++++++++++---------------- tests/imports.rs | 22 +++++++++ 2 files changed, 91 insertions(+), 39 deletions(-) diff --git a/src/parse/import.rs b/src/parse/import.rs index abef143..573a026 100644 --- a/src/parse/import.rs +++ b/src/parse/import.rs @@ -1,9 +1,15 @@ use std::{ffi::OsStr, fs, path::Path, path::PathBuf}; -use codemap::Spanned; +use codemap::{Span, Spanned}; use peekmore::PeekMore; -use crate::{common::QuoteKind, error::SassResult, lexer::Lexer, value::Value, Token}; +use crate::{ + common::{ListSeparator::Comma, QuoteKind}, + error::SassResult, + lexer::Lexer, + value::Value, + Token, +}; use super::{Parser, Stmt}; @@ -58,41 +64,7 @@ fn find_import(file_path: &PathBuf, name: &OsStr, load_paths: &[&Path]) -> Optio } impl<'a> Parser<'a> { - pub(super) fn import(&mut self) -> SassResult> { - self.whitespace(); - - match self.toks.peek() { - Some(Token { kind: '\'', .. }) - | Some(Token { kind: '"', .. }) - | Some(Token { kind: 'u', .. }) => {} - Some(Token { pos, .. }) => return Err(("Expected string.", *pos).into()), - None => return Err(("expected more input.", self.span_before).into()), - }; - - let Spanned { - node: file_name_as_value, - span, - } = self.parse_value(true)?; - let file_name = match file_name_as_value { - Value::String(s, QuoteKind::Quoted) => { - if s.ends_with(".css") || s.starts_with("http://") || s.starts_with("https://") { - return Ok(vec![Stmt::Import(format!("\"{}\"", s))]); - } else { - s - } - } - Value::String(s, QuoteKind::None) => { - if s.starts_with("url(") { - return Ok(vec![Stmt::Import(s)]); - } else { - s - } - } - _ => return Err(("Expected string.", span).into()), - }; - - self.whitespace(); - + pub fn _parse_single_import(&mut self, file_name: &str, span: Span) -> SassResult> { let path: &Path = file_name.as_ref(); let path_buf = if path.is_absolute() { @@ -104,7 +76,6 @@ impl<'a> Parser<'a> { .unwrap_or_else(|| Path::new("")) .join(path) }; - let name = path_buf.file_name().unwrap_or_else(|| OsStr::new("..")); if let Some(name) = find_import(&path_buf, name, &self.options.load_paths) { @@ -112,7 +83,6 @@ impl<'a> Parser<'a> { name.to_string_lossy().into(), String::from_utf8(fs::read(&name)?)?, ); - return Parser { toks: &mut Lexer::new(&file) .collect::>() @@ -134,7 +104,67 @@ impl<'a> Parser<'a> { } .parse(); } + self.whitespace(); Err(("Can't find stylesheet to import.", span).into()) } + pub(super) fn import(&mut self) -> SassResult> { + self.whitespace(); + match self.toks.peek() { + Some(Token { kind: '\'', .. }) + | Some(Token { kind: '"', .. }) + | Some(Token { kind: 'u', .. }) => {} + Some(Token { pos, .. }) => return Err(("Expected string.", *pos).into()), + None => return Err(("expected more input.", self.span_before).into()), + }; + let Spanned { + node: file_name_as_value, + span, + } = self.parse_value(true)?; + + match file_name_as_value { + Value::String(s, QuoteKind::Quoted) => { + if s.ends_with(".css") || s.starts_with("http://") || s.starts_with("https://") { + Ok(vec![Stmt::Import(format!("\"{}\"", s))]) + } else { + self._parse_single_import(&s, span) + } + } + Value::String(s, QuoteKind::None) => { + if s.starts_with("url(") { + Ok(vec![Stmt::Import(s)]) + } else { + self._parse_single_import(&s, span) + } + } + Value::List(v, Comma, _) => { + let mut list_of_imports: Vec = Vec::new(); + for file_name_element in v { + match file_name_element { + Value::String(s, QuoteKind::Quoted) => { + if s.ends_with(".css") + || s.starts_with("http://") + || s.starts_with("https://") + { + list_of_imports.push(Stmt::Import(format!("\"{}\"", s))); + } else { + list_of_imports.append(&mut self._parse_single_import(&s, span)?); + } + } + Value::String(s, QuoteKind::None) => { + if s.starts_with("url(") { + list_of_imports.push(Stmt::Import(s)); + } else { + list_of_imports.append(&mut self._parse_single_import(&s, span)?); + } + } + _ => return Err(("Expected string.", span).into()), + } + } + + Ok(list_of_imports) + } + _ => Err(("Expected string.", span).into()), + } + } } diff --git a/tests/imports.rs b/tests/imports.rs index 8c16a1f..01513e4 100644 --- a/tests/imports.rs +++ b/tests/imports.rs @@ -82,6 +82,28 @@ fn single_quotes_import() { ); } +#[test] +fn comma_seperated_import() { + let input = "@import 'firsta', 'seconda';\na {\n color: $a;\n}"; + tempfile!("firsta", "$a: red;"); + tempfile!("seconda", "p { color: blue; }"); + assert_eq!( + "p {\n color: blue;\n}\n\na {\n color: red;\n}\n", + &grass::from_string(input.to_string(), &grass::Options::default()).expect(input) + ); +} + +#[test] +fn comma_seperated_import_order() { + let input = "@import 'firstb', 'secondb', url(third);"; + tempfile!("firstb", "p { color: red; }"); + tempfile!("secondb", "p { color: blue; }"); + assert_eq!( + "p {\n color: red;\n}\n\np {\n color: blue;\n}\n@import url(third);\n", + &grass::from_string(input.to_string(), &grass::Options::default()).expect(input) + ); +} + #[test] fn finds_name_scss() { let input = "@import \"finds_name_scss\";\na {\n color: $a;\n}";