mirror of
https://github.com/denoland/deno.git
synced 2025-01-20 04:36:16 -05:00
3fb8fc1ba7
This PR changes the underlying buffer backed AST format we use for JavaScript-based linting plugins. It adds support for various new types, makes traversal code a lot easier and is more polished compared to previous iterations. Here is a quick summary (in no particular order): - Node prop data is separate from traversal, which makes traversal code so much easier to reason about. Previously, it was interleaved with node prop data - spans are in a separate table as well, as they are rarely needed. - schema is separate from SWC conversion logic, which makes - supports recursive plain objects - supports numbers - supports bigint - supports regex - adds all SWC nodes Apologies, this is kinda a big PR, but it's worth it imo. _Marking as draft because I need to update some tests tomorrow._
2614 lines
74 KiB
Rust
2614 lines
74 KiB
Rust
// Copyright 2018-2025 the Deno authors. MIT license.
|
|
|
|
use deno_ast::swc::ast::AssignTarget;
|
|
use deno_ast::swc::ast::AssignTargetPat;
|
|
use deno_ast::swc::ast::BindingIdent;
|
|
use deno_ast::swc::ast::BlockStmtOrExpr;
|
|
use deno_ast::swc::ast::Callee;
|
|
use deno_ast::swc::ast::ClassMember;
|
|
use deno_ast::swc::ast::Decl;
|
|
use deno_ast::swc::ast::Decorator;
|
|
use deno_ast::swc::ast::DefaultDecl;
|
|
use deno_ast::swc::ast::ExportSpecifier;
|
|
use deno_ast::swc::ast::Expr;
|
|
use deno_ast::swc::ast::ExprOrSpread;
|
|
use deno_ast::swc::ast::FnExpr;
|
|
use deno_ast::swc::ast::ForHead;
|
|
use deno_ast::swc::ast::Function;
|
|
use deno_ast::swc::ast::Ident;
|
|
use deno_ast::swc::ast::IdentName;
|
|
use deno_ast::swc::ast::ImportSpecifier;
|
|
use deno_ast::swc::ast::JSXAttrName;
|
|
use deno_ast::swc::ast::JSXAttrOrSpread;
|
|
use deno_ast::swc::ast::JSXAttrValue;
|
|
use deno_ast::swc::ast::JSXElement;
|
|
use deno_ast::swc::ast::JSXElementChild;
|
|
use deno_ast::swc::ast::JSXElementName;
|
|
use deno_ast::swc::ast::JSXExpr;
|
|
use deno_ast::swc::ast::JSXExprContainer;
|
|
use deno_ast::swc::ast::JSXFragment;
|
|
use deno_ast::swc::ast::JSXMemberExpr;
|
|
use deno_ast::swc::ast::JSXNamespacedName;
|
|
use deno_ast::swc::ast::JSXObject;
|
|
use deno_ast::swc::ast::JSXOpeningElement;
|
|
use deno_ast::swc::ast::Key;
|
|
use deno_ast::swc::ast::Lit;
|
|
use deno_ast::swc::ast::MemberExpr;
|
|
use deno_ast::swc::ast::MemberProp;
|
|
use deno_ast::swc::ast::ModuleDecl;
|
|
use deno_ast::swc::ast::ModuleExportName;
|
|
use deno_ast::swc::ast::ModuleItem;
|
|
use deno_ast::swc::ast::ObjectLit;
|
|
use deno_ast::swc::ast::ObjectPatProp;
|
|
use deno_ast::swc::ast::OptChainBase;
|
|
use deno_ast::swc::ast::Param;
|
|
use deno_ast::swc::ast::ParamOrTsParamProp;
|
|
use deno_ast::swc::ast::Pat;
|
|
use deno_ast::swc::ast::PrivateName;
|
|
use deno_ast::swc::ast::Program;
|
|
use deno_ast::swc::ast::Prop;
|
|
use deno_ast::swc::ast::PropName;
|
|
use deno_ast::swc::ast::PropOrSpread;
|
|
use deno_ast::swc::ast::SimpleAssignTarget;
|
|
use deno_ast::swc::ast::Stmt;
|
|
use deno_ast::swc::ast::SuperProp;
|
|
use deno_ast::swc::ast::TsEntityName;
|
|
use deno_ast::swc::ast::TsEnumMemberId;
|
|
use deno_ast::swc::ast::TsExprWithTypeArgs;
|
|
use deno_ast::swc::ast::TsFnOrConstructorType;
|
|
use deno_ast::swc::ast::TsFnParam;
|
|
use deno_ast::swc::ast::TsIndexSignature;
|
|
use deno_ast::swc::ast::TsLit;
|
|
use deno_ast::swc::ast::TsLitType;
|
|
use deno_ast::swc::ast::TsModuleName;
|
|
use deno_ast::swc::ast::TsModuleRef;
|
|
use deno_ast::swc::ast::TsNamespaceBody;
|
|
use deno_ast::swc::ast::TsParamPropParam;
|
|
use deno_ast::swc::ast::TsThisTypeOrIdent;
|
|
use deno_ast::swc::ast::TsType;
|
|
use deno_ast::swc::ast::TsTypeAnn;
|
|
use deno_ast::swc::ast::TsTypeElement;
|
|
use deno_ast::swc::ast::TsTypeParam;
|
|
use deno_ast::swc::ast::TsTypeParamDecl;
|
|
use deno_ast::swc::ast::TsTypeParamInstantiation;
|
|
use deno_ast::swc::ast::TsTypeQueryExpr;
|
|
use deno_ast::swc::ast::TsUnionOrIntersectionType;
|
|
use deno_ast::swc::ast::VarDeclOrExpr;
|
|
use deno_ast::swc::common::Span;
|
|
use deno_ast::swc::common::Spanned;
|
|
use deno_ast::swc::common::SyntaxContext;
|
|
use deno_ast::view::Accessibility;
|
|
use deno_ast::view::AssignOp;
|
|
use deno_ast::view::BinaryOp;
|
|
use deno_ast::view::MethodKind;
|
|
use deno_ast::view::TsKeywordTypeKind;
|
|
use deno_ast::view::TsTypeOperatorOp;
|
|
use deno_ast::view::UnaryOp;
|
|
use deno_ast::view::UpdateOp;
|
|
use deno_ast::view::VarDeclKind;
|
|
use deno_ast::ParsedSource;
|
|
|
|
use super::buffer::AstBufSerializer;
|
|
use super::buffer::NodeRef;
|
|
use super::ts_estree::AstNode;
|
|
use super::ts_estree::TsEsTreeBuilder;
|
|
use super::ts_estree::TsKeywordKind;
|
|
|
|
pub fn serialize_swc_to_buffer(parsed_source: &ParsedSource) -> Vec<u8> {
|
|
let mut ctx = TsEsTreeBuilder::new();
|
|
|
|
let program = &parsed_source.program();
|
|
|
|
match program.as_ref() {
|
|
Program::Module(module) => {
|
|
let children = module
|
|
.body
|
|
.iter()
|
|
.map(|item| match item {
|
|
ModuleItem::ModuleDecl(module_decl) => {
|
|
serialize_module_decl(&mut ctx, module_decl)
|
|
}
|
|
ModuleItem::Stmt(stmt) => serialize_stmt(&mut ctx, stmt),
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_program(&module.span, "module", children);
|
|
}
|
|
Program::Script(script) => {
|
|
let children = script
|
|
.body
|
|
.iter()
|
|
.map(|stmt| serialize_stmt(&mut ctx, stmt))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_program(&script.span, "script", children);
|
|
}
|
|
}
|
|
|
|
ctx.serialize()
|
|
}
|
|
|
|
fn serialize_module_decl(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
module_decl: &ModuleDecl,
|
|
) -> NodeRef {
|
|
match module_decl {
|
|
ModuleDecl::Import(node) => {
|
|
let src = serialize_lit(ctx, &Lit::Str(node.src.as_ref().clone()));
|
|
let attrs = serialize_import_attrs(ctx, &node.with);
|
|
|
|
let specifiers = node
|
|
.specifiers
|
|
.iter()
|
|
.map(|spec| match spec {
|
|
ImportSpecifier::Named(spec) => {
|
|
let local = serialize_ident(ctx, &spec.local, None);
|
|
let imported = spec
|
|
.imported
|
|
.as_ref()
|
|
.map_or(serialize_ident(ctx, &spec.local, None), |v| {
|
|
serialize_module_export_name(ctx, v)
|
|
});
|
|
ctx.write_import_spec(
|
|
&spec.span,
|
|
spec.is_type_only,
|
|
local,
|
|
imported,
|
|
)
|
|
}
|
|
ImportSpecifier::Default(spec) => {
|
|
let local = serialize_ident(ctx, &spec.local, None);
|
|
ctx.write_import_default_spec(&spec.span, local)
|
|
}
|
|
ImportSpecifier::Namespace(spec) => {
|
|
let local = serialize_ident(ctx, &spec.local, None);
|
|
ctx.write_import_ns_spec(&spec.span, local)
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_import_decl(&node.span, node.type_only, src, specifiers, attrs)
|
|
}
|
|
ModuleDecl::ExportDecl(node) => {
|
|
let decl = serialize_decl(ctx, &node.decl);
|
|
ctx.write_export_decl(&node.span, decl)
|
|
}
|
|
ModuleDecl::ExportNamed(node) => {
|
|
let attrs = serialize_import_attrs(ctx, &node.with);
|
|
let source = node
|
|
.src
|
|
.as_ref()
|
|
.map(|src| serialize_lit(ctx, &Lit::Str(*src.clone())));
|
|
|
|
if let Some(ExportSpecifier::Namespace(ns)) = node.specifiers.first() {
|
|
let exported = serialize_module_export_name(ctx, &ns.name);
|
|
ctx.write_export_all_decl(
|
|
&node.span,
|
|
node.type_only,
|
|
exported,
|
|
source,
|
|
attrs,
|
|
)
|
|
} else {
|
|
let specifiers = node
|
|
.specifiers
|
|
.iter()
|
|
.map(|spec| {
|
|
match spec {
|
|
ExportSpecifier::Named(spec) => {
|
|
let local = serialize_module_export_name(ctx, &spec.orig);
|
|
|
|
let exported = spec.exported.as_ref().map_or(
|
|
serialize_module_export_name(ctx, &spec.orig),
|
|
|exported| serialize_module_export_name(ctx, exported),
|
|
);
|
|
|
|
ctx.write_export_spec(
|
|
&spec.span,
|
|
spec.is_type_only,
|
|
local,
|
|
exported,
|
|
)
|
|
}
|
|
|
|
// Already handled earlier
|
|
ExportSpecifier::Namespace(_) => unreachable!(),
|
|
// this is not syntactically valid
|
|
ExportSpecifier::Default(_) => unreachable!(),
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_export_named_decl(&node.span, specifiers, source, attrs)
|
|
}
|
|
}
|
|
ModuleDecl::ExportDefaultDecl(node) => {
|
|
let (is_type_only, decl) = match &node.decl {
|
|
DefaultDecl::Class(node) => {
|
|
let ident = node
|
|
.ident
|
|
.as_ref()
|
|
.map(|ident| serialize_ident(ctx, ident, None));
|
|
|
|
let super_class = node
|
|
.class
|
|
.super_class
|
|
.as_ref()
|
|
.map(|expr| serialize_expr(ctx, expr.as_ref()));
|
|
|
|
let implements = node
|
|
.class
|
|
.implements
|
|
.iter()
|
|
.map(|item| serialize_ts_expr_with_type_args(ctx, item))
|
|
.collect::<Vec<_>>();
|
|
|
|
let members = node
|
|
.class
|
|
.body
|
|
.iter()
|
|
.filter_map(|member| serialize_class_member(ctx, member))
|
|
.collect::<Vec<_>>();
|
|
|
|
let body = ctx.write_class_body(&node.class.span, members);
|
|
|
|
let decl = ctx.write_class_decl(
|
|
&node.class.span,
|
|
false,
|
|
node.class.is_abstract,
|
|
ident,
|
|
super_class,
|
|
implements,
|
|
body,
|
|
);
|
|
|
|
(false, decl)
|
|
}
|
|
DefaultDecl::Fn(node) => {
|
|
let ident = node
|
|
.ident
|
|
.as_ref()
|
|
.map(|ident| serialize_ident(ctx, ident, None));
|
|
|
|
let fn_obj = node.function.as_ref();
|
|
|
|
let type_params =
|
|
maybe_serialize_ts_type_param_decl(ctx, &fn_obj.type_params);
|
|
|
|
let params = fn_obj
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_pat(ctx, ¶m.pat))
|
|
.collect::<Vec<_>>();
|
|
|
|
let return_type =
|
|
maybe_serialize_ts_type_ann(ctx, &fn_obj.return_type);
|
|
let body = fn_obj
|
|
.body
|
|
.as_ref()
|
|
.map(|block| serialize_stmt(ctx, &Stmt::Block(block.clone())));
|
|
|
|
let decl = ctx.write_fn_decl(
|
|
&fn_obj.span,
|
|
false,
|
|
fn_obj.is_async,
|
|
fn_obj.is_generator,
|
|
ident,
|
|
type_params,
|
|
return_type,
|
|
body,
|
|
params,
|
|
);
|
|
|
|
(false, decl)
|
|
}
|
|
DefaultDecl::TsInterfaceDecl(node) => {
|
|
let ident_id = serialize_ident(ctx, &node.id, None);
|
|
let type_param =
|
|
maybe_serialize_ts_type_param_decl(ctx, &node.type_params);
|
|
|
|
let extend_ids = node
|
|
.extends
|
|
.iter()
|
|
.map(|item| {
|
|
let expr = serialize_expr(ctx, &item.expr);
|
|
let type_args = item
|
|
.type_args
|
|
.clone()
|
|
.map(|params| serialize_ts_param_inst(ctx, params.as_ref()));
|
|
|
|
ctx.write_ts_interface_heritage(&item.span, expr, type_args)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let body_elem_ids = node
|
|
.body
|
|
.body
|
|
.iter()
|
|
.map(|item| serialize_ts_type_elem(ctx, item))
|
|
.collect::<Vec<_>>();
|
|
|
|
let body_pos =
|
|
ctx.write_ts_interface_body(&node.body.span, body_elem_ids);
|
|
|
|
let decl = ctx.write_ts_interface_decl(
|
|
&node.span,
|
|
node.declare,
|
|
ident_id,
|
|
type_param,
|
|
extend_ids,
|
|
body_pos,
|
|
);
|
|
|
|
(true, decl)
|
|
}
|
|
};
|
|
|
|
ctx.write_export_default_decl(&node.span, is_type_only, decl)
|
|
}
|
|
ModuleDecl::ExportDefaultExpr(node) => {
|
|
let expr = serialize_expr(ctx, &node.expr);
|
|
ctx.write_export_default_decl(&node.span, false, expr)
|
|
}
|
|
ModuleDecl::ExportAll(node) => {
|
|
let src = serialize_lit(ctx, &Lit::Str(node.src.as_ref().clone()));
|
|
let attrs = serialize_import_attrs(ctx, &node.with);
|
|
|
|
ctx.write_export_all_decl(&node.span, node.type_only, src, None, attrs)
|
|
}
|
|
ModuleDecl::TsImportEquals(node) => {
|
|
let ident = serialize_ident(ctx, &node.id, None);
|
|
let module_ref = match &node.module_ref {
|
|
TsModuleRef::TsEntityName(entity) => {
|
|
serialize_ts_entity_name(ctx, entity)
|
|
}
|
|
TsModuleRef::TsExternalModuleRef(external) => {
|
|
let expr = serialize_lit(ctx, &Lit::Str(external.expr.clone()));
|
|
ctx.write_ts_external_mod_ref(&external.span, expr)
|
|
}
|
|
};
|
|
|
|
ctx.write_export_ts_import_equals(
|
|
&node.span,
|
|
node.is_type_only,
|
|
ident,
|
|
module_ref,
|
|
)
|
|
}
|
|
ModuleDecl::TsExportAssignment(node) => {
|
|
let expr = serialize_expr(ctx, &node.expr);
|
|
ctx.write_export_assign(&node.span, expr)
|
|
}
|
|
ModuleDecl::TsNamespaceExport(node) => {
|
|
let decl = serialize_ident(ctx, &node.id, None);
|
|
ctx.write_export_ts_namespace(&node.span, decl)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serialize_import_attrs(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
raw_attrs: &Option<Box<ObjectLit>>,
|
|
) -> Vec<NodeRef> {
|
|
raw_attrs.as_ref().map_or(vec![], |obj| {
|
|
obj
|
|
.props
|
|
.iter()
|
|
.map(|prop| {
|
|
let (key, value) = match prop {
|
|
// Invalid syntax
|
|
PropOrSpread::Spread(_) => unreachable!(),
|
|
PropOrSpread::Prop(prop) => {
|
|
match prop.as_ref() {
|
|
Prop::Shorthand(ident) => (
|
|
serialize_ident(ctx, ident, None),
|
|
serialize_ident(ctx, ident, None),
|
|
),
|
|
Prop::KeyValue(kv) => (
|
|
serialize_prop_name(ctx, &kv.key),
|
|
serialize_expr(ctx, kv.value.as_ref()),
|
|
),
|
|
// Invalid syntax
|
|
Prop::Assign(_)
|
|
| Prop::Getter(_)
|
|
| Prop::Setter(_)
|
|
| Prop::Method(_) => unreachable!(),
|
|
}
|
|
}
|
|
};
|
|
|
|
ctx.write_import_attr(&prop.span(), key, value)
|
|
})
|
|
.collect::<Vec<_>>()
|
|
})
|
|
}
|
|
|
|
fn serialize_stmt(ctx: &mut TsEsTreeBuilder, stmt: &Stmt) -> NodeRef {
|
|
match stmt {
|
|
Stmt::Block(node) => {
|
|
let children = node
|
|
.stmts
|
|
.iter()
|
|
.map(|stmt| serialize_stmt(ctx, stmt))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_block_stmt(&node.span, children)
|
|
}
|
|
Stmt::Empty(_) => NodeRef(0),
|
|
Stmt::Debugger(node) => ctx.write_debugger_stmt(&node.span),
|
|
Stmt::With(node) => {
|
|
let obj = serialize_expr(ctx, &node.obj);
|
|
let body = serialize_stmt(ctx, &node.body);
|
|
|
|
ctx.write_with_stmt(&node.span, obj, body)
|
|
}
|
|
Stmt::Return(node) => {
|
|
let arg = node.arg.as_ref().map(|arg| serialize_expr(ctx, arg));
|
|
ctx.write_return_stmt(&node.span, arg)
|
|
}
|
|
Stmt::Labeled(node) => {
|
|
let ident = serialize_ident(ctx, &node.label, None);
|
|
let stmt = serialize_stmt(ctx, &node.body);
|
|
|
|
ctx.write_labeled_stmt(&node.span, ident, stmt)
|
|
}
|
|
Stmt::Break(node) => {
|
|
let arg = node
|
|
.label
|
|
.as_ref()
|
|
.map(|label| serialize_ident(ctx, label, None));
|
|
ctx.write_break_stmt(&node.span, arg)
|
|
}
|
|
Stmt::Continue(node) => {
|
|
let arg = node
|
|
.label
|
|
.as_ref()
|
|
.map(|label| serialize_ident(ctx, label, None));
|
|
|
|
ctx.write_continue_stmt(&node.span, arg)
|
|
}
|
|
Stmt::If(node) => {
|
|
let test = serialize_expr(ctx, node.test.as_ref());
|
|
let cons = serialize_stmt(ctx, node.cons.as_ref());
|
|
let alt = node.alt.as_ref().map(|alt| serialize_stmt(ctx, alt));
|
|
|
|
ctx.write_if_stmt(&node.span, test, cons, alt)
|
|
}
|
|
Stmt::Switch(node) => {
|
|
let disc = serialize_expr(ctx, &node.discriminant);
|
|
|
|
let cases = node
|
|
.cases
|
|
.iter()
|
|
.map(|case| {
|
|
let test = case.test.as_ref().map(|test| serialize_expr(ctx, test));
|
|
|
|
let cons = case
|
|
.cons
|
|
.iter()
|
|
.map(|cons| serialize_stmt(ctx, cons))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_switch_case(&case.span, test, cons)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_switch_stmt(&node.span, disc, cases)
|
|
}
|
|
Stmt::Throw(node) => {
|
|
let arg = serialize_expr(ctx, &node.arg);
|
|
ctx.write_throw_stmt(&node.span, arg)
|
|
}
|
|
Stmt::Try(node) => {
|
|
let block = serialize_stmt(ctx, &Stmt::Block(node.block.clone()));
|
|
|
|
let handler = node.handler.as_ref().map(|catch| {
|
|
let param = catch.param.as_ref().map(|param| serialize_pat(ctx, param));
|
|
|
|
let body = serialize_stmt(ctx, &Stmt::Block(catch.body.clone()));
|
|
|
|
ctx.write_catch_clause(&catch.span, param, body)
|
|
});
|
|
|
|
let finalizer = node
|
|
.finalizer
|
|
.as_ref()
|
|
.map(|finalizer| serialize_stmt(ctx, &Stmt::Block(finalizer.clone())));
|
|
|
|
ctx.write_try_stmt(&node.span, block, handler, finalizer)
|
|
}
|
|
Stmt::While(node) => {
|
|
let test = serialize_expr(ctx, node.test.as_ref());
|
|
let stmt = serialize_stmt(ctx, node.body.as_ref());
|
|
|
|
ctx.write_while_stmt(&node.span, test, stmt)
|
|
}
|
|
Stmt::DoWhile(node) => {
|
|
let expr = serialize_expr(ctx, node.test.as_ref());
|
|
let stmt = serialize_stmt(ctx, node.body.as_ref());
|
|
|
|
ctx.write_do_while_stmt(&node.span, expr, stmt)
|
|
}
|
|
Stmt::For(node) => {
|
|
let init = node.init.as_ref().map(|init| match init {
|
|
VarDeclOrExpr::VarDecl(var_decl) => {
|
|
serialize_stmt(ctx, &Stmt::Decl(Decl::Var(var_decl.clone())))
|
|
}
|
|
VarDeclOrExpr::Expr(expr) => serialize_expr(ctx, expr),
|
|
});
|
|
|
|
let test = node.test.as_ref().map(|expr| serialize_expr(ctx, expr));
|
|
let update = node.update.as_ref().map(|expr| serialize_expr(ctx, expr));
|
|
let body = serialize_stmt(ctx, node.body.as_ref());
|
|
|
|
ctx.write_for_stmt(&node.span, init, test, update, body)
|
|
}
|
|
Stmt::ForIn(node) => {
|
|
let left = serialize_for_head(ctx, &node.left);
|
|
let right = serialize_expr(ctx, node.right.as_ref());
|
|
let body = serialize_stmt(ctx, node.body.as_ref());
|
|
|
|
ctx.write_for_in_stmt(&node.span, left, right, body)
|
|
}
|
|
Stmt::ForOf(node) => {
|
|
let left = serialize_for_head(ctx, &node.left);
|
|
let right = serialize_expr(ctx, node.right.as_ref());
|
|
let body = serialize_stmt(ctx, node.body.as_ref());
|
|
|
|
ctx.write_for_of_stmt(&node.span, node.is_await, left, right, body)
|
|
}
|
|
Stmt::Decl(node) => serialize_decl(ctx, node),
|
|
Stmt::Expr(node) => {
|
|
let expr = serialize_expr(ctx, node.expr.as_ref());
|
|
ctx.write_expr_stmt(&node.span, expr)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serialize_expr(ctx: &mut TsEsTreeBuilder, expr: &Expr) -> NodeRef {
|
|
match expr {
|
|
Expr::This(node) => ctx.write_this_expr(&node.span),
|
|
Expr::Array(node) => {
|
|
let elems = node
|
|
.elems
|
|
.iter()
|
|
.map(|item| {
|
|
item
|
|
.as_ref()
|
|
.map_or(NodeRef(0), |item| serialize_expr_or_spread(ctx, item))
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_arr_expr(&node.span, elems)
|
|
}
|
|
Expr::Object(node) => {
|
|
let props = node
|
|
.props
|
|
.iter()
|
|
.map(|prop| serialize_prop_or_spread(ctx, prop))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_obj_expr(&node.span, props)
|
|
}
|
|
Expr::Fn(node) => {
|
|
let fn_obj = node.function.as_ref();
|
|
|
|
let ident = node
|
|
.ident
|
|
.as_ref()
|
|
.map(|ident| serialize_ident(ctx, ident, None));
|
|
|
|
let type_params =
|
|
maybe_serialize_ts_type_param_decl(ctx, &fn_obj.type_params);
|
|
|
|
let params = fn_obj
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_pat(ctx, ¶m.pat))
|
|
.collect::<Vec<_>>();
|
|
|
|
let return_id = maybe_serialize_ts_type_ann(ctx, &fn_obj.return_type);
|
|
let body = fn_obj
|
|
.body
|
|
.as_ref()
|
|
.map(|block| serialize_stmt(ctx, &Stmt::Block(block.clone())));
|
|
|
|
ctx.write_fn_expr(
|
|
&fn_obj.span,
|
|
fn_obj.is_async,
|
|
fn_obj.is_generator,
|
|
ident,
|
|
type_params,
|
|
params,
|
|
return_id,
|
|
body,
|
|
)
|
|
}
|
|
Expr::Unary(node) => {
|
|
let arg = serialize_expr(ctx, &node.arg);
|
|
let op = match node.op {
|
|
UnaryOp::Minus => "-",
|
|
UnaryOp::Plus => "+",
|
|
UnaryOp::Bang => "!",
|
|
UnaryOp::Tilde => "~",
|
|
UnaryOp::TypeOf => "typeof",
|
|
UnaryOp::Void => "void",
|
|
UnaryOp::Delete => "delete",
|
|
};
|
|
|
|
ctx.write_unary_expr(&node.span, op, arg)
|
|
}
|
|
Expr::Update(node) => {
|
|
let arg = serialize_expr(ctx, node.arg.as_ref());
|
|
let op = match node.op {
|
|
UpdateOp::PlusPlus => "++",
|
|
UpdateOp::MinusMinus => "--",
|
|
};
|
|
|
|
ctx.write_update_expr(&node.span, node.prefix, op, arg)
|
|
}
|
|
Expr::Bin(node) => {
|
|
let (node_type, flag_str) = match node.op {
|
|
BinaryOp::LogicalAnd => (AstNode::LogicalExpression, "&&"),
|
|
BinaryOp::LogicalOr => (AstNode::LogicalExpression, "||"),
|
|
BinaryOp::NullishCoalescing => (AstNode::LogicalExpression, "??"),
|
|
BinaryOp::EqEq => (AstNode::BinaryExpression, "=="),
|
|
BinaryOp::NotEq => (AstNode::BinaryExpression, "!="),
|
|
BinaryOp::EqEqEq => (AstNode::BinaryExpression, "==="),
|
|
BinaryOp::NotEqEq => (AstNode::BinaryExpression, "!="),
|
|
BinaryOp::Lt => (AstNode::BinaryExpression, "<"),
|
|
BinaryOp::LtEq => (AstNode::BinaryExpression, "<="),
|
|
BinaryOp::Gt => (AstNode::BinaryExpression, ">"),
|
|
BinaryOp::GtEq => (AstNode::BinaryExpression, ">="),
|
|
BinaryOp::LShift => (AstNode::BinaryExpression, "<<"),
|
|
BinaryOp::RShift => (AstNode::BinaryExpression, ">>"),
|
|
BinaryOp::ZeroFillRShift => (AstNode::BinaryExpression, ">>>"),
|
|
BinaryOp::Add => (AstNode::BinaryExpression, "+"),
|
|
BinaryOp::Sub => (AstNode::BinaryExpression, "-"),
|
|
BinaryOp::Mul => (AstNode::BinaryExpression, "*"),
|
|
BinaryOp::Div => (AstNode::BinaryExpression, "/"),
|
|
BinaryOp::Mod => (AstNode::BinaryExpression, "%"),
|
|
BinaryOp::BitOr => (AstNode::BinaryExpression, "|"),
|
|
BinaryOp::BitXor => (AstNode::BinaryExpression, "^"),
|
|
BinaryOp::BitAnd => (AstNode::BinaryExpression, "&"),
|
|
BinaryOp::In => (AstNode::BinaryExpression, "in"),
|
|
BinaryOp::InstanceOf => (AstNode::BinaryExpression, "instanceof"),
|
|
BinaryOp::Exp => (AstNode::BinaryExpression, "**"),
|
|
};
|
|
|
|
let left = serialize_expr(ctx, node.left.as_ref());
|
|
let right = serialize_expr(ctx, node.right.as_ref());
|
|
|
|
match node_type {
|
|
AstNode::LogicalExpression => {
|
|
ctx.write_logical_expr(&node.span, flag_str, left, right)
|
|
}
|
|
AstNode::BinaryExpression => {
|
|
ctx.write_bin_expr(&node.span, flag_str, left, right)
|
|
}
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
Expr::Assign(node) => {
|
|
let left = match &node.left {
|
|
AssignTarget::Simple(simple_assign_target) => {
|
|
match simple_assign_target {
|
|
SimpleAssignTarget::Ident(target) => {
|
|
serialize_binding_ident(ctx, target)
|
|
}
|
|
SimpleAssignTarget::Member(target) => {
|
|
serialize_expr(ctx, &Expr::Member(target.clone()))
|
|
}
|
|
SimpleAssignTarget::SuperProp(target) => {
|
|
serialize_expr(ctx, &Expr::SuperProp(target.clone()))
|
|
}
|
|
SimpleAssignTarget::Paren(target) => {
|
|
serialize_expr(ctx, &target.expr)
|
|
}
|
|
SimpleAssignTarget::OptChain(target) => {
|
|
serialize_expr(ctx, &Expr::OptChain(target.clone()))
|
|
}
|
|
SimpleAssignTarget::TsAs(target) => {
|
|
serialize_expr(ctx, &Expr::TsAs(target.clone()))
|
|
}
|
|
SimpleAssignTarget::TsSatisfies(target) => {
|
|
serialize_expr(ctx, &Expr::TsSatisfies(target.clone()))
|
|
}
|
|
SimpleAssignTarget::TsNonNull(target) => {
|
|
serialize_expr(ctx, &Expr::TsNonNull(target.clone()))
|
|
}
|
|
SimpleAssignTarget::TsTypeAssertion(target) => {
|
|
serialize_expr(ctx, &Expr::TsTypeAssertion(target.clone()))
|
|
}
|
|
SimpleAssignTarget::TsInstantiation(target) => {
|
|
serialize_expr(ctx, &Expr::TsInstantiation(target.clone()))
|
|
}
|
|
SimpleAssignTarget::Invalid(_) => unreachable!(),
|
|
}
|
|
}
|
|
AssignTarget::Pat(target) => match target {
|
|
AssignTargetPat::Array(array_pat) => {
|
|
serialize_pat(ctx, &Pat::Array(array_pat.clone()))
|
|
}
|
|
AssignTargetPat::Object(object_pat) => {
|
|
serialize_pat(ctx, &Pat::Object(object_pat.clone()))
|
|
}
|
|
AssignTargetPat::Invalid(_) => unreachable!(),
|
|
},
|
|
};
|
|
|
|
let right = serialize_expr(ctx, node.right.as_ref());
|
|
|
|
let op = match node.op {
|
|
AssignOp::Assign => "=",
|
|
AssignOp::AddAssign => "+=",
|
|
AssignOp::SubAssign => "-=",
|
|
AssignOp::MulAssign => "*=",
|
|
AssignOp::DivAssign => "/=",
|
|
AssignOp::ModAssign => "%=",
|
|
AssignOp::LShiftAssign => "<<=",
|
|
AssignOp::RShiftAssign => ">>=",
|
|
AssignOp::ZeroFillRShiftAssign => ">>>=",
|
|
AssignOp::BitOrAssign => "|=",
|
|
AssignOp::BitXorAssign => "^=",
|
|
AssignOp::BitAndAssign => "&=",
|
|
AssignOp::ExpAssign => "**=",
|
|
AssignOp::AndAssign => "&&=",
|
|
AssignOp::OrAssign => "||=",
|
|
AssignOp::NullishAssign => "??=",
|
|
};
|
|
|
|
ctx.write_assignment_expr(&node.span, op, left, right)
|
|
}
|
|
Expr::Member(node) => serialize_member_expr(ctx, node, false),
|
|
Expr::SuperProp(node) => {
|
|
let obj = ctx.write_super(&node.obj.span);
|
|
|
|
let mut computed = false;
|
|
let prop = match &node.prop {
|
|
SuperProp::Ident(ident_name) => serialize_ident_name(ctx, ident_name),
|
|
SuperProp::Computed(prop) => {
|
|
computed = true;
|
|
serialize_expr(ctx, &prop.expr)
|
|
}
|
|
};
|
|
|
|
ctx.write_member_expr(&node.span, false, computed, obj, prop)
|
|
}
|
|
Expr::Cond(node) => {
|
|
let test = serialize_expr(ctx, node.test.as_ref());
|
|
let cons = serialize_expr(ctx, node.cons.as_ref());
|
|
let alt = serialize_expr(ctx, node.alt.as_ref());
|
|
|
|
ctx.write_conditional_expr(&node.span, test, cons, alt)
|
|
}
|
|
Expr::Call(node) => {
|
|
if let Callee::Import(_) = node.callee {
|
|
let source = node
|
|
.args
|
|
.first()
|
|
.map_or(NodeRef(0), |arg| serialize_expr_or_spread(ctx, arg));
|
|
|
|
let options = node
|
|
.args
|
|
.get(1)
|
|
.map_or(NodeRef(0), |arg| serialize_expr_or_spread(ctx, arg));
|
|
|
|
ctx.write_import_expr(&node.span, source, options)
|
|
} else {
|
|
let callee = match &node.callee {
|
|
Callee::Super(super_node) => ctx.write_super(&super_node.span),
|
|
Callee::Import(_) => unreachable!("Already handled"),
|
|
Callee::Expr(expr) => serialize_expr(ctx, expr),
|
|
};
|
|
|
|
let type_arg = node
|
|
.type_args
|
|
.clone()
|
|
.map(|param_node| serialize_ts_param_inst(ctx, param_node.as_ref()));
|
|
|
|
let args = node
|
|
.args
|
|
.iter()
|
|
.map(|arg| serialize_expr_or_spread(ctx, arg))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_call_expr(&node.span, false, callee, type_arg, args)
|
|
}
|
|
}
|
|
Expr::New(node) => {
|
|
let callee = serialize_expr(ctx, node.callee.as_ref());
|
|
|
|
let args: Vec<NodeRef> = node.args.as_ref().map_or(vec![], |args| {
|
|
args
|
|
.iter()
|
|
.map(|arg| serialize_expr_or_spread(ctx, arg))
|
|
.collect::<Vec<_>>()
|
|
});
|
|
|
|
let type_args = node
|
|
.type_args
|
|
.clone()
|
|
.map(|param_node| serialize_ts_param_inst(ctx, param_node.as_ref()));
|
|
|
|
ctx.write_new_expr(&node.span, callee, type_args, args)
|
|
}
|
|
Expr::Seq(node) => {
|
|
let children = node
|
|
.exprs
|
|
.iter()
|
|
.map(|expr| serialize_expr(ctx, expr))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_sequence_expr(&node.span, children)
|
|
}
|
|
Expr::Ident(node) => serialize_ident(ctx, node, None),
|
|
Expr::Lit(node) => serialize_lit(ctx, node),
|
|
Expr::Tpl(node) => {
|
|
let quasis = node
|
|
.quasis
|
|
.iter()
|
|
.map(|quasi| {
|
|
ctx.write_template_elem(
|
|
&quasi.span,
|
|
quasi.tail,
|
|
&quasi.raw,
|
|
&quasi
|
|
.cooked
|
|
.as_ref()
|
|
.map_or("".to_string(), |v| v.to_string()),
|
|
)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let exprs = node
|
|
.exprs
|
|
.iter()
|
|
.map(|expr| serialize_expr(ctx, expr))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_template_lit(&node.span, quasis, exprs)
|
|
}
|
|
Expr::TaggedTpl(node) => {
|
|
let tag = serialize_expr(ctx, &node.tag);
|
|
let type_param = node
|
|
.type_params
|
|
.clone()
|
|
.map(|params| serialize_ts_param_inst(ctx, params.as_ref()));
|
|
let quasi = serialize_expr(ctx, &Expr::Tpl(*node.tpl.clone()));
|
|
|
|
ctx.write_tagged_template_expr(&node.span, tag, type_param, quasi)
|
|
}
|
|
Expr::Arrow(node) => {
|
|
let type_param =
|
|
maybe_serialize_ts_type_param_decl(ctx, &node.type_params);
|
|
|
|
let params = node
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_pat(ctx, param))
|
|
.collect::<Vec<_>>();
|
|
|
|
let body = match node.body.as_ref() {
|
|
BlockStmtOrExpr::BlockStmt(block_stmt) => {
|
|
serialize_stmt(ctx, &Stmt::Block(block_stmt.clone()))
|
|
}
|
|
BlockStmtOrExpr::Expr(expr) => serialize_expr(ctx, expr.as_ref()),
|
|
};
|
|
|
|
let return_type = maybe_serialize_ts_type_ann(ctx, &node.return_type);
|
|
|
|
ctx.write_arrow_fn_expr(
|
|
&node.span,
|
|
node.is_async,
|
|
node.is_generator,
|
|
type_param,
|
|
params,
|
|
return_type,
|
|
body,
|
|
)
|
|
}
|
|
Expr::Class(node) => {
|
|
let ident = node
|
|
.ident
|
|
.as_ref()
|
|
.map(|ident| serialize_ident(ctx, ident, None));
|
|
|
|
let super_class = node
|
|
.class
|
|
.super_class
|
|
.as_ref()
|
|
.map(|expr| serialize_expr(ctx, expr.as_ref()));
|
|
|
|
let implements = node
|
|
.class
|
|
.implements
|
|
.iter()
|
|
.map(|item| serialize_ts_expr_with_type_args(ctx, item))
|
|
.collect::<Vec<_>>();
|
|
|
|
let members = node
|
|
.class
|
|
.body
|
|
.iter()
|
|
.filter_map(|member| serialize_class_member(ctx, member))
|
|
.collect::<Vec<_>>();
|
|
|
|
let body = ctx.write_class_body(&node.class.span, members);
|
|
|
|
ctx.write_class_expr(
|
|
&node.class.span,
|
|
false,
|
|
node.class.is_abstract,
|
|
ident,
|
|
super_class,
|
|
implements,
|
|
body,
|
|
)
|
|
}
|
|
Expr::Yield(node) => {
|
|
let arg = node
|
|
.arg
|
|
.as_ref()
|
|
.map(|arg| serialize_expr(ctx, arg.as_ref()));
|
|
|
|
ctx.write_yield_expr(&node.span, node.delegate, arg)
|
|
}
|
|
Expr::MetaProp(node) => {
|
|
let prop = ctx.write_identifier(&node.span, "meta", false, None);
|
|
ctx.write_meta_prop(&node.span, prop)
|
|
}
|
|
Expr::Await(node) => {
|
|
let arg = serialize_expr(ctx, node.arg.as_ref());
|
|
ctx.write_await_expr(&node.span, arg)
|
|
}
|
|
Expr::Paren(node) => {
|
|
// Paren nodes are treated as a syntax only thing in TSEStree
|
|
// and are never materialized to actual AST nodes.
|
|
serialize_expr(ctx, &node.expr)
|
|
}
|
|
Expr::JSXMember(node) => serialize_jsx_member_expr(ctx, node),
|
|
Expr::JSXNamespacedName(node) => serialize_jsx_namespaced_name(ctx, node),
|
|
Expr::JSXEmpty(node) => ctx.write_jsx_empty_expr(&node.span),
|
|
Expr::JSXElement(node) => serialize_jsx_element(ctx, node),
|
|
Expr::JSXFragment(node) => serialize_jsx_fragment(ctx, node),
|
|
Expr::TsTypeAssertion(node) => {
|
|
let expr = serialize_expr(ctx, &node.expr);
|
|
let type_ann = serialize_ts_type(ctx, &node.type_ann);
|
|
|
|
ctx.write_ts_type_assertion(&node.span, expr, type_ann)
|
|
}
|
|
Expr::TsConstAssertion(node) => {
|
|
let expr = serialize_expr(ctx, node.expr.as_ref());
|
|
|
|
let type_name = ctx.write_identifier(&node.span, "const", false, None);
|
|
let type_ann = ctx.write_ts_type_ref(&node.span, type_name, None);
|
|
|
|
ctx.write_ts_as_expr(&node.span, expr, type_ann)
|
|
}
|
|
Expr::TsNonNull(node) => {
|
|
let expr = serialize_expr(ctx, node.expr.as_ref());
|
|
ctx.write_ts_non_null(&node.span, expr)
|
|
}
|
|
Expr::TsAs(node) => {
|
|
let expr = serialize_expr(ctx, node.expr.as_ref());
|
|
let type_ann = serialize_ts_type(ctx, node.type_ann.as_ref());
|
|
|
|
ctx.write_ts_as_expr(&node.span, expr, type_ann)
|
|
}
|
|
Expr::TsInstantiation(_) => {
|
|
// Invalid syntax
|
|
unreachable!()
|
|
}
|
|
Expr::TsSatisfies(node) => {
|
|
let expr = serialize_expr(ctx, node.expr.as_ref());
|
|
let type_ann = serialize_ts_type(ctx, node.type_ann.as_ref());
|
|
|
|
ctx.write_ts_satisfies_expr(&node.span, expr, type_ann)
|
|
}
|
|
Expr::PrivateName(node) => serialize_private_name(ctx, node),
|
|
Expr::OptChain(node) => {
|
|
let expr = match node.base.as_ref() {
|
|
OptChainBase::Member(member_expr) => {
|
|
serialize_member_expr(ctx, member_expr, true)
|
|
}
|
|
OptChainBase::Call(opt_call) => {
|
|
let callee = serialize_expr(ctx, &opt_call.callee);
|
|
|
|
let type_param_id = opt_call
|
|
.type_args
|
|
.clone()
|
|
.map(|params| serialize_ts_param_inst(ctx, params.as_ref()));
|
|
|
|
let args = opt_call
|
|
.args
|
|
.iter()
|
|
.map(|arg| serialize_expr_or_spread(ctx, arg))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_call_expr(&opt_call.span, true, callee, type_param_id, args)
|
|
}
|
|
};
|
|
|
|
ctx.write_chain_expr(&node.span, expr)
|
|
}
|
|
Expr::Invalid(_) => {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serialize_prop_or_spread(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
prop: &PropOrSpread,
|
|
) -> NodeRef {
|
|
match prop {
|
|
PropOrSpread::Spread(spread_element) => serialize_spread(
|
|
ctx,
|
|
spread_element.expr.as_ref(),
|
|
&spread_element.dot3_token,
|
|
),
|
|
PropOrSpread::Prop(prop) => {
|
|
let mut shorthand = false;
|
|
let mut computed = false;
|
|
let mut method = false;
|
|
let mut kind = "init";
|
|
|
|
let (key, value) = match prop.as_ref() {
|
|
Prop::Shorthand(ident) => {
|
|
shorthand = true;
|
|
|
|
let value = serialize_ident(ctx, ident, None);
|
|
let value2 = serialize_ident(ctx, ident, None);
|
|
(value, value2)
|
|
}
|
|
Prop::KeyValue(key_value_prop) => {
|
|
if let PropName::Computed(_) = key_value_prop.key {
|
|
computed = true;
|
|
}
|
|
|
|
let key = serialize_prop_name(ctx, &key_value_prop.key);
|
|
let value = serialize_expr(ctx, key_value_prop.value.as_ref());
|
|
|
|
(key, value)
|
|
}
|
|
Prop::Assign(assign_prop) => {
|
|
let left = serialize_ident(ctx, &assign_prop.key, None);
|
|
let right = serialize_expr(ctx, assign_prop.value.as_ref());
|
|
|
|
let child_pos = ctx.write_assign_pat(&assign_prop.span, left, right);
|
|
|
|
(left, child_pos)
|
|
}
|
|
Prop::Getter(getter_prop) => {
|
|
kind = "get";
|
|
|
|
let key = serialize_prop_name(ctx, &getter_prop.key);
|
|
|
|
let value = serialize_expr(
|
|
ctx,
|
|
&Expr::Fn(FnExpr {
|
|
ident: None,
|
|
function: Box::new(Function {
|
|
params: vec![],
|
|
decorators: vec![],
|
|
span: getter_prop.span,
|
|
ctxt: SyntaxContext::empty(),
|
|
body: getter_prop.body.clone(),
|
|
is_generator: false,
|
|
is_async: false,
|
|
type_params: None,
|
|
return_type: getter_prop.type_ann.clone(),
|
|
}),
|
|
}),
|
|
);
|
|
|
|
(key, value)
|
|
}
|
|
Prop::Setter(setter_prop) => {
|
|
kind = "set";
|
|
|
|
let key_id = serialize_prop_name(ctx, &setter_prop.key);
|
|
|
|
let param = Param::from(*setter_prop.param.clone());
|
|
|
|
let value_id = serialize_expr(
|
|
ctx,
|
|
&Expr::Fn(FnExpr {
|
|
ident: None,
|
|
function: Box::new(Function {
|
|
params: vec![param],
|
|
decorators: vec![],
|
|
span: setter_prop.span,
|
|
ctxt: SyntaxContext::empty(),
|
|
body: setter_prop.body.clone(),
|
|
is_generator: false,
|
|
is_async: false,
|
|
type_params: None,
|
|
return_type: None,
|
|
}),
|
|
}),
|
|
);
|
|
|
|
(key_id, value_id)
|
|
}
|
|
Prop::Method(method_prop) => {
|
|
method = true;
|
|
|
|
let key_id = serialize_prop_name(ctx, &method_prop.key);
|
|
|
|
let value_id = serialize_expr(
|
|
ctx,
|
|
&Expr::Fn(FnExpr {
|
|
ident: None,
|
|
function: method_prop.function.clone(),
|
|
}),
|
|
);
|
|
|
|
(key_id, value_id)
|
|
}
|
|
};
|
|
|
|
ctx.write_property(
|
|
&prop.span(),
|
|
shorthand,
|
|
computed,
|
|
method,
|
|
kind,
|
|
key,
|
|
value,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serialize_member_expr(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &MemberExpr,
|
|
optional: bool,
|
|
) -> NodeRef {
|
|
let mut computed = false;
|
|
let obj = serialize_expr(ctx, node.obj.as_ref());
|
|
|
|
let prop = match &node.prop {
|
|
MemberProp::Ident(ident_name) => serialize_ident_name(ctx, ident_name),
|
|
MemberProp::PrivateName(private_name) => {
|
|
serialize_private_name(ctx, private_name)
|
|
}
|
|
MemberProp::Computed(computed_prop_name) => {
|
|
computed = true;
|
|
serialize_expr(ctx, computed_prop_name.expr.as_ref())
|
|
}
|
|
};
|
|
|
|
ctx.write_member_expr(&node.span, optional, computed, obj, prop)
|
|
}
|
|
|
|
fn serialize_expr_or_spread(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
arg: &ExprOrSpread,
|
|
) -> NodeRef {
|
|
if let Some(spread) = &arg.spread {
|
|
serialize_spread(ctx, &arg.expr, spread)
|
|
} else {
|
|
serialize_expr(ctx, arg.expr.as_ref())
|
|
}
|
|
}
|
|
|
|
fn serialize_ident(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
ident: &Ident,
|
|
type_ann: Option<NodeRef>,
|
|
) -> NodeRef {
|
|
ctx.write_identifier(
|
|
&ident.span,
|
|
ident.sym.as_str(),
|
|
ident.optional,
|
|
type_ann,
|
|
)
|
|
}
|
|
|
|
fn serialize_module_export_name(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
name: &ModuleExportName,
|
|
) -> NodeRef {
|
|
match &name {
|
|
ModuleExportName::Ident(ident) => serialize_ident(ctx, ident, None),
|
|
ModuleExportName::Str(lit) => serialize_lit(ctx, &Lit::Str(lit.clone())),
|
|
}
|
|
}
|
|
|
|
fn serialize_decl(ctx: &mut TsEsTreeBuilder, decl: &Decl) -> NodeRef {
|
|
match decl {
|
|
Decl::Class(node) => {
|
|
let ident = serialize_ident(ctx, &node.ident, None);
|
|
|
|
let super_class = node
|
|
.class
|
|
.super_class
|
|
.as_ref()
|
|
.map(|expr| serialize_expr(ctx, expr.as_ref()));
|
|
|
|
let implements = node
|
|
.class
|
|
.implements
|
|
.iter()
|
|
.map(|item| serialize_ts_expr_with_type_args(ctx, item))
|
|
.collect::<Vec<_>>();
|
|
|
|
let members = node
|
|
.class
|
|
.body
|
|
.iter()
|
|
.filter_map(|member| serialize_class_member(ctx, member))
|
|
.collect::<Vec<_>>();
|
|
|
|
let body = ctx.write_class_body(&node.class.span, members);
|
|
|
|
ctx.write_class_decl(
|
|
&node.class.span,
|
|
false,
|
|
node.class.is_abstract,
|
|
Some(ident),
|
|
super_class,
|
|
implements,
|
|
body,
|
|
)
|
|
}
|
|
Decl::Fn(node) => {
|
|
let ident_id = serialize_ident(ctx, &node.ident, None);
|
|
let type_param_id =
|
|
maybe_serialize_ts_type_param_decl(ctx, &node.function.type_params);
|
|
let return_type =
|
|
maybe_serialize_ts_type_ann(ctx, &node.function.return_type);
|
|
|
|
let body = node
|
|
.function
|
|
.body
|
|
.as_ref()
|
|
.map(|body| serialize_stmt(ctx, &Stmt::Block(body.clone())));
|
|
|
|
let params = node
|
|
.function
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_pat(ctx, ¶m.pat))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_fn_decl(
|
|
&node.function.span,
|
|
node.declare,
|
|
node.function.is_async,
|
|
node.function.is_generator,
|
|
Some(ident_id),
|
|
type_param_id,
|
|
return_type,
|
|
body,
|
|
params,
|
|
)
|
|
}
|
|
Decl::Var(node) => {
|
|
let children = node
|
|
.decls
|
|
.iter()
|
|
.map(|decl| {
|
|
let ident = serialize_pat(ctx, &decl.name);
|
|
let init = decl
|
|
.init
|
|
.as_ref()
|
|
.map(|init| serialize_expr(ctx, init.as_ref()));
|
|
|
|
ctx.write_var_declarator(&decl.span, ident, init)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let kind = match node.kind {
|
|
VarDeclKind::Var => "var",
|
|
VarDeclKind::Let => "let",
|
|
VarDeclKind::Const => "const",
|
|
};
|
|
|
|
ctx.write_var_decl(&node.span, node.declare, kind, children)
|
|
}
|
|
Decl::Using(node) => {
|
|
let kind = if node.is_await {
|
|
"await using"
|
|
} else {
|
|
"using"
|
|
};
|
|
|
|
let children = node
|
|
.decls
|
|
.iter()
|
|
.map(|decl| {
|
|
let ident = serialize_pat(ctx, &decl.name);
|
|
let init = decl
|
|
.init
|
|
.as_ref()
|
|
.map(|init| serialize_expr(ctx, init.as_ref()));
|
|
|
|
ctx.write_var_declarator(&decl.span, ident, init)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_var_decl(&node.span, false, kind, children)
|
|
}
|
|
Decl::TsInterface(node) => {
|
|
let ident_id = serialize_ident(ctx, &node.id, None);
|
|
let type_param =
|
|
maybe_serialize_ts_type_param_decl(ctx, &node.type_params);
|
|
|
|
let extend_ids = node
|
|
.extends
|
|
.iter()
|
|
.map(|item| {
|
|
let expr = serialize_expr(ctx, &item.expr);
|
|
let type_args = item
|
|
.type_args
|
|
.clone()
|
|
.map(|params| serialize_ts_param_inst(ctx, params.as_ref()));
|
|
|
|
ctx.write_ts_interface_heritage(&item.span, expr, type_args)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let body_elem_ids = node
|
|
.body
|
|
.body
|
|
.iter()
|
|
.map(|item| serialize_ts_type_elem(ctx, item))
|
|
.collect::<Vec<_>>();
|
|
|
|
let body_pos =
|
|
ctx.write_ts_interface_body(&node.body.span, body_elem_ids);
|
|
ctx.write_ts_interface(
|
|
&node.span,
|
|
node.declare,
|
|
ident_id,
|
|
type_param,
|
|
extend_ids,
|
|
body_pos,
|
|
)
|
|
}
|
|
Decl::TsTypeAlias(node) => {
|
|
let ident = serialize_ident(ctx, &node.id, None);
|
|
let type_ann = serialize_ts_type(ctx, &node.type_ann);
|
|
let type_param =
|
|
maybe_serialize_ts_type_param_decl(ctx, &node.type_params);
|
|
|
|
ctx.write_ts_type_alias(
|
|
&node.span,
|
|
node.declare,
|
|
ident,
|
|
type_param,
|
|
type_ann,
|
|
)
|
|
}
|
|
Decl::TsEnum(node) => {
|
|
let id = serialize_ident(ctx, &node.id, None);
|
|
|
|
let members = node
|
|
.members
|
|
.iter()
|
|
.map(|member| {
|
|
let ident = match &member.id {
|
|
TsEnumMemberId::Ident(ident) => serialize_ident(ctx, ident, None),
|
|
TsEnumMemberId::Str(lit_str) => {
|
|
serialize_lit(ctx, &Lit::Str(lit_str.clone()))
|
|
}
|
|
};
|
|
|
|
let init = member.init.as_ref().map(|init| serialize_expr(ctx, init));
|
|
|
|
ctx.write_ts_enum_member(&member.span, ident, init)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let body = ctx.write_ts_enum_body(&node.span, members);
|
|
ctx.write_ts_enum(&node.span, node.declare, node.is_const, id, body)
|
|
}
|
|
Decl::TsModule(node) => {
|
|
let ident = match &node.id {
|
|
TsModuleName::Ident(ident) => serialize_ident(ctx, ident, None),
|
|
TsModuleName::Str(str_lit) => {
|
|
serialize_lit(ctx, &Lit::Str(str_lit.clone()))
|
|
}
|
|
};
|
|
|
|
let body = node
|
|
.body
|
|
.as_ref()
|
|
.map(|body| serialize_ts_namespace_body(ctx, body));
|
|
|
|
ctx.write_ts_module_decl(
|
|
&node.span,
|
|
node.declare,
|
|
node.global,
|
|
ident,
|
|
body,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serialize_ts_namespace_body(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &TsNamespaceBody,
|
|
) -> NodeRef {
|
|
match node {
|
|
TsNamespaceBody::TsModuleBlock(mod_block) => {
|
|
let items = mod_block
|
|
.body
|
|
.iter()
|
|
.map(|item| match item {
|
|
ModuleItem::ModuleDecl(decl) => serialize_module_decl(ctx, decl),
|
|
ModuleItem::Stmt(stmt) => serialize_stmt(ctx, stmt),
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_ts_module_block(&mod_block.span, items)
|
|
}
|
|
TsNamespaceBody::TsNamespaceDecl(node) => {
|
|
let ident = serialize_ident(ctx, &node.id, None);
|
|
let body = serialize_ts_namespace_body(ctx, &node.body);
|
|
|
|
ctx.write_ts_module_decl(
|
|
&node.span,
|
|
node.declare,
|
|
node.global,
|
|
ident,
|
|
Some(body),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serialize_ts_type_elem(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &TsTypeElement,
|
|
) -> NodeRef {
|
|
match node {
|
|
TsTypeElement::TsCallSignatureDecl(ts_call) => {
|
|
let type_ann =
|
|
maybe_serialize_ts_type_param_decl(ctx, &ts_call.type_params);
|
|
let return_type = maybe_serialize_ts_type_ann(ctx, &ts_call.type_ann);
|
|
let params = ts_call
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_ts_fn_param(ctx, param))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_ts_call_sig_decl(&ts_call.span, type_ann, params, return_type)
|
|
}
|
|
TsTypeElement::TsConstructSignatureDecl(sig) => {
|
|
let type_params =
|
|
maybe_serialize_ts_type_param_decl(ctx, &sig.type_params);
|
|
|
|
let params = sig
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_ts_fn_param(ctx, param))
|
|
.collect::<Vec<_>>();
|
|
|
|
// Must be present
|
|
let return_type =
|
|
maybe_serialize_ts_type_ann(ctx, &sig.type_ann).unwrap();
|
|
|
|
ctx.write_ts_construct_sig(&sig.span, type_params, params, return_type)
|
|
}
|
|
TsTypeElement::TsPropertySignature(sig) => {
|
|
let key = serialize_expr(ctx, &sig.key);
|
|
let type_ann = maybe_serialize_ts_type_ann(ctx, &sig.type_ann);
|
|
|
|
ctx.write_ts_property_sig(
|
|
&sig.span,
|
|
sig.computed,
|
|
sig.optional,
|
|
sig.readonly,
|
|
key,
|
|
type_ann,
|
|
)
|
|
}
|
|
TsTypeElement::TsGetterSignature(sig) => {
|
|
let key = serialize_expr(ctx, sig.key.as_ref());
|
|
let return_type = maybe_serialize_ts_type_ann(ctx, &sig.type_ann);
|
|
|
|
ctx.write_ts_getter_sig(&sig.span, key, return_type)
|
|
}
|
|
TsTypeElement::TsSetterSignature(sig) => {
|
|
let key = serialize_expr(ctx, sig.key.as_ref());
|
|
let param = serialize_ts_fn_param(ctx, &sig.param);
|
|
|
|
ctx.write_ts_setter_sig(&sig.span, key, param)
|
|
}
|
|
TsTypeElement::TsMethodSignature(sig) => {
|
|
let key = serialize_expr(ctx, &sig.key);
|
|
let type_parms =
|
|
maybe_serialize_ts_type_param_decl(ctx, &sig.type_params);
|
|
let params = sig
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_ts_fn_param(ctx, param))
|
|
.collect::<Vec<_>>();
|
|
let return_type = maybe_serialize_ts_type_ann(ctx, &sig.type_ann);
|
|
|
|
ctx.write_ts_method_sig(
|
|
&sig.span,
|
|
sig.computed,
|
|
sig.optional,
|
|
key,
|
|
type_parms,
|
|
params,
|
|
return_type,
|
|
)
|
|
}
|
|
TsTypeElement::TsIndexSignature(sig) => serialize_ts_index_sig(ctx, sig),
|
|
}
|
|
}
|
|
|
|
fn serialize_ts_index_sig(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &TsIndexSignature,
|
|
) -> NodeRef {
|
|
let params = node
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_ts_fn_param(ctx, param))
|
|
.collect::<Vec<_>>();
|
|
let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann);
|
|
|
|
ctx.write_ts_index_sig(&node.span, node.readonly, params, type_ann)
|
|
}
|
|
|
|
fn accessibility_to_str(accessibility: &Accessibility) -> String {
|
|
match accessibility {
|
|
Accessibility::Public => "public".to_string(),
|
|
Accessibility::Protected => "protected".to_string(),
|
|
Accessibility::Private => "private".to_string(),
|
|
}
|
|
}
|
|
|
|
fn serialize_private_name(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &PrivateName,
|
|
) -> NodeRef {
|
|
ctx.write_private_identifier(&node.span, node.name.as_str())
|
|
}
|
|
|
|
fn serialize_jsx_element(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &JSXElement,
|
|
) -> NodeRef {
|
|
let open = serialize_jsx_opening_element(ctx, &node.opening);
|
|
|
|
let close = node.closing.as_ref().map(|closing| {
|
|
let name = serialize_jsx_element_name(ctx, &closing.name);
|
|
ctx.write_jsx_closing_elem(&closing.span, name)
|
|
});
|
|
|
|
let children = serialize_jsx_children(ctx, &node.children);
|
|
|
|
ctx.write_jsx_elem(&node.span, open, close, children)
|
|
}
|
|
|
|
fn serialize_jsx_fragment(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &JSXFragment,
|
|
) -> NodeRef {
|
|
let opening = ctx.write_jsx_opening_frag(&node.opening.span);
|
|
let closing = ctx.write_jsx_closing_frag(&node.closing.span);
|
|
let children = serialize_jsx_children(ctx, &node.children);
|
|
|
|
ctx.write_jsx_frag(&node.span, opening, closing, children)
|
|
}
|
|
|
|
fn serialize_jsx_children(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
children: &[JSXElementChild],
|
|
) -> Vec<NodeRef> {
|
|
children
|
|
.iter()
|
|
.map(|child| {
|
|
match child {
|
|
JSXElementChild::JSXText(text) => {
|
|
ctx.write_jsx_text(&text.span, &text.raw, &text.value)
|
|
}
|
|
JSXElementChild::JSXExprContainer(container) => {
|
|
serialize_jsx_container_expr(ctx, container)
|
|
}
|
|
JSXElementChild::JSXElement(el) => serialize_jsx_element(ctx, el),
|
|
JSXElementChild::JSXFragment(frag) => serialize_jsx_fragment(ctx, frag),
|
|
// No parser supports this
|
|
JSXElementChild::JSXSpreadChild(_) => unreachable!(),
|
|
}
|
|
})
|
|
.collect::<Vec<_>>()
|
|
}
|
|
|
|
fn serialize_jsx_member_expr(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &JSXMemberExpr,
|
|
) -> NodeRef {
|
|
let obj = match &node.obj {
|
|
JSXObject::JSXMemberExpr(member) => serialize_jsx_member_expr(ctx, member),
|
|
JSXObject::Ident(ident) => serialize_jsx_identifier(ctx, ident),
|
|
};
|
|
|
|
let prop = serialize_ident_name_as_jsx_identifier(ctx, &node.prop);
|
|
|
|
ctx.write_jsx_member_expr(&node.span, obj, prop)
|
|
}
|
|
|
|
fn serialize_jsx_element_name(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &JSXElementName,
|
|
) -> NodeRef {
|
|
match &node {
|
|
JSXElementName::Ident(ident) => serialize_jsx_identifier(ctx, ident),
|
|
JSXElementName::JSXMemberExpr(member) => {
|
|
serialize_jsx_member_expr(ctx, member)
|
|
}
|
|
JSXElementName::JSXNamespacedName(ns) => {
|
|
serialize_jsx_namespaced_name(ctx, ns)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serialize_jsx_opening_element(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &JSXOpeningElement,
|
|
) -> NodeRef {
|
|
let name = serialize_jsx_element_name(ctx, &node.name);
|
|
|
|
let type_args = node
|
|
.type_args
|
|
.as_ref()
|
|
.map(|arg| serialize_ts_param_inst(ctx, arg));
|
|
|
|
let attrs = node
|
|
.attrs
|
|
.iter()
|
|
.map(|attr| match attr {
|
|
JSXAttrOrSpread::JSXAttr(attr) => {
|
|
let name = match &attr.name {
|
|
JSXAttrName::Ident(name) => {
|
|
serialize_ident_name_as_jsx_identifier(ctx, name)
|
|
}
|
|
JSXAttrName::JSXNamespacedName(node) => {
|
|
serialize_jsx_namespaced_name(ctx, node)
|
|
}
|
|
};
|
|
|
|
let value = attr.value.as_ref().map(|value| match value {
|
|
JSXAttrValue::Lit(lit) => serialize_lit(ctx, lit),
|
|
JSXAttrValue::JSXExprContainer(container) => {
|
|
serialize_jsx_container_expr(ctx, container)
|
|
}
|
|
JSXAttrValue::JSXElement(el) => serialize_jsx_element(ctx, el),
|
|
JSXAttrValue::JSXFragment(frag) => serialize_jsx_fragment(ctx, frag),
|
|
});
|
|
|
|
ctx.write_jsx_attr(&attr.span, name, value)
|
|
}
|
|
JSXAttrOrSpread::SpreadElement(spread) => {
|
|
let arg = serialize_expr(ctx, &spread.expr);
|
|
ctx.write_jsx_spread_attr(&spread.dot3_token, arg)
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_jsx_opening_elem(
|
|
&node.span,
|
|
node.self_closing,
|
|
name,
|
|
attrs,
|
|
type_args,
|
|
)
|
|
}
|
|
|
|
fn serialize_jsx_container_expr(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &JSXExprContainer,
|
|
) -> NodeRef {
|
|
let expr = match &node.expr {
|
|
JSXExpr::JSXEmptyExpr(expr) => ctx.write_jsx_empty_expr(&expr.span),
|
|
JSXExpr::Expr(expr) => serialize_expr(ctx, expr),
|
|
};
|
|
|
|
ctx.write_jsx_expr_container(&node.span, expr)
|
|
}
|
|
|
|
fn serialize_jsx_namespaced_name(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &JSXNamespacedName,
|
|
) -> NodeRef {
|
|
let ns = ctx.write_jsx_identifier(&node.ns.span, &node.ns.sym);
|
|
let name = ctx.write_jsx_identifier(&node.name.span, &node.name.sym);
|
|
|
|
ctx.write_jsx_namespaced_name(&node.span, ns, name)
|
|
}
|
|
|
|
fn serialize_ident_name_as_jsx_identifier(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &IdentName,
|
|
) -> NodeRef {
|
|
ctx.write_jsx_identifier(&node.span, &node.sym)
|
|
}
|
|
|
|
fn serialize_jsx_identifier(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &Ident,
|
|
) -> NodeRef {
|
|
ctx.write_jsx_identifier(&node.span, &node.sym)
|
|
}
|
|
|
|
fn serialize_pat(ctx: &mut TsEsTreeBuilder, pat: &Pat) -> NodeRef {
|
|
match pat {
|
|
Pat::Ident(node) => serialize_binding_ident(ctx, node),
|
|
Pat::Array(node) => {
|
|
let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann);
|
|
|
|
let children = node
|
|
.elems
|
|
.iter()
|
|
.map(|pat| pat.as_ref().map_or(NodeRef(0), |v| serialize_pat(ctx, v)))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_arr_pat(&node.span, node.optional, type_ann, children)
|
|
}
|
|
Pat::Rest(node) => {
|
|
let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann);
|
|
let arg = serialize_pat(ctx, &node.arg);
|
|
|
|
ctx.write_rest_elem(&node.span, type_ann, arg)
|
|
}
|
|
Pat::Object(node) => {
|
|
let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann);
|
|
|
|
let children = node
|
|
.props
|
|
.iter()
|
|
.map(|prop| match prop {
|
|
ObjectPatProp::KeyValue(key_value_prop) => {
|
|
let computed = matches!(key_value_prop.key, PropName::Computed(_));
|
|
|
|
let key = serialize_prop_name(ctx, &key_value_prop.key);
|
|
let value = serialize_pat(ctx, key_value_prop.value.as_ref());
|
|
|
|
ctx.write_property(
|
|
&key_value_prop.span(),
|
|
false,
|
|
computed,
|
|
false,
|
|
"init",
|
|
key,
|
|
value,
|
|
)
|
|
}
|
|
ObjectPatProp::Assign(assign_pat_prop) => {
|
|
let ident = serialize_binding_ident(ctx, &assign_pat_prop.key);
|
|
|
|
let value = assign_pat_prop
|
|
.value
|
|
.as_ref()
|
|
.map_or(NodeRef(0), |value| serialize_expr(ctx, value));
|
|
|
|
ctx.write_property(
|
|
&assign_pat_prop.span,
|
|
false,
|
|
false,
|
|
false,
|
|
"init",
|
|
ident,
|
|
value,
|
|
)
|
|
}
|
|
ObjectPatProp::Rest(rest_pat) => {
|
|
serialize_pat(ctx, &Pat::Rest(rest_pat.clone()))
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_obj_pat(&node.span, node.optional, type_ann, children)
|
|
}
|
|
Pat::Assign(node) => {
|
|
let left = serialize_pat(ctx, &node.left);
|
|
let right = serialize_expr(ctx, &node.right);
|
|
|
|
ctx.write_assign_pat(&node.span, left, right)
|
|
}
|
|
Pat::Invalid(_) => unreachable!(),
|
|
Pat::Expr(node) => serialize_expr(ctx, node),
|
|
}
|
|
}
|
|
|
|
fn serialize_for_head(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
for_head: &ForHead,
|
|
) -> NodeRef {
|
|
match for_head {
|
|
ForHead::VarDecl(var_decl) => {
|
|
serialize_decl(ctx, &Decl::Var(var_decl.clone()))
|
|
}
|
|
ForHead::UsingDecl(using_decl) => {
|
|
serialize_decl(ctx, &Decl::Using(using_decl.clone()))
|
|
}
|
|
ForHead::Pat(pat) => serialize_pat(ctx, pat),
|
|
}
|
|
}
|
|
|
|
fn serialize_spread(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
expr: &Expr,
|
|
span: &Span,
|
|
) -> NodeRef {
|
|
let expr = serialize_expr(ctx, expr);
|
|
ctx.write_spread(span, expr)
|
|
}
|
|
|
|
fn serialize_ident_name(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
ident_name: &IdentName,
|
|
) -> NodeRef {
|
|
ctx.write_identifier(&ident_name.span, ident_name.sym.as_str(), false, None)
|
|
}
|
|
|
|
fn serialize_prop_name(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
prop_name: &PropName,
|
|
) -> NodeRef {
|
|
match prop_name {
|
|
PropName::Ident(ident_name) => serialize_ident_name(ctx, ident_name),
|
|
PropName::Str(str_prop) => serialize_lit(ctx, &Lit::Str(str_prop.clone())),
|
|
PropName::Num(number) => serialize_lit(ctx, &Lit::Num(number.clone())),
|
|
PropName::Computed(node) => serialize_expr(ctx, &node.expr),
|
|
PropName::BigInt(big_int) => {
|
|
serialize_lit(ctx, &Lit::BigInt(big_int.clone()))
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serialize_lit(ctx: &mut TsEsTreeBuilder, lit: &Lit) -> NodeRef {
|
|
match lit {
|
|
Lit::Str(node) => {
|
|
let raw_value = if let Some(v) = &node.raw {
|
|
v.to_string()
|
|
} else {
|
|
format!("{}", node.value).to_string()
|
|
};
|
|
|
|
ctx.write_str_lit(&node.span, &node.value, &raw_value)
|
|
}
|
|
Lit::Bool(node) => ctx.write_bool_lit(&node.span, node.value),
|
|
Lit::Null(node) => ctx.write_null_lit(&node.span),
|
|
Lit::Num(node) => {
|
|
let raw_value = if let Some(v) = &node.raw {
|
|
v.to_string()
|
|
} else {
|
|
format!("{}", node.value).to_string()
|
|
};
|
|
|
|
let value = node.raw.as_ref().unwrap();
|
|
ctx.write_num_lit(&node.span, value, &raw_value)
|
|
}
|
|
Lit::BigInt(node) => {
|
|
let raw_bigint_value = if let Some(v) = &node.raw {
|
|
let mut s = v.to_string();
|
|
s.pop();
|
|
s.to_string()
|
|
} else {
|
|
format!("{}", node.value).to_string()
|
|
};
|
|
|
|
let raw_value = if let Some(v) = &node.raw {
|
|
v.to_string()
|
|
} else {
|
|
format!("{}", node.value).to_string()
|
|
};
|
|
|
|
ctx.write_bigint_lit(
|
|
&node.span,
|
|
&node.value.to_string(),
|
|
&raw_value,
|
|
&raw_bigint_value,
|
|
)
|
|
}
|
|
Lit::Regex(node) => {
|
|
let raw = format!("/{}/{}", node.exp.as_str(), node.flags.as_str());
|
|
|
|
ctx.write_regex_lit(
|
|
&node.span,
|
|
node.exp.as_str(),
|
|
node.flags.as_str(),
|
|
&raw,
|
|
&raw,
|
|
)
|
|
}
|
|
Lit::JSXText(node) => {
|
|
ctx.write_jsx_text(&node.span, &node.raw, &node.value)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serialize_class_member(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
member: &ClassMember,
|
|
) -> Option<NodeRef> {
|
|
match member {
|
|
ClassMember::Constructor(node) => {
|
|
let a11y = node.accessibility.as_ref().map(accessibility_to_str);
|
|
|
|
let key = serialize_prop_name(ctx, &node.key);
|
|
let params = node
|
|
.params
|
|
.iter()
|
|
.map(|param| match param {
|
|
ParamOrTsParamProp::TsParamProp(prop) => {
|
|
let a11y = node.accessibility.as_ref().map(accessibility_to_str);
|
|
|
|
let decorators = prop
|
|
.decorators
|
|
.iter()
|
|
.map(|deco| serialize_decorator(ctx, deco))
|
|
.collect::<Vec<_>>();
|
|
|
|
let paramter = match &prop.param {
|
|
TsParamPropParam::Ident(binding_ident) => {
|
|
serialize_binding_ident(ctx, binding_ident)
|
|
}
|
|
TsParamPropParam::Assign(assign_pat) => {
|
|
serialize_pat(ctx, &Pat::Assign(assign_pat.clone()))
|
|
}
|
|
};
|
|
|
|
ctx.write_ts_param_prop(
|
|
&prop.span,
|
|
prop.is_override,
|
|
prop.readonly,
|
|
a11y,
|
|
decorators,
|
|
paramter,
|
|
)
|
|
}
|
|
ParamOrTsParamProp::Param(param) => serialize_pat(ctx, ¶m.pat),
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let body = node
|
|
.body
|
|
.as_ref()
|
|
.map(|body| serialize_stmt(ctx, &Stmt::Block(body.clone())));
|
|
|
|
let value = ctx.write_fn_expr(
|
|
&node.span, false, false, None, None, params, None, body,
|
|
);
|
|
|
|
Some(ctx.write_class_method(
|
|
&node.span,
|
|
false,
|
|
false,
|
|
node.is_optional,
|
|
false,
|
|
false,
|
|
"constructor",
|
|
a11y,
|
|
key,
|
|
value,
|
|
))
|
|
}
|
|
ClassMember::Method(node) => {
|
|
let key = serialize_prop_name(ctx, &node.key);
|
|
|
|
Some(serialize_class_method(
|
|
ctx,
|
|
&node.span,
|
|
node.is_abstract,
|
|
node.is_override,
|
|
node.is_optional,
|
|
node.is_static,
|
|
node.accessibility,
|
|
&node.kind,
|
|
key,
|
|
&node.function,
|
|
))
|
|
}
|
|
ClassMember::PrivateMethod(node) => {
|
|
let key = serialize_private_name(ctx, &node.key);
|
|
|
|
Some(serialize_class_method(
|
|
ctx,
|
|
&node.span,
|
|
node.is_abstract,
|
|
node.is_override,
|
|
node.is_optional,
|
|
node.is_static,
|
|
node.accessibility,
|
|
&node.kind,
|
|
key,
|
|
&node.function,
|
|
))
|
|
}
|
|
ClassMember::ClassProp(node) => {
|
|
let a11y = node.accessibility.as_ref().map(accessibility_to_str);
|
|
|
|
let key = serialize_prop_name(ctx, &node.key);
|
|
let value = node.value.as_ref().map(|expr| serialize_expr(ctx, expr));
|
|
|
|
let decorators = node
|
|
.decorators
|
|
.iter()
|
|
.map(|deco| serialize_decorator(ctx, deco))
|
|
.collect::<Vec<_>>();
|
|
|
|
Some(ctx.write_class_prop(
|
|
&node.span,
|
|
node.declare,
|
|
false,
|
|
node.is_optional,
|
|
node.is_override,
|
|
node.readonly,
|
|
node.is_static,
|
|
a11y,
|
|
decorators,
|
|
key,
|
|
value,
|
|
))
|
|
}
|
|
ClassMember::PrivateProp(node) => {
|
|
let a11y = node.accessibility.as_ref().map(accessibility_to_str);
|
|
|
|
let decorators = node
|
|
.decorators
|
|
.iter()
|
|
.map(|deco| serialize_decorator(ctx, deco))
|
|
.collect::<Vec<_>>();
|
|
|
|
let key = serialize_private_name(ctx, &node.key);
|
|
|
|
let value = node.value.as_ref().map(|expr| serialize_expr(ctx, expr));
|
|
|
|
Some(ctx.write_class_prop(
|
|
&node.span,
|
|
false,
|
|
false,
|
|
node.is_optional,
|
|
node.is_override,
|
|
node.readonly,
|
|
node.is_static,
|
|
a11y,
|
|
decorators,
|
|
key,
|
|
value,
|
|
))
|
|
}
|
|
ClassMember::TsIndexSignature(node) => {
|
|
Some(serialize_ts_index_sig(ctx, node))
|
|
}
|
|
ClassMember::Empty(_) => None,
|
|
ClassMember::StaticBlock(node) => {
|
|
let body = serialize_stmt(ctx, &Stmt::Block(node.body.clone()));
|
|
Some(ctx.write_static_block(&node.span, body))
|
|
}
|
|
ClassMember::AutoAccessor(node) => {
|
|
let a11y = node.accessibility.as_ref().map(accessibility_to_str);
|
|
let decorators = node
|
|
.decorators
|
|
.iter()
|
|
.map(|deco| serialize_decorator(ctx, deco))
|
|
.collect::<Vec<_>>();
|
|
|
|
let key = match &node.key {
|
|
Key::Private(private_name) => serialize_private_name(ctx, private_name),
|
|
Key::Public(prop_name) => serialize_prop_name(ctx, prop_name),
|
|
};
|
|
|
|
let value = node.value.as_ref().map(|expr| serialize_expr(ctx, expr));
|
|
|
|
Some(ctx.write_accessor_property(
|
|
&node.span,
|
|
false,
|
|
false,
|
|
false,
|
|
node.is_override,
|
|
false,
|
|
node.is_static,
|
|
a11y,
|
|
decorators,
|
|
key,
|
|
value,
|
|
))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
fn serialize_class_method(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
span: &Span,
|
|
is_abstract: bool,
|
|
is_override: bool,
|
|
is_optional: bool,
|
|
is_static: bool,
|
|
accessibility: Option<Accessibility>,
|
|
method_kind: &MethodKind,
|
|
key: NodeRef,
|
|
function: &Function,
|
|
) -> NodeRef {
|
|
let kind = match method_kind {
|
|
MethodKind::Method => "method",
|
|
MethodKind::Getter => "getter",
|
|
MethodKind::Setter => "setter",
|
|
};
|
|
|
|
let type_params =
|
|
maybe_serialize_ts_type_param_decl(ctx, &function.type_params);
|
|
let params = function
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_pat(ctx, ¶m.pat))
|
|
.collect::<Vec<_>>();
|
|
|
|
let return_type = maybe_serialize_ts_type_ann(ctx, &function.return_type);
|
|
|
|
let body = function
|
|
.body
|
|
.as_ref()
|
|
.map(|body| serialize_stmt(ctx, &Stmt::Block(body.clone())));
|
|
|
|
let value = if let Some(body) = body {
|
|
ctx.write_fn_expr(
|
|
&function.span,
|
|
function.is_async,
|
|
function.is_generator,
|
|
None,
|
|
type_params,
|
|
params,
|
|
return_type,
|
|
Some(body),
|
|
)
|
|
} else {
|
|
ctx.write_ts_empty_body_fn_expr(
|
|
span,
|
|
false,
|
|
false,
|
|
function.is_async,
|
|
function.is_generator,
|
|
None,
|
|
type_params,
|
|
params,
|
|
return_type,
|
|
)
|
|
};
|
|
|
|
let a11y = accessibility.as_ref().map(accessibility_to_str);
|
|
|
|
if is_abstract {
|
|
ctx.write_ts_abstract_method_def(
|
|
span,
|
|
false,
|
|
is_optional,
|
|
is_override,
|
|
false,
|
|
a11y,
|
|
key,
|
|
value,
|
|
)
|
|
} else {
|
|
ctx.write_class_method(
|
|
span,
|
|
false,
|
|
false,
|
|
is_optional,
|
|
is_override,
|
|
is_static,
|
|
kind,
|
|
a11y,
|
|
key,
|
|
value,
|
|
)
|
|
}
|
|
}
|
|
|
|
fn serialize_ts_expr_with_type_args(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &TsExprWithTypeArgs,
|
|
) -> NodeRef {
|
|
let expr = serialize_expr(ctx, &node.expr);
|
|
let type_args = node
|
|
.type_args
|
|
.as_ref()
|
|
.map(|arg| serialize_ts_param_inst(ctx, arg));
|
|
|
|
ctx.write_ts_class_implements(&node.span, expr, type_args)
|
|
}
|
|
|
|
fn serialize_decorator(ctx: &mut TsEsTreeBuilder, node: &Decorator) -> NodeRef {
|
|
let expr = serialize_expr(ctx, &node.expr);
|
|
ctx.write_decorator(&node.span, expr)
|
|
}
|
|
|
|
fn serialize_binding_ident(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &BindingIdent,
|
|
) -> NodeRef {
|
|
let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann);
|
|
ctx.write_identifier(&node.span, &node.sym, node.optional, type_ann)
|
|
}
|
|
|
|
fn serialize_ts_param_inst(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &TsTypeParamInstantiation,
|
|
) -> NodeRef {
|
|
let params = node
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_ts_type(ctx, param))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_ts_type_param_inst(&node.span, params)
|
|
}
|
|
|
|
fn serialize_ts_type(ctx: &mut TsEsTreeBuilder, node: &TsType) -> NodeRef {
|
|
match node {
|
|
TsType::TsKeywordType(node) => {
|
|
let kind = match node.kind {
|
|
TsKeywordTypeKind::TsAnyKeyword => TsKeywordKind::Any,
|
|
TsKeywordTypeKind::TsUnknownKeyword => TsKeywordKind::Unknown,
|
|
TsKeywordTypeKind::TsNumberKeyword => TsKeywordKind::Number,
|
|
TsKeywordTypeKind::TsObjectKeyword => TsKeywordKind::Object,
|
|
TsKeywordTypeKind::TsBooleanKeyword => TsKeywordKind::Boolean,
|
|
TsKeywordTypeKind::TsBigIntKeyword => TsKeywordKind::BigInt,
|
|
TsKeywordTypeKind::TsStringKeyword => TsKeywordKind::String,
|
|
TsKeywordTypeKind::TsSymbolKeyword => TsKeywordKind::Symbol,
|
|
TsKeywordTypeKind::TsVoidKeyword => TsKeywordKind::Void,
|
|
TsKeywordTypeKind::TsUndefinedKeyword => TsKeywordKind::Undefined,
|
|
TsKeywordTypeKind::TsNullKeyword => TsKeywordKind::Null,
|
|
TsKeywordTypeKind::TsNeverKeyword => TsKeywordKind::Never,
|
|
TsKeywordTypeKind::TsIntrinsicKeyword => TsKeywordKind::Intrinsic,
|
|
};
|
|
|
|
ctx.write_ts_keyword(kind, &node.span)
|
|
}
|
|
TsType::TsThisType(node) => ctx.write_ts_this_type(&node.span),
|
|
TsType::TsFnOrConstructorType(node) => match node {
|
|
TsFnOrConstructorType::TsFnType(node) => {
|
|
let param_ids = node
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_ts_fn_param(ctx, param))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_ts_fn_type(&node.span, param_ids)
|
|
}
|
|
TsFnOrConstructorType::TsConstructorType(node) => {
|
|
// interface Foo { new<T>(arg1: any): any }
|
|
let type_params = node
|
|
.type_params
|
|
.as_ref()
|
|
.map(|param| serialize_ts_type_param_decl(ctx, param));
|
|
|
|
let params = node
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_ts_fn_param(ctx, param))
|
|
.collect::<Vec<_>>();
|
|
|
|
let return_type = serialize_ts_type_ann(ctx, node.type_ann.as_ref());
|
|
|
|
ctx.write_ts_construct_sig(&node.span, type_params, params, return_type)
|
|
}
|
|
},
|
|
TsType::TsTypeRef(node) => {
|
|
let name = serialize_ts_entity_name(ctx, &node.type_name);
|
|
|
|
let type_args = node
|
|
.type_params
|
|
.clone()
|
|
.map(|param| serialize_ts_param_inst(ctx, ¶m));
|
|
|
|
ctx.write_ts_type_ref(&node.span, name, type_args)
|
|
}
|
|
TsType::TsTypeQuery(node) => {
|
|
let expr_name = match &node.expr_name {
|
|
TsTypeQueryExpr::TsEntityName(entity) => {
|
|
serialize_ts_entity_name(ctx, entity)
|
|
}
|
|
TsTypeQueryExpr::Import(child) => {
|
|
serialize_ts_type(ctx, &TsType::TsImportType(child.clone()))
|
|
}
|
|
};
|
|
|
|
let type_args = node
|
|
.type_args
|
|
.clone()
|
|
.map(|param| serialize_ts_param_inst(ctx, ¶m));
|
|
|
|
ctx.write_ts_type_query(&node.span, expr_name, type_args)
|
|
}
|
|
TsType::TsTypeLit(node) => {
|
|
let members = node
|
|
.members
|
|
.iter()
|
|
.map(|member| serialize_ts_type_elem(ctx, member))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_ts_type_lit(&node.span, members)
|
|
}
|
|
TsType::TsArrayType(node) => {
|
|
let elem = serialize_ts_type(ctx, &node.elem_type);
|
|
ctx.write_ts_array_type(&node.span, elem)
|
|
}
|
|
TsType::TsTupleType(node) => {
|
|
let children = node
|
|
.elem_types
|
|
.iter()
|
|
.map(|elem| {
|
|
if let Some(label) = &elem.label {
|
|
let label = serialize_pat(ctx, label);
|
|
let type_id = serialize_ts_type(ctx, elem.ty.as_ref());
|
|
|
|
ctx.write_ts_named_tuple_member(&elem.span, label, type_id)
|
|
} else {
|
|
serialize_ts_type(ctx, elem.ty.as_ref())
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_ts_tuple_type(&node.span, children)
|
|
}
|
|
TsType::TsOptionalType(node) => {
|
|
let type_ann = serialize_ts_type(ctx, &node.type_ann);
|
|
ctx.write_ts_optional_type(&node.span, type_ann)
|
|
}
|
|
TsType::TsRestType(node) => {
|
|
let type_ann = serialize_ts_type(ctx, &node.type_ann);
|
|
ctx.write_ts_rest_type(&node.span, type_ann)
|
|
}
|
|
TsType::TsUnionOrIntersectionType(node) => match node {
|
|
TsUnionOrIntersectionType::TsUnionType(node) => {
|
|
let children = node
|
|
.types
|
|
.iter()
|
|
.map(|item| serialize_ts_type(ctx, item))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_ts_union_type(&node.span, children)
|
|
}
|
|
TsUnionOrIntersectionType::TsIntersectionType(node) => {
|
|
let children = node
|
|
.types
|
|
.iter()
|
|
.map(|item| serialize_ts_type(ctx, item))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_ts_intersection_type(&node.span, children)
|
|
}
|
|
},
|
|
TsType::TsConditionalType(node) => {
|
|
let check = serialize_ts_type(ctx, &node.check_type);
|
|
let extends = serialize_ts_type(ctx, &node.extends_type);
|
|
let v_true = serialize_ts_type(ctx, &node.true_type);
|
|
let v_false = serialize_ts_type(ctx, &node.false_type);
|
|
|
|
ctx.write_ts_conditional_type(&node.span, check, extends, v_true, v_false)
|
|
}
|
|
TsType::TsInferType(node) => {
|
|
let param = serialize_ts_type_param(ctx, &node.type_param);
|
|
ctx.write_ts_infer_type(&node.span, param)
|
|
}
|
|
TsType::TsParenthesizedType(node) => {
|
|
// Not materialized in TSEstree
|
|
serialize_ts_type(ctx, &node.type_ann)
|
|
}
|
|
TsType::TsTypeOperator(node) => {
|
|
let type_ann = serialize_ts_type(ctx, &node.type_ann);
|
|
|
|
let op = match node.op {
|
|
TsTypeOperatorOp::KeyOf => "keyof",
|
|
TsTypeOperatorOp::Unique => "unique",
|
|
TsTypeOperatorOp::ReadOnly => "readonly",
|
|
};
|
|
|
|
ctx.write_ts_type_op(&node.span, op, type_ann)
|
|
}
|
|
TsType::TsIndexedAccessType(node) => {
|
|
let index = serialize_ts_type(ctx, &node.index_type);
|
|
let obj = serialize_ts_type(ctx, &node.obj_type);
|
|
|
|
ctx.write_ts_indexed_access_type(&node.span, index, obj)
|
|
}
|
|
TsType::TsMappedType(node) => {
|
|
let name = maybe_serialize_ts_type(ctx, &node.name_type);
|
|
let type_ann = maybe_serialize_ts_type(ctx, &node.type_ann);
|
|
let type_param = serialize_ts_type_param(ctx, &node.type_param);
|
|
|
|
ctx.write_ts_mapped_type(
|
|
&node.span,
|
|
node.readonly,
|
|
node.optional,
|
|
name,
|
|
type_ann,
|
|
type_param,
|
|
)
|
|
}
|
|
TsType::TsLitType(node) => serialize_ts_lit_type(ctx, node),
|
|
TsType::TsTypePredicate(node) => {
|
|
let param_name = match &node.param_name {
|
|
TsThisTypeOrIdent::TsThisType(node) => {
|
|
ctx.write_ts_this_type(&node.span)
|
|
}
|
|
TsThisTypeOrIdent::Ident(ident) => serialize_ident(ctx, ident, None),
|
|
};
|
|
|
|
let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann);
|
|
|
|
ctx.write_ts_type_predicate(
|
|
&node.span,
|
|
node.asserts,
|
|
param_name,
|
|
type_ann,
|
|
)
|
|
}
|
|
TsType::TsImportType(node) => {
|
|
let arg = serialize_ts_lit_type(
|
|
ctx,
|
|
&TsLitType {
|
|
lit: TsLit::Str(node.arg.clone()),
|
|
span: node.arg.span,
|
|
},
|
|
);
|
|
|
|
let type_arg = node
|
|
.type_args
|
|
.clone()
|
|
.map(|param_node| serialize_ts_param_inst(ctx, param_node.as_ref()));
|
|
|
|
let qualifier = node
|
|
.qualifier
|
|
.clone()
|
|
.map(|quali| serialize_ts_entity_name(ctx, &quali));
|
|
|
|
ctx.write_ts_import_type(&node.span, arg, qualifier, type_arg)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serialize_ts_lit_type(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &TsLitType,
|
|
) -> NodeRef {
|
|
match &node.lit {
|
|
TsLit::Number(lit) => {
|
|
let lit = serialize_lit(ctx, &Lit::Num(lit.clone()));
|
|
ctx.write_ts_lit_type(&node.span, lit)
|
|
}
|
|
TsLit::Str(lit) => {
|
|
let lit = serialize_lit(ctx, &Lit::Str(lit.clone()));
|
|
ctx.write_ts_lit_type(&node.span, lit)
|
|
}
|
|
TsLit::Bool(lit) => {
|
|
let lit = serialize_lit(ctx, &Lit::Bool(*lit));
|
|
ctx.write_ts_lit_type(&node.span, lit)
|
|
}
|
|
TsLit::BigInt(lit) => {
|
|
let lit = serialize_lit(ctx, &Lit::BigInt(lit.clone()));
|
|
ctx.write_ts_lit_type(&node.span, lit)
|
|
}
|
|
TsLit::Tpl(lit) => {
|
|
let quasis = lit
|
|
.quasis
|
|
.iter()
|
|
.map(|quasi| {
|
|
ctx.write_template_elem(
|
|
&quasi.span,
|
|
quasi.tail,
|
|
&quasi.raw,
|
|
&quasi
|
|
.cooked
|
|
.as_ref()
|
|
.map_or("".to_string(), |v| v.to_string()),
|
|
)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
let types = lit
|
|
.types
|
|
.iter()
|
|
.map(|ts_type| serialize_ts_type(ctx, ts_type))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_ts_tpl_lit(&node.span, quasis, types)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serialize_ts_entity_name(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &TsEntityName,
|
|
) -> NodeRef {
|
|
match &node {
|
|
TsEntityName::TsQualifiedName(node) => {
|
|
let left = serialize_ts_entity_name(ctx, &node.left);
|
|
let right = serialize_ident_name(ctx, &node.right);
|
|
|
|
ctx.write_ts_qualified_name(&node.span, left, right)
|
|
}
|
|
TsEntityName::Ident(ident) => serialize_ident(ctx, ident, None),
|
|
}
|
|
}
|
|
|
|
fn maybe_serialize_ts_type_ann(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &Option<Box<TsTypeAnn>>,
|
|
) -> Option<NodeRef> {
|
|
node
|
|
.as_ref()
|
|
.map(|type_ann| serialize_ts_type_ann(ctx, type_ann))
|
|
}
|
|
|
|
fn serialize_ts_type_ann(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &TsTypeAnn,
|
|
) -> NodeRef {
|
|
let v_type = serialize_ts_type(ctx, &node.type_ann);
|
|
ctx.write_ts_type_ann(&node.span, v_type)
|
|
}
|
|
|
|
fn maybe_serialize_ts_type(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &Option<Box<TsType>>,
|
|
) -> Option<NodeRef> {
|
|
node.as_ref().map(|item| serialize_ts_type(ctx, item))
|
|
}
|
|
|
|
fn serialize_ts_type_param(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &TsTypeParam,
|
|
) -> NodeRef {
|
|
let name = serialize_ident(ctx, &node.name, None);
|
|
let constraint = maybe_serialize_ts_type(ctx, &node.constraint);
|
|
let default = maybe_serialize_ts_type(ctx, &node.default);
|
|
|
|
ctx.write_ts_type_param(
|
|
&node.span,
|
|
node.is_in,
|
|
node.is_out,
|
|
node.is_const,
|
|
name,
|
|
constraint,
|
|
default,
|
|
)
|
|
}
|
|
|
|
fn maybe_serialize_ts_type_param_decl(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &Option<Box<TsTypeParamDecl>>,
|
|
) -> Option<NodeRef> {
|
|
node
|
|
.as_ref()
|
|
.map(|node| serialize_ts_type_param_decl(ctx, node))
|
|
}
|
|
|
|
fn serialize_ts_type_param_decl(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &TsTypeParamDecl,
|
|
) -> NodeRef {
|
|
let params = node
|
|
.params
|
|
.iter()
|
|
.map(|param| serialize_ts_type_param(ctx, param))
|
|
.collect::<Vec<_>>();
|
|
|
|
ctx.write_ts_type_param_decl(&node.span, params)
|
|
}
|
|
|
|
fn serialize_ts_fn_param(
|
|
ctx: &mut TsEsTreeBuilder,
|
|
node: &TsFnParam,
|
|
) -> NodeRef {
|
|
match node {
|
|
TsFnParam::Ident(ident) => serialize_binding_ident(ctx, ident),
|
|
TsFnParam::Array(pat) => serialize_pat(ctx, &Pat::Array(pat.clone())),
|
|
TsFnParam::Rest(pat) => serialize_pat(ctx, &Pat::Rest(pat.clone())),
|
|
TsFnParam::Object(pat) => serialize_pat(ctx, &Pat::Object(pat.clone())),
|
|
}
|
|
}
|