diff --git a/.gitignore b/.gitignore index 1500b0d1..60cdb15b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ *.dummy *-test Makefile +target/ +doc/ +.*.swp diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..56d1eced --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +env: + global: + - LD_LIBRARY_PATH: /usr/local/lib +install: + - curl https://static.rust-lang.org/rustup.sh | sudo sh +script: + - rustc --version + - cargo --version + - cargo build +notifications: + email: + - damien.schoof+github@gmail.com diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..d9916e7f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "cssparser" +version = "0.0.0" + +authors = ["Your Name "] +tags = [] + +[[lib]] +name = "cssparser" + +[[bin]] +name = "rust-less" + +[dependencies.encoding] +git = "https://github.com/lifthrasiir/rust-encoding.git" diff --git a/ast.rs b/ast.rs deleted file mode 100644 index 73eaabf7..00000000 --- a/ast.rs +++ /dev/null @@ -1,177 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use std::fmt; -use std::slice; -use std::vec; - - -#[deriving(PartialEq)] -pub struct NumericValue { - pub representation: String, - pub value: f64, - pub int_value: Option, -} - - -#[deriving(PartialEq)] -pub struct SourceLocation { - pub line: uint, // First line is 1 - pub column: uint, // First character of a line is at column 1 -} - - -pub type Node = (ComponentValue, SourceLocation); // TODO this is not a good name - - -#[deriving(PartialEq)] -pub enum ComponentValue { - // Preserved tokens. - Ident(String), - AtKeyword(String), - Hash(String), - IDHash(String), // Hash that is a valid ID selector. - String(String), - URL(String), - Delim(char), - Number(NumericValue), - Percentage(NumericValue), - Dimension(NumericValue, String), - UnicodeRange(u32, u32), // (start, end) of range - WhiteSpace, - Colon, // : - Semicolon, // ; - Comma, // , - IncludeMatch, // ~= - DashMatch, // |= - PrefixMatch, // ^= - SuffixMatch, // $= - SubstringMatch, // *= - Column, // || - CDO, // - - // Function - Function(String, Vec), // name, arguments - - // Simple block - ParenthesisBlock(Vec), // (…) - SquareBracketBlock(Vec), // […] - CurlyBracketBlock(Vec), // {…} - - // These are always invalid - BadURL, - BadString, - CloseParenthesis, // ) - CloseSquareBracket, // ] - CloseCurlyBracket, // } -} - - -#[deriving(PartialEq)] -pub struct Declaration { - pub location: SourceLocation, - pub name: String, - pub value: Vec, - pub important: bool, -} - -#[deriving(PartialEq)] -pub struct QualifiedRule { - pub location: SourceLocation, - pub prelude: Vec, - pub block: Vec, -} - -#[deriving(PartialEq)] -pub struct AtRule { - pub location: SourceLocation, - pub name: String, - pub prelude: Vec, - pub block: Option>, -} - -#[deriving(PartialEq)] -pub enum DeclarationListItem { - Declaration(Declaration), - // A better idea for a name that means "at-rule" but is not "AtRule"? - DeclAtRule(AtRule), -} - -#[deriving(PartialEq)] -pub enum Rule { - QualifiedRule(QualifiedRule), - AtRule(AtRule), -} - -#[deriving(PartialEq)] -pub struct SyntaxError { - pub location: SourceLocation, - pub reason: ErrorReason, -} - -#[deriving(PartialEq)] -pub enum ErrorReason { - ErrEmptyInput, // Parsing a single "thing", found only whitespace. - ErrExtraInput, // Found more non-whitespace after parsing a single "thing". - ErrMissingQualifiedRuleBlock, // EOF in a qualified rule prelude, before '{' - ErrInvalidDeclarationSyntax, - ErrInvalidBangImportantSyntax, - // This is meant to be extended -} - -impl fmt::Show for SyntaxError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:u}:{:u} {:?}", self.location.line, self.location.column, self.reason) - } -} - - -pub trait SkipWhitespaceIterable<'a> { - fn skip_whitespace(self) -> SkipWhitespaceIterator<'a>; -} - -impl<'a> SkipWhitespaceIterable<'a> for &'a [ComponentValue] { - fn skip_whitespace(self) -> SkipWhitespaceIterator<'a> { - SkipWhitespaceIterator{ iter_with_whitespace: self.iter() } - } -} - -#[deriving(Clone)] -pub struct SkipWhitespaceIterator<'a> { - pub iter_with_whitespace: slice::Items<'a, ComponentValue>, -} - -impl<'a> Iterator<&'a ComponentValue> for SkipWhitespaceIterator<'a> { - fn next(&mut self) -> Option<&'a ComponentValue> { - for component_value in self.iter_with_whitespace { - if component_value != &WhiteSpace { return Some(component_value) } - } - None - } -} - - -pub trait MoveSkipWhitespaceIterable { - fn move_skip_whitespace(self) -> MoveSkipWhitespaceIterator; -} - -impl MoveSkipWhitespaceIterable for Vec { - fn move_skip_whitespace(self) -> MoveSkipWhitespaceIterator { - MoveSkipWhitespaceIterator{ iter_with_whitespace: self.move_iter() } - } -} - -pub struct MoveSkipWhitespaceIterator { - iter_with_whitespace: vec::MoveItems, -} - -impl Iterator for MoveSkipWhitespaceIterator { - fn next(&mut self) -> Option { - for component_value in self.iter_with_whitespace { - if component_value != WhiteSpace { return Some(component_value) } - } - None - } -} diff --git a/src/ast.rs b/src/ast.rs new file mode 100644 index 00000000..43d8f697 --- /dev/null +++ b/src/ast.rs @@ -0,0 +1,385 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::fmt; +use std::slice; +use std::vec; +use serialize::{json}; +use serialize::json::ToJson; + + +#[deriving(PartialEq, Show)] +pub struct NumericValue { + pub representation: String, + pub value: f64, + pub int_value: Option, +} + + +#[deriving(PartialEq, Show)] +pub struct SourceLocation { + pub line: uint, // First line is 1 + pub column: uint, // First character of a line is at column 1 +} + + +pub type Node = (ComponentValue, SourceLocation); // TODO this is not a good name + + +#[deriving(PartialEq, Show)] +pub enum ComponentValue { + // Preserved tokens. + Ident(String), + AtKeyword(String), + Hash(String), + IDHash(String), // Hash that is a valid ID selector. + String(String), + URL(String), + Delim(char), + Number(NumericValue), + Percentage(NumericValue), + Dimension(NumericValue, String), + UnicodeRange(u32, u32), // (start, end) of range + WhiteSpace(String), + Colon, // : + Semicolon, // ; + Comma, // , + IncludeMatch, // ~= + DashMatch, // |= + PrefixMatch, // ^= + SuffixMatch, // $= + SubstringMatch, // *= + Column, // || + CDO, // + + // Function + Function(String, Vec), // name, arguments + + // Simple block + ParenthesisBlock(Vec), // (…) + SquareBracketBlock(Vec), // […] + CurlyBracketBlock(Vec), // {…} + + // These are always invalid + BadURL, + BadString, + CloseParenthesis, // ) + CloseSquareBracket, // ] + CloseCurlyBracket, // } +} + + +#[deriving(PartialEq, Show)] +pub struct Declaration { + pub location: SourceLocation, + pub name: String, + pub value: Vec, + pub important: bool, +} + +#[deriving(PartialEq, Show)] +pub struct QualifiedRule { + pub location: SourceLocation, + pub prelude: Vec, + pub block: Vec, +} + +#[deriving(PartialEq, Show)] +pub struct AtRule { + pub location: SourceLocation, + pub name: String, + pub prelude: Vec, + pub block: Option>, +} + +#[deriving(PartialEq, Show)] +pub enum DeclarationListItem { + Declaration(Declaration), + // A better idea for a name that means "at-rule" but is not "AtRule"? + DeclAtRule(AtRule), +} + +#[deriving(PartialEq, Show)] +pub enum Rule { + QualifiedRule(QualifiedRule), + AtRule(AtRule), + NonRule(ComponentValue) +} + +#[deriving(PartialEq)] +pub struct SyntaxError { + pub location: SourceLocation, + pub reason: ErrorReason, +} + +#[deriving(PartialEq, Show)] +pub enum ErrorReason { + ErrEmptyInput, // Parsing a single "thing", found only whitespace. + ErrExtraInput, // Found more non-whitespace after parsing a single "thing". + ErrMissingQualifiedRuleBlock, // EOF in a qualified rule prelude, before '{' + ErrInvalidDeclarationSyntax, + ErrInvalidBangImportantSyntax, + // This is meant to be extended +} + +impl fmt::Show for SyntaxError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:u}:{:u} {:?}", self.location.line, self.location.column, self.reason) + } +} + + +pub trait SkipWhitespaceIterable<'a> { + fn skip_whitespace(self) -> SkipWhitespaceIterator<'a>; +} + +impl<'a> SkipWhitespaceIterable<'a> for &'a [ComponentValue] { + fn skip_whitespace(self) -> SkipWhitespaceIterator<'a> { + SkipWhitespaceIterator{ iter_with_whitespace: self.iter() } + } +} + +#[deriving(Clone)] +pub struct SkipWhitespaceIterator<'a> { + pub iter_with_whitespace: slice::Items<'a, ComponentValue>, +} + +impl<'a> Iterator<&'a ComponentValue> for SkipWhitespaceIterator<'a> { + fn next(&mut self) -> Option<&'a ComponentValue> { + for component_value in self.iter_with_whitespace { + match component_value { + &WhiteSpace(_) => (), + _ => return Some(component_value) + } + } + None + } +} + + +pub trait MoveSkipWhitespaceIterable { + fn move_skip_whitespace(self) -> MoveSkipWhitespaceIterator; +} + +impl MoveSkipWhitespaceIterable for Vec { + fn move_skip_whitespace(self) -> MoveSkipWhitespaceIterator { + MoveSkipWhitespaceIterator{ iter_with_whitespace: self.move_iter() } + } +} + +pub struct MoveSkipWhitespaceIterator { + iter_with_whitespace: vec::MoveItems, +} + +impl Iterator for MoveSkipWhitespaceIterator { + fn next(&mut self) -> Option { + for component_value in self.iter_with_whitespace { + match component_value { + WhiteSpace(_) => (), + _ => return Some(component_value) + } + } + None + } +} + +/* ToJson implementations for all the AST nodes + * + * These need to be implemented here because they can't be implemented in a + * crate that doesn't define these nodes + */ + +macro_rules! JString { + ($e: expr) => { json::String($e.to_string()) } +} + +macro_rules! JList { + ($($e: expr),*) => { json::List(vec!( $($e),* )) } +} + +fn list_to_json(list: &Vec<(ComponentValue, SourceLocation)>) -> Vec { + list.iter().map(|tuple| { + match *tuple { + (ref c, _) => c.to_json() + } + }).collect() +} + +impl ToJson for Result { + fn to_json(&self) -> json::Json { + match *self { + Ok(ref a) => a.to_json(), + Err(ref b) => b.to_json(), + } + } +} + + +impl ToJson for Result { + fn to_json(&self) -> json::Json { + match *self { + Ok(ref a) => a.to_json(), + Err(ref b) => b.to_json(), + } + } +} + + +impl ToJson for Result { + fn to_json(&self) -> json::Json { + match *self { + Ok(ref a) => a.to_json(), + Err(ref b) => b.to_json(), + } + } +} + + +impl ToJson for Result { + fn to_json(&self) -> json::Json { + match *self { + Ok(ref a) => a.to_json(), + Err(ref b) => b.to_json(), + } + } +} + + +impl ToJson for SyntaxError { + fn to_json(&self) -> json::Json { + json::List(vec!(JString!("error"), JString!(match self.reason { + ErrEmptyInput => "empty", + ErrExtraInput => "extra-input", + _ => "invalid", + }))) + } +} + + +impl ToJson for super::Color { + fn to_json(&self) -> json::Json { + use super::{RGBA, CurrentColor}; + + match *self { + RGBA(RGBA { red: r, green: g, blue: b, alpha: a }) => vec!(r, g, b, a).to_json(), + CurrentColor => JString!("currentColor"), + } + } +} + + +impl ToJson for Rule { + fn to_json(&self) -> json::Json { + match *self { + QualifiedRule(ref rule) => rule.to_json(), + AtRule(ref rule) => rule.to_json(), + NonRule(ref component_value) => component_value.to_json() + } + } +} + + +impl ToJson for DeclarationListItem { + fn to_json(&self) -> json::Json { + match *self { + Declaration(ref declaration) => declaration.to_json(), + DeclAtRule(ref at_rule) => at_rule.to_json(), + } + } +} + +impl ToJson for ComponentValue { + fn to_json(&self) -> json::Json { + fn numeric(value: &NumericValue) -> Vec { + match *value { + NumericValue{representation: ref r, value: ref v, int_value: ref i} + => vec!(r.to_json(), v.to_json(), + JString!(match *i { Some(_) => "integer", _ => "number" })) + } + } + + match *self { + Ident(ref value) => JList!(JString!("ident"), value.to_json()), + AtKeyword(ref value) => JList!(JString!("at-keyword"), value.to_json()), + Hash(ref value) => JList!(JString!("hash"), value.to_json(), + JString!("unrestricted")), + IDHash(ref value) => JList!(JString!("hash"), value.to_json(), JString!("id")), + String(ref value) => JList!(JString!("string"), value.to_json()), + URL(ref value) => JList!(JString!("url"), value.to_json()), + Delim('\\') => JString!("\\"), + Delim(value) => json::String(String::from_char(1, value)), + + Number(ref value) => json::List(vec!(JString!("number")) + numeric(value)), + Percentage(ref value) => json::List(vec!(JString!("percentage")) + numeric(value)), + Dimension(ref value, ref unit) + => json::List(vec!(JString!("dimension")) + numeric(value) + &[unit.to_json()]), + + UnicodeRange(start, end) + => JList!(JString!("unicode-range"), start.to_json(), end.to_json()), + + WhiteSpace(ref value) => JString!(value.to_json()), + Colon => JString!(":"), + Semicolon => JString!(";"), + Comma => JString!(","), + IncludeMatch => JString!("~="), + DashMatch => JString!("|="), + PrefixMatch => JString!("^="), + SuffixMatch => JString!("$="), + SubstringMatch => JString!("*="), + Column => JString!("||"), + CDO => JString!(""), + + Function(ref name, ref arguments) + => json::List(vec!(JString!("function"), name.to_json()) + + arguments.iter().map(|a| a.to_json()).collect::>()), + ParenthesisBlock(ref content) + => json::List(vec!(JString!("()")) + content.iter().map(|c| c.to_json()).collect::>()), + SquareBracketBlock(ref content) + => json::List(vec!(JString!("[]")) + content.iter().map(|c| c.to_json()).collect::>()), + CurlyBracketBlock(ref content) + => json::List(vec!(JString!("{}")) + list_to_json(content)), + + BadURL => JList!(JString!("error"), JString!("bad-url")), + BadString => JList!(JString!("error"), JString!("bad-string")), + CloseParenthesis => JList!(JString!("error"), JString!(")")), + CloseSquareBracket => JList!(JString!("error"), JString!("]")), + CloseCurlyBracket => JList!(JString!("error"), JString!("}")), + } + } +} + +impl ToJson for AtRule { + fn to_json(&self) -> json::Json { + match *self { + AtRule{name: ref name, prelude: ref prelude, block: ref block, ..} + => json::List(vec!(JString!("at-rule"), name.to_json(), + prelude.to_json(), block.as_ref().map(list_to_json).to_json())) + } + } +} + + +impl ToJson for QualifiedRule { + fn to_json(&self) -> json::Json { + match *self { + QualifiedRule{prelude: ref prelude, block: ref block, ..} + => json::List(vec!(JString!("qualified rule"), + prelude.to_json(), json::List(list_to_json(block)))) + } + } +} + + +impl ToJson for Declaration { + fn to_json(&self) -> json::Json { + match *self { + Declaration{name: ref name, value: ref value, important: ref important, ..} + => json::List(vec!(JString!("declaration"), name.to_json(), + value.to_json(), important.to_json())) + } + } +} + diff --git a/src/bin/rust-less.rs b/src/bin/rust-less.rs new file mode 100644 index 00000000..cd755ae3 --- /dev/null +++ b/src/bin/rust-less.rs @@ -0,0 +1,102 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![feature(macro_rules, globs, phase)] + +#[phase(plugin, link)] extern crate log; + +extern crate serialize; +extern crate encoding; +extern crate cssparser; + +use std::io; +use std::io::{File, Writer}; + +use cssparser::*; +use cssparser::ast::*; + +macro_rules! try_write( + ($buf:expr, $($args:tt)*) => (match write!($buf, $($args)*) { Ok(e) => e, Err(_e) => return Err(()) }) +) + +fn print_css(mut rules: Vec>) -> Result { + let mut buffer = io::MemWriter::new(); + + fn print_prelude(buffer: &mut io::MemWriter, + prelude: &mut Vec) -> Result<(), ()> { + for p in prelude.mut_iter() { + try_write!(buffer, "{}", p.to_css()); + } + Ok(()) + } + + fn print_block(buffer: &mut io::MemWriter, + block: &mut Vec) -> Result<(), ()> { + try_write!(buffer, "{{"); + for &(ref mut b, _) in block.mut_iter() { + try_write!(buffer, "{}", b.to_css()); + } + try_write!(buffer, "}}"); + + Ok(()) + } + + for r in rules.mut_iter() { + match *r { + Ok(ref mut rule) => { + match *rule { + QualifiedRule(ref mut q) => { + try!(print_prelude(&mut buffer, &mut q.prelude)); + try!(print_block(&mut buffer, &mut q.block)); + }, + AtRule(ref mut a) => { + //try_write!(buffer, "{}\n", a); + try_write!(buffer, "@{}", a.name); + try!(print_prelude(&mut buffer, &mut a.prelude)); + match a.block { + None => (), + Some(ref mut b) => try!(print_block(&mut buffer, b)) + } + }, + NonRule(ref mut component_value) => { + try_write!(buffer, "{}", component_value.to_css()); + } + } + }, + Err(e) => { + try_write!(buffer, "Err: {}", e); + } + }; + } + + String::from_utf8(buffer.unwrap()) + .map_err(|_| ()) +} + +fn print_json(rules: &Vec>) { + use serialize::json::ToJson; + debug!("{}", rules.to_json()); +} + +fn main() { + let contents = File::open(&Path::new("test/less/variables.less")).read_to_end(); + + let contents = match contents { + Err(e) => fail!(e), + Ok(c) => c + }; + + let (css_unicode, _encoding) = decode_stylesheet_bytes(contents.as_slice(), None, None); + + let tokens = tokenize(css_unicode.as_slice()); + let mut rules = parse_stylesheet_rules(tokens); + + let rules = rules.collect::>>(); + print_json(&rules); + + match print_css(rules) { + Ok(res) => println!("{}", res), + Err(e) => println!("Err: {}", e) + } +} diff --git a/color.rs b/src/color.rs similarity index 95% rename from color.rs rename to src/color.rs index 8978c816..d5245f11 100644 --- a/color.rs +++ b/src/color.rs @@ -205,10 +205,10 @@ fn parse_color_hash(value: &str) -> Option { macro_rules! from_hex( ($c: expr) => {{ let c = $c; - match c as char { - '0' .. '9' => c - ('0' as u8), - 'a' .. 'f' => c - ('a' as u8) + 10, - 'A' .. 'F' => c - ('A' as u8) + 10, + match c { + '0' .. '9' => (c as u8) - ('0' as u8), + 'a' .. 'f' => (c as u8) - ('a' as u8) + 10, + 'A' .. 'F' => (c as u8) - ('A' as u8) + 10, _ => return None // Not a valid color } }}; @@ -224,14 +224,14 @@ fn parse_color_hash(value: &str) -> Option { match value.len() { 6 => to_rgba!( - from_hex!(value[0]) * 16 + from_hex!(value[1]), - from_hex!(value[2]) * 16 + from_hex!(value[3]), - from_hex!(value[4]) * 16 + from_hex!(value[5]), + from_hex!(value.char_at(0)) * 16 + from_hex!(value.char_at(1)), + from_hex!(value.char_at(2)) * 16 + from_hex!(value.char_at(3)), + from_hex!(value.char_at(4)) * 16 + from_hex!(value.char_at(5)), ), 3 => to_rgba!( - from_hex!(value[0]) * 17, - from_hex!(value[1]) * 17, - from_hex!(value[2]) * 17, + from_hex!(value.char_at(0)) * 17, + from_hex!(value.char_at(1)) * 17, + from_hex!(value.char_at(2)) * 17, ), _ => None } diff --git a/from_bytes.rs b/src/from_bytes.rs similarity index 96% rename from from_bytes.rs rename to src/from_bytes.rs index d02eed80..0940366c 100644 --- a/from_bytes.rs +++ b/src/from_bytes.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::cmp; -use std::str; use encoding::label::encoding_from_whatwg_label; use encoding::all::UTF_8; @@ -50,7 +49,7 @@ pub fn decode_stylesheet_bytes(css: &[u8], protocol_encoding_label: Option<&str> Some(label_length) => if css.slice_from(10 + label_length).starts_with("\";".as_bytes()) { let label = css.slice(10, 10 + label_length); - let label = str::from_chars(label.iter().map(|&b| b as char).collect::>().as_slice()); + let label = String::from_chars(label.iter().map(|&b| b as char).collect::>().as_slice()); match encoding_from_whatwg_label(label.as_slice()) { None => (), Some(fallback) => match fallback.name() { diff --git a/lib.rs b/src/lib.rs similarity index 92% rename from lib.rs rename to src/lib.rs index 7285e881..6a46cf29 100644 --- a/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#![crate_id = "github.com/mozilla-servo/rust-cssparser#cssparser:0.1"] +#![crate_name = "cssparser"] #![crate_type = "lib"] #![crate_type = "dylib"] #![crate_type = "rlib"] @@ -16,7 +16,6 @@ extern crate debug; #[cfg(test)] extern crate test; -#[cfg(test)] extern crate serialize; pub use tokenizer::{tokenize, Tokenizer}; diff --git a/nth.rs b/src/nth.rs similarity index 100% rename from nth.rs rename to src/nth.rs diff --git a/parser.rs b/src/parser.rs similarity index 96% rename from parser.rs rename to src/parser.rs index fa490c8a..dcdb96f5 100644 --- a/parser.rs +++ b/src/parser.rs @@ -118,7 +118,7 @@ impl> Iterator> for StylesheetParser let iter = &mut self.iter; for_iter!(iter, (component_value, location), { match component_value { - WhiteSpace | CDO | CDC => (), + WhiteSpace(_) | CDO | CDC => return Some(Ok(NonRule(component_value))), AtKeyword(name) => return Some(Ok(AtRule(parse_at_rule(iter, name, location)))), _ => return Some(match parse_qualified_rule(iter, component_value, location) { Ok(rule) => Ok(QualifiedRule(rule)), @@ -136,7 +136,7 @@ impl> Iterator> for RuleListParser (), + WhiteSpace(_) => (), AtKeyword(name) => return Some(Ok(AtRule(parse_at_rule(iter, name, location)))), _ => return Some(match parse_qualified_rule(iter, component_value, location) { Ok(rule) => Ok(QualifiedRule(rule)), @@ -155,7 +155,7 @@ for DeclarationListParser { let iter = &mut self.iter; for_iter!(iter, (component_value, location), { match component_value { - WhiteSpace | Semicolon => (), + WhiteSpace(_) | Semicolon => (), AtKeyword(name) => return Some(Ok(DeclAtRule(parse_at_rule(iter, name, location)))), _ => return Some(match parse_declaration(iter, component_value, location) { @@ -180,7 +180,7 @@ fn parse_at_rule>(iter: &mut T, name: String, location: Source for_iter!(iter, (component_value, _location), { match component_value { CurlyBracketBlock(content) => { block = Some(content); break }, - Semicolon => break, + Semicolon => {prelude.push(Semicolon); break}, component_value => prelude.push(component_value), } }) @@ -255,7 +255,10 @@ fn parse_declaration_important>(iter: &mut T) -> bool { #[inline] fn next_non_whitespace>(iter: &mut T) -> Option { for (component_value, location) in *iter { - if component_value != WhiteSpace { return Some((component_value, location)) } + match component_value { + WhiteSpace(_) => (), + _ => return Some((component_value, location)) + } } None } diff --git a/serializer.rs b/src/serializer.rs similarity index 98% rename from serializer.rs rename to src/serializer.rs index 88b065d0..346df7bc 100644 --- a/serializer.rs +++ b/src/serializer.rs @@ -64,9 +64,9 @@ impl ast::ComponentValue { } } - WhiteSpace => css.push_char(' '), + WhiteSpace(ref s) => css.push_str(s.as_slice()), Colon => css.push_char(':'), - Semicolon => css.push_char(';'), + Semicolon => css.push_str(";"), Comma => css.push_char(','), IncludeMatch => css.push_str("~="), DashMatch => css.push_str("|="), @@ -168,7 +168,6 @@ pub trait ToCss { fn to_css_push(&mut self, css: &mut String); } - impl<'a, I: Iterator<&'a ComponentValue>> ToCss for I { fn to_css_push(&mut self, css: &mut String) { let mut previous = match self.next() { @@ -220,7 +219,7 @@ impl<'a, I: Iterator<&'a ComponentValue>> ToCss for I { css.push_str("/**/") } // Skip whitespace when '\n' was previously written at the previous iteration. - if !matches!((previous, component_value), (&Delim('\\'), &WhiteSpace)) { + if !matches!((previous, component_value), (&Delim('\\'), &WhiteSpace(_))) { component_value.to_css_push(css); } if component_value == &Delim('\\') { diff --git a/tests.rs b/src/tests.rs similarity index 88% rename from tests.rs rename to src/tests.rs index 4443fda4..67bfba78 100644 --- a/tests.rs +++ b/src/tests.rs @@ -58,10 +58,10 @@ fn assert_json_eq(results: json::Json, expected: json::Json, message: String) { write_whole_file(&expected_path, expected.as_slice()); Command::new("colordiff") .arg("-u1000") - .arg(result_path.display().to_str()) - .arg(expected_path.display().to_str()) - .status().unwrap(); - }).unwrap(); + .arg(result_path) + .arg(expected_path) + .status().unwrap_or_else(|e| fail!("Failed to get status of colordiff: {}", e)); + }).unwrap_or_else(|_e| fail!("Failed to execute task")); fail!(message) } @@ -102,7 +102,7 @@ fn run_json_tests(json_data: &str, parse: |input: &str| -> T) { #[test] fn component_value_list() { - run_json_tests(include_str!("css-parsing-tests/component_value_list.json"), |input| { + run_json_tests(include_str!("../css-parsing-tests/component_value_list.json"), |input| { tokenize(input).map(|(c, _)| c).collect::>() }); } @@ -110,7 +110,7 @@ fn component_value_list() { #[test] fn one_component_value() { - run_json_tests(include_str!("css-parsing-tests/one_component_value.json"), |input| { + run_json_tests(include_str!("../css-parsing-tests/one_component_value.json"), |input| { parse_one_component_value(tokenize(input)) }); } @@ -118,7 +118,7 @@ fn one_component_value() { #[test] fn declaration_list() { - run_json_tests(include_str!("css-parsing-tests/declaration_list.json"), |input| { + run_json_tests(include_str!("../css-parsing-tests/declaration_list.json"), |input| { parse_declaration_list(tokenize(input)).collect::>>() }); } @@ -126,7 +126,7 @@ fn declaration_list() { #[test] fn one_declaration() { - run_json_tests(include_str!("css-parsing-tests/one_declaration.json"), |input| { + run_json_tests(include_str!("../css-parsing-tests/one_declaration.json"), |input| { parse_one_declaration(tokenize(input)) }); } @@ -134,7 +134,7 @@ fn one_declaration() { #[test] fn rule_list() { - run_json_tests(include_str!("css-parsing-tests/rule_list.json"), |input| { + run_json_tests(include_str!("../css-parsing-tests/rule_list.json"), |input| { parse_rule_list(tokenize(input)).collect::>>() }); } @@ -142,7 +142,7 @@ fn rule_list() { #[test] fn stylesheet() { - run_json_tests(include_str!("css-parsing-tests/stylesheet.json"), |input| { + run_json_tests(include_str!("../css-parsing-tests/stylesheet.json"), |input| { parse_stylesheet_rules(tokenize(input)).collect::>>() }); } @@ -150,7 +150,7 @@ fn stylesheet() { #[test] fn one_rule() { - run_json_tests(include_str!("css-parsing-tests/one_rule.json"), |input| { + run_json_tests(include_str!("../css-parsing-tests/one_rule.json"), |input| { parse_one_rule(tokenize(input)) }); } @@ -158,7 +158,7 @@ fn one_rule() { #[test] fn stylesheet_from_bytes() { - run_raw_json_tests(include_str!("css-parsing-tests/stylesheet_bytes.json"), + run_raw_json_tests(include_str!("../css-parsing-tests/stylesheet_bytes.json"), |input, expected| { let map = match input { json::Object(map) => map, @@ -166,12 +166,12 @@ fn stylesheet_from_bytes() { }; let result = { - let css = get_string(map, &"css_bytes".to_string()).unwrap().chars().map(|c| { + let css = get_string(&map, &"css_bytes".to_string()).unwrap().chars().map(|c| { assert!(c as u32 <= 0xFF); c as u8 }).collect::>(); - let protocol_encoding_label = get_string(map, &"protocol_encoding".to_string()); - let environment_encoding = get_string(map, &"environment_encoding".to_string()) + let protocol_encoding_label = get_string(&map, &"protocol_encoding".to_string()); + let environment_encoding = get_string(&map, &"environment_encoding".to_string()) .and_then(encoding_from_whatwg_label); let (mut rules, used_encoding) = parse_stylesheet_rules_from_bytes( @@ -179,7 +179,7 @@ fn stylesheet_from_bytes() { (rules.collect::>>(), used_encoding.name().to_string()).to_json() }; - assert_json_eq(result, expected, json::Object(map).to_str()); + assert_json_eq(result, expected, json::Object(map).to_pretty_str()); }); fn get_string<'a>(map: &'a json::Object, key: &String) -> Option<&'a str> { @@ -205,20 +205,20 @@ fn run_color_tests(json_data: &str, to_json: |result: Option| -> json::Js #[test] fn color3() { - run_color_tests(include_str!("css-parsing-tests/color3.json"), |c| c.to_json()) + run_color_tests(include_str!("../css-parsing-tests/color3.json"), |c| c.to_json()) } #[test] fn color3_hsl() { - run_color_tests(include_str!("css-parsing-tests/color3_hsl.json"), |c| c.to_json()) + run_color_tests(include_str!("../css-parsing-tests/color3_hsl.json"), |c| c.to_json()) } /// color3_keywords.json is different: R, G and B are in 0..255 rather than 0..1 #[test] fn color3_keywords() { - run_color_tests(include_str!("css-parsing-tests/color3_keywords.json"), |c| { + run_color_tests(include_str!("../css-parsing-tests/color3_keywords.json"), |c| { match c { Some(RGBA(RGBA { red: r, green: g, blue: b, alpha: a })) => vec!(r * 255., g * 255., b * 255., a).to_json(), @@ -252,7 +252,7 @@ fn bench_color_lookup_fail(b: &mut test::Bencher) { #[test] fn nth() { - run_json_tests(include_str!("css-parsing-tests/An+B.json"), |input| { + run_json_tests(include_str!("../css-parsing-tests/An+B.json"), |input| { parse_nth(tokenize(input).map(|(c, _)| c).collect::>().as_slice()) }); } @@ -260,7 +260,7 @@ fn nth() { #[test] fn serializer() { - run_json_tests(include_str!("css-parsing-tests/component_value_list.json"), |input| { + run_json_tests(include_str!("../css-parsing-tests/component_value_list.json"), |input| { let component_values = tokenize(input).map(|(c, _)| c).collect::>(); let serialized = component_values.iter().to_css(); tokenize(serialized.as_slice()).map(|(c, _)| c).collect::>() diff --git a/tokenizer.rs b/src/tokenizer.rs similarity index 99% rename from tokenizer.rs rename to src/tokenizer.rs index 7294e0eb..fbf6f123 100644 --- a/tokenizer.rs +++ b/src/tokenizer.rs @@ -114,8 +114,11 @@ fn next_component_value(tokenizer: &mut Tokenizer) -> Option { let c = tokenizer.current_char(); let component_value = match c { '\t' | '\n' | ' ' => { + let mut spaces = String::new(); while !tokenizer.is_eof() { - match tokenizer.current_char() { + let c = tokenizer.current_char(); + match c { + ' ' | '\t' => tokenizer.position += 1, '\n' => { tokenizer.position += 1; @@ -123,8 +126,9 @@ fn next_component_value(tokenizer: &mut Tokenizer) -> Option { }, _ => break, } + spaces.push_char(c); } - WhiteSpace + WhiteSpace(spaces) }, '"' => consume_string(tokenizer, false), '#' => { diff --git a/test/css/charsets.css b/test/css/charsets.css new file mode 100644 index 00000000..9f44090c --- /dev/null +++ b/test/css/charsets.css @@ -0,0 +1 @@ +@charset "UTF-8"; diff --git a/test/css/colors.css b/test/css/colors.css new file mode 100644 index 00000000..08a22abb --- /dev/null +++ b/test/css/colors.css @@ -0,0 +1,87 @@ +#yelow #short { + color: #fea; +} +#yelow #long { + color: #ffeeaa; +} +#yelow #rgba { + color: rgba(255, 238, 170, 0.1); +} +#yelow #argb { + color: #1affeeaa; +} +#blue #short { + color: #00f; +} +#blue #long { + color: #0000ff; +} +#blue #rgba { + color: rgba(0, 0, 255, 0.1); +} +#blue #argb { + color: #1a0000ff; +} +#alpha #hsla { + color: rgba(61, 45, 41, 0.6); +} +#overflow .a { + color: #000000; +} +#overflow .b { + color: #ffffff; +} +#overflow .c { + color: #ffffff; +} +#overflow .d { + color: #00ff00; +} +#overflow .e { + color: rgba(0, 31, 255, 0.42); +} +#grey { + color: #c8c8c8; +} +#333333 { + color: #333333; +} +#808080 { + color: #808080; +} +#00ff00 { + color: #00ff00; +} +.lightenblue { + color: #3333ff; +} +.darkenblue { + color: #0000cc; +} +.unknowncolors { + color: blue2; + border: 2px solid superred; +} +.transparent { + color: transparent; + background-color: rgba(0, 0, 0, 0); +} +#alpha #fromvar { + opacity: 0.7; +} +#alpha #short { + opacity: 1; +} +#alpha #long { + opacity: 1; +} +#alpha #rgba { + opacity: 0.2; +} +#alpha #hsl { + opacity: 1; +} +#percentage { + color: 255; + border-color: rgba(255, 0, 0, 0.5); +} diff --git a/test/css/comments.css b/test/css/comments.css new file mode 100644 index 00000000..b85f5b4f --- /dev/null +++ b/test/css/comments.css @@ -0,0 +1,69 @@ +/******************\ +* * +* Comment Header * +* * +\******************/ +/* + + Comment + +*/ +/* + * Comment Test + * + * - cloudhead (http://cloudhead.net) + * + */ +/* Colors + * ------ + * #EDF8FC (background blue) + * #166C89 (darkest blue) + * + * Text: + * #333 (standard text) // A comment within a comment! + * #1F9EC9 (standard link) + * + */ +/* @group Variables +------------------- */ +#comments, +.comments { + /**/ + color: red; + /* A C-style comment */ + /* A C-style comment */ + background-color: orange; + font-size: 12px; + /* lost comment */ + content: "content"; + border: 1px solid black; + padding: 0; + margin: 2em; +} +/* commented out + #more-comments { + color: grey; + } +*/ +.selector, +.lots, +.comments { + color: #808080, /* blue */ #ffa500; + -webkit-border-radius: 2px /* webkit only */; + -moz-border-radius: 8px /* moz only with operation */; +} +.test { + color: 1px; +} +#last { + color: #0000ff; +} +/* */ +/* { */ +/* */ +/* */ +/* */ +#div { + color: #A33; +} +/* } */ diff --git a/test/css/compression/compression.css b/test/css/compression/compression.css new file mode 100644 index 00000000..f9cc90a3 --- /dev/null +++ b/test/css/compression/compression.css @@ -0,0 +1,3 @@ +#colours{color1:#fea;color2:#fea;color3:rgba(255,238,170,0.1);string:"#ffeeaa";/*! but not this type + Note preserved whitespace + */}dimensions{val:.1px;val:0;val:4cm;val:.2;val:5;angles-must-have-unit:0deg;durations-must-have-unit:0s;length-doesnt-have-unit:0;width:auto\9}@page{marks:none;@top-left-corner{vertical-align:top}@top-left{vertical-align:top}}.shadow^.dom,body^^.shadow{display:done} \ No newline at end of file diff --git a/test/css/css-3.css b/test/css/css-3.css new file mode 100644 index 00000000..4dd72432 --- /dev/null +++ b/test/css/css-3.css @@ -0,0 +1,132 @@ +.comma-delimited { + text-shadow: -1px -1px 1px #ff0000, 6px 5px 5px #ffff00; + -moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset, 0pt 4px 6px rgba(255, 255, 255, 0.4) inset; + -webkit-transform: rotate(0deg); +} +@font-face { + font-family: Headline; + unicode-range: U+??????, U+0???, U+0-7F, U+A5; +} +.other { + -moz-transform: translate(0, 11em) rotate(-90deg); + transform: rotateX(45deg); +} +.item[data-cra_zy-attr1b-ut3=bold] { + font-weight: bold; +} +p:not([class*="lead"]) { + color: black; +} +input[type="text"].class#id[attr=32]:not(1) { + color: white; +} +div#id.class[a=1][b=2].class:not(1) { + color: white; +} +ul.comma > li:not(:only-child)::after { + color: white; +} +ol.comma > li:nth-last-child(2)::after { + color: white; +} +li:nth-child(4n+1), +li:nth-child(-5n), +li:nth-child(-n+2) { + color: white; +} +a[href^="http://"] { + color: black; +} +a[href$="http://"] { + color: black; +} +form[data-disabled] { + color: black; +} +p::before { + color: black; +} +#issue322 { + -webkit-animation: anim2 7s infinite ease-in-out; +} +@-webkit-keyframes frames { + 0% { + border: 1px; + } + 5.5% { + border: 2px; + } + 100% { + border: 3px; + } +} +@keyframes fontbulger1 { + to { + font-size: 15px; + } + from, + to { + font-size: 12px; + } + 0%, + 100% { + font-size: 12px; + } +} +.units { + font: 1.2rem/2rem; + font: 8vw/9vw; + font: 10vh/12vh; + font: 12vm/15vm; + font: 12vmin/15vmin; + font: 1.2ch/1.5ch; +} +@supports ( box-shadow: 2px 2px 2px black ) or + ( -moz-box-shadow: 2px 2px 2px black ) { + .outline { + box-shadow: 2px 2px 2px black; + -moz-box-shadow: 2px 2px 2px black; + } +} +@-x-document url-prefix(""github.com"") { + h1 { + color: red; + } +} +@viewport { + font-size: 10px; +} +@namespace foo url(http://www.example.com); +foo|h1 { + color: blue; +} +foo|* { + color: yellow; +} +|h1 { + color: red; +} +*|h1 { + color: green; +} +h1 { + color: green; +} +.upper-test { + UpperCaseProperties: allowed; +} +@host { + div { + display: block; + } +} +::distributed(input::placeholder) { + color: #b3b3b3; +} +.shadow ^ .dom, +body ^^ .shadow { + display: done; +} +#issue2066 { + background: url('/images/icon-team.svg') 0 0 / contain; +} diff --git a/test/css/css-escapes.css b/test/css/css-escapes.css new file mode 100644 index 00000000..4d343aa6 --- /dev/null +++ b/test/css/css-escapes.css @@ -0,0 +1,24 @@ +.escape\|random\|char { + color: red; +} +.mixin\!tUp { + font-weight: bold; +} +.\34 04 { + background: red; +} +.\34 04 strong { + color: #ff00ff; + font-weight: bold; +} +.trailingTest\+ { + color: red; +} +/* This hideous test of hideousness checks for the selector "blockquote" with various permutations of hex escapes */ +\62\6c\6f \63 \6B \0071 \000075o\74 e { + color: silver; +} +[ng\:cloak], +ng\:form { + display: none; +} diff --git a/test/css/css-guards.css b/test/css/css-guards.css new file mode 100644 index 00000000..f4b8a108 --- /dev/null +++ b/test/css/css-guards.css @@ -0,0 +1,37 @@ +.light { + color: green; +} +.see-the { + color: green; +} +.hide-the { + color: green; +} +.multiple-conditions-1 { + color: red; +} +.inheritance .test { + color: black; +} +.inheritance:hover { + color: pink; +} +.clsWithGuard { + dispaly: none; +} +.dont-split-me-up { + width: 1px; + color: red; + height: 1px; +} + + .dont-split-me-up { + sibling: true; +} +.scope-check { + sub-prop: 2px; + prop: 1px; +} +.scope-check-2 { + sub-prop: 2px; + prop: 1px; +} diff --git a/test/css/css.css b/test/css/css.css new file mode 100644 index 00000000..b011a7e3 --- /dev/null +++ b/test/css/css.css @@ -0,0 +1,95 @@ +@charset "utf-8"; +div { + color: black; +} +div { + width: 99%; +} +* { + min-width: 45em; +} +h1, +h2 > a > p, +h3 { + color: none; +} +div.class { + color: blue; +} +div#id { + color: green; +} +.class#id { + color: purple; +} +.one.two.three { + color: grey; +} +@media print { + * { + font-size: 3em; + } +} +@media screen { + * { + font-size: 10px; + } +} +@font-face { + font-family: 'Garamond Pro'; +} +a:hover, +a:link { + color: #999; +} +p, +p:first-child { + text-transform: none; +} +q:lang(no) { + quotes: none; +} +p + h1 { + font-size: 2.2em; +} +#shorthands { + border: 1px solid #000; + font: 12px/16px Arial; + font: 100%/16px Arial; + margin: 1px 0; + padding: 0 auto; +} +#more-shorthands { + margin: 0; + padding: 1px 0 2px 0; + font: normal small / 20px 'Trebuchet MS', Verdana, sans-serif; + font: 0/0 a; + border-radius: 5px / 10px; +} +.misc { + -moz-border-radius: 2px; + display: -moz-inline-stack; + width: .1em; + background-color: #009998; + background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), to(#0000ff)); + margin: ; + filter: alpha(opacity=100); + width: auto\9; +} +.misc .nested-multiple { + multiple-semi-colons: yes; +} +#important { + color: red !important; + width: 100%!important; + height: 20px ! important; +} +@font-face { + font-family: font-a; +} +@font-face { + font-family: font-b; +} +.æøå { + margin: 0; +} diff --git a/test/css/debug/linenumbers-all.css b/test/css/debug/linenumbers-all.css new file mode 100644 index 00000000..87022aec --- /dev/null +++ b/test/css/debug/linenumbers-all.css @@ -0,0 +1,49 @@ +@charset "UTF-8"; +/* line 1, {pathimport}test.less */ +@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000031}} +/* @charset "ISO-8859-1"; */ +/* line 23, {pathimport}test.less */ +@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000323}} +.tst3 { + color: grey; +} +/* line 15, {path}linenumbers.less */ +@media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\0000315}} +.test1 { + color: black; +} +/* line 6, {path}linenumbers.less */ +@media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\000036}} +.test2 { + color: red; +} +@media all { + /* line 5, {pathimport}test.less */ + @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000035}} + .tst { + color: black; + } +} +@media all and screen { + /* line 7, {pathimport}test.less */ + @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000037}} + .tst { + color: red; + } + /* line 9, {pathimport}test.less */ + @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000039}} + .tst .tst3 { + color: white; + } +} +/* line 18, {pathimport}test.less */ +@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000318}} +.tst2 { + color: white; +} +/* line 27, {path}linenumbers.less */ +@media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\0000327}} +.test { + color: red; + width: 2; +} diff --git a/test/css/debug/linenumbers-comments.css b/test/css/debug/linenumbers-comments.css new file mode 100644 index 00000000..e5d6bb38 --- /dev/null +++ b/test/css/debug/linenumbers-comments.css @@ -0,0 +1,40 @@ +@charset "UTF-8"; +/* line 1, {pathimport}test.less */ +/* @charset "ISO-8859-1"; */ +/* line 23, {pathimport}test.less */ +.tst3 { + color: grey; +} +/* line 15, {path}linenumbers.less */ +.test1 { + color: black; +} +/* line 6, {path}linenumbers.less */ +.test2 { + color: red; +} +@media all { + /* line 5, {pathimport}test.less */ + .tst { + color: black; + } +} +@media all and screen { + /* line 7, {pathimport}test.less */ + .tst { + color: red; + } + /* line 9, {pathimport}test.less */ + .tst .tst3 { + color: white; + } +} +/* line 18, {pathimport}test.less */ +.tst2 { + color: white; +} +/* line 27, {path}linenumbers.less */ +.test { + color: red; + width: 2; +} diff --git a/test/css/debug/linenumbers-mediaquery.css b/test/css/debug/linenumbers-mediaquery.css new file mode 100644 index 00000000..e252ab3c --- /dev/null +++ b/test/css/debug/linenumbers-mediaquery.css @@ -0,0 +1,40 @@ +@charset "UTF-8"; +@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000031}} +/* @charset "ISO-8859-1"; */ +@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000323}} +.tst3 { + color: grey; +} +@media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\0000315}} +.test1 { + color: black; +} +@media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\000036}} +.test2 { + color: red; +} +@media all { + @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000035}} + .tst { + color: black; + } +} +@media all and screen { + @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000037}} + .tst { + color: red; + } + @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000039}} + .tst .tst3 { + color: white; + } +} +@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000318}} +.tst2 { + color: white; +} +@media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\0000327}} +.test { + color: red; + width: 2; +} diff --git a/test/css/detached-rulesets.css b/test/css/detached-rulesets.css new file mode 100644 index 00000000..300c08d0 --- /dev/null +++ b/test/css/detached-rulesets.css @@ -0,0 +1,71 @@ +.wrap-selector { + color: black; + one: 1px; + four: magic-frame; + visible-one: visible; + visible-two: visible; +} +.wrap-selector { + color: red; + visible-one: visible; + visible-two: visible; +} +.wrap-selector { + color: black; + background: white; + visible-one: visible; + visible-two: visible; +} +header { + background: blue; +} +@media screen and (min-width: 1200) { + header { + background: red; + } +} +html.lt-ie9 header { + background: red; +} +.wrap-selector { + test: extra-wrap; + visible-one: visible; + visible-two: visible; +} +.wrap-selector .wrap-selector { + test: wrapped-twice; + visible-one: visible; + visible-two: visible; +} +.wrap-selector { + test-func: 90; + test-arithmetic: 18px; + visible-one: visible; + visible-two: visible; +} +.without-mixins { + b: 1; +} +@media (orientation: portrait) and tv { + .my-selector { + background-color: black; + } +} +@media (orientation: portrait) and widescreen and print and tv { + .triple-wrapped-mq { + triple: true; + } +} +@media (orientation: portrait) and widescreen and tv { + .triple-wrapped-mq { + triple: true; + } +} +@media (orientation: portrait) and tv { + .triple-wrapped-mq { + triple: true; + } +} +.a { + test: test; +} diff --git a/test/css/empty.css b/test/css/empty.css new file mode 100644 index 00000000..e69de29b diff --git a/test/css/extend-chaining.css b/test/css/extend-chaining.css new file mode 100644 index 00000000..820e134f --- /dev/null +++ b/test/css/extend-chaining.css @@ -0,0 +1,81 @@ +.a, +.b, +.c { + color: black; +} +.f, +.e, +.d { + color: black; +} +.g.h, +.i.j.h, +.k.j.h { + color: black; +} +.i.j, +.k.j { + color: white; +} +.l, +.m, +.n, +.o, +.p, +.q, +.r, +.s, +.t { + color: black; +} +.u, +.v.u.v { + color: black; +} +.w, +.v.w.v { + color: black; +} +.x, +.y, +.z { + color: x; +} +.y, +.z, +.x { + color: y; +} +.z, +.x, +.y { + color: z; +} +.va, +.vb, +.vc { + color: black; +} +.vb, +.vc { + color: white; +} +@media tv { + .ma, + .mb, + .mc { + color: black; + } + .md, + .ma, + .mb, + .mc { + color: white; + } +} +@media tv and plasma { + .me, + .mf { + background: red; + } +} diff --git a/test/css/extend-clearfix.css b/test/css/extend-clearfix.css new file mode 100644 index 00000000..966892a2 --- /dev/null +++ b/test/css/extend-clearfix.css @@ -0,0 +1,19 @@ +.clearfix, +.foo, +.bar { + *zoom: 1; +} +.clearfix:after, +.foo:after, +.bar:after { + content: ''; + display: block; + clear: both; + height: 0; +} +.foo { + color: red; +} +.bar { + color: blue; +} diff --git a/test/css/extend-exact.css b/test/css/extend-exact.css new file mode 100644 index 00000000..beff4133 --- /dev/null +++ b/test/css/extend-exact.css @@ -0,0 +1,37 @@ +.replace.replace .replace, +.c.replace + .replace .replace, +.replace.replace .c, +.c.replace + .replace .c, +.rep_ace { + prop: copy-paste-replace; +} +.a .b .c { + prop: not_effected; +} +.a, +.effected { + prop: is_effected; +} +.a .b { + prop: not_effected; +} +.a .b.c { + prop: not_effected; +} +.c .b .a, +.a .b .a, +.c .a .a, +.a .a .a, +.c .b .c, +.a .b .c, +.c .a .c, +.a .a .c { + prop: not_effected; +} +.e.e, +.dbl { + prop: extend-double; +} +.e.e:hover { + hover: not-extended; +} diff --git a/test/css/extend-media.css b/test/css/extend-media.css new file mode 100644 index 00000000..23bd7b85 --- /dev/null +++ b/test/css/extend-media.css @@ -0,0 +1,24 @@ +.ext1 .ext2, +.all .ext2 { + background: black; +} +@media tv { + .ext1 .ext3, + .tv-lowres .ext3, + .all .ext3 { + color: white; + } + .tv-lowres { + background: blue; + } +} +@media tv and hires { + .ext1 .ext4, + .tv-hires .ext4, + .all .ext4 { + color: green; + } + .tv-hires { + background: red; + } +} diff --git a/test/css/extend-nest.css b/test/css/extend-nest.css new file mode 100644 index 00000000..2c3905d9 --- /dev/null +++ b/test/css/extend-nest.css @@ -0,0 +1,57 @@ +.sidebar, +.sidebar2, +.type1 .sidebar3, +.type2.sidebar4 { + width: 300px; + background: red; +} +.sidebar .box, +.sidebar2 .box, +.type1 .sidebar3 .box, +.type2.sidebar4 .box { + background: #FFF; + border: 1px solid #000; + margin: 10px 0; +} +.sidebar2 { + background: blue; +} +.type1 .sidebar3 { + background: green; +} +.type2.sidebar4 { + background: red; +} +.button, +.submit { + color: black; +} +.button:hover, +.submit:hover { + color: white; +} +.button2 :hover { + nested: white; +} +.button2 :hover { + notnested: black; +} +.amp-test-h, +.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e.amp-test-g, +.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e.amp-test-g { + test: extended by masses of selectors; +} diff --git a/test/css/extend-selector.css b/test/css/extend-selector.css new file mode 100644 index 00000000..da47254b --- /dev/null +++ b/test/css/extend-selector.css @@ -0,0 +1,80 @@ +.error, +.badError { + border: 1px #f00; + background: #fdd; +} +.error.intrusion, +.badError.intrusion { + font-size: 1.3em; + font-weight: bold; +} +.intrusion .error, +.intrusion .badError { + display: none; +} +.badError { + border-width: 3px; +} +.foo .bar, +.foo .baz, +.ext1 .ext2 .bar, +.ext1 .ext2 .baz, +.ext3 .bar, +.ext3 .baz, +.ext4 .bar, +.ext4 .baz { + display: none; +} +div.ext5, +.ext6 > .ext5, +div.ext7, +.ext6 > .ext7 { + width: 100px; +} +.ext, +.a .c, +.b .c { + test: 1; +} +.a, +.b { + test: 2; +} +.a .c, +.b .c { + test: 3; +} +.a .c .d, +.b .c .d { + test: 4; +} +.replace.replace .replace, +.c.replace + .replace .replace, +.replace.replace .c, +.c.replace + .replace .c, +.rep_ace.rep_ace .rep_ace, +.c.rep_ace + .rep_ace .rep_ace, +.rep_ace.rep_ace .c, +.c.rep_ace + .rep_ace .c { + prop: copy-paste-replace; +} +.attributes [data="test"], +.attributes .attributes .attribute-test { + extend: attributes; +} +.attributes [data], +.attributes .attributes .attribute-test2 { + extend: attributes2; +} +.attributes [data="test3"], +.attributes .attributes .attribute-test { + extend: attributes2; +} +.header .header-nav, +.footer .footer-nav { + background: red; +} +.header .header-nav:before, +.footer .footer-nav:before { + background: blue; +} diff --git a/test/css/extend.css b/test/css/extend.css new file mode 100644 index 00000000..2895641a --- /dev/null +++ b/test/css/extend.css @@ -0,0 +1,76 @@ +.error, +.badError { + border: 1px #f00; + background: #fdd; +} +.error.intrusion, +.badError.intrusion { + font-size: 1.3em; + font-weight: bold; +} +.intrusion .error, +.intrusion .badError { + display: none; +} +.badError { + border-width: 3px; +} +.foo .bar, +.foo .baz, +.ext1 .ext2 .bar, +.ext1 .ext2 .baz, +.ext3 .bar, +.ext3 .baz, +.foo .ext3, +.ext4 .bar, +.ext4 .baz, +.foo .ext4 { + display: none; +} +div.ext5, +.ext6 > .ext5, +div.ext7, +.ext6 > .ext7 { + width: 100px; +} +.ext8.ext9, +.fuu { + result: add-foo; +} +.ext8 .ext9, +.ext8 + .ext9, +.ext8 > .ext9, +.buu, +.zap, +.zoo { + result: bar-matched; +} +.ext8.nomatch { + result: none; +} +.ext8 .ext9, +.buu { + result: match-nested-bar; +} +.ext8.ext9, +.fuu { + result: match-nested-foo; +} +.aa, +.cc { + color: black; +} +.aa .dd, +.aa .ee { + background: red; +} +.bb, +.cc, +.ee, +.ff { + background: red; +} +.bb .bb, +.ff .ff { + color: black; +} diff --git a/test/css/extract-and-length.css b/test/css/extract-and-length.css new file mode 100644 index 00000000..f550e201 --- /dev/null +++ b/test/css/extract-and-length.css @@ -0,0 +1,133 @@ +.multiunit { + length: 6; + extract: abc "abc" 1 1px 1% #112233; +} +.incorrect-index { + v1: extract(a b c, 5); + v2: extract(a, b, c, -2); +} +.scalar { + var-value: variable; + var-length: 1; + ill-index: extract(variable, 2); + name-value: name; + string-value: "string"; + number-value: 12345678; + color-value: #0000ff; + rgba-value: rgba(80, 160, 240, 0.67); + empty-value: ; + name-length: 1; + string-length: 1; + number-length: 1; + color-length: 1; + rgba-length: 1; + empty-length: 1; +} +.mixin-arguments-1 { + length: 4; + extract: c | b | a; +} +.mixin-arguments-2 { + length: 4; + extract: c | b | a; +} +.mixin-arguments-3 { + length: 4; + extract: c | b | a; +} +.mixin-arguments-4 { + length: 0; + extract: extract(, 2) | extract(, 1); +} +.mixin-arguments-2 { + length: 4; + extract: c | b | a; +} +.mixin-arguments-3 { + length: 4; + extract: c | b | a; +} +.mixin-arguments-4 { + length: 3; + extract: c | b; +} +.mixin-arguments-2 { + length: 4; + extract: 3 | 2 | 1; +} +.mixin-arguments-3 { + length: 4; + extract: 3 | 2 | 1; +} +.mixin-arguments-4 { + length: 3; + extract: 3 | 2; +} +.md-space-comma { + length-1: 3; + extract-1: 1 2 3; + length-2: 3; + extract-2: 2; +} +.md-space-comma-as-args-2 { + length: 3; + extract: "x" "y" "z" | 1 2 3 | a b c; +} +.md-space-comma-as-args-3 { + length: 3; + extract: "x" "y" "z" | 1 2 3 | a b c; +} +.md-space-comma-as-args-4 { + length: 2; + extract: "x" "y" "z" | 1 2 3; +} +.md-cat-space-comma { + length-1: 3; + extract-1: 1 2 3; + length-2: 3; + extract-2: 2; +} +.md-cat-space-comma-as-args-2 { + length: 3; + extract: "x" "y" "z" | 1 2 3 | a b c; +} +.md-cat-space-comma-as-args-3 { + length: 3; + extract: "x" "y" "z" | 1 2 3 | a b c; +} +.md-cat-space-comma-as-args-4 { + length: 2; + extract: "x" "y" "z" | 1 2 3; +} +.md-cat-comma-space { + length-1: 3; + extract-1: 1, 2, 3; + length-2: 3; + extract-2: 2; +} +.md-cat-comma-space-as-args-1 { + length: 3; + extract: "x", "y", "z" | 1, 2, 3 | a, b, c; +} +.md-cat-comma-space-as-args-2 { + length: 3; + extract: "x", "y", "z" | 1, 2, 3 | a, b, c; +} +.md-cat-comma-space-as-args-3 { + length: 3; + extract: "x", "y", "z" | 1, 2, 3 | a, b, c; +} +.md-cat-comma-space-as-args-4 { + length: 0; + extract: extract(, 2) | extract(, 1); +} +.md-3D { + length-1: 2; + extract-1: a b c d, 1 2 3 4; + length-2: 2; + extract-2: 5 6 7 8; + length-3: 4; + extract-3: 7; + length-4: 1; + extract-4: 8; +} diff --git a/test/css/functions.css b/test/css/functions.css new file mode 100644 index 00000000..e39f7ecf --- /dev/null +++ b/test/css/functions.css @@ -0,0 +1,158 @@ +#functions { + color: #660000; + width: 16; + height: undefined("self"); + border-width: 5; + variable: 11; + background: linear-gradient(#000000, #ffffff); +} +#built-in { + escaped: -Some::weird(#thing, y); + lighten: #ffcccc; + darken: #330000; + saturate: #203c31; + desaturate: #29332f; + greyscale: #2e2e2e; + hsl-clamp: #ffffff; + spin-p: #bf6a40; + spin-n: #bf4055; + luma-white: 100%; + luma-black: 0%; + luma-black-alpha: 0%; + luma-red: 21.26%; + luma-green: 71.52%; + luma-blue: 7.22%; + luma-yellow: 92.78%; + luma-cyan: 78.74%; + luma-differs-from-luminance: 23.89833349%; + luminance-white: 100%; + luminance-black: 0%; + luminance-black-alpha: 0%; + luminance-red: 21.26%; + luminance-differs-from-luma: 36.40541176%; + contrast-filter: contrast(30%); + saturate-filter: saturate(5%); + contrast-white: #000000; + contrast-black: #ffffff; + contrast-red: #ffffff; + contrast-green: #000000; + contrast-blue: #ffffff; + contrast-yellow: #000000; + contrast-cyan: #000000; + contrast-light: #111111; + contrast-dark: #eeeeee; + contrast-wrongorder: #111111; + contrast-light-thresh: #111111; + contrast-dark-thresh: #eeeeee; + contrast-high-thresh: #eeeeee; + contrast-low-thresh: #111111; + contrast-light-thresh-per: #111111; + contrast-dark-thresh-per: #eeeeee; + contrast-high-thresh-per: #eeeeee; + contrast-low-thresh-per: #111111; + replace: "Hello, World!"; + replace-captured: "This is a new string."; + replace-with-flags: "2 + 2 = 4"; + replace-single-quoted: 'foo-2'; + replace-escaped-string: bar-2; + replace-keyword: baz-2; + format: "rgb(32, 128, 64)"; + format-string: "hello world"; + format-multiple: "hello earth 2"; + format-url-encode: "red is %23ff0000"; + format-single-quoted: 'hello single world'; + format-escaped-string: hello escaped world; + eformat: rgb(32, 128, 64); + unitless: 12; + unit: 14em; + unitpercentage: 100%; + get-unit: px; + get-unit-empty: ; + hue: 98; + saturation: 12%; + lightness: 95%; + hsvhue: 98; + hsvsaturation: 12%; + hsvvalue: 95%; + red: 255; + green: 255; + blue: 255; + rounded: 11; + rounded-two: 10.67; + roundedpx: 3px; + roundedpx-three: 3.333px; + rounded-percentage: 10%; + ceil: 11px; + floor: 12px; + sqrt: 5px; + pi: 3.14159265; + mod: 2m; + abs: 4%; + tan: 0.90040404; + sin: 0.17364818; + cos: 0.84385396; + atan: 0.1rad; + atan: 34deg; + atan: 45deg; + pow: 64px; + pow: 64; + pow: 27; + min: 0; + min: 5; + min: 1pt; + min: 3mm; + max: 3; + max: 5em; + percentage: 20%; + color: #ff0011; + tint: #898989; + tint-full: #ffffff; + tint-percent: #898989; + tint-negative: #656565; + shade: #686868; + shade-full: #000000; + shade-percent: #686868; + shade-negative: #868686; + fade-out: rgba(255, 0, 0, 0.95); + fade-in: rgba(255, 0, 0, 0.95); + hsv: #4d2926; + hsva: rgba(77, 40, 38, 0.2); + mix: #ff3300; + mix-0: #ffff00; + mix-100: #ff0000; + mix-weightless: #ff8000; + mixt: rgba(255, 0, 0, 0.5); +} +#built-in .is-a { + color: true; + color1: true; + color2: true; + color3: true; + keyword: true; + number: true; + string: true; + pixel: true; + percent: true; + em: true; + cat: true; +} +#alpha { + alpha: rgba(153, 94, 51, 0.6); + alpha2: 0.5; + alpha3: 0; +} +#blendmodes { + multiply: #ed0000; + screen: #f600f6; + overlay: #ed0000; + softlight: #fa0000; + hardlight: #0000ed; + difference: #f600f6; + exclusion: #f600f6; + average: #7b007b; + negation: #d73131; +} +#extract-and-length { + extract: 3 2 1 C B A; + length: 6; +} diff --git a/test/css/globalVars/extended.css b/test/css/globalVars/extended.css new file mode 100644 index 00000000..1149ac87 --- /dev/null +++ b/test/css/globalVars/extended.css @@ -0,0 +1,12 @@ +/** + * Test + */ +#header { + color: #333333; + border-left: 1px; + border-right: 2px; +} +#footer { + color: #114411; + border-color: #f20d0d; +} diff --git a/test/css/globalVars/simple.css b/test/css/globalVars/simple.css new file mode 100644 index 00000000..55779d8b --- /dev/null +++ b/test/css/globalVars/simple.css @@ -0,0 +1,6 @@ +/** + * Test + */ +.class { + color: #ff0000; +} diff --git a/test/css/ie-filters.css b/test/css/ie-filters.css new file mode 100644 index 00000000..007aa536 --- /dev/null +++ b/test/css/ie-filters.css @@ -0,0 +1,9 @@ +.nav { + filter: progid:DXImageTransform.Microsoft.Alpha(opacity=20); + filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#333333", endColorstr="#000000", GradientType=0); +} +.evalTest1 { + filter: progid:DXImageTransform.Microsoft.Alpha(opacity=30); + filter: progid:DXImageTransform.Microsoft.Alpha(opacity=5); +} diff --git a/test/css/import-inline.css b/test/css/import-inline.css new file mode 100644 index 00000000..f198d3c1 --- /dev/null +++ b/test/css/import-inline.css @@ -0,0 +1,5 @@ +this isn't very valid CSS. +@media (min-width: 600px) { + #css { color: yellow; } + +} diff --git a/test/css/import-interpolation.css b/test/css/import-interpolation.css new file mode 100644 index 00000000..16b7a150 --- /dev/null +++ b/test/css/import-interpolation.css @@ -0,0 +1,6 @@ +body { + width: 100%; +} +.a { + var: test; +} diff --git a/test/css/import-once.css b/test/css/import-once.css new file mode 100644 index 00000000..2f86b3b3 --- /dev/null +++ b/test/css/import-once.css @@ -0,0 +1,15 @@ +#import { + color: #ff0000; +} +body { + width: 100%; +} +.test-f { + height: 10px; +} +body { + width: 100%; +} +.test-f { + height: 10px; +} diff --git a/test/css/import-reference.css b/test/css/import-reference.css new file mode 100644 index 00000000..f25f4b1d --- /dev/null +++ b/test/css/import-reference.css @@ -0,0 +1,68 @@ +input[type="text"].class#id[attr=32]:not(1) { + color: white; +} +div#id.class[a=1][b=2].class:not(1) { + color: white; +} +@media print { + .class { + color: blue; + } + .class .sub { + width: 42; + } +} +.visible { + color: red; +} +.visible .c { + color: green; +} +.visible { + color: green; +} +.visible:hover { + color: green; +} +.only-with-visible + .visible, +.visible + .only-with-visible, +.visible + .visible { + color: green; +} +.only-with-visible + .visible .sub, +.visible + .only-with-visible .sub, +.visible + .visible .sub { + color: green; +} +.b { + color: red; + color: green; +} +.b .c { + color: green; +} +.b:hover { + color: green; +} +.b + .b { + color: green; +} +.b + .b .sub { + color: green; +} +.y { + pulled-in: yes; +} +/* comment pulled in */ +.visible { + extend: test; +} +.test-mediaq-import { + color: green; + test: 340px; +} +@media (max-size: 450px) { + .test-mediaq-import { + color: red; + } +} diff --git a/test/css/import.css b/test/css/import.css new file mode 100644 index 00000000..a3749181 --- /dev/null +++ b/test/css/import.css @@ -0,0 +1,36 @@ +@import url(http://fonts.googleapis.com/css?family=Open+Sans); +@import url(/absolute/something.css) screen and (color) and (max-width: 600px); +@import url("//ha.com/file.css") (min-width: 100px); +#import-test { + height: 10px; + color: #ff0000; + width: 10px; + height: 30%; +} +@media screen and (max-width: 600px) { + body { + width: 100%; + } +} +#import { + color: #ff0000; +} +.mixin { + height: 10px; + color: #ff0000; +} +@media screen and (max-width: 601px) { + #css { + color: yellow; + } +} +@media screen and (max-width: 602px) { + body { + width: 100%; + } +} +@media screen and (max-width: 603px) { + #css { + color: yellow; + } +} diff --git a/test/css/javascript.css b/test/css/javascript.css new file mode 100644 index 00000000..9cc1c3e9 --- /dev/null +++ b/test/css/javascript.css @@ -0,0 +1,28 @@ +.eval { + js: 42; + js: 2; + js: "hello world"; + js: 1, 2, 3; + title: "string"; + ternary: true; + multiline: 2; +} +.scope { + var: 42; + escaped: 7px; +} +.vars { + width: 8; +} +.escape-interpol { + width: hello world; +} +.arrays { + ary: "1, 2, 3"; + ary1: "1, 2, 3"; +} +.test-tran { + 1: opacity 0.3s ease-in 0.3s, max-height 0.6s linear, margin-bottom 0.4s linear; + 2: [opacity 0.3s ease-in 0.3s, max-height 0.6s linear, margin-bottom 0.4s linear]; + 3: opacity 0.3s ease-in 0.3s, max-height 0.6s linear, margin-bottom 0.4s linear; +} diff --git a/test/css/lazy-eval.css b/test/css/lazy-eval.css new file mode 100644 index 00000000..1adfb8f3 --- /dev/null +++ b/test/css/lazy-eval.css @@ -0,0 +1,3 @@ +.lazy-eval { + width: 100%; +} diff --git a/test/css/legacy/legacy.css b/test/css/legacy/legacy.css new file mode 100644 index 00000000..2f9bb80b --- /dev/null +++ b/test/css/legacy/legacy.css @@ -0,0 +1,7 @@ +@media (-o-min-device-pixel-ratio: 2/1) { + .test-math-and-units { + font: ignores 0/0 rules; + test-division: 7em; + simple: 2px; + } +} diff --git a/test/css/media.css b/test/css/media.css new file mode 100644 index 00000000..607f0e44 --- /dev/null +++ b/test/css/media.css @@ -0,0 +1,219 @@ +@media print { + .class { + color: blue; + } + .class .sub { + width: 42; + } + .top, + header > h1 { + color: #444444; + } +} +@media screen { + body { + max-width: 480; + } +} +@media all and (device-aspect-ratio: 16 / 9) { + body { + max-width: 800px; + } +} +@media all and (orientation: portrait) { + aside { + float: none; + } +} +@media handheld and (min-width: 42), screen and (min-width: 20em) { + body { + max-width: 480px; + } +} +@media print { + body { + padding: 20px; + } + body header { + background-color: red; + } +} +@media print and (orientation: landscape) { + body { + margin-left: 20px; + } +} +@media screen { + .sidebar { + width: 300px; + } +} +@media screen and (orientation: landscape) { + .sidebar { + width: 500px; + } +} +@media a and b { + .first .second .third { + width: 300px; + } + .first .second .fourth { + width: 3; + } +} +@media a and b and c { + .first .second .third { + width: 500px; + } +} +@media a, b and c { + body { + width: 95%; + } +} +@media a and x, b and c and x, a and y, b and c and y { + body { + width: 100%; + } +} +.a { + background: black; +} +@media handheld { + .a { + background: white; + } +} +@media handheld and (max-width: 100px) { + .a { + background: red; + } +} +.b { + background: black; +} +@media handheld { + .b { + background: white; + } +} +@media handheld and (max-width: 200px) { + .b { + background: red; + } +} +@media only screen and (max-width: 200px) { + body { + width: 480px; + } +} +@media print { + @page :left { + margin: 0.5cm; + } + @page :right { + margin: 0.5cm; + } + @page Test:first { + margin: 1cm; + } + @page :first { + size: 8.5in 11in; + + @top-left { + margin: 1cm; + } + @top-left-corner { + margin: 1cm; + } + @top-center { + margin: 1cm; + } + @top-right { + margin: 1cm; + } + @top-right-corner { + margin: 1cm; + } + @bottom-left { + margin: 1cm; + } + @bottom-left-corner { + margin: 1cm; + } + @bottom-center { + margin: 1cm; + } + @bottom-right { + margin: 1cm; + } + @bottom-right-corner { + margin: 1cm; + } + @left-top { + margin: 1cm; + } + @left-middle { + margin: 1cm; + } + @left-bottom { + margin: 1cm; + } + @right-top { + margin: 1cm; + } + @right-middle { + content: "Page " counter(page); + } + @right-bottom { + margin: 1cm; + } + } +} +@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2/1), (min-resolution: 2dppx), (min-resolution: 128dpcm) { + .b { + background: red; + } +} +body { + background: red; +} +@media (max-width: 500px) { + body { + background: green; + } +} +@media (max-width: 1000px) { + body { + background: red; + background: blue; + } +} +@media (max-width: 1000px) and (max-width: 500px) { + body { + background: green; + } +} +@media (max-width: 1200px) { + /* a comment */ +} +@media (max-width: 1200px) and (max-width: 900px) { + body { + font-size: 11px; + } +} +@media (min-width: 480px) { + .nav-justified > li { + display: table-cell; + } +} +@media (min-width: 768px) and (min-width: 480px) { + .menu > li { + display: table-cell; + } +} +@media all and tv { + .all-and-tv-variables { + var: all-and-tv; + } +} diff --git a/test/css/merge.css b/test/css/merge.css new file mode 100644 index 00000000..fe29dc83 --- /dev/null +++ b/test/css/merge.css @@ -0,0 +1,34 @@ +.test1 { + transform: rotate(90deg), skew(30deg), scale(2, 4); +} +.test2 { + transform: rotate(90deg), skew(30deg); + transform: scaleX(45deg); +} +.test3 { + transform: scaleX(45deg); + background: url(data://img1.png); +} +.test4 { + transform: rotate(90deg), skew(30deg); + transform: scale(2, 4) !important; +} +.test5 { + transform: rotate(90deg), skew(30deg); + transform: scale(2, 4) !important; +} +.test6 { + transform: scale(2, 4); +} +.test-interleaved { + transform: t1, t2, t3; + background: b1, b2, b3; +} +.test-spaced { + transform: t1 t2 t3; + background: b1 b2, b3; +} +.test-interleaved-with-spaced { + transform: t1s, t2 t3s, t4 t5s t6s; + background: b1 b2s, b3, b4; +} diff --git a/test/css/mixins-args.css b/test/css/mixins-args.css new file mode 100644 index 00000000..2b6c5c96 --- /dev/null +++ b/test/css/mixins-args.css @@ -0,0 +1,113 @@ +#hidden { + color: transparent; +} +#hidden1 { + color: transparent; +} +.two-args { + color: blue; + width: 10px; + height: 99%; + border: 2px dotted #000000; +} +.one-arg { + width: 15px; + height: 49%; +} +.no-parens { + width: 5px; + height: 49%; +} +.no-args { + width: 5px; + height: 49%; +} +.var-args { + width: 45; + height: 17%; +} +.multi-mix { + width: 10px; + height: 29%; + margin: 4; + padding: 5; +} +body { + padding: 30px; + color: #ff0000; +} +.scope-mix { + width: 8; +} +.content { + width: 600px; +} +.content .column { + margin: 600px; +} +#same-var-name { + radius: 5px; +} +#var-inside { + width: 10px; +} +.arguments { + border: 1px solid #000000; + width: 1px; +} +.arguments2 { + border: 0px; + width: 0px; +} +.arguments3 { + border: 0px; + width: 0px; +} +.arguments4 { + border: 0 1 2 3 4; + rest: 1 2 3 4; + width: 0; +} +.edge-case { + border: "{"; + width: "{"; +} +.slash-vs-math { + border-radius: 2px/5px; + border-radius: 5px/10px; + border-radius: 6px; +} +.comma-vs-semi-colon { + one: a; + two: b, c; + one: d, e; + two: f; + one: g; + one: h; + one: i; + one: j; + one: k; + two: l; + one: m, n; + one: o, p; + two: q; + one: r, s; + two: t; +} +#named-conflict { + four: a, 11, 12, 13; + four: a, 21, 22, 23; +} +.test-mixin-default-arg { + defaults: 1px 1px 1px; + defaults: 2px 2px 2px; +} +.selector { + margin: 2, 2, 2, 2; +} +.selector2 { + margin: 2, 2, 2, 2; +} +.selector3 { + margin: 4; +} diff --git a/test/css/mixins-closure.css b/test/css/mixins-closure.css new file mode 100644 index 00000000..b1021b6f --- /dev/null +++ b/test/css/mixins-closure.css @@ -0,0 +1,9 @@ +.class { + width: 99px; +} +.overwrite { + width: 99px; +} +.nested .class { + width: 5px; +} diff --git a/test/css/mixins-guards-default-func.css b/test/css/mixins-guards-default-func.css new file mode 100644 index 00000000..e47f05cf --- /dev/null +++ b/test/css/mixins-guards-default-func.css @@ -0,0 +1,129 @@ +guard-default-basic-1-1 { + case: 1; +} +guard-default-basic-1-2 { + default: 2; +} +guard-default-basic-2-0 { + default: 0; +} +guard-default-basic-2-2 { + case: 2; +} +guard-default-basic-3-0 { + default: 0; +} +guard-default-basic-3-2 { + case: 2; +} +guard-default-basic-3-3 { + case: 3; +} +guard-default-definition-order-0 { + default: 0; +} +guard-default-definition-order-2 { + case: 2; +} +guard-default-definition-order-2 { + case: 3; +} +guard-default-out-of-guard-0 { + case-0: default(); + case-1: 1; + default: 2; + case-2: default(); +} +guard-default-out-of-guard-1 { + default: default(); +} +guard-default-out-of-guard-2 { + default: default(); +} +guard-default-expr-not-1 { + case: 1; + default: 1; +} +guard-default-expr-eq-true { + case: true; +} +guard-default-expr-eq-false { + case: false; + default: false; +} +guard-default-expr-or-1 { + case: 1; +} +guard-default-expr-or-2 { + case: 2; + default: 2; +} +guard-default-expr-or-3 { + default: 3; +} +guard-default-expr-and-1 { + case: 1; +} +guard-default-expr-and-2 { + case: 2; +} +guard-default-expr-and-3 { + default: 3; +} +guard-default-expr-always-1 { + case: 1; + default: 1; +} +guard-default-expr-always-2 { + default: 2; +} +guard-default-expr-never-1 { + case: 1; +} +guard-default-multi-1-0 { + case: 0; +} +guard-default-multi-1-1 { + default-1: 1; +} +guard-default-multi-2-1 { + default-1: no; +} +guard-default-multi-2-2 { + default-2: no; +} +guard-default-multi-2-3 { + default-3: 3; +} +guard-default-multi-3-blue { + case-2: #00008b; +} +guard-default-multi-3-green { + default-color: #008000; +} +guard-default-multi-3-foo { + case-1: I am 'foo'; +} +guard-default-multi-3-baz { + default-string: I am 'baz'; +} +guard-default-multi-4 { + always: 1; + always: 2; + case: 2; +} +guard-default-not-ambiguos-2 { + case: 1; + not-default: 2; +} +guard-default-not-ambiguos-3 { + case: 1; + not-default-1: 2; + not-default-2: 2; +} +guard-default-scopes-3 { + 3: when default; +} +guard-default-scopes-1 { + 1: no condition; +} diff --git a/test/css/mixins-guards.css b/test/css/mixins-guards.css new file mode 100644 index 00000000..59b6f932 --- /dev/null +++ b/test/css/mixins-guards.css @@ -0,0 +1,93 @@ +.light1 { + color: white; + margin: 1px; +} +.light2 { + color: black; + margin: 1px; +} +.max1 { + width: 6; +} +.max2 { + width: 8; +} +.glob1 { + margin: auto auto; +} +.ops1 { + height: gt-or-eq; + height: lt-or-eq; + height: lt-or-eq-alias; +} +.ops2 { + height: gt-or-eq; + height: not-eq; +} +.ops3 { + height: lt-or-eq; + height: lt-or-eq-alias; + height: not-eq; +} +.default1 { + content: default; +} +.test1 { + content: "true."; +} +.test2 { + content: "false."; +} +.test3 { + content: "false."; +} +.test4 { + content: "false."; +} +.test5 { + content: "false."; +} +.bool1 { + content: true and true; + content: true; + content: false, true; + content: false and true and true, true; + content: false, true and true; + content: false, false, true; + content: false, true and true and true, false; + content: not false; + content: not false and false, not false; +} +.equality-units { + test: pass; +} +.colorguardtest { + content: is #ff0000; + content: is not #0000ff its #ff0000; + content: is not #0000ff its #800080; +} +.stringguardtest { + content: "theme1" is "theme1"; + content: "theme1" is not "theme2"; + content: "theme1" is 'theme1'; + content: "theme1" is not 'theme2'; + content: 'theme1' is "theme1"; + content: 'theme1' is not "theme2"; + content: 'theme1' is 'theme1'; + content: 'theme1' is not 'theme2'; + content: theme1 is not "theme2"; + content: theme1 is not 'theme2'; + content: theme1 is theme1; +} +#tryNumberPx { + catch: all; + declare: 4; + declare: 4px; +} +.call-lock-mixin .call-inner-lock-mixin { + a: 1; + x: 1; +} +.mixin-generated-class { + a: 1; +} diff --git a/test/css/mixins-important.css b/test/css/mixins-important.css new file mode 100644 index 00000000..b100af7f --- /dev/null +++ b/test/css/mixins-important.css @@ -0,0 +1,45 @@ +.class { + border: 1; + boxer: 1; + border-width: 1; + border: 2 !important; + boxer: 2 !important; + border-width: 2 !important; + border: 3; + boxer: 3; + border-width: 3; + border: 4 !important; + boxer: 4 !important; + border-width: 4 !important; + border: 5; + boxer: 5; + border-width: 5; + border: 0 !important; + boxer: 0 !important; + border-width: 0 !important; + border: 9 !important; + border: 9; + boxer: 9; + border-width: 9; +} +.class .inner { + test: 1; +} +.class .inner { + test: 2 !important; +} +.class .inner { + test: 3; +} +.class .inner { + test: 4 !important; +} +.class .inner { + test: 5; +} +.class .inner { + test: 0 !important; +} +.class .inner { + test: 9; +} diff --git a/test/css/mixins-interpolated.css b/test/css/mixins-interpolated.css new file mode 100644 index 00000000..637b5b68 --- /dev/null +++ b/test/css/mixins-interpolated.css @@ -0,0 +1,39 @@ +.foo { + a: 1; +} +.foo { + a: 2; +} +#foo { + a: 3; +} +#foo { + a: 4; +} +mi-test-a { + a: 1; + a: 2; + a: 3; + a: 4; +} +.b .bb.foo-xxx .yyy-foo#foo .foo.bbb { + b: 1; +} +mi-test-b { + b: 1; +} +#foo-foo > .bar .baz { + c: c; +} +mi-test-c-1 > .bar .baz { + c: c; +} +mi-test-c-2 .baz { + c: c; +} +mi-test-c-3 { + c: c; +} +mi-test-d { + gender: "Male"; +} diff --git a/test/css/mixins-named-args.css b/test/css/mixins-named-args.css new file mode 100644 index 00000000..e460aa10 --- /dev/null +++ b/test/css/mixins-named-args.css @@ -0,0 +1,27 @@ +.named-arg { + color: blue; + width: 5px; + height: 99%; + args: 1px 100%; + text-align: center; +} +.class { + width: 5px; + height: 19%; + args: 1px 20%; +} +.all-args-wrong-args { + width: 10px; + height: 9%; + args: 2px 10%; +} +.named-args2 { + width: 15px; + height: 49%; + color: #646464; +} +.named-args3 { + width: 5px; + height: 29%; + color: #123456; +} diff --git a/test/css/mixins-nested.css b/test/css/mixins-nested.css new file mode 100644 index 00000000..6378c475 --- /dev/null +++ b/test/css/mixins-nested.css @@ -0,0 +1,14 @@ +.class .inner { + height: 300; +} +.class .inner .innest { + width: 30; + border-width: 60; +} +.class2 .inner { + height: 600; +} +.class2 .inner .innest { + width: 60; + border-width: 120; +} diff --git a/test/css/mixins-pattern.css b/test/css/mixins-pattern.css new file mode 100644 index 00000000..1515f32a --- /dev/null +++ b/test/css/mixins-pattern.css @@ -0,0 +1,51 @@ +.zero { + variadic: true; + named-variadic: true; + zero: 0; + one: 1; + two: 2; + three: 3; +} +.one { + variadic: true; + named-variadic: true; + one: 1; + one-req: 1; + two: 2; + three: 3; +} +.two { + variadic: true; + named-variadic: true; + two: 2; + three: 3; +} +.three { + variadic: true; + named-variadic: true; + three-req: 3; + three: 3; +} +.left { + left: 1; +} +.right { + right: 1; +} +.border-right { + color: black; + border-right: 4px; +} +.border-left { + color: black; + border-left: 4px; +} +.only-right { + right: 33; +} +.only-left { + left: 33; +} +.left-right { + both: 330; +} diff --git a/test/css/mixins.css b/test/css/mixins.css new file mode 100644 index 00000000..32097f97 --- /dev/null +++ b/test/css/mixins.css @@ -0,0 +1,141 @@ +.mixin { + border: 1px solid black; +} +.mixout { + border-color: orange; +} +.borders { + border-style: dashed; +} +#namespace .borders { + border-style: dotted; +} +#namespace .biohazard { + content: "death"; +} +#namespace .biohazard .man { + color: transparent; +} +#theme > .mixin { + background-color: grey; +} +#container { + color: black; + border: 1px solid black; + border-color: orange; + background-color: grey; +} +#header .milk { + color: white; + border: 1px solid black; + background-color: grey; +} +#header #cookie { + border-style: dashed; +} +#header #cookie .chips { + border-style: dotted; +} +#header #cookie .chips .calories { + color: black; + border: 1px solid black; + border-color: orange; + background-color: grey; +} +.secure-zone { + color: transparent; +} +.direct { + border-style: dotted; +} +.bo, +.bar { + width: 100%; +} +.bo { + border: 1px; +} +.ar.bo.ca { + color: black; +} +.jo.ki { + background: none; +} +.amp.support { + color: orange; +} +.amp.support .higher { + top: 0px; +} +.amp.support.deeper { + height: auto; +} +.extended { + width: 100%; + border: 1px; + background: none; + color: orange; + top: 0px; + height: auto; +} +.extended .higher { + top: 0px; +} +.extended.deeper { + height: auto; +} +.do .re .mi .fa .sol .la .si { + color: cyan; +} +.mutli-selector-parents { + color: cyan; +} +.foo .bar { + width: 100%; +} +.underParents { + color: red; +} +.parent .underParents { + color: red; +} +* + h1 { + margin-top: 25px; +} +legend + h1 { + margin-top: 0; +} +h1 + * { + margin-top: 10px; +} +* + h2 { + margin-top: 20px; +} +legend + h2 { + margin-top: 0; +} +h2 + * { + margin-top: 8px; +} +* + h3 { + margin-top: 15px; +} +legend + h3 { + margin-top: 0; +} +h3 + * { + margin-top: 5px; +} +.error { + background-image: "/a.png"; + background-position: center center; +} +.test-rec .recursion { + color: black; +} +.button { + padding-left: 44px; +} +.button.large { + padding-left: 40em; +} diff --git a/test/css/modifyVars/extended.css b/test/css/modifyVars/extended.css new file mode 100644 index 00000000..32edb38f --- /dev/null +++ b/test/css/modifyVars/extended.css @@ -0,0 +1,9 @@ +#header { + color: #333333; + border-left: 1px; + border-right: 2px; +} +#footer { + color: #114411; + border-color: #842210; +} diff --git a/test/css/no-output.css b/test/css/no-output.css new file mode 100644 index 00000000..e69de29b diff --git a/test/css/operations.css b/test/css/operations.css new file mode 100644 index 00000000..fb9e0aff --- /dev/null +++ b/test/css/operations.css @@ -0,0 +1,49 @@ +#operations { + color: #111111; + height: 9px; + width: 3em; + substraction: 0; + division: 1; +} +#operations .spacing { + height: 9px; + width: 3em; +} +.with-variables { + height: 16em; + width: 24em; + size: 1cm; +} +.with-functions { + color: #646464; + color: #ff8080; + color: #c94a4a; +} +.negative { + height: 0px; + width: 4px; +} +.shorthands { + padding: -1px 2px 0 -4px; +} +.rem-dimensions { + font-size: 5.5rem; +} +.colors { + color: #123; + border-color: #334455; + background-color: #000000; +} +.colors .other { + color: #222222; + border-color: #222222; +} +.negations { + variable: -4px; + variable1: 0px; + variable2: 0px; + variable3: 8px; + variable4: 0px; + paren: -4px; + paren2: 16px; +} diff --git a/test/css/parens.css b/test/css/parens.css new file mode 100644 index 00000000..dc09fdf5 --- /dev/null +++ b/test/css/parens.css @@ -0,0 +1,36 @@ +.parens { + border: 2px solid #000000; + margin: 1px 3px 16 3; + width: 36; + padding: 2px 36px; +} +.more-parens { + padding: 8 4 4 4px; + width-all: 96; + width-first: 16 * 6; + width-keep: (4 * 4) * 6; + height-keep: (7 * 7) + (8 * 8); + height-all: 113; + height-parts: 49 + 64; + margin-keep: (4 * (5 + 5) / 2) - (4 * 2); + margin-parts: 20 - 8; + margin-all: 12; + border-radius-keep: 4px * (1 + 1) / 4 + 3px; + border-radius-parts: 8px / 7px; + border-radius-all: 5px; +} +.negative { + neg-var: -1; + neg-var-paren: -(1); +} +.nested-parens { + width: 2 * (4 * (2 + (1 + 6))) - 1; + height: ((2 + 3) * (2 + 3) / (9 - 4)) + 1; +} +.mixed-units { + margin: 2px 4em 1 5pc; + padding: 6px 1em 2px 2; +} +.test-false-negatives { + a: (; +} diff --git a/test/css/property-name-interp.css b/test/css/property-name-interp.css new file mode 100644 index 00000000..2082b819 --- /dev/null +++ b/test/css/property-name-interp.css @@ -0,0 +1,20 @@ +pi-test { + border: 0; + ufo-width: 50%; + *-z-border: 1px dashed blue; + -www-border-top: 2px; + radius-is-not-a-border: true; + border-top-left-radius: 2em; + border-top-red-radius-: 3pt; + global-local-mixer-property: strong; +} +pi-test-merge { + pre-property-ish: high, middle, low, base; + pre-property-ish+: nice try dude; +} +pi-indirect-vars { + auto: auto; +} +pi-complex-values { + 3px rgba(255, 255, 0, 0.5), 3.141592653589793 /* foo */3px rgba(255, 255, 0, 0.5), 3.141592653589793 /* foo */: none; +} diff --git a/test/css/rulesets.css b/test/css/rulesets.css new file mode 100644 index 00000000..408c76aa --- /dev/null +++ b/test/css/rulesets.css @@ -0,0 +1,33 @@ +#first > .one { + font-size: 2em; +} +#first > .one > #second .two > #deux { + width: 50%; +} +#first > .one > #second .two > #deux #third { + height: 100%; +} +#first > .one > #second .two > #deux #third:focus { + color: black; +} +#first > .one > #second .two > #deux #third:focus #fifth > #sixth .seventh #eighth + #ninth { + color: purple; +} +#first > .one > #second .two > #deux #fourth, +#first > .one > #second .two > #deux #five, +#first > .one > #second .two > #deux #six { + color: #110000; +} +#first > .one > #second .two > #deux #fourth .seven, +#first > .one > #second .two > #deux #five .seven, +#first > .one > #second .two > #deux #six .seven, +#first > .one > #second .two > #deux #fourth .eight > #nine, +#first > .one > #second .two > #deux #five .eight > #nine, +#first > .one > #second .two > #deux #six .eight > #nine { + border: 1px solid black; +} +#first > .one > #second .two > #deux #fourth #ten, +#first > .one > #second .two > #deux #five #ten, +#first > .one > #second .two > #deux #six #ten { + color: red; +} diff --git a/test/css/scope.css b/test/css/scope.css new file mode 100644 index 00000000..0e4c17d5 --- /dev/null +++ b/test/css/scope.css @@ -0,0 +1,38 @@ +.tiny-scope { + color: #998899; +} +.scope1 { + color: #0000ff; + border-color: #000000; +} +.scope1 .scope2 { + color: #0000ff; +} +.scope1 .scope2 .scope3 { + color: #ff0000; + border-color: #000000; + background-color: #ffffff; +} +.scope { + scoped-val: #008000; +} +.heightIsSet { + height: 1024px; +} +.useHeightInMixinCall { + mixin-height: 1024px; +} +.imported { + exists: true; +} +.testImported { + exists: true; +} +#allAreUsedHere { + default: 'top level'; + scope: 'top level'; + sub-scope-only: 'inside'; +} +#parentSelectorScope { + prop: #ffffff; +} diff --git a/test/css/selectors.css b/test/css/selectors.css new file mode 100644 index 00000000..ec855bec --- /dev/null +++ b/test/css/selectors.css @@ -0,0 +1,153 @@ +h1 a:hover, +h2 a:hover, +h3 a:hover, +h1 p:hover, +h2 p:hover, +h3 p:hover { + color: red; +} +#all { + color: blue; +} +#the { + color: blue; +} +#same { + color: blue; +} +ul, +li, +div, +q, +blockquote, +textarea { + margin: 0; +} +td { + margin: 0; + padding: 0; +} +td, +input { + line-height: 1em; +} +a { + color: red; +} +a:hover { + color: blue; +} +div a { + color: green; +} +p a span { + color: yellow; +} +.foo .bar .qux, +.foo .baz .qux { + display: block; +} +.qux .foo .bar, +.qux .foo .baz { + display: inline; +} +.qux.foo .bar, +.qux.foo .baz { + display: inline-block; +} +.qux .foo .bar .biz, +.qux .foo .baz .biz { + display: none; +} +.a.b.c { + color: red; +} +.c .b.a { + color: red; +} +.foo .p.bar { + color: red; +} +.foo.p.bar { + color: red; +} +.foo + .foo { + background: amber; +} +.foo + .foo { + background: amber; +} +.foo + .foo, +.foo + .bar, +.bar + .foo, +.bar + .bar { + background: amber; +} +.foo a > .foo a, +.foo a > .bar a, +.foo a > .foo b, +.foo a > .bar b, +.bar a > .foo a, +.bar a > .bar a, +.bar a > .foo b, +.bar a > .bar b, +.foo b > .foo a, +.foo b > .bar a, +.foo b > .foo b, +.foo b > .bar b, +.bar b > .foo a, +.bar b > .bar a, +.bar b > .foo b, +.bar b > .bar b { + background: amber; +} +.other ::fnord { + color: #ff0000; +} +.other::fnord { + color: #ff0000; +} +.other ::bnord { + color: #ff0000; +} +.other::bnord { + color: #ff0000; +} +.blood { + color: red; +} +.bloodred { + color: green; +} +#blood.blood.red.black { + color: black; +} +:nth-child(3) { + selector: interpolated; +} +.test:nth-child(odd):not(:nth-child(3)) { + color: #ff0000; +} +[prop], +[prop=10%], +[prop="value3"], +[prop*="val3"], +[|prop~="val3"], +[*|prop$="val3"], +[ns|prop^="val3"], +[3^="val3"], +[3=3], +[3] { + attributes: yes; +} +/* +Large comment means chunk will be emitted after } which means chunk will begin with whitespace... +blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank +blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank +blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank +blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank +blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank +*/ +.blood { + color: red; +} diff --git a/test/css/static-urls/urls.css b/test/css/static-urls/urls.css new file mode 100644 index 00000000..ed174e87 --- /dev/null +++ b/test/css/static-urls/urls.css @@ -0,0 +1,45 @@ +@import "css/background.css"; +@import "folder (1)/import-test-d.css"; +@font-face { + src: url("/fonts/garamond-pro.ttf"); + src: local(Futura-Medium), url(folder\ \(1\)/fonts.svg#MyGeometricModern) format("svg"); +} +#shorthands { + background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; +} +#misc { + background-image: url(folder\ \(1\)/images/image.jpg); +} +#data-uri { + background: url(data:image/png;charset=utf-8;base64, + kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ + k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U + kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); + background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); + background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); +} +#svg-data-uri { + background: transparent url('data:image/svg+xml, '); +} +.comma-delimited { + background: url(folder\ \(1\)/bg.jpg) no-repeat, url(folder\ \(1\)/bg.png) repeat-x top left, url(folder\ \(1\)/bg); +} +.values { + url: url('folder (1)/Trebuchet'); +} +#logo { + width: 100px; + height: 100px; + background: url('assets/logo.png'); +} +@font-face { + font-family: xecret; + src: url('assets/xecret.ttf'); +} +#secret { + font-family: xecret, sans-serif; +} +#imported-relative-path { + background-image: url(../data/image.jpg); + border-image: url('../data/image.jpg'); +} diff --git a/test/css/strings.css b/test/css/strings.css new file mode 100644 index 00000000..cd6d6020 --- /dev/null +++ b/test/css/strings.css @@ -0,0 +1,43 @@ +#strings { + background-image: url("http://son-of-a-banana.com"); + quotes: "~" "~"; + content: "#*%:&^,)!.(~*})"; + empty: ""; + brackets: "{" "}"; + escapes: "\"hello\" \\world"; + escapes2: "\"llo"; +} +#comments { + content: "/* hello */ // not-so-secret"; +} +#single-quote { + quotes: "'" "'"; + content: '""#!&""'; + empty: ''; + semi-colon: ';'; +} +#escaped { + filter: DX.Transform.MS.BS.filter(opacity=50); +} +#one-line { + image: url(http://tooks.com); +} +#crazy { + image: url(http://), "}", url("http://}"); +} +#interpolation { + url: "http://lesscss.org/dev/image.jpg"; + url2: "http://lesscss.org/image-256.jpg"; + url3: "http://lesscss.org#445566"; + url4: "http://lesscss.org/hello"; + url5: "http://lesscss.org/54.4px"; +} +.mix-mul-class { + color: #0000ff; + color: #ff0000; + color: #000000; + color: #ffa500; +} +.watermark { + family: Univers, Arial, Verdana, San-Serif; +} diff --git a/test/css/url-args/urls.css b/test/css/url-args/urls.css new file mode 100644 index 00000000..0b4b13f3 --- /dev/null +++ b/test/css/url-args/urls.css @@ -0,0 +1,56 @@ +@font-face { + src: url("/fonts/garamond-pro.ttf?424242"); + src: local(Futura-Medium), url(fonts.svg?424242#MyGeometricModern) format("svg"); +} +#shorthands { + background: url("http://www.lesscss.org/spec.html?424242") no-repeat 0 4px; + background: url("img.jpg?424242") center / 100px; + background: #ffffff url(image.png?424242) center / 1px 100px repeat-x scroll content-box padding-box; +} +#misc { + background-image: url(images/image.jpg?424242); +} +#data-uri { + background: url(data:image/png;charset=utf-8;base64, + kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ + k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U + kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); + background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); + background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700&424242); + background-image: url("http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700&424242"); +} +#svg-data-uri { + background: transparent url('data:image/svg+xml, '); +} +.comma-delimited { + background: url(bg.jpg?424242) no-repeat, url(bg.png?424242) repeat-x top left, url(bg?424242); +} +.values { + url: url('Trebuchet?424242'); +} +@font-face { + font-family: xecret; + src: url('../assets/xecret.ttf?424242'); +} +#secret { + font-family: xecret, sans-serif; +} +#data-uri { + uri: url("data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg=="); +} +#data-uri-guess { + uri: url("data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg=="); +} +#data-uri-ascii { + uri-1: url("data:text/html,%3Ch1%3EThis%20page%20is%20100%25%20Awesome.%3C%2Fh1%3E%0A"); + uri-2: url("data:text/html,%3Ch1%3EThis%20page%20is%20100%25%20Awesome.%3C%2Fh1%3E%0A"); +} +#svg-functions { + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZGllbnQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIvPjwvbGluZWFyR3JhZGllbnQ+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkaWVudCkiIC8+PC9zdmc+'); + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZGllbnQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIvPjxzdG9wIG9mZnNldD0iMyUiIHN0b3AtY29sb3I9IiNmZmE1MDAiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiLz48L2xpbmVhckdyYWRpZW50PjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZ3JhZGllbnQpIiAvPjwvc3ZnPg=='); + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZGllbnQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIxJSIgc3RvcC1jb2xvcj0iI2M0YzRjNCIvPjxzdG9wIG9mZnNldD0iMyUiIHN0b3AtY29sb3I9IiNmZmE1MDAiLz48c3RvcCBvZmZzZXQ9IjUlIiBzdG9wLWNvbG9yPSIjMDA4MDAwIi8+PHN0b3Agb2Zmc2V0PSI5NSUiIHN0b3AtY29sb3I9IiNmZmZmZmYiLz48L2xpbmVhckdyYWRpZW50PjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZ3JhZGllbnQpIiAvPjwvc3ZnPg=='); +} +#data-uri-with-spaces { + background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); + background-image: url(' data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9=='); +} diff --git a/test/css/urls.css b/test/css/urls.css new file mode 100644 index 00000000..cc7087d0 --- /dev/null +++ b/test/css/urls.css @@ -0,0 +1,71 @@ +@import "css/background.css"; +@import "import/import-test-d.css"; +@import "file.css"; +@font-face { + src: url("/fonts/garamond-pro.ttf"); + src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg"); +} +#shorthands { + background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; + background: url("img.jpg") center / 100px; + background: #ffffff url(image.png) center / 1px 100px repeat-x scroll content-box padding-box; +} +#misc { + background-image: url(images/image.jpg); +} +#data-uri { + background: url(data:image/png;charset=utf-8;base64, + kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ + k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U + kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); + background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); + background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); + background-image: url("http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700"); +} +#svg-data-uri { + background: transparent url('data:image/svg+xml, '); +} +.comma-delimited { + background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); +} +.values { + url: url('Trebuchet'); +} +#logo { + width: 100px; + height: 100px; + background: url('import/assets/logo.png'); +} +@font-face { + font-family: xecret; + src: url('import/assets/xecret.ttf'); +} +#secret { + font-family: xecret, sans-serif; +} +#imported-relative-path { + background-image: url(../data/image.jpg); + border-image: url('../data/image.jpg'); +} +#relative-url-import { + background-image: url(../data/image.jpg); + border-image: url('../data/image.jpg'); +} +#data-uri { + uri: url("data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg=="); +} +#data-uri-guess { + uri: url("data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg=="); +} +#data-uri-ascii { + uri-1: url("data:text/html,%3Ch1%3EThis%20page%20is%20100%25%20Awesome.%3C%2Fh1%3E%0A"); + uri-2: url("data:text/html,%3Ch1%3EThis%20page%20is%20100%25%20Awesome.%3C%2Fh1%3E%0A"); +} +#data-uri-toobig { + uri: url('../data/data-uri-fail.png'); +} +#svg-functions { + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZGllbnQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIvPjwvbGluZWFyR3JhZGllbnQ+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkaWVudCkiIC8+PC9zdmc+'); + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZGllbnQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIvPjxzdG9wIG9mZnNldD0iMyUiIHN0b3AtY29sb3I9IiNmZmE1MDAiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiLz48L2xpbmVhckdyYWRpZW50PjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZ3JhZGllbnQpIiAvPjwvc3ZnPg=='); + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZGllbnQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIxJSIgc3RvcC1jb2xvcj0iI2M0YzRjNCIvPjxzdG9wIG9mZnNldD0iMyUiIHN0b3AtY29sb3I9IiNmZmE1MDAiLz48c3RvcCBvZmZzZXQ9IjUlIiBzdG9wLWNvbG9yPSIjMDA4MDAwIi8+PHN0b3Agb2Zmc2V0PSI5NSUiIHN0b3AtY29sb3I9IiNmZmZmZmYiLz48L2xpbmVhckdyYWRpZW50PjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZ3JhZGllbnQpIiAvPjwvc3ZnPg=='); +} diff --git a/test/css/variables-in-at-rules.css b/test/css/variables-in-at-rules.css new file mode 100644 index 00000000..0327eb18 --- /dev/null +++ b/test/css/variables-in-at-rules.css @@ -0,0 +1,18 @@ +@charset "UTF-8"; +@namespace less "http://lesscss.org"; +@keyframes enlarger { + from { + font-size: 12px; + } + to { + font-size: 15px; + } +} +@-webkit-keyframes reducer { + from { + font-size: 13px; + } + to { + font-size: 10px; + } +} diff --git a/test/css/variables.css b/test/css/variables.css new file mode 100644 index 00000000..f8d8518b --- /dev/null +++ b/test/css/variables.css @@ -0,0 +1,45 @@ +.variables { + width: 14cm; +} +.variables { + height: 24px; + color: #888888; + font-family: "Trebuchet MS", Verdana, sans-serif; + quotes: "~" "~"; +} +.redef { + zero: 0; +} +.redef .inition { + three: 3; +} +.values { + minus-one: -1; + font-family: 'Trebuchet', 'Trebuchet', 'Trebuchet'; + color: #888888 !important; + multi: something 'A', B, C, 'Trebuchet'; +} +.variable-names { + name: 'hello'; +} +.alpha { + filter: alpha(opacity=42); +} +.testPollution { + a: 'no-pollution'; +} +.units { + width: 1px; + same-unit-as-previously: 1px; + square-pixel-divided: 1px; + odd-unit: 2; + percentage: 500%; + pixels: 500px; + conversion-metric-a: 30mm; + conversion-metric-b: 3cm; + conversion-imperial: 3in; + custom-unit: 420octocats; + custom-unit-cancelling: 18dogs; + mix-units: 2px; + invalid-units: 1px; +} diff --git a/test/css/whitespace.css b/test/css/whitespace.css new file mode 100644 index 00000000..74c9b65e --- /dev/null +++ b/test/css/whitespace.css @@ -0,0 +1,42 @@ +.whitespace { + color: white; +} +.whitespace { + color: white; +} +.whitespace { + color: white; +} +.whitespace { + color: white; +} +.whitespace { + color: white ; +} +.white, +.space, +.mania { + color: white; +} +.no-semi-column { + color: #ffffff; +} +.no-semi-column { + color: white; + white-space: pre; +} +.no-semi-column { + border: 2px solid #ffffff; +} +.newlines { + background: the, + great, + wall; + border: 2px + solid + black; +} +.sel .newline_ws .tab_ws { + color: white; + background-position: 45 -23; +} diff --git a/test/data/data-uri-fail.png b/test/data/data-uri-fail.png new file mode 100644 index 00000000..f91b59fb Binary files /dev/null and b/test/data/data-uri-fail.png differ diff --git a/test/data/image.jpg b/test/data/image.jpg new file mode 100644 index 00000000..83f77790 --- /dev/null +++ b/test/data/image.jpg @@ -0,0 +1 @@ +not actually a jpeg file diff --git a/test/data/page.html b/test/data/page.html new file mode 100644 index 00000000..ccdfe565 --- /dev/null +++ b/test/data/page.html @@ -0,0 +1 @@ +

