mirror of
https://github.com/swc-project/swc.git
synced 2024-11-23 17:54:15 +03:00
fix(css/lexer): Exclude whitespace from spans (#2702)
This commit is contained in:
parent
5db7bdc133
commit
0b1042354c
@ -88,25 +88,7 @@ where
|
||||
I: Input,
|
||||
{
|
||||
fn read_token(&mut self) -> LexResult<Token> {
|
||||
// Consume comments.
|
||||
// If the next two input code point are U+002F SOLIDUS (/) followed by a U+002A
|
||||
// ASTERISK (*), consume them and all following code points up to and including
|
||||
// the first U+002A ASTERISK (*) followed by a U+002F SOLIDUS (/), or up to an
|
||||
// EOF code point. Return to the start of this step.
|
||||
if self.input.cur() == Some('/') {
|
||||
if self.input.peek() == Some('*') {
|
||||
self.skip_block_comment()?;
|
||||
self.skip_ws()?;
|
||||
self.start_pos = self.input.cur_pos();
|
||||
|
||||
return self.read_token();
|
||||
} else if self.config.allow_wrong_line_comments && self.input.peek() == Some('/') {
|
||||
self.skip_line_comment()?;
|
||||
self.start_pos = self.input.cur_pos();
|
||||
|
||||
return self.read_token();
|
||||
}
|
||||
}
|
||||
self.read_comments()?;
|
||||
|
||||
let start = self.input.cur_pos();
|
||||
let next = self.input.cur();
|
||||
@ -116,7 +98,10 @@ where
|
||||
// whitespace
|
||||
// Consume as much whitespace as possible. Return a <whitespace-token>.
|
||||
Some(c) if is_whitespace(c) => {
|
||||
self.input.bump();
|
||||
|
||||
let mut value = String::new();
|
||||
value.push(c);
|
||||
|
||||
loop {
|
||||
let c = self.input.cur();
|
||||
@ -133,13 +118,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
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(Token::WhiteSpace {
|
||||
value: value.into(),
|
||||
});
|
||||
@ -430,6 +408,81 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// Consume comments.
|
||||
// This section describes how to consume comments from a stream of code points.
|
||||
// It returns nothing.
|
||||
fn read_comments(&mut self) -> LexResult<()> {
|
||||
// If the next two input code point are U+002F SOLIDUS (/) followed by a U+002A
|
||||
// ASTERISK (*), consume them and all following code points up to and including
|
||||
// the first U+002A ASTERISK (*) followed by a U+002F SOLIDUS (/), or up to an
|
||||
// EOF code point. Return to the start of this step.
|
||||
// NOTE: We allow to parse line comments under the option.
|
||||
if self.input.cur() == Some('/') && self.input.peek() == Some('*') {
|
||||
while self.input.cur() == Some('/') && self.input.peek() == Some('*') {
|
||||
self.input.bump(); // '*'
|
||||
self.input.bump(); // '/'
|
||||
|
||||
loop {
|
||||
let cur = self.input.cur();
|
||||
|
||||
if cur.is_some() {
|
||||
self.input.bump();
|
||||
}
|
||||
|
||||
match cur {
|
||||
Some('*') if self.input.cur() == Some('/') => {
|
||||
self.input.bump(); // '/'
|
||||
|
||||
break;
|
||||
}
|
||||
Some(_) => {}
|
||||
None => {
|
||||
return Err(ErrorKind::UnterminatedBlockComment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: invalid
|
||||
self.skip_ws()?;
|
||||
}
|
||||
|
||||
self.start_pos = self.input.cur_pos();
|
||||
} else if self.config.allow_wrong_line_comments
|
||||
&& self.input.cur() == Some('/')
|
||||
&& self.input.peek() == Some('/')
|
||||
{
|
||||
while self.input.cur() == Some('/') && self.input.peek() == Some('/') {
|
||||
self.input.bump(); // '/'
|
||||
self.input.bump(); // '/'
|
||||
|
||||
loop {
|
||||
let cur = self.input.cur();
|
||||
|
||||
if cur.is_some() {
|
||||
self.input.bump();
|
||||
}
|
||||
|
||||
match cur {
|
||||
Some(c) if is_newline(c) => {
|
||||
break;
|
||||
}
|
||||
Some(_) => {}
|
||||
None => {
|
||||
return Err(ErrorKind::UnterminatedBlockComment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: invalid
|
||||
self.skip_ws()?;
|
||||
}
|
||||
|
||||
self.start_pos = self.input.cur_pos();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This section describes how to consume a numeric token from a stream of code
|
||||
// points. It returns either a <number-token>, <percentage-token>, or
|
||||
// <dimension-token>.
|
||||
@ -1242,69 +1295,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
/// Expects current char to be '/' and next char to be '*'.
|
||||
fn skip_block_comment(&mut self) -> LexResult<()> {
|
||||
debug_assert_eq!(self.input.cur(), Some('/'));
|
||||
debug_assert_eq!(self.input.peek(), Some('*'));
|
||||
|
||||
self.input.bump();
|
||||
self.input.bump();
|
||||
|
||||
// let slice_start = self.input.cur_pos();
|
||||
let mut was_star = if self.input.is_byte(b'*') {
|
||||
self.input.bump();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
while let Some(c) = self.input.cur() {
|
||||
if was_star && c == '/' {
|
||||
debug_assert_eq!(self.input.cur(), Some('/'));
|
||||
self.input.bump(); // '/'
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
was_star = c == '*';
|
||||
self.input.bump();
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
6
css/parser/tests/errors/comments/bad-comment-4/input.css
Normal file
6
css/parser/tests/errors/comments/bad-comment-4/input.css
Normal file
@ -0,0 +1,6 @@
|
||||
a {
|
||||
background: url(
|
||||
/* test */
|
||||
"test.png"
|
||||
);
|
||||
}
|
10
css/parser/tests/errors/comments/bad-comment-4/output.stderr
Normal file
10
css/parser/tests/errors/comments/bad-comment-4/output.stderr
Normal file
@ -0,0 +1,10 @@
|
||||
error: Expected Declaration value
|
||||
--> $DIR/tests/errors/comments/bad-comment-4/input.css:2:17
|
||||
|
|
||||
2 | background: url(
|
||||
| _________________^
|
||||
3 | | /* test */
|
||||
4 | | "test.png"
|
||||
5 | | );
|
||||
| |_____^
|
||||
|
6
css/parser/tests/errors/comments/bad-comment-5/input.css
Normal file
6
css/parser/tests/errors/comments/bad-comment-5/input.css
Normal file
@ -0,0 +1,6 @@
|
||||
a {
|
||||
background: url(
|
||||
/* test */
|
||||
test.png
|
||||
);
|
||||
}
|
10
css/parser/tests/errors/comments/bad-comment-5/output.stderr
Normal file
10
css/parser/tests/errors/comments/bad-comment-5/output.stderr
Normal file
@ -0,0 +1,10 @@
|
||||
error: Expected Declaration value
|
||||
--> $DIR/tests/errors/comments/bad-comment-5/input.css:2:17
|
||||
|
|
||||
2 | background: url(
|
||||
| _________________^
|
||||
3 | | /* test */
|
||||
4 | | test.png
|
||||
5 | | );
|
||||
| |_____^
|
||||
|
@ -33,3 +33,4 @@ st*/
|
||||
/*!te**st*/
|
||||
/****************************/
|
||||
/*************** FOO *****************/
|
||||
/* comment *//* comment */
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"type": "Stylesheet",
|
||||
"span": {
|
||||
"start": 15,
|
||||
"start": 16,
|
||||
"end": 40,
|
||||
"ctxt": 0
|
||||
},
|
||||
|
5
css/parser/tests/line-comment/css-in-js/5/input.css
Normal file
5
css/parser/tests/line-comment/css-in-js/5/input.css
Normal file
@ -0,0 +1,5 @@
|
||||
// Line comment
|
||||
// Line comment
|
||||
foo {
|
||||
color: red;
|
||||
}
|
108
css/parser/tests/line-comment/css-in-js/5/output.json
Normal file
108
css/parser/tests/line-comment/css-in-js/5/output.json
Normal file
@ -0,0 +1,108 @@
|
||||
{
|
||||
"type": "Stylesheet",
|
||||
"span": {
|
||||
"start": 32,
|
||||
"end": 56,
|
||||
"ctxt": 0
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"type": "StyleRule",
|
||||
"span": {
|
||||
"start": 32,
|
||||
"end": 55,
|
||||
"ctxt": 0
|
||||
},
|
||||
"selectors": {
|
||||
"type": "SelectorList",
|
||||
"span": {
|
||||
"start": 32,
|
||||
"end": 35,
|
||||
"ctxt": 0
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "ComplexSelector",
|
||||
"span": {
|
||||
"start": 32,
|
||||
"end": 35,
|
||||
"ctxt": 0
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "CompoundSelector",
|
||||
"span": {
|
||||
"start": 32,
|
||||
"end": 35,
|
||||
"ctxt": 0
|
||||
},
|
||||
"nestingSelector": null,
|
||||
"typeSelector": {
|
||||
"type": "TypeSelector",
|
||||
"span": {
|
||||
"start": 32,
|
||||
"end": 35,
|
||||
"ctxt": 0
|
||||
},
|
||||
"prefix": null,
|
||||
"name": {
|
||||
"type": "Text",
|
||||
"span": {
|
||||
"start": 32,
|
||||
"end": 35,
|
||||
"ctxt": 0
|
||||
},
|
||||
"value": "foo",
|
||||
"raw": "foo"
|
||||
}
|
||||
},
|
||||
"subclassSelectors": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"block": {
|
||||
"type": "Block",
|
||||
"span": {
|
||||
"start": 36,
|
||||
"end": 55,
|
||||
"ctxt": 0
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"type": "Declaration",
|
||||
"span": {
|
||||
"start": 42,
|
||||
"end": 52,
|
||||
"ctxt": 0
|
||||
},
|
||||
"property": {
|
||||
"type": "Text",
|
||||
"span": {
|
||||
"start": 42,
|
||||
"end": 47,
|
||||
"ctxt": 0
|
||||
},
|
||||
"value": "color",
|
||||
"raw": "color"
|
||||
},
|
||||
"value": [
|
||||
{
|
||||
"type": "Text",
|
||||
"span": {
|
||||
"start": 49,
|
||||
"end": 52,
|
||||
"ctxt": 0
|
||||
},
|
||||
"value": "red",
|
||||
"raw": "red"
|
||||
}
|
||||
],
|
||||
"important": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
5
css/parser/tests/line-comment/css-in-js/6/input.css
Normal file
5
css/parser/tests/line-comment/css-in-js/6/input.css
Normal file
@ -0,0 +1,5 @@
|
||||
foo {
|
||||
// Line comment
|
||||
// Line comment
|
||||
color: red;
|
||||
}
|
108
css/parser/tests/line-comment/css-in-js/6/output.json
Normal file
108
css/parser/tests/line-comment/css-in-js/6/output.json
Normal file
@ -0,0 +1,108 @@
|
||||
{
|
||||
"type": "Stylesheet",
|
||||
"span": {
|
||||
"start": 0,
|
||||
"end": 64,
|
||||
"ctxt": 0
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"type": "StyleRule",
|
||||
"span": {
|
||||
"start": 0,
|
||||
"end": 63,
|
||||
"ctxt": 0
|
||||
},
|
||||
"selectors": {
|
||||
"type": "SelectorList",
|
||||
"span": {
|
||||
"start": 0,
|
||||
"end": 3,
|
||||
"ctxt": 0
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "ComplexSelector",
|
||||
"span": {
|
||||
"start": 0,
|
||||
"end": 3,
|
||||
"ctxt": 0
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "CompoundSelector",
|
||||
"span": {
|
||||
"start": 0,
|
||||
"end": 3,
|
||||
"ctxt": 0
|
||||
},
|
||||
"nestingSelector": null,
|
||||
"typeSelector": {
|
||||
"type": "TypeSelector",
|
||||
"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": "Block",
|
||||
"span": {
|
||||
"start": 4,
|
||||
"end": 63,
|
||||
"ctxt": 0
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"type": "Declaration",
|
||||
"span": {
|
||||
"start": 50,
|
||||
"end": 60,
|
||||
"ctxt": 0
|
||||
},
|
||||
"property": {
|
||||
"type": "Text",
|
||||
"span": {
|
||||
"start": 50,
|
||||
"end": 55,
|
||||
"ctxt": 0
|
||||
},
|
||||
"value": "color",
|
||||
"raw": "color"
|
||||
},
|
||||
"value": [
|
||||
{
|
||||
"type": "Text",
|
||||
"span": {
|
||||
"start": 57,
|
||||
"end": 60,
|
||||
"ctxt": 0
|
||||
},
|
||||
"value": "red",
|
||||
"raw": "red"
|
||||
}
|
||||
],
|
||||
"important": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user