mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
parent
b28b61774b
commit
198eea0bce
4 changed files with 2261 additions and 1234 deletions
|
|
@ -28,7 +28,7 @@ pub use crate::{
|
||||||
ast_builder::AstBuilder,
|
ast_builder::AstBuilder,
|
||||||
ast_kind::{AstKind, AstType},
|
ast_kind::{AstKind, AstType},
|
||||||
trivia::{Comment, CommentKind, Trivias, TriviasMap},
|
trivia::{Comment, CommentKind, Trivias, TriviasMap},
|
||||||
visit::Visit,
|
visit::{walk, Visit},
|
||||||
visit_mut::VisitMut,
|
visit_mut::VisitMut,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -2,8 +2,12 @@
|
||||||
//!
|
//!
|
||||||
//! * <https://github.com/guybedford/es-module-lexer>
|
//! * <https://github.com/guybedford/es-module-lexer>
|
||||||
|
|
||||||
|
use oxc_ast::walk::{
|
||||||
|
walk_export_all_declaration, walk_export_named_declaration, walk_import_declaration,
|
||||||
|
walk_import_expression, walk_meta_property, walk_module_declaration, walk_statement,
|
||||||
|
};
|
||||||
#[allow(clippy::wildcard_imports)]
|
#[allow(clippy::wildcard_imports)]
|
||||||
use oxc_ast::{ast::*, syntax_directed_operations::BoundNames, AstKind, Visit};
|
use oxc_ast::{ast::*, syntax_directed_operations::BoundNames, Visit};
|
||||||
use oxc_span::{Atom, GetSpan};
|
use oxc_span::{Atom, GetSpan};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -109,161 +113,170 @@ impl<'a> ModuleLexer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Visit<'a> for ModuleLexer<'a> {
|
impl<'a> Visit<'a> for ModuleLexer<'a> {
|
||||||
fn enter_node(&mut self, kind: AstKind<'a>) {
|
fn visit_statement(&mut self, stmt: &Statement<'a>) {
|
||||||
match kind {
|
if self.facade
|
||||||
kind if self.facade && kind.is_statement() => {
|
&& !matches!(stmt, Statement::ModuleDeclaration(..) | Statement::Declaration(..))
|
||||||
|
{
|
||||||
|
self.facade = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// import.meta
|
||||||
|
fn visit_meta_property(&mut self, prop: &MetaProperty<'a>) {
|
||||||
|
if !self.has_module_syntax {
|
||||||
|
self.has_module_syntax = true;
|
||||||
|
}
|
||||||
|
if prop.meta.name == "import" && prop.property.name == "meta" {
|
||||||
|
self.imports.push(ImportSpecifier {
|
||||||
|
n: None,
|
||||||
|
s: prop.span.start,
|
||||||
|
e: prop.span.end,
|
||||||
|
ss: prop.span.start,
|
||||||
|
se: prop.span.end,
|
||||||
|
d: ImportType::ImportMeta,
|
||||||
|
a: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
walk_meta_property(self, prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// import("foo")
|
||||||
|
fn visit_import_expression(&mut self, expr: &ImportExpression<'a>) {
|
||||||
|
let (source, source_span_start, source_span_end) =
|
||||||
|
if let Expression::StringLiteral(s) = &expr.source {
|
||||||
|
(Some(s.value.clone()), s.span.start, s.span.end)
|
||||||
|
} else {
|
||||||
|
let span = expr.source.span();
|
||||||
|
(None, span.start, span.end)
|
||||||
|
};
|
||||||
|
self.imports.push(ImportSpecifier {
|
||||||
|
n: source,
|
||||||
|
s: source_span_start,
|
||||||
|
e: source_span_end,
|
||||||
|
ss: expr.span.start,
|
||||||
|
se: expr.span.end,
|
||||||
|
d: ImportType::DynamicImport(expr.span.start + 6),
|
||||||
|
a: expr.arguments.first().map(|e| e.span().start),
|
||||||
|
});
|
||||||
|
walk_import_expression(self, expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_import_declaration(&mut self, decl: &ImportDeclaration<'a>) {
|
||||||
|
let assertions = decl
|
||||||
|
.with_clause
|
||||||
|
.as_ref()
|
||||||
|
.filter(|c| c.with_entries.first().is_some_and(|a| a.key.as_atom() == "type"))
|
||||||
|
.map(|c| c.span.start);
|
||||||
|
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::StaticImport,
|
||||||
|
a: assertions,
|
||||||
|
});
|
||||||
|
walk_import_declaration(self, decl);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_export_named_declaration(&mut self, decl: &ExportNamedDeclaration<'a>) {
|
||||||
|
if let Some(source) = &decl.source {
|
||||||
|
// export { named } from 'foo'
|
||||||
|
self.imports.push(ImportSpecifier {
|
||||||
|
n: Some(source.value.clone()),
|
||||||
|
s: source.span.start + 1,
|
||||||
|
e: source.span.end - 1,
|
||||||
|
ss: decl.span.start,
|
||||||
|
se: decl.span.end,
|
||||||
|
d: ImportType::StaticImport,
|
||||||
|
a: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// export const/let/var/function/class ...
|
||||||
|
if let Some(decl) = &decl.declaration {
|
||||||
|
if self.facade {
|
||||||
self.facade = false;
|
self.facade = false;
|
||||||
}
|
}
|
||||||
AstKind::ModuleDeclaration(_) if !self.has_module_syntax => {
|
decl.bound_names(&mut |ident| {
|
||||||
self.has_module_syntax = true;
|
|
||||||
}
|
|
||||||
// import.meta
|
|
||||||
AstKind::MetaProperty(prop) => {
|
|
||||||
if !self.has_module_syntax {
|
|
||||||
self.has_module_syntax = true;
|
|
||||||
}
|
|
||||||
if prop.meta.name == "import" && prop.property.name == "meta" {
|
|
||||||
self.imports.push(ImportSpecifier {
|
|
||||||
n: None,
|
|
||||||
s: prop.span.start,
|
|
||||||
e: prop.span.end,
|
|
||||||
ss: prop.span.start,
|
|
||||||
se: prop.span.end,
|
|
||||||
d: ImportType::ImportMeta,
|
|
||||||
a: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// import("foo")
|
|
||||||
AstKind::ImportExpression(expr) => {
|
|
||||||
let (source, source_span_start, source_span_end) =
|
|
||||||
if let Expression::StringLiteral(s) = &expr.source {
|
|
||||||
(Some(s.value.clone()), s.span.start, s.span.end)
|
|
||||||
} else {
|
|
||||||
let span = expr.source.span();
|
|
||||||
(None, span.start, span.end)
|
|
||||||
};
|
|
||||||
self.imports.push(ImportSpecifier {
|
|
||||||
n: source,
|
|
||||||
s: source_span_start,
|
|
||||||
e: source_span_end,
|
|
||||||
ss: expr.span.start,
|
|
||||||
se: expr.span.end,
|
|
||||||
d: ImportType::DynamicImport(expr.span.start + 6),
|
|
||||||
a: expr.arguments.first().map(|e| e.span().start),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
AstKind::ImportDeclaration(decl) => {
|
|
||||||
let assertions = decl
|
|
||||||
.with_clause
|
|
||||||
.as_ref()
|
|
||||||
.filter(|c| c.with_entries.first().is_some_and(|a| a.key.as_atom() == "type"))
|
|
||||||
.map(|c| c.span.start);
|
|
||||||
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::StaticImport,
|
|
||||||
a: assertions,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
AstKind::ExportNamedDeclaration(decl) => {
|
|
||||||
if let Some(source) = &decl.source {
|
|
||||||
// export { named } from 'foo'
|
|
||||||
self.imports.push(ImportSpecifier {
|
|
||||||
n: Some(source.value.clone()),
|
|
||||||
s: source.span.start + 1,
|
|
||||||
e: source.span.end - 1,
|
|
||||||
ss: decl.span.start,
|
|
||||||
se: decl.span.end,
|
|
||||||
d: ImportType::StaticImport,
|
|
||||||
a: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// export const/let/var/function/class ...
|
|
||||||
if let Some(decl) = &decl.declaration {
|
|
||||||
if self.facade {
|
|
||||||
self.facade = false;
|
|
||||||
}
|
|
||||||
decl.bound_names(&mut |ident| {
|
|
||||||
self.exports.push(ExportSpecifier {
|
|
||||||
n: ident.name.clone(),
|
|
||||||
ln: Some(ident.name.clone()),
|
|
||||||
s: ident.span.start,
|
|
||||||
e: ident.span.end,
|
|
||||||
ls: None,
|
|
||||||
le: None,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// export { named }
|
|
||||||
self.exports.extend(decl.specifiers.iter().map(|s| {
|
|
||||||
let (exported_start, exported_end) = match &s.exported {
|
|
||||||
ModuleExportName::Identifier(ident) => (ident.span.start, ident.span.end),
|
|
||||||
// +1 -1 to remove the string quotes
|
|
||||||
ModuleExportName::StringLiteral(s) => (s.span.start + 1, s.span.end - 1),
|
|
||||||
};
|
|
||||||
ExportSpecifier {
|
|
||||||
n: s.exported.name().clone(),
|
|
||||||
ln: decl.source.is_none().then(|| s.local.name().clone()),
|
|
||||||
s: exported_start,
|
|
||||||
e: exported_end,
|
|
||||||
ls: Some(s.local.span().start),
|
|
||||||
le: Some(s.local.span().end),
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
// export default foo
|
|
||||||
AstKind::ExportDefaultDeclaration(decl) => {
|
|
||||||
if self.facade {
|
|
||||||
self.facade = false;
|
|
||||||
}
|
|
||||||
let ln = match &decl.declaration {
|
|
||||||
ExportDefaultDeclarationKind::FunctionDeclaration(func) => func.id.as_ref(),
|
|
||||||
ExportDefaultDeclarationKind::ClassDeclaration(class) => class.id.as_ref(),
|
|
||||||
ExportDefaultDeclarationKind::Expression(_)
|
|
||||||
| ExportDefaultDeclarationKind::TSInterfaceDeclaration(_)
|
|
||||||
| ExportDefaultDeclarationKind::TSEnumDeclaration(_) => None,
|
|
||||||
};
|
|
||||||
self.exports.push(ExportSpecifier {
|
self.exports.push(ExportSpecifier {
|
||||||
n: decl.exported.name().clone(),
|
n: ident.name.clone(),
|
||||||
ln: ln.map(|id| id.name.clone()),
|
ln: Some(ident.name.clone()),
|
||||||
s: decl.exported.span().start,
|
s: ident.span.start,
|
||||||
e: decl.exported.span().end,
|
e: ident.span.end,
|
||||||
ls: None,
|
ls: None,
|
||||||
le: None,
|
le: None,
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
AstKind::ExportAllDeclaration(decl) => {
|
|
||||||
// export * as ns from 'foo'
|
|
||||||
if let Some(exported) = &decl.exported {
|
|
||||||
let n = exported.name().clone();
|
|
||||||
let s = exported.span().start;
|
|
||||||
let e = exported.span().end;
|
|
||||||
self.exports.push(ExportSpecifier {
|
|
||||||
n: n.clone(),
|
|
||||||
ln: None,
|
|
||||||
s,
|
|
||||||
e,
|
|
||||||
ls: None,
|
|
||||||
le: None,
|
|
||||||
});
|
|
||||||
self.imports.push(ImportSpecifier {
|
|
||||||
n: Some(n),
|
|
||||||
s,
|
|
||||||
e,
|
|
||||||
ss: decl.span.start,
|
|
||||||
se: decl.span.end,
|
|
||||||
d: ImportType::StaticImport,
|
|
||||||
a: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// export { named }
|
||||||
|
self.exports.extend(decl.specifiers.iter().map(|s| {
|
||||||
|
let (exported_start, exported_end) = match &s.exported {
|
||||||
|
ModuleExportName::Identifier(ident) => (ident.span.start, ident.span.end),
|
||||||
|
// +1 -1 to remove the string quotes
|
||||||
|
ModuleExportName::StringLiteral(s) => (s.span.start + 1, s.span.end - 1),
|
||||||
|
};
|
||||||
|
ExportSpecifier {
|
||||||
|
n: s.exported.name().clone(),
|
||||||
|
ln: decl.source.is_none().then(|| s.local.name().clone()),
|
||||||
|
s: exported_start,
|
||||||
|
e: exported_end,
|
||||||
|
ls: Some(s.local.span().start),
|
||||||
|
le: Some(s.local.span().end),
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
walk_export_named_declaration(self, decl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// export default foo
|
||||||
|
fn visit_export_default_declaration(&mut self, decl: &ExportDefaultDeclaration<'a>) {
|
||||||
|
if self.facade {
|
||||||
|
self.facade = false;
|
||||||
|
}
|
||||||
|
let ln = match &decl.declaration {
|
||||||
|
ExportDefaultDeclarationKind::FunctionDeclaration(func) => func.id.as_ref(),
|
||||||
|
ExportDefaultDeclarationKind::ClassDeclaration(class) => class.id.as_ref(),
|
||||||
|
ExportDefaultDeclarationKind::Expression(_)
|
||||||
|
| ExportDefaultDeclarationKind::TSInterfaceDeclaration(_)
|
||||||
|
| ExportDefaultDeclarationKind::TSEnumDeclaration(_) => None,
|
||||||
|
};
|
||||||
|
self.exports.push(ExportSpecifier {
|
||||||
|
n: decl.exported.name().clone(),
|
||||||
|
ln: ln.map(|id| id.name.clone()),
|
||||||
|
s: decl.exported.span().start,
|
||||||
|
e: decl.exported.span().end,
|
||||||
|
ls: None,
|
||||||
|
le: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_export_all_declaration(&mut self, decl: &ExportAllDeclaration<'a>) {
|
||||||
|
// export * as ns from 'foo'
|
||||||
|
if let Some(exported) = &decl.exported {
|
||||||
|
let n = exported.name().clone();
|
||||||
|
let s = exported.span().start;
|
||||||
|
let e = exported.span().end;
|
||||||
|
self.exports.push(ExportSpecifier { n: n.clone(), ln: None, s, e, ls: None, le: None });
|
||||||
|
self.imports.push(ImportSpecifier {
|
||||||
|
n: Some(n),
|
||||||
|
s,
|
||||||
|
e,
|
||||||
|
ss: decl.span.start,
|
||||||
|
se: decl.span.end,
|
||||||
|
d: ImportType::StaticImport,
|
||||||
|
a: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
walk_export_all_declaration(self, decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
use std::{env, path::Path};
|
use std::{env, path::Path};
|
||||||
|
|
||||||
use oxc_allocator::Allocator;
|
use oxc_allocator::Allocator;
|
||||||
use oxc_ast::{AstKind, Visit};
|
use oxc_ast::{
|
||||||
|
ast::{Class, Function},
|
||||||
|
walk::{walk_class, walk_function},
|
||||||
|
Visit,
|
||||||
|
};
|
||||||
use oxc_parser::Parser;
|
use oxc_parser::Parser;
|
||||||
use oxc_span::SourceType;
|
use oxc_span::SourceType;
|
||||||
|
use oxc_syntax::scope::ScopeFlags;
|
||||||
|
|
||||||
// Instruction:
|
// Instruction:
|
||||||
// create a `test.js`,
|
// create a `test.js`,
|
||||||
|
|
@ -39,15 +44,13 @@ struct ASTPass {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Visit<'a> for ASTPass {
|
impl<'a> Visit<'a> for ASTPass {
|
||||||
fn enter_node(&mut self, kind: AstKind<'a>) {
|
fn visit_function(&mut self, func: &Function<'a>, flags: Option<ScopeFlags>) {
|
||||||
match kind {
|
self.number_of_functions += 1;
|
||||||
AstKind::Function(_) => {
|
walk_function(self, func, flags);
|
||||||
self.number_of_functions += 1;
|
}
|
||||||
}
|
|
||||||
AstKind::Class(_) => {
|
fn visit_class(&mut self, class: &Class<'a>) {
|
||||||
self.number_of_classes += 1;
|
self.number_of_classes += 1;
|
||||||
}
|
walk_class(self, class);
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue