feat(syntax): add ExportEntry::is_type (#7676)

This commit is contained in:
Boshen 2024-12-05 09:02:18 +00:00
parent 245d7d922c
commit b8dc333ed4
4 changed files with 38 additions and 0 deletions

View file

@ -291,6 +291,19 @@ pub struct ExportEntry {
/// The name that is used to locally access the exported value from within the importing module.
/// null if the exported value is not locally accessible from within the module.
pub local_name: ExportLocalName,
/// Whether the export is a TypeScript `export type`.
///
/// Examples:
///
/// ```ts
/// export type * from 'mod'
/// export type * as ns from 'mod'
/// export type { foo }
/// export { type foo }
/// export type { foo } from 'mod'
/// ```
pub is_type: bool,
}
impl<'a> From<&oxc_syntax::module_record::ExportEntry<'a>> for ExportEntry {
@ -301,6 +314,7 @@ impl<'a> From<&oxc_syntax::module_record::ExportEntry<'a>> for ExportEntry {
import_name: ExportImportName::from(&other.import_name),
export_name: ExportExportName::from(&other.export_name),
local_name: ExportLocalName::from(&other.local_name),
is_type: other.is_type,
}
}
}

View file

@ -56,6 +56,9 @@ impl Rule for Export {
let mut visited = FxHashSet::default();
module_record.star_export_entries.iter().for_each(|star_export_entry| {
if star_export_entry.is_type {
return;
}
let mut export_names = FxHashSet::default();
let Some(module_request) = &star_export_entry.module_request else {
@ -266,6 +269,7 @@ fn test() {
const Bar = 2;
export {Bar as default};
"#),
"export type * from './export-props.js'",
];
let fail = vec![
(r#"let foo; export { foo }; export * from "./export-all""#),

View file

@ -154,6 +154,7 @@ impl<'a> ModuleRecordBuilder<'a> {
},
export_name: ee.export_name.clone(),
local_name: ExportLocalName::default(),
is_type: ie.is_type,
};
self.append_indirect_export_entry(export_entry);
}
@ -256,6 +257,7 @@ impl<'a> ModuleRecordBuilder<'a> {
ExportExportName::Name(NameSpan::new(exported_name.name(), exported_name.span()))
}),
local_name: ExportLocalName::default(),
is_type: decl.export_kind.is_type(),
};
self.add_export_entry(export_entry);
if let Some(exported_name) = &decl.exported {
@ -302,6 +304,7 @@ impl<'a> ModuleRecordBuilder<'a> {
import_name: ExportImportName::default(),
export_name: ExportExportName::Default(exported_name.span()),
local_name,
is_type: false,
};
self.add_export_entry(export_entry);
}
@ -343,6 +346,7 @@ impl<'a> ModuleRecordBuilder<'a> {
import_name: ExportImportName::Null,
export_name,
local_name,
is_type: decl.export_kind.is_type(),
};
self.add_export_entry(export_entry);
self.add_export_binding(ident.name.clone(), ident.span);
@ -377,6 +381,7 @@ impl<'a> ModuleRecordBuilder<'a> {
import_name,
export_name,
local_name,
is_type: specifier.export_kind.is_type() || decl.export_kind.is_type(),
};
self.add_export_entry(export_entry);
self.add_export_binding(specifier.exported.name().clone(), specifier.exported.span());
@ -670,6 +675,7 @@ mod module_record_tests {
import_name: ExportImportName::Name(NameSpan::new("x".into(), Span::new(9, 10))),
export_name: ExportExportName::Name(NameSpan::new("x".into(), Span::new(33, 34))),
local_name: ExportLocalName::Null,
is_type: false
}
);
assert_eq!(
@ -681,6 +687,7 @@ mod module_record_tests {
import_name: ExportImportName::All,
export_name: ExportExportName::Name(NameSpan::new("ns".into(), Span::new(49, 51))),
local_name: ExportLocalName::Null,
is_type: false
}
);
}

View file

@ -229,6 +229,19 @@ pub struct ExportEntry<'a> {
/// The name that is used to locally access the exported value from within the importing module.
/// null if the exported value is not locally accessible from within the module.
pub local_name: ExportLocalName<'a>,
/// Whether the export is a TypeScript `export type`.
///
/// Examples:
///
/// ```ts
/// export type * from 'mod'
/// export type * as ns from 'mod'
/// export type { foo }
/// export { type foo }
/// export type { foo } from 'mod'
/// ```
pub is_type: bool,
}
/// `ImportName` for `ExportEntry`