feat(ast)!: add IdentifierReference to ExportSpecifier (#3820)

closes #3795
closes #3796
This commit is contained in:
Boshen 2024-06-22 11:43:41 +00:00
parent 99a40ce6ac
commit 445603444f
21 changed files with 163 additions and 118 deletions

View file

@ -1895,7 +1895,7 @@ pub struct ExportDefaultDeclaration<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub declaration: ExportDefaultDeclarationKind<'a>,
pub exported: ModuleExportName<'a>, // `default`
pub exported: ModuleExportName<'a>, // the `default` Keyword
}
#[visited_node]
@ -1955,6 +1955,8 @@ pub enum ExportDefaultDeclarationKind<'a> {
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum ModuleExportName<'a> {
Identifier(IdentifierName<'a>),
IdentifierName(IdentifierName<'a>),
/// For `local` in `ExportSpecifier`: `foo` in `export { foo }`
IdentifierReference(IdentifierReference<'a>),
StringLiteral(StringLiteral<'a>),
}

View file

@ -1447,7 +1447,8 @@ impl<'a> ExportDefaultDeclarationKind<'a> {
impl<'a> fmt::Display for ModuleExportName<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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),
};
write!(f, "{s}")
@ -1457,8 +1458,17 @@ impl<'a> fmt::Display for ModuleExportName<'a> {
impl<'a> ModuleExportName<'a> {
pub fn name(&self) -> Atom<'a> {
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(),
}
}
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,
}
}
}

View file

