use proc_macro2::TokenStream;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct IrSpan {
pub start: usize,
pub end: usize,
}
impl IrSpan {
pub fn new(start: usize, end: usize) -> Self {
Self { start, end }
}
pub fn at(pos: usize) -> Self {
Self {
start: pos,
end: pos,
}
}
pub fn empty() -> Self {
Self::default()
}
pub fn extend(self, other: IrSpan) -> Self {
Self {
start: self.start.min(other.start),
end: self.end.max(other.end),
}
}
pub fn from_pos_len(start: usize, len: usize) -> Self {
Self {
start,
end: start + len,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PlaceholderKind {
Expr,
Type,
Ident,
Stmt,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VarKind {
Const,
Let,
Var,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Accessibility {
Public,
Private,
Protected,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MethodKind {
Method,
Getter,
Setter,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
Add, Sub, Mul, Div, Mod, Exp,
EqEq, NotEq, EqEqEq, NotEqEq, Lt, Le, Gt, Ge,
And, Or, NullishCoalesce,
BitAnd, BitOr, BitXor, Shl, Shr, UShr,
In, InstanceOf, }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AssignOp {
Assign, AddAssign, SubAssign, MulAssign, DivAssign, ModAssign, ExpAssign, ShlAssign, ShrAssign, UShrAssign, BitAndAssign, BitOrAssign, BitXorAssign, AndAssign, OrAssign, NullishAssign, }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
Minus, Plus, Not, BitNot, TypeOf, Void, Delete, }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UpdateOp {
Increment, Decrement, }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TsKeyword {
Any,
Unknown,
String,
Number,
Boolean,
Void,
Null,
Undefined,
Never,
Object,
BigInt,
Symbol,
}
#[derive(Debug, Clone)]
pub enum IrNode {
FnDecl {
span: IrSpan,
exported: bool,
declare: bool,
async_: bool,
generator: bool,
name: Box<IrNode>,
type_params: Option<Box<IrNode>>,
params: Vec<IrNode>,
return_type: Option<Box<IrNode>>,
body: Option<Box<IrNode>>,
},
ClassDecl {
span: IrSpan,
exported: bool,
declare: bool,
abstract_: bool,
decorators: Vec<IrNode>,
name: Box<IrNode>,
type_params: Option<Box<IrNode>>,
extends: Option<Box<IrNode>>,
implements: Vec<IrNode>,
body: Vec<IrNode>,
},
InterfaceDecl {
span: IrSpan,
exported: bool,
declare: bool,
name: Box<IrNode>,
type_params: Option<Box<IrNode>>,
extends: Vec<IrNode>,
body: Vec<IrNode>,
},
TypeAliasDecl {
span: IrSpan,
exported: bool,
declare: bool,
name: Box<IrNode>,
type_params: Option<Box<IrNode>>,
type_ann: Box<IrNode>,
},
VarDecl {
span: IrSpan,
exported: bool,
declare: bool,
kind: VarKind,
decls: Vec<VarDeclarator>,
},
EnumDecl {
span: IrSpan,
exported: bool,
declare: bool,
const_: bool,
name: Box<IrNode>,
members: Vec<IrNode>,
},
Constructor {
span: IrSpan,
accessibility: Option<Accessibility>,
params: Vec<IrNode>,
body: Option<Box<IrNode>>,
},
Method {
span: IrSpan,
static_: bool,
accessibility: Option<Accessibility>,
readonly: bool,
async_: bool,
generator: bool,
kind: MethodKind,
name: Box<IrNode>,
optional: bool,
type_params: Option<Box<IrNode>>,
params: Vec<IrNode>,
return_type: Option<Box<IrNode>>,
body: Option<Box<IrNode>>,
},
ClassProp {
span: IrSpan,
static_: bool,
accessibility: Option<Accessibility>,
readonly: bool,
declare: bool,
optional: bool,
definite: bool,
name: Box<IrNode>,
type_ann: Option<Box<IrNode>>,
value: Option<Box<IrNode>>,
},
IndexSignature {
span: IrSpan,
readonly: bool,
params: Vec<IrNode>,
type_ann: Box<IrNode>,
},
PropSignature {
span: IrSpan,
readonly: bool,
name: Box<IrNode>,
optional: bool,
type_ann: Option<Box<IrNode>>,
},
MethodSignature {
span: IrSpan,
name: Box<IrNode>,
optional: bool,
type_params: Option<Box<IrNode>>,
params: Vec<IrNode>,
return_type: Option<Box<IrNode>>,
},
BlockStmt { span: IrSpan, stmts: Vec<IrNode> },
ExprStmt { span: IrSpan, expr: Box<IrNode> },
ReturnStmt {
span: IrSpan,
arg: Option<Box<IrNode>>,
},
ThrowStmt { span: IrSpan, arg: Box<IrNode> },
TsIfStmt {
span: IrSpan,
test: Box<IrNode>,
cons: Box<IrNode>,
alt: Option<Box<IrNode>>,
},
ForInStmt {
span: IrSpan,
left: Box<IrNode>,
right: Box<IrNode>,
body: Box<IrNode>,
},
ForOfStmt {
span: IrSpan,
await_: bool,
left: Box<IrNode>,
right: Box<IrNode>,
body: Box<IrNode>,
},
TsForStmt {
span: IrSpan,
init: Option<Box<IrNode>>,
test: Option<Box<IrNode>>,
update: Option<Box<IrNode>>,
body: Box<IrNode>,
},
TsWhileStmt {
span: IrSpan,
test: Box<IrNode>,
body: Box<IrNode>,
},
TsDoWhileStmt {
span: IrSpan,
body: Box<IrNode>,
test: Box<IrNode>,
},
TsTryStmt {
span: IrSpan,
block: Box<IrNode>,
handler: Option<TsCatchClause>,
finalizer: Option<Box<IrNode>>,
},
EmptyStmt { span: IrSpan },
Ident { span: IrSpan, value: String },
PrivateName { span: IrSpan, value: String },
StrLit { span: IrSpan, value: String },
NumLit { span: IrSpan, value: String },
BigIntLit { span: IrSpan, value: String },
BoolLit { span: IrSpan, value: bool },
NullLit { span: IrSpan },
ThisExpr { span: IrSpan },
SuperExpr { span: IrSpan },
CallExpr {
span: IrSpan,
callee: Box<IrNode>,
type_args: Option<Box<IrNode>>,
args: Vec<IrNode>,
},
NewExpr {
span: IrSpan,
callee: Box<IrNode>,
type_args: Option<Box<IrNode>>,
args: Vec<IrNode>,
},
MemberExpr {
span: IrSpan,
obj: Box<IrNode>,
prop: Box<IrNode>,
computed: bool,
},
OptChainExpr {
span: IrSpan,
base: Box<IrNode>,
expr: Box<IrNode>,
},
ObjectLit { span: IrSpan, props: Vec<IrNode> },
ArrayLit { span: IrSpan, elems: Vec<IrNode> },
ArrowExpr {
span: IrSpan,
async_: bool,
type_params: Option<Box<IrNode>>,
params: Vec<IrNode>,
return_type: Option<Box<IrNode>>,
body: Box<IrNode>, },
FnExpr {
span: IrSpan,
async_: bool,
generator: bool,
name: Option<Box<IrNode>>,
type_params: Option<Box<IrNode>>,
params: Vec<IrNode>,
return_type: Option<Box<IrNode>>,
body: Option<Box<IrNode>>,
},
ClassExpr {
span: IrSpan,
name: Option<Box<IrNode>>,
type_params: Option<Box<IrNode>>,
extends: Option<Box<IrNode>>,
implements: Vec<IrNode>,
body: Vec<IrNode>,
},
BinExpr {
span: IrSpan,
left: Box<IrNode>,
op: BinaryOp,
right: Box<IrNode>,
},
AssignExpr {
span: IrSpan,
left: Box<IrNode>,
op: AssignOp,
right: Box<IrNode>,
},
UnaryExpr {
span: IrSpan,
op: UnaryOp,
arg: Box<IrNode>,
},
UpdateExpr {
span: IrSpan,
op: UpdateOp,
prefix: bool,
arg: Box<IrNode>,
},
CondExpr {
span: IrSpan,
test: Box<IrNode>,
consequent: Box<IrNode>,
alternate: Box<IrNode>,
},
SeqExpr { span: IrSpan, exprs: Vec<IrNode> },
TplLit {
span: IrSpan,
quasis: Vec<String>,
exprs: Vec<IrNode>,
},
TaggedTpl {
span: IrSpan,
tag: Box<IrNode>,
type_args: Option<Box<IrNode>>,
tpl: Box<IrNode>,
},
ParenExpr { span: IrSpan, expr: Box<IrNode> },
AwaitExpr { span: IrSpan, arg: Box<IrNode> },
YieldExpr {
span: IrSpan,
delegate: bool,
arg: Option<Box<IrNode>>,
},
TsAsExpr {
span: IrSpan,
expr: Box<IrNode>,
type_ann: Box<IrNode>,
},
TsConstAssertion { span: IrSpan, expr: Box<IrNode> },
TsSatisfiesExpr {
span: IrSpan,
expr: Box<IrNode>,
type_ann: Box<IrNode>,
},
TsNonNullExpr { span: IrSpan, expr: Box<IrNode> },
TsInstantiation {
span: IrSpan,
expr: Box<IrNode>,
type_args: Box<IrNode>,
},
KeyValueProp {
span: IrSpan,
key: Box<IrNode>,
value: Box<IrNode>,
},
ShorthandProp { span: IrSpan, key: Box<IrNode> },
SpreadElement { span: IrSpan, expr: Box<IrNode> },
ComputedPropName { span: IrSpan, expr: Box<IrNode> },
MethodProp {
span: IrSpan,
async_: bool,
generator: bool,
name: Box<IrNode>,
type_params: Option<Box<IrNode>>,
params: Vec<IrNode>,
return_type: Option<Box<IrNode>>,
body: Box<IrNode>,
},
GetterProp {
span: IrSpan,
name: Box<IrNode>,
type_ann: Option<Box<IrNode>>,
body: Box<IrNode>,
},
SetterProp {
span: IrSpan,
name: Box<IrNode>,
param: Box<IrNode>,
body: Box<IrNode>,
},
Param {
span: IrSpan,
decorators: Vec<IrNode>,
pat: Box<IrNode>,
},
BindingIdent {
span: IrSpan,
name: Box<IrNode>,
type_ann: Option<Box<IrNode>>,
optional: bool,
},
RestPat {
span: IrSpan,
arg: Box<IrNode>,
type_ann: Option<Box<IrNode>>,
},
AssignPat {
span: IrSpan,
left: Box<IrNode>,
right: Box<IrNode>,
},
ArrayPat {
span: IrSpan,
elems: Vec<Option<IrNode>>,
type_ann: Option<Box<IrNode>>,
optional: bool,
},
ObjectPat {
span: IrSpan,
props: Vec<IrNode>,
type_ann: Option<Box<IrNode>>,
optional: bool,
},
ObjectPatProp {
span: IrSpan,
key: Box<IrNode>,
value: Option<Box<IrNode>>,
},
TypeAnnotation { span: IrSpan, type_ann: Box<IrNode> },
TypeRef {
span: IrSpan,
name: Box<IrNode>,
type_params: Option<Box<IrNode>>,
},
QualifiedName {
span: IrSpan,
left: Box<IrNode>,
right: Box<IrNode>,
},
TypeParams { span: IrSpan, params: Vec<IrNode> },
TypeParam {
span: IrSpan,
name: String,
constraint: Option<Box<IrNode>>,
default: Option<Box<IrNode>>,
},
TypeArgs { span: IrSpan, args: Vec<IrNode> },
KeywordType { span: IrSpan, keyword: TsKeyword },
LiteralType { span: IrSpan, lit: Box<IrNode> },
UnionType { span: IrSpan, types: Vec<IrNode> },
IntersectionType { span: IrSpan, types: Vec<IrNode> },
ArrayType { span: IrSpan, elem: Box<IrNode> },
TupleType { span: IrSpan, elems: Vec<IrNode> },
OptionalType { span: IrSpan, type_ann: Box<IrNode> },
RestType { span: IrSpan, type_ann: Box<IrNode> },
FnType {
span: IrSpan,
type_params: Option<Box<IrNode>>,
params: Vec<IrNode>,
return_type: Box<IrNode>,
},
ConstructorType {
span: IrSpan,
type_params: Option<Box<IrNode>>,
params: Vec<IrNode>,
return_type: Box<IrNode>,
},
ObjectType { span: IrSpan, members: Vec<IrNode> },
ParenType { span: IrSpan, type_ann: Box<IrNode> },
TypeofType { span: IrSpan, expr: Box<IrNode> },
KeyofType { span: IrSpan, type_ann: Box<IrNode> },
IndexedAccessType {
span: IrSpan,
obj: Box<IrNode>,
index: Box<IrNode>,
},
ConditionalType {
span: IrSpan,
check: Box<IrNode>,
extends: Box<IrNode>,
true_type: Box<IrNode>,
false_type: Box<IrNode>,
},
InferType {
span: IrSpan,
type_param: Box<IrNode>,
},
MappedType {
span: IrSpan,
readonly: Option<bool>, type_param: Box<IrNode>,
name_type: Option<Box<IrNode>>,
optional: Option<bool>,
type_ann: Option<Box<IrNode>>,
},
ImportType {
span: IrSpan,
arg: Box<IrNode>,
qualifier: Option<Box<IrNode>>,
type_args: Option<Box<IrNode>>,
},
ThisType { span: IrSpan },
TypePredicate {
span: IrSpan,
asserts: bool,
param_name: Box<IrNode>,
type_ann: Option<Box<IrNode>>,
},
Placeholder {
span: IrSpan,
kind: PlaceholderKind,
expr: TokenStream,
},
If {
span: IrSpan,
condition: TokenStream,
then_body: Vec<IrNode>,
else_if_branches: Vec<(TokenStream, Vec<IrNode>)>,
else_body: Option<Vec<IrNode>>,
},
For {
span: IrSpan,
pattern: TokenStream,
iterator: TokenStream,
body: Vec<IrNode>,
},
While {
span: IrSpan,
condition: TokenStream,
body: Vec<IrNode>,
},
Match {
span: IrSpan,
expr: TokenStream,
arms: Vec<MatchArm>,
},
Let {
span: IrSpan,
pattern: TokenStream,
mutable: bool,
type_hint: Option<TokenStream>,
value: TokenStream,
},
Do { span: IrSpan, code: TokenStream },
IfExpr {
span: IrSpan,
condition: TokenStream,
then_expr: Box<IrNode>,
else_if_branches: Vec<(TokenStream, Box<IrNode>)>,
else_expr: Box<IrNode>,
},
ForExpr {
span: IrSpan,
pattern: TokenStream,
iterator: TokenStream,
body_expr: Box<IrNode>,
},
WhileExpr {
span: IrSpan,
condition: TokenStream,
body_expr: Box<IrNode>,
},
MatchExpr {
span: IrSpan,
expr: TokenStream,
arms: Vec<MatchArmExpr>,
},
TypeScript { span: IrSpan, stream: TokenStream },
LineComment { span: IrSpan, text: String },
BlockComment { span: IrSpan, text: String },
DocComment { span: IrSpan, text: String },
Documented {
span: IrSpan,
doc: String,
inner: Box<IrNode>,
},
IdentBlock { span: IrSpan, parts: Vec<IrNode> },
StringInterp {
span: IrSpan,
quote: char,
parts: Vec<IrNode>,
},
EnumMember {
span: IrSpan,
name: Box<IrNode>,
init: Option<Box<IrNode>>,
},
Decorator { span: IrSpan, expr: Box<IrNode> },
ImportDecl {
span: IrSpan,
type_only: bool,
specifiers: Vec<IrNode>,
src: String,
},
NamedImport {
span: IrSpan,
local: Box<IrNode>,
imported: Option<Box<IrNode>>,
type_only: bool,
},
DefaultImport { span: IrSpan, local: Box<IrNode> },
NamespaceImport { span: IrSpan, local: Box<IrNode> },
NamedExport {
span: IrSpan,
specifiers: Vec<IrNode>,
src: Option<String>,
type_only: bool,
},
ExportSpecifier {
span: IrSpan,
local: Box<IrNode>,
exported: Option<Box<IrNode>>,
type_only: bool,
},
ExportDefaultExpr { span: IrSpan, expr: Box<IrNode> },
ExportAll {
span: IrSpan,
src: String,
type_only: bool,
},
}
#[derive(Debug, Clone)]
pub struct VarDeclarator {
pub span: IrSpan,
pub name: Box<IrNode>,
pub type_ann: Option<Box<IrNode>>,
pub init: Option<Box<IrNode>>,
pub definite: bool,
}
#[derive(Debug, Clone)]
pub struct TsCatchClause {
pub span: IrSpan,
pub param: Option<Box<IrNode>>,
pub body: Box<IrNode>,
}
#[derive(Debug, Clone)]
pub struct MatchArm {
pub span: IrSpan,
pub pattern: TokenStream,
pub guard: Option<TokenStream>,
pub body: Vec<IrNode>,
}
#[derive(Debug, Clone)]
pub struct MatchArmExpr {
pub span: IrSpan,
pub pattern: TokenStream,
pub guard: Option<TokenStream>,
pub body_expr: Box<IrNode>,
}
#[derive(Debug)]
pub struct Ir {
pub nodes: Vec<IrNode>,
}
impl Ir {
pub fn new() -> Self {
Self { nodes: Vec::new() }
}
pub fn with_nodes(nodes: Vec<IrNode>) -> Self {
Self { nodes }
}
}
impl Default for Ir {
fn default() -> Self {
Self::new()
}
}
pub trait IntoIrNode {
fn text(&self) -> &str;
fn ir_span(&self) -> IrSpan;
}
impl IrNode {
pub fn ident(token: &impl IntoIrNode) -> Self {
IrNode::Ident {
span: token.ir_span(),
value: token.text().to_string(),
}
}
pub fn num_lit(token: &impl IntoIrNode) -> Self {
IrNode::NumLit {
span: token.ir_span(),
value: token.text().to_string(),
}
}
pub fn bool_lit(token: &impl IntoIrNode) -> Self {
IrNode::BoolLit {
span: token.ir_span(),
value: token.text() == "true",
}
}
pub fn bigint_lit(token: &impl IntoIrNode) -> Self {
let text = token.text();
let value = text.strip_suffix('n').unwrap_or(text);
IrNode::BigIntLit {
span: token.ir_span(),
value: value.to_string(),
}
}
pub fn private_name(token: &impl IntoIrNode) -> Self {
let text = token.text();
let value = text.strip_prefix('#').unwrap_or(text);
IrNode::PrivateName {
span: token.ir_span(),
value: value.to_string(),
}
}
pub fn null_lit(token: &impl IntoIrNode) -> Self {
IrNode::NullLit {
span: token.ir_span(),
}
}
pub fn this_expr(token: &impl IntoIrNode) -> Self {
IrNode::ThisExpr {
span: token.ir_span(),
}
}
pub fn super_expr(token: &impl IntoIrNode) -> Self {
IrNode::SuperExpr {
span: token.ir_span(),
}
}
pub fn empty_stmt(token: &impl IntoIrNode) -> Self {
IrNode::EmptyStmt {
span: token.ir_span(),
}
}
pub fn keyword_type(token: &impl IntoIrNode, keyword: TsKeyword) -> Self {
IrNode::KeywordType {
span: token.ir_span(),
keyword,
}
}
pub fn this_type(token: &impl IntoIrNode) -> Self {
IrNode::ThisType {
span: token.ir_span(),
}
}
pub fn ident_with(token: &impl IntoIrNode, value: impl Into<String>) -> Self {
IrNode::Ident {
span: token.ir_span(),
value: value.into(),
}
}
pub fn span(&self) -> IrSpan {
match self {
IrNode::FnDecl { span, .. } => *span,
IrNode::ClassDecl { span, .. } => *span,
IrNode::InterfaceDecl { span, .. } => *span,
IrNode::TypeAliasDecl { span, .. } => *span,
IrNode::VarDecl { span, .. } => *span,
IrNode::EnumDecl { span, .. } => *span,
IrNode::Constructor { span, .. } => *span,
IrNode::Method { span, .. } => *span,
IrNode::ClassProp { span, .. } => *span,
IrNode::IndexSignature { span, .. } => *span,
IrNode::PropSignature { span, .. } => *span,
IrNode::MethodSignature { span, .. } => *span,
IrNode::BlockStmt { span, .. } => *span,
IrNode::ExprStmt { span, .. } => *span,
IrNode::ReturnStmt { span, .. } => *span,
IrNode::ThrowStmt { span, .. } => *span,
IrNode::TsIfStmt { span, .. } => *span,
IrNode::ForInStmt { span, .. } => *span,
IrNode::ForOfStmt { span, .. } => *span,
IrNode::TsForStmt { span, .. } => *span,
IrNode::TsWhileStmt { span, .. } => *span,
IrNode::TsDoWhileStmt { span, .. } => *span,
IrNode::TsTryStmt { span, .. } => *span,
IrNode::EmptyStmt { span } => *span,
IrNode::Ident { span, .. } => *span,
IrNode::PrivateName { span, .. } => *span,
IrNode::StrLit { span, .. } => *span,
IrNode::NumLit { span, .. } => *span,
IrNode::BigIntLit { span, .. } => *span,
IrNode::BoolLit { span, .. } => *span,
IrNode::NullLit { span } => *span,
IrNode::ThisExpr { span } => *span,
IrNode::SuperExpr { span } => *span,
IrNode::CallExpr { span, .. } => *span,
IrNode::NewExpr { span, .. } => *span,
IrNode::MemberExpr { span, .. } => *span,
IrNode::OptChainExpr { span, .. } => *span,
IrNode::ObjectLit { span, .. } => *span,
IrNode::ArrayLit { span, .. } => *span,
IrNode::ArrowExpr { span, .. } => *span,
IrNode::FnExpr { span, .. } => *span,
IrNode::ClassExpr { span, .. } => *span,
IrNode::BinExpr { span, .. } => *span,
IrNode::AssignExpr { span, .. } => *span,
IrNode::UnaryExpr { span, .. } => *span,
IrNode::UpdateExpr { span, .. } => *span,
IrNode::CondExpr { span, .. } => *span,
IrNode::SeqExpr { span, .. } => *span,
IrNode::TplLit { span, .. } => *span,
IrNode::TaggedTpl { span, .. } => *span,
IrNode::ParenExpr { span, .. } => *span,
IrNode::AwaitExpr { span, .. } => *span,
IrNode::YieldExpr { span, .. } => *span,
IrNode::TsAsExpr { span, .. } => *span,
IrNode::TsConstAssertion { span, .. } => *span,
IrNode::TsSatisfiesExpr { span, .. } => *span,
IrNode::TsNonNullExpr { span, .. } => *span,
IrNode::TsInstantiation { span, .. } => *span,
IrNode::KeyValueProp { span, .. } => *span,
IrNode::ShorthandProp { span, .. } => *span,
IrNode::SpreadElement { span, .. } => *span,
IrNode::ComputedPropName { span, .. } => *span,
IrNode::MethodProp { span, .. } => *span,
IrNode::GetterProp { span, .. } => *span,
IrNode::SetterProp { span, .. } => *span,
IrNode::Param { span, .. } => *span,
IrNode::BindingIdent { span, .. } => *span,
IrNode::RestPat { span, .. } => *span,
IrNode::AssignPat { span, .. } => *span,
IrNode::ArrayPat { span, .. } => *span,
IrNode::ObjectPat { span, .. } => *span,
IrNode::ObjectPatProp { span, .. } => *span,
IrNode::TypeAnnotation { span, .. } => *span,
IrNode::TypeRef { span, .. } => *span,
IrNode::QualifiedName { span, .. } => *span,
IrNode::TypeParams { span, .. } => *span,
IrNode::TypeParam { span, .. } => *span,
IrNode::TypeArgs { span, .. } => *span,
IrNode::KeywordType { span, .. } => *span,
IrNode::LiteralType { span, .. } => *span,
IrNode::UnionType { span, .. } => *span,
IrNode::IntersectionType { span, .. } => *span,
IrNode::ArrayType { span, .. } => *span,
IrNode::TupleType { span, .. } => *span,
IrNode::OptionalType { span, .. } => *span,
IrNode::RestType { span, .. } => *span,
IrNode::FnType { span, .. } => *span,
IrNode::ConstructorType { span, .. } => *span,
IrNode::ObjectType { span, .. } => *span,
IrNode::ParenType { span, .. } => *span,
IrNode::TypeofType { span, .. } => *span,
IrNode::KeyofType { span, .. } => *span,
IrNode::IndexedAccessType { span, .. } => *span,
IrNode::ConditionalType { span, .. } => *span,
IrNode::InferType { span, .. } => *span,
IrNode::MappedType { span, .. } => *span,
IrNode::ImportType { span, .. } => *span,
IrNode::ThisType { span } => *span,
IrNode::TypePredicate { span, .. } => *span,
IrNode::Placeholder { span, .. } => *span,
IrNode::If { span, .. } => *span,
IrNode::For { span, .. } => *span,
IrNode::While { span, .. } => *span,
IrNode::Match { span, .. } => *span,
IrNode::Let { span, .. } => *span,
IrNode::Do { span, .. } => *span,
IrNode::IfExpr { span, .. } => *span,
IrNode::ForExpr { span, .. } => *span,
IrNode::WhileExpr { span, .. } => *span,
IrNode::MatchExpr { span, .. } => *span,
IrNode::TypeScript { span, .. } => *span,
IrNode::LineComment { span, .. } => *span,
IrNode::BlockComment { span, .. } => *span,
IrNode::DocComment { span, .. } => *span,
IrNode::Documented { span, .. } => *span,
IrNode::IdentBlock { span, .. } => *span,
IrNode::StringInterp { span, .. } => *span,
IrNode::EnumMember { span, .. } => *span,
IrNode::Decorator { span, .. } => *span,
IrNode::ImportDecl { span, .. } => *span,
IrNode::NamedImport { span, .. } => *span,
IrNode::DefaultImport { span, .. } => *span,
IrNode::NamespaceImport { span, .. } => *span,
IrNode::NamedExport { span, .. } => *span,
IrNode::ExportSpecifier { span, .. } => *span,
IrNode::ExportDefaultExpr { span, .. } => *span,
IrNode::ExportAll { span, .. } => *span,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_placeholder_kind_debug() {
let kind = PlaceholderKind::Expr;
assert_eq!(format!("{:?}", kind), "Expr");
}
#[test]
fn test_placeholder_kind_clone() {
let kind = PlaceholderKind::Type;
let cloned = kind;
assert_eq!(kind, cloned);
}
#[test]
fn test_placeholder_kind_equality() {
assert_eq!(PlaceholderKind::Expr, PlaceholderKind::Expr);
assert_eq!(PlaceholderKind::Type, PlaceholderKind::Type);
assert_eq!(PlaceholderKind::Ident, PlaceholderKind::Ident);
assert_eq!(PlaceholderKind::Stmt, PlaceholderKind::Stmt);
assert_ne!(PlaceholderKind::Expr, PlaceholderKind::Type);
}
#[test]
fn test_placeholder_kind_copy() {
let kind = PlaceholderKind::Stmt;
let copied: PlaceholderKind = kind; assert_eq!(kind, copied);
}
#[test]
fn test_var_kind_debug() {
assert_eq!(format!("{:?}", VarKind::Const), "Const");
assert_eq!(format!("{:?}", VarKind::Let), "Let");
assert_eq!(format!("{:?}", VarKind::Var), "Var");
}
#[test]
fn test_var_kind_equality() {
assert_eq!(VarKind::Const, VarKind::Const);
assert_ne!(VarKind::Const, VarKind::Let);
assert_ne!(VarKind::Let, VarKind::Var);
}
#[test]
fn test_accessibility_debug() {
assert_eq!(format!("{:?}", Accessibility::Public), "Public");
assert_eq!(format!("{:?}", Accessibility::Private), "Private");
assert_eq!(format!("{:?}", Accessibility::Protected), "Protected");
}
#[test]
fn test_accessibility_equality() {
assert_eq!(Accessibility::Public, Accessibility::Public);
assert_ne!(Accessibility::Public, Accessibility::Private);
}
#[test]
fn test_method_kind_debug() {
assert_eq!(format!("{:?}", MethodKind::Method), "Method");
assert_eq!(format!("{:?}", MethodKind::Getter), "Getter");
assert_eq!(format!("{:?}", MethodKind::Setter), "Setter");
}
#[test]
fn test_method_kind_equality() {
assert_eq!(MethodKind::Getter, MethodKind::Getter);
assert_ne!(MethodKind::Getter, MethodKind::Setter);
}
#[test]
fn test_binary_op_debug() {
assert_eq!(format!("{:?}", BinaryOp::Add), "Add");
assert_eq!(format!("{:?}", BinaryOp::Sub), "Sub");
assert_eq!(format!("{:?}", BinaryOp::EqEqEq), "EqEqEq");
}
#[test]
fn test_binary_op_equality() {
assert_eq!(BinaryOp::Add, BinaryOp::Add);
assert_ne!(BinaryOp::Add, BinaryOp::Sub);
}
#[test]
fn test_binary_op_all_variants() {
let ops = vec![
BinaryOp::Add,
BinaryOp::Sub,
BinaryOp::Mul,
BinaryOp::Div,
BinaryOp::Mod,
BinaryOp::Exp,
BinaryOp::EqEq,
BinaryOp::NotEq,
BinaryOp::EqEqEq,
BinaryOp::NotEqEq,
BinaryOp::Lt,
BinaryOp::Le,
BinaryOp::Gt,
BinaryOp::Ge,
BinaryOp::And,
BinaryOp::Or,
BinaryOp::NullishCoalesce,
BinaryOp::BitAnd,
BinaryOp::BitOr,
BinaryOp::BitXor,
BinaryOp::Shl,
BinaryOp::Shr,
BinaryOp::UShr,
BinaryOp::In,
BinaryOp::InstanceOf,
];
assert_eq!(ops.len(), 25);
}
#[test]
fn test_assign_op_debug() {
assert_eq!(format!("{:?}", AssignOp::Assign), "Assign");
assert_eq!(format!("{:?}", AssignOp::AddAssign), "AddAssign");
}
#[test]
fn test_assign_op_equality() {
assert_eq!(AssignOp::Assign, AssignOp::Assign);
assert_ne!(AssignOp::Assign, AssignOp::AddAssign);
}
#[test]
fn test_unary_op_debug() {
assert_eq!(format!("{:?}", UnaryOp::Minus), "Minus");
assert_eq!(format!("{:?}", UnaryOp::Not), "Not");
assert_eq!(format!("{:?}", UnaryOp::TypeOf), "TypeOf");
}
#[test]
fn test_unary_op_equality() {
assert_eq!(UnaryOp::Minus, UnaryOp::Minus);
assert_ne!(UnaryOp::Minus, UnaryOp::Plus);
}
#[test]
fn test_update_op_debug() {
assert_eq!(format!("{:?}", UpdateOp::Increment), "Increment");
assert_eq!(format!("{:?}", UpdateOp::Decrement), "Decrement");
}
#[test]
fn test_update_op_equality() {
assert_eq!(UpdateOp::Increment, UpdateOp::Increment);
assert_ne!(UpdateOp::Increment, UpdateOp::Decrement);
}
#[test]
fn test_ts_keyword_debug() {
assert_eq!(format!("{:?}", TsKeyword::String), "String");
assert_eq!(format!("{:?}", TsKeyword::Number), "Number");
assert_eq!(format!("{:?}", TsKeyword::Boolean), "Boolean");
}
#[test]
fn test_ts_keyword_all_variants() {
let keywords = vec![
TsKeyword::Any,
TsKeyword::Unknown,
TsKeyword::String,
TsKeyword::Number,
TsKeyword::Boolean,
TsKeyword::Void,
TsKeyword::Null,
TsKeyword::Undefined,
TsKeyword::Never,
TsKeyword::Object,
TsKeyword::BigInt,
TsKeyword::Symbol,
];
assert_eq!(keywords.len(), 12);
}
#[test]
fn test_ir_node_ident() {
let node = IrNode::Ident {
span: IrSpan::empty(),
value: "foo".to_string(),
};
assert!(matches!(node, IrNode::Ident { value, .. } if value == "foo"));
}
#[test]
fn test_ir_node_str_lit() {
let node = IrNode::StrLit {
span: IrSpan::empty(),
value: "hello".to_string(),
};
assert!(matches!(node, IrNode::StrLit { value, .. } if value == "hello"));
}
#[test]
fn test_ir_node_num_lit() {
let node = IrNode::NumLit {
span: IrSpan::empty(),
value: "42".to_string(),
};
assert!(matches!(node, IrNode::NumLit { value, .. } if value == "42"));
}
#[test]
fn test_ir_node_bool_lit() {
let true_node = IrNode::BoolLit {
span: IrSpan::empty(),
value: true,
};
let false_node = IrNode::BoolLit {
span: IrSpan::empty(),
value: false,
};
assert!(matches!(true_node, IrNode::BoolLit { value: true, .. }));
assert!(matches!(false_node, IrNode::BoolLit { value: false, .. }));
}
#[test]
fn test_ir_node_null_lit() {
let node = IrNode::NullLit {
span: IrSpan::empty(),
};
assert!(matches!(node, IrNode::NullLit { .. }));
}
#[test]
fn test_ir_node_this_expr() {
let node = IrNode::ThisExpr {
span: IrSpan::empty(),
};
assert!(matches!(node, IrNode::ThisExpr { .. }));
}
#[test]
fn test_ir_node_super_expr() {
let node = IrNode::SuperExpr {
span: IrSpan::empty(),
};
assert!(matches!(node, IrNode::SuperExpr { .. }));
}
#[test]
fn test_ir_node_empty_stmt() {
let node = IrNode::EmptyStmt {
span: IrSpan::empty(),
};
assert!(matches!(node, IrNode::EmptyStmt { .. }));
}
#[test]
fn test_ir_node_block_stmt() {
let node = IrNode::BlockStmt {
span: IrSpan::empty(),
stmts: vec![],
};
assert!(matches!(node, IrNode::BlockStmt { stmts, .. } if stmts.is_empty()));
}
#[test]
fn test_ir_node_expr_stmt() {
let node = IrNode::ExprStmt {
span: IrSpan::empty(),
expr: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "x".to_string(),
}),
};
assert!(matches!(node, IrNode::ExprStmt { .. }));
}
#[test]
fn test_ir_node_return_stmt_with_arg() {
let node = IrNode::ReturnStmt {
span: IrSpan::empty(),
arg: Some(Box::new(IrNode::NumLit {
span: IrSpan::empty(),
value: "42".to_string(),
})),
};
assert!(matches!(node, IrNode::ReturnStmt { arg: Some(_), .. }));
}
#[test]
fn test_ir_node_return_stmt_without_arg() {
let node = IrNode::ReturnStmt {
span: IrSpan::empty(),
arg: None,
};
assert!(matches!(node, IrNode::ReturnStmt { arg: None, .. }));
}
#[test]
fn test_ir_node_throw_stmt() {
let node = IrNode::ThrowStmt {
span: IrSpan::empty(),
arg: Box::new(IrNode::StrLit {
span: IrSpan::empty(),
value: "error".to_string(),
}),
};
assert!(matches!(node, IrNode::ThrowStmt { .. }));
}
#[test]
fn test_ir_node_bin_expr() {
let node = IrNode::BinExpr {
span: IrSpan::empty(),
left: Box::new(IrNode::NumLit {
span: IrSpan::empty(),
value: "1".to_string(),
}),
op: BinaryOp::Add,
right: Box::new(IrNode::NumLit {
span: IrSpan::empty(),
value: "2".to_string(),
}),
};
assert!(matches!(
node,
IrNode::BinExpr {
op: BinaryOp::Add,
..
}
));
}
#[test]
fn test_ir_node_unary_expr() {
let node = IrNode::UnaryExpr {
span: IrSpan::empty(),
op: UnaryOp::Minus,
arg: Box::new(IrNode::NumLit {
span: IrSpan::empty(),
value: "5".to_string(),
}),
};
assert!(matches!(
node,
IrNode::UnaryExpr {
op: UnaryOp::Minus,
..
}
));
}
#[test]
fn test_ir_node_call_expr() {
let node = IrNode::CallExpr {
span: IrSpan::empty(),
callee: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "foo".to_string(),
}),
type_args: None,
args: vec![IrNode::NumLit {
span: IrSpan::empty(),
value: "1".to_string(),
}],
};
assert!(matches!(node, IrNode::CallExpr { .. }));
}
#[test]
fn test_ir_node_new_expr() {
let node = IrNode::NewExpr {
span: IrSpan::empty(),
callee: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "MyClass".to_string(),
}),
type_args: None,
args: vec![],
};
assert!(matches!(node, IrNode::NewExpr { .. }));
}
#[test]
fn test_ir_node_member_expr() {
let node = IrNode::MemberExpr {
span: IrSpan::empty(),
obj: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "obj".to_string(),
}),
prop: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "prop".to_string(),
}),
computed: false,
};
assert!(matches!(
node,
IrNode::MemberExpr {
computed: false,
..
}
));
}
#[test]
fn test_ir_node_object_lit() {
let node = IrNode::ObjectLit {
span: IrSpan::empty(),
props: vec![],
};
assert!(matches!(node, IrNode::ObjectLit { props, .. } if props.is_empty()));
}
#[test]
fn test_ir_node_array_lit() {
let node = IrNode::ArrayLit {
span: IrSpan::empty(),
elems: vec![IrNode::NumLit {
span: IrSpan::empty(),
value: "1".to_string(),
}],
};
assert!(matches!(node, IrNode::ArrayLit { elems, .. } if elems.len() == 1));
}
#[test]
fn test_ir_node_arrow_expr() {
let node = IrNode::ArrowExpr {
span: IrSpan::empty(),
async_: false,
type_params: None,
params: vec![],
return_type: None,
body: Box::new(IrNode::NumLit {
span: IrSpan::empty(),
value: "42".to_string(),
}),
};
assert!(matches!(node, IrNode::ArrowExpr { async_: false, .. }));
}
#[test]
fn test_ir_node_cond_expr() {
let node = IrNode::CondExpr {
span: IrSpan::empty(),
test: Box::new(IrNode::BoolLit {
span: IrSpan::empty(),
value: true,
}),
consequent: Box::new(IrNode::NumLit {
span: IrSpan::empty(),
value: "1".to_string(),
}),
alternate: Box::new(IrNode::NumLit {
span: IrSpan::empty(),
value: "2".to_string(),
}),
};
assert!(matches!(node, IrNode::CondExpr { .. }));
}
#[test]
fn test_ir_node_keyword_type() {
let node = IrNode::KeywordType {
span: IrSpan::empty(),
keyword: TsKeyword::String,
};
assert!(matches!(
node,
IrNode::KeywordType {
keyword: TsKeyword::String,
..
}
));
}
#[test]
fn test_ir_node_union_type() {
let node = IrNode::UnionType {
span: IrSpan::empty(),
types: vec![
IrNode::KeywordType {
span: IrSpan::empty(),
keyword: TsKeyword::String,
},
IrNode::KeywordType {
span: IrSpan::empty(),
keyword: TsKeyword::Number,
},
],
};
assert!(matches!(node, IrNode::UnionType { types, .. } if types.len() == 2));
}
#[test]
fn test_ir_node_array_type() {
let node = IrNode::ArrayType {
span: IrSpan::empty(),
elem: Box::new(IrNode::KeywordType {
span: IrSpan::empty(),
keyword: TsKeyword::Number,
}),
};
assert!(matches!(node, IrNode::ArrayType { .. }));
}
#[test]
fn test_ir_node_var_decl() {
let node = IrNode::VarDecl {
span: IrSpan::empty(),
exported: false,
declare: false,
kind: VarKind::Const,
decls: vec![],
};
assert!(matches!(
node,
IrNode::VarDecl {
kind: VarKind::Const,
..
}
));
}
#[test]
fn test_ir_node_fn_decl() {
let node = IrNode::FnDecl {
span: IrSpan::empty(),
exported: false,
declare: false,
async_: true,
generator: false,
name: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "myFn".to_string(),
}),
type_params: None,
params: vec![],
return_type: None,
body: Some(Box::new(IrNode::BlockStmt {
span: IrSpan::empty(),
stmts: vec![],
})),
};
assert!(matches!(node, IrNode::FnDecl { async_: true, .. }));
}
#[test]
fn test_ir_node_class_decl() {
let node = IrNode::ClassDecl {
span: IrSpan::empty(),
exported: false,
declare: false,
abstract_: false,
decorators: vec![],
name: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "MyClass".to_string(),
}),
type_params: None,
extends: None,
implements: vec![],
body: vec![],
};
assert!(matches!(
node,
IrNode::ClassDecl {
abstract_: false,
..
}
));
}
#[test]
fn test_ir_node_interface_decl() {
let node = IrNode::InterfaceDecl {
span: IrSpan::empty(),
exported: true,
declare: false,
name: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "MyInterface".to_string(),
}),
type_params: None,
extends: vec![],
body: vec![],
};
assert!(matches!(node, IrNode::InterfaceDecl { exported: true, .. }));
}
#[test]
fn test_ir_node_type_alias_decl() {
let node = IrNode::TypeAliasDecl {
span: IrSpan::empty(),
exported: false,
declare: false,
name: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "MyType".to_string(),
}),
type_params: None,
type_ann: Box::new(IrNode::KeywordType {
span: IrSpan::empty(),
keyword: TsKeyword::String,
}),
};
assert!(matches!(node, IrNode::TypeAliasDecl { .. }));
}
#[test]
fn test_ir_node_clone() {
let node = IrNode::Ident {
span: IrSpan::empty(),
value: "test".to_string(),
};
let cloned = node.clone();
assert!(matches!(cloned, IrNode::Ident { value, .. } if value == "test"));
}
#[test]
fn test_var_declarator_basic() {
let decl = VarDeclarator {
span: IrSpan::empty(),
name: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "x".to_string(),
}),
type_ann: None,
init: None,
definite: false,
};
assert!(!decl.definite);
assert!(decl.init.is_none());
assert!(decl.type_ann.is_none());
}
#[test]
fn test_var_declarator_with_init() {
let decl = VarDeclarator {
span: IrSpan::empty(),
name: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "x".to_string(),
}),
type_ann: None,
init: Some(Box::new(IrNode::NumLit {
span: IrSpan::empty(),
value: "42".to_string(),
})),
definite: false,
};
assert!(decl.init.is_some());
}
#[test]
fn test_var_declarator_with_type() {
let decl = VarDeclarator {
span: IrSpan::empty(),
name: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "x".to_string(),
}),
type_ann: Some(Box::new(IrNode::KeywordType {
span: IrSpan::empty(),
keyword: TsKeyword::Number,
})),
init: None,
definite: true,
};
assert!(decl.type_ann.is_some());
assert!(decl.definite);
}
#[test]
fn test_var_declarator_clone() {
let decl = VarDeclarator {
span: IrSpan::empty(),
name: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "x".to_string(),
}),
type_ann: None,
init: None,
definite: false,
};
let cloned = decl.clone();
assert!(!cloned.definite);
}
#[test]
fn test_match_arm_basic() {
let arm = MatchArm {
span: IrSpan::empty(),
pattern: TokenStream::new(),
guard: None,
body: vec![],
};
assert!(arm.guard.is_none());
assert!(arm.body.is_empty());
}
#[test]
fn test_match_arm_with_guard() {
let arm = MatchArm {
span: IrSpan::empty(),
pattern: TokenStream::new(),
guard: Some(TokenStream::new()),
body: vec![IrNode::ReturnStmt {
span: IrSpan::empty(),
arg: None,
}],
};
assert!(arm.guard.is_some());
assert_eq!(arm.body.len(), 1);
}
#[test]
fn test_match_arm_clone() {
let arm = MatchArm {
span: IrSpan::empty(),
pattern: TokenStream::new(),
guard: None,
body: vec![],
};
let cloned = arm.clone();
assert!(cloned.guard.is_none());
}
#[test]
fn test_ir_new() {
let ir = Ir::new();
assert!(ir.nodes.is_empty());
}
#[test]
fn test_ir_default() {
let ir = Ir::default();
assert!(ir.nodes.is_empty());
}
#[test]
fn test_ir_with_nodes() {
let nodes = vec![
IrNode::Ident {
span: IrSpan::empty(),
value: "foo".to_string(),
},
IrNode::NumLit {
span: IrSpan::empty(),
value: "42".to_string(),
},
];
let ir = Ir::with_nodes(nodes);
assert_eq!(ir.nodes.len(), 2);
}
#[test]
fn test_ir_with_empty_nodes() {
let ir = Ir::with_nodes(vec![]);
assert!(ir.nodes.is_empty());
}
#[test]
fn test_ir_debug() {
let ir = Ir::new();
let debug_str = format!("{:?}", ir);
assert!(debug_str.contains("Ir"));
assert!(debug_str.contains("nodes"));
}
#[test]
fn test_nested_member_expr() {
let node = IrNode::MemberExpr {
span: IrSpan::empty(),
obj: Box::new(IrNode::MemberExpr {
span: IrSpan::empty(),
obj: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "obj".to_string(),
}),
prop: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "foo".to_string(),
}),
computed: false,
}),
prop: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "bar".to_string(),
}),
computed: false,
};
assert!(matches!(node, IrNode::MemberExpr { .. }));
}
#[test]
fn test_call_with_args() {
let node = IrNode::CallExpr {
span: IrSpan::empty(),
callee: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "foo".to_string(),
}),
type_args: None,
args: vec![
IrNode::NumLit {
span: IrSpan::empty(),
value: "1".to_string(),
},
IrNode::StrLit {
span: IrSpan::empty(),
value: "hello".to_string(),
},
IrNode::BoolLit {
span: IrSpan::empty(),
value: true,
},
],
};
if let IrNode::CallExpr { args, .. } = node {
assert_eq!(args.len(), 3);
} else {
panic!("Expected CallExpr");
}
}
#[test]
fn test_class_with_members() {
let node = IrNode::ClassDecl {
span: IrSpan::empty(),
exported: true,
declare: false,
abstract_: false,
decorators: vec![],
name: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "MyClass".to_string(),
}),
type_params: None,
extends: Some(Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "BaseClass".to_string(),
})),
implements: vec![IrNode::Ident {
span: IrSpan::empty(),
value: "Interface1".to_string(),
}],
body: vec![
IrNode::Constructor {
span: IrSpan::empty(),
accessibility: Some(Accessibility::Public),
params: vec![],
body: Some(Box::new(IrNode::BlockStmt {
span: IrSpan::empty(),
stmts: vec![],
})),
},
IrNode::ClassProp {
span: IrSpan::empty(),
static_: false,
accessibility: Some(Accessibility::Private),
readonly: true,
declare: false,
optional: false,
definite: false,
name: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "value".to_string(),
}),
type_ann: Some(Box::new(IrNode::KeywordType {
span: IrSpan::empty(),
keyword: TsKeyword::Number,
})),
value: None,
},
],
};
if let IrNode::ClassDecl { body, .. } = node {
assert_eq!(body.len(), 2);
} else {
panic!("Expected ClassDecl");
}
}
#[test]
fn test_type_ref_with_params() {
let node = IrNode::TypeRef {
span: IrSpan::empty(),
name: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "Promise".to_string(),
}),
type_params: Some(Box::new(IrNode::TypeArgs {
span: IrSpan::empty(),
args: vec![IrNode::KeywordType {
span: IrSpan::empty(),
keyword: TsKeyword::String,
}],
})),
};
assert!(matches!(node, IrNode::TypeRef { .. }));
}
#[test]
fn test_fn_type() {
let node = IrNode::FnType {
span: IrSpan::empty(),
type_params: None,
params: vec![IrNode::Param {
span: IrSpan::empty(),
decorators: vec![],
pat: Box::new(IrNode::BindingIdent {
span: IrSpan::empty(),
name: Box::new(IrNode::Ident {
span: IrSpan::empty(),
value: "x".to_string(),
}),
type_ann: Some(Box::new(IrNode::KeywordType {
span: IrSpan::empty(),
keyword: TsKeyword::Number,
})),
optional: false,
}),
}],
return_type: Box::new(IrNode::KeywordType {
span: IrSpan::empty(),
keyword: TsKeyword::String,
}),
};
assert!(matches!(node, IrNode::FnType { .. }));
}
}