Skip to content

Commit

Permalink
feat(napi/parser): expose dynamic import expressions (#8540)
Browse files Browse the repository at this point in the history
closes #8369
  • Loading branch information
Boshen authored Jan 16, 2025
1 parent f57aac2 commit c479a58
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 6 deletions.
5 changes: 4 additions & 1 deletion crates/oxc_parser/src/js/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ impl<'a> ParserImpl<'a> {
self.ctx = self.ctx.and_in(has_in);
self.bump(Kind::Comma);
self.expect(Kind::RParen)?;
Ok(self.ast.expression_import(self.end_span(span), expression, arguments, phase))
let expr =
self.ast.alloc_import_expression(self.end_span(span), expression, arguments, phase);
self.module_record_builder.visit_import_expression(&expr);
Ok(Expression::ImportExpression(expr))
}

/// Section 16.2.2 Import Declaration
Expand Down
15 changes: 15 additions & 0 deletions crates/oxc_parser/src/module_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ impl<'a> ModuleRecordBuilder<'a> {
}
}

pub fn visit_import_expression(&mut self, e: &ImportExpression<'a>) {
self.module_record
.dynamic_imports
.push(DynamicImport { span: e.span, module_request: e.source.span() });
}

pub fn visit_import_meta(&mut self, span: Span) {
self.module_record.has_module_syntax = true;
self.module_record.import_metas.push(span);
Expand Down Expand Up @@ -701,4 +707,13 @@ mod module_record_tests {
assert_eq!(module_record.import_metas[0], Span::new(0, 11));
assert_eq!(module_record.import_metas[1], Span::new(17, 28));
}

#[test]
fn dynamic_imports() {
let allocator = Allocator::default();
let module_record = build(&allocator, "import('foo')");
assert_eq!(module_record.dynamic_imports.len(), 1);
assert_eq!(module_record.dynamic_imports[0].span, Span::new(0, 13));
assert_eq!(module_record.dynamic_imports[0].module_request, Span::new(7, 12));
}
}
13 changes: 13 additions & 0 deletions crates/oxc_syntax/src/module_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ pub struct ModuleRecord<'a> {
/// Local exported bindings
pub exported_bindings: FxHashMap<Atom<'a>, Span>,

/// Dynamic import expressions `import(specifier)`.
pub dynamic_imports: Vec<'a, DynamicImport>,

/// Span position of `import.meta`.
pub import_metas: Vec<'a, Span>,
}
Expand All @@ -72,6 +75,7 @@ impl<'a> ModuleRecord<'a> {
indirect_export_entries: Vec::new_in(allocator),
star_export_entries: Vec::new_in(allocator),
exported_bindings: FxHashMap::default(),
dynamic_imports: Vec::new_in(allocator),
import_metas: Vec::new_in(allocator),
}
}
Expand Down Expand Up @@ -374,6 +378,15 @@ pub struct RequestedModule {
pub is_import: bool,
}

/// Dynamic import expression.
#[derive(Debug, Clone, Copy)]
pub struct DynamicImport {
/// Span of the import expression.
pub span: Span,
/// Span the ModuleSpecifier, which is an expression.
pub module_request: Span,
}

#[cfg(test)]
mod test {
use oxc_span::Span;
Expand Down
12 changes: 10 additions & 2 deletions napi/parser/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ export interface Comment {
end: number
}

export interface DynamicImport {
start: number
end: number
moduleRequest: Span
}

export interface EcmaScriptModule {
/**
* Has ESM syntax.
Expand All @@ -46,10 +52,12 @@ export interface EcmaScriptModule {
* Dynamic imports `import('foo')` are ignored since they can be used in non-ESM files.
*/
hasModuleSyntax: boolean
/** Import Statements. */
/** Import statements. */
staticImports: Array<StaticImport>
/** Export Statements. */
/** Export statements. */
staticExports: Array<StaticExport>
/** Dynamic import expressions. */
dynamicImports: Array<DynamicImport>
/** Span positions` of `import.meta` */
importMetas: Array<Span>
}
Expand Down
13 changes: 12 additions & 1 deletion napi/parser/src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rustc_hash::FxHashMap;
use oxc::syntax::module_record::{self, ModuleRecord};

use crate::types::{
EcmaScriptModule, ExportExportName, ExportExportNameKind, ExportImportName,
DynamicImport, EcmaScriptModule, ExportExportName, ExportExportNameKind, ExportImportName,
ExportImportNameKind, ExportLocalName, ExportLocalNameKind, ImportName, ImportNameKind, Span,
StaticExport, StaticExportEntry, StaticImport, StaticImportEntry, ValueSpan,
};
Expand Down Expand Up @@ -55,12 +55,23 @@ impl From<&ModuleRecord<'_>> for EcmaScriptModule {
.collect::<Vec<_>>();
static_exports.sort_unstable_by_key(|e| e.start);

let dynamic_imports = record
.dynamic_imports
.iter()
.map(|i| DynamicImport {
start: i.span.start,
end: i.span.end,
module_request: Span::from(&i.module_request),
})
.collect::<Vec<_>>();

let import_metas = record.import_metas.iter().map(Span::from).collect();

Self {
has_module_syntax: record.has_module_syntax,
static_imports,
static_exports,
dynamic_imports,
import_metas,
}
}
Expand Down
13 changes: 11 additions & 2 deletions napi/parser/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,12 @@ pub struct EcmaScriptModule {
///
/// Dynamic imports `import('foo')` are ignored since they can be used in non-ESM files.
pub has_module_syntax: bool,
/// Import Statements.
/// Import statements.
pub static_imports: Vec<StaticImport>,
/// Export Statements.
/// Export statements.
pub static_exports: Vec<StaticExport>,
/// Dynamic import expressions.
pub dynamic_imports: Vec<DynamicImport>,
/// Span positions` of `import.meta`
pub import_metas: Vec<Span>,
}
Expand Down Expand Up @@ -245,3 +247,10 @@ pub enum ExportLocalNameKind {
/// `export default function () {}`
None,
}

#[napi(object)]
pub struct DynamicImport {
pub start: u32,
pub end: u32,
pub module_request: Span,
}
Loading

0 comments on commit c479a58

Please sign in to comment.