From ac1f1d66b2105c0423fd1d70a62e7b716aa33674 Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Sat, 26 Feb 2022 21:15:05 +0300 Subject: [PATCH] refactor: code --- crates/swc_css_ast/src/value.rs | 12 +- crates/swc_css_codegen/src/lib.rs | 17 +- crates/swc_css_minifier/src/compress/mod.rs | 2 +- .../compress/{urange.rs => unicore_range.rs} | 56 ++--- crates/swc_css_minifier/src/lib.rs | 5 +- .../fixture/compress-urange/output.min.css | 2 +- crates/swc_css_parser/src/parser/value/mod.rs | 204 +++++++++++++++-- crates/swc_css_parser/tests/fixture.rs | 2 +- .../tests/fixture/value/urange/input.css | 1 + .../tests/fixture/value/urange/output.json | 162 ++++++++++---- .../fixture/value/urange/span.rust-debug | 116 ++++++---- .../tests/recovery/unicode-range/input.css | 4 + .../tests/recovery/unicode-range/output.json | 205 ++++++++++++++++++ .../recovery/unicode-range/output.swc-stderr | 12 + crates/swc_css_visit/src/lib.rs | 8 +- 15 files changed, 640 insertions(+), 168 deletions(-) rename crates/swc_css_minifier/src/compress/{urange.rs => unicore_range.rs} (51%) create mode 100644 crates/swc_css_parser/tests/recovery/unicode-range/input.css create mode 100644 crates/swc_css_parser/tests/recovery/unicode-range/output.json create mode 100644 crates/swc_css_parser/tests/recovery/unicode-range/output.swc-stderr diff --git a/crates/swc_css_ast/src/value.rs b/crates/swc_css_ast/src/value.rs index 31c63fde1536..fc9581d2d36f 100644 --- a/crates/swc_css_ast/src/value.rs +++ b/crates/swc_css_ast/src/value.rs @@ -45,8 +45,8 @@ pub enum Value { #[tag("Url")] Url(Url), - #[tag("Urange")] - Urange(Urange), + #[tag("UnicodeRange")] + UnicodeRange(UnicodeRange), #[tag("ComplexSelector")] ComplexSelector(ComplexSelector), @@ -265,10 +265,12 @@ pub enum UrlModifier { Function(Function), } -#[ast_node("Urange")] -pub struct Urange { +#[ast_node("UnicodeRange")] +pub struct UnicodeRange { pub span: Span, - pub value: JsWord, + pub prefix: char, + pub start: JsWord, + pub end: Option, } #[ast_node("CalcSum")] diff --git a/crates/swc_css_codegen/src/lib.rs b/crates/swc_css_codegen/src/lib.rs index e03ff7112aa1..fd0392a3391a 100644 --- a/crates/swc_css_codegen/src/lib.rs +++ b/crates/swc_css_codegen/src/lib.rs @@ -794,7 +794,7 @@ where Value::CalcSum(n) => emit!(self, n), Value::Url(n) => emit!(self, n), Value::Delimiter(n) => emit!(self, n), - Value::Urange(n) => emit!(self, n), + Value::UnicodeRange(n) => emit!(self, n), Value::ComplexSelector(n) => emit!(self, n), Value::PreservedToken(n) => emit!(self, n), } @@ -1498,8 +1498,19 @@ where } #[emitter] - fn emit_urange(&mut self, n: &Urange) -> Result { - self.wr.write_raw(Some(n.span), &n.value)?; + fn emit_unicode_range(&mut self, n: &UnicodeRange) -> Result { + let mut value = String::new(); + + value.push(n.prefix); + value.push('+'); + value.push_str(&n.start); + + if let Some(end) = &n.end { + value.push('-'); + value.push_str(end); + } + + self.wr.write_raw(Some(n.span), &value)?; } #[emitter] diff --git a/crates/swc_css_minifier/src/compress/mod.rs b/crates/swc_css_minifier/src/compress/mod.rs index 158f0a29922a..e3e0f056b385 100644 --- a/crates/swc_css_minifier/src/compress/mod.rs +++ b/crates/swc_css_minifier/src/compress/mod.rs @@ -9,5 +9,5 @@ pub mod length; pub mod selector; pub mod time; pub mod transform_function; -pub mod urange; +pub mod unicore_range; pub mod url; diff --git a/crates/swc_css_minifier/src/compress/urange.rs b/crates/swc_css_minifier/src/compress/unicore_range.rs similarity index 51% rename from crates/swc_css_minifier/src/compress/urange.rs rename to crates/swc_css_minifier/src/compress/unicore_range.rs index 18e60d809576..8d2e300429fe 100644 --- a/crates/swc_css_minifier/src/compress/urange.rs +++ b/crates/swc_css_minifier/src/compress/unicore_range.rs @@ -1,13 +1,13 @@ use swc_css_ast::*; use swc_css_visit::{VisitMut, VisitMutWith}; -pub fn compress_urange() -> impl VisitMut { - CompressUrange {} +pub fn compress_unicode_range() -> impl VisitMut { + CompressUnicodeRange {} } -struct CompressUrange {} +struct CompressUnicodeRange {} -impl CompressUrange { +impl CompressUnicodeRange { fn remove_leading_zeros(&mut self, value: &str) -> String { let mut result = String::new(); let mut is_leading = true; @@ -49,52 +49,26 @@ impl CompressUrange { } } -// IE and Edge before 16 version ignore the unicode-range if the 'U' is -// lowercase +impl VisitMut for CompressUnicodeRange { + fn visit_mut_unicode_range(&mut self, unicode_range: &mut UnicodeRange) { + unicode_range.visit_mut_children_with(self); -impl VisitMut for CompressUrange { - fn visit_mut_urange(&mut self, urange: &mut Urange) { - urange.visit_mut_children_with(self); + if unicode_range.end.is_none() { + unicode_range.start = self.remove_leading_zeros(&*unicode_range.start).into(); - let str_value = &urange.value[2..]; - - if !urange.value.contains('-') { - let mut value = String::new(); - - value.push_str("U+"); - value.push_str(&self.remove_leading_zeros(str_value)); - - urange.value = value.into(); - - return; - } - - let parts: Vec<&str> = str_value.split('-').collect(); - - if parts.len() != 2 { return; } - let start = parts[0]; - let end = parts[1]; + let start = &unicode_range.start; + let end = unicode_range.end.as_ref().unwrap(); let merged = self.merge_start_and_end(start, end); if let Some(merged) = &merged { - let mut value = String::new(); - - value.push_str("U+"); - value.push_str(&self.remove_leading_zeros(merged)); - - urange.value = value.into(); + unicode_range.start = self.remove_leading_zeros(merged).into(); + unicode_range.end = None; } else { - let mut value = String::new(); - - value.push_str("U+"); - value.push_str(&self.remove_leading_zeros(start)); - value.push('-'); - value.push_str(&self.remove_leading_zeros(end)); - - urange.value = value.into(); + unicode_range.start = self.remove_leading_zeros(start).into(); + unicode_range.end = Some(self.remove_leading_zeros(end).into()); } } } diff --git a/crates/swc_css_minifier/src/lib.rs b/crates/swc_css_minifier/src/lib.rs index 492f003dc6e4..172b7a0fe8f6 100644 --- a/crates/swc_css_minifier/src/lib.rs +++ b/crates/swc_css_minifier/src/lib.rs @@ -8,7 +8,8 @@ use self::compress::{ easing_function::compress_easing_function, empty::compress_empty, frequency::compress_frequency, keyframes::compress_keyframes, length::compress_length, selector::compress_selector, time::compress_time, - transform_function::compress_transform_function, urange::compress_urange, url::compress_url, + transform_function::compress_transform_function, unicore_range::compress_unicode_range, + url::compress_url, }; mod compress; @@ -21,7 +22,7 @@ pub fn minify(stylesheet: &mut Stylesheet) { stylesheet.visit_mut_with(&mut compress_time()); stylesheet.visit_mut_with(&mut compress_frequency()); stylesheet.visit_mut_with(&mut compress_url()); - stylesheet.visit_mut_with(&mut compress_urange()); + stylesheet.visit_mut_with(&mut compress_unicode_range()); stylesheet.visit_mut_with(&mut compress_easing_function()); stylesheet.visit_mut_with(&mut compress_transform_function()); stylesheet.visit_mut_with(&mut compress_declaration()); diff --git a/crates/swc_css_minifier/tests/fixture/compress-urange/output.min.css b/crates/swc_css_minifier/tests/fixture/compress-urange/output.min.css index 4c4021bc0505..6f6c590e7124 100644 --- a/crates/swc_css_minifier/tests/fixture/compress-urange/output.min.css +++ b/crates/swc_css_minifier/tests/fixture/compress-urange/output.min.css @@ -1 +1 @@ -@font-face{unicode-range:U+26}@font-face{unicode-range:U+-7F}@font-face{unicode-range:U+25-FF}@font-face{unicode-range:U+25-FF,U+4??}@font-face{unicode-range:U+10????}@font-face{unicode-range:U+2b??}@font-face{unicode-range:U+2b??}@font-face{unicode-range:U+1e??}@font-face{unicode-range:U+2125-2128}@font-face{unicode-range:U+4??}@font-face{unicode-range:U+25-FF,U+4??}@font-face{unicode-range:U+450-4FF}@font-face{unicode-range:U+A5,U+4E00-9FFF,U+30??,U+FF00-FF9F}@font-face{unicode-range:U+????}@font-face{unicode-range:U+????}@font-face{unicode-range:U+10????}@font-face{unicode-range:U+10????}@font-face{unicode-range:U+1e1e?}@font-face{unicode-range:U+????,U+1????,U+10????}@font-face{unicode-range:U+25}@font-face{unicode-range:U+1e1e?}@font-face{unicode-range:U+25}@font-face{unicode-range:U+125}@font-face{unicode-range:U+100-FFFF}@font-face{unicode-range:U+10125}@font-face{unicode-range:U+450-4FF}@font-face{unicode-range:U+450-4FF}@font-face{unicode-range:U+450-4FF} +@font-face{unicode-range:U+26}@font-face{unicode-range:U+-7F}@font-face{unicode-range:U+25-FF}@font-face{unicode-range:U+25-FF,U+4??}@font-face{unicode-range:U+10????}@font-face{unicode-range:U+2b??}@font-face{unicode-range:u+2b??}@font-face{unicode-range:U+1e??}@font-face{unicode-range:U+2125-2128}@font-face{unicode-range:U+4??}@font-face{unicode-range:U+25-FF,U+4??}@font-face{unicode-range:U+450-4FF}@font-face{unicode-range:U+A5,U+4E00-9FFF,U+30??,U+FF00-FF9F}@font-face{unicode-range:U+????}@font-face{unicode-range:U+????}@font-face{unicode-range:U+10????}@font-face{unicode-range:U+10????}@font-face{unicode-range:U+1e1e?}@font-face{unicode-range:u+????,U+1????,U+10????}@font-face{unicode-range:U+25}@font-face{unicode-range:U+1e1e?}@font-face{unicode-range:U+25}@font-face{unicode-range:U+125}@font-face{unicode-range:U+100-FFFF}@font-face{unicode-range:U+10125}@font-face{unicode-range:U+450-4FF}@font-face{unicode-range:U+450-4FF}@font-face{unicode-range:U+450-4FF} diff --git a/crates/swc_css_parser/src/parser/value/mod.rs b/crates/swc_css_parser/src/parser/value/mod.rs index b12027ba1b0b..2979fa1297c5 100644 --- a/crates/swc_css_parser/src/parser/value/mod.rs +++ b/crates/swc_css_parser/src/parser/value/mod.rs @@ -188,7 +188,7 @@ where } else if &*value.to_ascii_lowercase() == "u" && peeked_is_one_of!(self, "+", "number", "dimension") { - return Ok(Value::Urange(self.parse()?)); + return Ok(Value::UnicodeRange(self.parse()?)); } return Ok(Value::Ident(self.parse()?)); @@ -1358,13 +1358,13 @@ where // u | // u | // u '+' '?'+ -impl Parse for Parser +impl Parse for Parser where I: ParserInput, { - fn parse(&mut self) -> PResult { + fn parse(&mut self) -> PResult { let span = self.input.cur_span()?; - let mut urange = String::new(); + let mut unicode_range = String::new(); // should start with `u` or `U` match cur!(self) { @@ -1376,7 +1376,7 @@ where } }; - urange.push_str(&ident); + unicode_range.push_str(&ident); } _ => { return Err(Error::new(span, ErrorKind::Expected("'u' ident token"))); @@ -1394,7 +1394,7 @@ where } }; - urange.push(plus); + unicode_range.push(plus); if is!(self, Ident) { let ident = match bump!(self) { @@ -1404,7 +1404,7 @@ where } }; - urange.push_str(&ident); + unicode_range.push_str(&ident); loop { if !is!(self, "?") { @@ -1418,7 +1418,7 @@ where } }; - urange.push(question); + unicode_range.push(question); } } else { let question = match bump!(self) { @@ -1428,7 +1428,7 @@ where } }; - urange.push(question); + unicode_range.push(question); loop { if !is!(self, "?") { @@ -1442,7 +1442,7 @@ where } }; - urange.push(question); + unicode_range.push(question); } } } @@ -1457,7 +1457,7 @@ where } }; - urange.push_str(&number); + unicode_range.push_str(&number.to_string()); match cur!(self) { tok!("?") => { @@ -1468,7 +1468,7 @@ where } }; - urange.push(question); + unicode_range.push(question); loop { if !is!(self, "?") { @@ -1482,7 +1482,7 @@ where } }; - urange.push(question); + unicode_range.push(question); } } tok!("dimension") => { @@ -1497,8 +1497,8 @@ where } }; - urange.push_str(&dimension.0); - urange.push_str(&dimension.1); + unicode_range.push_str(&dimension.0); + unicode_range.push_str(&dimension.1); } tok!("number") => { let number = match bump!(self) { @@ -1508,7 +1508,7 @@ where } }; - urange.push_str(&number); + unicode_range.push_str(&number); } _ => {} } @@ -1526,8 +1526,8 @@ where } }; - urange.push_str(&dimension.0); - urange.push_str(&dimension.1); + unicode_range.push_str(&dimension.0); + unicode_range.push_str(&dimension.1); loop { if !is!(self, "?") { @@ -1541,7 +1541,7 @@ where } }; - urange.push(question); + unicode_range.push(question); } } _ => { @@ -1552,9 +1552,171 @@ where } } - return Ok(Urange { + let mut chars = unicode_range.chars(); + + // 1. Skipping the first u token, concatenate the representations of all the + // tokens in the production together. Let this be text. + let prefix = chars.next().unwrap(); + + let mut next = chars.next(); + + // 2. If the first character of text is U+002B PLUS SIGN, consume it. Otherwise, + // this is an invalid , and this algorithm must exit. + if next != Some('+') { + return Err(Error::new( + span, + ErrorKind::Expected("'+' character after 'u' in unicode range"), + )); + } else { + next = chars.next(); + } + + // 3. Consume as many hex digits from text as possible. then consume as many + // U+003F QUESTION MARK (?) code points as possible. If zero code points + // were consumed, or more than six code points were consumed, this is an + // invalid , and this algorithm must exit. + let mut start = String::new(); + + loop { + match next { + Some(c) if c.is_digit(10) => { + start.push(c); + + next = chars.next(); + } + Some(c @ 'A'..='F') | Some(c @ 'a'..='f') => { + start.push(c); + + next = chars.next(); + } + _ => { + break; + } + } + } + + let mut has_question_mark = false; + + while let Some(c @ '?') = next { + has_question_mark = true; + + start.push(c); + + next = chars.next(); + } + + let len = start.len(); + + if len == 0 || len > 6 { + return Err(Error::new( + span, + ErrorKind::Expected( + "valid length (minimum 1 or maximum 6 hex digits) in the start of unicode \ + range", + ), + )); + } + + // If any U+003F QUESTION MARK (?) code points were consumed, then: + if has_question_mark { + // 1. If there are any code points left in text, this is an invalid , + // and this algorithm must exit. + if next != None { + return Err(Error::new( + span, + ErrorKind::Expected("no characters after '?' in unicode range"), + )); + } + + // 2. Interpret the consumed code points + // as a hexadecimal number, with the U+003F QUESTION MARK (?) code points + // replaced by U+0030 DIGIT ZERO (0) code points. This is the start value. + // + // 3. Interpret the consumed code points as a hexadecimal number again, with the + // U+003F QUESTION MARK (?) code points replaced by U+0046 LATIN CAPITAL LETTER + // F (F) code points. This is the end value. + // + + // 4. Exit this algorithm. + return Ok(UnicodeRange { + span: span!(self, span.lo), + prefix, + start: start.into(), + end: None, + }); + } + + // Otherwise, interpret the consumed code points as a hexadecimal number. This + // is the start value. + + // 4. If there are no code points left in text, The end value is the same as the + // start value. Exit this algorithm. + if next == None { + return Ok(UnicodeRange { + span: span!(self, span.lo), + prefix, + start: start.into(), + end: None, + }); + } + + // 5. If the next code point in text is U+002D HYPHEN-MINUS (-), consume it. + // Otherwise, this is an invalid , and this algorithm must exit. + if next != Some('-') { + return Err(Error::new( + span, + ErrorKind::Expected("'-' between start and end in unicode range"), + )); + } else { + next = chars.next(); + } + + // 6. Consume as many hex digits as possible from text. + // If zero hex digits were consumed, or more than 6 hex digits were consumed, + // this is an invalid , and this algorithm must exit. If there are any + // code points left in text, this is an invalid , and this algorithm + // must exit. + let mut end = String::new(); + + loop { + match next { + Some(c) if c.is_digit(10) => { + end.push(c); + next = chars.next(); + } + Some(c @ 'A'..='F') | Some(c @ 'a'..='f') => { + end.push(c); + next = chars.next(); + } + _ => { + break; + } + } + } + + let len = end.len(); + + if len == 0 || len > 6 { + return Err(Error::new( + span, + ErrorKind::Expected( + "valid length (minimum 1 or maximum 6 hex digits) in the end of unicode range", + ), + )); + } + + if chars.next() != None { + return Err(Error::new( + span, + ErrorKind::Expected("no characters after end in unicode range"), + )); + } + + return Ok(UnicodeRange { span: span!(self, span.lo), - value: urange.into(), + prefix, + start: start.into(), + end: Some(end.into()), }); } } diff --git a/crates/swc_css_parser/tests/fixture.rs b/crates/swc_css_parser/tests/fixture.rs index 0dd2bfab4e1a..b3e0f93032e2 100644 --- a/crates/swc_css_parser/tests/fixture.rs +++ b/crates/swc_css_parser/tests/fixture.rs @@ -396,7 +396,7 @@ impl Visit for SpanVisualizer<'_> { mtd!(UrlModifier, visit_url_modifier); - mtd!(Urange, visit_urange); + mtd!(UnicodeRange, visit_unicode_range); mtd!(Value, visit_value); diff --git a/crates/swc_css_parser/tests/fixture/value/urange/input.css b/crates/swc_css_parser/tests/fixture/value/urange/input.css index 451f870d7a31..c77ab4b75dc9 100644 --- a/crates/swc_css_parser/tests/fixture/value/urange/input.css +++ b/crates/swc_css_parser/tests/fixture/value/urange/input.css @@ -13,6 +13,7 @@ unicode-range: U+12; unicode-range: U+12e112; unicode-range: U+1e1ee1; + unicode-range: U+1e1ee1-FFFFFF; unicode-range: U+1e1ee?; unicode-range: U+12-13; } diff --git a/crates/swc_css_parser/tests/fixture/value/urange/output.json b/crates/swc_css_parser/tests/fixture/value/urange/output.json index 2c41a1e0665c..a43a423fe519 100644 --- a/crates/swc_css_parser/tests/fixture/value/urange/output.json +++ b/crates/swc_css_parser/tests/fixture/value/urange/output.json @@ -2,7 +2,7 @@ "type": "Stylesheet", "span": { "start": 0, - "end": 653, + "end": 689, "ctxt": 0 }, "rules": [ @@ -10,14 +10,14 @@ "type": "FontFaceRule", "span": { "start": 0, - "end": 652, + "end": 688, "ctxt": 0 }, "block": { "type": "SimpleBlock", "span": { "start": 11, - "end": 652, + "end": 688, "ctxt": 0 }, "name": "{", @@ -123,13 +123,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 97, "end": 101, "ctxt": 0 }, - "value": "U+26" + "prefix": "U", + "start": "26", + "end": null } ], "important": null @@ -153,13 +155,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 159, "end": 163, "ctxt": 0 }, - "value": "u+26" + "prefix": "u", + "start": "26", + "end": null } ], "important": null @@ -183,13 +187,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 184, "end": 190, "ctxt": 0 }, - "value": "U+0-7F" + "prefix": "U", + "start": "0", + "end": "7F" } ], "important": null @@ -213,13 +219,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 211, "end": 222, "ctxt": 0 }, - "value": "U+0025-00FF" + "prefix": "U", + "start": "0025", + "end": "00FF" } ], "important": null @@ -243,13 +251,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 272, "end": 277, "ctxt": 0 }, - "value": "U+4??" + "prefix": "U", + "start": "4??", + "end": null } ], "important": null @@ -273,13 +283,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 332, "end": 343, "ctxt": 0 }, - "value": "U+0025-00FF" + "prefix": "U", + "start": "0025", + "end": "00FF" }, { "type": "Delimiter", @@ -291,13 +303,15 @@ "value": "," }, { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 345, "end": 350, "ctxt": 0 }, - "value": "U+4??" + "prefix": "U", + "start": "4??", + "end": null } ], "important": null @@ -321,13 +335,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 393, "end": 397, "ctxt": 0 }, - "value": "U+A5" + "prefix": "U", + "start": "A5", + "end": null }, { "type": "Delimiter", @@ -339,13 +355,15 @@ "value": "," }, { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 399, "end": 410, "ctxt": 0 }, - "value": "U+4E00-9FFF" + "prefix": "U", + "start": "4E00", + "end": "9FFF" }, { "type": "Delimiter", @@ -357,13 +375,15 @@ "value": "," }, { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 412, "end": 418, "ctxt": 0 }, - "value": "U+30??" + "prefix": "U", + "start": "30??", + "end": null }, { "type": "Delimiter", @@ -375,13 +395,15 @@ "value": "," }, { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 420, "end": 431, "ctxt": 0 }, - "value": "U+FF00-FF9F" + "prefix": "U", + "start": "FF00", + "end": "FF9F" } ], "important": null @@ -405,13 +427,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 474, "end": 480, "ctxt": 0 }, - "value": "U+????" + "prefix": "U", + "start": "????", + "end": null } ], "important": null @@ -435,13 +459,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 501, "end": 509, "ctxt": 0 }, - "value": "U+??????" + "prefix": "U", + "start": "??????", + "end": null } ], "important": null @@ -465,13 +491,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 530, "end": 534, "ctxt": 0 }, - "value": "U+12" + "prefix": "U", + "start": "12", + "end": null } ], "important": null @@ -495,13 +523,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 555, "end": 563, "ctxt": 0 }, - "value": "U+12e112" + "prefix": "U", + "start": "12e112", + "end": null } ], "important": null @@ -525,13 +555,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 584, "end": 592, "ctxt": 0 }, - "value": "U+1e1ee1" + "prefix": "U", + "start": "1e1ee1", + "end": null } ], "important": null @@ -540,7 +572,7 @@ "type": "Declaration", "span": { "start": 598, - "end": 621, + "end": 628, "ctxt": 0 }, "name": { @@ -555,13 +587,15 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { "start": 613, - "end": 621, + "end": 628, "ctxt": 0 }, - "value": "U+1e1ee?" + "prefix": "U", + "start": "1e1ee1", + "end": "FFFFFF" } ], "important": null @@ -569,15 +603,15 @@ { "type": "Declaration", "span": { - "start": 627, - "end": 649, + "start": 634, + "end": 657, "ctxt": 0 }, "name": { "type": "Ident", "span": { - "start": 627, - "end": 640, + "start": 634, + "end": 647, "ctxt": 0 }, "value": "unicode-range", @@ -585,13 +619,47 @@ }, "value": [ { - "type": "Urange", + "type": "UnicodeRange", "span": { - "start": 642, - "end": 649, + "start": 649, + "end": 657, "ctxt": 0 }, - "value": "U+12-13" + "prefix": "U", + "start": "1e1ee?", + "end": null + } + ], + "important": null + }, + { + "type": "Declaration", + "span": { + "start": 663, + "end": 685, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 663, + "end": 676, + "ctxt": 0 + }, + "value": "unicode-range", + "raw": "unicode-range" + }, + "value": [ + { + "type": "UnicodeRange", + "span": { + "start": 678, + "end": 685, + "ctxt": 0 + }, + "prefix": "U", + "start": "12", + "end": "13" } ], "important": null diff --git a/crates/swc_css_parser/tests/fixture/value/urange/span.rust-debug b/crates/swc_css_parser/tests/fixture/value/urange/span.rust-debug index f87b1ae3f811..7c28364de915 100644 --- a/crates/swc_css_parser/tests/fixture/value/urange/span.rust-debug +++ b/crates/swc_css_parser/tests/fixture/value/urange/span.rust-debug @@ -6,8 +6,8 @@ error: Stylesheet 3 | | src: local('Times New Roman'); 4 | | unicode-range: U+26; /* single codepoint */ ... | -17 | | unicode-range: U+12-13; -18 | | } +18 | | unicode-range: U+12-13; +19 | | } | |__^ error: Rule @@ -18,8 +18,8 @@ error: Rule 3 | | src: local('Times New Roman'); 4 | | unicode-range: U+26; /* single codepoint */ ... | -17 | | unicode-range: U+12-13; -18 | | } +18 | | unicode-range: U+12-13; +19 | | } | |_^ error: AtRule @@ -30,8 +30,8 @@ error: AtRule 3 | | src: local('Times New Roman'); 4 | | unicode-range: U+26; /* single codepoint */ ... | -17 | | unicode-range: U+12-13; -18 | | } +18 | | unicode-range: U+12-13; +19 | | } | |_^ error: FontFaceRule @@ -42,8 +42,8 @@ error: FontFaceRule 3 | | src: local('Times New Roman'); 4 | | unicode-range: U+26; /* single codepoint */ ... | -17 | | unicode-range: U+12-13; -18 | | } +18 | | unicode-range: U+12-13; +19 | | } | |_^ error: SimpleBlock @@ -55,8 +55,8 @@ error: SimpleBlock 3 | | src: local('Times New Roman'); 4 | | unicode-range: U+26; /* single codepoint */ ... | -17 | | unicode-range: U+12-13; -18 | | } +18 | | unicode-range: U+12-13; +19 | | } | |_^ error: Declaration @@ -161,7 +161,7 @@ error: Value 4 | unicode-range: U+26; /* single codepoint */ | ^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:4:20 | 4 | unicode-range: U+26; /* single codepoint */ @@ -191,7 +191,7 @@ error: Value 5 | unicode-range: u+26; | ^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:5:20 | 5 | unicode-range: u+26; @@ -221,7 +221,7 @@ error: Value 6 | unicode-range: U+0-7F; | ^^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:6:20 | 6 | unicode-range: U+0-7F; @@ -251,7 +251,7 @@ error: Value 7 | unicode-range: U+0025-00FF; /* codepoint range */ | ^^^^^^^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:7:20 | 7 | unicode-range: U+0025-00FF; /* codepoint range */ @@ -281,7 +281,7 @@ error: Value 8 | unicode-range: U+4??; /* wildcard range */ | ^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:8:20 | 8 | unicode-range: U+4??; /* wildcard range */ @@ -311,7 +311,7 @@ error: Value 9 | unicode-range: U+0025-00FF, U+4??; /* multiple values */ | ^^^^^^^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:9:20 | 9 | unicode-range: U+0025-00FF, U+4??; /* multiple values */ @@ -335,7 +335,7 @@ error: Value 9 | unicode-range: U+0025-00FF, U+4??; /* multiple values */ | ^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:9:33 | 9 | unicode-range: U+0025-00FF, U+4??; /* multiple values */ @@ -365,7 +365,7 @@ error: Value 10 | unicode-range: U+A5, U+4E00-9FFF, U+30??, U+FF00-FF9F; /* multiple values */ | ^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:10:20 | 10 | unicode-range: U+A5, U+4E00-9FFF, U+30??, U+FF00-FF9F; /* multiple values */ @@ -389,7 +389,7 @@ error: Value 10 | unicode-range: U+A5, U+4E00-9FFF, U+30??, U+FF00-FF9F; /* multiple values */ | ^^^^^^^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:10:26 | 10 | unicode-range: U+A5, U+4E00-9FFF, U+30??, U+FF00-FF9F; /* multiple values */ @@ -413,7 +413,7 @@ error: Value 10 | unicode-range: U+A5, U+4E00-9FFF, U+30??, U+FF00-FF9F; /* multiple values */ | ^^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:10:39 | 10 | unicode-range: U+A5, U+4E00-9FFF, U+30??, U+FF00-FF9F; /* multiple values */ @@ -437,7 +437,7 @@ error: Value 10 | unicode-range: U+A5, U+4E00-9FFF, U+30??, U+FF00-FF9F; /* multiple values */ | ^^^^^^^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:10:47 | 10 | unicode-range: U+A5, U+4E00-9FFF, U+30??, U+FF00-FF9F; /* multiple values */ @@ -467,7 +467,7 @@ error: Value 11 | unicode-range: U+????; | ^^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:11:20 | 11 | unicode-range: U+????; @@ -497,7 +497,7 @@ error: Value 12 | unicode-range: U+??????; | ^^^^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:12:20 | 12 | unicode-range: U+??????; @@ -527,7 +527,7 @@ error: Value 13 | unicode-range: U+12; | ^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:13:20 | 13 | unicode-range: U+12; @@ -557,7 +557,7 @@ error: Value 14 | unicode-range: U+12e112; | ^^^^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:14:20 | 14 | unicode-range: U+12e112; @@ -587,7 +587,7 @@ error: Value 15 | unicode-range: U+1e1ee1; | ^^^^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:15:20 | 15 | unicode-range: U+1e1ee1; @@ -596,60 +596,90 @@ error: Urange error: Declaration --> $DIR/tests/fixture/value/urange/input.css:16:5 | -16 | unicode-range: U+1e1ee?; - | ^^^^^^^^^^^^^^^^^^^^^^^ +16 | unicode-range: U+1e1ee1-FFFFFF; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: DeclarationName --> $DIR/tests/fixture/value/urange/input.css:16:5 | -16 | unicode-range: U+1e1ee?; +16 | unicode-range: U+1e1ee1-FFFFFF; | ^^^^^^^^^^^^^ error: Ident --> $DIR/tests/fixture/value/urange/input.css:16:5 | -16 | unicode-range: U+1e1ee?; +16 | unicode-range: U+1e1ee1-FFFFFF; | ^^^^^^^^^^^^^ error: Value --> $DIR/tests/fixture/value/urange/input.css:16:20 | -16 | unicode-range: U+1e1ee?; - | ^^^^^^^^ +16 | unicode-range: U+1e1ee1-FFFFFF; + | ^^^^^^^^^^^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:16:20 | -16 | unicode-range: U+1e1ee?; - | ^^^^^^^^ +16 | unicode-range: U+1e1ee1-FFFFFF; + | ^^^^^^^^^^^^^^^ error: Declaration --> $DIR/tests/fixture/value/urange/input.css:17:5 | -17 | unicode-range: U+12-13; - | ^^^^^^^^^^^^^^^^^^^^^^ +17 | unicode-range: U+1e1ee?; + | ^^^^^^^^^^^^^^^^^^^^^^^ error: DeclarationName --> $DIR/tests/fixture/value/urange/input.css:17:5 | -17 | unicode-range: U+12-13; +17 | unicode-range: U+1e1ee?; | ^^^^^^^^^^^^^ error: Ident --> $DIR/tests/fixture/value/urange/input.css:17:5 | -17 | unicode-range: U+12-13; +17 | unicode-range: U+1e1ee?; | ^^^^^^^^^^^^^ error: Value --> $DIR/tests/fixture/value/urange/input.css:17:20 | -17 | unicode-range: U+12-13; - | ^^^^^^^ +17 | unicode-range: U+1e1ee?; + | ^^^^^^^^ -error: Urange +error: UnicodeRange --> $DIR/tests/fixture/value/urange/input.css:17:20 | -17 | unicode-range: U+12-13; +17 | unicode-range: U+1e1ee?; + | ^^^^^^^^ + +error: Declaration + --> $DIR/tests/fixture/value/urange/input.css:18:5 + | +18 | unicode-range: U+12-13; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: DeclarationName + --> $DIR/tests/fixture/value/urange/input.css:18:5 + | +18 | unicode-range: U+12-13; + | ^^^^^^^^^^^^^ + +error: Ident + --> $DIR/tests/fixture/value/urange/input.css:18:5 + | +18 | unicode-range: U+12-13; + | ^^^^^^^^^^^^^ + +error: Value + --> $DIR/tests/fixture/value/urange/input.css:18:20 + | +18 | unicode-range: U+12-13; + | ^^^^^^^ + +error: UnicodeRange + --> $DIR/tests/fixture/value/urange/input.css:18:20 + | +18 | unicode-range: U+12-13; | ^^^^^^^ diff --git a/crates/swc_css_parser/tests/recovery/unicode-range/input.css b/crates/swc_css_parser/tests/recovery/unicode-range/input.css new file mode 100644 index 000000000000..c67ca51c4eb6 --- /dev/null +++ b/crates/swc_css_parser/tests/recovery/unicode-range/input.css @@ -0,0 +1,4 @@ +.class { + unicode-range: U+1Z1ee1-FFFFFF; + unicode-range: U+1e1ee1-FFZFFF; +} diff --git a/crates/swc_css_parser/tests/recovery/unicode-range/output.json b/crates/swc_css_parser/tests/recovery/unicode-range/output.json new file mode 100644 index 000000000000..25f7f3a0cf6f --- /dev/null +++ b/crates/swc_css_parser/tests/recovery/unicode-range/output.json @@ -0,0 +1,205 @@ +{ + "type": "Stylesheet", + "span": { + "start": 0, + "end": 83, + "ctxt": 0 + }, + "rules": [ + { + "type": "QualifiedRule", + "span": { + "start": 0, + "end": 82, + "ctxt": 0 + }, + "prelude": { + "type": "SelectorList", + "span": { + "start": 0, + "end": 6, + "ctxt": 0 + }, + "children": [ + { + "type": "ComplexSelector", + "span": { + "start": 0, + "end": 6, + "ctxt": 0 + }, + "children": [ + { + "type": "CompoundSelector", + "span": { + "start": 0, + "end": 6, + "ctxt": 0 + }, + "nestingSelector": null, + "typeSelector": null, + "subclassSelectors": [ + { + "type": "ClassSelector", + "span": { + "start": 0, + "end": 6, + "ctxt": 0 + }, + "text": { + "type": "Ident", + "span": { + "start": 1, + "end": 6, + "ctxt": 0 + }, + "value": "class", + "raw": "class" + } + } + ] + } + ] + } + ] + }, + "block": { + "type": "SimpleBlock", + "span": { + "start": 7, + "end": 82, + "ctxt": 0 + }, + "name": "{", + "value": [ + { + "type": "Declaration", + "span": { + "start": 13, + "end": 43, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 13, + "end": 26, + "ctxt": 0 + }, + "value": "unicode-range", + "raw": "unicode-range" + }, + "value": [ + { + "type": "PreservedToken", + "span": { + "start": 28, + "end": 29, + "ctxt": 0 + }, + "token": { + "Ident": { + "value": "U", + "raw": "U" + } + } + }, + { + "type": "UnknownDimension", + "span": { + "start": 29, + "end": 43, + "ctxt": 0 + }, + "value": { + "type": "Number", + "span": { + "start": 29, + "end": 31, + "ctxt": 0 + }, + "value": 1.0, + "raw": "+1" + }, + "unit": { + "type": "Ident", + "span": { + "start": 31, + "end": 43, + "ctxt": 0 + }, + "value": "Z1ee1-FFFFFF", + "raw": "Z1ee1-FFFFFF" + } + } + ], + "important": null + }, + { + "type": "Declaration", + "span": { + "start": 49, + "end": 79, + "ctxt": 0 + }, + "name": { + "type": "Ident", + "span": { + "start": 49, + "end": 62, + "ctxt": 0 + }, + "value": "unicode-range", + "raw": "unicode-range" + }, + "value": [ + { + "type": "PreservedToken", + "span": { + "start": 64, + "end": 65, + "ctxt": 0 + }, + "token": { + "Ident": { + "value": "U", + "raw": "U" + } + } + }, + { + "type": "UnknownDimension", + "span": { + "start": 65, + "end": 79, + "ctxt": 0 + }, + "value": { + "type": "Number", + "span": { + "start": 65, + "end": 69, + "ctxt": 0 + }, + "value": 10.0, + "raw": "+1e1" + }, + "unit": { + "type": "Ident", + "span": { + "start": 69, + "end": 79, + "ctxt": 0 + }, + "value": "ee1-FFZFFF", + "raw": "ee1-FFZFFF" + } + } + ], + "important": null + } + ] + } + } + ] +} diff --git a/crates/swc_css_parser/tests/recovery/unicode-range/output.swc-stderr b/crates/swc_css_parser/tests/recovery/unicode-range/output.swc-stderr new file mode 100644 index 000000000000..946bde45a7c5 --- /dev/null +++ b/crates/swc_css_parser/tests/recovery/unicode-range/output.swc-stderr @@ -0,0 +1,12 @@ +error: Expected '-' between start and end in unicode range + --> $DIR/tests/recovery/unicode-range/input.css:2:20 + | +2 | unicode-range: U+1Z1ee1-FFFFFF; + | ^ + +error: Expected no characters after end in unicode range + --> $DIR/tests/recovery/unicode-range/input.css:3:20 + | +3 | unicode-range: U+1e1ee1-FFZFFF; + | ^ + diff --git a/crates/swc_css_visit/src/lib.rs b/crates/swc_css_visit/src/lib.rs index 886ac9e00a01..bb218fe5b5e0 100644 --- a/crates/swc_css_visit/src/lib.rs +++ b/crates/swc_css_visit/src/lib.rs @@ -114,7 +114,7 @@ define!({ Function(Function), CalcSum(CalcSum), Delimiter(Delimiter), - Urange(Urange), + UnicodeRange(UnicodeRange), Url(Url), ComplexSelector(ComplexSelector), PreservedToken(TokenAndSpan), @@ -236,9 +236,11 @@ define!({ Function(Function), } - pub struct Urange { + pub struct UnicodeRange { pub span: Span, - pub value: JsWord, + pub prefix: char, + pub start: JsWord, + pub end: Option, } pub struct CalcSum {