#![allow(non_snake_case)]
use std::{cell::Cell, fmt, hash::Hash};
use oxc_allocator::{Box, Vec};
use oxc_ast_macros::visited_node;
use oxc_span::{Atom, CompactStr, SourceType, Span};
use oxc_syntax::{
operator::{
AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator,
},
reference::{ReferenceFlag, ReferenceId},
scope::{ScopeFlags, ScopeId},
symbol::SymbolId,
};
#[cfg(feature = "serialize")]
use serde::Serialize;
#[cfg(feature = "serialize")]
use tsify::Tsify;
use super::inherit_variants;
use super::{jsx::*, literal::*, ts::*};
#[cfg(feature = "serialize")]
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
const TS_APPEND_CONTENT: &'static str = r#"
export interface BindingIdentifier extends Span { type: "Identifier", name: Atom }
export interface IdentifierReference extends Span { type: "Identifier", name: Atom }
export interface IdentifierName extends Span { type: "Identifier", name: Atom }
export interface LabelIdentifier extends Span { type: "Identifier", name: Atom }
export interface AssignmentTargetRest extends Span { type: "RestElement", argument: AssignmentTarget }
export interface BindingRestElement extends Span { type: "RestElement", argument: BindingPattern }
export interface FormalParameterRest extends Span {
type: "RestElement",
argument: BindingPatternKind,
typeAnnotation?: TSTypeAnnotation,
optional: boolean,
}
"#;
#[visited_node(
scope(ScopeFlags::Top),
strict_if(self.source_type.is_strict() || self.directives.iter().any(Directive::is_use_strict))
)]
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct Program<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub source_type: SourceType,
pub directives: Vec<'a, Directive<'a>>,
pub hashbang: Option<Hashbang<'a>>,
pub body: Vec<'a, Statement<'a>>,
pub scope_id: Cell<Option<ScopeId>>,
}
impl<'a> Program<'a> {
pub fn new(
span: Span,
source_type: SourceType,
directives: Vec<'a, Directive<'a>>,
hashbang: Option<Hashbang<'a>>,
body: Vec<'a, Statement<'a>>,
) -> Self {
Self { span, source_type, directives, hashbang, body, scope_id: Cell::default() }
}
}
impl<'a> Hash for Program<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.source_type.hash(state);
self.directives.hash(state);
self.hashbang.hash(state);
self.body.hash(state);
}
}
impl<'a> Program<'a> {
pub fn is_empty(&self) -> bool {
self.body.is_empty() && self.directives.is_empty()
}
pub fn is_strict(&self) -> bool {
self.source_type.is_strict() || self.directives.iter().any(Directive::is_use_strict)
}
}
inherit_variants! {
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum Expression<'a> {
BooleanLiteral(Box<'a, BooleanLiteral>) = 0,
NullLiteral(Box<'a, NullLiteral>) = 1,
NumericLiteral(Box<'a, NumericLiteral<'a>>) = 2,
BigintLiteral(Box<'a, BigIntLiteral<'a>>) = 3,
RegExpLiteral(Box<'a, RegExpLiteral<'a>>) = 4,
StringLiteral(Box<'a, StringLiteral<'a>>) = 5,
TemplateLiteral(Box<'a, TemplateLiteral<'a>>) = 6,
Identifier(Box<'a, IdentifierReference<'a>>) = 7,
MetaProperty(Box<'a, MetaProperty<'a>>) = 8,
Super(Box<'a, Super>) = 9,
ArrayExpression(Box<'a, ArrayExpression<'a>>) = 10,
ArrowFunctionExpression(Box<'a, ArrowFunctionExpression<'a>>) = 11,
AssignmentExpression(Box<'a, AssignmentExpression<'a>>) = 12,
AwaitExpression(Box<'a, AwaitExpression<'a>>) = 13,
BinaryExpression(Box<'a, BinaryExpression<'a>>) = 14,
CallExpression(Box<'a, CallExpression<'a>>) = 15,
ChainExpression(Box<'a, ChainExpression<'a>>) = 16,
ClassExpression(Box<'a, Class<'a>>) = 17,
ConditionalExpression(Box<'a, ConditionalExpression<'a>>) = 18,
FunctionExpression(Box<'a, Function<'a>>) = 19,
ImportExpression(Box<'a, ImportExpression<'a>>) = 20,
LogicalExpression(Box<'a, LogicalExpression<'a>>) = 21,
NewExpression(Box<'a, NewExpression<'a>>) = 22,
ObjectExpression(Box<'a, ObjectExpression<'a>>) = 23,
ParenthesizedExpression(Box<'a, ParenthesizedExpression<'a>>) = 24,
SequenceExpression(Box<'a, SequenceExpression<'a>>) = 25,
TaggedTemplateExpression(Box<'a, TaggedTemplateExpression<'a>>) = 26,
ThisExpression(Box<'a, ThisExpression>) = 27,
UnaryExpression(Box<'a, UnaryExpression<'a>>) = 28,
UpdateExpression(Box<'a, UpdateExpression<'a>>) = 29,
YieldExpression(Box<'a, YieldExpression<'a>>) = 30,
PrivateInExpression(Box<'a, PrivateInExpression<'a>>) = 31,
JSXElement(Box<'a, JSXElement<'a>>) = 32,
JSXFragment(Box<'a, JSXFragment<'a>>) = 33,
TSAsExpression(Box<'a, TSAsExpression<'a>>) = 34,
TSSatisfiesExpression(Box<'a, TSSatisfiesExpression<'a>>) = 35,
TSTypeAssertion(Box<'a, TSTypeAssertion<'a>>) = 36,
TSNonNullExpression(Box<'a, TSNonNullExpression<'a>>) = 37,
TSInstantiationExpression(Box<'a, TSInstantiationExpression<'a>>) = 38,
@inherit MemberExpression
}
}
#[macro_export]
macro_rules! match_expression {
($ty:ident) => {
$ty::BooleanLiteral(_)
| $ty::NullLiteral(_)
| $ty::NumericLiteral(_)
| $ty::BigintLiteral(_)
| $ty::RegExpLiteral(_)
| $ty::StringLiteral(_)
| $ty::TemplateLiteral(_)
| $ty::Identifier(_)
| $ty::MetaProperty(_)
| $ty::Super(_)
| $ty::ArrayExpression(_)
| $ty::ArrowFunctionExpression(_)
| $ty::AssignmentExpression(_)
| $ty::AwaitExpression(_)
| $ty::BinaryExpression(_)
| $ty::CallExpression(_)
| $ty::ChainExpression(_)
| $ty::ClassExpression(_)
| $ty::ConditionalExpression(_)
| $ty::FunctionExpression(_)
| $ty::ImportExpression(_)
| $ty::LogicalExpression(_)
| $ty::NewExpression(_)
| $ty::ObjectExpression(_)
| $ty::ParenthesizedExpression(_)
| $ty::SequenceExpression(_)
| $ty::TaggedTemplateExpression(_)
| $ty::ThisExpression(_)
| $ty::UnaryExpression(_)
| $ty::UpdateExpression(_)
| $ty::YieldExpression(_)
| $ty::PrivateInExpression(_)
| $ty::JSXElement(_)
| $ty::JSXFragment(_)
| $ty::TSAsExpression(_)
| $ty::TSSatisfiesExpression(_)
| $ty::TSTypeAssertion(_)
| $ty::TSNonNullExpression(_)
| $ty::TSInstantiationExpression(_)
| $ty::ComputedMemberExpression(_)
| $ty::StaticMemberExpression(_)
| $ty::PrivateFieldExpression(_)
};
}
pub use match_expression;
impl<'a> Expression<'a> {
pub fn is_typescript_syntax(&self) -> bool {
matches!(
self,
Self::TSAsExpression(_)
| Self::TSSatisfiesExpression(_)
| Self::TSTypeAssertion(_)
| Self::TSNonNullExpression(_)
| Self::TSInstantiationExpression(_)
)
}
pub fn is_primary_expression(&self) -> bool {
self.is_literal()
|| matches!(
self,
Self::Identifier(_)
| Self::ThisExpression(_)
| Self::FunctionExpression(_)
| Self::ClassExpression(_)
| Self::ParenthesizedExpression(_)
| Self::ArrayExpression(_)
| Self::ObjectExpression(_)
)
}
pub fn is_literal(&self) -> bool {
matches!(
self,
Self::BooleanLiteral(_)
| Self::NullLiteral(_)
| Self::NumericLiteral(_)
| Self::BigintLiteral(_)
| Self::RegExpLiteral(_)
| Self::StringLiteral(_)
)
}
pub fn is_string_literal(&self) -> bool {
matches!(self, Self::StringLiteral(_) | Self::TemplateLiteral(_))
}
pub fn is_specific_string_literal(&self, string: &str) -> bool {
match self {
Self::StringLiteral(s) => s.value == string,
_ => false,
}
}
pub fn is_null(&self) -> bool {
matches!(self, Expression::NullLiteral(_))
}
pub fn is_undefined(&self) -> bool {
matches!(self, Self::Identifier(ident) if ident.name == "undefined")
}
pub fn is_void(&self) -> bool {
matches!(self, Self::UnaryExpression(expr) if expr.operator == UnaryOperator::Void)
}
pub fn is_void_0(&self) -> bool {
match self {
Self::UnaryExpression(expr) if expr.operator == UnaryOperator::Void => {
matches!(&expr.argument, Self::NumericLiteral(lit) if lit.value == 0.0)
}
_ => false,
}
}
pub fn is_number_0(&self) -> bool {
matches!(self, Self::NumericLiteral(lit) if lit.value == 0.0)
}
pub fn is_number(&self, val: f64) -> bool {
matches!(self, Self::NumericLiteral(lit) if (lit.value - val).abs() < f64::EPSILON)
}
pub fn is_specific_raw_number_literal(&self, val: &str) -> bool {
matches!(self, Self::NumericLiteral(lit) if lit.raw == val)
}
pub fn evaluate_to_undefined(&self) -> bool {
self.is_undefined() || self.is_void()
}
pub fn is_null_or_undefined(&self) -> bool {
self.is_null() || self.evaluate_to_undefined()
}
pub fn is_nan(&self) -> bool {
matches!(self, Self::Identifier(ident) if ident.name == "NaN")
}
pub fn without_parenthesized(&self) -> &Self {
match self {
Expression::ParenthesizedExpression(expr) => expr.expression.without_parenthesized(),
_ => self,
}
}
pub fn is_specific_id(&self, name: &str) -> bool {
match self.get_inner_expression() {
Expression::Identifier(ident) => ident.name == name,
_ => false,
}
}
pub fn is_specific_member_access(&self, object: &str, property: &str) -> bool {
match self.get_inner_expression() {
expr if expr.is_member_expression() => {
expr.to_member_expression().is_specific_member_access(object, property)
}
Expression::ChainExpression(chain) => {
let Some(expr) = chain.expression.as_member_expression() else {
return false;
};
expr.is_specific_member_access(object, property)
}
_ => false,
}
}
pub fn get_inner_expression(&self) -> &Expression<'a> {
match self {
Expression::ParenthesizedExpression(expr) => expr.expression.get_inner_expression(),
Expression::TSAsExpression(expr) => expr.expression.get_inner_expression(),
Expression::TSSatisfiesExpression(expr) => expr.expression.get_inner_expression(),
Expression::TSInstantiationExpression(expr) => expr.expression.get_inner_expression(),
Expression::TSNonNullExpression(expr) => expr.expression.get_inner_expression(),
Expression::TSTypeAssertion(expr) => expr.expression.get_inner_expression(),
_ => self,
}
}
pub fn is_identifier_reference(&self) -> bool {
matches!(self, Expression::Identifier(_))
}
pub fn get_identifier_reference(&self) -> Option<&IdentifierReference<'a>> {
match self.get_inner_expression() {
Expression::Identifier(ident) => Some(ident),
_ => None,
}
}
pub fn is_function(&self) -> bool {
matches!(self, Expression::FunctionExpression(_) | Expression::ArrowFunctionExpression(_))
}
pub fn is_call_expression(&self) -> bool {
matches!(self, Expression::CallExpression(_))
}
pub fn is_super_call_expression(&self) -> bool {
matches!(self, Expression::CallExpression(expr) if matches!(&expr.callee, Expression::Super(_)))
}
pub fn is_call_like_expression(&self) -> bool {
self.is_call_expression()
&& matches!(self, Expression::NewExpression(_) | Expression::ImportExpression(_))
}
pub fn is_binaryish(&self) -> bool {
matches!(self, Expression::BinaryExpression(_) | Expression::LogicalExpression(_))
}
pub fn get_boolean_value(&self) -> Option<bool> {
match self {
Self::BooleanLiteral(lit) => Some(lit.value),
Self::NullLiteral(_) => Some(false),
Self::NumericLiteral(lit) => Some(lit.value != 0.0),
Self::BigintLiteral(lit) => Some(!lit.is_zero()),
Self::RegExpLiteral(_) => Some(true),
Self::StringLiteral(lit) => Some(!lit.value.is_empty()),
_ => None,
}
}
pub fn get_member_expr(&self) -> Option<&MemberExpression<'a>> {
match self.get_inner_expression() {
Expression::ChainExpression(chain_expr) => chain_expr.expression.as_member_expression(),
expr => expr.as_member_expression(),
}
}
pub fn is_immutable_value(&self) -> bool {
match self {
Self::BooleanLiteral(_)
| Self::NullLiteral(_)
| Self::NumericLiteral(_)
| Self::BigintLiteral(_)
| Self::RegExpLiteral(_)
| Self::StringLiteral(_) => true,
Self::TemplateLiteral(lit) if lit.is_no_substitution_template() => true,
Self::UnaryExpression(unary_expr) => unary_expr.argument.is_immutable_value(),
Self::Identifier(ident) => {
matches!(ident.name.as_str(), "undefined" | "Infinity" | "NaN")
}
_ => false,
}
}
}
#[visited_node]
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename = "Identifier"))]
pub struct IdentifierName<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub name: Atom<'a>,
}
impl<'a> IdentifierName<'a> {
pub fn new(span: Span, name: Atom<'a>) -> Self {
Self { span, name }
}
}
#[visited_node]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename = "Identifier"))]
pub struct IdentifierReference<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub name: Atom<'a>,
#[cfg_attr(feature = "serialize", serde(skip))]
pub reference_id: Cell<Option<ReferenceId>>,
#[cfg_attr(feature = "serialize", serde(skip))]
pub reference_flag: ReferenceFlag,
}
impl<'a> Hash for IdentifierReference<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl<'a> IdentifierReference<'a> {
pub fn new(span: Span, name: Atom<'a>) -> Self {
Self { span, name, reference_id: Cell::default(), reference_flag: ReferenceFlag::default() }
}
pub fn new_read(span: Span, name: Atom<'a>, reference_id: Option<ReferenceId>) -> Self {
Self {
span,
name,
reference_id: Cell::new(reference_id),
reference_flag: ReferenceFlag::Read,
}
}
}
#[visited_node]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename = "Identifier"))]
pub struct BindingIdentifier<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub name: Atom<'a>,
#[cfg_attr(feature = "serialize", serde(skip))]
pub symbol_id: Cell<Option<SymbolId>>,
}
impl<'a> Hash for BindingIdentifier<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl<'a> BindingIdentifier<'a> {
pub fn new(span: Span, name: Atom<'a>) -> Self {
Self { span, name, symbol_id: Cell::default() }
}
}
#[visited_node]
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename = "Identifier"))]
pub struct LabelIdentifier<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub name: Atom<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ThisExpression {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct ArrayExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
#[cfg_attr(feature = "serialize", tsify(type = "Array<SpreadElement | Expression | null>"))]
pub elements: Vec<'a, ArrayExpressionElement<'a>>,
#[cfg_attr(feature = "serialize", serde(skip))]
pub trailing_comma: Option<Span>,
}
inherit_variants! {
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum ArrayExpressionElement<'a> {
SpreadElement(Box<'a, SpreadElement<'a>>) = 64,
Elision(Elision) = 65,
@inherit Expression
}
}
impl<'a> ArrayExpressionElement<'a> {
pub fn is_elision(&self) -> bool {
matches!(self, Self::Elision(_))
}
}
#[visited_node]
#[derive(Debug, Clone, Hash)]
pub struct Elision {
pub span: Span,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ObjectExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub properties: Vec<'a, ObjectPropertyKind<'a>>,
#[cfg_attr(feature = "serialize", serde(skip))]
pub trailing_comma: Option<Span>,
}
impl<'a> ObjectExpression<'a> {
pub fn has_proto(&self) -> bool {
use crate::syntax_directed_operations::PropName;
self.properties.iter().any(|p| p.prop_name().is_some_and(|name| name.0 == "__proto__"))
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum ObjectPropertyKind<'a> {
ObjectProperty(Box<'a, ObjectProperty<'a>>),
SpreadProperty(Box<'a, SpreadElement<'a>>),
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ObjectProperty<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub kind: PropertyKind,
pub key: PropertyKey<'a>,
pub value: Expression<'a>,
pub init: Option<Expression<'a>>, pub method: bool,
pub shorthand: bool,
pub computed: bool,
}
inherit_variants! {
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum PropertyKey<'a> {
StaticIdentifier(Box<'a, IdentifierName<'a>>) = 64,
PrivateIdentifier(Box<'a, PrivateIdentifier<'a>>) = 65,
@inherit Expression
}
}
impl<'a> PropertyKey<'a> {
pub fn static_name(&self) -> Option<CompactStr> {
match self {
Self::StaticIdentifier(ident) => Some(ident.name.to_compact_str()),
Self::StringLiteral(lit) => Some(lit.value.to_compact_str()),
Self::RegExpLiteral(lit) => Some(lit.regex.to_string().into()),
Self::NumericLiteral(lit) => Some(lit.value.to_string().into()),
Self::BigintLiteral(lit) => Some(lit.raw.to_compact_str()),
Self::NullLiteral(_) => Some("null".into()),
Self::TemplateLiteral(lit) => {
lit.expressions.is_empty().then(|| lit.quasi()).flatten().map(Atom::to_compact_str)
}
_ => None,
}
}
pub fn is_specific_static_name(&self, name: &str) -> bool {
self.static_name().is_some_and(|n| n == name)
}
pub fn is_identifier(&self) -> bool {
matches!(self, Self::PrivateIdentifier(_) | Self::StaticIdentifier(_))
}
pub fn is_private_identifier(&self) -> bool {
matches!(self, Self::PrivateIdentifier(_))
}
pub fn private_name(&self) -> Option<&Atom<'a>> {
match self {
Self::PrivateIdentifier(ident) => Some(&ident.name),
_ => None,
}
}
pub fn name(&self) -> Option<CompactStr> {
if self.is_private_identifier() {
self.private_name().map(Atom::to_compact_str)
} else {
self.static_name()
}
}
pub fn is_specific_id(&self, name: &str) -> bool {
match self {
PropertyKey::StaticIdentifier(ident) => ident.name == name,
_ => false,
}
}
pub fn is_specific_string_literal(&self, string: &str) -> bool {
matches!(self, Self::StringLiteral(s) if s.value == string)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(rename_all = "lowercase"))]
pub enum PropertyKind {
Init,
Get,
Set,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct TemplateLiteral<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub quasis: Vec<'a, TemplateElement<'a>>,
pub expressions: Vec<'a, Expression<'a>>,
}
impl<'a> TemplateLiteral<'a> {
pub fn is_no_substitution_template(&self) -> bool {
self.expressions.is_empty() && self.quasis.len() == 1
}
pub fn quasi(&self) -> Option<&Atom<'a>> {
self.quasis.first().and_then(|quasi| quasi.value.cooked.as_ref())
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct TaggedTemplateExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub tag: Expression<'a>,
pub quasi: TemplateLiteral<'a>,
pub type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct TemplateElement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub tail: bool,
pub value: TemplateElementValue<'a>,
}
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
pub struct TemplateElementValue<'a> {
pub raw: Atom<'a>,
pub cooked: Option<Atom<'a>>,
}
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum MemberExpression<'a> {
ComputedMemberExpression(Box<'a, ComputedMemberExpression<'a>>) = 48,
StaticMemberExpression(Box<'a, StaticMemberExpression<'a>>) = 49,
PrivateFieldExpression(Box<'a, PrivateFieldExpression<'a>>) = 50,
}
#[macro_export]
macro_rules! match_member_expression {
($ty:ident) => {
$ty::ComputedMemberExpression(_)
| $ty::StaticMemberExpression(_)
| $ty::PrivateFieldExpression(_)
};
}
pub use match_member_expression;
impl<'a> MemberExpression<'a> {
pub fn is_computed(&self) -> bool {
matches!(self, MemberExpression::ComputedMemberExpression(_))
}
pub fn optional(&self) -> bool {
match self {
MemberExpression::ComputedMemberExpression(expr) => expr.optional,
MemberExpression::StaticMemberExpression(expr) => expr.optional,
MemberExpression::PrivateFieldExpression(expr) => expr.optional,
}
}
pub fn object(&self) -> &Expression<'a> {
match self {
MemberExpression::ComputedMemberExpression(expr) => &expr.object,
MemberExpression::StaticMemberExpression(expr) => &expr.object,
MemberExpression::PrivateFieldExpression(expr) => &expr.object,
}
}
pub fn static_property_name(&self) -> Option<&str> {
match self {
MemberExpression::ComputedMemberExpression(expr) => {
expr.static_property_name().map(|name| name.as_str())
}
MemberExpression::StaticMemberExpression(expr) => Some(expr.property.name.as_str()),
MemberExpression::PrivateFieldExpression(_) => None,
}
}
pub fn static_property_info(&self) -> Option<(Span, &str)> {
match self {
MemberExpression::ComputedMemberExpression(expr) => match &expr.expression {
Expression::StringLiteral(lit) => Some((lit.span, &lit.value)),
Expression::TemplateLiteral(lit) => {
if lit.expressions.is_empty() && lit.quasis.len() == 1 {
Some((lit.span, &lit.quasis[0].value.raw))
} else {
None
}
}
_ => None,
},
MemberExpression::StaticMemberExpression(expr) => {
Some((expr.property.span, &expr.property.name))
}
MemberExpression::PrivateFieldExpression(_) => None,
}
}
pub fn through_optional_is_specific_member_access(&self, object: &str, property: &str) -> bool {
let object_matches = match self.object().without_parenthesized() {
Expression::ChainExpression(x) => match &x.expression {
ChainElement::CallExpression(_) => false,
match_member_expression!(ChainElement) => {
let member_expr = x.expression.to_member_expression();
member_expr.object().without_parenthesized().is_specific_id(object)
}
},
x => x.is_specific_id(object),
};
let property_matches = self.static_property_name().is_some_and(|p| p == property);
object_matches && property_matches
}
pub fn is_specific_member_access(&self, object: &str, property: &str) -> bool {
self.object().is_specific_id(object)
&& self.static_property_name().is_some_and(|p| p == property)
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ComputedMemberExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub object: Expression<'a>,
pub expression: Expression<'a>,
pub optional: bool, }
impl<'a> ComputedMemberExpression<'a> {
pub fn static_property_name(&self) -> Option<Atom<'a>> {
match &self.expression {
Expression::StringLiteral(lit) => Some(lit.value.clone()),
Expression::TemplateLiteral(lit)
if lit.expressions.is_empty() && lit.quasis.len() == 1 =>
{
Some(lit.quasis[0].value.raw.clone())
}
_ => None,
}
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct StaticMemberExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub object: Expression<'a>,
pub property: IdentifierName<'a>,
pub optional: bool, }
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct PrivateFieldExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub object: Expression<'a>,
pub field: PrivateIdentifier<'a>,
pub optional: bool, }
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct CallExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub callee: Expression<'a>,
pub arguments: Vec<'a, Argument<'a>>,
pub optional: bool, pub type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
}
impl<'a> CallExpression<'a> {
pub fn callee_name(&self) -> Option<&str> {
match &self.callee {
Expression::Identifier(ident) => Some(ident.name.as_str()),
expr => expr.as_member_expression().and_then(MemberExpression::static_property_name),
}
}
pub fn is_require_call(&self) -> bool {
if self.arguments.len() != 1 {
return false;
}
if let Expression::Identifier(id) = &self.callee {
id.name == "require"
&& matches!(
self.arguments.first(),
Some(Argument::StringLiteral(_) | Argument::TemplateLiteral(_)),
)
} else {
false
}
}
pub fn is_symbol_or_symbol_for_call(&self) -> bool {
match &self.callee {
Expression::Identifier(id) => id.name == "Symbol",
expr => match expr.as_member_expression() {
Some(member) => {
matches!(member.object(), Expression::Identifier(id) if id.name == "Symbol")
&& member.static_property_name() == Some("for")
}
None => false,
},
}
}
pub fn common_js_require(&self) -> Option<&StringLiteral> {
if !(self.callee.is_specific_id("require") && self.arguments.len() == 1) {
return None;
}
match &self.arguments[0] {
Argument::StringLiteral(str_literal) => Some(str_literal),
_ => None,
}
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct NewExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub callee: Expression<'a>,
pub arguments: Vec<'a, Argument<'a>>,
pub type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct MetaProperty<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub meta: IdentifierName<'a>,
pub property: IdentifierName<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct SpreadElement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub argument: Expression<'a>,
}
inherit_variants! {
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum Argument<'a> {
SpreadElement(Box<'a, SpreadElement<'a>>) = 64,
@inherit Expression
}
}
impl Argument<'_> {
pub fn is_spread(&self) -> bool {
matches!(self, Self::SpreadElement(_))
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct UpdateExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub operator: UpdateOperator,
pub prefix: bool,
pub argument: SimpleAssignmentTarget<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct UnaryExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub operator: UnaryOperator,
pub argument: Expression<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct BinaryExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub left: Expression<'a>,
pub operator: BinaryOperator,
pub right: Expression<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct PrivateInExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub left: PrivateIdentifier<'a>,
pub operator: BinaryOperator, pub right: Expression<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct LogicalExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub left: Expression<'a>,
pub operator: LogicalOperator,
pub right: Expression<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ConditionalExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub test: Expression<'a>,
pub consequent: Expression<'a>,
pub alternate: Expression<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct AssignmentExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub operator: AssignmentOperator,
pub left: AssignmentTarget<'a>,
pub right: Expression<'a>,
}
inherit_variants! {
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum AssignmentTarget<'a> {
@inherit SimpleAssignmentTarget
@inherit AssignmentTargetPattern
}
}
impl<'a> AssignmentTarget<'a> {
pub fn get_identifier(&self) -> Option<&str> {
self.as_simple_assignment_target().and_then(|it| it.get_identifier())
}
pub fn get_expression(&self) -> Option<&Expression<'a>> {
self.as_simple_assignment_target().and_then(|it| it.get_expression())
}
}
#[macro_export]
macro_rules! match_assignment_target {
($ty:ident) => {
$ty::AssignmentTargetIdentifier(_)
| $ty::ComputedMemberExpression(_)
| $ty::StaticMemberExpression(_)
| $ty::PrivateFieldExpression(_)
| $ty::TSAsExpression(_)
| $ty::TSSatisfiesExpression(_)
| $ty::TSNonNullExpression(_)
| $ty::TSTypeAssertion(_)
| $ty::TSInstantiationExpression(_)
| $ty::ArrayAssignmentTarget(_)
| $ty::ObjectAssignmentTarget(_)
};
}
pub use match_assignment_target;
inherit_variants! {
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum SimpleAssignmentTarget<'a> {
AssignmentTargetIdentifier(Box<'a, IdentifierReference<'a>>) = 0,
TSAsExpression(Box<'a, TSAsExpression<'a>>) = 1,
TSSatisfiesExpression(Box<'a, TSSatisfiesExpression<'a>>) = 2,
TSNonNullExpression(Box<'a, TSNonNullExpression<'a>>) = 3,
TSTypeAssertion(Box<'a, TSTypeAssertion<'a>>) = 4,
TSInstantiationExpression(Box<'a, TSInstantiationExpression<'a>>) = 5,
@inherit MemberExpression
}
}
#[macro_export]
macro_rules! match_simple_assignment_target {
($ty:ident) => {
$ty::AssignmentTargetIdentifier(_)
| $ty::ComputedMemberExpression(_)
| $ty::StaticMemberExpression(_)
| $ty::PrivateFieldExpression(_)
| $ty::TSAsExpression(_)
| $ty::TSSatisfiesExpression(_)
| $ty::TSNonNullExpression(_)
| $ty::TSTypeAssertion(_)
| $ty::TSInstantiationExpression(_)
};
}
pub use match_simple_assignment_target;
impl<'a> SimpleAssignmentTarget<'a> {
pub fn get_identifier(&self) -> Option<&str> {
match self {
Self::AssignmentTargetIdentifier(ident) => Some(ident.name.as_str()),
match_member_expression!(Self) => self.to_member_expression().static_property_name(),
_ => None,
}
}
pub fn get_expression(&self) -> Option<&Expression<'a>> {
match self {
Self::TSAsExpression(expr) => Some(&expr.expression),
Self::TSSatisfiesExpression(expr) => Some(&expr.expression),
Self::TSNonNullExpression(expr) => Some(&expr.expression),
Self::TSTypeAssertion(expr) => Some(&expr.expression),
_ => None,
}
}
}
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum AssignmentTargetPattern<'a> {
ArrayAssignmentTarget(Box<'a, ArrayAssignmentTarget<'a>>) = 8,
ObjectAssignmentTarget(Box<'a, ObjectAssignmentTarget<'a>>) = 9,
}
#[macro_export]
macro_rules! match_assignment_target_pattern {
($ty:ident) => {
$ty::ArrayAssignmentTarget(_) | $ty::ObjectAssignmentTarget(_)
};
}
pub use match_assignment_target_pattern;
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ArrayAssignmentTarget<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
#[cfg_attr(
feature = "serialize",
tsify(type = "Array<AssignmentTargetMaybeDefault | AssignmentTargetRest | null>")
)]
pub elements: Vec<'a, Option<AssignmentTargetMaybeDefault<'a>>>,
#[cfg_attr(feature = "serialize", serde(skip))]
pub rest: Option<AssignmentTargetRest<'a>>,
#[cfg_attr(feature = "serialize", serde(skip))]
pub trailing_comma: Option<Span>,
}
impl<'a> ArrayAssignmentTarget<'a> {
pub fn new_with_elements(
span: Span,
elements: Vec<'a, Option<AssignmentTargetMaybeDefault<'a>>>,
) -> Self {
Self { span, elements, rest: None, trailing_comma: None }
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ObjectAssignmentTarget<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
#[cfg_attr(
feature = "serialize",
tsify(type = "Array<AssignmentTargetProperty | AssignmentTargetRest>")
)]
pub properties: Vec<'a, AssignmentTargetProperty<'a>>,
#[cfg_attr(feature = "serialize", serde(skip))]
pub rest: Option<AssignmentTargetRest<'a>>,
}
impl<'a> ObjectAssignmentTarget<'a> {
pub fn new_with_properties(
span: Span,
properties: Vec<'a, AssignmentTargetProperty<'a>>,
) -> Self {
Self { span, properties, rest: None }
}
pub fn is_empty(&self) -> bool {
self.properties.is_empty() && self.rest.is_none()
}
pub fn len(&self) -> usize {
self.properties.len() + usize::from(self.rest.is_some())
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename = "RestElement"))]
pub struct AssignmentTargetRest<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
#[cfg_attr(feature = "serialize", serde(rename = "argument"))]
pub target: AssignmentTarget<'a>,
}
inherit_variants! {
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum AssignmentTargetMaybeDefault<'a> {
AssignmentTargetWithDefault(Box<'a, AssignmentTargetWithDefault<'a>>) = 16,
@inherit AssignmentTarget
}
}
impl<'a> AssignmentTargetMaybeDefault<'a> {
pub fn name(&self) -> Option<Atom> {
match self {
AssignmentTargetMaybeDefault::AssignmentTargetIdentifier(id) => Some(id.name.clone()),
Self::AssignmentTargetWithDefault(target) => {
if let AssignmentTarget::AssignmentTargetIdentifier(id) = &target.binding {
Some(id.name.clone())
} else {
None
}
}
_ => None,
}
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct AssignmentTargetWithDefault<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub binding: AssignmentTarget<'a>,
pub init: Expression<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum AssignmentTargetProperty<'a> {
AssignmentTargetPropertyIdentifier(Box<'a, AssignmentTargetPropertyIdentifier<'a>>),
AssignmentTargetPropertyProperty(Box<'a, AssignmentTargetPropertyProperty<'a>>),
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct AssignmentTargetPropertyIdentifier<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub binding: IdentifierReference<'a>,
pub init: Option<Expression<'a>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct AssignmentTargetPropertyProperty<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub name: PropertyKey<'a>,
pub binding: AssignmentTargetMaybeDefault<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct SequenceExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub expressions: Vec<'a, Expression<'a>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct Super {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct AwaitExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub argument: Expression<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ChainExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub expression: ChainElement<'a>,
}
inherit_variants! {
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum ChainElement<'a> {
CallExpression(Box<'a, CallExpression<'a>>) = 0,
@inherit MemberExpression
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ParenthesizedExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub expression: Expression<'a>,
}
inherit_variants! {
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum Statement<'a> {
BlockStatement(Box<'a, BlockStatement<'a>>) = 0,
BreakStatement(Box<'a, BreakStatement<'a>>) = 1,
ContinueStatement(Box<'a, ContinueStatement<'a>>) = 2,
DebuggerStatement(Box<'a, DebuggerStatement>) = 3,
DoWhileStatement(Box<'a, DoWhileStatement<'a>>) = 4,
EmptyStatement(Box<'a, EmptyStatement>) = 5,
ExpressionStatement(Box<'a, ExpressionStatement<'a>>) = 6,
ForInStatement(Box<'a, ForInStatement<'a>>) = 7,
ForOfStatement(Box<'a, ForOfStatement<'a>>) = 8,
ForStatement(Box<'a, ForStatement<'a>>) = 9,
IfStatement(Box<'a, IfStatement<'a>>) = 10,
LabeledStatement(Box<'a, LabeledStatement<'a>>) = 11,
ReturnStatement(Box<'a, ReturnStatement<'a>>) = 12,
SwitchStatement(Box<'a, SwitchStatement<'a>>) = 13,
ThrowStatement(Box<'a, ThrowStatement<'a>>) = 14,
TryStatement(Box<'a, TryStatement<'a>>) = 15,
WhileStatement(Box<'a, WhileStatement<'a>>) = 16,
WithStatement(Box<'a, WithStatement<'a>>) = 17,
@inherit Declaration
@inherit ModuleDeclaration
}
}
impl<'a> Statement<'a> {
pub fn is_typescript_syntax(&self) -> bool {
match self {
match_declaration!(Self) => {
self.as_declaration().is_some_and(Declaration::is_typescript_syntax)
}
match_module_declaration!(Self) => {
self.as_module_declaration().is_some_and(ModuleDeclaration::is_typescript_syntax)
}
_ => false,
}
}
pub fn is_iteration_statement(&self) -> bool {
matches!(
self,
Statement::DoWhileStatement(_)
| Statement::ForInStatement(_)
| Statement::ForOfStatement(_)
| Statement::ForStatement(_)
| Statement::WhileStatement(_)
)
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct Directive<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub expression: StringLiteral<'a>,
pub directive: Atom<'a>,
}
impl<'a> Directive<'a> {
pub fn is_use_strict(&self) -> bool {
self.directive == "use strict"
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct Hashbang<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub value: Atom<'a>,
}
#[visited_node(scope(ScopeFlags::empty()))]
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct BlockStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub body: Vec<'a, Statement<'a>>,
pub scope_id: Cell<Option<ScopeId>>,
}
impl<'a> BlockStatement<'a> {
pub fn new(span: Span, body: Vec<'a, Statement<'a>>) -> Self {
Self { span, body, scope_id: Cell::default() }
}
}
impl<'a> Hash for BlockStatement<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.body.hash(state);
}
}
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum Declaration<'a> {
VariableDeclaration(Box<'a, VariableDeclaration<'a>>) = 32,
FunctionDeclaration(Box<'a, Function<'a>>) = 33,
ClassDeclaration(Box<'a, Class<'a>>) = 34,
UsingDeclaration(Box<'a, UsingDeclaration<'a>>) = 35,
TSTypeAliasDeclaration(Box<'a, TSTypeAliasDeclaration<'a>>) = 36,
TSInterfaceDeclaration(Box<'a, TSInterfaceDeclaration<'a>>) = 37,
TSEnumDeclaration(Box<'a, TSEnumDeclaration<'a>>) = 38,
TSModuleDeclaration(Box<'a, TSModuleDeclaration<'a>>) = 39,
TSImportEqualsDeclaration(Box<'a, TSImportEqualsDeclaration<'a>>) = 40,
}
#[macro_export]
macro_rules! match_declaration {
($ty:ident) => {
$ty::VariableDeclaration(_)
| $ty::FunctionDeclaration(_)
| $ty::ClassDeclaration(_)
| $ty::UsingDeclaration(_)
| $ty::TSTypeAliasDeclaration(_)
| $ty::TSInterfaceDeclaration(_)
| $ty::TSEnumDeclaration(_)
| $ty::TSModuleDeclaration(_)
| $ty::TSImportEqualsDeclaration(_)
};
}
pub use match_declaration;
impl<'a> Declaration<'a> {
pub fn is_typescript_syntax(&self) -> bool {
match self {
Self::VariableDeclaration(decl) => decl.is_typescript_syntax(),
Self::FunctionDeclaration(func) => func.is_typescript_syntax(),
Self::ClassDeclaration(class) => class.is_typescript_syntax(),
Self::UsingDeclaration(_) => false,
_ => true,
}
}
pub fn id(&self) -> Option<&BindingIdentifier<'a>> {
match self {
Declaration::FunctionDeclaration(decl) => decl.id.as_ref(),
Declaration::ClassDeclaration(decl) => decl.id.as_ref(),
Declaration::TSTypeAliasDeclaration(decl) => Some(&decl.id),
Declaration::TSInterfaceDeclaration(decl) => Some(&decl.id),
Declaration::TSEnumDeclaration(decl) => Some(&decl.id),
Declaration::TSImportEqualsDeclaration(decl) => Some(&decl.id),
_ => None,
}
}
pub fn modifiers(&self) -> Option<&Modifiers<'a>> {
match self {
Declaration::VariableDeclaration(decl) => Some(&decl.modifiers),
Declaration::FunctionDeclaration(decl) => Some(&decl.modifiers),
Declaration::ClassDeclaration(decl) => Some(&decl.modifiers),
Declaration::TSEnumDeclaration(decl) => Some(&decl.modifiers),
Declaration::TSTypeAliasDeclaration(decl) => Some(&decl.modifiers),
Declaration::TSModuleDeclaration(decl) => Some(&decl.modifiers),
Declaration::TSInterfaceDeclaration(decl) => Some(&decl.modifiers),
_ => None,
}
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct VariableDeclaration<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub kind: VariableDeclarationKind,
pub declarations: Vec<'a, VariableDeclarator<'a>>,
pub modifiers: Modifiers<'a>,
}
impl<'a> VariableDeclaration<'a> {
pub fn is_typescript_syntax(&self) -> bool {
self.modifiers.contains(ModifierKind::Declare)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(rename_all = "lowercase"))]
pub enum VariableDeclarationKind {
Var,
Const,
Let,
}
impl VariableDeclarationKind {
pub fn is_var(&self) -> bool {
matches!(self, Self::Var)
}
pub fn is_const(&self) -> bool {
matches!(self, Self::Const)
}
pub fn is_lexical(&self) -> bool {
matches!(self, Self::Const | Self::Let)
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Var => "var",
Self::Const => "const",
Self::Let => "let",
}
}
}
impl fmt::Display for VariableDeclarationKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = self.as_str();
write!(f, "{s}")
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct VariableDeclarator<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
#[cfg_attr(feature = "serialize", serde(skip))]
pub kind: VariableDeclarationKind,
pub id: BindingPattern<'a>,
pub init: Option<Expression<'a>>,
pub definite: bool,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct UsingDeclaration<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub is_await: bool,
#[cfg_attr(feature = "serialize", serde(default))]
pub declarations: Vec<'a, VariableDeclarator<'a>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct EmptyStatement {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ExpressionStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub expression: Expression<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct IfStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub test: Expression<'a>,
pub consequent: Statement<'a>,
pub alternate: Option<Statement<'a>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct DoWhileStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub body: Statement<'a>,
pub test: Expression<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct WhileStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub test: Expression<'a>,
pub body: Statement<'a>,
}
#[visited_node(
scope(ScopeFlags::empty()),
scope_if(self.init.as_ref().is_some_and(ForStatementInit::is_lexical_declaration))
)]
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ForStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub init: Option<ForStatementInit<'a>>,
pub test: Option<Expression<'a>>,
pub update: Option<Expression<'a>>,
pub body: Statement<'a>,
pub scope_id: Cell<Option<ScopeId>>,
}
impl<'a> ForStatement<'a> {
pub fn new(
span: Span,
init: Option<ForStatementInit<'a>>,
test: Option<Expression<'a>>,
update: Option<Expression<'a>>,
body: Statement<'a>,
) -> Self {
Self { span, init, test, update, body, scope_id: Cell::default() }
}
}
impl<'a> Hash for ForStatement<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.init.hash(state);
self.test.hash(state);
self.update.hash(state);
self.body.hash(state);
}
}
inherit_variants! {
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum ForStatementInit<'a> {
VariableDeclaration(Box<'a, VariableDeclaration<'a>>) = 64,
UsingDeclaration(Box<'a, UsingDeclaration<'a>>) = 65,
@inherit Expression
}
}
impl<'a> ForStatementInit<'a> {
pub fn is_lexical_declaration(&self) -> bool {
matches!(self, Self::VariableDeclaration(decl) if decl.kind.is_lexical())
}
}
#[visited_node(scope(ScopeFlags::empty()), scope_if(self.left.is_lexical_declaration()))]
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ForInStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub left: ForStatementLeft<'a>,
pub right: Expression<'a>,
pub body: Statement<'a>,
pub scope_id: Cell<Option<ScopeId>>,
}
impl<'a> ForInStatement<'a> {
pub fn new(
span: Span,
left: ForStatementLeft<'a>,
right: Expression<'a>,
body: Statement<'a>,
) -> Self {
Self { span, left, right, body, scope_id: Cell::default() }
}
}
impl<'a> Hash for ForInStatement<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.left.hash(state);
self.right.hash(state);
self.body.hash(state);
}
}
#[visited_node(scope(ScopeFlags::empty()), scope_if(self.left.is_lexical_declaration()))]
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ForOfStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub r#await: bool,
pub left: ForStatementLeft<'a>,
pub right: Expression<'a>,
pub body: Statement<'a>,
pub scope_id: Cell<Option<ScopeId>>,
}
impl<'a> ForOfStatement<'a> {
pub fn new(
span: Span,
r#await: bool,
left: ForStatementLeft<'a>,
right: Expression<'a>,
body: Statement<'a>,
) -> Self {
Self { span, r#await, left, right, body, scope_id: Cell::default() }
}
}
impl<'a> Hash for ForOfStatement<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.r#await.hash(state);
self.left.hash(state);
self.right.hash(state);
self.body.hash(state);
}
}
inherit_variants! {
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum ForStatementLeft<'a> {
VariableDeclaration(Box<'a, VariableDeclaration<'a>>) = 16,
UsingDeclaration(Box<'a, UsingDeclaration<'a>>) = 17,
@inherit AssignmentTarget
}
}
impl<'a> ForStatementLeft<'a> {
pub fn is_lexical_declaration(&self) -> bool {
matches!(self, Self::VariableDeclaration(decl) if decl.kind.is_lexical())
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ContinueStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub label: Option<LabelIdentifier<'a>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct BreakStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub label: Option<LabelIdentifier<'a>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ReturnStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub argument: Option<Expression<'a>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct WithStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub object: Expression<'a>,
pub body: Statement<'a>,
}
#[visited_node(scope(ScopeFlags::empty()), enter_scope_before(cases))]
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct SwitchStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub discriminant: Expression<'a>,
pub cases: Vec<'a, SwitchCase<'a>>,
pub scope_id: Cell<Option<ScopeId>>,
}
impl<'a> SwitchStatement<'a> {
pub fn new(span: Span, discriminant: Expression<'a>, cases: Vec<'a, SwitchCase<'a>>) -> Self {
Self { span, discriminant, cases, scope_id: Cell::default() }
}
}
impl<'a> Hash for SwitchStatement<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.discriminant.hash(state);
self.cases.hash(state);
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct SwitchCase<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub test: Option<Expression<'a>>,
pub consequent: Vec<'a, Statement<'a>>,
}
impl<'a> SwitchCase<'a> {
pub fn is_default_case(&self) -> bool {
self.test.is_none()
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct LabeledStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub label: LabelIdentifier<'a>,
pub body: Statement<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ThrowStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub argument: Expression<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct TryStatement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub block: Box<'a, BlockStatement<'a>>,
pub handler: Option<Box<'a, CatchClause<'a>>>,
pub finalizer: Option<Box<'a, BlockStatement<'a>>>,
}
#[visited_node(scope(ScopeFlags::empty()), scope_if(self.param.is_some()))]
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct CatchClause<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub param: Option<CatchParameter<'a>>,
pub body: Box<'a, BlockStatement<'a>>,
pub scope_id: Cell<Option<ScopeId>>,
}
impl<'a> CatchClause<'a> {
pub fn new(
span: Span,
param: Option<CatchParameter<'a>>,
body: Box<'a, BlockStatement<'a>>,
) -> Self {
Self { span, param, body, scope_id: Cell::default() }
}
}
impl<'a> Hash for CatchClause<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.param.hash(state);
self.body.hash(state);
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct CatchParameter<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub pattern: BindingPattern<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct DebuggerStatement {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
pub struct BindingPattern<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
#[cfg_attr(
feature = "serialize",
tsify(type = "(BindingIdentifier | ObjectPattern | ArrayPattern | AssignmentPattern)")
)]
pub kind: BindingPatternKind<'a>,
pub type_annotation: Option<Box<'a, TSTypeAnnotation<'a>>>,
pub optional: bool,
}
impl<'a> BindingPattern<'a> {
pub fn new_with_kind(kind: BindingPatternKind<'a>) -> Self {
Self { kind, type_annotation: None, optional: false }
}
pub fn get_identifier(&self) -> Option<&Atom<'a>> {
self.kind.get_identifier()
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum BindingPatternKind<'a> {
BindingIdentifier(Box<'a, BindingIdentifier<'a>>),
ObjectPattern(Box<'a, ObjectPattern<'a>>),
ArrayPattern(Box<'a, ArrayPattern<'a>>),
AssignmentPattern(Box<'a, AssignmentPattern<'a>>),
}
impl<'a> BindingPatternKind<'a> {
pub fn get_identifier(&self) -> Option<&Atom<'a>> {
match self {
Self::BindingIdentifier(ident) => Some(&ident.name),
Self::AssignmentPattern(assign) => assign.left.get_identifier(),
_ => None,
}
}
pub fn is_destructuring_pattern(&self) -> bool {
matches!(self, Self::ObjectPattern(_) | Self::ArrayPattern(_))
}
pub fn is_binding_identifier(&self) -> bool {
matches!(self, Self::BindingIdentifier(_))
}
pub fn is_assignment_pattern(&self) -> bool {
matches!(self, Self::AssignmentPattern(_))
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct AssignmentPattern<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub left: BindingPattern<'a>,
pub right: Expression<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ObjectPattern<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
#[cfg_attr(feature = "serialize", tsify(type = "Array<BindingProperty | BindingRestElement>"))]
pub properties: Vec<'a, BindingProperty<'a>>,
#[cfg_attr(feature = "serialize", serde(skip))]
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
}
impl<'a> ObjectPattern<'a> {
pub fn is_empty(&self) -> bool {
self.properties.is_empty() && self.rest.is_none()
}
pub fn len(&self) -> usize {
self.properties.len() + usize::from(self.rest.is_some())
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct BindingProperty<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub key: PropertyKey<'a>,
pub value: BindingPattern<'a>,
pub shorthand: bool,
pub computed: bool,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ArrayPattern<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
#[cfg_attr(
feature = "serialize",
tsify(type = "Array<BindingPattern | BindingRestElement | null>")
)]
pub elements: Vec<'a, Option<BindingPattern<'a>>>,
#[cfg_attr(feature = "serialize", serde(skip))]
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
}
impl<'a> ArrayPattern<'a> {
pub fn is_empty(&self) -> bool {
self.elements.is_empty() && self.rest.is_none()
}
pub fn len(&self) -> usize {
self.elements.len() + usize::from(self.rest.is_some())
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename = "RestElement"))]
pub struct BindingRestElement<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub argument: BindingPattern<'a>,
}
#[visited_node(
scope(ScopeFlags::Function),
strict_if(self.body.as_ref().is_some_and(|body| body.has_use_strict_directive()))
)]
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
pub struct Function<'a> {
pub r#type: FunctionType,
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub id: Option<BindingIdentifier<'a>>,
pub generator: bool,
pub r#async: bool,
pub this_param: Option<TSThisParameter<'a>>,
pub params: Box<'a, FormalParameters<'a>>,
pub body: Option<Box<'a, FunctionBody<'a>>>,
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
pub return_type: Option<Box<'a, TSTypeAnnotation<'a>>>,
pub modifiers: Modifiers<'a>,
pub scope_id: Cell<Option<ScopeId>>,
}
impl<'a> Function<'a> {
#![allow(clippy::too_many_arguments)]
pub fn new(
r#type: FunctionType,
span: Span,
id: Option<BindingIdentifier<'a>>,
generator: bool,
r#async: bool,
this_param: Option<TSThisParameter<'a>>,
params: Box<'a, FormalParameters<'a>>,
body: Option<Box<'a, FunctionBody<'a>>>,
type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
return_type: Option<Box<'a, TSTypeAnnotation<'a>>>,
modifiers: Modifiers<'a>,
) -> Self {
Self {
r#type,
span,
id,
generator,
r#async,
this_param,
params,
body,
type_parameters,
return_type,
modifiers,
scope_id: Cell::default(),
}
}
pub fn is_typescript_syntax(&self) -> bool {
matches!(
self.r#type,
FunctionType::TSDeclareFunction | FunctionType::TSEmptyBodyFunctionExpression
) || self.body.is_none()
|| self.modifiers.contains(ModifierKind::Declare)
}
pub fn is_expression(&self) -> bool {
self.r#type == FunctionType::FunctionExpression
}
pub fn is_function_declaration(&self) -> bool {
matches!(self.r#type, FunctionType::FunctionDeclaration)
}
pub fn is_ts_declare_function(&self) -> bool {
matches!(self.r#type, FunctionType::TSDeclareFunction)
}
pub fn is_declaration(&self) -> bool {
matches!(self.r#type, FunctionType::FunctionDeclaration | FunctionType::TSDeclareFunction)
}
pub fn is_strict(&self) -> bool {
self.body.as_ref().is_some_and(|body| body.has_use_strict_directive())
}
}
impl<'a> Hash for Function<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.r#type.hash(state);
self.id.hash(state);
self.generator.hash(state);
self.r#async.hash(state);
self.this_param.hash(state);
self.params.hash(state);
self.body.hash(state);
self.type_parameters.hash(state);
self.return_type.hash(state);
self.modifiers.hash(state);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
pub enum FunctionType {
FunctionDeclaration,
FunctionExpression,
TSDeclareFunction,
TSEmptyBodyFunctionExpression,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct FormalParameters<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub kind: FormalParameterKind,
#[cfg_attr(
feature = "serialize",
tsify(type = "Array<FormalParameter | FormalParameterRest>")
)]
pub items: Vec<'a, FormalParameter<'a>>,
#[cfg_attr(feature = "serialize", serde(skip))]
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
}
impl<'a> FormalParameters<'a> {
pub fn parameters_count(&self) -> usize {
self.items.len() + self.rest.as_ref().map_or(0, |_| 1)
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct FormalParameter<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub pattern: BindingPattern<'a>,
pub accessibility: Option<TSAccessibility>,
pub readonly: bool,
pub r#override: bool,
pub decorators: Vec<'a, Decorator<'a>>,
}
impl<'a> FormalParameter<'a> {
pub fn is_public(&self) -> bool {
matches!(self.accessibility, Some(TSAccessibility::Public))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
pub enum FormalParameterKind {
FormalParameter,
UniqueFormalParameters,
ArrowFormalParameters,
Signature,
}
impl FormalParameterKind {
pub fn is_signature(&self) -> bool {
matches!(self, Self::Signature)
}
}
impl<'a> FormalParameters<'a> {
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct FunctionBody<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub directives: Vec<'a, Directive<'a>>,
pub statements: Vec<'a, Statement<'a>>,
}
impl<'a> FunctionBody<'a> {
pub fn is_empty(&self) -> bool {
self.directives.is_empty() && self.statements.is_empty()
}
pub fn has_use_strict_directive(&self) -> bool {
self.directives.iter().any(Directive::is_use_strict)
}
}
#[visited_node(
scope(ScopeFlags::Function | ScopeFlags::Arrow),
strict_if(self.body.has_use_strict_directive())
)]
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct ArrowFunctionExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub expression: bool,
pub r#async: bool,
pub params: Box<'a, FormalParameters<'a>>,
pub body: Box<'a, FunctionBody<'a>>,
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
pub return_type: Option<Box<'a, TSTypeAnnotation<'a>>>,
pub scope_id: Cell<Option<ScopeId>>,
}
impl<'a> ArrowFunctionExpression<'a> {
pub fn new(
span: Span,
expression: bool,
r#async: bool,
params: Box<'a, FormalParameters<'a>>,
body: Box<'a, FunctionBody<'a>>,
type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
return_type: Option<Box<'a, TSTypeAnnotation<'a>>>,
) -> Self {
Self {
span,
expression,
r#async,
params,
body,
type_parameters,
return_type,
scope_id: Cell::default(),
}
}
pub fn get_expression(&self) -> Option<&Expression<'a>> {
if self.expression {
if let Statement::ExpressionStatement(expr_stmt) = &self.body.statements[0] {
return Some(&expr_stmt.expression);
}
}
None
}
}
impl<'a> Hash for ArrowFunctionExpression<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.expression.hash(state);
self.r#async.hash(state);
self.params.hash(state);
self.body.hash(state);
self.type_parameters.hash(state);
self.return_type.hash(state);
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct YieldExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub delegate: bool,
pub argument: Option<Expression<'a>>,
}
#[visited_node(scope(ScopeFlags::StrictMode), enter_scope_before(id))]
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
pub struct Class<'a> {
pub r#type: ClassType,
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub decorators: Vec<'a, Decorator<'a>>,
pub id: Option<BindingIdentifier<'a>>,
pub super_class: Option<Expression<'a>>,
pub body: Box<'a, ClassBody<'a>>,
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
pub super_type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
pub implements: Option<Vec<'a, TSClassImplements<'a>>>,
pub modifiers: Modifiers<'a>,
pub scope_id: Cell<Option<ScopeId>>,
}
impl<'a> Class<'a> {
#[allow(clippy::too_many_arguments)]
pub fn new(
r#type: ClassType,
span: Span,
decorators: Vec<'a, Decorator<'a>>,
id: Option<BindingIdentifier<'a>>,
super_class: Option<Expression<'a>>,
body: Box<'a, ClassBody<'a>>,
type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
super_type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
implements: Option<Vec<'a, TSClassImplements<'a>>>,
modifiers: Modifiers<'a>,
) -> Self {
Self {
r#type,
span,
decorators,
id,
super_class,
body,
type_parameters,
super_type_parameters,
implements,
modifiers,
scope_id: Cell::default(),
}
}
pub fn is_expression(&self) -> bool {
self.r#type == ClassType::ClassExpression
}
pub fn is_declaration(&self) -> bool {
self.r#type == ClassType::ClassDeclaration
}
pub fn is_declare(&self) -> bool {
self.modifiers.contains(ModifierKind::Declare)
}
pub fn is_typescript_syntax(&self) -> bool {
self.is_declare()
}
}
impl<'a> Hash for Class<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.r#type.hash(state);
self.decorators.hash(state);
self.id.hash(state);
self.super_class.hash(state);
self.body.hash(state);
self.type_parameters.hash(state);
self.super_type_parameters.hash(state);
self.implements.hash(state);
self.modifiers.hash(state);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
pub enum ClassType {
ClassDeclaration,
ClassExpression,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ClassBody<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub body: Vec<'a, ClassElement<'a>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum ClassElement<'a> {
StaticBlock(Box<'a, StaticBlock<'a>>),
MethodDefinition(Box<'a, MethodDefinition<'a>>),
PropertyDefinition(Box<'a, PropertyDefinition<'a>>),
AccessorProperty(Box<'a, AccessorProperty<'a>>),
TSIndexSignature(Box<'a, TSIndexSignature<'a>>),
}
impl<'a> ClassElement<'a> {
pub fn r#static(&self) -> bool {
match self {
Self::TSIndexSignature(_) | Self::StaticBlock(_) => false,
Self::MethodDefinition(def) => def.r#static,
Self::PropertyDefinition(def) => def.r#static,
Self::AccessorProperty(def) => def.r#static,
}
}
pub fn computed(&self) -> bool {
match self {
Self::TSIndexSignature(_) | Self::StaticBlock(_) => false,
Self::MethodDefinition(def) => def.computed,
Self::PropertyDefinition(def) => def.computed,
Self::AccessorProperty(def) => def.computed,
}
}
pub fn accessibility(&self) -> Option<TSAccessibility> {
match self {
Self::StaticBlock(_) | Self::TSIndexSignature(_) | Self::AccessorProperty(_) => None,
Self::MethodDefinition(def) => def.accessibility,
Self::PropertyDefinition(def) => def.accessibility,
}
}
pub fn method_definition_kind(&self) -> Option<MethodDefinitionKind> {
match self {
Self::TSIndexSignature(_)
| Self::StaticBlock(_)
| Self::PropertyDefinition(_)
| Self::AccessorProperty(_) => None,
Self::MethodDefinition(def) => Some(def.kind),
}
}
pub fn property_key(&self) -> Option<&PropertyKey<'a>> {
match self {
Self::TSIndexSignature(_) | Self::StaticBlock(_) => None,
Self::MethodDefinition(def) => Some(&def.key),
Self::PropertyDefinition(def) => Some(&def.key),
Self::AccessorProperty(def) => Some(&def.key),
}
}
pub fn static_name(&self) -> Option<CompactStr> {
match self {
Self::TSIndexSignature(_) | Self::StaticBlock(_) => None,
Self::MethodDefinition(def) => def.key.static_name(),
Self::PropertyDefinition(def) => def.key.static_name(),
Self::AccessorProperty(def) => def.key.static_name(),
}
}
pub fn is_property(&self) -> bool {
matches!(self, Self::PropertyDefinition(_) | Self::AccessorProperty(_))
}
pub fn is_ts_empty_body_function(&self) -> bool {
match self {
Self::PropertyDefinition(_)
| Self::StaticBlock(_)
| Self::AccessorProperty(_)
| Self::TSIndexSignature(_) => false,
Self::MethodDefinition(method) => method.value.body.is_none(),
}
}
pub fn is_typescript_syntax(&self) -> bool {
match self {
Self::TSIndexSignature(_) => true,
Self::MethodDefinition(method) => method.value.is_typescript_syntax(),
Self::PropertyDefinition(property) => {
property.r#type == PropertyDefinitionType::TSAbstractPropertyDefinition
}
Self::AccessorProperty(property) => property.r#type.is_abstract(),
Self::StaticBlock(_) => false,
}
}
pub fn has_decorator(&self) -> bool {
match self {
Self::MethodDefinition(method) => !method.decorators.is_empty(),
Self::PropertyDefinition(property) => !property.decorators.is_empty(),
Self::AccessorProperty(property) => !property.decorators.is_empty(),
Self::StaticBlock(_) | Self::TSIndexSignature(_) => false,
}
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
pub struct MethodDefinition<'a> {
pub r#type: MethodDefinitionType,
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub decorators: Vec<'a, Decorator<'a>>,
pub key: PropertyKey<'a>,
pub value: Box<'a, Function<'a>>, pub kind: MethodDefinitionKind,
pub computed: bool,
pub r#static: bool,
pub r#override: bool,
pub optional: bool,
pub accessibility: Option<TSAccessibility>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
pub enum MethodDefinitionType {
MethodDefinition,
TSAbstractMethodDefinition,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
pub struct PropertyDefinition<'a> {
pub r#type: PropertyDefinitionType,
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub key: PropertyKey<'a>,
pub value: Option<Expression<'a>>,
pub computed: bool,
pub r#static: bool,
pub declare: bool,
pub r#override: bool,
pub optional: bool,
pub definite: bool,
pub readonly: bool,
pub type_annotation: Option<Box<'a, TSTypeAnnotation<'a>>>,
pub accessibility: Option<TSAccessibility>,
pub decorators: Vec<'a, Decorator<'a>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
pub enum PropertyDefinitionType {
PropertyDefinition,
TSAbstractPropertyDefinition,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(rename_all = "lowercase"))]
pub enum MethodDefinitionKind {
Constructor,
Method,
Get,
Set,
}
impl MethodDefinitionKind {
pub fn is_constructor(&self) -> bool {
matches!(self, Self::Constructor)
}
pub fn is_method(&self) -> bool {
matches!(self, Self::Method)
}
pub fn is_set(&self) -> bool {
matches!(self, Self::Set)
}
pub fn scope_flags(self) -> ScopeFlags {
match self {
Self::Constructor => ScopeFlags::Constructor | ScopeFlags::Function,
Self::Method => ScopeFlags::Function,
Self::Get => ScopeFlags::GetAccessor | ScopeFlags::Function,
Self::Set => ScopeFlags::SetAccessor | ScopeFlags::Function,
}
}
}
#[visited_node]
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct PrivateIdentifier<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub name: Atom<'a>,
}
impl<'a> PrivateIdentifier<'a> {
pub fn new(span: Span, name: Atom<'a>) -> Self {
Self { span, name }
}
}
#[visited_node(scope(ScopeFlags::ClassStaticBlock))]
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct StaticBlock<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub body: Vec<'a, Statement<'a>>,
pub scope_id: Cell<Option<ScopeId>>,
}
impl<'a> StaticBlock<'a> {
pub fn new(span: Span, body: Vec<'a, Statement<'a>>) -> Self {
Self { span, body, scope_id: Cell::default() }
}
}
impl<'a> Hash for StaticBlock<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.body.hash(state);
}
}
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum ModuleDeclaration<'a> {
ImportDeclaration(Box<'a, ImportDeclaration<'a>>) = 64,
ExportAllDeclaration(Box<'a, ExportAllDeclaration<'a>>) = 65,
ExportDefaultDeclaration(Box<'a, ExportDefaultDeclaration<'a>>) = 66,
ExportNamedDeclaration(Box<'a, ExportNamedDeclaration<'a>>) = 67,
TSExportAssignment(Box<'a, TSExportAssignment<'a>>) = 68,
TSNamespaceExportDeclaration(Box<'a, TSNamespaceExportDeclaration<'a>>) = 69,
}
#[macro_export]
macro_rules! match_module_declaration {
($ty:ident) => {
$ty::ImportDeclaration(_)
| $ty::ExportAllDeclaration(_)
| $ty::ExportDefaultDeclaration(_)
| $ty::ExportNamedDeclaration(_)
| $ty::TSExportAssignment(_)
| $ty::TSNamespaceExportDeclaration(_)
};
}
pub use match_module_declaration;
impl<'a> ModuleDeclaration<'a> {
pub fn is_typescript_syntax(&self) -> bool {
match self {
ModuleDeclaration::ImportDeclaration(_) => false,
ModuleDeclaration::ExportDefaultDeclaration(decl) => decl.is_typescript_syntax(),
ModuleDeclaration::ExportNamedDeclaration(decl) => decl.is_typescript_syntax(),
ModuleDeclaration::ExportAllDeclaration(decl) => decl.is_typescript_syntax(),
ModuleDeclaration::TSNamespaceExportDeclaration(_)
| ModuleDeclaration::TSExportAssignment(_) => true,
}
}
pub fn is_import(&self) -> bool {
matches!(self, Self::ImportDeclaration(_))
}
pub fn is_export(&self) -> bool {
matches!(
self,
Self::ExportAllDeclaration(_)
| Self::ExportDefaultDeclaration(_)
| Self::ExportNamedDeclaration(_)
| Self::TSExportAssignment(_)
| Self::TSNamespaceExportDeclaration(_)
)
}
pub fn is_default_export(&self) -> bool {
matches!(self, Self::ExportDefaultDeclaration(_))
}
pub fn source(&self) -> Option<&StringLiteral<'a>> {
match self {
Self::ImportDeclaration(decl) => Some(&decl.source),
Self::ExportAllDeclaration(decl) => Some(&decl.source),
Self::ExportNamedDeclaration(decl) => decl.source.as_ref(),
Self::ExportDefaultDeclaration(_)
| Self::TSExportAssignment(_)
| Self::TSNamespaceExportDeclaration(_) => None,
}
}
pub fn with_clause(&self) -> Option<&WithClause<'a>> {
match self {
Self::ImportDeclaration(decl) => decl.with_clause.as_ref(),
Self::ExportAllDeclaration(decl) => decl.with_clause.as_ref(),
Self::ExportNamedDeclaration(decl) => decl.with_clause.as_ref(),
Self::ExportDefaultDeclaration(_)
| Self::TSExportAssignment(_)
| Self::TSNamespaceExportDeclaration(_) => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
pub enum AccessorPropertyType {
AccessorProperty,
TSAbstractAccessorProperty,
}
impl AccessorPropertyType {
pub fn is_abstract(&self) -> bool {
matches!(self, Self::TSAbstractAccessorProperty)
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
pub struct AccessorProperty<'a> {
pub r#type: AccessorPropertyType,
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub key: PropertyKey<'a>,
pub value: Option<Expression<'a>>,
pub computed: bool,
pub r#static: bool,
pub decorators: Vec<'a, Decorator<'a>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ImportExpression<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub source: Expression<'a>,
pub arguments: Vec<'a, Expression<'a>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct ImportDeclaration<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub specifiers: Option<Vec<'a, ImportDeclarationSpecifier<'a>>>,
pub source: StringLiteral<'a>,
pub with_clause: Option<WithClause<'a>>,
pub import_kind: ImportOrExportKind,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum ImportDeclarationSpecifier<'a> {
ImportSpecifier(Box<'a, ImportSpecifier<'a>>),
ImportDefaultSpecifier(Box<'a, ImportDefaultSpecifier<'a>>),
ImportNamespaceSpecifier(Box<'a, ImportNamespaceSpecifier<'a>>),
}
impl<'a> ImportDeclarationSpecifier<'a> {
pub fn name(&self) -> CompactStr {
match self {
ImportDeclarationSpecifier::ImportSpecifier(specifier) => {
specifier.local.name.to_compact_str()
}
ImportDeclarationSpecifier::ImportNamespaceSpecifier(specifier) => {
specifier.local.name.to_compact_str()
}
ImportDeclarationSpecifier::ImportDefaultSpecifier(specifier) => {
specifier.local.name.to_compact_str()
}
}
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct ImportSpecifier<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub imported: ModuleExportName<'a>,
pub local: BindingIdentifier<'a>,
pub import_kind: ImportOrExportKind,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ImportDefaultSpecifier<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub local: BindingIdentifier<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ImportNamespaceSpecifier<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub local: BindingIdentifier<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct WithClause<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub attributes_keyword: IdentifierName<'a>, pub with_entries: Vec<'a, ImportAttribute<'a>>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ImportAttribute<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub key: ImportAttributeKey<'a>,
pub value: StringLiteral<'a>,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum ImportAttributeKey<'a> {
Identifier(IdentifierName<'a>),
StringLiteral(StringLiteral<'a>),
}
impl<'a> ImportAttributeKey<'a> {
pub fn as_atom(&self) -> Atom<'a> {
match self {
Self::Identifier(identifier) => identifier.name.clone(),
Self::StringLiteral(literal) => literal.value.clone(),
}
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct ExportNamedDeclaration<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub declaration: Option<Declaration<'a>>,
pub specifiers: Vec<'a, ExportSpecifier<'a>>,
pub source: Option<StringLiteral<'a>>,
pub export_kind: ImportOrExportKind,
pub with_clause: Option<WithClause<'a>>,
}
impl<'a> ExportNamedDeclaration<'a> {
pub fn is_typescript_syntax(&self) -> bool {
self.export_kind == ImportOrExportKind::Type
|| self.declaration.as_ref().map_or(false, Declaration::is_typescript_syntax)
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
pub struct ExportDefaultDeclaration<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub declaration: ExportDefaultDeclarationKind<'a>,
pub exported: ModuleExportName<'a>, }
impl<'a> ExportDefaultDeclaration<'a> {
pub fn is_typescript_syntax(&self) -> bool {
self.declaration.is_typescript_syntax()
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct ExportAllDeclaration<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub exported: Option<ModuleExportName<'a>>,
pub source: StringLiteral<'a>,
pub with_clause: Option<WithClause<'a>>, pub export_kind: ImportOrExportKind, }
impl<'a> ExportAllDeclaration<'a> {
pub fn is_typescript_syntax(&self) -> bool {
self.export_kind.is_type()
}
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct ExportSpecifier<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub local: ModuleExportName<'a>,
pub exported: ModuleExportName<'a>,
pub export_kind: ImportOrExportKind, }
impl<'a> ExportSpecifier<'a> {
pub fn new(span: Span, local: ModuleExportName<'a>, exported: ModuleExportName<'a>) -> Self {
Self { span, local, exported, export_kind: ImportOrExportKind::Value }
}
}
inherit_variants! {
#[visited_node]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum ExportDefaultDeclarationKind<'a> {
FunctionDeclaration(Box<'a, Function<'a>>) = 64,
ClassDeclaration(Box<'a, Class<'a>>) = 65,
TSInterfaceDeclaration(Box<'a, TSInterfaceDeclaration<'a>>) = 66,
TSEnumDeclaration(Box<'a, TSEnumDeclaration<'a>>) = 67,
@inherit Expression
}
}
impl<'a> ExportDefaultDeclarationKind<'a> {
#[inline]
pub fn is_typescript_syntax(&self) -> bool {
match self {
Self::FunctionDeclaration(func) => func.is_typescript_syntax(),
Self::ClassDeclaration(class) => class.is_typescript_syntax(),
Self::TSInterfaceDeclaration(_) | Self::TSEnumDeclaration(_) => true,
_ => false,
}
}
}
#[visited_node]
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(untagged))]
pub enum ModuleExportName<'a> {
Identifier(IdentifierName<'a>),
StringLiteral(StringLiteral<'a>),
}
impl<'a> fmt::Display for ModuleExportName<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match self {
Self::Identifier(identifier) => identifier.name.to_string(),
Self::StringLiteral(literal) => format!(r#""{}""#, literal.value),
};
write!(f, "{s}")
}
}
impl<'a> ModuleExportName<'a> {
pub fn name(&self) -> &Atom<'a> {
match self {
Self::Identifier(identifier) => &identifier.name,
Self::StringLiteral(literal) => &literal.value,
}
}
}