This page is 100% Awesome.

diff --git a/test/index.js b/test/index.js new file mode 100644 index 00000000..33e79637 --- /dev/null +++ b/test/index.js @@ -0,0 +1,45 @@ +var lessTest = require("./less-test"), + lessTester = lessTest(), + path = require("path"), + stylize = require('../lib/less/lessc_helper').stylize; + +function getErrorPathReplacementFunction(dir) { + return function(input) { + return input.replace( + "{path}", path.join(process.cwd(), "/test/less/" + dir + "/")) + .replace("{pathrel}", path.join("test", "less", dir + "/")) + .replace("{pathhref}", "") + .replace("{404status}", "") + .replace(/\r\n/g, '\n'); + }; +} + +console.log("\n" + stylize("Less", 'underline') + "\n"); +lessTester.runTestSet({strictMath: true, relativeUrls: true, silent: true}); +lessTester.runTestSet({strictMath: true, strictUnits: true}, "errors/", + lessTester.testErrors, null, getErrorPathReplacementFunction("errors")); +lessTester.runTestSet({strictMath: true, strictUnits: true, javascriptEnabled: false}, "no-js-errors/", + lessTester.testErrors, null, getErrorPathReplacementFunction("no-js-errors")); +lessTester.runTestSet({strictMath: true, dumpLineNumbers: 'comments'}, "debug/", null, + function(name) { return name + '-comments'; }); +lessTester.runTestSet({strictMath: true, dumpLineNumbers: 'mediaquery'}, "debug/", null, + function(name) { return name + '-mediaquery'; }); +lessTester.runTestSet({strictMath: true, dumpLineNumbers: 'all'}, "debug/", null, + function(name) { return name + '-all'; }); +lessTester.runTestSet({strictMath: true, relativeUrls: false, rootpath: "folder (1)/"}, "static-urls/"); +lessTester.runTestSet({strictMath: true, compress: true}, "compression/"); +lessTester.runTestSet({}, "legacy/"); +lessTester.runTestSet({strictMath: true, strictUnits: true, sourceMap: true, globalVars: true }, "sourcemaps/", + lessTester.testSourcemap, null, null, + function(filename, type) { + if (type === "vars") { + return path.join('test/less/', filename) + '.json'; + } + return path.join('test/sourcemaps', filename) + '.json'; + }); +lessTester.runTestSet({globalVars: true, banner: "/**\n * Test\n */\n"}, "globalVars/", + null, null, null, function(name) { return path.join('test/less/', name) + '.json'; }); +lessTester.runTestSet({modifyVars: true}, "modifyVars/", + null, null, null, function(name) { return path.join('test/less/', name) + '.json'; }); +lessTester.runTestSet({urlArgs: '424242'}, "url-args/"); +lessTester.testNoOptions(); diff --git a/test/less-test.js b/test/less-test.js new file mode 100644 index 00000000..0c1bf4a0 --- /dev/null +++ b/test/less-test.js @@ -0,0 +1,259 @@ +/*jshint latedef: nofunc */ + +module.exports = function() { + var path = require('path'), + fs = require('fs'), + sys = require('util'); + + var less = require('../lib/less'); + var stylize = require('../lib/less/lessc_helper').stylize; + + var globals = Object.keys(global); + + var oneTestOnly = process.argv[2]; + + var isVerbose = process.env.npm_config_loglevel === 'verbose'; + + var totalTests = 0, + failedTests = 0, + passedTests = 0; + + + less.tree.functions.add = function (a, b) { + return new(less.tree.Dimension)(a.value + b.value); + }; + less.tree.functions.increment = function (a) { + return new(less.tree.Dimension)(a.value + 1); + }; + less.tree.functions._color = function (str) { + if (str.value === "evil red") { return new(less.tree.Color)("600"); } + }; + + function testSourcemap(name, err, compiledLess, doReplacements, sourcemap) { + fs.readFile(path.join('test/', name) + '.json', 'utf8', function (e, expectedSourcemap) { + sys.print("- " + name + ": "); + if (sourcemap === expectedSourcemap) { + ok('OK'); + } else if (err) { + fail("ERROR: " + (err && err.message)); + if (isVerbose) { + console.error(); + console.error(err.stack); + } + } else { + difference("FAIL", expectedSourcemap, sourcemap); + } + }); + } + + function testErrors(name, err, compiledLess, doReplacements) { + fs.readFile(path.join('test/less/', name) + '.txt', 'utf8', function (e, expectedErr) { + sys.print("- " + name + ": "); + expectedErr = doReplacements(expectedErr, 'test/less/errors/'); + if (!err) { + if (compiledLess) { + fail("No Error", 'red'); + } else { + fail("No Error, No Output"); + } + } else { + var errMessage = less.formatError(err); + if (errMessage === expectedErr) { + ok('OK'); + } else { + difference("FAIL", expectedErr, errMessage); + } + } + }); + } + + function globalReplacements(input, directory) { + var p = path.join(process.cwd(), directory), + pathimport = path.join(process.cwd(), directory + "import/"), + pathesc = p.replace(/[.:/\\]/g, function(a) { return '\\' + (a=='\\' ? '\/' : a); }), + pathimportesc = pathimport.replace(/[.:/\\]/g, function(a) { return '\\' + (a=='\\' ? '\/' : a); }); + + return input.replace(/\{path\}/g, p) + .replace(/\{pathesc\}/g, pathesc) + .replace(/\{pathimport\}/g, pathimport) + .replace(/\{pathimportesc\}/g, pathimportesc) + .replace(/\r\n/g, '\n'); + } + + function checkGlobalLeaks() { + return Object.keys(global).filter(function(v) { + return globals.indexOf(v) < 0; + }); + } + + function runTestSet(options, foldername, verifyFunction, nameModifier, doReplacements, getFilename) { + foldername = foldername || ""; + + if(!doReplacements) { + doReplacements = globalReplacements; + } + + function getBasename(file) { + return foldername + path.basename(file, '.less'); + } + + fs.readdirSync(path.join('test/less/', foldername)).forEach(function (file) { + if (! /\.less/.test(file)) { return; } + + var name = getBasename(file); + + if (oneTestOnly && name !== oneTestOnly) { + return; + } + + totalTests++; + + if (options.sourceMap) { + var sourceMapOutput; + options.writeSourceMap = function(output) { + sourceMapOutput = output; + }; + options.sourceMapOutputFilename = name + ".css"; + options.sourceMapBasepath = path.join(process.cwd(), "test/less"); + options.sourceMapRootpath = "testweb/"; + } + + options.getVars = function(file) { + return JSON.parse(fs.readFileSync(getFilename(getBasename(file), 'vars'), 'utf8')); + }; + + toCSS(options, path.join('test/less/', foldername + file), function (err, less) { + + if (verifyFunction) { + return verifyFunction(name, err, less, doReplacements, sourceMapOutput); + } + var css_name = name; + if(nameModifier) { css_name = nameModifier(name); } + fs.readFile(path.join('test/css', css_name) + '.css', 'utf8', function (e, css) { + sys.print("- " + css_name + ": "); + + css = css && doReplacements(css, 'test/less/' + foldername); + if (less === css) { ok('OK'); } + else if (err) { + fail("ERROR: " + (err && err.message)); + if (isVerbose) { + console.error(); + console.error(err.stack); + } + } else { + difference("FAIL", css, less); + } + }); + }); + }); + } + + function diff(left, right) { + require('diff').diffLines(left, right).forEach(function(item) { + if(item.added || item.removed) { + var text = item.value.replace("\n", String.fromCharCode(182) + "\n"); + sys.print(stylize(text, item.added ? 'green' : 'red')); + } else { + sys.print(item.value); + } + }); + console.log(""); + } + + function fail(msg) { + console.error(stylize(msg, 'red')); + failedTests++; + endTest(); + } + + function difference(msg, left, right) { + console.warn(stylize(msg, 'yellow')); + failedTests++; + + diff(left, right); + endTest(); + } + + function ok(msg) { + console.log(stylize(msg, 'green')); + passedTests++; + endTest(); + } + + function endTest() { + var leaked = checkGlobalLeaks(); + if (failedTests + passedTests === totalTests) { + console.log(""); + if (failedTests > 0) { + console.error(failedTests + stylize(" Failed", "red") + ", " + passedTests + " passed"); + } else { + console.log(stylize("All Passed ", "green") + passedTests + " run"); + } + if (leaked.length > 0) { + console.log(""); + console.warn(stylize("Global leak detected: ", "red") + leaked.join(', ')); + } + + if (leaked.length || failedTests) { + //process.exit(1); + process.on('exit', function() { process.reallyExit(1) }); + } + } + } + + function toCSS(options, path, callback) { + var css; + options = options || {}; + fs.readFile(path, 'utf8', function (e, str) { + if (e) { return callback(e); } + + options.paths = [require('path').dirname(path)]; + options.filename = require('path').resolve(process.cwd(), path); + options.optimization = options.optimization || 0; + + var parser = new(less.Parser)(options); + var additionalData = {}; + if (options.globalVars) { + additionalData.globalVars = options.getVars(path); + } else if (options.modifyVars) { + additionalData.modifyVars = options.getVars(path); + } + if (options.banner) { + additionalData.banner = options.banner; + } + parser.parse(str, function (err, tree) { + if (err) { + callback(err); + } else { + try { + css = tree.toCSS(options); + var css2 = tree.toCSS(options); // integration test that 2nd call gets same output + if (css2 !== css) { throw new Error("css not equal to 2nd call"); } + callback(null, css); + } catch (e) { + callback(e); + } + } + }, additionalData); + }); + } + + function testNoOptions() { + totalTests++; + try { + sys.print("- Integration - creating parser without options: "); + new(less.Parser)(); + } catch(e) { + fail(stylize("FAIL\n", "red")); + return; + } + ok(stylize("OK\n", "green")); + } + + return { + runTestSet: runTestSet, + testErrors: testErrors, + testSourcemap: testSourcemap, + testNoOptions: testNoOptions + }; +}; diff --git a/test/less/charsets.less b/test/less/charsets.less new file mode 100644 index 00000000..550d40e9 --- /dev/null +++ b/test/less/charsets.less @@ -0,0 +1,3 @@ +@charset "UTF-8"; + +@import "import/import-charset-test"; \ No newline at end of file diff --git a/test/less/colors.less b/test/less/colors.less new file mode 100644 index 00000000..7abda4e5 --- /dev/null +++ b/test/less/colors.less @@ -0,0 +1,98 @@ +#yelow { + #short { + color: #fea; + } + #long { + color: #ffeeaa; + } + #rgba { + color: rgba(255, 238, 170, 0.1); + } + #argb { + color: argb(rgba(255, 238, 170, 0.1)); + } +} + +#blue { + #short { + color: #00f; + } + #long { + color: #0000ff; + } + #rgba { + color: rgba(0, 0, 255, 0.1); + } + #argb { + color: argb(rgba(0, 0, 255, 0.1)); + } +} + +#alpha #hsla { + color: hsla(11, 20%, 20%, 0.6); +} + +#overflow { + .a { color: (#111111 - #444444); } // #000000 + .b { color: (#eee + #fff); } // #ffffff + .c { color: (#aaa * 3); } // #ffffff + .d { color: (#00ee00 + #009900); } // #00ff00 + .e { color: rgba(-99.9, 31.4159, 321, 0.42); } +} + +#grey { + color: rgb(200, 200, 200); +} + +#333333 { + color: rgb(20%, 20%, 20%); +} + +#808080 { + color: hsl(50, 0%, 50%); +} + +#00ff00 { + color: hsl(120, 100%, 50%); +} + +.lightenblue { + color: lighten(blue, 10%); +} + +.darkenblue { + color: darken(blue, 10%); +} + +.unknowncolors { + color: blue2; + border: 2px solid superred; +} + +.transparent { + color: transparent; + background-color: rgba(0, 0, 0, 0); +} +#alpha { + @colorvar: rgba(150, 200, 150, 0.7); + #fromvar { + opacity: alpha(@colorvar); + } + #short { + opacity: alpha(#aaa); + } + #long { + opacity: alpha(#bababa); + } + #rgba { + opacity: alpha(rgba(50, 120, 95, 0.2)); + } + #hsl { + opacity: alpha(hsl(120, 100%, 50%)); + } +} + +#percentage { + color: red(rgb(100%, 0, 0)); + border-color: rgba(100%, 0, 0, 50%); +} diff --git a/test/less/comments.less b/test/less/comments.less new file mode 100644 index 00000000..7859911e --- /dev/null +++ b/test/less/comments.less @@ -0,0 +1,83 @@ +/******************\ +* * +* Comment Header * +* * +\******************/ + +/* + + Comment + +*/ + +/* + * Comment Test + * + * - cloudhead (http://cloudhead.net) + * + */ + +//////////////// +@var: "content"; +//////////////// + +/* Colors + * ------ + * #EDF8FC (background blue) + * #166C89 (darkest blue) + * + * Text: + * #333 (standard text) // A comment within a comment! + * #1F9EC9 (standard link) + * + */ + +/* @group Variables +------------------- */ +#comments /* boo *//* boo again*/, +//.commented_out1 +//.commented_out2 +//.commented_out3 +.comments //end of comments1 +//end of comments2 +{ + /**/ // An empty comment + color: red; /* A C-style comment */ /* A C-style comment */ + background-color: orange; // A little comment + font-size: 12px; + + /* lost comment */ content: @var; + + border: 1px solid black; + + // padding & margin // + padding: 0; // }{ '" + margin: 2em; +} // + +/* commented out + #more-comments { + color: grey; + } +*/ + +.selector /* .with */, .lots, /* of */ .comments { + color: grey, /* blue */ orange; + -webkit-border-radius: 2px /* webkit only */; + -moz-border-radius: (2px * 4) /* moz only with operation */; +} + +.mixin_def_with_colors(@a: white, // in + @b: 1px //put in @b - causes problems! ---> + ) // the + when (@a = white) { + .test { + color: @b; + } +} +.mixin_def_with_colors(); + +#last { color: blue } +// + +/* *//* { *//* *//* *//* */#div { color:#A33; }/* } */ diff --git a/test/less/compression/compression.less b/test/less/compression/compression.less new file mode 100644 index 00000000..c196336a --- /dev/null +++ b/test/less/compression/compression.less @@ -0,0 +1,36 @@ +#colours { + color1: #fea; + color2: #ffeeaa; + color3: rgba(255, 238, 170, 0.1); + @color1: #fea; + string: "@{color1}"; + /* comments are stripped */ + // both types! + /*! but not this type + Note preserved whitespace + */ +} +dimensions { + val: 0.1px; + val: 0em; + val: 4cm; + val: 0.2; + val: 5; + angles-must-have-unit: 0deg; + durations-must-have-unit: 0s; + length-doesnt-have-unit: 0px; + width: auto\9; +} +@page { + marks: none; +@top-left-corner { + vertical-align: top; +} +@top-left { + vertical-align: top; +} +} +.shadow ^ .dom, +body ^^ .shadow { + display: done; +} diff --git a/test/less/css-3.less b/test/less/css-3.less new file mode 100644 index 00000000..c054dc48 --- /dev/null +++ b/test/less/css-3.less @@ -0,0 +1,133 @@ +.comma-delimited { + text-shadow: -1px -1px 1px red, 6px 5px 5px yellow; + -moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset, + 0pt 4px 6px rgba(255, 255, 255, 0.4) inset; + -webkit-transform: rotate(-0.0000000001deg); +} +@font-face { + font-family: Headline; + unicode-range: U+??????, U+0???, U+0-7F, U+A5; +} +.other { + -moz-transform: translate(0, 11em) rotate(-90deg); + transform: rotateX(45deg); +} +.item[data-cra_zy-attr1b-ut3=bold] { + font-weight: bold; +} +p:not([class*="lead"]) { + color: black; +} + +input[type="text"].class#id[attr=32]:not(1) { + color: white; +} + +div#id.class[a=1][b=2].class:not(1) { + color: white; +} + +ul.comma > li:not(:only-child)::after { + color: white; +} + +ol.comma > li:nth-last-child(2)::after { + color: white; +} + +li:nth-child(4n+1), +li:nth-child(-5n), +li:nth-child(-n+2) { + color: white; +} + +a[href^="http://"] { + color: black; +} + +a[href$="http://"] { + color: black; +} + +form[data-disabled] { + color: black; +} + +p::before { + color: black; +} + +#issue322 { + -webkit-animation: anim2 7s infinite ease-in-out; +} + +@-webkit-keyframes frames { + 0% { border: 1px } + 5.5% { border: 2px } + 100% { border: 3px } +} + +@keyframes fontbulger1 { + to { + font-size: 15px; + } + from,to { + font-size: 12px; + } + 0%,100% { + font-size: 12px; + } +} + +.units { + font: 1.2rem/2rem; + font: 8vw/9vw; + font: 10vh/12vh; + font: 12vm/15vm; + font: 12vmin/15vmin; + font: 1.2ch/1.5ch; +} + +@supports ( box-shadow: 2px 2px 2px black ) or + ( -moz-box-shadow: 2px 2px 2px black ) { + .outline { + box-shadow: 2px 2px 2px black; + -moz-box-shadow: 2px 2px 2px black; + } +} + +@-x-document url-prefix(""github.com"") { + h1 { + color: red; + } +} + +@viewport { + font-size: 10px; +} +@namespace foo url(http://www.example.com); + +foo|h1 { color: blue; } +foo|* { color: yellow; } +|h1 { color: red; } +*|h1 { color: green; } +h1 { color: green; } +.upper-test { + UpperCaseProperties: allowed; +} +@host { + div { + display: block; + } +} +::distributed(input::placeholder) { + color: #b3b3b3; +} +.shadow ^ .dom, +body ^^ .shadow { + display: done; +} + +#issue2066 { + background: url('/images/icon-team.svg') 0 0 / contain; +} diff --git a/test/less/css-escapes.less b/test/less/css-escapes.less new file mode 100644 index 00000000..6a4b2830 --- /dev/null +++ b/test/less/css-escapes.less @@ -0,0 +1,33 @@ +@ugly: fuchsia; + +.escape\|random\|char { + color: red; +} + +.mixin\!tUp { + font-weight: bold; +} + +// class="404" +.\34 04 { + background: red; + + strong { + color: @ugly; + .mixin\!tUp; + } +} + +.trailingTest\+ { + color: red; +} + +/* This hideous test of hideousness checks for the selector "blockquote" with various permutations of hex escapes */ +\62\6c\6f \63 \6B \0071 \000075o\74 e { + color: silver; +} + +[ng\:cloak], +ng\:form { + display: none; +} diff --git a/test/less/css-guards.less b/test/less/css-guards.less new file mode 100644 index 00000000..85ec8d29 --- /dev/null +++ b/test/less/css-guards.less @@ -0,0 +1,102 @@ + +.light when (lightness(@a) > 50%) { + color: green; +} +.dark when (lightness(@a) < 50%) { + color: orange; +} +@a: #ddd; + +.see-the { + @a: #444; // this mirrors what mixins do - they evaluate the guards at the point of definition + .light(); + .dark(); +} + +.hide-the { + .light(); + .dark(); +} + +.multiple-conditions-1 when (@b = 1), (@c = 2), (@d = 3) { + color: red; +} + +.multiple-conditions-2 when (@b = 1), (@c = 2), (@d = 2) { + color: blue; +} + +@b: 2; +@c: 3; +@d: 3; + +.inheritance when (@b = 2) { + .test { + color: black; + } + &:hover { + color: pink; + } + .hideme when (@b = 1) { + color: green; + } + & when (@b = 1) { + hideme: green; + } +} + +.hideme when (@b = 1) { + .test { + color: black; + } + &:hover { + color: pink; + } + .hideme when (@b = 1) { + color: green; + } +} + +& when (@b = 1) { + .hideme { + color: red; + } +} + +.mixin-with-guard-inside(@colWidth) { + // selector with guard (applies also to & when() ...) + .clsWithGuard when (@colWidth <= 0) { + dispaly: none; + } +} + +.mixin-with-guard-inside(0px); + +.dont-split-me-up { + width: 1px; + & when (@c = 3) { + color: red; + } + & when (@c = 3) { + height: 1px; + } + + & when (@c = 3) { // creates invalid css but tests that we don't fold it in + sibling: true; + } +} + +.scope-check when (@c = 3) { + @k: 1px; + & when (@c = 3) { + @k: 2px; + sub-prop: @k; + } + prop: @k; +} +.scope-check-2 { + .scope-check(); + @k:4px; +} +.errors-if-called when (@c = never) { + .mixin-doesnt-exist(); +} \ No newline at end of file diff --git a/test/less/css.less b/test/less/css.less new file mode 100644 index 00000000..766bdd4d --- /dev/null +++ b/test/less/css.less @@ -0,0 +1,108 @@ +@charset "utf-8"; +div { color: black; } +div { width: 99%; } + +* { + min-width: 45em; +} + +h1, h2 > a > p, h3 { + color: none; +} + +div.class { + color: blue; +} + +div#id { + color: green; +} + +.class#id { + color: purple; +} + +.one.two.three { + color: grey; +} + +@media print { + * { + font-size: 3em; + } +} + +@media screen { + * { + font-size: 10px; + } +} + +@font-face { + font-family: 'Garamond Pro'; +} + +a:hover, a:link { + color: #999; +} + +p, p:first-child { + text-transform: none; +} + +q:lang(no) { + quotes: none; +} + +p + h1 { + font-size: +2.2em; +} + +#shorthands { + border: 1px solid #000; + font: 12px/16px Arial; + font: 100%/16px Arial; + margin: 1px 0; + padding: 0 auto; +} + +#more-shorthands { + margin: 0; + padding: 1px 0 2px 0; + font: normal small/20px 'Trebuchet MS', Verdana, sans-serif; + font: 0/0 a; + border-radius: 5px / 10px; +} + +.misc { + -moz-border-radius: 2px; + display: -moz-inline-stack; + width: .1em; + background-color: #009998; + background: -webkit-gradient(linear, left top, left bottom, from(red), to(blue)); + margin: ; + .nested-multiple { + multiple-semi-colons: yes;;;;;; + }; + filter: alpha(opacity=100); + width: auto\9; +} + +#important { + color: red !important; + width: 100%!important; + height: 20px ! important; +} + +.def-font(@name) { + @font-face { + font-family: @name + } +} + +.def-font(font-a); +.def-font(font-b); + +.æøå { + margin: 0; +} diff --git a/test/less/debug/import/test.less b/test/less/debug/import/test.less new file mode 100644 index 00000000..795082f5 --- /dev/null +++ b/test/less/debug/import/test.less @@ -0,0 +1,25 @@ +@charset "ISO-8859-1"; + +.mixin_import1() { + @media all { + .tst { + color: black; + @media screen { + color: red; + .tst3 { + color: white; + } + } + } + } +} + +.mixin_import2() { + .tst2 { + color: white; + } +} + +.tst3 { + color: grey; +} \ No newline at end of file diff --git a/test/less/debug/linenumbers.less b/test/less/debug/linenumbers.less new file mode 100644 index 00000000..3bcaed01 --- /dev/null +++ b/test/less/debug/linenumbers.less @@ -0,0 +1,33 @@ +@charset "UTF-8"; + +@import "import/test.less"; + +.start() { + .test2 { + color: red; + } +} + +.mix() { + color: black; +} + +.test1 { + .mix(); +} + +.start(); + +.mixin_import1(); + +.mixin_import2(); + +@debug: 1; +& when (@debug = 1) { + .test { + color: red; + & when (@debug = 1) { + width: 2; + } + } +} \ No newline at end of file diff --git a/test/less/detached-rulesets.less b/test/less/detached-rulesets.less new file mode 100644 index 00000000..6a98d890 --- /dev/null +++ b/test/less/detached-rulesets.less @@ -0,0 +1,103 @@ +@ruleset: { + color: black; + background: white; + }; + +@a: 1px; +.wrap-mixin(@ruleset) { + @a: hidden and if you see this in the output its a bug; + @b: visible; + @d: magic-frame; // same behaviour as mixin calls - falls back to this frame + .wrap-selector { + @c: visible; + @ruleset(); + visible-one: @b; + visible-two: @c; + } +}; + +.wrap-mixin({ + color: black; + one: @a; + @b: hidden and if you see this in the output its a bug; + @c: hidden and if you see this in the output its a bug; + four: @d; +}); + +.wrap-mixin(@ruleset: { + color: red; +}); + +.wrap-mixin(@ruleset); + +.desktop-and-old-ie(@rules) { + @media screen and (min-width: 1200) { @rules(); } + html.lt-ie9 & { @rules(); } +} + +header { + background: blue; + + .desktop-and-old-ie({ + background: red; + }); +} + +.wrap-mixin-calls-wrap(@ruleset) { + .wrap-mixin(@ruleset); +}; + +.wrap-mixin({ + test: extra-wrap; + .wrap-mixin-calls-wrap({ + test: wrapped-twice; + }); +}); + +.wrap-mixin({ + test-func: unit(90px); + test-arithmetic: unit((9+9), px); +}); +// without mixins +@ruleset-2: { + b: 1; +}; +.without-mixins { + @ruleset-2(); +} +@my-ruleset: { + .my-selector { + @media tv { + background-color: black; + } + } + }; +@media (orientation:portrait) { + @my-ruleset(); + .wrap-media-mixin({ + @media tv { + .triple-wrapped-mq { + triple: true; + } + } + }); +} +.wrap-media-mixin(@ruleset) { + @media widescreen { + @media print { + @ruleset(); + } + @ruleset(); + } + @ruleset(); +} +// unlocking mixins +@my-mixins: { + .mixin() { + test: test; + } +}; +@my-mixins(); +.a { + .mixin(); +} \ No newline at end of file diff --git a/test/less/empty.less b/test/less/empty.less new file mode 100644 index 00000000..e69de29b diff --git a/test/less/errors/add-mixed-units.less b/test/less/errors/add-mixed-units.less new file mode 100644 index 00000000..9b708de9 --- /dev/null +++ b/test/less/errors/add-mixed-units.less @@ -0,0 +1,3 @@ +.a { + error: (1px + 3em); +} \ No newline at end of file diff --git a/test/less/errors/add-mixed-units.txt b/test/less/errors/add-mixed-units.txt new file mode 100644 index 00000000..9ea45438 --- /dev/null +++ b/test/less/errors/add-mixed-units.txt @@ -0,0 +1,4 @@ +SyntaxError: Incompatible units. Change the units or use the unit function. Bad units: 'px' and 'em'. in {path}add-mixed-units.less on line 2, column 3: +1 .a { +2 error: (1px + 3em); +3 } diff --git a/test/less/errors/add-mixed-units2.less b/test/less/errors/add-mixed-units2.less new file mode 100644 index 00000000..26631160 --- /dev/null +++ b/test/less/errors/add-mixed-units2.less @@ -0,0 +1,3 @@ +.a { + error: ((1px * 2px) + (3em * 3px)); +} \ No newline at end of file diff --git a/test/less/errors/add-mixed-units2.txt b/test/less/errors/add-mixed-units2.txt new file mode 100644 index 00000000..ca34304f --- /dev/null +++ b/test/less/errors/add-mixed-units2.txt @@ -0,0 +1,4 @@ +SyntaxError: Incompatible units. Change the units or use the unit function. Bad units: 'px*px' and 'em*px'. in {path}add-mixed-units2.less on line 2, column 3: +1 .a { +2 error: ((1px * 2px) + (3em * 3px)); +3 } diff --git a/test/less/errors/at-rules-undefined-var.less b/test/less/errors/at-rules-undefined-var.less new file mode 100644 index 00000000..a1473805 --- /dev/null +++ b/test/less/errors/at-rules-undefined-var.less @@ -0,0 +1,4 @@ + +@keyframes @name { + 50% {width: 20px;} +} diff --git a/test/less/errors/at-rules-undefined-var.txt b/test/less/errors/at-rules-undefined-var.txt new file mode 100644 index 00000000..48ca57c4 --- /dev/null +++ b/test/less/errors/at-rules-undefined-var.txt @@ -0,0 +1,4 @@ +NameError: variable @name is undefined in {path}at-rules-undefined-var.less on line 2, column 12: +1 +2 @keyframes @name { +3 50% {width: 20px;} diff --git a/test/less/errors/bad-variable-declaration1.less b/test/less/errors/bad-variable-declaration1.less new file mode 100644 index 00000000..c2dc6ac0 --- /dev/null +++ b/test/less/errors/bad-variable-declaration1.less @@ -0,0 +1 @@ +@@demo: "hi"; \ No newline at end of file diff --git a/test/less/errors/bad-variable-declaration1.txt b/test/less/errors/bad-variable-declaration1.txt new file mode 100644 index 00000000..5ae9d4a4 --- /dev/null +++ b/test/less/errors/bad-variable-declaration1.txt @@ -0,0 +1,2 @@ +ParseError: Unrecognised input in {path}bad-variable-declaration1.less on line 1, column 1: +1 @@demo: "hi"; diff --git a/test/less/errors/color-func-invalid-color.less b/test/less/errors/color-func-invalid-color.less new file mode 100644 index 00000000..5a1edd01 --- /dev/null +++ b/test/less/errors/color-func-invalid-color.less @@ -0,0 +1,3 @@ +.test { + color: color("NOT A COLOR"); +} \ No newline at end of file diff --git a/test/less/errors/color-func-invalid-color.txt b/test/less/errors/color-func-invalid-color.txt new file mode 100644 index 00000000..08990c30 --- /dev/null +++ b/test/less/errors/color-func-invalid-color.txt @@ -0,0 +1,4 @@ +ArgumentError: error evaluating function `color`: argument must be a color keyword or 3/6 digit hex e.g. #FFF in {path}color-func-invalid-color.less on line 2, column 10: +1 .test { +2 color: color("NOT A COLOR"); +3 } diff --git a/test/less/errors/color-invalid-hex-code.less b/test/less/errors/color-invalid-hex-code.less new file mode 100644 index 00000000..0e6c5deb --- /dev/null +++ b/test/less/errors/color-invalid-hex-code.less @@ -0,0 +1,3 @@ +.a { + @wrongHEXColorCode: #DCALLB; +} \ No newline at end of file diff --git a/test/less/errors/color-invalid-hex-code.txt b/test/less/errors/color-invalid-hex-code.txt new file mode 100644 index 00000000..0f8a82ce --- /dev/null +++ b/test/less/errors/color-invalid-hex-code.txt @@ -0,0 +1,4 @@ +SyntaxError: Invalid HEX color code in {path}color-invalid-hex-code.less on line 2, column 29: +1 .a { +2 @wrongHEXColorCode: #DCALLB; +3 } diff --git a/test/less/errors/color-invalid-hex-code2.less b/test/less/errors/color-invalid-hex-code2.less new file mode 100644 index 00000000..cb9a9b76 --- /dev/null +++ b/test/less/errors/color-invalid-hex-code2.less @@ -0,0 +1,3 @@ +.a { + @wrongHEXColorCode: #fffblack; +} \ No newline at end of file diff --git a/test/less/errors/color-invalid-hex-code2.txt b/test/less/errors/color-invalid-hex-code2.txt new file mode 100644 index 00000000..dd3996b1 --- /dev/null +++ b/test/less/errors/color-invalid-hex-code2.txt @@ -0,0 +1,4 @@ +SyntaxError: Invalid HEX color code in {path}color-invalid-hex-code2.less on line 2, column 29: +1 .a { +2 @wrongHEXColorCode: #fffblack; +3 } diff --git a/test/less/errors/comment-in-selector.less b/test/less/errors/comment-in-selector.less new file mode 100644 index 00000000..a7d26396 --- /dev/null +++ b/test/less/errors/comment-in-selector.less @@ -0,0 +1 @@ +#gaga /* Comment */ span { color: red } \ No newline at end of file diff --git a/test/less/errors/comment-in-selector.txt b/test/less/errors/comment-in-selector.txt new file mode 100644 index 00000000..e48f878c --- /dev/null +++ b/test/less/errors/comment-in-selector.txt @@ -0,0 +1,2 @@ +ParseError: Unrecognised input in {path}comment-in-selector.less on line 1, column 21: +1 #gaga /* Comment */ span { color: red } diff --git a/test/less/errors/css-guard-default-func.less b/test/less/errors/css-guard-default-func.less new file mode 100644 index 00000000..db6639e1 --- /dev/null +++ b/test/less/errors/css-guard-default-func.less @@ -0,0 +1,4 @@ + +selector when (default()) { + color: red; +} diff --git a/test/less/errors/css-guard-default-func.txt b/test/less/errors/css-guard-default-func.txt new file mode 100644 index 00000000..ea670295 --- /dev/null +++ b/test/less/errors/css-guard-default-func.txt @@ -0,0 +1,4 @@ +SyntaxError: error evaluating function `default`: it is currently only allowed in parametric mixin guards, in {path}css-guard-default-func.less on line 2, column 16: +1 +2 selector when (default()) { +3 color: red; diff --git a/test/less/errors/detached-ruleset-1.less b/test/less/errors/detached-ruleset-1.less new file mode 100644 index 00000000..ac5b8db0 --- /dev/null +++ b/test/less/errors/detached-ruleset-1.less @@ -0,0 +1,6 @@ +@a: { + b: 1; +}; +.a { + a: @a; +} \ No newline at end of file diff --git a/test/less/errors/detached-ruleset-1.txt b/test/less/errors/detached-ruleset-1.txt new file mode 100644 index 00000000..7407741c --- /dev/null +++ b/test/less/errors/detached-ruleset-1.txt @@ -0,0 +1,4 @@ +SyntaxError: Rulesets cannot be evaluated on a property. in {path}detached-ruleset-1.less on line 5, column 3: +4 .a { +5 a: @a; +6 } diff --git a/test/less/errors/detached-ruleset-2.less b/test/less/errors/detached-ruleset-2.less new file mode 100644 index 00000000..51a7af6b --- /dev/null +++ b/test/less/errors/detached-ruleset-2.less @@ -0,0 +1,6 @@ +@a: { + b: 1; +}; +.a { + a: @a(); +} \ No newline at end of file diff --git a/test/less/errors/detached-ruleset-2.txt b/test/less/errors/detached-ruleset-2.txt new file mode 100644 index 00000000..f18e0935 --- /dev/null +++ b/test/less/errors/detached-ruleset-2.txt @@ -0,0 +1,4 @@ +ParseError: Unrecognised input in {path}detached-ruleset-2.less on line 5, column 3: +4 .a { +5 a: @a(); +6 } diff --git a/test/less/errors/detached-ruleset-3.less b/test/less/errors/detached-ruleset-3.less new file mode 100644 index 00000000..c50119d9 --- /dev/null +++ b/test/less/errors/detached-ruleset-3.less @@ -0,0 +1,4 @@ +@a: { + b: 1; +}; +@a(); \ No newline at end of file diff --git a/test/less/errors/detached-ruleset-3.txt b/test/less/errors/detached-ruleset-3.txt new file mode 100644 index 00000000..15d281fa --- /dev/null +++ b/test/less/errors/detached-ruleset-3.txt @@ -0,0 +1,4 @@ +SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}detached-ruleset-3.less on line 2, column 3: +1 @a: { +2 b: 1; +3 }; diff --git a/test/less/errors/detached-ruleset-4.less b/test/less/errors/detached-ruleset-4.less new file mode 100644 index 00000000..14ac314b --- /dev/null +++ b/test/less/errors/detached-ruleset-4.less @@ -0,0 +1,5 @@ +.mixin-definition(@a: { + b: 1; +}) { + @a(); +} \ No newline at end of file diff --git a/test/less/errors/detached-ruleset-4.txt b/test/less/errors/detached-ruleset-4.txt new file mode 100644 index 00000000..d6d6526d --- /dev/null +++ b/test/less/errors/detached-ruleset-4.txt @@ -0,0 +1,3 @@ +ParseError: Unrecognised input in {path}detached-ruleset-4.less on line 1, column 18: +1 .mixin-definition(@a: { +2 b: 1; diff --git a/test/less/errors/detached-ruleset-5.less b/test/less/errors/detached-ruleset-5.less new file mode 100644 index 00000000..174ebf35 --- /dev/null +++ b/test/less/errors/detached-ruleset-5.less @@ -0,0 +1,4 @@ +.mixin-definition(@b) { + @a(); +} +.mixin-definition({color: red;}); \ No newline at end of file diff --git a/test/less/errors/detached-ruleset-5.txt b/test/less/errors/detached-ruleset-5.txt new file mode 100644 index 00000000..56189795 --- /dev/null +++ b/test/less/errors/detached-ruleset-5.txt @@ -0,0 +1,3 @@ +SyntaxError: variable @a is undefined in {path}detached-ruleset-5.less on line 4, column 1: +3 } +4 .mixin-definition({color: red;}); diff --git a/test/less/errors/detached-ruleset-6.less b/test/less/errors/detached-ruleset-6.less new file mode 100644 index 00000000..121099f7 --- /dev/null +++ b/test/less/errors/detached-ruleset-6.less @@ -0,0 +1,5 @@ +.a { + b: { + color: red; + }; +} \ No newline at end of file diff --git a/test/less/errors/detached-ruleset-6.txt b/test/less/errors/detached-ruleset-6.txt new file mode 100644 index 00000000..07840445 --- /dev/null +++ b/test/less/errors/detached-ruleset-6.txt @@ -0,0 +1,4 @@ +ParseError: Unrecognised input in {path}detached-ruleset-6.less on line 2, column 3: +1 .a { +2 b: { +3 color: red; diff --git a/test/less/errors/divide-mixed-units.less b/test/less/errors/divide-mixed-units.less new file mode 100644 index 00000000..d228b7c4 --- /dev/null +++ b/test/less/errors/divide-mixed-units.less @@ -0,0 +1,3 @@ +.a { + error: (1px / 3em); +} \ No newline at end of file diff --git a/test/less/errors/divide-mixed-units.txt b/test/less/errors/divide-mixed-units.txt new file mode 100644 index 00000000..c189d2aa --- /dev/null +++ b/test/less/errors/divide-mixed-units.txt @@ -0,0 +1,4 @@ +SyntaxError: Multiple units in dimension. Correct the units or use the unit function. Bad unit: px/em in {path}divide-mixed-units.less on line 2, column 3: +1 .a { +2 error: (1px / 3em); +3 } diff --git a/test/less/errors/extend-no-selector.less b/test/less/errors/extend-no-selector.less new file mode 100644 index 00000000..84689ef3 --- /dev/null +++ b/test/less/errors/extend-no-selector.less @@ -0,0 +1,3 @@ +:extend(.a all) { + property: red; +} \ No newline at end of file diff --git a/test/less/errors/extend-no-selector.txt b/test/less/errors/extend-no-selector.txt new file mode 100644 index 00000000..bd2e3cd7 --- /dev/null +++ b/test/less/errors/extend-no-selector.txt @@ -0,0 +1,3 @@ +SyntaxError: Extend must be used to extend a selector, it cannot be used on its own in {path}extend-no-selector.less on line 1, column 17: +1 :extend(.a all) { +2 property: red; diff --git a/test/less/errors/extend-not-at-end.less b/test/less/errors/extend-not-at-end.less new file mode 100644 index 00000000..90ee512c --- /dev/null +++ b/test/less/errors/extend-not-at-end.less @@ -0,0 +1,3 @@ +.a:extend(.b all).c { + property: red; +} \ No newline at end of file diff --git a/test/less/errors/extend-not-at-end.txt b/test/less/errors/extend-not-at-end.txt new file mode 100644 index 00000000..32ebedfc --- /dev/null +++ b/test/less/errors/extend-not-at-end.txt @@ -0,0 +1,3 @@ +SyntaxError: Extend can only be used at the end of selector in {path}extend-not-at-end.less on line 1, column 21: +1 .a:extend(.b all).c { +2 property: red; diff --git a/test/less/errors/import-missing.less b/test/less/errors/import-missing.less new file mode 100644 index 00000000..5ce8e4d9 --- /dev/null +++ b/test/less/errors/import-missing.less @@ -0,0 +1,6 @@ +.a { + color: green; + // tests line number for import reference is correct +} + +@import "file-does-not-exist.less"; \ No newline at end of file diff --git a/test/less/errors/import-missing.txt b/test/less/errors/import-missing.txt new file mode 100644 index 00000000..488d154a --- /dev/null +++ b/test/less/errors/import-missing.txt @@ -0,0 +1,3 @@ +FileError: '{pathhref}file-does-not-exist.less' wasn't found{404status} in {path}import-missing.less on line 6, column 1: +5 +6 @import "file-does-not-exist.less"; diff --git a/test/less/errors/import-no-semi.less b/test/less/errors/import-no-semi.less new file mode 100644 index 00000000..bf2c7f65 --- /dev/null +++ b/test/less/errors/import-no-semi.less @@ -0,0 +1 @@ +@import "this-statement-is-invalid.less" \ No newline at end of file diff --git a/test/less/errors/import-no-semi.txt b/test/less/errors/import-no-semi.txt new file mode 100644 index 00000000..8b3f795c --- /dev/null +++ b/test/less/errors/import-no-semi.txt @@ -0,0 +1,2 @@ +ParseError: Unrecognised input in {path}import-no-semi.less on line 1, column 1: +1 @import "this-statement-is-invalid.less" diff --git a/test/less/errors/import-subfolder1.less b/test/less/errors/import-subfolder1.less new file mode 100644 index 00000000..4280673b --- /dev/null +++ b/test/less/errors/import-subfolder1.less @@ -0,0 +1 @@ +@import "imports/import-subfolder1.less"; \ No newline at end of file diff --git a/test/less/errors/import-subfolder1.txt b/test/less/errors/import-subfolder1.txt new file mode 100644 index 00000000..97629276 --- /dev/null +++ b/test/less/errors/import-subfolder1.txt @@ -0,0 +1,3 @@ +NameError: .mixin-not-defined is undefined in {path}mixin-not-defined.less on line 11, column 1: +10 +11 .mixin-not-defined(); diff --git a/test/less/errors/import-subfolder2.less b/test/less/errors/import-subfolder2.less new file mode 100644 index 00000000..a6b9b9ce --- /dev/null +++ b/test/less/errors/import-subfolder2.less @@ -0,0 +1 @@ +@import "imports/import-subfolder2.less"; \ No newline at end of file diff --git a/test/less/errors/import-subfolder2.txt b/test/less/errors/import-subfolder2.txt new file mode 100644 index 00000000..b5b1a69b --- /dev/null +++ b/test/less/errors/import-subfolder2.txt @@ -0,0 +1,4 @@ +ParseError: missing opening `{` in {path}parse-error-curly-bracket.less on line 4, column 1: +3 } +4 } +5 diff --git a/test/less/errors/imports/import-subfolder1.less b/test/less/errors/imports/import-subfolder1.less new file mode 100644 index 00000000..24ec0532 --- /dev/null +++ b/test/less/errors/imports/import-subfolder1.less @@ -0,0 +1 @@ +@import "subfolder/mixin-not-defined.less"; \ No newline at end of file diff --git a/test/less/errors/imports/import-subfolder2.less b/test/less/errors/imports/import-subfolder2.less new file mode 100644 index 00000000..6058ad14 --- /dev/null +++ b/test/less/errors/imports/import-subfolder2.less @@ -0,0 +1 @@ +@import "subfolder/parse-error-curly-bracket.less"; \ No newline at end of file diff --git a/test/less/errors/imports/import-test.less b/test/less/errors/imports/import-test.less new file mode 100644 index 00000000..a91ae054 --- /dev/null +++ b/test/less/errors/imports/import-test.less @@ -0,0 +1,4 @@ +.someclass +{ + font-weight: bold; +} \ No newline at end of file diff --git a/test/less/errors/imports/subfolder/mixin-not-defined.less b/test/less/errors/imports/subfolder/mixin-not-defined.less new file mode 100644 index 00000000..2bb2d091 --- /dev/null +++ b/test/less/errors/imports/subfolder/mixin-not-defined.less @@ -0,0 +1 @@ +@import "../../mixin-not-defined.less"; \ No newline at end of file diff --git a/test/less/errors/imports/subfolder/parse-error-curly-bracket.less b/test/less/errors/imports/subfolder/parse-error-curly-bracket.less new file mode 100644 index 00000000..f37fa9d0 --- /dev/null +++ b/test/less/errors/imports/subfolder/parse-error-curly-bracket.less @@ -0,0 +1 @@ +@import "../../parse-error-curly-bracket.less"; \ No newline at end of file diff --git a/test/less/errors/javascript-error.less b/test/less/errors/javascript-error.less new file mode 100644 index 00000000..9332a37d --- /dev/null +++ b/test/less/errors/javascript-error.less @@ -0,0 +1,3 @@ +.scope { + var: `this.foo.toJS`; +} diff --git a/test/less/errors/javascript-error.txt b/test/less/errors/javascript-error.txt new file mode 100644 index 00000000..c4da9508 --- /dev/null +++ b/test/less/errors/javascript-error.txt @@ -0,0 +1,4 @@ +SyntaxError: JavaScript evaluation error: 'TypeError: Cannot read property 'toJS' of undefined' in {path}javascript-error.less on line 2, column 25: +1 .scope { +2 var: `this.foo.toJS`; +3 } diff --git a/test/less/errors/javascript-undefined-var.less b/test/less/errors/javascript-undefined-var.less new file mode 100644 index 00000000..7cd580c4 --- /dev/null +++ b/test/less/errors/javascript-undefined-var.less @@ -0,0 +1,3 @@ +.scope { + @a: `@{b}`; +} diff --git a/test/less/errors/javascript-undefined-var.txt b/test/less/errors/javascript-undefined-var.txt new file mode 100644 index 00000000..b363aff9 --- /dev/null +++ b/test/less/errors/javascript-undefined-var.txt @@ -0,0 +1,4 @@ +NameError: variable @b is undefined in {path}javascript-undefined-var.less on line 2, column 15: +1 .scope { +2 @a: `@{b}`; +3 } diff --git a/test/less/errors/mixed-mixin-definition-args-1.less b/test/less/errors/mixed-mixin-definition-args-1.less new file mode 100644 index 00000000..9b0e23af --- /dev/null +++ b/test/less/errors/mixed-mixin-definition-args-1.less @@ -0,0 +1,6 @@ +.mixin(@a : 4, @b : 3, @c: 2) { + will: fail; +} +.mixin-test { + .mixin(@a: 5; @b: 6, @c: 7); +} \ No newline at end of file diff --git a/test/less/errors/mixed-mixin-definition-args-1.txt b/test/less/errors/mixed-mixin-definition-args-1.txt new file mode 100644 index 00000000..a07f5e9d --- /dev/null +++ b/test/less/errors/mixed-mixin-definition-args-1.txt @@ -0,0 +1,4 @@ +SyntaxError: Cannot mix ; and , as delimiter types in {path}mixed-mixin-definition-args-1.less on line 5, column 30: +4 .mixin-test { +5 .mixin(@a: 5; @b: 6, @c: 7); +6 } diff --git a/test/less/errors/mixed-mixin-definition-args-2.less b/test/less/errors/mixed-mixin-definition-args-2.less new file mode 100644 index 00000000..c9709427 --- /dev/null +++ b/test/less/errors/mixed-mixin-definition-args-2.less @@ -0,0 +1,6 @@ +.mixin(@a : 4, @b : 3, @c: 2) { + will: fail; +} +.mixin-test { + .mixin(@a: 5, @b: 6; @c: 7); +} diff --git a/test/less/errors/mixed-mixin-definition-args-2.txt b/test/less/errors/mixed-mixin-definition-args-2.txt new file mode 100644 index 00000000..fa00183b --- /dev/null +++ b/test/less/errors/mixed-mixin-definition-args-2.txt @@ -0,0 +1,4 @@ +SyntaxError: Cannot mix ; and , as delimiter types in {path}mixed-mixin-definition-args-2.less on line 5, column 26: +4 .mixin-test { +5 .mixin(@a: 5, @b: 6; @c: 7); +6 } diff --git a/test/less/errors/mixin-not-defined.less b/test/less/errors/mixin-not-defined.less new file mode 100644 index 00000000..e2dad5ce --- /dev/null +++ b/test/less/errors/mixin-not-defined.less @@ -0,0 +1,11 @@ + +.error-is-further-on() { +} + +.pad-here-to-reproduce-error-in() { +} + +.the-import-subfolder-test() { +} + +.mixin-not-defined(); \ No newline at end of file diff --git a/test/less/errors/mixin-not-defined.txt b/test/less/errors/mixin-not-defined.txt new file mode 100644 index 00000000..97629276 --- /dev/null +++ b/test/less/errors/mixin-not-defined.txt @@ -0,0 +1,3 @@ +NameError: .mixin-not-defined is undefined in {path}mixin-not-defined.less on line 11, column 1: +10 +11 .mixin-not-defined(); diff --git a/test/less/errors/mixin-not-matched.less b/test/less/errors/mixin-not-matched.less new file mode 100644 index 00000000..be0d6b1a --- /dev/null +++ b/test/less/errors/mixin-not-matched.less @@ -0,0 +1,6 @@ +@saxofon:trumpete; + +.mixin(saxofon) { +} + +.mixin(@saxofon); \ No newline at end of file diff --git a/test/less/errors/mixin-not-matched.txt b/test/less/errors/mixin-not-matched.txt new file mode 100644 index 00000000..57df9772 --- /dev/null +++ b/test/less/errors/mixin-not-matched.txt @@ -0,0 +1,3 @@ +RuntimeError: No matching definition was found for `.mixin(trumpete)` in {path}mixin-not-matched.less on line 6, column 1: +5 +6 .mixin(@saxofon); diff --git a/test/less/errors/mixin-not-matched2.less b/test/less/errors/mixin-not-matched2.less new file mode 100644 index 00000000..14f44bf3 --- /dev/null +++ b/test/less/errors/mixin-not-matched2.less @@ -0,0 +1,6 @@ +@saxofon:trumpete; + +.mixin(@a, @b) { +} + +.mixin(@a: @saxofon); \ No newline at end of file diff --git a/test/less/errors/mixin-not-matched2.txt b/test/less/errors/mixin-not-matched2.txt new file mode 100644 index 00000000..dceedaf0 --- /dev/null +++ b/test/less/errors/mixin-not-matched2.txt @@ -0,0 +1,3 @@ +RuntimeError: No matching definition was found for `.mixin(@a:trumpete)` in {path}mixin-not-matched2.less on line 6, column 1: +5 +6 .mixin(@a: @saxofon); diff --git a/test/less/errors/mixin-not-visible-in-scope-1.less b/test/less/errors/mixin-not-visible-in-scope-1.less new file mode 100644 index 00000000..2842613e --- /dev/null +++ b/test/less/errors/mixin-not-visible-in-scope-1.less @@ -0,0 +1,9 @@ +.something { + & { + .a {value: a} + } + + & { + .b {.a} // was Err. before 1.6.2 + } +} \ No newline at end of file diff --git a/test/less/errors/mixin-not-visible-in-scope-1.txt b/test/less/errors/mixin-not-visible-in-scope-1.txt new file mode 100644 index 00000000..15e64dc2 --- /dev/null +++ b/test/less/errors/mixin-not-visible-in-scope-1.txt @@ -0,0 +1,4 @@ +NameError: .a is undefined in {path}mixin-not-visible-in-scope-1.less on line 7, column 13: +6 & { +7 .b {.a} // was Err. before 1.6.2 +8 } diff --git a/test/less/errors/mixins-guards-default-func-1.less b/test/less/errors/mixins-guards-default-func-1.less new file mode 100644 index 00000000..dc90b86b --- /dev/null +++ b/test/less/errors/mixins-guards-default-func-1.less @@ -0,0 +1,9 @@ + +guard-default-func-conflict { + .m(@x, 1) {} + .m(@x, 2) when (default()) {} + .m(@x, 2) when (default()) {} + + .m(1, 1); + .m(1, 2); +} diff --git a/test/less/errors/mixins-guards-default-func-1.txt b/test/less/errors/mixins-guards-default-func-1.txt new file mode 100644 index 00000000..d123c21c --- /dev/null +++ b/test/less/errors/mixins-guards-default-func-1.txt @@ -0,0 +1,4 @@ +RuntimeError: Ambiguous use of `default()` found when matching for `.m(1, 2)` in {path}mixins-guards-default-func-1.less on line 8, column 5: +7 .m(1, 1); +8 .m(1, 2); +9 } diff --git a/test/less/errors/mixins-guards-default-func-2.less b/test/less/errors/mixins-guards-default-func-2.less new file mode 100644 index 00000000..079b5737 --- /dev/null +++ b/test/less/errors/mixins-guards-default-func-2.less @@ -0,0 +1,9 @@ + +guard-default-func-conflict { + .m(1) {} + .m(@x) when not(default()) {} + .m(@x) when (@x = 3) and (default()) {} + + .m(2); + .m(3); +} diff --git a/test/less/errors/mixins-guards-default-func-2.txt b/test/less/errors/mixins-guards-default-func-2.txt new file mode 100644 index 00000000..7f7d7cce --- /dev/null +++ b/test/less/errors/mixins-guards-default-func-2.txt @@ -0,0 +1,4 @@ +RuntimeError: Ambiguous use of `default()` found when matching for `.m(3)` in {path}mixins-guards-default-func-2.less on line 8, column 5: +7 .m(2); +8 .m(3); +9 } diff --git a/test/less/errors/mixins-guards-default-func-3.less b/test/less/errors/mixins-guards-default-func-3.less new file mode 100644 index 00000000..ec357fa1 --- /dev/null +++ b/test/less/errors/mixins-guards-default-func-3.less @@ -0,0 +1,9 @@ + +guard-default-func-conflict { + .m(1) {} + .m(@x) when not(default()) {} + .m(@x) when not(default()) {} + + .m(1); + .m(2); +} diff --git a/test/less/errors/mixins-guards-default-func-3.txt b/test/less/errors/mixins-guards-default-func-3.txt new file mode 100644 index 00000000..2a2728cc --- /dev/null +++ b/test/less/errors/mixins-guards-default-func-3.txt @@ -0,0 +1,4 @@ +RuntimeError: Ambiguous use of `default()` found when matching for `.m(2)` in {path}mixins-guards-default-func-3.less on line 8, column 5: +7 .m(1); +8 .m(2); +9 } diff --git a/test/less/errors/multiple-guards-on-css-selectors.less b/test/less/errors/multiple-guards-on-css-selectors.less new file mode 100644 index 00000000..4eabb60a --- /dev/null +++ b/test/less/errors/multiple-guards-on-css-selectors.less @@ -0,0 +1,4 @@ +@ie8: true; +.a when (@ie8 = true), +.b { +} \ No newline at end of file diff --git a/test/less/errors/multiple-guards-on-css-selectors.txt b/test/less/errors/multiple-guards-on-css-selectors.txt new file mode 100644 index 00000000..3d23e26b --- /dev/null +++ b/test/less/errors/multiple-guards-on-css-selectors.txt @@ -0,0 +1,4 @@ +SyntaxError: Guards are only currently allowed on a single selector. in {path}multiple-guards-on-css-selectors.less on line 3, column 1: +2 .a when (@ie8 = true), +3 .b { +4 } diff --git a/test/less/errors/multiple-guards-on-css-selectors2.less b/test/less/errors/multiple-guards-on-css-selectors2.less new file mode 100644 index 00000000..4b1bc6ff --- /dev/null +++ b/test/less/errors/multiple-guards-on-css-selectors2.less @@ -0,0 +1,4 @@ +@ie8: true; +.a, +.b when (@ie8 = true) { +} \ No newline at end of file diff --git a/test/less/errors/multiple-guards-on-css-selectors2.txt b/test/less/errors/multiple-guards-on-css-selectors2.txt new file mode 100644 index 00000000..d0e5a52b --- /dev/null +++ b/test/less/errors/multiple-guards-on-css-selectors2.txt @@ -0,0 +1,4 @@ +SyntaxError: Guards are only currently allowed on a single selector. in {path}multiple-guards-on-css-selectors2.less on line 3, column 23: +2 .a, +3 .b when (@ie8 = true) { +4 } diff --git a/test/less/errors/multiply-mixed-units.less b/test/less/errors/multiply-mixed-units.less new file mode 100644 index 00000000..ff983a85 --- /dev/null +++ b/test/less/errors/multiply-mixed-units.less @@ -0,0 +1,7 @@ +/* Test */ +#blah { + // blah +} +.a { + error: (1px * 1em); +} \ No newline at end of file diff --git a/test/less/errors/multiply-mixed-units.txt b/test/less/errors/multiply-mixed-units.txt new file mode 100644 index 00000000..9ed834f1 --- /dev/null +++ b/test/less/errors/multiply-mixed-units.txt @@ -0,0 +1,4 @@ +SyntaxError: Multiple units in dimension. Correct the units or use the unit function. Bad unit: em*px in {path}multiply-mixed-units.less on line 6, column 3: +5 .a { +6 error: (1px * 1em); +7 } diff --git a/test/less/errors/parens-error-1.less b/test/less/errors/parens-error-1.less new file mode 100644 index 00000000..7c8ec10e --- /dev/null +++ b/test/less/errors/parens-error-1.less @@ -0,0 +1,3 @@ +.a { + something: (12 (13 + 5 -23) + 5); +} \ No newline at end of file diff --git a/test/less/errors/parens-error-1.txt b/test/less/errors/parens-error-1.txt new file mode 100644 index 00000000..6fc40ac0 --- /dev/null +++ b/test/less/errors/parens-error-1.txt @@ -0,0 +1,4 @@ +SyntaxError: expected ')' got '(' in {path}parens-error-1.less on line 2, column 18: +1 .a { +2 something: (12 (13 + 5 -23) + 5); +3 } diff --git a/test/less/errors/parens-error-2.less b/test/less/errors/parens-error-2.less new file mode 100644 index 00000000..4a392b8e --- /dev/null +++ b/test/less/errors/parens-error-2.less @@ -0,0 +1,3 @@ +.a { + something: (12 * (13 + 5 -23)); +} \ No newline at end of file diff --git a/test/less/errors/parens-error-2.txt b/test/less/errors/parens-error-2.txt new file mode 100644 index 00000000..cee5c52d --- /dev/null +++ b/test/less/errors/parens-error-2.txt @@ -0,0 +1,4 @@ +SyntaxError: expected ')' got '-' in {path}parens-error-2.less on line 2, column 28: +1 .a { +2 something: (12 * (13 + 5 -23)); +3 } diff --git a/test/less/errors/parens-error-3.less b/test/less/errors/parens-error-3.less new file mode 100644 index 00000000..9e6d5405 --- /dev/null +++ b/test/less/errors/parens-error-3.less @@ -0,0 +1,3 @@ +.a { + something: (12 + (13 + 10 -23)); +} \ No newline at end of file diff --git a/test/less/errors/parens-error-3.txt b/test/less/errors/parens-error-3.txt new file mode 100644 index 00000000..3280ef04 --- /dev/null +++ b/test/less/errors/parens-error-3.txt @@ -0,0 +1,4 @@ +SyntaxError: expected ')' got '-' in {path}parens-error-3.less on line 2, column 29: +1 .a { +2 something: (12 + (13 + 10 -23)); +3 } diff --git a/test/less/errors/parse-error-curly-bracket.less b/test/less/errors/parse-error-curly-bracket.less new file mode 100644 index 00000000..f78ceb70 --- /dev/null +++ b/test/less/errors/parse-error-curly-bracket.less @@ -0,0 +1,4 @@ +body { + background-color: #fff; + } +} diff --git a/test/less/errors/parse-error-curly-bracket.txt b/test/less/errors/parse-error-curly-bracket.txt new file mode 100644 index 00000000..b5b1a69b --- /dev/null +++ b/test/less/errors/parse-error-curly-bracket.txt @@ -0,0 +1,4 @@ +ParseError: missing opening `{` in {path}parse-error-curly-bracket.less on line 4, column 1: +3 } +4 } +5 diff --git a/test/less/errors/parse-error-extra-parens.less b/test/less/errors/parse-error-extra-parens.less new file mode 100644 index 00000000..46d023a9 --- /dev/null +++ b/test/less/errors/parse-error-extra-parens.less @@ -0,0 +1,5 @@ +@media (extra: bracket)) { + body { + background-color: #fff; + } +} diff --git a/test/less/errors/parse-error-extra-parens.txt b/test/less/errors/parse-error-extra-parens.txt new file mode 100644 index 00000000..5c1aaef2 --- /dev/null +++ b/test/less/errors/parse-error-extra-parens.txt @@ -0,0 +1,3 @@ +ParseError: missing opening `(` in {path}parse-error-extra-parens.less on line 1, column 24: +1 @media (extra: bracket)) { +2 body { diff --git a/test/less/errors/parse-error-missing-bracket.less b/test/less/errors/parse-error-missing-bracket.less new file mode 100644 index 00000000..144a6edf --- /dev/null +++ b/test/less/errors/parse-error-missing-bracket.less @@ -0,0 +1,2 @@ +body { + background-color: #fff; diff --git a/test/less/errors/parse-error-missing-bracket.txt b/test/less/errors/parse-error-missing-bracket.txt new file mode 100644 index 00000000..7db2716e --- /dev/null +++ b/test/less/errors/parse-error-missing-bracket.txt @@ -0,0 +1,3 @@ +ParseError: missing closing `}` in {path}parse-error-missing-bracket.less on line 1, column 6: +1 body { +2 background-color: #fff; diff --git a/test/less/errors/parse-error-missing-parens.less b/test/less/errors/parse-error-missing-parens.less new file mode 100644 index 00000000..55d25791 --- /dev/null +++ b/test/less/errors/parse-error-missing-parens.less @@ -0,0 +1,5 @@ +@media (missing: bracket { + body { + background-color: #fff; + } +} diff --git a/test/less/errors/parse-error-missing-parens.txt b/test/less/errors/parse-error-missing-parens.txt new file mode 100644 index 00000000..a7a67067 --- /dev/null +++ b/test/less/errors/parse-error-missing-parens.txt @@ -0,0 +1,3 @@ +ParseError: missing closing `)` in {path}parse-error-missing-parens.less on line 1, column 8: +1 @media (missing: bracket { +2 body { diff --git a/test/less/errors/parse-error-with-import.less b/test/less/errors/parse-error-with-import.less new file mode 100644 index 00000000..6be3de85 --- /dev/null +++ b/test/less/errors/parse-error-with-import.less @@ -0,0 +1,13 @@ +@import 'import/import-test.less'; + +body +{ + font-family: arial, sans-serif; +} + +nonsense; + +.clickable +{ + cursor: pointer; +} \ No newline at end of file diff --git a/test/less/errors/parse-error-with-import.txt b/test/less/errors/parse-error-with-import.txt new file mode 100644 index 00000000..07732c92 --- /dev/null +++ b/test/less/errors/parse-error-with-import.txt @@ -0,0 +1,4 @@ +ParseError: Unrecognised input in {path}parse-error-with-import.less on line 8, column 9: +7 +8 nonsense; +9 diff --git a/test/less/errors/percentage-missing-space.less b/test/less/errors/percentage-missing-space.less new file mode 100644 index 00000000..247f7733 --- /dev/null +++ b/test/less/errors/percentage-missing-space.less @@ -0,0 +1,3 @@ +.a { + error: calc(1 %); +} \ No newline at end of file diff --git a/test/less/errors/percentage-missing-space.txt b/test/less/errors/percentage-missing-space.txt new file mode 100644 index 00000000..776d8d5d --- /dev/null +++ b/test/less/errors/percentage-missing-space.txt @@ -0,0 +1,4 @@ +SyntaxError: Invalid % without number in {path}percentage-missing-space.less on line 2, column 3: +1 .a { +2 error: calc(1 %); +3 } diff --git a/test/less/errors/property-asterisk-only-name.less b/test/less/errors/property-asterisk-only-name.less new file mode 100644 index 00000000..c6a9990c --- /dev/null +++ b/test/less/errors/property-asterisk-only-name.less @@ -0,0 +1,3 @@ +a { + * : 1; +} \ No newline at end of file diff --git a/test/less/errors/property-asterisk-only-name.txt b/test/less/errors/property-asterisk-only-name.txt new file mode 100644 index 00000000..6adc6c69 --- /dev/null +++ b/test/less/errors/property-asterisk-only-name.txt @@ -0,0 +1,4 @@ +ParseError: Unrecognised input in {path}property-asterisk-only-name.less on line 2, column 5: +1 a { +2 * : 1; +3 } diff --git a/test/less/errors/property-ie5-hack.less b/test/less/errors/property-ie5-hack.less new file mode 100644 index 00000000..51bf6e39 --- /dev/null +++ b/test/less/errors/property-ie5-hack.less @@ -0,0 +1,3 @@ +.test { + display/*/: block; /*sorry for IE5*/ +} \ No newline at end of file diff --git a/test/less/errors/property-ie5-hack.txt b/test/less/errors/property-ie5-hack.txt new file mode 100644 index 00000000..e42ef90e --- /dev/null +++ b/test/less/errors/property-ie5-hack.txt @@ -0,0 +1,4 @@ +ParseError: Unrecognised input in {path}property-ie5-hack.less on line 2, column 3: +1 .test { +2 display/*/: block; /*sorry for IE5*/ +3 } diff --git a/test/less/errors/property-in-root.less b/test/less/errors/property-in-root.less new file mode 100644 index 00000000..8fed4be3 --- /dev/null +++ b/test/less/errors/property-in-root.less @@ -0,0 +1,4 @@ +.a() { + prop:1; +} +.a(); \ No newline at end of file diff --git a/test/less/errors/property-in-root.txt b/test/less/errors/property-in-root.txt new file mode 100644 index 00000000..04b27766 --- /dev/null +++ b/test/less/errors/property-in-root.txt @@ -0,0 +1,4 @@ +SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}property-in-root.less on line 2, column 3: +1 .a() { +2 prop:1; +3 } diff --git a/test/less/errors/property-in-root2.less b/test/less/errors/property-in-root2.less new file mode 100644 index 00000000..ce8656d1 --- /dev/null +++ b/test/less/errors/property-in-root2.less @@ -0,0 +1 @@ +@import "property-in-root"; \ No newline at end of file diff --git a/test/less/errors/property-in-root2.txt b/test/less/errors/property-in-root2.txt new file mode 100644 index 00000000..04b27766 --- /dev/null +++ b/test/less/errors/property-in-root2.txt @@ -0,0 +1,4 @@ +SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}property-in-root.less on line 2, column 3: +1 .a() { +2 prop:1; +3 } diff --git a/test/less/errors/property-in-root3.less b/test/less/errors/property-in-root3.less new file mode 100644 index 00000000..056c2f72 --- /dev/null +++ b/test/less/errors/property-in-root3.less @@ -0,0 +1,4 @@ +prop:1; +.a { + prop:1; +} \ No newline at end of file diff --git a/test/less/errors/property-in-root3.txt b/test/less/errors/property-in-root3.txt new file mode 100644 index 00000000..68ef9454 --- /dev/null +++ b/test/less/errors/property-in-root3.txt @@ -0,0 +1,3 @@ +SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}property-in-root3.less on line 1, column 1: +1 prop:1; +2 .a { diff --git a/test/less/errors/property-interp-not-defined.less b/test/less/errors/property-interp-not-defined.less new file mode 100644 index 00000000..544fd5f9 --- /dev/null +++ b/test/less/errors/property-interp-not-defined.less @@ -0,0 +1 @@ +a {outline-@{color}: green} \ No newline at end of file diff --git a/test/less/errors/property-interp-not-defined.txt b/test/less/errors/property-interp-not-defined.txt new file mode 100644 index 00000000..2537f9ea --- /dev/null +++ b/test/less/errors/property-interp-not-defined.txt @@ -0,0 +1,2 @@ +NameError: variable @color is undefined in {path}property-interp-not-defined.less on line 1, column 12: +1 a {outline-@{color}: green} diff --git a/test/less/errors/recursive-variable.less b/test/less/errors/recursive-variable.less new file mode 100644 index 00000000..c1ca75f1 --- /dev/null +++ b/test/less/errors/recursive-variable.less @@ -0,0 +1 @@ +@bodyColor: darken(@bodyColor, 30%); \ No newline at end of file diff --git a/test/less/errors/recursive-variable.txt b/test/less/errors/recursive-variable.txt new file mode 100644 index 00000000..eb616e7d --- /dev/null +++ b/test/less/errors/recursive-variable.txt @@ -0,0 +1,2 @@ +NameError: Recursive variable definition for @bodyColor in {path}recursive-variable.less on line 1, column 20: +1 @bodyColor: darken(@bodyColor, 30%); diff --git a/test/less/errors/svg-gradient1.less b/test/less/errors/svg-gradient1.less new file mode 100644 index 00000000..c069ff72 --- /dev/null +++ b/test/less/errors/svg-gradient1.less @@ -0,0 +1,3 @@ +.a { + a: svg-gradient(horizontal, black, white); +} \ No newline at end of file diff --git a/test/less/errors/svg-gradient1.txt b/test/less/errors/svg-gradient1.txt new file mode 100644 index 00000000..ec662fe6 --- /dev/null +++ b/test/less/errors/svg-gradient1.txt @@ -0,0 +1,4 @@ +ArgumentError: error evaluating function `svg-gradient`: svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center' in {path}svg-gradient1.less on line 2, column 6: +1 .a { +2 a: svg-gradient(horizontal, black, white); +3 } diff --git a/test/less/errors/svg-gradient2.less b/test/less/errors/svg-gradient2.less new file mode 100644 index 00000000..ff14ef11 --- /dev/null +++ b/test/less/errors/svg-gradient2.less @@ -0,0 +1,3 @@ +.a { + a: svg-gradient(to bottom, black, orange, 45%, white); +} \ No newline at end of file diff --git a/test/less/errors/svg-gradient2.txt b/test/less/errors/svg-gradient2.txt new file mode 100644 index 00000000..7004115f --- /dev/null +++ b/test/less/errors/svg-gradient2.txt @@ -0,0 +1,4 @@ +ArgumentError: error evaluating function `svg-gradient`: svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position] in {path}svg-gradient2.less on line 2, column 6: +1 .a { +2 a: svg-gradient(to bottom, black, orange, 45%, white); +3 } diff --git a/test/less/errors/svg-gradient3.less b/test/less/errors/svg-gradient3.less new file mode 100644 index 00000000..8f185246 --- /dev/null +++ b/test/less/errors/svg-gradient3.less @@ -0,0 +1,3 @@ +.a { + a: svg-gradient(black, orange); +} \ No newline at end of file diff --git a/test/less/errors/svg-gradient3.txt b/test/less/errors/svg-gradient3.txt new file mode 100644 index 00000000..eb0b483e --- /dev/null +++ b/test/less/errors/svg-gradient3.txt @@ -0,0 +1,4 @@ +ArgumentError: error evaluating function `svg-gradient`: svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position] in {path}svg-gradient3.less on line 2, column 6: +1 .a { +2 a: svg-gradient(black, orange); +3 } diff --git a/test/less/errors/unit-function.less b/test/less/errors/unit-function.less new file mode 100644 index 00000000..119e9818 --- /dev/null +++ b/test/less/errors/unit-function.less @@ -0,0 +1,3 @@ +.a { + font-size: unit(80/16,rem); +} \ No newline at end of file diff --git a/test/less/errors/unit-function.txt b/test/less/errors/unit-function.txt new file mode 100644 index 00000000..baf90f42 --- /dev/null +++ b/test/less/errors/unit-function.txt @@ -0,0 +1,4 @@ +ArgumentError: error evaluating function `unit`: the first argument to unit must be a number. Have you forgotten parenthesis? in {path}unit-function.less on line 2, column 14: +1 .a { +2 font-size: unit(80/16,rem); +3 } diff --git a/test/less/extend-chaining.less b/test/less/extend-chaining.less new file mode 100644 index 00000000..aad221ea --- /dev/null +++ b/test/less/extend-chaining.less @@ -0,0 +1,91 @@ +//very simple chaining +.a { + color: black; +} +.b:extend(.a) {} +.c:extend(.b) {} + +//very simple chaining, ordering not important + +.d:extend(.e) {} +.e:extend(.f) {} +.f { + color: black; +} + +//extend with all + +.g.h { + color: black; +} +.i.j:extend(.g all) { + color: white; +} +.k:extend(.i all) {} + +//extend multi-chaining + +.l { + color: black; +} +.m:extend(.l){} +.n:extend(.m){} +.o:extend(.n){} +.p:extend(.o){} +.q:extend(.p){} +.r:extend(.q){} +.s:extend(.r){} +.t:extend(.s){} + +// self referencing is ignored + +.u {color: black;} +.v.u.v:extend(.u all){} + +// circular reference because the new extend product will match the existing extend + +.w:extend(.w) {color: black;} +.v.w.v:extend(.w all){} + +// classic circular references + +.x:extend(.z) { + color: x; +} +.y:extend(.x) { + color: y; +} +.z:extend(.y) { + color: z; +} + +//very simple chaining, but with the extend inside the ruleset +.va { + color: black; +} +.vb { + &:extend(.va); + color: white; +} +.vc { + &:extend(.vb); +} + +// media queries - dont extend outside, do extend inside + +@media tv { + .ma:extend(.a,.b,.c,.d,.e,.f,.g,.h,.i,.j,.k,.l,.m,.n,.o,.p,.q,.r,.s,.t,.u,.v,.w,.x,.y,.z,.md) { + color: black; + } + .md { + color: white; + } + @media plasma { + .me, .mf { + &:extend(.mb,.md); + background: red; + } + } +} +.mb:extend(.ma) {}; +.mc:extend(.mb) {}; \ No newline at end of file diff --git a/test/less/extend-clearfix.less b/test/less/extend-clearfix.less new file mode 100644 index 00000000..82445dfa --- /dev/null +++ b/test/less/extend-clearfix.less @@ -0,0 +1,19 @@ +.clearfix { + *zoom: 1; + &:after { + content: ''; + display: block; + clear: both; + height: 0; + } +} + +.foo { + &:extend(.clearfix all); + color: red; +} + +.bar { + &:extend(.clearfix all); + color: blue; +} diff --git a/test/less/extend-exact.less b/test/less/extend-exact.less new file mode 100644 index 00000000..41dc4130 --- /dev/null +++ b/test/less/extend-exact.less @@ -0,0 +1,46 @@ +.replace.replace, +.c.replace + .replace { + .replace, + .c { + prop: copy-paste-replace; + } +} +.rep_ace:extend(.replace.replace .replace) {} + +.a .b .c { + prop: not_effected; +} + +.a { + prop: is_effected; + .b { + prop: not_effected; + } + .b.c { + prop: not_effected; + } +} + +.c, .a { + .b, .a { + .a, .c { + prop: not_effected; + } + } +} + +.effected { + &:extend(.a); + &:extend(.b); + &:extend(.c); +} + +.e { + && { + prop: extend-double; + &:hover { + hover: not-extended; + } + } +} +.dbl:extend(.e.e) {} diff --git a/test/less/extend-media.less b/test/less/extend-media.less new file mode 100644 index 00000000..1b22c3fa --- /dev/null +++ b/test/less/extend-media.less @@ -0,0 +1,24 @@ +.ext1 .ext2 { + background: black; +} + +@media tv { + .ext1 .ext3 { + color: white; + } + .tv-lowres :extend(.ext1 all) { + background: blue; + } + @media hires { + .ext1 .ext4 { + color: green; + } + .tv-hires :extend(.ext1 all) { + background: red; + } + } +} + +.all:extend(.ext1 all) { + +} \ No newline at end of file diff --git a/test/less/extend-nest.less b/test/less/extend-nest.less new file mode 100644 index 00000000..9d4d27bb --- /dev/null +++ b/test/less/extend-nest.less @@ -0,0 +1,65 @@ +.sidebar { + width: 300px; + background: red; + + .box { + background: #FFF; + border: 1px solid #000; + margin: 10px 0; + } +} + +.sidebar2 { + &:extend(.sidebar all); + background: blue; +} + +.type1 { + .sidebar3 { + &:extend(.sidebar all); + background: green; + } +} + +.type2 { + &.sidebar4 { + &:extend(.sidebar all); + background: red; + } +} + +.button { + color: black; + &:hover { + color: white; + } +} +.submit { + &:extend(.button); + &:hover:extend(.button:hover) {} +} + +.nomatch { + &:hover:extend(.button :hover) {} +} + +.button2 { + :hover { + nested: white; + } +} +.button2 :hover { + notnested: black; +} + +.nomatch :extend(.button2:hover) {} + +.amp-test-a, +.amp-test-b { + .amp-test-c &.amp-test-d&.amp-test-e { + .amp-test-f&+&.amp-test-g:extend(.amp-test-h) {} + } +} +.amp-test-h { + test: extended by masses of selectors; +} \ No newline at end of file diff --git a/test/less/extend-selector.less b/test/less/extend-selector.less new file mode 100644 index 00000000..c7588ee0 --- /dev/null +++ b/test/less/extend-selector.less @@ -0,0 +1,99 @@ +.error { + border: 1px #f00; + background: #fdd; +} +.error.intrusion { + font-size: 1.3em; + font-weight: bold; +} +.intrusion .error { + display: none; +} +.badError:extend(.error all) { + border-width: 3px; +} + +.foo .bar, .foo .baz { + display: none; +} + +.ext1 .ext2 + :extend(.foo all) { +} + +.ext3:extend(.foo all), +.ext4:extend(.foo all) { +} + +div.ext5, +.ext6 > .ext5 { + width: 100px; +} + +.should-not-exist-in-output, +.ext7:extend(.ext5 all) { +} + +.ext { + test: 1; +} +// same as +// .a .c:extend(.ext all) +// .b .c:extend(.ext all) +// .a .c .d +// .b .c .d +.a, .b { + test: 2; + .c:extend(.ext all) { + test: 3; + .d { + test: 4; + } + } +} + +.replace.replace, +.c.replace + .replace { + .replace, + .c { + prop: copy-paste-replace; + } +} +.rep_ace:extend(.replace all) {} + +.attributes { + [data="test"] { + extend: attributes; + } + .attribute-test { + &:extend([data="test"] all); + } + [data] { + extend: attributes2; + } + .attribute-test2 { + &:extend([data] all); //you could argue it should match [data="test"]... not for now though... + } + @attr-data: "test3"; + [data=@{attr-data}] { + extend: attributes2; + } + .attribute-test { + &:extend([data="test3"] all); + } +} + +.header { + .header-nav { + background: red; + &:before { + background: blue; + } + } +} + +.footer { + .footer-nav { + &:extend( .header .header-nav all ); + } +} \ No newline at end of file diff --git a/test/less/extend.less b/test/less/extend.less new file mode 100644 index 00000000..1db5d431 --- /dev/null +++ b/test/less/extend.less @@ -0,0 +1,81 @@ +.error { + border: 1px #f00; + background: #fdd; +} +.error.intrusion { + font-size: 1.3em; + font-weight: bold; +} +.intrusion .error { + display: none; +} +.badError { + &:extend(.error all); + border-width: 3px; +} + +.foo .bar, .foo .baz { + display: none; +} + +.ext1 .ext2 { + &:extend(.foo all); +} + +.ext3, +.ext4 { + &:extend(.foo all); + &:extend(.bar all); +} + +div.ext5, +.ext6 > .ext5 { + width: 100px; +} + +.ext7 { + &:extend(.ext5 all); +} + +.ext8.ext9 { + result: add-foo; +} +.ext8 .ext9, +.ext8 + .ext9, +.ext8 > .ext9 { + result: bar-matched; +} +.ext8.nomatch { + result: none; +} +.ext8 { + .ext9 { + result: match-nested-bar; + } +} +.ext8 { + &.ext9 { + result: match-nested-foo; + } +} + +.fuu:extend(.ext8.ext9 all) {} +.buu:extend(.ext8 .ext9 all) {} +.zap:extend(.ext8 + .ext9 all) {} +.zoo:extend(.ext8 > .ext9 all) {} + +.aa { + color: black; + .dd { + background: red; + } +} +.bb { + background: red; + .bb { + color: black; + } +} +.cc:extend(.aa,.bb) {} +.ee:extend(.dd all,.bb) {} +.ff:extend(.dd,.bb all) {} \ No newline at end of file diff --git a/test/less/extract-and-length.less b/test/less/extract-and-length.less new file mode 100644 index 00000000..d81e118f --- /dev/null +++ b/test/less/extract-and-length.less @@ -0,0 +1,133 @@ + +// simple array/list: + +.multiunit { + @v: abc "abc" 1 1px 1% #123; + length: length(@v); + extract: extract(@v, 1) extract(@v, 2) extract(@v, 3) extract(@v, 4) extract(@v, 5) extract(@v, 6); +} + +.incorrect-index { + @v1: a b c; + @v2: a, b, c; + v1: extract(@v1, 5); + v2: extract(@v2, -2); +} + +.scalar { + @var: variable; + var-value: extract(@var, 1); + var-length: length(@var); + ill-index: extract(@var, 2); + + name-value: extract(name, 1); + string-value: extract("string", 1); + number-value: extract(12345678, 1); + color-value: extract(blue, 1); + rgba-value: extract(rgba(80, 160, 240, 0.67), 1); + empty-value: extract(~'', 1); + + name-length: length(name); + string-length: length("string"); + number-length: length(12345678); + color-length: length(blue); + rgba-length: length(rgba(80, 160, 240, 0.67)); + empty-length: length(~''); +} + +.mixin-arguments { + .mixin-args(a b c d); + .mixin-args(a, b, c, d); + .mixin-args(1; 2; 3; 4); +} + +.mixin-args(@value) { + &-1 { + length: length(@value); + extract: extract(@value, 3) ~"|" extract(@value, 2) ~"|" extract(@value, 1); + } +} + +.mixin-args(...) { + &-2 { + length: length(@arguments); + extract: extract(@arguments, 3) ~"|" extract(@arguments, 2) ~"|" extract(@arguments, 1); + } +} + +.mixin-args(@values...) { + &-3 { + length: length(@values); + extract: extract(@values, 3) ~"|" extract(@values, 2) ~"|" extract(@values, 1); + } +} + +.mixin-args(@head, @tail...) { + &-4 { + length: length(@tail); + extract: extract(@tail, 2) ~"|" extract(@tail, 1); + } +} + +// "multidimensional" array/list + +.md-space-comma { + @v: a b c, 1 2 3, "x" "y" "z"; + length-1: length(@v); + extract-1: extract(@v, 2); + length-2: length(extract(@v, 2)); + extract-2: extract(extract(@v, 2), 2); + + &-as-args {.mixin-args(a b c, 1 2 3, "x" "y" "z")} +} + +.md-cat-space-comma { + @a: a b c; + @b: 1 2 3; + @c: "x" "y" "z"; + @v: @a, @b, @c; + length-1: length(@v); + extract-1: extract(@v, 2); + length-2: length(extract(@v, 2)); + extract-2: extract(extract(@v, 2), 2); + + &-as-args {.mixin-args(@a, @b, @c)} +} + +.md-cat-comma-space { + @a: a, b, c; + @b: 1, 2, 3; + @c: "x", "y", "z"; + @v: @a @b @c; + length-1: length(@v); + extract-1: extract(@v, 2); + length-2: length(extract(@v, 2)); + extract-2: extract(extract(@v, 2), 2); + + &-as-args {.mixin-args(@a @b @c)} +} + +.md-3D { + @a: a b c d, 1 2 3 4; + @b: 5 6 7 8, e f g h; + .3D(@a, @b); + + .3D(...) { + + @v1: @arguments; + length-1: length(@v1); + extract-1: extract(@v1, 1); + + @v2: extract(@v1, 2); + length-2: length(@v2); + extract-2: extract(@v2, 1); + + @v3: extract(@v2, 1); + length-3: length(@v3); + extract-3: extract(@v3, 3); + + @v4: extract(@v3, 4); + length-4: length(@v4); + extract-4: extract(@v4, 1); + } +} diff --git a/test/less/functions.less b/test/less/functions.less new file mode 100644 index 00000000..4b4720d9 --- /dev/null +++ b/test/less/functions.less @@ -0,0 +1,173 @@ +#functions { + @var: 10; + @colors: #000, #fff; + color: _color("evil red"); // #660000 + width: increment(15); + height: undefined("self"); + border-width: add(2, 3); + variable: increment(@var); + background: linear-gradient(@colors); +} + +#built-in { + @r: 32; + escaped: e("-Some::weird(#thing, y)"); + lighten: lighten(#ff0000, 40%); + darken: darken(#ff0000, 40%); + saturate: saturate(#29332f, 20%); + desaturate: desaturate(#203c31, 20%); + greyscale: greyscale(#203c31); + hsl-clamp: hsl(380, 150%, 150%); + spin-p: spin(hsl(340, 50%, 50%), 40); + spin-n: spin(hsl(30, 50%, 50%), -40); + luma-white: luma(#fff); + luma-black: luma(#000); + luma-black-alpha: luma(rgba(0,0,0,0.5)); + luma-red: luma(#ff0000); + luma-green: luma(#00ff00); + luma-blue: luma(#0000ff); + luma-yellow: luma(#ffff00); + luma-cyan: luma(#00ffff); + luma-differs-from-luminance: luma(#ff3600); + luminance-white: luma(#fff); + luminance-black: luma(#000); + luminance-black-alpha: luma(rgba(0,0,0,0.5)); + luminance-red: luma(#ff0000); + luminance-differs-from-luma: luminance(#ff3600); + contrast-filter: contrast(30%); + saturate-filter: saturate(5%); + contrast-white: contrast(#fff); + contrast-black: contrast(#000); + contrast-red: contrast(#ff0000); + contrast-green: contrast(#00ff00); + contrast-blue: contrast(#0000ff); + contrast-yellow: contrast(#ffff00); + contrast-cyan: contrast(#00ffff); + contrast-light: contrast(#fff, #111111, #eeeeee); + contrast-dark: contrast(#000, #111111, #eeeeee); + contrast-wrongorder: contrast(#fff, #eeeeee, #111111, 0.5); + contrast-light-thresh: contrast(#fff, #111111, #eeeeee, 0.5); + contrast-dark-thresh: contrast(#000, #111111, #eeeeee, 0.5); + contrast-high-thresh: contrast(#555, #111111, #eeeeee, 0.6); + contrast-low-thresh: contrast(#555, #111111, #eeeeee, 0.09); + contrast-light-thresh-per: contrast(#fff, #111111, #eeeeee, 50%); + contrast-dark-thresh-per: contrast(#000, #111111, #eeeeee, 50%); + contrast-high-thresh-per: contrast(#555, #111111, #eeeeee, 60%); + contrast-low-thresh-per: contrast(#555, #111111, #eeeeee, 9%); + replace: replace("Hello, Mars.", "Mars\.", "World!"); + replace-captured: replace("This is a string.", "(string)\.$", "new $1."); + replace-with-flags: replace("One + one = 4", "one", "2", "gi"); + replace-single-quoted: replace('foo-1', "1", "2"); + replace-escaped-string: replace(~"bar-1", "1", "2"); + replace-keyword: replace(baz-1, "1", "2"); + format: %("rgb(%d, %d, %d)", @r, 128, 64); + format-string: %("hello %s", "world"); + format-multiple: %("hello %s %d", "earth", 2); + format-url-encode: %("red is %A", #ff0000); + format-single-quoted: %('hello %s', "single world"); + format-escaped-string: %(~"hello %s", "escaped world"); + eformat: e(%("rgb(%d, %d, %d)", @r, 128, 64)); + + unitless: unit(12px); + unit: unit((13px + 1px), em); + unitpercentage: unit(100, %); + + get-unit: get-unit(10px); + get-unit-empty: get-unit(10); + + hue: hue(hsl(98, 12%, 95%)); + saturation: saturation(hsl(98, 12%, 95%)); + lightness: lightness(hsl(98, 12%, 95%)); + hsvhue: hsvhue(hsv(98, 12%, 95%)); + hsvsaturation: hsvsaturation(hsv(98, 12%, 95%)); + hsvvalue: hsvvalue(hsv(98, 12%, 95%)); + red: red(#f00); + green: green(#0f0); + blue: blue(#00f); + rounded: round((@r/3)); + rounded-two: round((@r/3), 2); + roundedpx: round((10px / 3)); + roundedpx-three: round((10px / 3), 3); + rounded-percentage: round(10.2%); + ceil: ceil(10.1px); + floor: floor(12.9px); + sqrt: sqrt(25px); + pi: pi(); + mod: mod(13m, 11cm); // could take into account units, doesn't at the moment + abs: abs(-4%); + tan: tan(42deg); + sin: sin(10deg); + cos: cos(12); + atan: atan(tan(0.1rad)); + atan: convert(acos(cos(34deg)), deg); + atan: convert(acos(cos(50grad)), deg); + pow: pow(8px, 2); + pow: pow(4, 3); + pow: pow(3, 3em); + min: min(0); + min: min(6, 5); + min: min(1pt, 3pt); + min: min(1cm, 3mm); + max: max(1, 3); + max: max(3em, 1em, 2em, 5em); + percentage: percentage((10px / 50)); + color: color("#ff0011"); + tint: tint(#777777, 13); + tint-full: tint(#777777, 100); + tint-percent: tint(#777777, 13%); + tint-negative: tint(#777777, -13%); + shade: shade(#777777, 13); + shade-full: shade(#777777, 100); + shade-percent: shade(#777777, 13%); + shade-negative: shade(#777777, -13%); + + fade-out: fadeOut(red, 5%); // support fadeOut and fadeout + fade-in: fadein(fadeout(red, 10%), 5%); + + hsv: hsv(5, 50%, 30%); + hsva: hsva(3, 50%, 30%, 0.2); + + mix: mix(#ff0000, #ffff00, 80); + mix-0: mix(#ff0000, #ffff00, 0); + mix-100: mix(#ff0000, #ffff00, 100); + mix-weightless: mix(#ff0000, #ffff00); + mixt: mix(#ff0000, transparent); + + .is-a { + color: iscolor(#ddd); + color1: iscolor(red); + color2: iscolor(rgb(0, 0, 0)); + color3: iscolor(transparent); + keyword: iskeyword(hello); + number: isnumber(32); + string: isstring("hello"); + pixel: ispixel(32px); + percent: ispercentage(32%); + em: isem(32em); + cat: isunit(32cat, cat); + } +} + +#alpha { + alpha: darken(hsla(25, 50%, 50%, 0.6), 10%); + alpha2: alpha(rgba(3, 4, 5, 0.5)); + alpha3: alpha(transparent); +} + +#blendmodes { + multiply: multiply(#f60000, #f60000); + screen: screen(#f60000, #0000f6); + overlay: overlay(#f60000, #0000f6); + softlight: softlight(#f60000, #ffffff); + hardlight: hardlight(#f60000, #0000f6); + difference: difference(#f60000, #0000f6); + exclusion: exclusion(#f60000, #0000f6); + average: average(#f60000, #0000f6); + negation: negation(#f60000, #313131); +} + +#extract-and-length { + @anon: A B C 1 2 3; + extract: extract(@anon, 6) extract(@anon, 5) extract(@anon, 4) extract(@anon, 3) extract(@anon, 2) extract(@anon, 1); + length: length(@anon); +} diff --git a/test/less/globalVars/extended.json b/test/less/globalVars/extended.json new file mode 100644 index 00000000..6bd2a484 --- /dev/null +++ b/test/less/globalVars/extended.json @@ -0,0 +1,5 @@ +{ + "the-border": "1px", + "base-color": "#111", + "red": "#842210" +} \ No newline at end of file diff --git a/test/less/globalVars/extended.less b/test/less/globalVars/extended.less new file mode 100644 index 00000000..7a3bf291 --- /dev/null +++ b/test/less/globalVars/extended.less @@ -0,0 +1,10 @@ +#header { + color: (@base-color * 3); + border-left: @the-border; + border-right: (@the-border * 2); +} +#footer { + color: (@base-color + #003300); + border-color: @red; +} +@red: desaturate(red, 10%); // less file overrides passed in color <- note line comment on last line to check it is okay \ No newline at end of file diff --git a/test/less/globalVars/simple.json b/test/less/globalVars/simple.json new file mode 100644 index 00000000..76a63c5a --- /dev/null +++ b/test/less/globalVars/simple.json @@ -0,0 +1,3 @@ +{ + "my-color": "red" +} \ No newline at end of file diff --git a/test/less/globalVars/simple.less b/test/less/globalVars/simple.less new file mode 100644 index 00000000..c3c5e3b8 --- /dev/null +++ b/test/less/globalVars/simple.less @@ -0,0 +1,3 @@ +.class { + color: @my-color; +} \ No newline at end of file diff --git a/test/less/ie-filters.less b/test/less/ie-filters.less new file mode 100644 index 00000000..3350b653 --- /dev/null +++ b/test/less/ie-filters.less @@ -0,0 +1,15 @@ +@fat: 0; +@cloudhead: "#000000"; + +.nav { + filter: progid:DXImageTransform.Microsoft.Alpha(opacity = 20); + filter: progid:DXImageTransform.Microsoft.Alpha(opacity=@fat); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#333333", endColorstr=@cloudhead, GradientType=@fat); +} +.evalTest(@arg) { + filter: progid:DXImageTransform.Microsoft.Alpha(opacity=@arg); +} +.evalTest1 { + .evalTest(30); + .evalTest(5); +} \ No newline at end of file diff --git a/test/less/import-inline.less b/test/less/import-inline.less new file mode 100644 index 00000000..95a11896 --- /dev/null +++ b/test/less/import-inline.less @@ -0,0 +1,2 @@ +@import (inline) url("import/import-test-d.css") (min-width:600px); +@import (inline, css) url("import/invalid-css.less"); \ No newline at end of file diff --git a/test/less/import-interpolation.less b/test/less/import-interpolation.less new file mode 100644 index 00000000..21cfe086 --- /dev/null +++ b/test/less/import-interpolation.less @@ -0,0 +1,8 @@ +@my_theme: "test"; + +@import "import/import-@{my_theme}-e.less"; + +@import "import/import-@{in}@{terpolation}.less"; + +@in: "in"; +@terpolation: "terpolation"; \ No newline at end of file diff --git a/test/less/import-once.less b/test/less/import-once.less new file mode 100644 index 00000000..0a4024a3 --- /dev/null +++ b/test/less/import-once.less @@ -0,0 +1,6 @@ +@import "import/import-once-test-c"; +@import "import/import-once-test-c"; +@import "import/import-once-test-c.less"; +@import "import/deeper/import-once-test-a"; +@import (multiple) "import/import-test-f.less"; +@import (multiple) "import/import-test-f.less"; \ No newline at end of file diff --git a/test/less/import-reference.less b/test/less/import-reference.less new file mode 100644 index 00000000..93160ab5 --- /dev/null +++ b/test/less/import-reference.less @@ -0,0 +1,21 @@ +@import (reference) url("import-once.less"); +@import (reference) url("css-3.less"); +@import (reference) url("media.less"); +@import (reference) url("import/import-reference.less"); + +.b { + .z(); +} + +.zz(); + +.visible:extend(.z all) { + extend: test; +} + +.test-mediaq-import { + .mixin-with-mediaq(340px); +} + +.class:extend(.class all) { +} \ No newline at end of file diff --git a/test/less/import.less b/test/less/import.less new file mode 100644 index 00000000..01689408 --- /dev/null +++ b/test/less/import.less @@ -0,0 +1,21 @@ +@import url(http://fonts.googleapis.com/css?family=Open+Sans); + +@import url(/absolute/something.css) screen and (color) and (max-width: 600px); + +@var: 100px; +@import url("//ha.com/file.css") (min-width:@var); + +#import-test { + .mixin; + width: 10px; + height: (@a + 10%); +} +@import "import/import-test-e" screen and (max-width: 600px); + +@import url("import/import-test-a.less"); + +@import (less, multiple) "import/import-test-d.css" screen and (max-width: 601px); + +@import (multiple) "import/import-test-e" screen and (max-width: 602px); + +@import (less, multiple) url("import/import-test-d.css") screen and (max-width: 603px); \ No newline at end of file diff --git a/test/less/import/deeper/import-once-test-a.less b/test/less/import/deeper/import-once-test-a.less new file mode 100644 index 00000000..8a747fc0 --- /dev/null +++ b/test/less/import/deeper/import-once-test-a.less @@ -0,0 +1 @@ +@import "../import-once-test-c"; \ No newline at end of file diff --git a/test/less/import/import-and-relative-paths-test.less b/test/less/import/import-and-relative-paths-test.less new file mode 100644 index 00000000..d6256c6b --- /dev/null +++ b/test/less/import/import-and-relative-paths-test.less @@ -0,0 +1,17 @@ +@import "../css/background.css"; +@import "import-test-d.css"; + +@import "imports/logo"; +@import "imports/font"; + +.unquoted-relative-path-bg() { + background-image: url(../../data/image.jpg); +} +.quoted-relative-path-border-image() { + border-image: url('../../data/image.jpg'); +} + +#imported-relative-path { + .unquoted-relative-path-bg; + .quoted-relative-path-border-image; +} \ No newline at end of file diff --git a/test/less/import/import-charset-test.less b/test/less/import/import-charset-test.less new file mode 100644 index 00000000..07a66e1a --- /dev/null +++ b/test/less/import/import-charset-test.less @@ -0,0 +1 @@ +@charset "ISO-8859-1"; \ No newline at end of file diff --git a/test/less/import/import-interpolation.less b/test/less/import/import-interpolation.less new file mode 100644 index 00000000..aa49a702 --- /dev/null +++ b/test/less/import/import-interpolation.less @@ -0,0 +1 @@ +@import "import-@{in}@{terpolation}2.less"; \ No newline at end of file diff --git a/test/less/import/import-interpolation2.less b/test/less/import/import-interpolation2.less new file mode 100644 index 00000000..12bfb4e1 --- /dev/null +++ b/test/less/import/import-interpolation2.less @@ -0,0 +1,5 @@ +.a { + var: test; +} + +@in: "redefined-does-nothing"; \ No newline at end of file diff --git a/test/less/import/import-once-test-c.less b/test/less/import/import-once-test-c.less new file mode 100644 index 00000000..686747a8 --- /dev/null +++ b/test/less/import/import-once-test-c.less @@ -0,0 +1,6 @@ + +@c: red; + +#import { + color: @c; +} diff --git a/test/less/import/import-reference.less b/test/less/import/import-reference.less new file mode 100644 index 00000000..c77f692e --- /dev/null +++ b/test/less/import/import-reference.less @@ -0,0 +1,51 @@ +.z { + color: red; + .c { + color: green; + } +} +.only-with-visible, +.z { + color: green; + &:hover { + color: green; + } + & { + color: green; + } + & + & { + color: green; + .sub { + color: green; + } + } +} + +& { + .hidden { + hidden: true; + } +} + +@media tv { + .hidden { + hidden: true; + } +} + +/* comment is not output */ + +.zz { + .y { + pulled-in: yes; + } + /* comment pulled in */ +} +@max-size: 450px; +.mixin-with-mediaq(@num) { + color: green; + test: @num; + @media (max-size: @max-size) { + color: red; + } +} \ No newline at end of file diff --git a/test/less/import/import-test-a.less b/test/less/import/import-test-a.less new file mode 100644 index 00000000..b3b3b8fc --- /dev/null +++ b/test/less/import/import-test-a.less @@ -0,0 +1,3 @@ +@import "import-test-b.less"; +@a: 20%; +@import "urls.less"; \ No newline at end of file diff --git a/test/less/import/import-test-b.less b/test/less/import/import-test-b.less new file mode 100644 index 00000000..ce2d35a8 --- /dev/null +++ b/test/less/import/import-test-b.less @@ -0,0 +1,8 @@ +@import "import-test-c"; + +@b: 100%; + +.mixin { + height: 10px; + color: @c; +} diff --git a/test/less/import/import-test-c.less b/test/less/import/import-test-c.less new file mode 100644 index 00000000..686747a8 --- /dev/null +++ b/test/less/import/import-test-c.less @@ -0,0 +1,6 @@ + +@c: red; + +#import { + color: @c; +} diff --git a/test/less/import/import-test-d.css b/test/less/import/import-test-d.css new file mode 100644 index 00000000..30575f01 --- /dev/null +++ b/test/less/import/import-test-d.css @@ -0,0 +1 @@ +#css { color: yellow; } diff --git a/test/less/import/import-test-e.less b/test/less/import/import-test-e.less new file mode 100644 index 00000000..98b84b0a --- /dev/null +++ b/test/less/import/import-test-e.less @@ -0,0 +1,2 @@ + +body { width: 100% } diff --git a/test/less/import/import-test-f.less b/test/less/import/import-test-f.less new file mode 100644 index 00000000..fad630f9 --- /dev/null +++ b/test/less/import/import-test-f.less @@ -0,0 +1,5 @@ +@import "import-test-e"; + +.test-f { + height: 10px; +} diff --git a/test/less/import/imports/font.less b/test/less/import/imports/font.less new file mode 100644 index 00000000..5abb7e76 --- /dev/null +++ b/test/less/import/imports/font.less @@ -0,0 +1,8 @@ +@font-face { + font-family: xecret; + src: url('../assets/xecret.ttf'); +} + +#secret { + font-family: xecret, sans-serif; +} diff --git a/test/less/import/imports/logo.less b/test/less/import/imports/logo.less new file mode 100644 index 00000000..22893a23 --- /dev/null +++ b/test/less/import/imports/logo.less @@ -0,0 +1,5 @@ +#logo { + width: 100px; + height: 100px; + background: url('../assets/logo.png'); +} diff --git a/test/less/import/invalid-css.less b/test/less/import/invalid-css.less new file mode 100644 index 00000000..ed585d63 --- /dev/null +++ b/test/less/import/invalid-css.less @@ -0,0 +1 @@ +this isn't very valid CSS. \ No newline at end of file diff --git a/test/less/import/urls.less b/test/less/import/urls.less new file mode 100644 index 00000000..bb48f77a --- /dev/null +++ b/test/less/import/urls.less @@ -0,0 +1 @@ +// empty file showing that it loads from the relative path first diff --git a/test/less/javascript.less b/test/less/javascript.less new file mode 100644 index 00000000..a8e7eb37 --- /dev/null +++ b/test/less/javascript.less @@ -0,0 +1,38 @@ +.eval { + js: `42`; + js: `1 + 1`; + js: `"hello world"`; + js: `[1, 2, 3]`; + title: `typeof process.title`; + ternary: `(1 + 1 == 2 ? true : false)`; + multiline: `(function(){var x = 1 + 1; + return x})()`; +} +.scope { + @foo: 42; + var: `parseInt(this.foo.toJS())`; + escaped: ~`2 + 5 + 'px'`; +} +.vars { + @var: `4 + 4`; + width: @var; +} +.escape-interpol { + @world: "world"; + width: ~`"hello" + " " + @{world}`; +} +.arrays { + @ary: 1, 2, 3; + @ary2: 1 2 3; + ary: `@{ary}.join(', ')`; + ary1: `@{ary2}.join(', ')`; +} +.transitions(...) { + @arg: ~`"@{arguments}".replace(/[\[\]]*/g, '')`; + 1: @arg; // rounded to integers + 2: ~`"@{arguments}"`; // rounded to integers + 3: @arguments; // OK +} +.test-tran { + .transitions(opacity 0.3s ease-in 0.3s, max-height 0.6s linear, margin-bottom 0.4s linear;); +} diff --git a/test/less/lazy-eval.less b/test/less/lazy-eval.less new file mode 100644 index 00000000..72b3fd46 --- /dev/null +++ b/test/less/lazy-eval.less @@ -0,0 +1,6 @@ +@var: @a; +@a: 100%; + +.lazy-eval { + width: @var; +} diff --git a/test/less/legacy/legacy.less b/test/less/legacy/legacy.less new file mode 100644 index 00000000..92d00088 --- /dev/null +++ b/test/less/legacy/legacy.less @@ -0,0 +1,7 @@ +@media (-o-min-device-pixel-ratio: 2/1) { + .test-math-and-units { + font: ignores 0/0 rules; + test-division: 4 / 2 + 5em; + simple: 1px + 1px; + } +} \ No newline at end of file diff --git a/test/less/media.less b/test/less/media.less new file mode 100644 index 00000000..01a6a020 --- /dev/null +++ b/test/less/media.less @@ -0,0 +1,234 @@ + +// For now, variables can't be declared inside @media blocks. + +@var: 42; + +@media print { + .class { + color: blue; + .sub { + width: @var; + } + } + .top, header > h1 { + color: (#222 * 2); + } +} + +@media screen { + @base: 8; + body { max-width: (@base * 60); } +} + +@ratio_large: 16; +@ratio_small: 9; + +@media all and (device-aspect-ratio: @ratio_large / @ratio_small) { + body { max-width: 800px; } +} + +@media all and (orientation:portrait) { + aside { float: none; } +} + +@media handheld and (min-width: @var), screen and (min-width: 20em) { + body { + max-width: 480px; + } +} + +body { + @media print { + padding: 20px; + + header { + background-color: red; + } + + @media (orientation:landscape) { + margin-left: 20px; + } + } +} + +@media screen { + .sidebar { + width: 300px; + @media (orientation: landscape) { + width: 500px; + } + } +} + +@media a { + .first { + @media b { + .second { + .third { + width: 300px; + @media c { + width: 500px; + } + } + .fourth { + width: 3; + } + } + } + } +} + +body { + @media a, b and c { + width: 95%; + + @media x, y { + width: 100%; + } + } +} + +.mediaMixin(@fallback: 200px) { + background: black; + + @media handheld { + background: white; + + @media (max-width: @fallback) { + background: red; + } + } +} + +.a { + .mediaMixin(100px); +} + +.b { + .mediaMixin(); +} +@smartphone: ~"only screen and (max-width: 200px)"; +@media @smartphone { + body { + width: 480px; + } +} + +@media print { + @page :left { + margin: 0.5cm; + } + @page :right { + margin: 0.5cm; + } + @page Test:first { + margin: 1cm; + } + @page :first { + size: 8.5in 11in; + @top-left { + margin: 1cm; + } + @top-left-corner { + margin: 1cm; + } + @top-center { + margin: 1cm; + } + @top-right { + margin: 1cm; + } + @top-right-corner { + margin: 1cm; + } + @bottom-left { + margin: 1cm; + } + @bottom-left-corner { + margin: 1cm; + } + @bottom-center { + margin: 1cm; + } + @bottom-right { + margin: 1cm; + } + @bottom-right-corner { + margin: 1cm; + } + @left-top { + margin: 1cm; + } + @left-middle { + margin: 1cm; + } + @left-bottom { + margin: 1cm; + } + @right-top { + margin: 1cm; + } + @right-middle { + content: "Page " counter(page); + } + @right-bottom { + margin: 1cm; + } + } +} + +@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2/1), (min-resolution: 2dppx), (min-resolution: 128dpcm) { + .b { + background: red; + } +} + +.bg() { + background: red; + + @media (max-width: 500px) { + background: green; + } +} + +body { + .bg(); +} + +@bpMedium: 1000px; +@media (max-width: @bpMedium) { + body { + .bg(); + background: blue; + } +} + +@media (max-width: 1200px) { + /* a comment */ + + @media (max-width: 900px) { + body { font-size: 11px; } + } +} + +.nav-justified { + @media (min-width: 480px) { + > li { + display: table-cell; + } + } +} + +.menu +{ + @media (min-width: 768px) { + .nav-justified(); + } +} +@all: ~"all"; +@tv: ~"tv"; +@media @all and @tv { + .all-and-tv-variables { + var: all-and-tv; + } +} \ No newline at end of file diff --git a/test/less/merge.less b/test/less/merge.less new file mode 100644 index 00000000..5b5def35 --- /dev/null +++ b/test/less/merge.less @@ -0,0 +1,78 @@ +.first-transform() { + transform+: rotate(90deg), skew(30deg); +} +.second-transform() { + transform+: scale(2,4); +} +.third-transform() { + transform: scaleX(45deg); +} +.fourth-transform() { + transform+: scaleX(45deg); +} +.fifth-transform() { + transform+: scale(2,4) !important; +} +.first-background() { + background+: url(data://img1.png); +} +.second-background() { + background+: url(data://img2.png); +} + +.test1 { + // Can merge values + .first-transform(); + .second-transform(); +} +.test2 { + // Wont merge values without +: merge directive, for backwards compatibility with css + .first-transform(); + .third-transform(); +} +.test3 { + // Wont merge values from two sources with different properties + .fourth-transform(); + .first-background(); +} +.test4 { + // Wont merge values from sources that merked as !important, for backwards compatibility with css + .first-transform(); + .fifth-transform(); +} +.test5 { + // Wont merge values from mixins that merked as !important, for backwards compatibility with css + .first-transform(); + .second-transform() !important; +} +.test6 { + // Ignores !merge if no peers found + .second-transform(); +} + +.test-interleaved { + transform+: t1; + background+: b1; + transform+: t2; + background+: b2, b3; + transform+: t3; +} + +.test-spaced { + transform+_: t1; + background+_: b1; + transform+_: t2; + background+_: b2, b3; + transform+_: t3; +} + +.test-interleaved-with-spaced { + transform+_: t1s; + transform+: t2; + background+: b1; + transform+_: t3s; + transform+: t4 t5s; + background+_: b2s, b3; + transform+_: t6s; + background+: b4; +} diff --git a/test/less/mixins-args.less b/test/less/mixins-args.less new file mode 100644 index 00000000..8cdc67df --- /dev/null +++ b/test/less/mixins-args.less @@ -0,0 +1,215 @@ +.mixin (@a: 1px, @b: 50%) { + width: (@a * 5); + height: (@b - 1%); +} + +.mixina (@style, @width, @color: black) { + border: @width @style @color; +} + +.mixiny +(@a: 0, @b: 0) { + margin: @a; + padding: @b; +} + +.hidden() { + color: transparent; // asd +} + +#hidden { + .hidden; +} + +#hidden1 { + .hidden(); +} + +.two-args { + color: blue; + .mixin(2px, 100%); + .mixina(dotted, 2px); +} + +.one-arg { + .mixin(3px); +} + +.no-parens { + .mixin; +} + +.no-args { + .mixin(); +} + +.var-args { + @var: 9; + .mixin(@var, (@var * 2)); +} + +.multi-mix { + .mixin(2px, 30%); + .mixiny(4, 5); +} + +.maxa(@arg1: 10, @arg2: #f00) { + padding: (@arg1 * 2px); + color: @arg2; +} + +body { + .maxa(15); +} + +@glob: 5; +.global-mixin(@a:2) { + width: (@glob + @a); +} + +.scope-mix { + .global-mixin(3); +} + +.nested-ruleset (@width: 200px) { + width: @width; + .column { margin: @width; } +} +.content { + .nested-ruleset(600px); +} + +// + +.same-var-name2(@radius) { + radius: @radius; +} +.same-var-name(@radius) { + .same-var-name2(@radius); +} +#same-var-name { + .same-var-name(5px); +} + +// + +.var-inside () { + @var: 10px; + width: @var; +} +#var-inside { .var-inside; } + +.mixin-arguments (@width: 0px, ...) { + border: @arguments; + width: @width; +} + +.arguments { + .mixin-arguments(1px, solid, black); +} +.arguments2 { + .mixin-arguments(); +} +.arguments3 { + .mixin-arguments; +} + +.mixin-arguments2 (@width, @rest...) { + border: @arguments; + rest: @rest; + width: @width; +} +.arguments4 { + .mixin-arguments2(0, 1, 2, 3, 4); +} + +// Edge cases + +.edge-case { + .mixin-arguments("{"); +} + +// Division vs. Literal Slash +.border-radius(@r: 2px/5px) { + border-radius: @r; +} +.slash-vs-math { + .border-radius(); + .border-radius(5px/10px); + .border-radius((3px * 2)); +} +// semi-colon vs comma for delimiting + +.mixin-takes-one(@a) { + one: @a; +} + +.mixin-takes-two(@a; @b) { + one: @a; + two: @b; +} + +.comma-vs-semi-colon { + .mixin-takes-two(@a : a; @b : b, c); + .mixin-takes-two(@a : d, e; @b : f); + .mixin-takes-one(@a: g); + .mixin-takes-one(@a : h;); + .mixin-takes-one(i); + .mixin-takes-one(j;); + .mixin-takes-two(k, l); + .mixin-takes-one(m, n;); + .mixin-takes-two(o, p; q); + .mixin-takes-two(r, s; t;); +} + +.mixin-conflict(@a:defA, @b:defB, @c:defC) { + three: @a, @b, @c; +} + +.mixin-conflict(@a:defA, @b:defB, @c:defC, @d:defD) { + four: @a, @b, @c, @d; +} + +#named-conflict { + .mixin-conflict(11, 12, 13, @a:a); + .mixin-conflict(@a:a, 21, 22, 23); +} +@a: 3px; +.mixin-default-arg(@a: 1px, @b: @a, @c: @b) { + defaults: 1px 1px 1px; + defaults: 2px 2px 2px; +} + +.test-mixin-default-arg { + .mixin-default-arg(); + .mixin-default-arg(2px); +} + +.mixin-comma-default1(@color; @padding; @margin: 2, 2, 2, 2) { + margin: @margin; +} +.selector { + .mixin-comma-default1(#33acfe; 4); +} +.mixin-comma-default2(@margin: 2, 2, 2, 2;) { + margin: @margin; +} +.selector2 { + .mixin-comma-default2(); +} +.mixin-comma-default3(@margin: 2, 2, 2, 2) { + margin: @margin; +} +.selector3 { + .mixin-comma-default3(4,2,2,2); +} + +.test-calling-one-arg-mixin(@a) { +} + +.test-calling-one-arg-mixin(@a, @b, @rest...) { +} + +div { + .test-calling-one-arg-mixin(1); +} \ No newline at end of file diff --git a/test/less/mixins-closure.less b/test/less/mixins-closure.less new file mode 100644 index 00000000..01251d2a --- /dev/null +++ b/test/less/mixins-closure.less @@ -0,0 +1,26 @@ +.scope { + @var: 99px; + .mixin () { + width: @var; + } +} + +.class { + .scope > .mixin; +} + +.overwrite { + @var: 0px; + .scope > .mixin; +} + +.nested { + @var: 5px; + .mixin () { + width: @var; + } + .class { + @var: 10px; + .mixin; + } +} diff --git a/test/less/mixins-guards-default-func.less b/test/less/mixins-guards-default-func.less new file mode 100644 index 00000000..eada9381 --- /dev/null +++ b/test/less/mixins-guards-default-func.less @@ -0,0 +1,195 @@ + +// basics: + +guard-default-basic-1 { + .m(1) {case: 1} + .m(@x) when (default()) {default: @x} + + &-1 {.m(1)} + &-2 {.m(2)} +} + +guard-default-basic-2 { + .m(1) {case: 1} + .m(2) {case: 2} + .m(3) {case: 3} + .m(@x) when (default()) {default: @x} + + &-0 {.m(0)} + &-2 {.m(2)} +} + +guard-default-basic-3 { + .m(@x) when (@x = 1) {case: 1} + .m(2) {case: 2} + .m(@x) when (@x = 3) {case: 3} + .m(@x) when (default()) {default: @x} + + &-0 {.m(0)} + &-2 {.m(2)} + &-3 {.m(3)} +} + +guard-default-definition-order { + .m(@x) when (default()) {default: @x} + .m(@x) when (@x = 1) {case: 1} + .m(2) {case: 2} + .m(@x) when (@x = 3) {case: 3} + + &-0 {.m(0)} + &-2 {.m(2)} + &-2 {.m(3)} +} + +// out of guard: + +guard-default-out-of-guard { + .m(1) {case-1: 1} + .m(@x: default()) when (default()) {default: @x} + + &-0 { + case-0: default(); + .m(1); + .m(2); + case-2: default(); + } + &-1 {.m(default())} + &-2 {.m()} +} + +// expressions: + +guard-default-expr-not { + .m(1) {case: 1} + .m(@x) when not(default()) {default: @x} + + &-1 {.m(1)} + &-2 {.m(2)} +} + +guard-default-expr-eq { + .m(@x) when (@x = true) {case: @x} + .m(@x) when (@x = false) {case: @x} + .m(@x) when (@x = default()) {default: @x} + + &-true {.m(true)} + &-false {.m(false)} +} + +guard-default-expr-or { + .m(1) {case: 1} + .m(2) {case: 2} + .m(@x) when (default()), (@x = 2) {default: @x} + + &-1 {.m(1)} + &-2 {.m(2)} + &-3 {.m(3)} +} + +guard-default-expr-and { + .m(1) {case: 1} + .m(2) {case: 2} + .m(@x) when (default()) and (@x = 3) {default: @x} + + &-1 {.m(1)} + &-2 {.m(2)} + &-3 {.m(3)} + &-4 {.m(4)} +} + +guard-default-expr-always { + .m(1) {case: 1} + .m(@x) when (default()), not(default()) {default: @x} // always match + + &-1 {.m(1)} + &-2 {.m(2)} +} + +guard-default-expr-never { + .m(1) {case: 1} + .m(@x) when (default()) and not(default()) {default: @x} // never match + + &-1 {.m(1)} + &-2 {.m(2)} +} + + +// not conflicting multiple default() uses: + +guard-default-multi-1 { + .m(0) {case: 0} + .m(@x) when (default()) {default-1: @x} + .m(2) when (default()) {default-2: @x} + + &-0 {.m(0)} + &-1 {.m(1)} +} + +guard-default-multi-2 { + .m(1, @x) when (default()) {default-1: @x} + .m(2, @x) when (default()) {default-2: @x} + .m(@x, yes) when (default()) {default-3: @x} + + &-1 {.m(1, no)} + &-2 {.m(2, no)} + &-3 {.m(3, yes)} +} + +guard-default-multi-3 { + .m(red) {case-1: darkred} + .m(blue) {case-2: darkblue} + .m(@x) when (iscolor(@x)) and (default()) {default-color: @x} + .m('foo') {case-1: I am 'foo'} + .m('bar') {case-2: I am 'bar'} + .m(@x) when (isstring(@x)) and (default()) {default-string: I am @x} + + &-blue {.m(blue)} + &-green {.m(green)} + &-foo {.m('foo')} + &-baz {.m('baz')} +} + +guard-default-multi-4 { + .m(@x) when (default()), not(default()) {always: @x} + .m(@x) when (default()) and not(default()) {never: @x} + .m(2) {case: 2} + + .m(1); + .m(2); +} + +guard-default-not-ambiguos-2 { + .m(@x) {case: 1} + .m(@x) when (default()) {default: @x} + .m(@x) when not(default()) {not-default: @x} + + .m(2); +} + +guard-default-not-ambiguos-3 { + .m(@x) {case: 1} + .m(@x) when not(default()) {not-default-1: @x} + .m(@x) when not(default()) {not-default-2: @x} + + .m(2); +} + +// default & scope + +guard-default-scopes { + .s1() {.m(@v) {1: no condition}} + .s2() {.m(@v) when (@v) {2: when true}} + .s3() {.m(@v) when (default()) {3: when default}} + + &-3 { + .s2(); + .s3(); + .m(false); + } + + &-1 { + .s1(); + .s3(); + .m(false); + } +} diff --git a/test/less/mixins-guards.less b/test/less/mixins-guards.less new file mode 100644 index 00000000..5aec2e51 --- /dev/null +++ b/test/less/mixins-guards.less @@ -0,0 +1,173 @@ + +// Stacking, functions.. + +.light (@a) when (lightness(@a) > 50%) { + color: white; +} +.light (@a) when (lightness(@a) < 50%) { + color: black; +} +.light (@a) { + margin: 1px; +} + +.light1 { .light(#ddd) } +.light2 { .light(#444) } + +// Arguments against each other + +.max (@a, @b) when (@a > @b) { + width: @a; +} +.max (@a, @b) when (@a < @b) { + width: @b; +} + +.max1 { .max(3, 6) } +.max2 { .max(8, 1) } + +// Globals inside guards + +@g: auto; + +.glob (@a) when (@a = @g) { + margin: @a @g; +} +.glob1 { .glob(auto) } + +// Other operators + +.ops (@a) when (@a >= 0) { + height: gt-or-eq; +} +.ops (@a) when (@a =< 0) { + height: lt-or-eq; +} +.ops (@a) when (@a <= 0) { + height: lt-or-eq-alias; +} +.ops (@a) when not(@a = 0) { + height: not-eq; +} +.ops1 { .ops(0) } +.ops2 { .ops(1) } +.ops3 { .ops(-1) } + +// Scope and default values + +@a: auto; + +.default (@a: inherit) when (@a = inherit) { + content: default; +} +.default1 { .default } + +// true & false keywords +.test (@a) when (@a) { + content: "true."; +} +.test (@a) when not (@a) { + content: "false."; +} + +.test1 { .test(true) } +.test2 { .test(false) } +.test3 { .test(1) } +.test4 { .test(boo) } +.test5 { .test("true") } + +// Boolean expressions + +.bool () when (true) and (false) { content: true and false } // FALSE +.bool () when (true) and (true) { content: true and true } // TRUE +.bool () when (true) { content: true } // TRUE +.bool () when (false) and (false) { content: true } // FALSE +.bool () when (false), (true) { content: false, true } // TRUE +.bool () when (false) and (true) and (true), (true) { content: false and true and true, true } // TRUE +.bool () when (true) and (true) and (false), (false) { content: true and true and false, false } // FALSE +.bool () when (false), (true) and (true) { content: false, true and true } // TRUE +.bool () when (false), (false), (true) { content: false, false, true } // TRUE +.bool () when (false), (false) and (true), (false) { content: false, false and true, false } // FALSE +.bool () when (false), (true) and (true) and (true), (false) { content: false, true and true and true, false } // TRUE +.bool () when not (false) { content: not false } +.bool () when not (true) and not (false) { content: not true and not false } +.bool () when not (true) and not (true) { content: not true and not true } +.bool () when not (false) and (false), not (false) { content: not false and false, not false } + +.bool1 { .bool } + +.equality-unit-test(@num) when (@num = 1%) { + test: fail; +} +.equality-unit-test(@num) when (@num = 2) { + test: pass; +} +.equality-units { + .equality-unit-test(1px); + .equality-unit-test(2px); +} + +.colorguard(@col) when (@col = red) { content: is @col; } +.colorguard(@col) when not (blue = @col) { content: is not blue its @col; } +.colorguard(@col) {} +.colorguardtest { + .colorguard(red); + .colorguard(blue); + .colorguard(purple); +} + +.stringguard(@str) when (@str = "theme1") { content: @str is "theme1"; } +.stringguard(@str) when not ("theme2" = @str) { content: @str is not "theme2"; } +.stringguard(@str) when (@str = 'theme1') { content: @str is 'theme1'; } +.stringguard(@str) when not ('theme2' = @str) { content: @str is not 'theme2'; } +.stringguard(@str) when (~"theme1" = @str) { content: @str is theme1; } +.stringguard(@str) {} +.stringguardtest { + .stringguard("theme1"); + .stringguard("theme2"); + .stringguard('theme1'); + .stringguard('theme2'); + .stringguard(theme1); +} + +.mixin(...) { + catch:all; +} +.mixin(@var) when (@var=4) { + declare: 4; +} +.mixin(@var) when (@var=4px) { + declare: 4px; +} +#tryNumberPx { + .mixin(4px); +} + +.lock-mixin(@a) { + .inner-locked-mixin(@x: @a) when (@a = 1) { + a: @a; + x: @x; + } +} +.call-lock-mixin { + .lock-mixin(1); + .call-inner-lock-mixin { + .inner-locked-mixin(); + } +} +.bug-100cm-1m(@a) when (@a = 1) { + .failed { + one-hundred: not-equal-to-1; + } +} +.bug-100cm-1m(100cm); + +#ns { + .mixin-for-root-usage(@a) when (@a > 0) { + .mixin-generated-class { + a: @a; + } + } +} + +#ns > .mixin-for-root-usage(1); diff --git a/test/less/mixins-important.less b/test/less/mixins-important.less new file mode 100644 index 00000000..c8cc1d5c --- /dev/null +++ b/test/less/mixins-important.less @@ -0,0 +1,25 @@ +.submixin(@a) { + border-width: @a; +} +.mixin (9) { + border: 9 !important; +} +.mixin (@a: 0) { + border: @a; + boxer: @a; + .inner { + test: @a; + } + // comment + .submixin(@a); +} + +.class { + .mixin(1); + .mixin(2) !important; + .mixin(3); + .mixin(4) !important; + .mixin(5); + .mixin !important; + .mixin(9); +} diff --git a/test/less/mixins-interpolated.less b/test/less/mixins-interpolated.less new file mode 100644 index 00000000..2e75e980 --- /dev/null +++ b/test/less/mixins-interpolated.less @@ -0,0 +1,69 @@ + +@a1: foo; +@a2: ~".foo"; +@a4: ~"#foo"; + +.@{a1} { + a: 1; +} + +@{a2} { + a: 2; +} + +#@{a1} { + a: 3; +} + +@{a4} { + a: 4; +} + +mi-test-a { + .foo; + #foo; +} + +.b .bb { + &.@{a1}-xxx .yyy-@{a1}@{a4} { + & @{a2}.bbb { + b: 1; + } + } +} + +mi-test-b { + .b.bb.foo-xxx.yyy-foo#foo.foo.bbb; +} + +@c1: @a1; +@c2: bar; +@c3: baz; + +#@{c1}-foo { + > .@{c2} { + .@{c3} { + c: c; + } + } +} + +mi-test-c { + &-1 {#foo-foo;} + &-2 {#foo-foo > .bar;} + &-3 {#foo-foo > .bar.baz;} +} + +.Person(@name, @gender_) { + .@{name} { + @gender: @gender_; + .sayGender() { + gender: @gender; + } + } +} + +mi-test-d { + .Person(person, "Male"); + .person.sayGender(); +} diff --git a/test/less/mixins-named-args.less b/test/less/mixins-named-args.less new file mode 100644 index 00000000..d79e0f47 --- /dev/null +++ b/test/less/mixins-named-args.less @@ -0,0 +1,36 @@ +.mixin (@a: 1px, @b: 50%) { + width: (@a * 5); + height: (@b - 1%); + args: @arguments; +} +.mixin (@a: 1px, @b: 50%) when (@b > 75%){ + text-align: center; +} + +.named-arg { + color: blue; + .mixin(@b: 100%); +} + +.class { + @var: 20%; + .mixin(@b: @var); +} + +.all-args-wrong-args { + .mixin(@b: 10%, @a: 2px); +} + +.mixin2 (@a: 1px, @b: 50%, @c: 50) { + width: (@a * 5); + height: (@b - 1%); + color: (#000000 + @c); +} + +.named-args2 { + .mixin2(3px, @c: 100); +} + +.named-args3 { + .mixin2(@b: 30%, @c: #123456); +} \ No newline at end of file diff --git a/test/less/mixins-nested.less b/test/less/mixins-nested.less new file mode 100644 index 00000000..43443de2 --- /dev/null +++ b/test/less/mixins-nested.less @@ -0,0 +1,22 @@ +.mix-inner (@var) { + border-width: @var; +} + +.mix (@a: 10) { + .inner { + height: (@a * 10); + + .innest { + width: @a; + .mix-inner((@a * 2)); + } + } +} + +.class { + .mix(30); +} + +.class2 { + .mix(60); +} diff --git a/test/less/mixins-pattern.less b/test/less/mixins-pattern.less new file mode 100644 index 00000000..e769b0cf --- /dev/null +++ b/test/less/mixins-pattern.less @@ -0,0 +1,102 @@ +.mixin (...) { + variadic: true; +} +.mixin (@a...) { + named-variadic: true; +} +.mixin () { + zero: 0; +} +.mixin (@a: 1px) { + one: 1; +} +.mixin (@a) { + one-req: 1; +} +.mixin (@a: 1px, @b: 2px) { + two: 2; +} + +.mixin (@a, @b, @c) { + three-req: 3; +} + +.mixin (@a: 1px, @b: 2px, @c: 3px) { + three: 3; +} + +.zero { + .mixin(); +} + +.one { + .mixin(1); +} + +.two { + .mixin(1, 2); +} + +.three { + .mixin(1, 2, 3); +} + +// + +.mixout ('left') { + left: 1; +} + +.mixout ('right') { + right: 1; +} + +.left { + .mixout('left'); +} +.right { + .mixout('right'); +} + +// + +.border (@side, @width) { + color: black; + .border-side(@side, @width); +} +.border-side (left, @w) { + border-left: @w; +} +.border-side (right, @w) { + border-right: @w; +} + +.border-right { + .border(right, 4px); +} +.border-left { + .border(left, 4px); +} + +// + + +.border-radius (@r) { + both: (@r * 10); +} +.border-radius (@r, left) { + left: @r; +} +.border-radius (@r, right) { + right: @r; +} + +.only-right { + .border-radius(33, right); +} +.only-left { + .border-radius(33, left); +} +.left-right { + .border-radius(33); +} diff --git a/test/less/mixins.less b/test/less/mixins.less new file mode 100644 index 00000000..b98836c5 --- /dev/null +++ b/test/less/mixins.less @@ -0,0 +1,144 @@ +.mixin { border: 1px solid black; } +.mixout { border-color: orange; } +.borders { border-style: dashed; } + +#namespace { + .borders { + border-style: dotted; + } + .biohazard { + content: "death"; + .man { + color: transparent; + } + } +} +#theme { + > .mixin { + background-color: grey; + } +} +#container { + color: black; + .mixin; + .mixout; + #theme > .mixin; +} + +#header { + .milk { + color: white; + .mixin; + #theme > .mixin; + } + #cookie { + .chips { + #namespace .borders; + .calories { + #container; + } + } + .borders; + } +} +.secure-zone { #namespace .biohazard .man; } +.direct { + #namespace > .borders; +} + +.bo, .bar { + width: 100%; +} +.bo { + border: 1px; +} +.ar.bo.ca { + color: black; +} +.jo.ki { + background: none; +} +.amp { + &.support { + color: orange; + .higher { + top: 0px; + } + &.deeper { + height: auto; + } + } +} +.extended { + .bo; + .jo.ki; + .amp.support; + .amp.support.higher; + .amp.support.deeper; +} +.do .re .mi .fa { + .sol .la { + .si { + color: cyan; + } + } +} +.mutli-selector-parents { + .do.re.mi.fa.sol.la.si; +} +.foo .bar { + .bar; +} +.has_parents() { + & .underParents { + color: red; + } +} +.has_parents(); +.parent { + .has_parents(); +} +.margin_between(@above, @below) { + * + & { margin-top: @above; } + legend + & { margin-top: 0; } + & + * { margin-top: @below; } +} +h1 { .margin_between(25px, 10px); } +h2 { .margin_between(20px, 8px); } +h3 { .margin_between(15px, 5px); } + +.mixin_def(@url, @position){ + background-image: @url; + background-position: @position; +} +.error{ + @s: "/"; + .mixin_def( "@{s}a.png", center center); +} +.recursion() { + color: black; +} +.test-rec { + .recursion { + .recursion(); + } +} +.paddingFloat(@padding) { padding-left: @padding; } + +.button { + .paddingFloat(((10px + 12) * 2)); + + &.large { .paddingFloat(((10em * 2) * 2)); } +} +.clearfix() { + // ... +} +.clearfix { + .clearfix(); +} +.clearfix { + .clearfix(); +} +.foo { + .clearfix(); +} \ No newline at end of file diff --git a/test/less/modifyVars/extended.json b/test/less/modifyVars/extended.json new file mode 100644 index 00000000..6bd2a484 --- /dev/null +++ b/test/less/modifyVars/extended.json @@ -0,0 +1,5 @@ +{ + "the-border": "1px", + "base-color": "#111", + "red": "#842210" +} \ No newline at end of file diff --git a/test/less/modifyVars/extended.less b/test/less/modifyVars/extended.less new file mode 100644 index 00000000..0badc671 --- /dev/null +++ b/test/less/modifyVars/extended.less @@ -0,0 +1,11 @@ +#header { + color: (@base-color * 3); + border-left: @the-border; + border-right: (@the-border * 2); +} +#footer { + color: (@base-color + #003300); + border-color: @red; +} +@red: blue; // var is overridden by the modifyVars +//@base-color: green; \ No newline at end of file diff --git a/test/less/no-js-errors/no-js-errors.less b/test/less/no-js-errors/no-js-errors.less new file mode 100644 index 00000000..15ef8a45 --- /dev/null +++ b/test/less/no-js-errors/no-js-errors.less @@ -0,0 +1,3 @@ +.a { + a: `1 + 1`; +} \ No newline at end of file diff --git a/test/less/no-js-errors/no-js-errors.txt b/test/less/no-js-errors/no-js-errors.txt new file mode 100644 index 00000000..d81dd2bd --- /dev/null +++ b/test/less/no-js-errors/no-js-errors.txt @@ -0,0 +1,4 @@ +SyntaxError: You are using JavaScript, which has been disabled. in {path}no-js-errors.less on line 2, column 6: +1 .a { +2 a: `1 + 1`; +3 } diff --git a/test/less/no-output.less b/test/less/no-output.less new file mode 100644 index 00000000..b4e6a499 --- /dev/null +++ b/test/less/no-output.less @@ -0,0 +1,2 @@ +.mixin() { +} \ No newline at end of file diff --git a/test/less/operations.less b/test/less/operations.less new file mode 100644 index 00000000..3e483c8b --- /dev/null +++ b/test/less/operations.less @@ -0,0 +1,62 @@ +#operations { + color: (#110000 + #000011 + #001100); // #111111 + height: (10px / 2px + 6px - 1px * 2); // 9px + width: (2 * 4 - 5em); // 3em + .spacing { + height: (10px / 2px+6px-1px*2); + width: (2 * 4-5em); + } + substraction: (20 - 10 - 5 - 5); // 0 + division: (20 / 5 / 4); // 1 +} + +@x: 4; +@y: 12em; + +.with-variables { + height: (@x + @y); // 16em + width: (12 + @y); // 24em + size: (5cm - @x); // 1cm +} + +.with-functions { + color: (rgb(200, 200, 200) / 2); + color: (2 * hsl(0, 50%, 50%)); + color: (rgb(10, 10, 10) + hsl(0, 50%, 50%)); +} + +@z: -2; + +.negative { + height: (2px + @z); // 0px + width: (2px - @z); // 4px +} + +.shorthands { + padding: -1px 2px 0 -4px; // +} + +.rem-dimensions { + font-size: (20rem / 5 + 1.5rem); // 5.5rem +} + +.colors { + color: #123; // #112233 + border-color: (#234 + #111111); // #334455 + background-color: (#222222 - #fff); // #000000 + .other { + color: (2 * #111); // #222222 + border-color: (#333333 / 3 + #111); // #222222 + } +} + +.negations { + @var: 4px; + variable: (-@var); // 4 + variable1: (-@var + @var); // 0 + variable2: (@var + -@var); // 0 + variable3: (@var - -@var); // 8 + variable4: (-@var - -@var); // 0 + paren: (-(@var)); // -4px + paren2: (-(2 + 2) * -@var); // 16 +} diff --git a/test/less/parens.less b/test/less/parens.less new file mode 100644 index 00000000..eeef3448 --- /dev/null +++ b/test/less/parens.less @@ -0,0 +1,45 @@ +.parens { + @var: 1px; + border: (@var * 2) solid black; + margin: (@var * 1) (@var + 2) (4 * 4) 3; + width: (6 * 6); + padding: 2px (6 * 6px); +} + +.more-parens { + @var: (2 * 2); + padding: (2 * @var) 4 4 (@var * 1px); + width-all: ((@var * @var) * 6); + width-first: ((@var * @var)) * 6; + width-keep: (@var * @var) * 6; + height-keep: (7 * 7) + (8 * 8); + height-all: ((7 * 7) + (8 * 8)); + height-parts: ((7 * 7)) + ((8 * 8)); + margin-keep: (4 * (5 + 5) / 2) - (@var * 2); + margin-parts: ((4 * (5 + 5) / 2)) - ((@var * 2)); + margin-all: ((4 * (5 + 5) / 2) + (-(@var * 2))); + border-radius-keep: 4px * (1 + 1) / @var + 3px; + border-radius-parts: ((4px * (1 + 1))) / ((@var + 3px)); + border-radius-all: (4px * (1 + 1) / @var + 3px); + //margin: (6 * 6)px; +} + +.negative { + @var: 1; + neg-var: -@var; // -1 ? + neg-var-paren: -(@var); // -(1) ? +} + +.nested-parens { + width: 2 * (4 * (2 + (1 + 6))) - 1; + height: ((2 + 3) * (2 + 3) / (9 - 4)) + 1; +} + +.mixed-units { + margin: 2px 4em 1 5pc; + padding: (2px + 4px) 1em 2px 2; +} + +.test-false-negatives { + a: ~"("; +} diff --git a/test/less/property-name-interp.less b/test/less/property-name-interp.less new file mode 100644 index 00000000..9886e65f --- /dev/null +++ b/test/less/property-name-interp.less @@ -0,0 +1,53 @@ + +pi-test { + @prefix: ufo-; + @a: border; + @bb: top; + @c_c: left; + @d-d4: radius; + @-: -; + + @{a}: 0; + @{prefix}width: 50%; + *-z-@{a} :1px dashed blue; + -www-@{a}-@{bb}: 2px; + @{d-d4}-is-not-a-@{a}:true; + @{a}-@{bb}-@{c_c}-@{d-d4} : 2em; + @{a}@{-}@{bb}@{-}red@{-}@{d-d4}-: 3pt; + + .mixin(mixer); + .merge(ish, base); +} + +@global: global; + +.mixin(@arg) { + @local: local; + @{global}-@{local}-@{arg}-property: strong; +} + +.merge(@p, @v) { + &-merge { + @prefix: pre; + @suffix: ish; + @{prefix}-property-ish+ :high; + pre-property-@{suffix} +: middle; + @{prefix}-property-@{suffix}+: low; + @{prefix}-property-@{p} + : @v; + + @subterfuge: ~'+'; + pre-property-ish@{subterfuge}: nice try dude; + } +} + +pi-indirect-vars { + @{p}: @p; + @p: @@a; + @a: b; + @b: auto; +} + +pi-complex-values { + @{p}@{p}: none; + @p: (1 + 2px) fadeout(#ff0, 50%), pi() /* foo */; +} diff --git a/test/less/rulesets.less b/test/less/rulesets.less new file mode 100644 index 00000000..e81192db --- /dev/null +++ b/test/less/rulesets.less @@ -0,0 +1,30 @@ +#first > .one { + > #second .two > #deux { + width: 50%; + #third { + &:focus { + color: black; + #fifth { + > #sixth { + .seventh #eighth { + + #ninth { + color: purple; + } + } + } + } + } + height: 100%; + } + #fourth, #five, #six { + color: #110000; + .seven, .eight > #nine { + border: 1px solid black; + } + #ten { + color: red; + } + } + } + font-size: 2em; +} diff --git a/test/less/scope.less b/test/less/scope.less new file mode 100644 index 00000000..475b1f6d --- /dev/null +++ b/test/less/scope.less @@ -0,0 +1,104 @@ +@x: red; +@x: blue; +@z: transparent; +@mix: none; + +.mixin { + @mix: #989; +} +@mix: blue; +.tiny-scope { + color: @mix; // #989 + .mixin; +} + +.scope1 { + @y: orange; + @z: black; + color: @x; // blue + border-color: @z; // black + .hidden { + @x: #131313; + } + .scope2 { + @y: red; + color: @x; // blue + .scope3 { + @local: white; + color: @y; // red + border-color: @z; // black + background-color: @local; // white + } + } +} + +#namespace { + .scoped_mixin() { + @local-will-be-made-global: green; + .scope { + scoped-val: @local-will-be-made-global; + } + } +} + +#namespace > .scoped_mixin(); + +.setHeight(@h) { @height: 1024px; } +.useHeightInMixinCall(@h) { .useHeightInMixinCall { mixin-height: @h; } } +@mainHeight: 50%; +.setHeight(@mainHeight); +.heightIsSet { height: @height; } +.useHeightInMixinCall(@height); + +.importRuleset() { + .imported { + exists: true; + } +} +.importRuleset(); +.testImported { + .imported; +} + +@parameterDefault: 'top level'; +@anotherVariable: 'top level'; +//mixin uses top-level variables +.mixinNoParam(@parameter: @parameterDefault) when (@parameter = 'top level') { + default: @parameter; + scope: @anotherVariable; + sub-scope-only: @subScopeOnly; +} + +#allAreUsedHere { + //redefine top-level variables in different scope + @parameterDefault: 'inside'; + @anotherVariable: 'inside'; + @subScopeOnly: 'inside'; + //use the mixin + .mixinNoParam(); +} +#parentSelectorScope { + @col: white; + & { + @col: black; + } + prop: @col; + & { + @col: black; + } +} +.test-empty-mixin() { +} +#parentSelectorScopeMixins { + & { + .test-empty-mixin() { + should: never seee 1; + } + } + .test-empty-mixin(); + & { + .test-empty-mixin() { + should: never seee 2; + } + } +} \ No newline at end of file diff --git a/test/less/selectors.less b/test/less/selectors.less new file mode 100644 index 00000000..8b30546f --- /dev/null +++ b/test/less/selectors.less @@ -0,0 +1,156 @@ +h1, h2, h3 { + a, p { + &:hover { + color: red; + } + } +} + +#all { color: blue; } +#the { color: blue; } +#same { color: blue; } + +ul, li, div, q, blockquote, textarea { + margin: 0; +} + +td { + margin: 0; + padding: 0; +} + +td, input { + line-height: 1em; +} + +a { + color: red; + + &:hover { color: blue; } + + div & { color: green; } + + p & span { color: yellow; } +} + +.foo { + .bar, .baz { + & .qux { + display: block; + } + .qux & { + display: inline; + } + .qux& { + display: inline-block; + } + .qux & .biz { + display: none; + } + } +} + +.b { + &.c { + .a& { + color: red; + } + } +} + +.b { + .c & { + &.a { + color: red; + } + } +} + +.p { + .foo &.bar { + color: red; + } +} + +.p { + .foo&.bar { + color: red; + } +} + +.foo { + .foo + & { + background: amber; + } + & + & { + background: amber; + } +} + +.foo, .bar { + & + & { + background: amber; + } +} + +.foo, .bar { + a, b { + & > & { + background: amber; + } + } +} + +.other ::fnord { color: red } +.other::fnord { color: red } +.other { + ::bnord {color: red } + &::bnord {color: red } +} +// selector interpolation +@theme: blood; +@selector: ~".@{theme}"; +@{selector} { + color:red; +} +@{selector}red { + color: green; +} +.red { + #@{theme}.@{theme}&.black { + color:black; + } +} +@num: 3; +:nth-child(@{num}) { + selector: interpolated; +} +.test { + &:nth-child(odd):not(:nth-child(3)) { + color: #ff0000; + } +} +[prop], +[prop=10%], +[prop="value@{num}"], +[prop*="val@{num}"], +[|prop~="val@{num}"], +[*|prop$="val@{num}"], +[ns|prop^="val@{num}"], +[@{num}^="val@{num}"], +[@{num}=@{num}], +[@{num}] { + attributes: yes; +} + +/* +Large comment means chunk will be emitted after } which means chunk will begin with whitespace... +blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank +blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank +blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank +blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank +blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank +*/ +@{selector} { + color: red; +} \ No newline at end of file diff --git a/test/less/sourcemaps/basic.json b/test/less/sourcemaps/basic.json new file mode 100644 index 00000000..76a63c5a --- /dev/null +++ b/test/less/sourcemaps/basic.json @@ -0,0 +1,3 @@ +{ + "my-color": "red" +} \ No newline at end of file diff --git a/test/less/sourcemaps/basic.less b/test/less/sourcemaps/basic.less new file mode 100644 index 00000000..4ee8b4f6 --- /dev/null +++ b/test/less/sourcemaps/basic.less @@ -0,0 +1,27 @@ +@var: black; + +.a() { + color: red; +} + +.b { + color: green; + .a(); + color: blue; + background: @var; +} + +.a, .b { + background: green; + .c, .d { + background: gray; + & + & { + color: red; + } + } +} + +.extend:extend(.a all) { + color: pink; +} +@import (inline) "imported.css"; \ No newline at end of file diff --git a/test/less/sourcemaps/imported.css b/test/less/sourcemaps/imported.css new file mode 100644 index 00000000..2ee35f06 --- /dev/null +++ b/test/less/sourcemaps/imported.css @@ -0,0 +1,7 @@ +/*comments*/ +.unused-css { + color: white; +} +.imported { + color: black; +} \ No newline at end of file diff --git a/test/less/static-urls/urls.less b/test/less/static-urls/urls.less new file mode 100644 index 00000000..b0c7de09 --- /dev/null +++ b/test/less/static-urls/urls.less @@ -0,0 +1,33 @@ +@font-face { + src: url("/fonts/garamond-pro.ttf"); + src: local(Futura-Medium), + url(fonts.svg#MyGeometricModern) format("svg"); +} +#shorthands { + background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; +} +#misc { + background-image: url(images/image.jpg); +} +#data-uri { + background: url(data:image/png;charset=utf-8;base64, + kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ + k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U + kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); + background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); + background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); +} + +#svg-data-uri { + background: transparent url('data:image/svg+xml, '); +} + +.comma-delimited { + background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); +} +.values { + @a: 'Trebuchet'; + url: url(@a); +} + +@import "../import/import-and-relative-paths-test"; diff --git a/test/less/strings.less b/test/less/strings.less new file mode 100644 index 00000000..c43e368d --- /dev/null +++ b/test/less/strings.less @@ -0,0 +1,57 @@ +#strings { + background-image: url("http://son-of-a-banana.com"); + quotes: "~" "~"; + content: "#*%:&^,)!.(~*})"; + empty: ""; + brackets: "{" "}"; + escapes: "\"hello\" \\world"; + escapes2: "\"llo"; +} +#comments { + content: "/* hello */ // not-so-secret"; +} +#single-quote { + quotes: "'" "'"; + content: '""#!&""'; + empty: ''; + semi-colon: ';'; +} +#escaped { + filter: ~"DX.Transform.MS.BS.filter(opacity=50)"; +} +#one-line { image: url(http://tooks.com) } +#crazy { image: url(http://), "}", url("http://}") } +#interpolation { + @var: '/dev'; + url: "http://lesscss.org@{var}/image.jpg"; + + @var2: 256; + url2: "http://lesscss.org/image-@{var2}.jpg"; + + @var3: #456; + url3: "http://lesscss.org@{var3}"; + + @var4: hello; + url4: "http://lesscss.org/@{var4}"; + + @var5: 54.4px; + url5: "http://lesscss.org/@{var5}"; +} + +// multiple calls with string interpolation + +.mix-mul (@a: green) { + color: ~"@{a}"; +} +.mix-mul-class { + .mix-mul(blue); + .mix-mul(red); + .mix-mul(black); + .mix-mul(orange); +} + +@test: Arial, Verdana, San-Serif; +.watermark { + @family: ~"Univers, @{test}"; + family: @family; +} diff --git a/test/less/url-args/urls.less b/test/less/url-args/urls.less new file mode 100644 index 00000000..2f1bd872 --- /dev/null +++ b/test/less/url-args/urls.less @@ -0,0 +1,63 @@ +@font-face { + src: url("/fonts/garamond-pro.ttf"); + src: local(Futura-Medium), + url(fonts.svg#MyGeometricModern) format("svg"); +} +#shorthands { + background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; + background: url("img.jpg") center / 100px; + background: #fff url(image.png) center / 1px 100px repeat-x scroll content-box padding-box; +} +#misc { + background-image: url(images/image.jpg); +} +#data-uri { + background: url(data:image/png;charset=utf-8;base64, + kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ + k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U + kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); + background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); + background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); + background-image: url("http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700"); +} + +#svg-data-uri { + background: transparent url('data:image/svg+xml, '); +} + +.comma-delimited { + background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); +} +.values { + @a: 'Trebuchet'; + url: url(@a); +} + +@import "../import/imports/font"; + +#data-uri { + uri: data-uri('image/jpeg;base64', '../../data/image.jpg'); +} + +#data-uri-guess { + uri: data-uri('../../data/image.jpg'); +} + +#data-uri-ascii { + uri-1: data-uri('text/html', '../../data/page.html'); + uri-2: data-uri('../../data/page.html'); +} + +#svg-functions { + background-image: svg-gradient(to bottom, black, white); + background-image: svg-gradient(to bottom, black, orange 3%, white); + @green_5: green 5%; + @orange_percentage: 3%; + @orange_color: orange; + background-image: svg-gradient(to bottom, (mix(black, white) + #444) 1%, @orange_color @orange_percentage, ((@green_5)), white 95%); +} + +#data-uri-with-spaces { + background-image: url( data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); + background-image: url( ' data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9=='); +} diff --git a/test/less/urls.less b/test/less/urls.less new file mode 100644 index 00000000..ca1602e2 --- /dev/null +++ b/test/less/urls.less @@ -0,0 +1,72 @@ +@font-face { + src: url("/fonts/garamond-pro.ttf"); + src: local(Futura-Medium), + url(fonts.svg#MyGeometricModern) format("svg"); +} +#shorthands { + background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; + background: url("img.jpg") center / 100px; + background: #fff url(image.png) center / 1px 100px repeat-x scroll content-box padding-box; +} +#misc { + background-image: url(images/image.jpg); +} +#data-uri { + background: url(data:image/png;charset=utf-8;base64, + kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ + k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U + kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); + background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); + background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); + background-image: url("http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700"); +} + +#svg-data-uri { + background: transparent url('data:image/svg+xml, '); +} + +.comma-delimited { + background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); +} +.values { + @a: 'Trebuchet'; + url: url(@a); +} + +@import "import/import-and-relative-paths-test"; + +#relative-url-import { + .unquoted-relative-path-bg; + .quoted-relative-path-border-image; +} + +#data-uri { + uri: data-uri('image/jpeg;base64', '../data/image.jpg'); +} + +#data-uri-guess { + uri: data-uri('../data/image.jpg'); +} + +#data-uri-ascii { + uri-1: data-uri('text/html', '../data/page.html'); + uri-2: data-uri('../data/page.html'); +} + +#data-uri-toobig { + uri: data-uri('../data/data-uri-fail.png'); +} +.add_an_import(@file_to_import) { +@import "@{file_to_import}"; +} + +.add_an_import("file.css"); + +#svg-functions { + background-image: svg-gradient(to bottom, black, white); + background-image: svg-gradient(to bottom, black, orange 3%, white); + @green_5: green 5%; + @orange_percentage: 3%; + @orange_color: orange; + background-image: svg-gradient(to bottom, (mix(black, white) + #444) 1%, @orange_color @orange_percentage, ((@green_5)), white 95%); +} diff --git a/test/less/variables-in-at-rules.less b/test/less/variables-in-at-rules.less new file mode 100644 index 00000000..96d8c611 --- /dev/null +++ b/test/less/variables-in-at-rules.less @@ -0,0 +1,20 @@ + +@Eight: 8; +@charset "UTF-@{Eight}"; + +@ns: less; +@namespace @ns "http://lesscss.org"; + +@name: enlarger; +@keyframes @name { + from {font-size: 12px;} + to {font-size: 15px;} +} + +.m(reducer); +.m(@name) { + @-webkit-keyframes @name { + from {font-size: 13px;} + to {font-size: 10px;} + } +} diff --git a/test/less/variables.less b/test/less/variables.less new file mode 100644 index 00000000..e896f404 --- /dev/null +++ b/test/less/variables.less @@ -0,0 +1,83 @@ +@a: 2; +@x: (@a * @a); +@y: (@x + 1); +@z: (@x * 2 + @y); +@var: -1; + +.variables { + width: (@z + 1cm); // 14cm +} + +@b: @a * 10; +@c: #888; + +@fonts: "Trebuchet MS", Verdana, sans-serif; +@f: @fonts; + +@quotes: "~" "~"; +@q: @quotes; +@onePixel: 1px; + +.variables { + height: (@b + @x + 0px); // 24px + color: @c; + font-family: @f; + quotes: @q; +} + +.redef { + @var: 0; + .inition { + @var: 4; + @var: 2; + three: @var; + @var: 3; + } + zero: @var; +} + +.values { + minus-one: @var; + @a: 'Trebuchet'; + @multi: 'A', B, C; + font-family: @a, @a, @a; + color: @c !important; + multi: something @multi, @a; +} + +.variable-names { + @var: 'hello'; + @name: 'var'; + name: @@name; +} + +.alpha { + @var: 42; + filter: alpha(opacity=@var); +} + +.polluteMixin() { + @a: 'pollution'; +} +.testPollution { + @a: 'no-pollution'; + a: @a; + .polluteMixin(); + a: @a; +} + +.units { + width: @onePixel; + same-unit-as-previously: (@onePixel / @onePixel); + square-pixel-divided: (@onePixel * @onePixel / @onePixel); + odd-unit: unit((@onePixel * 4em / 2cm)); + percentage: (10 * 50%); + pixels: (50px * 10); + conversion-metric-a: (20mm + 1cm); + conversion-metric-b: (1cm + 20mm); + conversion-imperial: (1in + 72pt + 6pc); + custom-unit: (42octocats * 10); + custom-unit-cancelling: (8cats * 9dogs / 4cats); + mix-units: (1px + 1em); + invalid-units: (1px * 1px); +} diff --git a/test/less/whitespace.less b/test/less/whitespace.less new file mode 100644 index 00000000..ab4804da --- /dev/null +++ b/test/less/whitespace.less @@ -0,0 +1,44 @@ + + +.whitespace + { color: white; } + +.whitespace +{ + color: white; +} + .whitespace +{ color: white; } + +.whitespace{color:white;} +.whitespace { color : white ; } + +.white, +.space, +.mania +{ color: white; } + +.no-semi-column { color: white } +.no-semi-column { + color: white; + white-space: pre +} +.no-semi-column {border: 2px solid white} +.newlines { + background: the, + great, + wall; + border: 2px + solid + black; +} +.empty { + +} +.sel +.newline_ws .tab_ws { +color: +white; +background-position: 45 +-23; +} diff --git a/test/sourcemaps/basic.json b/test/sourcemaps/basic.json new file mode 100644 index 00000000..ab73305d --- /dev/null +++ b/test/sourcemaps/basic.json @@ -0,0 +1 @@ +{"version":3,"file":"sourcemaps/basic.css","sources":["testweb/sourcemaps/imported.css","testweb/sourcemaps/basic.less"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;ACAA;EACE,YAAA;EAJA,UAAA;EAWA,iBAAA;EALA,WAAA;EACA,mBAAA;;AAJF,EASE;AATF,EASM;EACF,gBAAA;;AACA,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFA;AAEF,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFA;EAGA,UAAA;;AALN;AAAI;AAUJ;EATE,iBAAA;;AADF,EAEE;AAFE,EAEF;AAFF,EAEM;AAFF,EAEE;AAQN,OARE;AAQF,OARM;EACF,gBAAA;;AACA,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFA;AAEF,EAFF,GAEI,KAFA;AAEF,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFA;AAEF,EAFF,GAEI,KAFA;AAEF,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFA;AAEF,EAFE,GAEA,KAFA;AAEF,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFA;AAEF,EAFE,GAEA,KAFA;AAQN,OARE,GAQF,UARE;AAQF,OARE,GAEI,KAFJ;AAQF,OARE,GAQF,UARM;AAQN,OARE,GAEI,KAFA;AAEF,EAFF,GAQF,UARE;AAEE,EAFF,GAQF,UARM;AAQN,OARM,GAQN,UARE;AAQF,OARM,GAEA,KAFJ;AAQF,OARM,GAQN,UARM;AAQN,OARM,GAEA,KAFA;AAEF,EAFE,GAQN,UARE;AAEE,EAFE,GAQN,UARM;EAGA,UAAA;;AAKN;EACE,WAAA"} \ No newline at end of file diff --git a/test/sourcemaps/index.html b/test/sourcemaps/index.html new file mode 100644 index 00000000..89acca77 --- /dev/null +++ b/test/sourcemaps/index.html @@ -0,0 +1,17 @@ + + + + + + +
id import-test
+
id import-test
+
class imported inline
+
class mixin
+
class a
+
class b
+
class b
class c
+
class a
class d
+
class extend
class c
+ + \ No newline at end of file