mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(ast)!: add IdentifierReference to ExportSpecifier (#3820)
closes #3795 closes #3796
This commit is contained in:
parent
99a40ce6ac
commit
445603444f
21 changed files with 163 additions and 118 deletions
|
|
@ -1895,7 +1895,7 @@ pub struct ExportDefaultDeclaration<'a> {
|
||||||
#[cfg_attr(feature = "serialize", serde(flatten))]
|
#[cfg_attr(feature = "serialize", serde(flatten))]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub declaration: ExportDefaultDeclarationKind<'a>,
|
pub declaration: ExportDefaultDeclarationKind<'a>,
|
||||||
pub exported: ModuleExportName<'a>, // `default`
|
pub exported: ModuleExportName<'a>, // the `default` Keyword
|
||||||
}
|
}
|
||||||
|
|
||||||
#[visited_node]
|
#[visited_node]
|
||||||
|
|
@ -1955,6 +1955,8 @@ pub enum ExportDefaultDeclarationKind<'a> {
|
||||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||||
pub enum ModuleExportName<'a> {
|
pub enum ModuleExportName<'a> {
|
||||||
Identifier(IdentifierName<'a>),
|
IdentifierName(IdentifierName<'a>),
|
||||||
|
/// For `local` in `ExportSpecifier`: `foo` in `export { foo }`
|
||||||
|
IdentifierReference(IdentifierReference<'a>),
|
||||||
StringLiteral(StringLiteral<'a>),
|
StringLiteral(StringLiteral<'a>),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1447,7 +1447,8 @@ impl<'a> ExportDefaultDeclarationKind<'a> {
|
||||||
impl<'a> fmt::Display for ModuleExportName<'a> {
|
impl<'a> fmt::Display for ModuleExportName<'a> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let s = match self {
|
let s = match self {
|
||||||
Self::Identifier(identifier) => identifier.name.to_string(),
|
Self::IdentifierName(identifier) => identifier.name.to_string(),
|
||||||
|
Self::IdentifierReference(identifier) => identifier.name.to_string(),
|
||||||
Self::StringLiteral(literal) => format!(r#""{}""#, literal.value),
|
Self::StringLiteral(literal) => format!(r#""{}""#, literal.value),
|
||||||
};
|
};
|
||||||
write!(f, "{s}")
|
write!(f, "{s}")
|
||||||
|
|
@ -1457,8 +1458,17 @@ impl<'a> fmt::Display for ModuleExportName<'a> {
|
||||||
impl<'a> ModuleExportName<'a> {
|
impl<'a> ModuleExportName<'a> {
|
||||||
pub fn name(&self) -> Atom<'a> {
|
pub fn name(&self) -> Atom<'a> {
|
||||||
match self {
|
match self {
|
||||||
Self::Identifier(identifier) => identifier.name.clone(),
|
Self::IdentifierName(identifier) => identifier.name.clone(),
|
||||||
|
Self::IdentifierReference(identifier) => identifier.name.clone(),
|
||||||
Self::StringLiteral(literal) => literal.value.clone(),
|
Self::StringLiteral(literal) => literal.value.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn identifier_name(&self) -> Option<Atom<'a>> {
|
||||||
|
match self {
|
||||||
|
Self::IdentifierName(identifier) => Some(identifier.name.clone()),
|
||||||
|
Self::IdentifierReference(identifier) => Some(identifier.name.clone()),
|
||||||
|
Self::StringLiteral(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,7 @@ ast_kinds! {
|
||||||
ModuleDeclaration(&'a ModuleDeclaration<'a>),
|
ModuleDeclaration(&'a ModuleDeclaration<'a>),
|
||||||
ImportDeclaration(&'a ImportDeclaration<'a>),
|
ImportDeclaration(&'a ImportDeclaration<'a>),
|
||||||
ImportSpecifier(&'a ImportSpecifier<'a>),
|
ImportSpecifier(&'a ImportSpecifier<'a>),
|
||||||
|
ExportSpecifier(&'a ExportSpecifier<'a>),
|
||||||
ImportDefaultSpecifier(&'a ImportDefaultSpecifier<'a>),
|
ImportDefaultSpecifier(&'a ImportDefaultSpecifier<'a>),
|
||||||
ImportNamespaceSpecifier(&'a ImportNamespaceSpecifier<'a>),
|
ImportNamespaceSpecifier(&'a ImportNamespaceSpecifier<'a>),
|
||||||
ExportDefaultDeclaration(&'a ExportDefaultDeclaration<'a>),
|
ExportDefaultDeclaration(&'a ExportDefaultDeclaration<'a>),
|
||||||
|
|
@ -469,6 +470,7 @@ impl<'a> GetSpan for AstKind<'a> {
|
||||||
Self::ModuleDeclaration(x) => x.span(),
|
Self::ModuleDeclaration(x) => x.span(),
|
||||||
Self::ImportDeclaration(x) => x.span,
|
Self::ImportDeclaration(x) => x.span,
|
||||||
Self::ImportSpecifier(x) => x.span,
|
Self::ImportSpecifier(x) => x.span,
|
||||||
|
Self::ExportSpecifier(x) => x.span,
|
||||||
Self::ImportDefaultSpecifier(x) => x.span,
|
Self::ImportDefaultSpecifier(x) => x.span,
|
||||||
Self::ImportNamespaceSpecifier(x) => x.span,
|
Self::ImportNamespaceSpecifier(x) => x.span,
|
||||||
Self::ExportDefaultDeclaration(x) => x.span,
|
Self::ExportDefaultDeclaration(x) => x.span,
|
||||||
|
|
@ -675,6 +677,7 @@ impl<'a> AstKind<'a> {
|
||||||
Self::ModuleDeclaration(_) => "ModuleDeclaration".into(),
|
Self::ModuleDeclaration(_) => "ModuleDeclaration".into(),
|
||||||
Self::ImportDeclaration(_) => "ImportDeclaration".into(),
|
Self::ImportDeclaration(_) => "ImportDeclaration".into(),
|
||||||
Self::ImportSpecifier(_) => "ImportSpecifier".into(),
|
Self::ImportSpecifier(_) => "ImportSpecifier".into(),
|
||||||
|
Self::ExportSpecifier(_) => "ExportSpecifier".into(),
|
||||||
Self::ImportDefaultSpecifier(_) => "ImportDefaultSpecifier".into(),
|
Self::ImportDefaultSpecifier(_) => "ImportDefaultSpecifier".into(),
|
||||||
Self::ImportNamespaceSpecifier(_) => "ImportNamespaceSpecifier".into(),
|
Self::ImportNamespaceSpecifier(_) => "ImportNamespaceSpecifier".into(),
|
||||||
Self::ExportDefaultDeclaration(_) => "ExportDefaultDeclaration".into(),
|
Self::ExportDefaultDeclaration(_) => "ExportDefaultDeclaration".into(),
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,8 @@ impl<'a> GetSpan for ImportAttributeKey<'a> {
|
||||||
impl<'a> GetSpan for ModuleExportName<'a> {
|
impl<'a> GetSpan for ModuleExportName<'a> {
|
||||||
fn span(&self) -> Span {
|
fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
Self::Identifier(identifier) => identifier.span,
|
Self::IdentifierName(identifier) => identifier.span,
|
||||||
|
Self::IdentifierReference(identifier) => identifier.span,
|
||||||
Self::StringLiteral(literal) => literal.span,
|
Self::StringLiteral(literal) => literal.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -617,6 +617,14 @@ pub trait Visit<'a>: Sized {
|
||||||
walk_export_named_declaration(self, decl);
|
walk_export_named_declaration(self, decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_export_specifier(&mut self, specifier: &ExportSpecifier<'a>) {
|
||||||
|
walk_export_specifier(self, specifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_module_export_name(&mut self, name: &ModuleExportName<'a>) {
|
||||||
|
walk_module_export_name(self, name);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_enum_member(&mut self, member: &TSEnumMember<'a>) {
|
fn visit_enum_member(&mut self, member: &TSEnumMember<'a>) {
|
||||||
walk_enum_member(self, member);
|
walk_enum_member(self, member);
|
||||||
}
|
}
|
||||||
|
|
@ -2433,7 +2441,7 @@ pub mod walk {
|
||||||
) {
|
) {
|
||||||
let kind = AstKind::ImportSpecifier(visitor.alloc(specifier));
|
let kind = AstKind::ImportSpecifier(visitor.alloc(specifier));
|
||||||
visitor.enter_node(kind);
|
visitor.enter_node(kind);
|
||||||
// TODO: imported
|
visitor.visit_module_export_name(&specifier.imported);
|
||||||
visitor.visit_binding_identifier(&specifier.local);
|
visitor.visit_binding_identifier(&specifier.local);
|
||||||
visitor.leave_node(kind);
|
visitor.leave_node(kind);
|
||||||
}
|
}
|
||||||
|
|
@ -2496,12 +2504,36 @@ pub mod walk {
|
||||||
if let Some(decl) = &decl.declaration {
|
if let Some(decl) = &decl.declaration {
|
||||||
visitor.visit_declaration(decl);
|
visitor.visit_declaration(decl);
|
||||||
}
|
}
|
||||||
|
for export_specifier in &decl.specifiers {
|
||||||
|
visitor.visit_export_specifier(export_specifier);
|
||||||
|
}
|
||||||
if let Some(ref source) = decl.source {
|
if let Some(ref source) = decl.source {
|
||||||
visitor.visit_string_literal(source);
|
visitor.visit_string_literal(source);
|
||||||
}
|
}
|
||||||
visitor.leave_node(kind);
|
visitor.leave_node(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk_export_specifier<'a, V: Visit<'a>>(
|
||||||
|
visitor: &mut V,
|
||||||
|
specifier: &ExportSpecifier<'a>,
|
||||||
|
) {
|
||||||
|
let kind = AstKind::ExportSpecifier(visitor.alloc(specifier));
|
||||||
|
visitor.enter_node(kind);
|
||||||
|
visitor.visit_module_export_name(&specifier.local);
|
||||||
|
visitor.visit_module_export_name(&specifier.exported);
|
||||||
|
visitor.leave_node(kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_module_export_name<'a, V: Visit<'a>>(visitor: &mut V, name: &ModuleExportName<'a>) {
|
||||||
|
match name {
|
||||||
|
ModuleExportName::IdentifierName(ident) => visitor.visit_identifier_name(ident),
|
||||||
|
ModuleExportName::IdentifierReference(ident) => {
|
||||||
|
visitor.visit_identifier_reference(ident);
|
||||||
|
}
|
||||||
|
ModuleExportName::StringLiteral(ident) => visitor.visit_string_literal(ident),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn walk_enum_member<'a, V: Visit<'a>>(visitor: &mut V, member: &TSEnumMember<'a>) {
|
pub fn walk_enum_member<'a, V: Visit<'a>>(visitor: &mut V, member: &TSEnumMember<'a>) {
|
||||||
let kind = AstKind::TSEnumMember(visitor.alloc(member));
|
let kind = AstKind::TSEnumMember(visitor.alloc(member));
|
||||||
visitor.enter_node(kind);
|
visitor.enter_node(kind);
|
||||||
|
|
|
||||||
|
|
@ -784,7 +784,11 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ImportDeclaration<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let imported_name = match &spec.imported {
|
let imported_name = match &spec.imported {
|
||||||
ModuleExportName::Identifier(identifier) => {
|
ModuleExportName::IdentifierName(identifier) => {
|
||||||
|
identifier.gen(p, ctx);
|
||||||
|
identifier.name.as_bytes()
|
||||||
|
}
|
||||||
|
ModuleExportName::IdentifierReference(identifier) => {
|
||||||
identifier.gen(p, ctx);
|
identifier.gen(p, ctx);
|
||||||
identifier.name.as_bytes()
|
identifier.name.as_bytes()
|
||||||
}
|
}
|
||||||
|
|
@ -961,9 +965,8 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ExportSpecifier<'a> {
|
||||||
impl<'a, const MINIFY: bool> Gen<MINIFY> for ModuleExportName<'a> {
|
impl<'a, const MINIFY: bool> Gen<MINIFY> for ModuleExportName<'a> {
|
||||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||||
match self {
|
match self {
|
||||||
Self::Identifier(identifier) => {
|
Self::IdentifierName(identifier) => p.print_str(identifier.name.as_bytes()),
|
||||||
p.print_str(identifier.name.as_bytes());
|
Self::IdentifierReference(identifier) => p.print_str(identifier.name.as_bytes()),
|
||||||
}
|
|
||||||
Self::StringLiteral(literal) => literal.gen(p, ctx),
|
Self::StringLiteral(literal) => literal.gen(p, ctx),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ impl<'a> IsolatedDeclarations<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
declaration.map(|(var_decl, declaration)| {
|
declaration.map(|(var_decl, declaration)| {
|
||||||
let exported = ModuleExportName::Identifier(IdentifierName::new(
|
let exported = ModuleExportName::IdentifierName(IdentifierName::new(
|
||||||
SPAN,
|
SPAN,
|
||||||
self.ast.new_atom("default"),
|
self.ast.new_atom("default"),
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -123,9 +123,9 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
|
||||||
|
|
||||||
fn visit_export_named_declaration(&mut self, decl: &ExportNamedDeclaration<'a>) {
|
fn visit_export_named_declaration(&mut self, decl: &ExportNamedDeclaration<'a>) {
|
||||||
for specifier in &decl.specifiers {
|
for specifier in &decl.specifiers {
|
||||||
if let ModuleExportName::Identifier(ident) = &specifier.local {
|
if let Some(name) = specifier.local.identifier_name() {
|
||||||
self.add_type_reference(ident.name.clone());
|
self.add_type_reference(name.clone());
|
||||||
self.add_value_reference(ident.name.clone());
|
self.add_value_reference(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use oxc_ast::{
|
||||||
FormalParameter, Function, IdentifierReference, JSXAttribute, JSXAttributeItem,
|
FormalParameter, Function, IdentifierReference, JSXAttribute, JSXAttributeItem,
|
||||||
JSXAttributeValue, JSXChild, JSXElement, JSXElementName, JSXExpression,
|
JSXAttributeValue, JSXChild, JSXElement, JSXElementName, JSXExpression,
|
||||||
JSXExpressionContainer, JSXFragment, JSXIdentifier, JSXOpeningElement, LogicalExpression,
|
JSXExpressionContainer, JSXFragment, JSXIdentifier, JSXOpeningElement, LogicalExpression,
|
||||||
MemberExpression, ModuleExportName, NewExpression, ObjectExpression, ObjectPropertyKind,
|
MemberExpression, NewExpression, ObjectExpression, ObjectPropertyKind,
|
||||||
ParenthesizedExpression, PrivateFieldExpression, Program, PropertyKey, SequenceExpression,
|
ParenthesizedExpression, PrivateFieldExpression, Program, PropertyKey, SequenceExpression,
|
||||||
SimpleAssignmentTarget, Statement, StaticMemberExpression, SwitchCase, ThisExpression,
|
SimpleAssignmentTarget, Statement, StaticMemberExpression, SwitchCase, ThisExpression,
|
||||||
UnaryExpression, VariableDeclarator,
|
UnaryExpression, VariableDeclarator,
|
||||||
|
|
@ -198,10 +198,8 @@ impl<'a> ListenerMap for ExportSpecifier<'a> {
|
||||||
let ctx = options.ctx;
|
let ctx = options.ctx;
|
||||||
let symbol_table = ctx.symbols();
|
let symbol_table = ctx.symbols();
|
||||||
if has_comment_about_side_effect_check(self.exported.span(), ctx) {
|
if has_comment_about_side_effect_check(self.exported.span(), ctx) {
|
||||||
let ModuleExportName::Identifier(ident_name) = &self.exported else {
|
let Some(name) = self.exported.identifier_name() else { return };
|
||||||
return;
|
let Some(symbol_id) = options.ctx.symbols().get_symbol_id_from_name(name.as_str())
|
||||||
};
|
|
||||||
let Some(symbol_id) = options.ctx.symbols().get_symbol_id_from_name(&ident_name.name)
|
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@ use oxc_ast::{
|
||||||
ast::{
|
ast::{
|
||||||
match_expression, Argument, ArrayExpressionElement, AssignmentExpression, AssignmentTarget,
|
match_expression, Argument, ArrayExpressionElement, AssignmentExpression, AssignmentTarget,
|
||||||
BindingPatternKind, CallExpression, Declaration, Expression, ModuleDeclaration,
|
BindingPatternKind, CallExpression, Declaration, Expression, ModuleDeclaration,
|
||||||
ModuleExportName, ObjectPropertyKind, PropertyKey, VariableDeclarator,
|
ObjectPropertyKind, PropertyKey, VariableDeclarator,
|
||||||
},
|
},
|
||||||
AstKind,
|
AstKind,
|
||||||
};
|
};
|
||||||
use oxc_diagnostics::OxcDiagnostic;
|
use oxc_diagnostics::OxcDiagnostic;
|
||||||
use oxc_macros::declare_oxc_lint;
|
use oxc_macros::declare_oxc_lint;
|
||||||
use oxc_span::Span;
|
use oxc_span::{GetSpan, Span};
|
||||||
|
|
||||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||||
|
|
||||||
|
|
@ -107,17 +107,8 @@ impl Rule for NoThenable {
|
||||||
}
|
}
|
||||||
// check specifier
|
// check specifier
|
||||||
for spec in &decl.specifiers {
|
for spec in &decl.specifiers {
|
||||||
match spec.exported {
|
if spec.exported.name() == "then" {
|
||||||
ModuleExportName::Identifier(ref ident) => {
|
ctx.diagnostic(export(spec.exported.span()));
|
||||||
if ident.name == "then" {
|
|
||||||
ctx.diagnostic(export(ident.span));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ModuleExportName::StringLiteral(ref lit) => {
|
|
||||||
if lit.value == "then" {
|
|
||||||
ctx.diagnostic(export(lit.span));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,8 @@ impl<'a> Visit<'a> for ModuleLexer<'a> {
|
||||||
// export { named }
|
// export { named }
|
||||||
self.exports.extend(decl.specifiers.iter().map(|s| {
|
self.exports.extend(decl.specifiers.iter().map(|s| {
|
||||||
let (exported_start, exported_end) = match &s.exported {
|
let (exported_start, exported_end) = match &s.exported {
|
||||||
ModuleExportName::Identifier(ident) => (ident.span.start, ident.span.end),
|
ModuleExportName::IdentifierName(ident) => (ident.span.start, ident.span.end),
|
||||||
|
ModuleExportName::IdentifierReference(ident) => (ident.span.start, ident.span.end),
|
||||||
// +1 -1 to remove the string quotes
|
// +1 -1 to remove the string quotes
|
||||||
ModuleExportName::StringLiteral(s) => (s.span.start + 1, s.span.end - 1),
|
ModuleExportName::StringLiteral(s) => (s.span.start + 1, s.span.end - 1),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<Box<'a, ExportNamedDeclaration<'a>>> {
|
) -> Result<Box<'a, ExportNamedDeclaration<'a>>> {
|
||||||
let export_kind = self.parse_import_or_export_kind();
|
let export_kind = self.parse_import_or_export_kind();
|
||||||
let specifiers =
|
let mut specifiers =
|
||||||
self.context(Context::empty(), self.ctx, ExportNamedSpecifiers::parse)?.elements;
|
self.context(Context::empty(), self.ctx, ExportNamedSpecifiers::parse)?.elements;
|
||||||
let (source, with_clause) = if self.eat(Kind::From) && self.cur_kind().is_literal() {
|
let (source, with_clause) = if self.eat(Kind::From) && self.cur_kind().is_literal() {
|
||||||
let source = self.parse_literal_string()?;
|
let source = self.parse_literal_string()?;
|
||||||
|
|
@ -229,7 +229,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
|
|
||||||
// ExportDeclaration : export NamedExports ;
|
// ExportDeclaration : export NamedExports ;
|
||||||
if source.is_none() {
|
if source.is_none() {
|
||||||
for specifier in &specifiers {
|
for specifier in specifiers.iter_mut() {
|
||||||
match &specifier.local {
|
match &specifier.local {
|
||||||
// It is a Syntax Error if ReferencedBindings of NamedExports contains any StringLiterals.
|
// It is a Syntax Error if ReferencedBindings of NamedExports contains any StringLiterals.
|
||||||
ModuleExportName::StringLiteral(literal) => {
|
ModuleExportName::StringLiteral(literal) => {
|
||||||
|
|
@ -242,18 +242,25 @@ impl<'a> ParserImpl<'a> {
|
||||||
// For each IdentifierName n in ReferencedBindings of NamedExports:
|
// 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
|
// 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".
|
// is one of "implements", "interface", "let", "package", "private", "protected", "public", or "static".
|
||||||
ModuleExportName::Identifier(id) => {
|
ModuleExportName::IdentifierName(ident) => {
|
||||||
let match_result = Kind::match_keyword(&id.name);
|
let match_result = Kind::match_keyword(&ident.name);
|
||||||
if match_result.is_reserved_keyword()
|
if match_result.is_reserved_keyword()
|
||||||
|| match_result.is_future_reserved_keyword()
|
|| match_result.is_future_reserved_keyword()
|
||||||
{
|
{
|
||||||
self.error(diagnostics::export_reserved_word(
|
self.error(diagnostics::export_reserved_word(
|
||||||
&specifier.local.to_string(),
|
&specifier.local.to_string(),
|
||||||
&specifier.exported.to_string(),
|
&specifier.exported.to_string(),
|
||||||
id.span,
|
ident.span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `local` becomes a reference for `export { local }`.
|
||||||
|
specifier.local = ModuleExportName::IdentifierReference(
|
||||||
|
self.ast.identifier_reference(ident.span, ident.name.as_str()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
// No prior code path should lead to parsing `ModuleExportName` as `IdentifierReference`.
|
||||||
|
ModuleExportName::IdentifierReference(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -343,7 +350,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
decl
|
decl
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let exported = ModuleExportName::Identifier(exported);
|
let exported = ModuleExportName::IdentifierName(exported);
|
||||||
let span = self.end_span(span);
|
let span = self.end_span(span);
|
||||||
Ok(self.ast.export_default_declaration(span, declaration, exported))
|
Ok(self.ast.export_default_declaration(span, declaration, exported))
|
||||||
}
|
}
|
||||||
|
|
@ -400,7 +407,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
} else {
|
} else {
|
||||||
let local = self.parse_binding_identifier()?;
|
let local = self.parse_binding_identifier()?;
|
||||||
let imported = IdentifierName { span: local.span, name: local.name.clone() };
|
let imported = IdentifierName { span: local.span, name: local.name.clone() };
|
||||||
(ModuleExportName::Identifier(imported), local)
|
(ModuleExportName::IdentifierName(imported), local)
|
||||||
};
|
};
|
||||||
Ok(self.ast.alloc(ImportSpecifier {
|
Ok(self.ast.alloc(ImportSpecifier {
|
||||||
span: self.end_span(specifier_span),
|
span: self.end_span(specifier_span),
|
||||||
|
|
@ -424,7 +431,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
};
|
};
|
||||||
Ok(ModuleExportName::StringLiteral(literal))
|
Ok(ModuleExportName::StringLiteral(literal))
|
||||||
}
|
}
|
||||||
_ => Ok(ModuleExportName::Identifier(self.parse_identifier_name()?)),
|
_ => Ok(ModuleExportName::IdentifierName(self.parse_identifier_name()?)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1209,7 +1209,8 @@ impl<'a> Format<'a> for ExportSpecifier<'a> {
|
||||||
impl<'a> Format<'a> for ModuleExportName<'a> {
|
impl<'a> Format<'a> for ModuleExportName<'a> {
|
||||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||||
match self {
|
match self {
|
||||||
Self::Identifier(ident) => ident.format(p),
|
Self::IdentifierName(ident) => ident.format(p),
|
||||||
|
Self::IdentifierReference(ident) => ident.format(p),
|
||||||
Self::StringLiteral(literal) => literal.format(p),
|
Self::StringLiteral(literal) => literal.format(p),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,7 @@ use oxc_cfg::{
|
||||||
};
|
};
|
||||||
use oxc_diagnostics::OxcDiagnostic;
|
use oxc_diagnostics::OxcDiagnostic;
|
||||||
use oxc_span::{CompactStr, SourceType, Span};
|
use oxc_span::{CompactStr, SourceType, Span};
|
||||||
use oxc_syntax::{
|
use oxc_syntax::{module_record::ModuleRecord, operator::AssignmentOperator};
|
||||||
module_record::{ExportImportName, ModuleRecord},
|
|
||||||
operator::AssignmentOperator,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
binder::Binder,
|
binder::Binder,
|
||||||
|
|
@ -388,23 +385,30 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
self.symbols.add_redeclare_variable(symbol_id, span);
|
self.symbols.add_redeclare_variable(symbol_id, span);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_export_flag_for_export_identifier(&mut self) {
|
fn add_export_flag_to_export_identifiers(&mut self, program: &Program<'a>) {
|
||||||
self.module_record.indirect_export_entries.iter().for_each(|entry| {
|
for stmt in &program.body {
|
||||||
if let ExportImportName::Name(name) = &entry.import_name {
|
if let Statement::ExportDefaultDeclaration(decl) = stmt {
|
||||||
if let Some(symbol_id) = self.symbols.get_symbol_id_from_name(name.name()) {
|
if let ExportDefaultDeclarationKind::Identifier(ident) = &decl.declaration {
|
||||||
self.symbols.union_flag(symbol_id, SymbolFlags::Export);
|
self.add_export_flag_to_identifier(ident.name.as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Statement::ExportNamedDeclaration(decl) = stmt {
|
||||||
|
for specifier in &decl.specifiers {
|
||||||
|
if specifier.export_kind.is_value() {
|
||||||
|
if let Some(name) = specifier.local.identifier_name() {
|
||||||
|
self.add_export_flag_to_identifier(name.as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
self.module_record.local_export_entries.iter().for_each(|entry| {
|
fn add_export_flag_to_identifier(&mut self, name: &str) {
|
||||||
if let Some(name) = entry.local_name.name() {
|
if let Some(symbol_id) = self.scope.get_binding(self.current_scope_id, name) {
|
||||||
if let Some(symbol_id) = self.scope.get_root_binding(name.as_str()) {
|
|
||||||
self.symbols.union_flag(symbol_id, SymbolFlags::Export);
|
self.symbols.union_flag(symbol_id, SymbolFlags::Export);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||||
|
|
@ -1680,9 +1684,21 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
/* cfg */
|
/* cfg */
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
AstKind::ExportDefaultDeclaration(_) | AstKind::ExportNamedDeclaration(_) => {
|
AstKind::ExportDefaultDeclaration(_) => {
|
||||||
self.current_symbol_flags |= SymbolFlags::Export;
|
self.current_symbol_flags |= SymbolFlags::Export;
|
||||||
}
|
}
|
||||||
|
AstKind::ExportNamedDeclaration(decl) => {
|
||||||
|
self.current_symbol_flags |= SymbolFlags::Export;
|
||||||
|
if decl.export_kind.is_type() {
|
||||||
|
self.current_reference_flag = ReferenceFlag::Type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AstKind::ExportAllDeclaration(s) if s.export_kind.is_type() => {
|
||||||
|
self.current_reference_flag = ReferenceFlag::Type;
|
||||||
|
}
|
||||||
|
AstKind::ExportSpecifier(s) if s.export_kind.is_type() => {
|
||||||
|
self.current_reference_flag = ReferenceFlag::Type;
|
||||||
|
}
|
||||||
AstKind::ImportSpecifier(specifier) => {
|
AstKind::ImportSpecifier(specifier) => {
|
||||||
specifier.bind(self);
|
specifier.bind(self);
|
||||||
}
|
}
|
||||||
|
|
@ -1768,6 +1784,9 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
AstKind::TSTypeParameter(type_parameter) => {
|
AstKind::TSTypeParameter(type_parameter) => {
|
||||||
type_parameter.bind(self);
|
type_parameter.bind(self);
|
||||||
}
|
}
|
||||||
|
AstKind::ExportSpecifier(s) if s.export_kind.is_type() => {
|
||||||
|
self.current_reference_flag = ReferenceFlag::Type;
|
||||||
|
}
|
||||||
AstKind::TSTypeName(_) => {
|
AstKind::TSTypeName(_) => {
|
||||||
self.current_reference_flag = ReferenceFlag::Type;
|
self.current_reference_flag = ReferenceFlag::Type;
|
||||||
}
|
}
|
||||||
|
|
@ -1815,16 +1834,28 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
fn leave_kind(&mut self, kind: AstKind<'a>) {
|
fn leave_kind(&mut self, kind: AstKind<'a>) {
|
||||||
match kind {
|
match kind {
|
||||||
AstKind::Program(_) => {
|
AstKind::Program(program) => {
|
||||||
self.add_export_flag_for_export_identifier();
|
self.add_export_flag_to_export_identifiers(program);
|
||||||
}
|
}
|
||||||
AstKind::Class(_) => {
|
AstKind::Class(_) => {
|
||||||
self.current_node_flags -= NodeFlags::Class;
|
self.current_node_flags -= NodeFlags::Class;
|
||||||
self.class_table_builder.pop_class();
|
self.class_table_builder.pop_class();
|
||||||
}
|
}
|
||||||
AstKind::ExportDefaultDeclaration(_) | AstKind::ExportNamedDeclaration(_) => {
|
AstKind::ExportDefaultDeclaration(_) => {
|
||||||
self.current_symbol_flags -= SymbolFlags::Export;
|
self.current_symbol_flags -= SymbolFlags::Export;
|
||||||
}
|
}
|
||||||
|
AstKind::ExportNamedDeclaration(decl) => {
|
||||||
|
self.current_symbol_flags -= SymbolFlags::Export;
|
||||||
|
if decl.export_kind.is_type() {
|
||||||
|
self.current_reference_flag -= ReferenceFlag::Type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AstKind::ExportAllDeclaration(s) if s.export_kind.is_type() => {
|
||||||
|
self.current_reference_flag -= ReferenceFlag::Type;
|
||||||
|
}
|
||||||
|
AstKind::ExportSpecifier(s) if s.export_kind.is_type() => {
|
||||||
|
self.current_reference_flag -= ReferenceFlag::Type;
|
||||||
|
}
|
||||||
AstKind::LabeledStatement(_) => self.label_builder.leave(),
|
AstKind::LabeledStatement(_) => self.label_builder.leave(),
|
||||||
AstKind::StaticBlock(_) => {
|
AstKind::StaticBlock(_) => {
|
||||||
self.label_builder.leave_function_or_static_block();
|
self.label_builder.leave_function_or_static_block();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use oxc_semantic::SymbolFlags;
|
use oxc_semantic::SymbolFlags;
|
||||||
use oxc_syntax::module_record::ExportExportName;
|
|
||||||
|
|
||||||
use crate::util::SemanticTester;
|
use crate::util::SemanticTester;
|
||||||
|
|
||||||
|
|
@ -26,9 +25,7 @@ fn test_exports() {
|
||||||
);
|
);
|
||||||
|
|
||||||
test.has_some_symbol("foo").is_exported().test();
|
test.has_some_symbol("foo").is_exported().test();
|
||||||
|
test.has_some_symbol("defaultExport").is_exported().test();
|
||||||
// FIXME: failing
|
|
||||||
// test.has_some_symbol("defaultExport").is_exported().test();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -118,21 +115,6 @@ fn test_exported_default_class() {
|
||||||
test.has_class("Foo");
|
test.has_class("Foo");
|
||||||
test.has_some_symbol("a").is_not_exported().test();
|
test.has_some_symbol("a").is_not_exported().test();
|
||||||
test.has_some_symbol("T").is_not_exported().test();
|
test.has_some_symbol("T").is_not_exported().test();
|
||||||
|
|
||||||
{
|
|
||||||
let foo_test = test.has_some_symbol("Foo");
|
|
||||||
let (semantic, _) = foo_test.inner();
|
|
||||||
let m = semantic.module_record();
|
|
||||||
let local_default_entry = m
|
|
||||||
.local_export_entries
|
|
||||||
.iter()
|
|
||||||
.find(|export| matches!(export.export_name, ExportExportName::Default(_)))
|
|
||||||
.unwrap();
|
|
||||||
assert!(local_default_entry.local_name.name().is_some_and(|name| name == &"Foo"));
|
|
||||||
assert!(!m.exported_bindings.contains_key("Foo"));
|
|
||||||
assert!(m.export_default.is_some());
|
|
||||||
foo_test.contains_flags(SymbolFlags::Export).test();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME
|
// FIXME
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
mod class_tester;
|
mod class_tester;
|
||||||
mod expect;
|
mod expect;
|
||||||
mod symbol_tester;
|
mod symbol_tester;
|
||||||
use std::{path::PathBuf, sync::Arc};
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub use class_tester::ClassTester;
|
pub use class_tester::ClassTester;
|
||||||
pub use expect::Expect;
|
pub use expect::Expect;
|
||||||
|
|
@ -88,7 +88,6 @@ impl<'a> SemanticTester<'a> {
|
||||||
let semantic_ret = SemanticBuilder::new(self.source_text, self.source_type)
|
let semantic_ret = SemanticBuilder::new(self.source_text, self.source_type)
|
||||||
.with_check_syntax_error(true)
|
.with_check_syntax_error(true)
|
||||||
.with_trivias(parse.trivias)
|
.with_trivias(parse.trivias)
|
||||||
.build_module_record(PathBuf::new(), program)
|
|
||||||
.with_cfg(self.cfg)
|
.with_cfg(self.cfg)
|
||||||
.build(program);
|
.build(program);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -159,21 +159,12 @@ impl<'a> SymbolTester<'a> {
|
||||||
self.test_result = match self.test_result {
|
self.test_result = match self.test_result {
|
||||||
Ok(symbol_id) => {
|
Ok(symbol_id) => {
|
||||||
let binding = self.target_symbol_name.clone();
|
let binding = self.target_symbol_name.clone();
|
||||||
let is_in_module_record =
|
if self.semantic.symbols().get_flag(symbol_id).is_export() {
|
||||||
self.semantic.module_record().exported_bindings.contains_key(binding.as_str())
|
Ok(symbol_id)
|
||||||
&& self.semantic.scopes().get_root_binding(&binding) == Some(symbol_id);
|
} else {
|
||||||
let has_export_flag = self.semantic.symbols().get_flag(symbol_id).is_export();
|
Err(OxcDiagnostic::error(format!(
|
||||||
match (is_in_module_record, has_export_flag) {
|
"Expected {binding} to be exported with SymbolFlags::Export"
|
||||||
(false, false) => Err(OxcDiagnostic::error(format!(
|
)))
|
||||||
"Expected {binding} to be exported. Symbol is not in module record and does not have SymbolFlags::Export"
|
|
||||||
))),
|
|
||||||
(false, true) => Err(OxcDiagnostic::error(format!(
|
|
||||||
"Expected {binding} to be exported. Symbol is not in module record, but has SymbolFlags::Export"
|
|
||||||
))),
|
|
||||||
(true, false) => Err(OxcDiagnostic::error(format!(
|
|
||||||
"Expected {binding} to be exported. Symbol is in module record, but does not have SymbolFlags::Export"
|
|
||||||
))),
|
|
||||||
(true, true) => Ok(symbol_id),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e => e,
|
e => e,
|
||||||
|
|
@ -191,15 +182,6 @@ impl<'a> SymbolTester<'a> {
|
||||||
Err(OxcDiagnostic::error(format!(
|
Err(OxcDiagnostic::error(format!(
|
||||||
"Expected {binding} to not be exported. Symbol has export flag."
|
"Expected {binding} to not be exported. Symbol has export flag."
|
||||||
)))
|
)))
|
||||||
} else if self
|
|
||||||
.semantic
|
|
||||||
.module_record()
|
|
||||||
.exported_bindings
|
|
||||||
.contains_key(binding.as_str())
|
|
||||||
{
|
|
||||||
Err(OxcDiagnostic::error(format!(
|
|
||||||
"Expected {binding} to not be exported. Binding is in the module record"
|
|
||||||
)))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(symbol_id)
|
Ok(symbol_id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,10 @@ impl<'a> ModuleImports<'a> {
|
||||||
let local = name.local.unwrap_or_else(|| name.imported.clone());
|
let local = name.local.unwrap_or_else(|| name.imported.clone());
|
||||||
ImportDeclarationSpecifier::ImportSpecifier(self.ast.alloc(ImportSpecifier {
|
ImportDeclarationSpecifier::ImportSpecifier(self.ast.alloc(ImportSpecifier {
|
||||||
span: SPAN,
|
span: SPAN,
|
||||||
imported: ModuleExportName::Identifier(IdentifierName::new(SPAN, name.imported)),
|
imported: ModuleExportName::IdentifierName(IdentifierName::new(
|
||||||
|
SPAN,
|
||||||
|
name.imported,
|
||||||
|
)),
|
||||||
local: BindingIdentifier {
|
local: BindingIdentifier {
|
||||||
span: SPAN,
|
span: SPAN,
|
||||||
name: local,
|
name: local,
|
||||||
|
|
|
||||||
|
|
@ -516,11 +516,6 @@ impl<'a> TypeScriptAnnotations<'a> {
|
||||||
|
|
||||||
pub fn has_value_reference(&self, name: &str, ctx: &TraverseCtx<'a>) -> bool {
|
pub fn has_value_reference(&self, name: &str, ctx: &TraverseCtx<'a>) -> bool {
|
||||||
if let Some(symbol_id) = ctx.scopes().get_root_binding(name) {
|
if let Some(symbol_id) = ctx.scopes().get_root_binding(name) {
|
||||||
if ctx.symbols().get_flag(symbol_id).is_export()
|
|
||||||
&& !self.type_identifier_names.contains(name)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ctx
|
if ctx
|
||||||
.symbols()
|
.symbols()
|
||||||
.get_resolved_references(symbol_id)
|
.get_resolved_references(symbol_id)
|
||||||
|
|
|
||||||
|
|
@ -3109,7 +3109,12 @@ pub(crate) unsafe fn walk_module_export_name<'a, Tr: Traverse<'a>>(
|
||||||
) {
|
) {
|
||||||
traverser.enter_module_export_name(&mut *node, ctx);
|
traverser.enter_module_export_name(&mut *node, ctx);
|
||||||
match &mut *node {
|
match &mut *node {
|
||||||
ModuleExportName::Identifier(node) => walk_identifier_name(traverser, node as *mut _, ctx),
|
ModuleExportName::IdentifierName(node) => {
|
||||||
|
walk_identifier_name(traverser, node as *mut _, ctx)
|
||||||
|
}
|
||||||
|
ModuleExportName::IdentifierReference(node) => {
|
||||||
|
walk_identifier_reference(traverser, node as *mut _, ctx)
|
||||||
|
}
|
||||||
ModuleExportName::StringLiteral(node) => {
|
ModuleExportName::StringLiteral(node) => {
|
||||||
walk_string_literal(traverser, node as *mut _, ctx)
|
walk_string_literal(traverser, node as *mut _, ctx)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
commit: 12619ffe
|
commit: 12619ffe
|
||||||
|
|
||||||
Passed: 472/927
|
Passed: 473/927
|
||||||
|
|
||||||
# All Passed:
|
# All Passed:
|
||||||
* babel-preset-react
|
* babel-preset-react
|
||||||
|
|
@ -445,11 +445,10 @@ Passed: 472/927
|
||||||
* opts/optimizeConstEnums/input.ts
|
* opts/optimizeConstEnums/input.ts
|
||||||
* opts/rewriteImportExtensions/input.ts
|
* opts/rewriteImportExtensions/input.ts
|
||||||
|
|
||||||
# babel-plugin-transform-typescript (128/151)
|
# babel-plugin-transform-typescript (129/151)
|
||||||
* enum/mix-references/input.ts
|
* enum/mix-references/input.ts
|
||||||
* enum/ts5.0-const-foldable/input.ts
|
* enum/ts5.0-const-foldable/input.ts
|
||||||
* exports/declared-types/input.ts
|
* exports/declared-types/input.ts
|
||||||
* exports/imported-types/input.ts
|
|
||||||
* exports/interface/input.ts
|
* exports/interface/input.ts
|
||||||
* imports/elide-no-import-specifiers/input.ts
|
* imports/elide-no-import-specifiers/input.ts
|
||||||
* imports/elision-locations/input.ts
|
* imports/elision-locations/input.ts
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue