diff --git a/crates/oxc_parser/src/js/expression.rs b/crates/oxc_parser/src/js/expression.rs index b3e8ab53009ca..5743d440f56c5 100644 --- a/crates/oxc_parser/src/js/expression.rs +++ b/crates/oxc_parser/src/js/expression.rs @@ -568,15 +568,16 @@ impl<'a> ParserImpl<'a> { meta: IdentifierName<'a>, ) -> Result> { self.bump_any(); // bump `.` + let kind = self.cur_kind(); let property = match self.cur_kind() { - Kind::Meta => { - self.module_record_builder.visit_import_meta(); - self.parse_keyword_identifier(Kind::Meta) - } + Kind::Meta => self.parse_keyword_identifier(Kind::Meta), Kind::Target => self.parse_keyword_identifier(Kind::Target), _ => self.parse_identifier_name()?, }; let span = self.end_span(span); + if kind == Kind::Meta { + self.module_record_builder.visit_import_meta(span); + } Ok(self.ast.expression_meta_property(span, meta, property)) } diff --git a/crates/oxc_parser/src/module_record.rs b/crates/oxc_parser/src/module_record.rs index 228b0b6fed7c4..86c59934be73e 100644 --- a/crates/oxc_parser/src/module_record.rs +++ b/crates/oxc_parser/src/module_record.rs @@ -174,8 +174,9 @@ impl<'a> ModuleRecordBuilder<'a> { } } - pub fn visit_import_meta(&mut self) { + pub fn visit_import_meta(&mut self, span: Span) { self.module_record.has_module_syntax = true; + self.module_record.import_metas.push(span); } pub fn visit_module_declaration(&mut self, module_decl: &ModuleDeclaration<'a>) { @@ -691,4 +692,13 @@ mod module_record_tests { } ); } + + #[test] + fn import_meta() { + let allocator = Allocator::default(); + let module_record = build(&allocator, "import.meta.foo; import.meta.bar"); + assert_eq!(module_record.import_metas.len(), 2); + assert_eq!(module_record.import_metas[0], Span::new(0, 11)); + assert_eq!(module_record.import_metas[1], Span::new(17, 28)); + } } diff --git a/crates/oxc_syntax/src/module_record.rs b/crates/oxc_syntax/src/module_record.rs index b5e6844fe3264..6af5157868275 100644 --- a/crates/oxc_syntax/src/module_record.rs +++ b/crates/oxc_syntax/src/module_record.rs @@ -56,6 +56,9 @@ pub struct ModuleRecord<'a> { /// Local exported bindings pub exported_bindings: FxHashMap, Span>, + + /// Span position of `import.meta`. + pub import_metas: Vec<'a, Span>, } impl<'a> ModuleRecord<'a> { @@ -69,6 +72,7 @@ impl<'a> ModuleRecord<'a> { indirect_export_entries: Vec::new_in(allocator), star_export_entries: Vec::new_in(allocator), exported_bindings: FxHashMap::default(), + import_metas: Vec::new_in(allocator), } } } diff --git a/napi/parser/index.d.ts b/napi/parser/index.d.ts index 252d1cc4e9b09..5cc9dfafd328b 100644 --- a/napi/parser/index.d.ts +++ b/napi/parser/index.d.ts @@ -22,6 +22,8 @@ export interface EcmaScriptModule { staticImports: Array /** Export Statements. */ staticExports: Array + /** Span positions` of `import.meta` */ + importMetas: Array } export interface ExportExportName { @@ -133,6 +135,11 @@ export declare function parseSync(filename: string, sourceText: string, options? */ export declare function parseWithoutReturn(filename: string, sourceText: string, options?: ParserOptions | undefined | null): void +export interface Span { + start: number + end: number +} + export interface StaticExport { start: number end: number diff --git a/napi/parser/src/convert.rs b/napi/parser/src/convert.rs index 5800166d74ec3..4bfb1f5a6a032 100644 --- a/napi/parser/src/convert.rs +++ b/napi/parser/src/convert.rs @@ -1,13 +1,10 @@ use rustc_hash::FxHashMap; -use oxc::{ - span::Span, - syntax::module_record::{self, ModuleRecord}, -}; +use oxc::syntax::module_record::{self, ModuleRecord}; use crate::types::{ EcmaScriptModule, ExportExportName, ExportExportNameKind, ExportImportName, - ExportImportNameKind, ExportLocalName, ExportLocalNameKind, ImportName, ImportNameKind, + ExportImportNameKind, ExportLocalName, ExportLocalNameKind, ImportName, ImportNameKind, Span, StaticExport, StaticExportEntry, StaticImport, StaticImportEntry, ValueSpan, }; @@ -49,7 +46,7 @@ impl From<&ModuleRecord<'_>> for EcmaScriptModule { .map(|e| (e.statement_span, StaticExportEntry::from(e))) .collect::>() .into_iter() - .fold(FxHashMap::>::default(), |mut acc, (span, e)| { + .fold(FxHashMap::<_, Vec>::default(), |mut acc, (span, e)| { acc.entry(span).or_default().push(e); acc }) @@ -58,7 +55,20 @@ impl From<&ModuleRecord<'_>> for EcmaScriptModule { .collect::>(); static_exports.sort_unstable_by_key(|e| e.start); - Self { has_module_syntax: record.has_module_syntax, static_imports, static_exports } + let import_metas = record.import_metas.iter().map(Span::from).collect(); + + Self { + has_module_syntax: record.has_module_syntax, + static_imports, + static_exports, + import_metas, + } + } +} + +impl From<&oxc::span::Span> for Span { + fn from(span: &oxc::span::Span) -> Self { + Self { start: span.start, end: span.end } } } diff --git a/napi/parser/src/types.rs b/napi/parser/src/types.rs index ba379f9152786..a3c309fcef756 100644 --- a/napi/parser/src/types.rs +++ b/napi/parser/src/types.rs @@ -50,6 +50,14 @@ pub struct EcmaScriptModule { pub static_imports: Vec, /// Export Statements. pub static_exports: Vec, + /// Span positions` of `import.meta` + pub import_metas: Vec, +} + +#[napi(object)] +pub struct Span { + pub start: u32, + pub end: u32, } #[napi(object)] diff --git a/napi/parser/test/__snapshots__/esm.test.ts.snap b/napi/parser/test/__snapshots__/esm.test.ts.snap index a261d34cbd577..073428784f267 100644 --- a/napi/parser/test/__snapshots__/esm.test.ts.snap +++ b/napi/parser/test/__snapshots__/esm.test.ts.snap @@ -32,7 +32,8 @@ exports[`esm > export * as name1 from "module-name"; 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -65,7 +66,8 @@ exports[`esm > export * from "module-name"; 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -104,7 +106,8 @@ exports[`esm > export { default as name1 } from "module-name"; 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -143,7 +146,8 @@ exports[`esm > export { default, /* …, */ } from "module-name"; 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -230,7 +234,8 @@ exports[`esm > export { import1 as name1, import2 as name2, /* …, */ nameN } f } ] } - ] + ], + "importMetas": [] }" `; @@ -264,7 +269,8 @@ exports[`esm > export { name1 as default /*, … */ }; 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -327,7 +333,8 @@ exports[`esm > export { name1, /* …, */ nameN } from "module-name"; 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -380,7 +387,8 @@ exports[`esm > export { name1, /* …, */ nameN }; 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -414,7 +422,8 @@ exports[`esm > export { variable1 as "string name" }; 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -486,7 +495,8 @@ exports[`esm > export { variable1 as name1, variable2 as name2, /* …, */ nameN } ] } - ] + ], + "importMetas": [] }" `; @@ -520,7 +530,8 @@ exports[`esm > export class ClassName { /* … */ } 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -573,7 +584,8 @@ exports[`esm > export const [ name1, name2 ] = array; 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -626,7 +638,8 @@ exports[`esm > export const { name1, name2: bar } = o; 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -679,7 +692,8 @@ exports[`esm > export const name1 = 1, name2 = 2/*, … */; // also var, let 1`] } ] } - ] + ], + "importMetas": [] }" `; @@ -709,7 +723,8 @@ exports[`esm > export default class { /* … */ } 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -742,7 +757,8 @@ exports[`esm > export default class ClassName { /* … */ } 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -775,7 +791,8 @@ exports[`esm > export default expression; 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -805,7 +822,8 @@ exports[`esm > export default function () { /* … */ } 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -838,7 +856,8 @@ exports[`esm > export default function functionName() { /* … */ } 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -868,7 +887,8 @@ exports[`esm > export default function* () { /* … */ } 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -901,7 +921,8 @@ exports[`esm > export default function* generatorFunctionName() { /* … */ } 1` } ] } - ] + ], + "importMetas": [] }" `; @@ -935,7 +956,8 @@ exports[`esm > export function functionName() { /* … */ } 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -969,7 +991,8 @@ exports[`esm > export function* generatorFunctionName() { /* … */ } 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -1022,7 +1045,8 @@ exports[`esm > export let name1, name2/*, … */; // also var 1`] = ` } ] } - ] + ], + "importMetas": [] }" `; @@ -1041,7 +1065,8 @@ exports[`esm > import "module-name"; 1`] = ` "entries": [] } ], - "staticExports": [] + "staticExports": [], + "importMetas": [] }" `; @@ -1072,7 +1097,8 @@ exports[`esm > import * as name from "module-name"; 1`] = ` ] } ], - "staticExports": [] + "staticExports": [], + "importMetas": [] }" `; @@ -1106,7 +1132,8 @@ exports[`esm > import { "string name" as alias } from "module-name"; 1`] = ` ] } ], - "staticExports": [] + "staticExports": [], + "importMetas": [] }" `; @@ -1140,7 +1167,8 @@ exports[`esm > import { default as alias } from "module-name"; 1`] = ` ] } ], - "staticExports": [] + "staticExports": [], + "importMetas": [] }" `; @@ -1174,7 +1202,8 @@ exports[`esm > import { export1 } from "module-name"; 1`] = ` ] } ], - "staticExports": [] + "staticExports": [], + "importMetas": [] }" `; @@ -1208,7 +1237,8 @@ exports[`esm > import { export1 as alias1 } from "module-name"; 1`] = ` ] } ], - "staticExports": [] + "staticExports": [], + "importMetas": [] }" `; @@ -1256,7 +1286,8 @@ exports[`esm > import { export1, export2 } from "module-name"; 1`] = ` ] } ], - "staticExports": [] + "staticExports": [], + "importMetas": [] }" `; @@ -1304,7 +1335,8 @@ exports[`esm > import { export1, export2 as alias2, /* … */ } from "module-nam ] } ], - "staticExports": [] + "staticExports": [], + "importMetas": [] }" `; @@ -1337,7 +1369,8 @@ exports[`esm > import defaultExport from "module-name"; 1`] = ` ] } ], - "staticExports": [] + "staticExports": [], + "importMetas": [] }" `; @@ -1381,7 +1414,8 @@ exports[`esm > import defaultExport, * as name from "module-name"; 1`] = ` ] } ], - "staticExports": [] + "staticExports": [], + "importMetas": [] }" `; @@ -1428,6 +1462,7 @@ exports[`esm > import defaultExport, { export1, /* … */ } from "module-name"; ] } ], - "staticExports": [] + "staticExports": [], + "importMetas": [] }" `; diff --git a/napi/parser/test/esm.test.ts b/napi/parser/test/esm.test.ts index 411926a1de95b..e08f44c2b301e 100644 --- a/napi/parser/test/esm.test.ts +++ b/napi/parser/test/esm.test.ts @@ -68,6 +68,7 @@ describe('hasModuleSyntax', () => { test('import.meta', () => { const ret = parseSync('test.js', 'import.meta.foo'); expect(ret.module.hasModuleSyntax).toBe(true); + expect(ret.module.importMetas).toEqual([{ start: 0, end: 11 }]); }); test('import expression', () => {