fix(parser): Disallow ReservedWord in NamedExports (#1230)

- fix: #1222

---------

Co-authored-by: Boshen <boshenc@gmail.com>
This commit is contained in:
magic-akari 2023-11-12 18:52:02 +08:00 committed by GitHub
parent f775488102
commit 9c0aafcd1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 48 additions and 12 deletions

View file

@ -2063,7 +2063,7 @@ impl fmt::Display for ModuleExportName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match self {
Self::Identifier(identifier) => identifier.name.to_string(),
Self::StringLiteral(literal) => literal.value.to_string(),
Self::StringLiteral(literal) => format!(r#""{}""#, literal.value),
};
write!(f, "{s}")
}

View file

@ -2,7 +2,7 @@ use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::{self, Error},
};
use oxc_span::{Atom, Span};
use oxc_span::Span;
#[derive(Debug, Error, Diagnostic)]
#[error("Flow is not supported")]
@ -215,8 +215,13 @@ pub struct ExportLoneSurrogate(#[label] pub Span);
#[derive(Debug, Error, Diagnostic)]
#[error("A string literal cannot be used as an exported binding without `from`")]
#[diagnostic(help("Did you mean `export {{ '{0}' as '{1}' }} from 'some-module'`?"))]
pub struct ExportNamedString(pub Atom, pub Atom, #[label] pub Span);
#[diagnostic(help("Did you mean `export {{ {0} as {1} }} from 'some-module'`?"))]
pub struct ExportNamedString(pub String, pub String, #[label] pub Span);
#[derive(Debug, Error, Diagnostic)]
#[error("A reserved word cannot be used as an exported binding without `from`")]
#[diagnostic(help("Did you mean `export {{ {0} as {1} }} from 'some-module'`?"))]
pub struct ExportReservedWord(pub String, pub String, #[label] pub Span);
#[derive(Debug, Error, Diagnostic)]
#[error("Bad escape sequence in untagged template literal")]

View file

@ -239,15 +239,32 @@ impl<'a> Parser<'a> {
};
// ExportDeclaration : export NamedExports ;
// * It is a Syntax Error if ReferencedBindings of NamedExports contains any StringLiterals.
if source.is_none() {
for specifier in &specifiers {
if let ModuleExportName::StringLiteral(literal) = &specifier.local {
self.error(diagnostics::ExportNamedString(
literal.value.clone(),
specifier.local.name().clone(),
literal.span,
));
match &specifier.local {
// It is a Syntax Error if ReferencedBindings of NamedExports contains any StringLiterals.
ModuleExportName::StringLiteral(literal) => {
self.error(diagnostics::ExportNamedString(
specifier.local.to_string(),
specifier.exported.to_string(),
literal.span,
));
}
// For each IdentifierName n in ReferencedBindings of NamedExports:
// It is a Syntax Error if StringValue of n is a ReservedWord or the StringValue of n
// is one of "implements", "interface", "let", "package", "private", "protected", "public", or "static".
ModuleExportName::Identifier(id) => {
let match_result = Kind::match_keyword(&id.name);
if match_result.is_reserved_keyword()
|| match_result.is_future_reserved_keyword()
{
self.error(diagnostics::ExportReservedWord(
specifier.local.to_string(),
specifier.exported.to_string(),
id.span,
));
}
}
}
}
}

View file

@ -6947,6 +6947,13 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
· ─
╰────
× A reserved word cannot be used as an exported binding without `from`
╭─[esprima/es2015-export-declaration/invalid-export-default-token/input.js:1:1]
1 │ export {default} +
· ───────
╰────
help: Did you mean `export { default as default } from 'some-module'`?
× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[esprima/es2015-export-declaration/invalid-export-default-token/input.js:1:1]
1 │ export {default} +
@ -6954,6 +6961,13 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
╰────
help: Try insert a semicolon here
× A reserved word cannot be used as an exported binding without `from`
╭─[esprima/es2015-export-declaration/invalid-export-named-default/input.js:1:1]
1 │ export {default}
· ───────
╰────
help: Did you mean `export { default as default } from 'some-module'`?
× Export 'default' is not defined
╭─[esprima/es2015-export-declaration/invalid-export-named-default/input.js:1:1]
1 │ export {default}

View file

@ -19729,7 +19729,7 @@ Negative Passed: 3918/3918 (100.00%)
· ─────
22 │
╰────
help: Did you mean `export { 'foo' as 'foo' } from 'some-module'`?
help: Did you mean `export { "foo" as "bar" } from 'some-module'`?
× An export name cannot include a unicode lone surrogate
╭─[language/module-code/export-expname-unpaired-surrogate.js:20:1]