@ -126,6 +126,7 @@ ast_kinds! {
ModuleDeclaration(&'a ModuleDeclaration<'a>),
ImportDeclaration(&'a ImportDeclaration<'a>),
ImportSpecifier(&'a ImportSpecifier<'a>),
ExportSpecifier(&'a ExportSpecifier<'a>),
ImportDefaultSpecifier(&'a ImportDefaultSpecifier<'a>),
ImportNamespaceSpecifier(&'a ImportNamespaceSpecifier<'a>),
ExportDefaultDeclaration(&'a ExportDefaultDeclaration<'a>),
@ -469,6 +470,7 @@ impl<'a> GetSpan for AstKind<'a> {
Self::ModuleDeclaration(x) => x.span(),
Self::ImportDeclaration(x) => x.span,
Self::ImportSpecifier(x) => x.span,
Self::ExportSpecifier(x) => x.span,
Self::ImportDefaultSpecifier(x) => x.span,
Self::ImportNamespaceSpecifier(x) => x.span,
Self::ExportDefaultDeclaration(x) => x.span,
@ -675,6 +677,7 @@ impl<'a> AstKind<'a> {
Self::ModuleDeclaration(_) => "ModuleDeclaration".into(),
Self::ImportDeclaration(_) => "ImportDeclaration".into(),
Self::ImportSpecifier(_) => "ImportSpecifier".into(),
Self::ExportSpecifier(_) => "ExportSpecifier".into(),
Self::ImportDefaultSpecifier(_) => "ImportDefaultSpecifier".into(),
Self::ImportNamespaceSpecifier(_) => "ImportNamespaceSpecifier".into(),
Self::ExportDefaultDeclaration(_) => "ExportDefaultDeclaration".into(),

View file

@ -208,7 +208,8 @@ impl<'a> GetSpan for ImportAttributeKey<'a> {
impl<'a> GetSpan for ModuleExportName<'a> {
fn span(&self) -> Span {
match self {
Self::Identifier(identifier) => identifier.span,
Self::IdentifierName(identifier) => identifier.span,
Self::IdentifierReference(identifier) => identifier.span,
Self::StringLiteral(literal) => literal.span,
}
}

View file

@ -617,6 +617,14 @@ pub trait Visit<'a>: Sized {
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>) {
walk_enum_member(self, member);
}
@ -2433,7 +2441,7 @@ pub mod walk {
) {
let kind = AstKind::ImportSpecifier(visitor.alloc(specifier));
visitor.enter_node(kind);
// TODO: imported
visitor.visit_module_export_name(&specifier.imported);
visitor.visit_binding_identifier(&specifier.local);
visitor.leave_node(kind);
}
@ -2496,12 +2504,36 @@ pub mod walk {
if let Some(decl) = &decl.declaration {
visitor.visit_declaration(decl);
}
for export_specifier in &decl.specifiers {
visitor.visit_export_specifier(export_specifier);
}
if let Some(ref source) = decl.source {
visitor.visit_string_literal(source);
}
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>) {
let kind = AstKind::TSEnumMember(visitor.alloc(member));
visitor.enter_node(kind);

View file

@ -784,7 +784,11 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ImportDeclaration<'a> {
}
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.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> {
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
match self {
Self::Identifier(identifier) => {
p.print_str(identifier.name.as_bytes());
}
Self::IdentifierName(identifier) => p.print_str(identifier.name.as_bytes()),
Self::IdentifierReference(identifier) => p.print_str(identifier.name.as_bytes()),
Self::StringLiteral(literal) => literal.gen(p, ctx),
};
}

View file

@ -88,7 +88,7 @@ impl<'a> IsolatedDeclarations<'a> {
};
declaration.map(|(var_decl, declaration)| {
let exported = ModuleExportName::Identifier(IdentifierName::new(
let exported = ModuleExportName::IdentifierName(IdentifierName::new(
SPAN,
self.ast.new_atom("default"),
));

View file

@ -123,9 +123,9 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
fn visit_export_named_declaration(&mut self, decl: &ExportNamedDeclaration<'a>) {
for specifier in &decl.specifiers {
if let ModuleExportName::Identifier(ident) = &specifier.local {
self.add_type_reference(ident.name.clone());
self.add_value_reference(ident.name.clone());
if let Some(name) = specifier.local.identifier_name() {
self.add_type_reference(name.clone());
self.add_value_reference(name);
}
}
}

View file

@ -8,7 +8,7 @@ use oxc_ast::{
FormalParameter, Function, IdentifierReference, JSXAttribute, JSXAttributeItem,
JSXAttributeValue, JSXChild, JSXElement, JSXElementName, JSXExpression,
JSXExpressionContainer, JSXFragment, JSXIdentifier, JSXOpeningElement, LogicalExpression,
MemberExpression, ModuleExportName, NewExpression, ObjectExpression, ObjectPropertyKind,
MemberExpression, NewExpression, ObjectExpression, ObjectPropertyKind,
ParenthesizedExpression, PrivateFieldExpression, Program, PropertyKey, SequenceExpression,
SimpleAssignmentTarget, Statement, StaticMemberExpression, SwitchCase, ThisExpression,
UnaryExpression, VariableDeclarator,
@ -198,10 +198,8 @@ impl<'a> ListenerMap for ExportSpecifier<'a> {
let ctx = options.ctx;
let symbol_table = ctx.symbols();
if has_comment_about_side_effect_check(self.exported.span(), ctx) {
let ModuleExportName::Identifier(ident_name) = &self.exported else {
return;
};
let Some(symbol_id) = options.ctx.symbols().get_symbol_id_from_name(&ident_name.name)
let Some(name) = self.exported.identifier_name() else { return };
let Some(symbol_id) = options.ctx.symbols().get_symbol_id_from_name(name.as_str())
else {
return;
};

View file

@ -2,13 +2,13 @@ use oxc_ast::{
ast::{
match_expression, Argument, ArrayExpressionElement, AssignmentExpression, AssignmentTarget,
BindingPatternKind, CallExpression, Declaration, Expression, ModuleDeclaration,
ModuleExportName, ObjectPropertyKind, PropertyKey, VariableDeclarator,
ObjectPropertyKind, PropertyKey, VariableDeclarator,
},
AstKind,
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use oxc_span::{GetSpan, Span};
use crate::{context::LintContext, rule::Rule, AstNode};
@ -107,17 +107,8 @@ impl Rule for NoThenable {
}
// check specifier
for spec in &decl.specifiers {
match spec.exported {
ModuleExportName::Identifier(ref ident) => {
if ident.name == "then" {
ctx.diagnostic(export(ident.span));
}
}
ModuleExportName::StringLiteral(ref lit) => {
if lit.value == "then" {
ctx.diagnostic(export(lit.span));
}
}
if spec.exported.name() == "then" {
ctx.diagnostic(export(spec.exported.span()));
}
}
}

View file

@ -220,7 +220,8 @@ impl<'a> Visit<'a> for ModuleLexer<'a> {
// export { named }
self.exports.extend(decl.specifiers.iter().map(|s| {
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
ModuleExportName::StringLiteral(s) => (s.span.start + 1, s.span.end - 1),
};

View file

@ -218,7 +218,7 @@ impl<'a> ParserImpl<'a> {
span: Span,
) -> Result<Box<'a, ExportNamedDeclaration<'a>>> {
let export_kind = self.parse_import_or_export_kind();
let specifiers =
let mut specifiers =
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 = self.parse_literal_string()?;
@ -229,7 +229,7 @@ impl<'a> ParserImpl<'a> {
// ExportDeclaration : export NamedExports ;
if source.is_none() {
for specifier in &specifiers {
for specifier in specifiers.iter_mut() {
match &specifier.local {
// It is a Syntax Error if ReferencedBindings of NamedExports contains any StringLiterals.
ModuleExportName::StringLiteral(literal) => {
@ -242,18 +242,25 @@ impl<'a> ParserImpl<'a> {
// 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);
ModuleExportName::IdentifierName(ident) => {
let match_result = Kind::match_keyword(&ident.name);
if match_result.is_reserved_keyword()
|| match_result.is_future_reserved_keyword()
{
self.error(diagnostics::export_reserved_word(
&specifier.local.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
}
};
let exported = ModuleExportName::Identifier(exported);
let exported = ModuleExportName::IdentifierName(exported);
let span = self.end_span(span);
Ok(self.ast.export_default_declaration(span, declaration, exported))
}
@ -400,7 +407,7 @@ impl<'a> ParserImpl<'a> {
} else {
let local = self.parse_binding_identifier()?;
let imported = IdentifierName { span: local.span, name: local.name.clone() };
(ModuleExportName::Identifier(imported), local)
(ModuleExportName::IdentifierName(imported), local)
};
Ok(self.ast.alloc(ImportSpecifier {
span: self.end_span(specifier_span),
@ -424,7 +431,7 @@ impl<'a> ParserImpl<'a> {
};
Ok(ModuleExportName::StringLiteral(literal))
}
_ => Ok(ModuleExportName::Identifier(self.parse_identifier_name()?)),
_ => Ok(ModuleExportName::IdentifierName(self.parse_identifier_name()?)),
}
}

View file

@ -1209,7 +1209,8 @@ impl<'a> Format<'a> for ExportSpecifier<'a> {
impl<'a> Format<'a> for ModuleExportName<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
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),
}
}

View file

@ -10,10 +10,7 @@ use oxc_cfg::{
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{CompactStr, SourceType, Span};
use oxc_syntax::{
module_record::{ExportImportName, ModuleRecord},
operator::AssignmentOperator,
};
use oxc_syntax::{module_record::ModuleRecord, operator::AssignmentOperator};
use crate::{
binder::Binder,
@ -388,22 +385,29 @@ impl<'a> SemanticBuilder<'a> {
self.symbols.add_redeclare_variable(symbol_id, span);
}
fn add_export_flag_for_export_identifier(&mut self) {
self.module_record.indirect_export_entries.iter().for_each(|entry| {
if let ExportImportName::Name(name) = &entry.import_name {
if let Some(symbol_id) = self.symbols.get_symbol_id_from_name(name.name()) {
self.symbols.union_flag(symbol_id, SymbolFlags::Export);
fn add_export_flag_to_export_identifiers(&mut self, program: &Program<'a>) {
for stmt in &program.body {
if let Statement::ExportDefaultDeclaration(decl) = stmt {
if let ExportDefaultDeclarationKind::Identifier(ident) = &decl.declaration {
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| {
if let Some(name) = entry.local_name.name() {
if let Some(symbol_id) = self.scope.get_root_binding(name.as_str()) {
self.symbols.union_flag(symbol_id, SymbolFlags::Export);
}
}
});
fn add_export_flag_to_identifier(&mut self, name: &str) {
if let Some(symbol_id) = self.scope.get_binding(self.current_scope_id, name) {
self.symbols.union_flag(symbol_id, SymbolFlags::Export);
}
}
}
@ -1680,9 +1684,21 @@ impl<'a> SemanticBuilder<'a> {
/* cfg */
match kind {
AstKind::ExportDefaultDeclaration(_) | AstKind::ExportNamedDeclaration(_) => {
AstKind::ExportDefaultDeclaration(_) => {
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) => {
specifier.bind(self);
}
@ -1768,6 +1784,9 @@ impl<'a> SemanticBuilder<'a> {
AstKind::TSTypeParameter(type_parameter) => {
type_parameter.bind(self);
}
AstKind::ExportSpecifier(s) if s.export_kind.is_type() => {
self.current_reference_flag = ReferenceFlag::Type;
}
AstKind::TSTypeName(_) => {
self.current_reference_flag = ReferenceFlag::Type;
}
@ -1815,16 +1834,28 @@ impl<'a> SemanticBuilder<'a> {
#[allow(clippy::single_match)]
fn leave_kind(&mut self, kind: AstKind<'a>) {
match kind {
AstKind::Program(_) => {
self.add_export_flag_for_export_identifier();
AstKind::Program(program) => {
self.add_export_flag_to_export_identifiers(program);
}
AstKind::Class(_) => {
self.current_node_flags -= NodeFlags::Class;
self.class_table_builder.pop_class();
}
AstKind::ExportDefaultDeclaration(_) | AstKind::ExportNamedDeclaration(_) => {
AstKind::ExportDefaultDeclaration(_) => {
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::StaticBlock(_) => {
self.label_builder.leave_function_or_static_block();

View file

@ -1,5 +1,4 @@
use oxc_semantic::SymbolFlags;
use oxc_syntax::module_record::ExportExportName;
use crate::util::SemanticTester;
@ -26,9 +25,7 @@ fn test_exports() {
);
test.has_some_symbol("foo").is_exported().test();
// FIXME: failing
// test.has_some_symbol("defaultExport").is_exported().test();
test.has_some_symbol("defaultExport").is_exported().test();
}
#[test]
@ -118,21 +115,6 @@ fn test_exported_default_class() {
test.has_class("Foo");
test.has_some_symbol("a").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

View file

@ -1,7 +1,7 @@
mod class_tester;
mod expect;
mod symbol_tester;
use std::{path::PathBuf, sync::Arc};
use std::sync::Arc;
pub use class_tester::ClassTester;
pub use expect::Expect;
@ -88,7 +88,6 @@ impl<'a> SemanticTester<'a> {
let semantic_ret = SemanticBuilder::new(self.source_text, self.source_type)
.with_check_syntax_error(true)
.with_trivias(parse.trivias)
.build_module_record(PathBuf::new(), program)
.with_cfg(self.cfg)
.build(program);

View file

@ -159,21 +159,12 @@ impl<'a> SymbolTester<'a> {
self.test_result = match self.test_result {
Ok(symbol_id) => {
let binding = self.target_symbol_name.clone();
let is_in_module_record =
self.semantic.module_record().exported_bindings.contains_key(binding.as_str())
&& self.semantic.scopes().get_root_binding(&binding) == Some(symbol_id);
let has_export_flag = self.semantic.symbols().get_flag(symbol_id).is_export();
match (is_in_module_record, has_export_flag) {
(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),
if self.semantic.symbols().get_flag(symbol_id).is_export() {
Ok(symbol_id)
} else {
Err(OxcDiagnostic::error(format!(
"Expected {binding} to be exported with SymbolFlags::Export"
)))
}
}
e => e,
@ -191,15 +182,6 @@ impl<'a> SymbolTester<'a> {
Err(OxcDiagnostic::error(format!(
"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 {
Ok(symbol_id)
}

View file

@ -90,7 +90,10 @@ impl<'a> ModuleImports<'a> {
let local = name.local.unwrap_or_else(|| name.imported.clone());
ImportDeclarationSpecifier::ImportSpecifier(self.ast.alloc(ImportSpecifier {
span: SPAN,
imported: ModuleExportName::Identifier(IdentifierName::new(SPAN, name.imported)),
imported: ModuleExportName::IdentifierName(IdentifierName::new(
SPAN,
name.imported,
)),
local: BindingIdentifier {
span: SPAN,
name: local,

View file

@ -516,11 +516,6 @@ impl<'a> TypeScriptAnnotations<'a> {
pub fn has_value_reference(&self, name: &str, ctx: &TraverseCtx<'a>) -> bool {
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
.symbols()
.get_resolved_references(symbol_id)

View file

@ -3109,7 +3109,12 @@ pub(crate) unsafe fn walk_module_export_name<'a, Tr: Traverse<'a>>(
) {
traverser.enter_module_export_name(&mut *node, ctx);
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) => {
walk_string_literal(traverser, node as *mut _, ctx)
}

View file

@ -1,6 +1,6 @@
commit: 12619ffe
Passed: 472/927
Passed: 473/927
# All Passed:
* babel-preset-react
@ -445,11 +445,10 @@ Passed: 472/927
* opts/optimizeConstEnums/input.ts
* opts/rewriteImportExtensions/input.ts
# babel-plugin-transform-typescript (128/151)
# babel-plugin-transform-typescript (129/151)
* enum/mix-references/input.ts
* enum/ts5.0-const-foldable/input.ts
* exports/declared-types/input.ts
* exports/imported-types/input.ts
* exports/interface/input.ts
* imports/elide-no-import-specifiers/input.ts
* imports/elision-locations/input.ts