Skip to content

Commit

Permalink
refactor(syntax): remove ModuleRecord::export_default (#7578)
Browse files Browse the repository at this point in the history
This value can be derived.
  • Loading branch information
Boshen committed Dec 2, 2024
1 parent d476660 commit 18519de
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 60 deletions.
12 changes: 11 additions & 1 deletion crates/oxc_linter/src/module_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,17 @@ impl ModuleRecord {
.iter()
.map(|(name, span)| (CompactStr::from(name.as_str()), *span))
.collect(),
export_default: other.export_default,
export_default: other
.local_export_entries
.iter()
.filter_map(|export_entry| export_entry.export_name.default_export_span())
.chain(
other
.indirect_export_entries
.iter()
.filter_map(|export_entry| export_entry.export_name.default_export_span()),
)
.next(),
..ModuleRecord::default()
}
}
Expand Down
3 changes: 0 additions & 3 deletions crates/oxc_linter/src/rules/import/no_default_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ impl Rule for NoDefaultExport {
if let Some(span) = module_record.export_default {
ctx.diagnostic(no_default_export_diagnostic(span));
}
if let Some(span) = module_record.exported_bindings.get("default") {
ctx.diagnostic(no_default_export_diagnostic(*span));
}
}
}

Expand Down
5 changes: 3 additions & 2 deletions crates/oxc_parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,20 +438,21 @@ impl<'a> ParserImpl<'a> {
errors.push(error);
}
}
let (module_record, module_record_errors) = self.module_record_builder.build();
if errors.len() != 1 {
errors.reserve(self.lexer.errors.len() + self.errors.len());
errors.extend(self.lexer.errors);
errors.extend(self.errors);
// Skip checking for exports in TypeScript {
if !self.source_type.is_typescript() {
errors.extend(self.module_record_builder.errors());
errors.extend(module_record_errors);
}
}
let irregular_whitespaces =
self.lexer.trivia_builder.irregular_whitespaces.into_boxed_slice();
ParserReturn {
program,
module_record: self.module_record_builder.build(),
module_record,
errors,
irregular_whitespaces,
panicked,
Expand Down
45 changes: 21 additions & 24 deletions crates/oxc_parser/src/module_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ pub struct ModuleRecordBuilder<'a> {
allocator: &'a Allocator,
module_record: ModuleRecord<'a>,
export_entries: Vec<ExportEntry<'a>>,
export_default_duplicated: Vec<Span>,
exported_bindings_duplicated: Vec<NameSpan<'a>>,
}

Expand All @@ -21,16 +20,16 @@ impl<'a> ModuleRecordBuilder<'a> {
allocator,
module_record: ModuleRecord::new(allocator),
export_entries: vec![],
export_default_duplicated: vec![],
exported_bindings_duplicated: vec![],
}
}

pub fn build(mut self) -> ModuleRecord<'a> {
pub fn build(mut self) -> (ModuleRecord<'a>, Vec<OxcDiagnostic>) {
// The `ParseModule` algorithm requires `importedBoundNames` (import entries) to be
// resolved before resolving export entries.
self.resolve_export_entries();
self.module_record
let errors = self.errors();
(self.module_record, errors)
}

pub fn errors(&self) -> Vec<OxcDiagnostic> {
Expand All @@ -44,19 +43,25 @@ impl<'a> ModuleRecordBuilder<'a> {
errors.push(diagnostics::duplicate_export(&name_span.name, name_span.span, old_span));
}

for span in &self.export_default_duplicated {
let old_span = module_record.export_default.unwrap();
errors.push(diagnostics::duplicate_export("default", *span, old_span));
}

// `export default x;`
// `export { y as default };`
if let (Some(span), Some(default_span)) =
(module_record.exported_bindings.get("default"), &module_record.export_default)
{
errors.push(diagnostics::duplicate_export("default", *default_span, *span));
// Multiple default exports
// `export default foo`
// `export { default }`
let default_exports = module_record
.local_export_entries
.iter()
.filter_map(|export_entry| export_entry.export_name.default_export_span())
.chain(
module_record
.indirect_export_entries
.iter()
.filter_map(|export_entry| export_entry.export_name.default_export_span()),
)
.collect::<Vec<_>>();
if default_exports.len() > 1 {
errors.push(
OxcDiagnostic::error("Duplicated default export").with_labels(default_exports),
);
}

errors
}

Expand Down Expand Up @@ -94,12 +99,6 @@ impl<'a> ModuleRecordBuilder<'a> {
}
}

fn add_default_export(&mut self, span: Span) {
if let Some(old_node) = self.module_record.export_default.replace(span) {
self.export_default_duplicated.push(old_node);
}
}

/// [ParseModule](https://tc39.es/ecma262/#sec-parsemodule)
/// Step 10.
fn resolve_export_entries(&mut self) {
Expand Down Expand Up @@ -264,8 +263,6 @@ impl<'a> ModuleRecordBuilder<'a> {
return;
}
let exported_name = &decl.exported;
let exported_name_span = decl.exported.span();
self.add_default_export(exported_name_span);

let local_name = match &decl.declaration {
ExportDefaultDeclarationKind::Identifier(ident) => {
Expand Down
16 changes: 11 additions & 5 deletions crates/oxc_syntax/src/module_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@ pub struct ModuleRecord<'a> {

/// Local exported bindings
pub exported_bindings: FxHashMap<Atom<'a>, Span>,

/// `export default name`
/// ^^^^^^^ span
pub export_default: Option<Span>,
}

impl<'a> ModuleRecord<'a> {
Expand All @@ -72,7 +68,6 @@ impl<'a> ModuleRecord<'a> {
indirect_export_entries: Vec::new_in(allocator),
star_export_entries: Vec::new_in(allocator),
exported_bindings: FxHashMap::default(),
export_default: None,
}
}
}
Expand Down Expand Up @@ -287,6 +282,17 @@ impl ExportExportName<'_> {
Self::Null => None,
}
}

/// Get default export span
/// `export default foo`
/// `export { default }`
pub fn default_export_span(&self) -> Option<Span> {
match self {
Self::Default(span) => Some(*span),
Self::Name(name_span) if name_span.name == "default" => Some(name_span.span),
_ => None,
}
}
}

/// `LocalName` for `ExportEntry`
Expand Down
16 changes: 6 additions & 10 deletions tasks/coverage/snapshots/parser_babel.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3031,24 +3031,20 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ───────────
╰────

× Duplicated export 'default'
× Duplicated default export
╭─[babel/packages/babel-parser/test/fixtures/es2015/modules/duplicate-export-default/input.js:1:8]
1 │ export default {};
· ───┬───
· ╰── Export has already been declared here
· ───────
2 │ export default function() {};
· ───┬───
· ╰── It cannot be redeclared here
· ───────
╰────

× Duplicated export 'default'
× Duplicated default export
╭─[babel/packages/babel-parser/test/fixtures/es2015/modules/duplicate-export-default-and-export-as-default/input.js:1:8]
1 │ export default function() {};
· ───┬───
· ╰── Export has already been declared here
· ───────
2 │ export { foo as default };
· ───┬───
· ╰── It cannot be redeclared here
· ───────
╰────

× Export 'foo' is not defined
Expand Down
16 changes: 6 additions & 10 deletions tasks/coverage/snapshots/parser_test262.snap
Original file line number Diff line number Diff line change
Expand Up @@ -22158,15 +22158,13 @@ Expect Syntax Error: tasks/coverage/test262/test/language/import/import-attribut
· ╰── It can not be redeclared here
╰────

× Duplicated export 'default'
× Duplicated default export
╭─[test262/test/language/module-code/early-dup-export-dflt-id.js:18:8]
17 │ var x, y;
18 │ export default x;
· ───┬───
· ╰── Export has already been declared here
· ───────
19 │ export { y as default };
· ───┬───
· ╰── It cannot be redeclared here
· ───────
╰────

× Unexpected token
Expand Down Expand Up @@ -22199,15 +22197,13 @@ Expect Syntax Error: tasks/coverage/test262/test/language/import/import-attribut
· ╰── It cannot be redeclared here
╰────

× Duplicated export 'default'
× Duplicated default export
╭─[test262/test/language/module-code/early-dup-export-star-as-dflt.js:18:8]
17 │ var x;
18 │ export default x;
· ───┬───
· ╰── Export has already been declared here
· ───────
19 │ export * as default from './early-dup-export-start-as-dflt.js';
· ───┬───
· ╰── It cannot be redeclared here
· ───────
╰────

× Label `label` has already been declared
Expand Down
8 changes: 3 additions & 5 deletions tasks/coverage/snapshots/parser_typescript.snap
Original file line number Diff line number Diff line change
Expand Up @@ -22418,14 +22418,12 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private
13 │ deleted() {
╰────

× Duplicated export 'default'
× Duplicated default export
╭─[typescript/tests/cases/conformance/salsa/plainJSBinderErrors.ts:1:8]
1 │ export default 12
· ───┬───
· ╰── Export has already been declared here
· ───────
2 │ export default 13
· ───┬───
· ╰── It cannot be redeclared here
· ───────
3 │ const await = 1
╰────

Expand Down

0 comments on commit 18519de

Please sign in to comment.