Skip to content

Commit

Permalink
fix(module_lexer): add missing export * from 'foo'; case (#7103)
Browse files Browse the repository at this point in the history
fixes #7039
  • Loading branch information
Boshen committed Nov 3, 2024
1 parent 9f611a1 commit 9ed9501
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 19 deletions.
41 changes: 25 additions & 16 deletions crates/oxc_module_lexer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
//!
//! * <https://github.com/guybedford/es-module-lexer>
use oxc_ast::visit::walk::{
walk_export_all_declaration, walk_export_named_declaration, walk_import_declaration,
walk_import_expression, walk_meta_property, walk_module_declaration, walk_statement,
};
use oxc_ast::{ast::*, Visit};
use oxc_ast::{ast::*, visit::walk, Visit};
use oxc_ecmascript::BoundNames;
use oxc_span::{Atom, GetSpan};

Expand Down Expand Up @@ -67,11 +63,13 @@ pub struct ExportSpecifier<'a> {

#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
pub enum ImportType {
/// If this import keyword is a dynamic import, this is the start value.
DynamicImport(u32),
/// If this import keyword is a static import
#[default]
StaticImport,
/// If this import is an `export *`
ExportStar,
/// If this import keyword is a dynamic import, this is the start value.
DynamicImport(u32),
/// If this import keyword is an import.meta expression
ImportMeta,
}
Expand All @@ -80,7 +78,7 @@ impl ImportType {
pub fn as_dynamic_import(&self) -> Option<u32> {
match self {
Self::DynamicImport(start) => Some(*start),
Self::StaticImport | Self::ImportMeta => None,
Self::StaticImport | Self::ExportStar | Self::ImportMeta => None,
}
}
}
Expand Down Expand Up @@ -123,15 +121,14 @@ impl<'a> Visit<'a> for ModuleLexer<'a> {
if self.facade && !stmt.is_module_declaration() && !stmt.is_declaration() {
self.facade = false;
}

walk_statement(self, stmt);
walk::walk_statement(self, stmt);
}

fn visit_module_declaration(&mut self, decl: &ModuleDeclaration<'a>) {
if !self.has_module_syntax {
self.has_module_syntax = true;
}
walk_module_declaration(self, decl);
walk::walk_module_declaration(self, decl);
}

// import.meta
Expand All @@ -151,7 +148,7 @@ impl<'a> Visit<'a> for ModuleLexer<'a> {
t: false,
});
}
walk_meta_property(self, prop);
walk::walk_meta_property(self, prop);
}

// import("foo")
Expand All @@ -173,7 +170,7 @@ impl<'a> Visit<'a> for ModuleLexer<'a> {
a: expr.arguments.first().map(|e| e.span().start),
t: false,
});
walk_import_expression(self, expr);
walk::walk_import_expression(self, expr);
}

fn visit_ts_import_type(&mut self, impt: &TSImportType<'a>) {
Expand Down Expand Up @@ -213,7 +210,7 @@ impl<'a> Visit<'a> for ModuleLexer<'a> {
a: assertions,
t: decl.import_kind.is_type(),
});
walk_import_declaration(self, decl);
walk::walk_import_declaration(self, decl);
}

fn visit_export_named_declaration(&mut self, decl: &ExportNamedDeclaration<'a>) {
Expand Down Expand Up @@ -267,7 +264,7 @@ impl<'a> Visit<'a> for ModuleLexer<'a> {
t: decl.export_kind.is_type(),
}
}));
walk_export_named_declaration(self, decl);
walk::walk_export_named_declaration(self, decl);
}

// export default foo
Expand Down Expand Up @@ -316,7 +313,19 @@ impl<'a> Visit<'a> for ModuleLexer<'a> {
a: None,
t: decl.export_kind.is_type(),
});
} else {
// export * from 'foo'
self.imports.push(ImportSpecifier {
n: Some(decl.source.value.clone()),
s: decl.source.span.start + 1, // +- 1 for removing string quotes
e: decl.source.span.end - 1,
ss: decl.span.start,
se: decl.span.end,
d: ImportType::ExportStar,
a: None,
t: decl.export_kind.is_type(),
});
}
walk_export_all_declaration(self, decl);
walk::walk_export_all_declaration(self, decl);
}
}
17 changes: 15 additions & 2 deletions crates/oxc_module_lexer/tests/integration/esm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,21 @@ fn named_imports() {
let source = "import { a, b, c } from 'foo'";
let imports = &parse(source).imports;
assert_eq!(imports.len(), 1);
// assert_eq!(source.slice(impt.ss, impt.se), r#"import(("asdf"))"#);
// assert_eq!(source.slice(impt.s, impt.e), r#"("asdf")"#);
let impt = &parse(source).imports[0];
assert_eq!(source.slice(impt.ss, impt.se), source);
assert_eq!(source.slice(impt.s, impt.e), "foo");
}

#[test]
fn export_star_from() {
let source = "export * from 'foo'";
let imports = &parse(source).imports;
assert_eq!(imports.len(), 1);
let impt = &parse(source).imports[0];
assert_eq!(source.slice(impt.ss, impt.se), source);
assert_eq!(source.slice(impt.s, impt.e), "foo");
assert_eq!(impt.n.as_deref(), Some("foo"));
assert_eq!(impt.d, ImportType::ExportStar);
}

/* Suite Lexer */
Expand Down
1 change: 1 addition & 0 deletions napi/parser/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export interface ImportSpecifier {
* * If this import keyword is a dynamic import, this is the start value.
* * If this import keyword is a static import, this is -1.
* * If this import keyword is an import.meta expression, this is -2.
* * If this import is an `export *`, this is -3.
*/
d: number
/**
Expand Down
2 changes: 2 additions & 0 deletions napi/parser/src/module_lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub struct ImportSpecifier {
/// * If this import keyword is a dynamic import, this is the start value.
/// * If this import keyword is a static import, this is -1.
/// * If this import keyword is an import.meta expression, this is -2.
/// * If this import is an `export *`, this is -3.
pub d: i64,

/// If this import has an import assertion, this is the start value
Expand Down Expand Up @@ -72,6 +73,7 @@ impl<'a> From<oxc_module_lexer::ImportSpecifier<'a>> for ImportSpecifier {
ImportType::DynamicImport(start) => start as i64,
ImportType::StaticImport => -1,
ImportType::ImportMeta => -2,
ImportType::ExportStar => -3,
},
a: i.a.map_or(-1, |a| a as i64),
}
Expand Down
14 changes: 13 additions & 1 deletion napi/parser/test/module_lexer.test.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assert, describe, it } from 'vitest';
import { assert, describe, expect, it } from 'vitest';

import * as oxc from '../index.js';

Expand All @@ -14,4 +14,16 @@ describe('module lexer', () => {
const ret = await oxc.moduleLexerAsync(code);
assert(ret.exports.length == 1);
});

it('returns export *', async () => {
const ret = await oxc.moduleLexerAsync("export * from 'foo';");
expect(ret).toEqual(
{
imports: [{ n: 'foo', s: 15, e: 18, ss: 0, se: 20, d: -3, a: -1 }],
exports: [],
hasModuleSyntax: true,
facade: true,
},
);
});
});

0 comments on commit 9ed9501

Please sign in to comment.