mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
fix(parser): fix incorrectly identified directives (#1885)
Parser incorrectly identifies string literals as directives if they
follow after `import`s, `export`s, or decorators.
In all of these cases, `'use strict'` produces a directive in the AST,
where it should be parsed as an `ExpressionStatement` containing a
`StringLiteral`:
```js
import x from 'foo';
'use strict';
```
```js
export {x};
'use strict';
```
```js
@foo
'use strict';
```
[Playground](https://oxc-project.github.io/oxc/playground/?code=3YCAAIC0gICAgICAgIC0G8rnONK89ITJ3zrK%2FUP7OmSZPgHQzStr3yMtwFTU%2BD1WPt09JgqZJLoYooydbGsM5vGcf34BnIA%3D)
This PR should fix that.
I'm not sure about the decorator case, though. I assume it's not a
directive. But is prefixing a string literal with a decorator even legal
syntax anyway?
And a side nit: If I'm reading it right, I don't think the `continue`
statement in the decorator arm of the match does anything. Do I have
that right?
Last question: Where does one go about putting a test? I guess these
silly cases aren't covered by Babel etc's tests.
---------
Co-authored-by: Boshen <boshenc@gmail.com>
This commit is contained in:
parent
11ca5c2bad
commit
eb2966c512
2 changed files with 19 additions and 0 deletions
|
|
@ -44,13 +44,16 @@ impl<'a> Parser<'a> {
|
||||||
Kind::Import if !matches!(self.peek_kind(), Kind::Dot | Kind::LParen) => {
|
Kind::Import if !matches!(self.peek_kind(), Kind::Dot | Kind::LParen) => {
|
||||||
let stmt = self.parse_import_declaration()?;
|
let stmt = self.parse_import_declaration()?;
|
||||||
statements.push(stmt);
|
statements.push(stmt);
|
||||||
|
expecting_directives = false;
|
||||||
}
|
}
|
||||||
Kind::Export => {
|
Kind::Export => {
|
||||||
let stmt = self.parse_export_declaration()?;
|
let stmt = self.parse_export_declaration()?;
|
||||||
statements.push(stmt);
|
statements.push(stmt);
|
||||||
|
expecting_directives = false;
|
||||||
}
|
}
|
||||||
Kind::At => {
|
Kind::At => {
|
||||||
self.eat_decorators()?;
|
self.eat_decorators()?;
|
||||||
|
expecting_directives = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
||||||
|
|
@ -300,6 +300,22 @@ mod test {
|
||||||
assert_eq!(ret.errors.first().unwrap().to_string(), "Flow is not supported");
|
assert_eq!(ret.errors.first().unwrap().to_string(), "Flow is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn directives() {
|
||||||
|
let allocator = Allocator::default();
|
||||||
|
let source_type = SourceType::default();
|
||||||
|
let sources = [
|
||||||
|
("import x from 'foo'; 'use strict';", 2),
|
||||||
|
("export {x} from 'foo'; 'use strict';", 2),
|
||||||
|
("@decorator 'use strict';", 1),
|
||||||
|
];
|
||||||
|
for (source, body_length) in sources {
|
||||||
|
let ret = Parser::new(&allocator, source, source_type).parse();
|
||||||
|
assert!(ret.program.directives.is_empty(), "{source}");
|
||||||
|
assert_eq!(ret.program.body.len(), body_length, "{source}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Source with length u32::MAX + 1 fails to parse
|
// Source with length u32::MAX + 1 fails to parse
|
||||||
#[test]
|
#[test]
|
||||||
fn overlong_source() {
|
fn overlong_source() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue