feat(css/parser): Allow invalid line comments (#2443)

swc_css_parser:
 - Accept line comments with an option.
This commit is contained in:
Donny/강동윤 2021-10-15 23:21:33 +09:00 committed by GitHub
parent c2ce89c0fb
commit 7f04ef4715
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 629 additions and 51 deletions

8
Cargo.lock generated
View File

@ -2500,7 +2500,7 @@ dependencies = [
[[package]] [[package]]
name = "swc_css" name = "swc_css"
version = "0.17.0" version = "0.18.0"
dependencies = [ dependencies = [
"swc_css_ast", "swc_css_ast",
"swc_css_codegen", "swc_css_codegen",
@ -2522,7 +2522,7 @@ dependencies = [
[[package]] [[package]]
name = "swc_css_codegen" name = "swc_css_codegen"
version = "0.15.0" version = "0.16.0"
dependencies = [ dependencies = [
"auto_impl", "auto_impl",
"bitflags", "bitflags",
@ -2548,7 +2548,7 @@ dependencies = [
[[package]] [[package]]
name = "swc_css_parser" name = "swc_css_parser"
version = "0.17.0" version = "0.18.0"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"lexical", "lexical",
@ -3142,7 +3142,7 @@ dependencies = [
[[package]] [[package]]
name = "swc_stylis" name = "swc_stylis"
version = "0.14.0" version = "0.15.0"
dependencies = [ dependencies = [
"swc_atoms 0.2.8", "swc_atoms 0.2.8",
"swc_common", "swc_common",

View File

@ -6,11 +6,11 @@ edition = "2018"
license = "Apache-2.0/MIT" license = "Apache-2.0/MIT"
name = "swc_css" name = "swc_css"
repository = "https://github.com/swc-project/swc.git" repository = "https://github.com/swc-project/swc.git"
version = "0.17.0" version = "0.18.0"
[dependencies] [dependencies]
swc_css_ast = {version = "0.16.0", path = "./ast"} swc_css_ast = {version = "0.16.0", path = "./ast"}
swc_css_codegen = {version = "0.15.0", path = "./codegen"} swc_css_codegen = {version = "0.16.0", path = "./codegen"}
swc_css_parser = {version = "0.17.0", path = "./parser"} swc_css_parser = {version = "0.18.0", path = "./parser"}
swc_css_utils = {version = "0.13.0", path = "./utils/"} swc_css_utils = {version = "0.13.0", path = "./utils/"}
swc_css_visit = {version = "0.15.0", path = "./visit"} swc_css_visit = {version = "0.15.0", path = "./visit"}

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT" license = "Apache-2.0/MIT"
name = "swc_css_codegen" name = "swc_css_codegen"
repository = "https://github.com/swc-project/swc.git" repository = "https://github.com/swc-project/swc.git"
version = "0.15.0" version = "0.16.0"
[dependencies] [dependencies]
auto_impl = "0.4.1" auto_impl = "0.4.1"
@ -17,6 +17,6 @@ swc_css_ast = {version = "0.16.0", path = "../ast/"}
swc_css_codegen_macros = {version = "0.2.0", path = "macros/"} swc_css_codegen_macros = {version = "0.2.0", path = "macros/"}
[dev-dependencies] [dev-dependencies]
swc_css_parser = {version = "0.17.0", path = "../parser"} swc_css_parser = {version = "0.18.0", path = "../parser"}
swc_css_visit = {version = "0.15.0", path = "../visit"} swc_css_visit = {version = "0.15.0", path = "../visit"}
testing = {version = "0.14.0", path = "../../testing"} testing = {version = "0.14.0", path = "../../testing"}

View File

@ -19,8 +19,15 @@ fn parse_again(input: PathBuf) {
eprintln!("==== ==== Input ==== ====\n{}\n", fm.src); eprintln!("==== ==== Input ==== ====\n{}\n", fm.src);
let mut errors = vec![]; let mut errors = vec![];
let mut stylesheet: Stylesheet = let mut stylesheet: Stylesheet = parse_file(
parse_file(&fm, ParserConfig { parse_values: true }, &mut errors).unwrap(); &fm,
ParserConfig {
parse_values: true,
..Default::default()
},
&mut errors,
)
.unwrap();
for err in take(&mut errors) { for err in take(&mut errors) {
err.to_diagnostics(&handler).emit(); err.to_diagnostics(&handler).emit();
@ -37,12 +44,17 @@ fn parse_again(input: PathBuf) {
eprintln!("==== ==== Codegen ==== ====\n{}\n", css_str); eprintln!("==== ==== Codegen ==== ====\n{}\n", css_str);
let new_fm = cm.new_source_file(FileName::Anon, css_str); let new_fm = cm.new_source_file(FileName::Anon, css_str);
let mut parsed: Stylesheet = let mut parsed: Stylesheet = parse_file(
parse_file(&new_fm, ParserConfig { parse_values: true }, &mut errors).map_err( &new_fm,
|err| { ParserConfig {
err.to_diagnostics(&handler).emit(); parse_values: true,
..Default::default()
}, },
)?; &mut errors,
)
.map_err(|err| {
err.to_diagnostics(&handler).emit();
})?;
for err in errors { for err in errors {
err.to_diagnostics(&handler).emit(); err.to_diagnostics(&handler).emit();

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT" license = "Apache-2.0/MIT"
name = "swc_css_parser" name = "swc_css_parser"
repository = "https://github.com/swc-project/swc.git" repository = "https://github.com/swc-project/swc.git"
version = "0.17.0" version = "0.18.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features] [features]

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
error::{Error, ErrorKind}, error::{Error, ErrorKind},
parser::{input::ParserInput, PResult}, parser::{input::ParserInput, PResult, ParserConfig},
}; };
use swc_atoms::{js_word, JsWord}; use swc_atoms::{js_word, JsWord};
use swc_common::{input::Input, BytePos, Span}; use swc_common::{input::Input, BytePos, Span};
@ -19,18 +19,20 @@ where
start_pos: BytePos, start_pos: BytePos,
/// Used to override last_pos /// Used to override last_pos
last_pos: Option<BytePos>, last_pos: Option<BytePos>,
config: ParserConfig,
} }
impl<I> Lexer<I> impl<I> Lexer<I>
where where
I: Input, I: Input,
{ {
pub fn new(input: I) -> Self { pub fn new(input: I, config: ParserConfig) -> Self {
let start_pos = input.last_pos(); let start_pos = input.last_pos();
Lexer { Lexer {
input, input,
start_pos, start_pos,
last_pos: None, last_pos: None,
config,
} }
} }
} }
@ -100,6 +102,15 @@ where
return self.read_token(); return self.read_token();
} }
if self.config.allow_wrong_line_comments {
if self.input.is_byte(b'/') && self.input.peek() == Some('/') {
self.skip_line_comment()?;
self.start_pos = self.input.cur_pos();
return self.read_token();
}
}
macro_rules! try_delim { macro_rules! try_delim {
($b:tt,$tok:tt) => {{ ($b:tt,$tok:tt) => {{
if self.input.eat_byte($b) { if self.input.eat_byte($b) {
@ -755,6 +766,15 @@ where
break; break;
} }
if self.config.allow_wrong_line_comments {
if self.input.is_byte(b'/') && self.input.peek() == Some('/') {
self.skip_line_comment()?;
self.start_pos = self.input.cur_pos();
return Ok(());
}
}
Ok(()) Ok(())
} }
@ -788,6 +808,29 @@ where
Err(ErrorKind::UnterminatedBlockComment) Err(ErrorKind::UnterminatedBlockComment)
} }
fn skip_line_comment(&mut self) -> LexResult<()> {
debug_assert_eq!(self.input.cur(), Some('/'));
debug_assert_eq!(self.input.peek(), Some('/'));
self.input.bump();
self.input.bump();
debug_assert!(
self.config.allow_wrong_line_comments,
"Line comments are wrong and should be lexed only if it's explicitly requested"
);
while let Some(c) = self.input.cur() {
if is_newline(c) {
break;
}
self.input.bump();
}
Ok(())
}
} }
#[inline(always)] #[inline(always)]

View File

@ -43,7 +43,7 @@ pub fn parse_str<'a, T>(
where where
Parser<Lexer<StringInput<'a>>>: Parse<T>, Parser<Lexer<StringInput<'a>>>: Parse<T>,
{ {
let lexer = Lexer::new(StringInput::new(src, start_pos, end_pos)); let lexer = Lexer::new(StringInput::new(src, start_pos, end_pos), config);
let mut parser = Parser::new(lexer, config); let mut parser = Parser::new(lexer, config);
let res = parser.parse(); let res = parser.parse();
@ -63,7 +63,7 @@ pub fn parse_file<'a, T>(
where where
Parser<Lexer<StringInput<'a>>>: Parse<T>, Parser<Lexer<StringInput<'a>>>: Parse<T>,
{ {
let lexer = Lexer::new(StringInput::from(fm)); let lexer = Lexer::new(StringInput::from(fm), config);
let mut parser = Parser::new(lexer, config); let mut parser = Parser::new(lexer, config);
let res = parser.parse(); let res = parser.parse();

View File

@ -24,6 +24,13 @@ pub type PResult<T> = Result<T, Error>;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ParserConfig { pub struct ParserConfig {
pub parse_values: bool, pub parse_values: bool,
/// If this is `true`, **wrong** comments starting with `//` will be treated
/// as a comment.
///
/// This option exists because there are so many css-in-js tools and people
/// use `//` as a comment because it's javascript file.
pub allow_wrong_line_comments: bool,
} }
#[derive(Debug, Default, Clone, Copy)] #[derive(Debug, Default, Clone, Copy)]

View File

@ -27,8 +27,15 @@ impl Visit for AssertValid {
let mut errors = vec![]; let mut errors = vec![];
let _selectors: Vec<ComplexSelector> = let _selectors: Vec<ComplexSelector> = parse_tokens(
parse_tokens(&s.args, ParserConfig { parse_values: true }, &mut errors) &s.args,
ParserConfig {
parse_values: true,
..Default::default()
},
&mut errors,
)
.unwrap_or_else(|err| panic!("failed to parse tokens: {:?}\n{:?}", err, s.args)); .unwrap_or_else(|err| panic!("failed to parse tokens: {:?}\n{:?}", err, s.args));
for err in errors { for err in errors {
@ -45,7 +52,7 @@ fn tokens_input(input: PathBuf) {
let fm = cm.load_file(&input).unwrap(); let fm = cm.load_file(&input).unwrap();
let tokens = { let tokens = {
let mut lexer = Lexer::new(SourceFileInput::from(&*fm)); let mut lexer = Lexer::new(SourceFileInput::from(&*fm), Default::default());
let mut tokens = vec![]; let mut tokens = vec![];
@ -59,8 +66,15 @@ fn tokens_input(input: PathBuf) {
}; };
let mut errors = vec![]; let mut errors = vec![];
let ss: Stylesheet = let ss: Stylesheet = parse_tokens(
parse_tokens(&tokens, ParserConfig { parse_values: true }, &mut errors) &tokens,
ParserConfig {
parse_values: true,
..Default::default()
},
&mut errors,
)
.expect("failed to parse tokens"); .expect("failed to parse tokens");
for err in errors { for err in errors {
@ -78,16 +92,15 @@ fn tokens_input(input: PathBuf) {
.unwrap(); .unwrap();
} }
#[testing::fixture("tests/fixture/**/input.css")] fn test_pass(input: PathBuf, config: ParserConfig) {
fn pass(input: PathBuf) {
eprintln!("Input: {}", input.display()); eprintln!("Input: {}", input.display());
testing::run_test2(false, |cm, handler| { testing::run_test2(false, |cm, handler| {
let ref_json_path = input.parent().unwrap().join("output.json"); let ref_json_path = input.parent().unwrap().join("output.json");
let fm = cm.load_file(&input).unwrap(); let fm = cm.load_file(&input).unwrap();
let lexer = Lexer::new(SourceFileInput::from(&*fm)); let lexer = Lexer::new(SourceFileInput::from(&*fm), config);
let mut parser = Parser::new(lexer, ParserConfig { parse_values: true }); let mut parser = Parser::new(lexer, config);
let stylesheet = parser.parse_all(); let stylesheet = parser.parse_all();
@ -99,8 +112,8 @@ fn pass(input: PathBuf) {
actual_json.clone().compare_to_file(&ref_json_path).unwrap(); actual_json.clone().compare_to_file(&ref_json_path).unwrap();
{ if !config.allow_wrong_line_comments {
let mut lexer = Lexer::new(SourceFileInput::from(&*fm)); let mut lexer = Lexer::new(SourceFileInput::from(&*fm), Default::default());
let mut tokens = Tokens { let mut tokens = Tokens {
span: Span::new(fm.start_pos, fm.end_pos, Default::default()), span: Span::new(fm.start_pos, fm.end_pos, Default::default()),
tokens: vec![], tokens: vec![],
@ -123,8 +136,15 @@ fn pass(input: PathBuf) {
} }
let mut errors = vec![]; let mut errors = vec![];
let ss_tok: Stylesheet = let ss_tok: Stylesheet = parse_tokens(
parse_tokens(&tokens, ParserConfig { parse_values: true }, &mut errors) &tokens,
ParserConfig {
parse_values: true,
..Default::default()
},
&mut errors,
)
.expect("failed to parse token"); .expect("failed to parse token");
for err in errors { for err in errors {
@ -153,6 +173,29 @@ fn pass(input: PathBuf) {
.unwrap(); .unwrap();
} }
#[testing::fixture("tests/fixture/**/input.css")]
fn pass(input: PathBuf) {
test_pass(
input,
ParserConfig {
parse_values: true,
..Default::default()
},
)
}
#[testing::fixture("tests/line-comment/**/input.css")]
fn line_commetns(input: PathBuf) {
test_pass(
input,
ParserConfig {
parse_values: true,
allow_wrong_line_comments: true,
..Default::default()
},
)
}
#[testing::fixture("tests/recovery/**/input.css")] #[testing::fixture("tests/recovery/**/input.css")]
fn recovery(input: PathBuf) { fn recovery(input: PathBuf) {
eprintln!("Input: {}", input.display()); eprintln!("Input: {}", input.display());
@ -168,9 +211,13 @@ fn recovery(input: PathBuf) {
let ref_json_path = input.parent().unwrap().join("output.json"); let ref_json_path = input.parent().unwrap().join("output.json");
let config = ParserConfig {
parse_values: true,
allow_wrong_line_comments: false,
};
let fm = cm.load_file(&input).unwrap(); let fm = cm.load_file(&input).unwrap();
let lexer = Lexer::new(SourceFileInput::from(&*fm)); let lexer = Lexer::new(SourceFileInput::from(&*fm), config);
let mut parser = Parser::new(lexer, ParserConfig { parse_values: true }); let mut parser = Parser::new(lexer, config);
let stylesheet = parser.parse_all(); let stylesheet = parser.parse_all();
@ -183,7 +230,7 @@ fn recovery(input: PathBuf) {
actual_json.clone().compare_to_file(&ref_json_path).unwrap(); actual_json.clone().compare_to_file(&ref_json_path).unwrap();
{ {
let mut lexer = Lexer::new(SourceFileInput::from(&*fm)); let mut lexer = Lexer::new(SourceFileInput::from(&*fm), Default::default());
let mut tokens = Tokens { let mut tokens = Tokens {
span: Span::new(fm.start_pos, fm.end_pos, Default::default()), span: Span::new(fm.start_pos, fm.end_pos, Default::default()),
tokens: vec![], tokens: vec![],
@ -206,8 +253,14 @@ fn recovery(input: PathBuf) {
} }
let mut errors = vec![]; let mut errors = vec![];
let ss_tok: Stylesheet = let ss_tok: Stylesheet = parse_tokens(
parse_tokens(&tokens, ParserConfig { parse_values: true }, &mut errors) &tokens,
ParserConfig {
parse_values: true,
..Default::default()
},
&mut errors,
)
.expect("failed to parse token"); .expect("failed to parse token");
for err in errors { for err in errors {
@ -340,13 +393,19 @@ fn span(input: PathBuf) {
let dir = input.parent().unwrap().to_path_buf(); let dir = input.parent().unwrap().to_path_buf();
let output = testing::run_test2(false, |cm, handler| { let output = testing::run_test2(false, |cm, handler| {
// Type annotation
if false { if false {
return Ok(()); return Ok(());
} }
let config = ParserConfig {
parse_values: true,
..Default::default()
};
let fm = cm.load_file(&input).unwrap(); let fm = cm.load_file(&input).unwrap();
let lexer = Lexer::new(SourceFileInput::from(&*fm)); let lexer = Lexer::new(SourceFileInput::from(&*fm), config);
let mut parser = Parser::new(lexer, ParserConfig { parse_values: true }); let mut parser = Parser::new(lexer, config);
let stylesheet = parser.parse_all(); let stylesheet = parser.parse_all();
@ -382,9 +441,15 @@ fn fail(input: PathBuf) {
let stderr_path = input.parent().unwrap().join("output.stderr"); let stderr_path = input.parent().unwrap().join("output.stderr");
let stderr = testing::run_test2(false, |cm, handler| -> Result<(), _> { let stderr = testing::run_test2(false, |cm, handler| -> Result<(), _> {
let config = ParserConfig {
parse_values: true,
..Default::default()
};
let fm = cm.load_file(&input).unwrap(); let fm = cm.load_file(&input).unwrap();
let lexer = Lexer::new(SourceFileInput::from(&*fm)); let lexer = Lexer::new(SourceFileInput::from(&*fm), config);
let mut parser = Parser::new(lexer, ParserConfig { parse_values: true }); let mut parser = Parser::new(lexer, config);
let stylesheet = parser.parse_all(); let stylesheet = parser.parse_all();

View File

@ -0,0 +1,4 @@
// Line comment
foo {
color: red;
}

View File

@ -0,0 +1,101 @@
{
"type": "Stylesheet",
"span": {
"start": 15,
"end": 40,
"ctxt": 0
},
"rules": [
{
"type": "StyleRule",
"span": {
"start": 16,
"end": 39,
"ctxt": 0
},
"selectors": [
{
"type": "ComplexSelector",
"span": {
"start": 16,
"end": 19,
"ctxt": 0
},
"selectors": [
{
"type": "CompoundSelector",
"span": {
"start": 16,
"end": 19,
"ctxt": 0
},
"hasNestPrefix": false,
"combinator": null,
"typeSelector": {
"type": "NamespacedName",
"span": {
"start": 16,
"end": 19,
"ctxt": 0
},
"prefix": null,
"name": {
"type": "Text",
"span": {
"start": 16,
"end": 19,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
}
},
"subclassSelectors": []
}
]
}
],
"block": {
"type": "DeclBlock",
"span": {
"start": 20,
"end": 39,
"ctxt": 0
},
"items": [
{
"type": "Property",
"span": {
"start": 26,
"end": 36,
"ctxt": 0
},
"name": {
"type": "Text",
"span": {
"start": 26,
"end": 31,
"ctxt": 0
},
"value": "color",
"raw": "color"
},
"values": [
{
"type": "Text",
"span": {
"start": 33,
"end": 36,
"ctxt": 0
},
"value": "red",
"raw": "red"
}
],
"important": null
}
]
}
}
]
}

View File

@ -0,0 +1,4 @@
foo {
// Line comment
color: red;
}

View File

@ -0,0 +1,101 @@
{
"type": "Stylesheet",
"span": {
"start": 0,
"end": 44,
"ctxt": 0
},
"rules": [
{
"type": "StyleRule",
"span": {
"start": 0,
"end": 43,
"ctxt": 0
},
"selectors": [
{
"type": "ComplexSelector",
"span": {
"start": 0,
"end": 3,
"ctxt": 0
},
"selectors": [
{
"type": "CompoundSelector",
"span": {
"start": 0,
"end": 3,
"ctxt": 0
},
"hasNestPrefix": false,
"combinator": null,
"typeSelector": {
"type": "NamespacedName",
"span": {
"start": 0,
"end": 3,
"ctxt": 0
},
"prefix": null,
"name": {
"type": "Text",
"span": {
"start": 0,
"end": 3,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
}
},
"subclassSelectors": []
}
]
}
],
"block": {
"type": "DeclBlock",
"span": {
"start": 4,
"end": 43,
"ctxt": 0
},
"items": [
{
"type": "Property",
"span": {
"start": 30,
"end": 40,
"ctxt": 0
},
"name": {
"type": "Text",
"span": {
"start": 30,
"end": 35,
"ctxt": 0
},
"value": "color",
"raw": "color"
},
"values": [
{
"type": "Text",
"span": {
"start": 37,
"end": 40,
"ctxt": 0
},
"value": "red",
"raw": "red"
}
],
"important": null
}
]
}
}
]
}

View File

@ -0,0 +1,4 @@
foo {
color: red;
// Line comment
}

View File

@ -0,0 +1,101 @@
{
"type": "Stylesheet",
"span": {
"start": 0,
"end": 44,
"ctxt": 0
},
"rules": [
{
"type": "StyleRule",
"span": {
"start": 0,
"end": 43,
"ctxt": 0
},
"selectors": [
{
"type": "ComplexSelector",
"span": {
"start": 0,
"end": 3,
"ctxt": 0
},
"selectors": [
{
"type": "CompoundSelector",
"span": {
"start": 0,
"end": 3,
"ctxt": 0
},
"hasNestPrefix": false,
"combinator": null,
"typeSelector": {
"type": "NamespacedName",
"span": {
"start": 0,
"end": 3,
"ctxt": 0
},
"prefix": null,
"name": {
"type": "Text",
"span": {
"start": 0,
"end": 3,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
}
},
"subclassSelectors": []
}
]
}
],
"block": {
"type": "DeclBlock",
"span": {
"start": 4,
"end": 43,
"ctxt": 0
},
"items": [
{
"type": "Property",
"span": {
"start": 10,
"end": 20,
"ctxt": 0
},
"name": {
"type": "Text",
"span": {
"start": 10,
"end": 15,
"ctxt": 0
},
"value": "color",
"raw": "color"
},
"values": [
{
"type": "Text",
"span": {
"start": 17,
"end": 20,
"ctxt": 0
},
"value": "red",
"raw": "red"
}
],
"important": null
}
]
}
}
]
}

View File

@ -0,0 +1,5 @@
foo {
color: red;
// Line comment
top: 0;
}

View File

@ -0,0 +1,131 @@
{
"type": "Stylesheet",
"span": {
"start": 0,
"end": 56,
"ctxt": 0
},
"rules": [
{
"type": "StyleRule",
"span": {
"start": 0,
"end": 55,
"ctxt": 0
},
"selectors": [
{
"type": "ComplexSelector",
"span": {
"start": 0,
"end": 3,
"ctxt": 0
},
"selectors": [
{
"type": "CompoundSelector",
"span": {
"start": 0,
"end": 3,
"ctxt": 0
},
"hasNestPrefix": false,
"combinator": null,
"typeSelector": {
"type": "NamespacedName",
"span": {
"start": 0,
"end": 3,
"ctxt": 0
},
"prefix": null,
"name": {
"type": "Text",
"span": {
"start": 0,
"end": 3,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
}
},
"subclassSelectors": []
}
]
}
],
"block": {
"type": "DeclBlock",
"span": {
"start": 4,
"end": 55,
"ctxt": 0
},
"items": [
{
"type": "Property",
"span": {
"start": 10,
"end": 20,
"ctxt": 0
},
"name": {
"type": "Text",
"span": {
"start": 10,
"end": 15,
"ctxt": 0
},
"value": "color",
"raw": "color"
},
"values": [
{
"type": "Text",
"span": {
"start": 17,
"end": 20,
"ctxt": 0
},
"value": "red",
"raw": "red"
}
],
"important": null
},
{
"type": "Property",
"span": {
"start": 46,
"end": 52,
"ctxt": 0
},
"name": {
"type": "Text",
"span": {
"start": 46,
"end": 49,
"ctxt": 0
},
"value": "top",
"raw": "top"
},
"values": [
{
"type": "Number",
"span": {
"start": 51,
"end": 52,
"ctxt": 0
},
"value": 0.0
}
],
"important": null
}
]
}
}
]
}

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT" license = "Apache-2.0/MIT"
name = "swc_stylis" name = "swc_stylis"
repository = "https://github.com/swc-project/swc.git" repository = "https://github.com/swc-project/swc.git"
version = "0.14.0" version = "0.15.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -18,6 +18,6 @@ swc_css_utils = {version = "0.13.0", path = "../utils/"}
swc_css_visit = {version = "0.15.0", path = "../visit"} swc_css_visit = {version = "0.15.0", path = "../visit"}
[dev-dependencies] [dev-dependencies]
swc_css_codegen = {version = "0.15.0", path = "../codegen"} swc_css_codegen = {version = "0.16.0", path = "../codegen"}
swc_css_parser = {version = "0.17.0", path = "../parser"} swc_css_parser = {version = "0.18.0", path = "../parser"}
testing = {version = "0.14.0", path = "../../testing"} testing = {version = "0.14.0", path = "../../testing"}