mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[rust] Remove SWC
After the previous PR we no longer depend on SWC for the critical path of development/testing. Notably this unblocks adding support for the rest of the language: the new `forget_hermes_parser` crate automatically converts Hermes Parser's AST into our `forget_estree` format via codegen. Achieving full language support with SWC would have required manually defining the remaining conversions for the rest of the language. Long-term we'll need to revisit how to integrate into SWC, and more generally into setups build atop SWC such as Next.js's Turbopack-based build configuration. But i'll delete for now since we don't depend on it for iteration, it's slow to build, and requires us to opt-in to nightly Rust.
This commit is contained in:
Generated
+24
-1997
File diff suppressed because it is too large
Load Diff
@@ -17,14 +17,12 @@ forget_build_hir = { path = "crates/forget_build_hir" }
|
||||
forget_diagnostics = { path = "crates/forget_diagnostics" }
|
||||
forget_estree = { path = "crates/forget_estree" }
|
||||
forget_estree_codegen = { path = "crates/forget_estree_codegen" }
|
||||
forget_estree_swc = { path = "crates/forget_estree_swc" }
|
||||
forget_fixtures = { path = "crates/forget_fixtures" }
|
||||
forget_hermes_parser = { path = "crates/forget_hermes_parser" }
|
||||
forget_hir = { path = "crates/forget_hir" }
|
||||
forget_optimization = { path = "crates/forget_optimization" }
|
||||
forget_semantic_analysis = { path = "crates/forget_semantic_analysis" }
|
||||
forget_ssa = { path = "crates/forget_ssa" }
|
||||
forget_swc_demo = { path = "crates/forget_swc_demo" }
|
||||
forget_utils = { path = "crates/forget_utils" }
|
||||
|
||||
# dependencies
|
||||
@@ -37,8 +35,6 @@ serde = { version = "1.0.167", features = ["serde_derive"] }
|
||||
serde_json = "1.0.100"
|
||||
stacker = "0.1.15"
|
||||
static_assertions = "1.1.0"
|
||||
swc = "0.264.8"
|
||||
swc_core = { version = "0.79.9", features = ["swc_ecma_visit", "__ecma_transforms", "swc_ecma_ast", "swc_common", "swc", "swc_ecma_parser", "__ecma", "__common", "ecma_ast", "__visit", "__parser"] }
|
||||
syn = "2.0.23"
|
||||
thiserror = "1.0.41"
|
||||
hermes = { git = "https://github.com/facebook/hermes.git" }
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
[package]
|
||||
name = "forget_estree_swc"
|
||||
version = "0.1.0"
|
||||
publish = false
|
||||
authors.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
forget_estree = { workspace = true }
|
||||
swc = { workspace = true }
|
||||
swc_core = { workspace = true }
|
||||
@@ -1,4 +0,0 @@
|
||||
# forget_estree_swc
|
||||
|
||||
This crate converts from SWC's AST format into Forget's `forget_estree` format, which is used as the primary
|
||||
input/type in Forget's public APIs.
|
||||
@@ -1,963 +0,0 @@
|
||||
use std::io::stderr;
|
||||
use std::num::NonZeroU32;
|
||||
use std::sync::Arc;
|
||||
|
||||
use forget_estree::{Binding, BindingId};
|
||||
use swc::Compiler;
|
||||
use swc_core::common::errors::Handler;
|
||||
use swc_core::common::source_map::Pos;
|
||||
use swc_core::common::{FileName, FilePathMapping, Mark, SourceMap, Span, SyntaxContext, GLOBALS};
|
||||
use swc_core::ecma::ast::{
|
||||
AssignOp, BinaryOp, BlockStmt, BlockStmtOrExpr, Callee, Decl, EsVersion, Expr, ExprOrSpread,
|
||||
Function, Ident, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, JSXElement,
|
||||
JSXElementChild, JSXElementName, JSXExpr, JSXMemberExpr, JSXObject, Lit, MemberExpr,
|
||||
MemberProp, ModuleItem, OptChainBase, Pat, PatOrExpr, Program, Stmt, UnaryOp, UpdateOp,
|
||||
VarDecl, VarDeclKind, VarDeclOrExpr,
|
||||
};
|
||||
use swc_core::ecma::parser::{Syntax, TsConfig};
|
||||
use swc_core::ecma::transforms::base::resolver;
|
||||
use swc_core::ecma::visit::FoldWith;
|
||||
|
||||
/// Parses source text into an forget_estree::Program via SWC, internally performing the parsing
|
||||
/// and SWC -> ESTree conversion.
|
||||
pub fn parse(
|
||||
source: &str,
|
||||
file: &str,
|
||||
) -> Result<forget_estree::Program, Box<dyn std::error::Error>> {
|
||||
GLOBALS.set(&Default::default(), || {
|
||||
let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let c = Compiler::new(cm);
|
||||
let fm =
|
||||
c.cm.new_source_file(FileName::Real(file.into()), source.to_string());
|
||||
|
||||
let handler = Handler::with_emitter_writer(Box::new(stderr()), Some(c.cm.clone()));
|
||||
|
||||
let comments = c.comments().clone();
|
||||
let module = c.parse_js(
|
||||
fm.clone(),
|
||||
&handler,
|
||||
EsVersion::Es5,
|
||||
Syntax::Typescript(TsConfig {
|
||||
tsx: true,
|
||||
..Default::default()
|
||||
}),
|
||||
swc::config::IsModule::Bool(true),
|
||||
Some(&comments),
|
||||
)?;
|
||||
|
||||
let context = Context {
|
||||
top_level_mark: Mark::new(),
|
||||
unresolved_mark: Mark::new(),
|
||||
};
|
||||
|
||||
let module = c.run_transform(&handler, false, || {
|
||||
module.fold_with(&mut resolver(
|
||||
context.unresolved_mark,
|
||||
context.top_level_mark,
|
||||
true,
|
||||
))
|
||||
});
|
||||
|
||||
Ok(convert_program(&context, &module))
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Context {
|
||||
unresolved_mark: Mark,
|
||||
top_level_mark: Mark,
|
||||
}
|
||||
|
||||
fn convert_program(cx: &Context, program: &Program) -> forget_estree::Program {
|
||||
let mut program_items: Vec<forget_estree::ModuleItem>;
|
||||
match program {
|
||||
Program::Module(program) => {
|
||||
let body = &program.body;
|
||||
program_items = Vec::with_capacity(body.len());
|
||||
for item in body {
|
||||
program_items.push(convert_module_item(cx, item));
|
||||
}
|
||||
}
|
||||
Program::Script(program) => {
|
||||
let body = &program.body;
|
||||
program_items = Vec::with_capacity(body.len());
|
||||
for item in body {
|
||||
program_items.push(forget_estree::ModuleItem::Statement(convert_statement(
|
||||
cx, item,
|
||||
)));
|
||||
}
|
||||
}
|
||||
};
|
||||
forget_estree::Program {
|
||||
source_type: if program.is_script() {
|
||||
forget_estree::SourceType::Script
|
||||
} else {
|
||||
forget_estree::SourceType::Module
|
||||
},
|
||||
body: program_items,
|
||||
// comments: None,
|
||||
loc: None,
|
||||
range: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_module_item(cx: &Context, item: &ModuleItem) -> forget_estree::ModuleItem {
|
||||
match item {
|
||||
ModuleItem::Stmt(item) => forget_estree::ModuleItem::Statement(convert_statement(cx, item)),
|
||||
_ => todo!("translate module item {:#?}", item),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_span(span: &Span) -> Option<forget_estree::SourceRange> {
|
||||
Some(forget_estree::SourceRange {
|
||||
start: span.lo().to_u32(),
|
||||
end: NonZeroU32::new(span.hi().to_u32())?,
|
||||
})
|
||||
}
|
||||
|
||||
fn convert_decl_kind(kind: &VarDeclKind) -> forget_estree::VariableDeclarationKind {
|
||||
match kind {
|
||||
VarDeclKind::Const => forget_estree::VariableDeclarationKind::Const,
|
||||
VarDeclKind::Let => forget_estree::VariableDeclarationKind::Let,
|
||||
VarDeclKind::Var => forget_estree::VariableDeclarationKind::Var,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_block_statement(cx: &Context, stmt: &BlockStmt) -> forget_estree::BlockStatement {
|
||||
let mut body: Vec<forget_estree::Statement> = Vec::with_capacity(stmt.stmts.len());
|
||||
for stmt in &stmt.stmts {
|
||||
body.push(convert_statement(cx, stmt));
|
||||
}
|
||||
forget_estree::BlockStatement {
|
||||
body,
|
||||
loc: None,
|
||||
range: convert_span(&stmt.span),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_function(cx: &Context, id: Option<&Ident>, fun: &Function) -> forget_estree::Function {
|
||||
forget_estree::Function {
|
||||
id: id.map(|id| forget_estree::Identifier {
|
||||
name: id.sym.to_string(),
|
||||
binding: convert_binding(cx, id.span.ctxt),
|
||||
type_annotation: None,
|
||||
loc: None,
|
||||
range: convert_span(&id.span),
|
||||
}),
|
||||
params: fun
|
||||
.params
|
||||
.iter()
|
||||
.map(|param| convert_pattern(cx, ¶m.pat))
|
||||
.collect(),
|
||||
body: fun.body.as_ref().map(|body| {
|
||||
forget_estree::FunctionBody::BlockStatement(Box::new(convert_block_statement(cx, body)))
|
||||
}),
|
||||
is_async: fun.is_async,
|
||||
is_generator: fun.is_generator,
|
||||
loc: None,
|
||||
range: convert_span(&fun.span),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_statement(cx: &Context, stmt: &Stmt) -> forget_estree::Statement {
|
||||
match stmt {
|
||||
Stmt::Decl(Decl::Fn(item)) => forget_estree::Statement::FunctionDeclaration(Box::new(
|
||||
forget_estree::FunctionDeclaration {
|
||||
function: convert_function(cx, Some(&item.ident), &item.function),
|
||||
loc: None,
|
||||
range: convert_span(&item.function.span),
|
||||
},
|
||||
)),
|
||||
Stmt::Decl(Decl::Var(item)) => forget_estree::Statement::VariableDeclaration(Box::new(
|
||||
convert_variable_declaration(cx, item),
|
||||
)),
|
||||
Stmt::Block(item) => {
|
||||
forget_estree::Statement::BlockStatement(Box::new(convert_block_statement(cx, item)))
|
||||
}
|
||||
Stmt::Break(item) => {
|
||||
forget_estree::Statement::BreakStatement(Box::new(forget_estree::BreakStatement {
|
||||
label: item
|
||||
.label
|
||||
.as_ref()
|
||||
.map(|label| convert_identifier(cx, label)),
|
||||
loc: None,
|
||||
range: convert_span(&item.span),
|
||||
}))
|
||||
}
|
||||
Stmt::Continue(item) => forget_estree::Statement::ContinueStatement(Box::new(
|
||||
forget_estree::ContinueStatement {
|
||||
label: item
|
||||
.label
|
||||
.as_ref()
|
||||
.map(|label| convert_identifier(cx, label)),
|
||||
loc: None,
|
||||
range: convert_span(&item.span),
|
||||
},
|
||||
)),
|
||||
Stmt::Debugger(item) => forget_estree::Statement::DebuggerStatement(Box::new(
|
||||
forget_estree::DebuggerStatement {
|
||||
loc: None,
|
||||
range: convert_span(&item.span),
|
||||
},
|
||||
)),
|
||||
Stmt::DoWhile(item) => {
|
||||
forget_estree::Statement::DoWhileStatement(Box::new(forget_estree::DoWhileStatement {
|
||||
body: convert_statement(cx, &item.body),
|
||||
test: convert_expression(cx, &item.test),
|
||||
loc: None,
|
||||
range: convert_span(&item.span),
|
||||
}))
|
||||
}
|
||||
Stmt::Empty(item) => {
|
||||
forget_estree::Statement::EmptyStatement(Box::new(forget_estree::EmptyStatement {
|
||||
loc: None,
|
||||
range: convert_span(&item.span),
|
||||
}))
|
||||
}
|
||||
Stmt::Expr(item) => {
|
||||
let expression = convert_expression(cx, &item.expr);
|
||||
forget_estree::Statement::ExpressionStatement(Box::new(
|
||||
forget_estree::ExpressionStatement {
|
||||
expression,
|
||||
directive: None,
|
||||
loc: None,
|
||||
range: convert_span(&item.span),
|
||||
},
|
||||
))
|
||||
}
|
||||
Stmt::For(item) => {
|
||||
forget_estree::Statement::ForStatement(Box::new(forget_estree::ForStatement {
|
||||
init: item.init.as_ref().map(|init| match init {
|
||||
VarDeclOrExpr::Expr(init) => {
|
||||
forget_estree::ForInit::Expression(convert_expression(cx, init))
|
||||
}
|
||||
VarDeclOrExpr::VarDecl(init) => {
|
||||
assert_eq!(init.decls.len(), 1);
|
||||
forget_estree::ForInit::VariableDeclaration(Box::new(
|
||||
convert_variable_declaration(cx, init),
|
||||
))
|
||||
}
|
||||
}),
|
||||
test: item.test.as_ref().map(|test| convert_expression(cx, test)),
|
||||
update: item
|
||||
.update
|
||||
.as_ref()
|
||||
.map(|update| convert_expression(cx, update)),
|
||||
body: convert_statement(cx, &item.body),
|
||||
loc: None,
|
||||
range: convert_span(&item.span),
|
||||
}))
|
||||
}
|
||||
Stmt::Return(item) => {
|
||||
forget_estree::Statement::ReturnStatement(Box::new(forget_estree::ReturnStatement {
|
||||
argument: item.arg.as_ref().map(|arg| convert_expression(cx, arg)),
|
||||
loc: None,
|
||||
range: convert_span(&item.span),
|
||||
}))
|
||||
}
|
||||
Stmt::Throw(item) => {
|
||||
forget_estree::Statement::ThrowStatement(Box::new(forget_estree::ThrowStatement {
|
||||
argument: convert_expression(cx, &item.arg),
|
||||
loc: None,
|
||||
range: convert_span(&item.span),
|
||||
}))
|
||||
}
|
||||
Stmt::If(item) => {
|
||||
forget_estree::Statement::IfStatement(Box::new(forget_estree::IfStatement {
|
||||
test: convert_expression(cx, &item.test),
|
||||
consequent: convert_statement(cx, &item.cons),
|
||||
alternate: item.alt.as_ref().map(|alt| convert_statement(cx, alt)),
|
||||
loc: None,
|
||||
range: convert_span(&item.span),
|
||||
}))
|
||||
}
|
||||
Stmt::Labeled(item) => {
|
||||
forget_estree::Statement::LabeledStatement(Box::new(forget_estree::LabeledStatement {
|
||||
label: convert_identifier(cx, &item.label),
|
||||
body: convert_statement(cx, &item.body),
|
||||
loc: None,
|
||||
range: convert_span(&item.span),
|
||||
}))
|
||||
}
|
||||
_ => todo!("translate statement {:#?}", stmt),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_variable_declaration(
|
||||
cx: &Context,
|
||||
decl: &VarDecl,
|
||||
) -> forget_estree::VariableDeclaration {
|
||||
forget_estree::VariableDeclaration {
|
||||
kind: convert_decl_kind(&decl.kind),
|
||||
declarations: decl
|
||||
.decls
|
||||
.iter()
|
||||
.map(|declarator| forget_estree::VariableDeclarator {
|
||||
id: convert_pattern(cx, &declarator.name),
|
||||
init: declarator
|
||||
.init
|
||||
.as_ref()
|
||||
.map(|init| convert_expression(cx, init)),
|
||||
loc: None,
|
||||
range: convert_span(&decl.span),
|
||||
})
|
||||
.collect(),
|
||||
loc: None,
|
||||
range: convert_span(&decl.span),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_expression(cx: &Context, expr: &Expr) -> forget_estree::Expression {
|
||||
match expr {
|
||||
Expr::Ident(expr) => {
|
||||
forget_estree::Expression::Identifier(Box::new(convert_identifier(cx, expr)))
|
||||
}
|
||||
Expr::Array(expr) => {
|
||||
forget_estree::Expression::ArrayExpression(Box::new(forget_estree::ArrayExpression {
|
||||
elements: expr
|
||||
.elems
|
||||
.iter()
|
||||
.map(|item| match item {
|
||||
Some(ExprOrSpread {
|
||||
spread: Some(spread),
|
||||
expr,
|
||||
}) => Some(forget_estree::ExpressionOrSpread::SpreadElement(Box::new(
|
||||
forget_estree::SpreadElement {
|
||||
argument: convert_expression(cx, expr),
|
||||
loc: None,
|
||||
range: convert_span(&spread),
|
||||
},
|
||||
))),
|
||||
Some(ExprOrSpread { spread: None, expr }) => {
|
||||
Some(forget_estree::ExpressionOrSpread::Expression(
|
||||
convert_expression(cx, expr),
|
||||
))
|
||||
}
|
||||
None => None,
|
||||
})
|
||||
.collect(),
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
}))
|
||||
}
|
||||
Expr::Call(expr) => {
|
||||
forget_estree::Expression::CallExpression(Box::new(forget_estree::CallExpression {
|
||||
callee: match &expr.callee {
|
||||
Callee::Expr(callee) => {
|
||||
forget_estree::ExpressionOrSuper::Expression(convert_expression(cx, callee))
|
||||
}
|
||||
_ => todo!(),
|
||||
},
|
||||
arguments: convert_arguments(cx, &expr.args),
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
}))
|
||||
}
|
||||
Expr::Await(expr) => {
|
||||
forget_estree::Expression::AwaitExpression(Box::new(forget_estree::AwaitExpression {
|
||||
argument: convert_expression(cx, &expr.arg),
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
}))
|
||||
}
|
||||
Expr::Yield(expr) => {
|
||||
forget_estree::Expression::YieldExpression(Box::new(forget_estree::YieldExpression {
|
||||
argument: expr.arg.as_ref().map(|arg| convert_expression(cx, arg)),
|
||||
is_delegate: expr.delegate,
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
}))
|
||||
}
|
||||
Expr::Unary(expr) => {
|
||||
forget_estree::Expression::UnaryExpression(Box::new(forget_estree::UnaryExpression {
|
||||
operator: convert_unary_operator(expr.op),
|
||||
prefix: false,
|
||||
argument: convert_expression(cx, &expr.arg),
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
}))
|
||||
}
|
||||
Expr::Bin(expr) => match convert_binary_operator(expr.op) {
|
||||
Operator::Binary(op) => forget_estree::Expression::BinaryExpression(Box::new(
|
||||
forget_estree::BinaryExpression {
|
||||
operator: op,
|
||||
left: convert_expression(cx, &expr.left),
|
||||
right: convert_expression(cx, &expr.right),
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
},
|
||||
)),
|
||||
Operator::Logical(op) => forget_estree::Expression::LogicalExpression(Box::new(
|
||||
forget_estree::LogicalExpression {
|
||||
operator: op,
|
||||
left: convert_expression(cx, &expr.left),
|
||||
right: convert_expression(cx, &expr.right),
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
},
|
||||
)),
|
||||
},
|
||||
Expr::Lit(expr) => forget_estree::Expression::Literal(Box::new(convert_literal(cx, expr))),
|
||||
Expr::Assign(expr) => forget_estree::Expression::AssignmentExpression(Box::new(
|
||||
forget_estree::AssignmentExpression {
|
||||
operator: convert_assignment_operator(expr.op),
|
||||
left: convert_assignment_target(cx, &expr.left),
|
||||
right: convert_expression(cx, &expr.right),
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
},
|
||||
)),
|
||||
Expr::Member(expr) => forget_estree::Expression::MemberExpression(Box::new(
|
||||
convert_member_expression(cx, expr),
|
||||
)),
|
||||
Expr::Fn(expr) => forget_estree::Expression::FunctionExpression(Box::new(
|
||||
forget_estree::FunctionExpression {
|
||||
function: convert_function(cx, expr.ident.as_ref(), &expr.function),
|
||||
loc: None,
|
||||
range: convert_span(&expr.function.span),
|
||||
},
|
||||
)),
|
||||
Expr::Arrow(expr) => forget_estree::Expression::ArrowFunctionExpression(Box::new(
|
||||
forget_estree::ArrowFunctionExpression {
|
||||
function: forget_estree::Function {
|
||||
id: None,
|
||||
body: match expr.body.as_ref() {
|
||||
BlockStmtOrExpr::Expr(body) => Some(
|
||||
forget_estree::FunctionBody::Expression(convert_expression(cx, body)),
|
||||
),
|
||||
BlockStmtOrExpr::BlockStmt(body) => {
|
||||
Some(forget_estree::FunctionBody::BlockStatement(Box::new(
|
||||
convert_block_statement(cx, body),
|
||||
)))
|
||||
}
|
||||
},
|
||||
params: expr
|
||||
.params
|
||||
.iter()
|
||||
.map(|param| convert_pattern(cx, param))
|
||||
.collect(),
|
||||
is_generator: expr.is_generator,
|
||||
is_async: expr.is_async,
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
},
|
||||
is_expression: true, // TODO
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
},
|
||||
)),
|
||||
Expr::OptChain(expr) => match expr.base.as_ref() {
|
||||
OptChainBase::Call(base) => forget_estree::Expression::OptionalCallExpression(
|
||||
Box::new(forget_estree::OptionalCallExpression {
|
||||
callee: forget_estree::ExpressionOrSuper::Expression(convert_expression(
|
||||
cx,
|
||||
&base.callee,
|
||||
)),
|
||||
arguments: convert_arguments(cx, &base.args),
|
||||
is_optional: expr.optional,
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
}),
|
||||
),
|
||||
OptChainBase::Member(base) => {
|
||||
let mut member = convert_optional_member_expression(cx, base);
|
||||
member.is_optional = expr.optional;
|
||||
forget_estree::Expression::OptionalMemberExpression(Box::new(member))
|
||||
}
|
||||
},
|
||||
Expr::JSXElement(expr) => {
|
||||
forget_estree::Expression::JSXElement(Box::new(convert_jsx_element(cx, expr)))
|
||||
}
|
||||
Expr::Paren(expr) => convert_expression(cx, &expr.expr),
|
||||
Expr::Update(expr) => {
|
||||
forget_estree::Expression::UpdateExpression(Box::new(forget_estree::UpdateExpression {
|
||||
operator: convert_update_operator(expr.op),
|
||||
argument: convert_expression(cx, &expr.arg),
|
||||
prefix: expr.prefix,
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
}))
|
||||
}
|
||||
_ => todo!("translate expression {:#?}", expr),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_jsx_element(cx: &Context, expr: &JSXElement) -> forget_estree::JSXElement {
|
||||
let attributes = expr
|
||||
.opening
|
||||
.attrs
|
||||
.iter()
|
||||
.map(|attr| match attr {
|
||||
JSXAttrOrSpread::JSXAttr(attr) => forget_estree::JSXAttributeOrSpread::JSXAttribute(
|
||||
Box::new(convert_jsx_attribute(cx, attr)),
|
||||
),
|
||||
JSXAttrOrSpread::SpreadElement(attr) => {
|
||||
forget_estree::JSXAttributeOrSpread::JSXSpreadAttribute(Box::new(
|
||||
forget_estree::JSXSpreadAttribute {
|
||||
argument: convert_expression(cx, &attr.expr),
|
||||
loc: None,
|
||||
range: None, // sigh, no span
|
||||
},
|
||||
))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let opening_element = forget_estree::JSXOpeningElement {
|
||||
attributes,
|
||||
name: convert_jsx_name(cx, &expr.opening.name),
|
||||
self_closing: expr.opening.self_closing,
|
||||
loc: None,
|
||||
range: convert_span(&expr.opening.span),
|
||||
};
|
||||
let children = expr
|
||||
.children
|
||||
.iter()
|
||||
.map(|child| convert_jsx_child(cx, child))
|
||||
.collect();
|
||||
let closing_element = expr
|
||||
.closing
|
||||
.as_ref()
|
||||
.map(|closing| forget_estree::JSXClosingElement {
|
||||
name: convert_jsx_name(cx, &closing.name),
|
||||
loc: None,
|
||||
range: convert_span(&closing.span),
|
||||
});
|
||||
forget_estree::JSXElement {
|
||||
opening_element,
|
||||
children,
|
||||
closing_element,
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_jsx_name(cx: &Context, name: &JSXElementName) -> forget_estree::JSXElementName {
|
||||
match name {
|
||||
JSXElementName::Ident(name) => {
|
||||
forget_estree::JSXElementName::JSXIdentifier(Box::new(convert_jsx_identifier(cx, name)))
|
||||
}
|
||||
JSXElementName::JSXMemberExpr(name) => forget_estree::JSXElementName::JSXMemberExpression(
|
||||
Box::new(convert_jsx_member_expression(cx, name)),
|
||||
),
|
||||
JSXElementName::JSXNamespacedName(name) => {
|
||||
forget_estree::JSXElementName::JSXNamespacedName(Box::new(
|
||||
forget_estree::JSXNamespacedName {
|
||||
namespace: convert_jsx_identifier(cx, &name.ns),
|
||||
name: convert_jsx_identifier(cx, &name.name),
|
||||
loc: None,
|
||||
range: None, // sigh, swc doesn't have a span for the entire name
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_jsx_member_expression(
|
||||
cx: &Context,
|
||||
expr: &JSXMemberExpr,
|
||||
) -> forget_estree::JSXMemberExpression {
|
||||
forget_estree::JSXMemberExpression {
|
||||
object: match &expr.obj {
|
||||
JSXObject::JSXMemberExpr(obj) => {
|
||||
forget_estree::JSXMemberExpressionOrIdentifier::JSXMemberExpression(Box::new(
|
||||
convert_jsx_member_expression(cx, obj),
|
||||
))
|
||||
}
|
||||
JSXObject::Ident(obj) => forget_estree::JSXMemberExpressionOrIdentifier::JSXIdentifier(
|
||||
Box::new(convert_jsx_identifier(cx, obj)),
|
||||
),
|
||||
},
|
||||
property: convert_jsx_identifier(cx, &expr.prop),
|
||||
loc: None,
|
||||
range: None, // sigh, swc doesn't have a span for the member expr
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_jsx_child(cx: &Context, child: &JSXElementChild) -> forget_estree::JSXChildItem {
|
||||
match child {
|
||||
JSXElementChild::JSXText(child) => {
|
||||
forget_estree::JSXChildItem::JSXText(Box::new(forget_estree::JSXText {
|
||||
value: child.value.to_string(),
|
||||
raw: child.raw.to_string(),
|
||||
loc: None,
|
||||
range: convert_span(&child.span),
|
||||
}))
|
||||
}
|
||||
JSXElementChild::JSXElement(child) => {
|
||||
forget_estree::JSXChildItem::JSXElement(Box::new(convert_jsx_element(cx, child)))
|
||||
}
|
||||
JSXElementChild::JSXExprContainer(child) => {
|
||||
forget_estree::JSXChildItem::JSXExpressionContainer(Box::new(
|
||||
forget_estree::JSXExpressionContainer {
|
||||
expression: match &child.expr {
|
||||
JSXExpr::Expr(expr) => forget_estree::JSXExpressionOrEmpty::Expression(
|
||||
convert_expression(cx, expr),
|
||||
),
|
||||
JSXExpr::JSXEmptyExpr(expr) => {
|
||||
forget_estree::JSXExpressionOrEmpty::JSXEmptyExpression(Box::new(
|
||||
forget_estree::JSXEmptyExpression {
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
},
|
||||
))
|
||||
}
|
||||
},
|
||||
loc: None,
|
||||
range: convert_span(&child.span),
|
||||
},
|
||||
))
|
||||
}
|
||||
_ => todo!("handle other jsx child types"),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_jsx_attribute(cx: &Context, attr: &JSXAttr) -> forget_estree::JSXAttribute {
|
||||
let name = match &attr.name {
|
||||
JSXAttrName::Ident(name) => {
|
||||
forget_estree::JSXIdentifierOrNamespacedName::JSXIdentifier(Box::new({
|
||||
let ident = convert_identifier(cx, name);
|
||||
forget_estree::JSXIdentifier {
|
||||
name: ident.name,
|
||||
binding: ident.binding,
|
||||
loc: ident.loc,
|
||||
range: ident.range,
|
||||
}
|
||||
}))
|
||||
}
|
||||
JSXAttrName::JSXNamespacedName(name) => {
|
||||
forget_estree::JSXIdentifierOrNamespacedName::JSXNamespacedName(Box::new(
|
||||
forget_estree::JSXNamespacedName {
|
||||
namespace: convert_jsx_identifier(cx, &name.ns),
|
||||
name: convert_jsx_identifier(cx, &name.name),
|
||||
loc: None,
|
||||
range: None, // sigh, swc doesn't have a span for the entire name
|
||||
},
|
||||
))
|
||||
}
|
||||
};
|
||||
let value = attr.value.as_ref().map(|attr| match attr {
|
||||
JSXAttrValue::Lit(value) => {
|
||||
forget_estree::JSXAttributeValue::Literal(Box::new(convert_literal(cx, value)))
|
||||
}
|
||||
JSXAttrValue::JSXElement(value) => {
|
||||
forget_estree::JSXAttributeValue::JSXElement(Box::new(convert_jsx_element(cx, value)))
|
||||
}
|
||||
JSXAttrValue::JSXExprContainer(value) => {
|
||||
forget_estree::JSXAttributeValue::JSXExpressionContainer(Box::new(
|
||||
forget_estree::JSXExpressionContainer {
|
||||
expression: match &value.expr {
|
||||
JSXExpr::Expr(expr) => forget_estree::JSXExpressionOrEmpty::Expression(
|
||||
convert_expression(cx, expr),
|
||||
),
|
||||
JSXExpr::JSXEmptyExpr(expr) => {
|
||||
forget_estree::JSXExpressionOrEmpty::JSXEmptyExpression(Box::new(
|
||||
forget_estree::JSXEmptyExpression {
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
},
|
||||
))
|
||||
}
|
||||
},
|
||||
loc: None,
|
||||
range: convert_span(&value.span),
|
||||
},
|
||||
))
|
||||
}
|
||||
_ => todo!("handle other attribute value types"),
|
||||
});
|
||||
forget_estree::JSXAttribute {
|
||||
name,
|
||||
value,
|
||||
loc: None,
|
||||
range: convert_span(&attr.span),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_literal(_cx: &Context, expr: &Lit) -> forget_estree::Literal {
|
||||
let (value, range, regex, bigint) = match expr {
|
||||
Lit::Bool(expr) => (
|
||||
forget_estree::JsValue::Boolean(expr.value),
|
||||
convert_span(&expr.span),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
Lit::Num(expr) => (
|
||||
forget_estree::JsValue::Number(expr.value.into()),
|
||||
convert_span(&expr.span),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
Lit::Str(expr) => (
|
||||
forget_estree::JsValue::String(expr.value.to_string()),
|
||||
convert_span(&expr.span),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
Lit::Null(expr) => (
|
||||
forget_estree::JsValue::Null,
|
||||
convert_span(&expr.span),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
Lit::Regex(expr) => (
|
||||
forget_estree::JsValue::Undefined,
|
||||
convert_span(&expr.span),
|
||||
Some(forget_estree::RegExpValue {
|
||||
pattern: expr.exp.to_string(),
|
||||
flags: expr.flags.to_string(),
|
||||
}),
|
||||
None,
|
||||
),
|
||||
Lit::BigInt(expr) => (
|
||||
forget_estree::JsValue::Undefined,
|
||||
convert_span(&expr.span),
|
||||
None,
|
||||
Some(
|
||||
expr.raw
|
||||
.as_ref()
|
||||
.expect("Expected bigint to have a raw value")
|
||||
.to_string(),
|
||||
),
|
||||
),
|
||||
Lit::JSXText(_) => {
|
||||
panic!("Unexpected expression: JSXText is not an expression")
|
||||
}
|
||||
};
|
||||
forget_estree::Literal {
|
||||
value,
|
||||
raw: None,
|
||||
loc: None,
|
||||
regex,
|
||||
range,
|
||||
bigint,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_arguments(
|
||||
cx: &Context,
|
||||
arguments: &[ExprOrSpread],
|
||||
) -> Vec<forget_estree::ExpressionOrSpread> {
|
||||
arguments
|
||||
.iter()
|
||||
.map(|arg| match arg {
|
||||
ExprOrSpread {
|
||||
spread: Some(spread),
|
||||
expr,
|
||||
} => forget_estree::ExpressionOrSpread::SpreadElement(Box::new(
|
||||
forget_estree::SpreadElement {
|
||||
argument: convert_expression(cx, expr),
|
||||
loc: None,
|
||||
range: convert_span(&spread),
|
||||
},
|
||||
)),
|
||||
ExprOrSpread { spread: None, expr } => {
|
||||
forget_estree::ExpressionOrSpread::Expression(convert_expression(cx, expr))
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn convert_assignment_target(cx: &Context, target: &PatOrExpr) -> forget_estree::AssignmentTarget {
|
||||
match target {
|
||||
PatOrExpr::Pat(target) => {
|
||||
forget_estree::AssignmentTarget::Pattern(convert_pattern(cx, target))
|
||||
}
|
||||
PatOrExpr::Expr(target) => match target.as_ref() {
|
||||
Expr::Member(target) => forget_estree::AssignmentTarget::Expression(
|
||||
forget_estree::Expression::MemberExpression(Box::new(convert_member_expression(
|
||||
cx, target,
|
||||
))),
|
||||
),
|
||||
Expr::Ident(target) => forget_estree::AssignmentTarget::Pattern(
|
||||
forget_estree::Pattern::Identifier(Box::new(convert_identifier(cx, target))),
|
||||
),
|
||||
_ => {
|
||||
panic!(
|
||||
"Expected assignment target to be member expression or identifier, got {:#?}",
|
||||
target
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_member_expression(cx: &Context, expr: &MemberExpr) -> forget_estree::MemberExpression {
|
||||
let (is_computed, property) = match &expr.prop {
|
||||
MemberProp::Ident(prop) => (
|
||||
false,
|
||||
forget_estree::ExpressionOrPrivateIdentifier::Expression(
|
||||
forget_estree::Expression::Identifier(Box::new(convert_identifier(cx, prop))),
|
||||
),
|
||||
),
|
||||
MemberProp::Computed(prop) => (
|
||||
true,
|
||||
forget_estree::ExpressionOrPrivateIdentifier::Expression(convert_expression(
|
||||
cx, &prop.expr,
|
||||
)),
|
||||
),
|
||||
MemberProp::PrivateName(prop) => {
|
||||
let name = prop.id.sym.as_ref().to_string();
|
||||
(
|
||||
false,
|
||||
forget_estree::ExpressionOrPrivateIdentifier::PrivateIdentifier(Box::new(
|
||||
forget_estree::PrivateIdentifier {
|
||||
name,
|
||||
loc: None,
|
||||
range: convert_span(&prop.span),
|
||||
},
|
||||
)),
|
||||
)
|
||||
}
|
||||
};
|
||||
forget_estree::MemberExpression {
|
||||
object: forget_estree::ExpressionOrSuper::Expression(convert_expression(cx, &expr.obj)),
|
||||
property,
|
||||
is_computed,
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_optional_member_expression(
|
||||
cx: &Context,
|
||||
expr: &MemberExpr,
|
||||
) -> forget_estree::OptionalMemberExpression {
|
||||
let (is_computed, property) = match &expr.prop {
|
||||
MemberProp::Ident(prop) => (
|
||||
false,
|
||||
forget_estree::Expression::Identifier(Box::new(convert_identifier(cx, prop))),
|
||||
),
|
||||
MemberProp::Computed(prop) => (true, convert_expression(cx, &prop.expr)),
|
||||
_ => {
|
||||
panic!("PrivateName member expression properties are not supported")
|
||||
}
|
||||
};
|
||||
forget_estree::OptionalMemberExpression {
|
||||
object: convert_expression(cx, &expr.obj),
|
||||
property,
|
||||
is_computed,
|
||||
is_optional: false,
|
||||
loc: None,
|
||||
range: convert_span(&expr.span),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_unary_operator(op: UnaryOp) -> forget_estree::UnaryOperator {
|
||||
match op {
|
||||
UnaryOp::Bang => forget_estree::UnaryOperator::Negation,
|
||||
UnaryOp::Delete => forget_estree::UnaryOperator::Delete,
|
||||
UnaryOp::Minus => forget_estree::UnaryOperator::Minus,
|
||||
UnaryOp::Plus => forget_estree::UnaryOperator::Plus,
|
||||
UnaryOp::Tilde => forget_estree::UnaryOperator::Tilde,
|
||||
UnaryOp::TypeOf => forget_estree::UnaryOperator::Typeof,
|
||||
UnaryOp::Void => forget_estree::UnaryOperator::Void,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_assignment_operator(op: AssignOp) -> forget_estree::AssignmentOperator {
|
||||
match op {
|
||||
AssignOp::Assign => forget_estree::AssignmentOperator::Equals,
|
||||
AssignOp::AddAssign => forget_estree::AssignmentOperator::PlusEquals,
|
||||
_ => todo!("translate assignment operator"),
|
||||
}
|
||||
}
|
||||
|
||||
enum Operator {
|
||||
Binary(forget_estree::BinaryOperator),
|
||||
Logical(forget_estree::LogicalOperator),
|
||||
}
|
||||
|
||||
fn convert_binary_operator(op: BinaryOp) -> Operator {
|
||||
match op {
|
||||
BinaryOp::Add => Operator::Binary(forget_estree::BinaryOperator::Add),
|
||||
BinaryOp::BitAnd => Operator::Binary(forget_estree::BinaryOperator::BinaryAnd),
|
||||
BinaryOp::BitOr => Operator::Binary(forget_estree::BinaryOperator::BinaryOr),
|
||||
BinaryOp::BitXor => Operator::Binary(forget_estree::BinaryOperator::BinaryXor),
|
||||
BinaryOp::Div => Operator::Binary(forget_estree::BinaryOperator::Divide),
|
||||
BinaryOp::EqEq => Operator::Binary(forget_estree::BinaryOperator::Equals),
|
||||
BinaryOp::EqEqEq => Operator::Binary(forget_estree::BinaryOperator::StrictEquals),
|
||||
BinaryOp::Exp => Operator::Binary(forget_estree::BinaryOperator::Exponent),
|
||||
BinaryOp::Gt => Operator::Binary(forget_estree::BinaryOperator::GreaterThan),
|
||||
BinaryOp::GtEq => Operator::Binary(forget_estree::BinaryOperator::GreaterThanOrEqual),
|
||||
BinaryOp::In => Operator::Binary(forget_estree::BinaryOperator::In),
|
||||
BinaryOp::InstanceOf => Operator::Binary(forget_estree::BinaryOperator::Instanceof),
|
||||
BinaryOp::LShift => Operator::Binary(forget_estree::BinaryOperator::ShiftLeft),
|
||||
BinaryOp::Lt => Operator::Binary(forget_estree::BinaryOperator::LessThan),
|
||||
BinaryOp::LtEq => Operator::Binary(forget_estree::BinaryOperator::LessThanOrEqual),
|
||||
BinaryOp::Mod => Operator::Binary(forget_estree::BinaryOperator::Modulo),
|
||||
BinaryOp::Mul => Operator::Binary(forget_estree::BinaryOperator::Multiply),
|
||||
BinaryOp::NotEq => Operator::Binary(forget_estree::BinaryOperator::NotEquals),
|
||||
BinaryOp::NotEqEq => Operator::Binary(forget_estree::BinaryOperator::NotStrictEquals),
|
||||
BinaryOp::RShift => Operator::Binary(forget_estree::BinaryOperator::ShiftRight),
|
||||
BinaryOp::Sub => Operator::Binary(forget_estree::BinaryOperator::Subtract),
|
||||
BinaryOp::ZeroFillRShift => {
|
||||
Operator::Binary(forget_estree::BinaryOperator::UnsignedShiftRight)
|
||||
}
|
||||
|
||||
BinaryOp::LogicalAnd => Operator::Logical(forget_estree::LogicalOperator::And),
|
||||
BinaryOp::LogicalOr => Operator::Logical(forget_estree::LogicalOperator::Or),
|
||||
BinaryOp::NullishCoalescing => {
|
||||
Operator::Logical(forget_estree::LogicalOperator::NullCoalescing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_update_operator(op: UpdateOp) -> forget_estree::UpdateOperator {
|
||||
match op {
|
||||
UpdateOp::MinusMinus => forget_estree::UpdateOperator::Decrement,
|
||||
UpdateOp::PlusPlus => forget_estree::UpdateOperator::Increment,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_pattern(cx: &Context, pat: &Pat) -> forget_estree::Pattern {
|
||||
match pat {
|
||||
Pat::Ident(pat) => {
|
||||
forget_estree::Pattern::Identifier(Box::new(forget_estree::Identifier {
|
||||
name: pat.id.sym.to_string(),
|
||||
binding: convert_binding(cx, pat.id.span.ctxt),
|
||||
type_annotation: None,
|
||||
loc: None,
|
||||
range: convert_span(&pat.span),
|
||||
}))
|
||||
}
|
||||
_ => todo!("translate pattern {:#?}", pat),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_binding(context: &Context, binding_cx: SyntaxContext) -> Option<Binding> {
|
||||
let id = BindingId::new(binding_cx.as_u32());
|
||||
if binding_cx.as_u32() == context.top_level_mark.as_u32() {
|
||||
Some(Binding::Global)
|
||||
} else if binding_cx.as_u32() == context.unresolved_mark.as_u32() {
|
||||
Some(Binding::Module(id))
|
||||
} else {
|
||||
Some(Binding::Local(id))
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_identifier(cx: &Context, identifier: &Ident) -> forget_estree::Identifier {
|
||||
let name = identifier.sym.as_ref().to_string();
|
||||
forget_estree::Identifier {
|
||||
name,
|
||||
binding: convert_binding(cx, identifier.span.ctxt),
|
||||
type_annotation: None,
|
||||
loc: None,
|
||||
range: convert_span(&identifier.span),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_jsx_identifier(cx: &Context, identifier: &Ident) -> forget_estree::JSXIdentifier {
|
||||
let name = identifier.sym.as_ref().to_string();
|
||||
forget_estree::JSXIdentifier {
|
||||
name,
|
||||
binding: convert_binding(cx, identifier.span.ctxt),
|
||||
loc: None,
|
||||
range: convert_span(&identifier.span),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {}
|
||||
}
|
||||
@@ -1,3 +1,2 @@
|
||||
[toolchain]
|
||||
# Sigh, because SWC
|
||||
channel = "nightly"
|
||||
channel = "stable"
|
||||
Reference in New Issue
Block a user