mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
fix(module_lexer): add missing export * from 'foo'; case (#7103)
fixes #7039
This commit is contained in:
parent
9f611a18cf
commit
9ed9501bcd
5 changed files with 56 additions and 19 deletions
|
|
@ -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};
|
||||
|
||||
|
|
@ -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,
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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")
|
||||
|
|
@ -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>) {
|
||||
|
|
@ -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>) {
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
1
napi/parser/index.d.ts
vendored
1
napi/parser/index.d.ts
vendored
|
|
@ -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
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { assert, describe, it } from 'vitest';
|
||||
import { assert, describe, expect, it } from 'vitest';
|
||||
|
||||
import * as oxc from '../index.js';
|
||||
|
||||
|
|
@ -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,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue