From 2cd04811d1ea341f91669a4dc3d7b355c22bffe6 Mon Sep 17 00:00:00 2001 From: Boshen Date: Tue, 25 Apr 2023 19:19:36 +0800 Subject: [PATCH] feat(hir): copy AST over to HIR (#316) --- .github/codecov.yml | 1 + crates/oxc_hir/src/hir.rs | 2938 ++++++++++++++++++++++++++++++++++++- crates/oxc_hir/src/lib.rs | 2 + 3 files changed, 2937 insertions(+), 4 deletions(-) diff --git a/.github/codecov.yml b/.github/codecov.yml index 54d28305a..43e41e399 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -8,6 +8,7 @@ ignore: - "**/main.rs" - "**/examples" - "tasks" + - "crates/oxc_hir" - "crates/oxc_wasm" # Remove this once wasm is completed - "crates/oxc_parser/fuzz" - "crates/oxc_diagnostics" diff --git a/crates/oxc_hir/src/hir.rs b/crates/oxc_hir/src/hir.rs index bdcfb4905..55f6babcd 100644 --- a/crates/oxc_hir/src/hir.rs +++ b/crates/oxc_hir/src/hir.rs @@ -1,5 +1,12 @@ -use oxc_allocator::Vec; -use oxc_ast::{SourceType, Span}; +use std::fmt::Display; + +use oxc_allocator::{Box, Vec}; +use oxc_ast::ast::{ + AssignmentOperator, BigintLiteral, BinaryOperator, BooleanLiteral, LogicalOperator, + NullLiteral, NumberLiteral, RegExpLiteral, StringLiteral, UnaryOperator, UpdateOperator, +}; +use oxc_ast::BigUint; +use oxc_ast::{Atom, SourceType, Span}; #[cfg(feature = "serde")] use serde::Serialize; @@ -13,8 +20,857 @@ pub struct Program<'a> { // pub body: Vec<'a, Statement<'a>>, } +// impl<'a> Program<'a> { +// #[must_use] +// pub fn is_empty(&self) -> bool { +// self.body.is_empty() && self.directives.is_empty() +// } +// } + +/// Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum Expression<'a> { + BooleanLiteral(Box<'a, BooleanLiteral>), + NullLiteral(Box<'a, NullLiteral>), + NumberLiteral(Box<'a, NumberLiteral<'a>>), + BigintLiteral(Box<'a, BigintLiteral>), + RegExpLiteral(Box<'a, RegExpLiteral>), + StringLiteral(Box<'a, StringLiteral>), + TemplateLiteral(Box<'a, TemplateLiteral<'a>>), + + Identifier(Box<'a, IdentifierReference>), + + MetaProperty(Box<'a, MetaProperty>), + Super(Box<'a, Super>), + + ArrayExpression(Box<'a, ArrayExpression<'a>>), + ArrowFunctionExpression(Box<'a, ArrowExpression<'a>>), + AssignmentExpression(Box<'a, AssignmentExpression<'a>>), + AwaitExpression(Box<'a, AwaitExpression<'a>>), + BinaryExpression(Box<'a, BinaryExpression<'a>>), + CallExpression(Box<'a, CallExpression<'a>>), + ChainExpression(Box<'a, ChainExpression<'a>>), + ClassExpression(Box<'a, Class<'a>>), + ConditionalExpression(Box<'a, ConditionalExpression<'a>>), + FunctionExpression(Box<'a, Function<'a>>), + ImportExpression(Box<'a, ImportExpression<'a>>), + LogicalExpression(Box<'a, LogicalExpression<'a>>), + MemberExpression(Box<'a, MemberExpression<'a>>), + NewExpression(Box<'a, NewExpression<'a>>), + ObjectExpression(Box<'a, ObjectExpression<'a>>), + ParenthesizedExpression(Box<'a, ParenthesizedExpression<'a>>), + SequenceExpression(Box<'a, SequenceExpression<'a>>), + TaggedTemplateExpression(Box<'a, TaggedTemplateExpression<'a>>), + ThisExpression(Box<'a, ThisExpression>), + UnaryExpression(Box<'a, UnaryExpression<'a>>), + UpdateExpression(Box<'a, UpdateExpression<'a>>), + YieldExpression(Box<'a, YieldExpression<'a>>), + PrivateInExpression(Box<'a, PrivateInExpression<'a>>), + + JSXElement(Box<'a, JSXElement<'a>>), + JSXFragment(Box<'a, JSXFragment<'a>>), + + TSAsExpression(Box<'a, TSAsExpression<'a>>), + TSSatisfiesExpression(Box<'a, TSSatisfiesExpression<'a>>), + TSTypeAssertion(Box<'a, TSTypeAssertion<'a>>), + TSNonNullExpression(Box<'a, TSNonNullExpression<'a>>), + TSInstantiationExpression(Box<'a, TSInstantiationExpression<'a>>), +} + +impl<'a> Expression<'a> { + /// `PrimaryExpression` + /// [tc39/ecma262#prod-PrimaryExpression](https://tc39.es/ecma262/#prod-PrimaryExpression) + #[must_use] + pub fn is_primary_expression(&self) -> bool { + self.is_literal_expression() + || matches!( + self, + Self::Identifier(_) + | Self::ThisExpression(_) + | Self::FunctionExpression(_) + | Self::ClassExpression(_) + | Self::ParenthesizedExpression(_) + | Self::ArrayExpression(_) + | Self::ObjectExpression(_) + ) + } + + #[must_use] + pub fn is_literal_expression(&self) -> bool { + matches!( + self, + Self::BooleanLiteral(_) + | Self::NullLiteral(_) + | Self::NumberLiteral(_) + | Self::BigintLiteral(_) + | Self::RegExpLiteral(_) + | Self::StringLiteral(_) // TemplateLiteral is not `Literal` type per oxc_ast + ) + } + + #[must_use] + pub fn is_string_literal(&self) -> bool { + matches!(self, Self::StringLiteral(_) | Self::TemplateLiteral(_)) + } + + /// Determines whether the given expr is a `null` literal + #[must_use] + pub fn is_null(&self) -> bool { + matches!(self, Expression::NullLiteral(_)) + } + + /// Determines whether the given expr is a `undefined` literal + #[must_use] + pub fn is_undefined(&self) -> bool { + matches!(self, Self::Identifier(ident) if ident.name == "undefined") + } + + /// Determines whether the given expr is a `void 0` + #[must_use] + pub fn is_void_0(&self) -> bool { + matches!(self, Self::UnaryExpression(expr) if expr.operator == UnaryOperator::Void) + } + + /// Determines whether the given expr is a `0` + #[must_use] + pub fn is_number_0(&self) -> bool { + matches!(self, Self::NumberLiteral(lit) if lit.value == 0.0) + } + + /// Determines whether the given expr evaluate to `undefined` + #[must_use] + pub fn evaluate_to_undefined(&self) -> bool { + self.is_undefined() || self.is_void_0() + } + + /// Determines whether the given expr is a `null` or `undefined` or `void 0` + #[must_use] + pub fn is_null_or_undefined(&self) -> bool { + self.is_null() || self.evaluate_to_undefined() + } + + /// Remove nested parentheses from this expression. + #[must_use] + pub fn without_parenthesized(&self) -> &Self { + match self { + Expression::ParenthesizedExpression(Box(expr)) => { + expr.expression.without_parenthesized() + } + _ => self, + } + } + + #[must_use] + pub fn is_specific_id(&self, name: &str) -> bool { + match self.get_inner_expression() { + Expression::Identifier(ident) => ident.name == name, + _ => false, + } + } + + #[must_use] + pub fn is_specific_member_access(&'a self, object: &str, property: &str) -> bool { + match self.get_inner_expression() { + Expression::MemberExpression(expr) => expr.is_specific_member_access(object, property), + Expression::ChainExpression(chain) => { + let ChainElement::MemberExpression(expr) = &chain.expression else { + return false; + }; + expr.is_specific_member_access(object, property) + } + _ => false, + } + } + + #[must_use] + 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, + } + } + + #[must_use] + pub fn get_identifier_reference(&self) -> Option<&IdentifierReference> { + match self.get_inner_expression() { + Expression::Identifier(ident) => Some(ident), + _ => None, + } + } + + #[must_use] + pub fn is_function(&self) -> bool { + matches!(self, Expression::FunctionExpression(_) | Expression::ArrowFunctionExpression(_)) + } + + /// Returns literal's value converted to the Boolean type + /// returns `true` when node is truthy, `false` when node is falsy, `None` when it cannot be determined. + #[must_use] + pub fn get_boolean_value(&self) -> Option { + match self { + Self::BooleanLiteral(lit) => Some(lit.value), + Self::NullLiteral(_) => Some(false), + Self::NumberLiteral(lit) => Some(lit.value != 0.0), + Self::BigintLiteral(lit) => Some(lit.value != BigUint::new(vec![])), + Self::RegExpLiteral(_) => Some(true), + Self::StringLiteral(lit) => Some(!lit.value.is_empty()), + _ => None, + } + } +} + +/// Identifier Name +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct IdentifierName { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub name: Atom, +} + +/// Identifier Reference +#[derive(Debug, Clone, PartialEq, Hash, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct IdentifierReference { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub name: Atom, +} + +/// Binding Identifier +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct BindingIdentifier { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub name: Atom, +} + +/// Label Identifier +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct LabelIdentifier { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub name: Atom, +} + +/// This Expression +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ThisExpression { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +/// Array Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ArrayExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub elements: Vec<'a, Option>>, + pub trailing_comma: Option, +} + +/// Object Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ObjectExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub properties: Vec<'a, ObjectProperty<'a>>, + pub trailing_comma: Option, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum ObjectProperty<'a> { + Property(Box<'a, Property<'a>>), + SpreadProperty(Box<'a, SpreadElement<'a>>), +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct Property<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub kind: PropertyKind, + pub key: PropertyKey<'a>, + pub value: PropertyValue<'a>, + pub method: bool, + pub shorthand: bool, + pub computed: bool, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum PropertyKey<'a> { + Identifier(Box<'a, IdentifierName>), + PrivateIdentifier(Box<'a, PrivateIdentifier>), + Expression(Expression<'a>), +} + +impl<'a> PropertyKey<'a> { + #[must_use] + pub fn static_name(&self) -> Option { + match self { + Self::Identifier(ident) => Some(ident.name.clone()), + Self::PrivateIdentifier(_) => None, + Self::Expression(expr) => match expr { + Expression::StringLiteral(lit) => Some(lit.value.clone()), + Expression::RegExpLiteral(lit) => Some(Atom::from(lit.regex.to_string())), + Expression::NumberLiteral(lit) => Some(Atom::from(lit.value.to_string())), + Expression::BigintLiteral(lit) => Some(Atom::from(lit.value.to_string())), + Expression::NullLiteral(_) => Some("null".into()), + Expression::TemplateLiteral(lit) => { + lit.expressions.is_empty().then(|| lit.quasi()).flatten().cloned() + } + _ => None, + }, + } + } + + #[must_use] + pub fn is_private_identifier(&self) -> bool { + matches!(self, Self::PrivateIdentifier(_)) + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum PropertyValue<'a> { + // For AssignmentProperty in ObjectPattern + Pattern(BindingPattern<'a>), + Expression(Expression<'a>), +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "lowercase"))] +pub enum PropertyKind { + Init, + Get, + Set, +} + +/// Template Literal +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TemplateLiteral<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub quasis: Vec<'a, TemplateElement>, + pub expressions: Vec<'a, Expression<'a>>, +} + +impl<'a> TemplateLiteral<'a> { + #[must_use] + pub fn is_no_substitution_template(&self) -> bool { + self.expressions.is_empty() && self.quasis.len() == 1 + } + + /// Get single quasi from `template` + #[must_use] + pub fn quasi(&self) -> Option<&Atom> { + self.quasis.first().and_then(|quasi| quasi.value.cooked.as_ref()) + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TaggedTemplateExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub tag: Expression<'a>, + pub quasi: TemplateLiteral<'a>, + pub type_parameters: Option>>, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TemplateElement { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub tail: bool, + pub value: TemplateElementValue, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize))] +pub struct TemplateElementValue { + pub raw: Atom, + pub cooked: Option, +} + +/// Member Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum MemberExpression<'a> { + ComputedMemberExpression(ComputedMemberExpression<'a>), + StaticMemberExpression(StaticMemberExpression<'a>), + PrivateFieldExpression(PrivateFieldExpression<'a>), +} + +impl<'a> MemberExpression<'a> { + #[must_use] + pub fn optional(&self) -> bool { + match self { + MemberExpression::ComputedMemberExpression(expr) => expr.optional, + MemberExpression::StaticMemberExpression(expr) => expr.optional, + MemberExpression::PrivateFieldExpression(expr) => expr.optional, + } + } + + #[must_use] + pub fn object(&self) -> &Expression<'a> { + match self { + MemberExpression::ComputedMemberExpression(expr) => &expr.object, + MemberExpression::StaticMemberExpression(expr) => &expr.object, + MemberExpression::PrivateFieldExpression(expr) => &expr.object, + } + } + + #[must_use] + pub fn static_property_name(&'a self) -> Option<&'a str> { + match self { + MemberExpression::ComputedMemberExpression(expr) => match &expr.expression { + Expression::StringLiteral(lit) => Some(&lit.value), + Expression::TemplateLiteral(lit) => { + if lit.expressions.is_empty() && lit.quasis.len() == 1 { + Some(&lit.quasis[0].value.raw) + } else { + None + } + } + _ => None, + }, + MemberExpression::StaticMemberExpression(expr) => Some(&expr.property.name), + MemberExpression::PrivateFieldExpression(_) => None, + } + } + + /// Whether it is a static member access `object.property` + #[must_use] + pub fn is_specific_member_access(&'a self, object: &str, property: &str) -> bool { + self.object().is_specific_id(object) + && self.static_property_name().is_some_and(|p| p == property) + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ComputedMemberExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub object: Expression<'a>, + pub expression: Expression<'a>, + pub optional: bool, // for optional chaining +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct StaticMemberExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub object: Expression<'a>, + pub property: IdentifierName, + pub optional: bool, // for optional chaining +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct PrivateFieldExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub object: Expression<'a>, + pub field: PrivateIdentifier, + pub optional: bool, // for optional chaining +} + +/// Call Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct CallExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub callee: Expression<'a>, + pub arguments: Vec<'a, Argument<'a>>, + pub optional: bool, // for optional chaining + pub type_parameters: Option>>, +} + +impl<'a> CallExpression<'a> { + #[must_use] + 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::Expression( + Expression::StringLiteral(_) | Expression::TemplateLiteral(_), + )), + ) + } else { + false + } + } + + #[must_use] + pub fn is_symbol_or_symbol_for_call(&'a self) -> bool { + // TODO: is 'Symbol' reference to global object + match &self.callee { + Expression::Identifier(id) => id.name == "Symbol", + Expression::MemberExpression(member) => { + matches!(member.object(), Expression::Identifier(id) if id.name == "Symbol") + && member.static_property_name() == Some("for") + } + _ => false, + } + } + + #[must_use] + pub fn common_js_require(&self) -> Option<&StringLiteral> { + if let Expression::Identifier(ident) = &self.callee + && ident.name =="require" + && self.arguments.len() == 1 + && let Argument::Expression(Expression::StringLiteral(str_literal)) = &self.arguments[0] { + Some(str_literal) + } else { + None + } + } +} + +/// New Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct NewExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub callee: Expression<'a>, + pub arguments: Vec<'a, Argument<'a>>, + pub type_parameters: Option>>, +} + +/// Meta Property `new.target` | `import.meta` +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct MetaProperty { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub meta: IdentifierName, + pub property: IdentifierName, +} + +/// Spread Element +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct SpreadElement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub argument: Expression<'a>, +} + +/// Argument +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum Argument<'a> { + SpreadElement(Box<'a, SpreadElement<'a>>), + Expression(Expression<'a>), +} + +/// Update Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct UpdateExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub operator: UpdateOperator, + pub prefix: bool, + pub argument: SimpleAssignmentTarget<'a>, +} + +/// Unary Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct UnaryExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub operator: UnaryOperator, + pub prefix: bool, + pub argument: Expression<'a>, +} + +/// Binary Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct BinaryExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub left: Expression<'a>, + pub operator: BinaryOperator, + pub right: Expression<'a>, +} + +/// Private Identifier in Shift Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct PrivateInExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub left: PrivateIdentifier, + pub operator: BinaryOperator, // BinaryOperator::In + pub right: Expression<'a>, +} + +/// Binary Logical Operators +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct LogicalExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub left: Expression<'a>, + pub operator: LogicalOperator, + pub right: Expression<'a>, +} + +/// Conditional Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ConditionalExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub test: Expression<'a>, + pub consequent: Expression<'a>, + pub alternate: Expression<'a>, +} + +/// Assignment Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct AssignmentExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub operator: AssignmentOperator, + pub left: AssignmentTarget<'a>, + pub right: Expression<'a>, +} + +/// Destructuring Assignment +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum AssignmentTarget<'a> { + SimpleAssignmentTarget(SimpleAssignmentTarget<'a>), + AssignmentTargetPattern(AssignmentTargetPattern<'a>), +} + +impl<'a> AssignmentTarget<'a> { + #[must_use] + pub fn is_destructuring_pattern(&self) -> bool { + matches!(self, Self::AssignmentTargetPattern(_)) + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum SimpleAssignmentTarget<'a> { + AssignmentTargetIdentifier(Box<'a, IdentifierReference>), + MemberAssignmentTarget(Box<'a, MemberExpression<'a>>), + TSAsExpression(Box<'a, TSAsExpression<'a>>), + TSSatisfiesExpression(Box<'a, TSSatisfiesExpression<'a>>), + TSNonNullExpression(Box<'a, TSNonNullExpression<'a>>), + TSTypeAssertion(Box<'a, TSTypeAssertion<'a>>), +} + +impl<'a> SimpleAssignmentTarget<'a> { + #[must_use] + 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, + } + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum AssignmentTargetPattern<'a> { + ArrayAssignmentTarget(Box<'a, ArrayAssignmentTarget<'a>>), + ObjectAssignmentTarget(Box<'a, ObjectAssignmentTarget<'a>>), +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ArrayAssignmentTarget<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub elements: Vec<'a, Option>>, + pub rest: Option>, + pub trailing_comma: Option, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ObjectAssignmentTarget<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub properties: Vec<'a, AssignmentTargetProperty<'a>>, + pub rest: Option>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum AssignmentTargetMaybeDefault<'a> { + AssignmentTarget(Box<'a, AssignmentTarget<'a>>), + AssignmentTargetWithDefault(Box<'a, AssignmentTargetWithDefault<'a>>), +} + +impl<'a> AssignmentTargetMaybeDefault<'a> { + #[must_use] + pub fn name(&self) -> Option { + let target = match self { + Self::AssignmentTarget(target) => target, + Self::AssignmentTargetWithDefault(target) => &target.binding, + }; + + if let AssignmentTarget::SimpleAssignmentTarget( + SimpleAssignmentTarget::AssignmentTargetIdentifier(id), + ) = target + { + Some(id.name.clone()) + } else { + None + } + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct AssignmentTargetWithDefault<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub binding: AssignmentTarget<'a>, + pub init: Expression<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum AssignmentTargetProperty<'a> { + AssignmentTargetPropertyIdentifier(Box<'a, AssignmentTargetPropertyIdentifier<'a>>), + AssignmentTargetPropertyProperty(Box<'a, AssignmentTargetPropertyProperty<'a>>), +} + +/// Assignment Property - Identifier Reference +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct AssignmentTargetPropertyIdentifier<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub binding: IdentifierReference, + pub init: Option>, +} + +/// Assignment Property - Property Name +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct AssignmentTargetPropertyProperty<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub name: PropertyKey<'a>, + pub binding: AssignmentTargetMaybeDefault<'a>, +} + +/// Sequence Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct SequenceExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expressions: Vec<'a, Expression<'a>>, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct Super { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +/// Await Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct AwaitExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub argument: Expression<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ChainExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: ChainElement<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum ChainElement<'a> { + CallExpression(Box<'a, CallExpression<'a>>), + MemberExpression(Box<'a, MemberExpression<'a>>), +} + +/// Parenthesized Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ParenthesizedExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: Expression<'a>, +} + +/// Statements +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum Statement<'a> { + // Statements + BlockStatement(Box<'a, BlockStatement<'a>>), + BreakStatement(Box<'a, BreakStatement>), + ContinueStatement(Box<'a, ContinueStatement>), + DebuggerStatement(Box<'a, DebuggerStatement>), + DoWhileStatement(Box<'a, DoWhileStatement<'a>>), + EmptyStatement(Box<'a, EmptyStatement>), + ExpressionStatement(Box<'a, ExpressionStatement<'a>>), + ForInStatement(Box<'a, ForInStatement<'a>>), + ForOfStatement(Box<'a, ForOfStatement<'a>>), + ForStatement(Box<'a, ForStatement<'a>>), + IfStatement(Box<'a, IfStatement<'a>>), + LabeledStatement(Box<'a, LabeledStatement<'a>>), + ReturnStatement(Box<'a, ReturnStatement<'a>>), + SwitchStatement(Box<'a, SwitchStatement<'a>>), + ThrowStatement(Box<'a, ThrowStatement<'a>>), + TryStatement(Box<'a, TryStatement<'a>>), + WhileStatement(Box<'a, WhileStatement<'a>>), + WithStatement(Box<'a, WithStatement<'a>>), + + ModuleDeclaration(Box<'a, ModuleDeclaration<'a>>), + Declaration(Declaration<'a>), +} + /// Directive Prologue -#[derive(Debug, Eq, PartialEq, Hash)] +#[derive(Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] pub struct Directive<'a> { #[cfg_attr(feature = "serde", serde(flatten))] @@ -24,4 +880,2078 @@ pub struct Directive<'a> { pub directive: &'a str, } -// ... All AST copied over +/// Block Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct BlockStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub body: Vec<'a, Statement<'a>>, +} + +/// Declarations and the Variable Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum Declaration<'a> { + VariableDeclaration(Box<'a, VariableDeclaration<'a>>), + FunctionDeclaration(Box<'a, Function<'a>>), + ClassDeclaration(Box<'a, Class<'a>>), + + TSTypeAliasDeclaration(Box<'a, TSTypeAliasDeclaration<'a>>), + TSInterfaceDeclaration(Box<'a, TSInterfaceDeclaration<'a>>), + TSEnumDeclaration(Box<'a, TSEnumDeclaration<'a>>), + TSModuleDeclaration(Box<'a, TSModuleDeclaration<'a>>), + TSImportEqualsDeclaration(Box<'a, TSImportEqualsDeclaration<'a>>), +} + +impl<'a> Declaration<'a> { + #[must_use] + pub fn is_typescript_syntax(&self) -> bool { + match self { + Self::VariableDeclaration(_) => false, + Self::FunctionDeclaration(func) => func.is_typescript_syntax(), + Self::ClassDeclaration(class) => class.is_declare(), + _ => true, + } + } +} + +/// Variable Declaration +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct VariableDeclaration<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub kind: VariableDeclarationKind, + pub declarations: Vec<'a, VariableDeclarator<'a>>, + /// Valid Modifiers: `export`, `declare` + pub modifiers: Modifiers<'a>, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "lowercase"))] +pub enum VariableDeclarationKind { + Var, + Const, + Let, +} + +impl VariableDeclarationKind { + #[must_use] + pub fn is_const(&self) -> bool { + matches!(self, Self::Const) + } + + #[must_use] + pub fn is_lexical(&self) -> bool { + matches!(self, Self::Const | Self::Let) + } +} + +impl Display for VariableDeclarationKind { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let s = match self { + Self::Var => "var", + Self::Const => "const", + Self::Let => "let", + }; + write!(f, "{s}") + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct VariableDeclarator<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + #[cfg_attr(feature = "serde", serde(skip))] + pub kind: VariableDeclarationKind, + pub id: BindingPattern<'a>, + pub init: Option>, + pub definite: bool, +} + +/// Empty Statement +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct EmptyStatement { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +/// Expression Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ExpressionStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: Expression<'a>, +} + +/// If Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct IfStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub test: Expression<'a>, + pub consequent: Statement<'a>, + pub alternate: Option>, +} + +/// Do-While Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct DoWhileStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub body: Statement<'a>, + pub test: Expression<'a>, +} + +/// While Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct WhileStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub test: Expression<'a>, + pub body: Statement<'a>, +} + +/// For Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ForStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub init: Option>, + pub test: Option>, + pub update: Option>, + pub body: Statement<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum ForStatementInit<'a> { + VariableDeclaration(Box<'a, VariableDeclaration<'a>>), + Expression(Expression<'a>), +} + +/// For-In Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ForInStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub left: ForStatementLeft<'a>, + pub right: Expression<'a>, + pub body: Statement<'a>, +} + +/// For-Of Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ForOfStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub r#await: bool, + pub left: ForStatementLeft<'a>, + pub right: Expression<'a>, + pub body: Statement<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum ForStatementLeft<'a> { + VariableDeclaration(Box<'a, VariableDeclaration<'a>>), + AssignmentTarget(AssignmentTarget<'a>), +} + +/// Continue Statement +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ContinueStatement { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub label: Option, +} + +/// Break Statement +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct BreakStatement { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub label: Option, +} + +/// Return Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ReturnStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub argument: Option>, +} + +/// With Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct WithStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub object: Expression<'a>, + pub body: Statement<'a>, +} + +/// Switch Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct SwitchStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub discriminant: Expression<'a>, + pub cases: Vec<'a, SwitchCase<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct SwitchCase<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub test: Option>, + pub consequent: Vec<'a, Statement<'a>>, +} + +impl<'a> SwitchCase<'a> { + #[must_use] + pub fn is_default_case(&self) -> bool { + self.test.is_none() + } +} + +/// Labelled Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct LabeledStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub label: LabelIdentifier, + pub body: Statement<'a>, +} + +/// Throw Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ThrowStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub argument: Expression<'a>, +} + +/// Try Statement +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TryStatement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub block: Box<'a, BlockStatement<'a>>, + pub handler: Option>>, + pub finalizer: Option>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct CatchClause<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub param: Option>, + pub body: Box<'a, BlockStatement<'a>>, +} + +/// Debugger Statement +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct DebuggerStatement { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +/// Destructuring Binding Patterns +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))] +pub struct BindingPattern<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub kind: BindingPatternKind<'a>, + pub type_annotation: Option>>, + pub optional: bool, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum BindingPatternKind<'a> { + BindingIdentifier(Box<'a, BindingIdentifier>), + ObjectPattern(Box<'a, ObjectPattern<'a>>), + ArrayPattern(Box<'a, ArrayPattern<'a>>), + RestElement(Box<'a, RestElement<'a>>), + AssignmentPattern(Box<'a, AssignmentPattern<'a>>), +} + +impl<'a> BindingPatternKind<'a> { + #[must_use] + pub fn is_destructuring_pattern(&self) -> bool { + matches!(self, Self::ObjectPattern(_) | Self::ArrayPattern(_)) + } + + #[must_use] + pub fn is_rest_element(&self) -> bool { + matches!(self, Self::RestElement(_)) + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct AssignmentPattern<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub left: BindingPattern<'a>, + pub right: Expression<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ObjectPattern<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub properties: Vec<'a, ObjectPatternProperty<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum ObjectPatternProperty<'a> { + Property(Box<'a, Property<'a>>), + RestElement(Box<'a, RestElement<'a>>), +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ArrayPattern<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub elements: Vec<'a, Option>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct RestElement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub argument: BindingPattern<'a>, +} + +/// Function Definitions +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))] +#[allow(clippy::struct_excessive_bools)] +pub struct Function<'a> { + pub r#type: FunctionType, + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub id: Option, + pub expression: bool, + pub generator: bool, + pub r#async: bool, + pub params: Box<'a, FormalParameters<'a>>, + pub body: Option>>, + pub type_parameters: Option>>, + pub return_type: Option>>, + /// Valid modifiers: `export`, `default`, `async` + pub modifiers: Modifiers<'a>, +} + +impl<'a> Function<'a> { + #[must_use] + pub fn is_typescript_syntax(&self) -> bool { + self.modifiers.contains(ModifierKind::Declare) || self.body.is_none() + } + + #[must_use] + pub fn is_expression(&self) -> bool { + self.r#type == FunctionType::FunctionExpression + } + + #[must_use] + pub fn is_function_declaration(&self) -> bool { + matches!(self.r#type, FunctionType::FunctionDeclaration) + } + + #[must_use] + pub fn is_ts_declare_function(&self) -> bool { + matches!(self.r#type, FunctionType::TSDeclareFunction) + } + + #[must_use] + pub fn is_declaration(&self) -> bool { + matches!(self.r#type, FunctionType::FunctionDeclaration | FunctionType::TSDeclareFunction) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize))] +pub enum FunctionType { + FunctionDeclaration, + FunctionExpression, + TSDeclareFunction, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct FormalParameters<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub kind: FormalParameterKind, + pub items: Vec<'a, FormalParameter<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize))] +pub struct FormalParameter<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + #[cfg_attr(feature = "serde", serde(flatten))] + pub pattern: BindingPattern<'a>, + pub accessibility: Option, + pub readonly: bool, + pub decorators: Vec<'a, Decorator<'a>>, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum FormalParameterKind { + /// + FormalParameter, + /// + UniqueFormalParameters, + /// + ArrowFormalParameters, + /// Part of TypeScript type signatures + Signature, +} + +impl<'a> FormalParameters<'a> { + #[must_use] + pub fn is_empty(&self) -> bool { + self.items.is_empty() + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct FunctionBody<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub directives: Vec<'a, Directive<'a>>, + pub statements: Vec<'a, Statement<'a>>, +} + +impl<'a> FunctionBody<'a> { + #[must_use] + pub fn is_empty(&self) -> bool { + self.directives.is_empty() && self.statements.is_empty() + } +} + +/// Arrow Function Definitions +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct ArrowExpression<'a> { + pub span: Span, + pub expression: bool, + pub generator: bool, + pub r#async: bool, + pub params: Box<'a, FormalParameters<'a>>, // UniqueFormalParameters in spec + pub body: Box<'a, FunctionBody<'a>>, + + pub type_parameters: Option>>, + pub return_type: Option>>, +} + +impl<'a> ArrowExpression<'a> { + /// Is of form () => x without curly braces. + #[inline] + #[must_use] + pub fn is_single_expression(&self) -> bool { + self.expression + } +} + +/// Generator Function Definitions +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct YieldExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub delegate: bool, + pub argument: Option>, +} + +/// Class Definitions +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))] +pub struct Class<'a> { + pub r#type: ClassType, + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub id: Option, + pub super_class: Option>, + pub body: Box<'a, ClassBody<'a>>, + pub type_parameters: Option>>, + pub super_type_parameters: Option>>, + pub implements: Option>>>, + pub decorators: Vec<'a, Decorator<'a>>, + /// Valid Modifiers: `export`, `abstract` + pub modifiers: Modifiers<'a>, +} + +impl<'a> Class<'a> { + #[must_use] + pub fn is_expression(&self) -> bool { + self.r#type == ClassType::ClassExpression + } + + #[must_use] + pub fn is_declaration(&self) -> bool { + self.r#type == ClassType::ClassDeclaration + } + + #[must_use] + pub fn is_declare(&self) -> bool { + self.modifiers.contains(ModifierKind::Declare) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize))] +pub enum ClassType { + ClassDeclaration, + ClassExpression, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ClassBody<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub body: Vec<'a, ClassElement<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(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>>), + TSAbstractMethodDefinition(Box<'a, TSAbstractMethodDefinition<'a>>), + TSAbstractPropertyDefinition(Box<'a, TSAbstractPropertyDefinition<'a>>), + TSIndexSignature(Box<'a, TSIndexSignature<'a>>), +} + +impl<'a> ClassElement<'a> { + #[must_use] + 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, + Self::TSAbstractMethodDefinition(def) => def.method_definition.r#static, + Self::TSAbstractPropertyDefinition(def) => def.property_definition.r#static, + } + } + + #[must_use] + 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, + Self::TSAbstractMethodDefinition(def) => def.method_definition.computed, + Self::TSAbstractPropertyDefinition(def) => def.property_definition.computed, + } + } + + #[must_use] + pub fn method_definition_kind(&self) -> Option { + match self { + Self::TSIndexSignature(_) + | Self::StaticBlock(_) + | Self::PropertyDefinition(_) + | Self::AccessorProperty(_) => None, + Self::MethodDefinition(def) => Some(def.kind), + Self::TSAbstractMethodDefinition(def) => Some(def.method_definition.kind), + Self::TSAbstractPropertyDefinition(_def) => None, + } + } + + #[must_use] + 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), + Self::TSAbstractMethodDefinition(def) => Some(&def.method_definition.key), + Self::TSAbstractPropertyDefinition(def) => Some(&def.property_definition.key), + } + } + + #[must_use] + pub fn static_name(&self) -> Option { + 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(), + Self::TSAbstractMethodDefinition(_def) => None, + Self::TSAbstractPropertyDefinition(_def) => None, + } + } + + #[must_use] + pub fn is_ts_empty_body_function(&self) -> bool { + match self { + Self::PropertyDefinition(_) + | Self::StaticBlock(_) + | Self::AccessorProperty(_) + | Self::TSAbstractPropertyDefinition(_) + | Self::TSIndexSignature(_) => false, + Self::MethodDefinition(method) => method.value.body.is_none(), + Self::TSAbstractMethodDefinition(_) => true, + } + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +#[allow(clippy::struct_excessive_bools)] +pub struct MethodDefinition<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub key: PropertyKey<'a>, + pub value: Box<'a, Function<'a>>, // FunctionExpression + pub kind: MethodDefinitionKind, + pub computed: bool, + pub r#static: bool, + pub r#override: bool, + pub optional: bool, + pub accessibility: Option, + pub decorators: Vec<'a, Decorator<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +#[allow(clippy::struct_excessive_bools)] +pub struct PropertyDefinition<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub key: PropertyKey<'a>, + pub value: Option>, + 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>>, + pub accessibility: Option, + pub decorators: Vec<'a, Decorator<'a>>, +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "lowercase"))] +pub enum MethodDefinitionKind { + Constructor, + Method, + Get, + Set, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct PrivateIdentifier { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub name: Atom, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct StaticBlock<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub body: Vec<'a, Statement<'a>>, +} + +/// Imports +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize))] +pub struct ModuleDeclaration<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + #[cfg_attr(feature = "serde", serde(flatten))] + pub kind: ModuleDeclarationKind<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum ModuleDeclarationKind<'a> { + ImportDeclaration(Box<'a, ImportDeclaration<'a>>), + ExportAllDeclaration(Box<'a, ExportAllDeclaration<'a>>), + ExportDefaultDeclaration(Box<'a, ExportDefaultDeclaration<'a>>), + ExportNamedDeclaration(Box<'a, ExportNamedDeclaration<'a>>), + + TSExportAssignment(Box<'a, TSExportAssignment<'a>>), + TSNamespaceExportDeclaration(Box<'a, TSNamespaceExportDeclaration>), +} + +impl<'a> ModuleDeclarationKind<'a> { + #[must_use] + pub fn is_export(&self) -> bool { + matches!( + self, + Self::ExportAllDeclaration(_) + | Self::ExportDefaultDeclaration(_) + | Self::ExportNamedDeclaration(_) + | Self::TSExportAssignment(_) + | Self::TSNamespaceExportDeclaration(_) + ) + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct AccessorProperty<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub key: PropertyKey<'a>, + pub value: Option>, + pub computed: bool, + pub r#static: bool, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ImportExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub source: Expression<'a>, + pub arguments: Vec<'a, Expression<'a>>, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct ImportDeclaration<'a> { + pub specifiers: Vec<'a, ImportDeclarationSpecifier>, + pub source: StringLiteral, + pub assertions: Option>, // Some(vec![]) for empty assertion + pub import_kind: Option, // `import type { foo } from 'bar'` +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum ImportDeclarationSpecifier { + ImportSpecifier(ImportSpecifier), + ImportDefaultSpecifier(ImportDefaultSpecifier), + ImportNamespaceSpecifier(ImportNamespaceSpecifier), +} + +// import {imported} from "source" +// import {imported as local} from "source" +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ImportSpecifier { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub imported: ModuleExportName, + pub local: BindingIdentifier, +} + +// import local from "source" +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ImportDefaultSpecifier { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub local: BindingIdentifier, +} + +// import * as local from "source" +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ImportNamespaceSpecifier { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub local: BindingIdentifier, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ImportAttribute { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub key: ImportAttributeKey, + pub value: StringLiteral, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum ImportAttributeKey { + Identifier(IdentifierName), + StringLiteral(StringLiteral), +} + +impl ImportAttributeKey { + #[must_use] + pub fn as_atom(&self) -> Atom { + match self { + Self::Identifier(identifier) => identifier.name.clone(), + Self::StringLiteral(literal) => literal.value.clone(), + } + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ExportNamedDeclaration<'a> { + pub declaration: Option>, + pub specifiers: Vec<'a, ExportSpecifier>, + pub source: Option, + pub export_kind: Option, // `export type { foo }` +} + +impl<'a> ExportNamedDeclaration<'a> { + #[must_use] + pub fn is_typescript_syntax(&self) -> bool { + self.export_kind == Some(ImportOrExportKind::Type) + || self.declaration.as_ref().map_or(false, Declaration::is_typescript_syntax) + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ExportDefaultDeclaration<'a> { + pub declaration: ExportDefaultDeclarationKind<'a>, + pub exported: ModuleExportName, // `default` +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ExportAllDeclaration<'a> { + pub exported: Option, + pub source: StringLiteral, + pub assertions: Option>, // Some(vec![]) for empty assertion + pub export_kind: Option, // `export type *` +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct ExportSpecifier { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub local: ModuleExportName, + pub exported: ModuleExportName, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum ExportDefaultDeclarationKind<'a> { + Expression(Expression<'a>), + FunctionDeclaration(Box<'a, Function<'a>>), + ClassDeclaration(Box<'a, Class<'a>>), + + TSInterfaceDeclaration(Box<'a, TSInterfaceDeclaration<'a>>), + TSEnumDeclaration(Box<'a, TSEnumDeclaration<'a>>), +} + +impl<'a> ExportDefaultDeclarationKind<'a> { + #[inline] + #[must_use] + pub fn is_typescript_syntax(&self) -> bool { + match self { + ExportDefaultDeclarationKind::FunctionDeclaration(func) + if func.is_typescript_syntax() => + { + true + } + ExportDefaultDeclarationKind::TSInterfaceDeclaration(_) + | ExportDefaultDeclarationKind::TSEnumDeclaration(_) => true, + _ => false, + } + } +} + +// es2022: +// +// support: +// import {"\0 any unicode" as foo} from ""; +// export {foo as "\0 any unicode"}; +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum ModuleExportName { + Identifier(IdentifierName), + StringLiteral(StringLiteral), +} + +impl Display for ModuleExportName { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let s = match self { + Self::Identifier(identifier) => identifier.name.to_string(), + Self::StringLiteral(literal) => literal.value.to_string(), + }; + write!(f, "{s}") + } +} + +impl ModuleExportName { + #[must_use] + pub fn name(&self) -> &Atom { + match self { + Self::Identifier(identifier) => &identifier.name, + Self::StringLiteral(literal) => &literal.value, + } + } +} + +/* TypeScript */ + +/// Enum Declaration +/// +/// `const_opt` enum `BindingIdentifier` { `EnumBody_opt` } +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSEnumDeclaration<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub id: BindingIdentifier, + pub members: Vec<'a, TSEnumMember<'a>>, + /// Valid Modifiers: `const`, `export`, `declare` + pub modifiers: Modifiers<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSEnumMember<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub id: TSEnumMemberName<'a>, + pub initializer: Option>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum TSEnumMemberName<'a> { + Identifier(IdentifierName), + StringLiteral(StringLiteral), + // Invalid Grammar `enum E { [computed] }` + ComputedPropertyName(Expression<'a>), + // Invalid Grammar `enum E { 1 }` + NumberLiteral(NumberLiteral<'a>), +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSTypeAnnotation<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub type_annotation: TSType<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSLiteralType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub literal: TSLiteral<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged, rename_all = "camelCase"))] +pub enum TSLiteral<'a> { + BooleanLiteral(Box<'a, BooleanLiteral>), + NullLiteral(Box<'a, NullLiteral>), + NumberLiteral(Box<'a, NumberLiteral<'a>>), + BigintLiteral(Box<'a, BigintLiteral>), + RegExpLiteral(Box<'a, RegExpLiteral>), + StringLiteral(Box<'a, StringLiteral>), + TemplateLiteral(Box<'a, TemplateLiteral<'a>>), + UnaryExpression(Box<'a, UnaryExpression<'a>>), +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged, rename_all = "camelCase"))] +pub enum TSType<'a> { + // Keyword + TSAnyKeyword(Box<'a, TSAnyKeyword>), + TSBigIntKeyword(Box<'a, TSBigIntKeyword>), + TSBooleanKeyword(Box<'a, TSBooleanKeyword>), + TSNeverKeyword(Box<'a, TSNeverKeyword>), + TSNullKeyword(Box<'a, TSNullKeyword>), + TSNumberKeyword(Box<'a, TSNumberKeyword>), + TSObjectKeyword(Box<'a, TSObjectKeyword>), + TSStringKeyword(Box<'a, TSStringKeyword>), + TSSymbolKeyword(Box<'a, TSSymbolKeyword>), + TSThisKeyword(Box<'a, TSThisKeyword>), + TSUndefinedKeyword(Box<'a, TSUndefinedKeyword>), + TSUnknownKeyword(Box<'a, TSUnknownKeyword>), + TSVoidKeyword(Box<'a, TSVoidKeyword>), + // Compound + TSArrayType(Box<'a, TSArrayType<'a>>), + TSConditionalType(Box<'a, TSConditionalType<'a>>), + TSConstructorType(Box<'a, TSConstructorType<'a>>), + TSFunctionType(Box<'a, TSFunctionType<'a>>), + TSImportType(Box<'a, TSImportType<'a>>), + TSIndexedAccessType(Box<'a, TSIndexedAccessType<'a>>), + TSInferType(Box<'a, TSInferType<'a>>), + TSIntersectionType(Box<'a, TSIntersectionType<'a>>), + TSLiteralType(Box<'a, TSLiteralType<'a>>), + TSMappedType(Box<'a, TSMappedType<'a>>), + TSQualifiedName(Box<'a, TSQualifiedName<'a>>), + TSTemplateLiteralType(Box<'a, TSTemplateLiteralType<'a>>), + TSTupleType(Box<'a, TSTupleType<'a>>), + TSTypeLiteral(Box<'a, TSTypeLiteral<'a>>), + TSTypeOperatorType(Box<'a, TSTypeOperatorType<'a>>), + TSTypePredicate(Box<'a, TSTypePredicate<'a>>), + TSTypeQuery(Box<'a, TSTypeQuery<'a>>), + TSTypeReference(Box<'a, TSTypeReference<'a>>), + TSUnionType(Box<'a, TSUnionType<'a>>), + // JSDoc + JSDocNullableType(Box<'a, JSDocNullableType<'a>>), + JSDocUnknownType(Box<'a, JSDocUnknownType>), +} + +impl<'a> TSType<'a> { + #[must_use] + pub fn is_const_type_reference(&self) -> bool { + matches!(self, TSType::TSTypeReference(reference) if reference.type_name.is_const()) + } +} + +/// `SomeType extends OtherType ? TrueType : FalseType;` +/// +/// +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSConditionalType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub check_type: TSType<'a>, + pub extends_type: TSType<'a>, + pub true_type: TSType<'a>, + pub false_type: TSType<'a>, +} + +/// string | string[] | (() => string) | { s: string } +/// +/// +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSUnionType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub types: Vec<'a, TSType<'a>>, +} + +/// type `ColorfulCircle` = Colorful & Circle; +/// +/// +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSIntersectionType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub types: Vec<'a, TSType<'a>>, +} + +/// keyof unique readonly +/// +/// +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename = "TSTypeOperator"))] +pub struct TSTypeOperatorType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub operator: TSTypeOperator, + pub type_annotation: TSType<'a>, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged, rename_all = "lowercase"))] +pub enum TSTypeOperator { + Keyof, + Unique, + Readonly, +} + +impl TSTypeOperator { + #[must_use] + pub fn from_src(src: &str) -> Option { + match src { + "keyof" => Some(Self::Keyof), + "unique" => Some(Self::Unique), + "readonly" => Some(Self::Readonly), + _ => None, + } + } +} + +/// `let myArray: string[] = ["hello", "world"];` +/// +/// +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSArrayType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub element_type: TSType<'a>, +} + +/// `type I1 = Person["age" | "name"];` +/// +/// +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSIndexedAccessType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub object_type: TSType<'a>, + pub index_type: TSType<'a>, +} + +/// type `StringNumberPair` = [string, number]; +/// +/// +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSTupleType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub element_types: Vec<'a, TSTupleElement<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSNamedTupleMember<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub element_type: TSType<'a>, + pub label: IdentifierName, + pub optional: bool, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSOptionalType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub type_annotation: TSType<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSRestType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub type_annotation: TSType<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged, rename_all = "camelCase"))] +pub enum TSTupleElement<'a> { + TSType(TSType<'a>), + TSOptionalType(Box<'a, TSOptionalType<'a>>), + TSRestType(Box<'a, TSRestType<'a>>), + TSNamedTupleMember(Box<'a, TSNamedTupleMember<'a>>), +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSAnyKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSStringKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSBooleanKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSNumberKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSNeverKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSUnknownKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSNullKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSUndefinedKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSVoidKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSSymbolKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSThisKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSObjectKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct TSBigIntKeyword { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +/// type C = A; +/// type D = B.a; +/// type E = D.c.b.a; +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSTypeReference<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub type_name: TSTypeName<'a>, + pub type_parameters: Option>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum TSTypeName<'a> { + IdentifierName(Box<'a, IdentifierName>), + QualifiedName(Box<'a, TSQualifiedName<'a>>), +} + +impl<'a> TSTypeName<'a> { + #[must_use] + pub fn get_first_name(name: &TSTypeName) -> IdentifierName { + match name { + TSTypeName::IdentifierName(name) => (*name).clone(), + TSTypeName::QualifiedName(name) => TSTypeName::get_first_name(&name.left), + } + } + + #[must_use] + pub fn is_const(&self) -> bool { + if let TSTypeName::IdentifierName(ident) = self { + if ident.name == "const" { + return true; + } + } + false + } + + #[must_use] + pub fn is_identifier(&self) -> bool { + matches!(self, Self::IdentifierName(_)) + } + + #[must_use] + pub fn is_qualified_name(&self) -> bool { + matches!(self, Self::QualifiedName(_)) + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSQualifiedName<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub left: TSTypeName<'a>, + pub right: IdentifierName, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSTypeParameterInstantiation<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub params: Vec<'a, TSType<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSTypeParameter<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub name: BindingIdentifier, + pub constraint: Option>, + pub default: Option>, + pub r#in: bool, + pub out: bool, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSTypeParameterDeclaration<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub params: Vec<'a, Box<'a, TSTypeParameter<'a>>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSTypeAliasDeclaration<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub id: BindingIdentifier, + pub type_annotation: TSType<'a>, + pub type_parameters: Option>>, + /// Valid Modifiers: `declare`, `export` + pub modifiers: Modifiers<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSAbstractMethodDefinition<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub method_definition: MethodDefinition<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSAbstractPropertyDefinition<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub property_definition: PropertyDefinition<'a>, +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "lowercase"))] +pub enum TSAccessibility { + Private, + Protected, + Public, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSClassImplements<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: TSTypeName<'a>, + pub type_parameters: Option>>, +} + +/// Interface Declaration +/// +/// interface `BindingIdentifier` `TypeParameters_opt` `InterfaceExtendsClause_opt` `ObjectType` +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSInterfaceDeclaration<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub id: BindingIdentifier, + pub body: Box<'a, TSInterfaceBody<'a>>, + pub type_parameters: Option>>, + pub extends: Option>>>, + /// Valid Modifiers: `export`, `default`, `declare` + pub modifiers: Modifiers<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSInterfaceBody<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub body: Vec<'a, TSSignature<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSPropertySignature<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub computed: bool, + pub optional: bool, + pub readonly: bool, + pub key: PropertyKey<'a>, + pub type_annotation: Option>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged, rename_all = "camelCase"))] +pub enum TSSignature<'a> { + TSIndexSignature(Box<'a, TSIndexSignature<'a>>), + TSPropertySignature(Box<'a, TSPropertySignature<'a>>), + TSCallSignatureDeclaration(Box<'a, TSCallSignatureDeclaration<'a>>), + TSConstructSignatureDeclaration(Box<'a, TSConstructSignatureDeclaration<'a>>), + TSMethodSignature(Box<'a, TSMethodSignature<'a>>), +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSIndexSignature<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub parameters: Vec<'a, Box<'a, TSIndexSignatureName<'a>>>, + pub type_annotation: Box<'a, TSTypeAnnotation<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSCallSignatureDeclaration<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub params: Box<'a, FormalParameters<'a>>, + pub return_type: Option>>, + pub type_parameters: Option>>, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "lowercase"))] +pub enum TSMethodSignatureKind { + Method, + Get, + Set, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSMethodSignature<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub key: PropertyKey<'a>, + pub computed: bool, + pub optional: bool, + pub kind: TSMethodSignatureKind, + pub params: Box<'a, FormalParameters<'a>>, + pub return_type: Option>>, + pub type_parameters: Option>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSConstructSignatureDeclaration<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub params: Box<'a, FormalParameters<'a>>, + pub return_type: Option>>, + pub type_parameters: Option>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSIndexSignatureName<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub name: Atom, + pub type_annotation: Box<'a, TSTypeAnnotation<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSInterfaceHeritage<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: Expression<'a>, + pub type_parameters: Option>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSTypePredicate<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub parameter_name: TSTypePredicateName, + pub asserts: bool, + pub type_annotation: Option>>, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged, rename_all = "camelCase"))] +pub enum TSTypePredicateName { + Identifier(IdentifierName), + This(TSThisKeyword), +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSModuleDeclaration<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub id: TSModuleDeclarationName, + pub body: TSModuleDeclarationBody<'a>, + /// Valid Modifiers: `declare`, `export` + pub modifiers: Modifiers<'a>, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum TSModuleDeclarationName { + Identifier(IdentifierName), + StringLiteral(StringLiteral), +} + +impl TSModuleDeclarationName { + #[must_use] + pub fn name(&self) -> &Atom { + match self { + Self::Identifier(ident) => &ident.name, + Self::StringLiteral(lit) => &lit.value, + } + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum TSModuleDeclarationBody<'a> { + TSModuleDeclaration(Box<'a, TSModuleDeclaration<'a>>), + TSModuleBlock(Box<'a, TSModuleBlock<'a>>), +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSModuleBlock<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub body: Vec<'a, Statement<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSTypeLiteral<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub members: Vec<'a, TSSignature<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSInferType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub type_parameter: Box<'a, TSTypeParameter<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSTypeQuery<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expr_name: TSTypeName<'a>, + pub type_parameters: Option>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSImportType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub is_type_of: bool, + pub parameter: TSType<'a>, + pub qualifier: Option>, + pub type_parameters: Option>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSFunctionType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub params: Box<'a, FormalParameters<'a>>, + pub return_type: Box<'a, TSTypeAnnotation<'a>>, + pub type_parameters: Option>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSConstructorType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub r#abstract: bool, + pub params: Box<'a, FormalParameters<'a>>, + pub return_type: Box<'a, TSTypeAnnotation<'a>>, + pub type_parameters: Option>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSMappedType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub type_parameter: Box<'a, TSTypeParameter<'a>>, + pub name_type: Option>, + pub type_annotation: TSType<'a>, + pub optional: TSMappedTypeModifierOperator, + pub readonly: TSMappedTypeModifierOperator, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged, rename_all = "camelCase"))] +pub enum TSMappedTypeModifierOperator { + True, + #[cfg_attr(feature = "serde", serde(rename = "+"))] + Plus, + #[cfg_attr(feature = "serde", serde(rename = "-"))] + Minus, + None, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSTemplateLiteralType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub quasis: Vec<'a, TemplateElement>, + pub types: Vec<'a, TSType<'a>>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSAsExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: Expression<'a>, + pub type_annotation: TSType<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSSatisfiesExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: Expression<'a>, + pub type_annotation: TSType<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSTypeAssertion<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: Expression<'a>, + pub type_annotation: TSType<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSImportEqualsDeclaration<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub id: BindingIdentifier, + pub module_reference: Box<'a, TSModuleReference<'a>>, + pub is_export: bool, + pub import_kind: ImportOrExportKind, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged, rename_all = "camelCase"))] +pub enum TSModuleReference<'a> { + TypeName(TSTypeName<'a>), + ExternalModuleReference(TSExternalModuleReference), +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSExternalModuleReference { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: StringLiteral, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSNonNullExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: Expression<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct Decorator<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: Expression<'a>, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub enum ModifierKind { + Abstract, + Accessor, + Async, + Const, + Declare, + Default, + Export, + In, + Public, + Private, + Protected, + Readonly, + Static, + Out, + Override, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct Modifier { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub kind: ModifierKind, +} + +#[derive(Debug, PartialEq, Eq, Hash, Default)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(transparent))] +pub struct Modifiers<'a>(Option>); + +impl<'a> Modifiers<'a> { + #[must_use] + pub fn new(modifiers: Vec<'a, Modifier>) -> Self { + Self(Some(modifiers)) + } + + #[must_use] + pub fn empty() -> Self { + Self(None) + } + + #[must_use] + pub fn is_none(&self) -> bool { + self.0.is_none() + } + + #[must_use] + pub fn contains(&self, target: ModifierKind) -> bool { + self.0 + .as_ref() + .map_or(false, |modifiers| modifiers.iter().any(|modifier| modifier.kind == target)) + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSExportAssignment<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: Expression<'a>, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSNamespaceExportDeclaration { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub id: IdentifierName, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct TSInstantiationExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: Expression<'a>, + pub type_parameters: Box<'a, TSTypeParameterInstantiation<'a>>, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub enum ImportOrExportKind { + Value, + Type, +} + +impl ImportOrExportKind { + #[must_use] + pub fn is_value(&self) -> bool { + matches!(self, Self::Value) + } + + #[must_use] + pub fn is_type(&self) -> bool { + matches!(self, Self::Type) + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct JSDocNullableType<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub type_annotation: TSType<'a>, + pub postfix: bool, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct JSDocUnknownType { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +/// JSX Element +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct JSXElement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub opening_element: Box<'a, JSXOpeningElement<'a>>, + pub closing_element: Option>>, + pub children: Vec<'a, JSXChild<'a>>, +} + +/// JSX Opening Element +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct JSXOpeningElement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub self_closing: bool, + pub name: JSXElementName<'a>, + pub attributes: Vec<'a, JSXAttributeItem<'a>>, + pub type_parameters: Option>>, +} + +/// JSX Closing Element +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct JSXClosingElement<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub name: JSXElementName<'a>, +} + +/// JSX Fragment +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] +pub struct JSXFragment<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub opening_fragment: JSXOpeningFragment, + pub closing_fragment: JSXClosingFragment, + pub children: Vec<'a, JSXChild<'a>>, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct JSXOpeningFragment { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct JSXClosingFragment { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +/// JSX Element Name +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum JSXElementName<'a> { + Identifier(JSXIdentifier), + NamespacedName(Box<'a, JSXNamespacedName>), + MemberExpression(Box<'a, JSXMemberExpression<'a>>), +} + +/// JSX Namespaced Name +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct JSXNamespacedName { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub namespace: JSXIdentifier, + pub property: JSXIdentifier, +} + +/// JSX Member Expression +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct JSXMemberExpression<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub object: JSXMemberExpressionObject<'a>, + pub property: JSXIdentifier, +} + +impl<'a> JSXMemberExpression<'a> { + #[must_use] + pub fn get_object_identifier(&self) -> &JSXIdentifier { + match &self.object { + JSXMemberExpressionObject::Identifier(ident) => ident, + JSXMemberExpressionObject::MemberExpression(expr) => expr.get_object_identifier(), + } + } +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum JSXMemberExpressionObject<'a> { + Identifier(JSXIdentifier), + MemberExpression(Box<'a, JSXMemberExpression<'a>>), +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct JSXExpressionContainer<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: JSXExpression<'a>, +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum JSXExpression<'a> { + Expression(Expression<'a>), + EmptyExpression(JSXEmptyExpression), +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct JSXEmptyExpression { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, +} + +// 1.3 JSX Attributes + +/// JSX Attributes +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum JSXAttributeItem<'a> { + Attribute(Box<'a, JSXAttribute<'a>>), + SpreadAttribute(Box<'a, JSXSpreadAttribute<'a>>), +} + +/// JSX Attribute +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct JSXAttribute<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub name: JSXAttributeName<'a>, + pub value: Option>, +} + +/// JSX Spread Attribute +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct JSXSpreadAttribute<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub argument: Expression<'a>, +} + +/// JSX Attribute Name +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum JSXAttributeName<'a> { + Identifier(JSXIdentifier), + NamespacedName(Box<'a, JSXNamespacedName>), +} + +/// JSX Attribute Value +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum JSXAttributeValue<'a> { + StringLiteral(StringLiteral), + ExpressionContainer(JSXExpressionContainer<'a>), + Element(Box<'a, JSXElement<'a>>), + Fragment(Box<'a, JSXFragment<'a>>), +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct JSXIdentifier { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub name: Atom, +} + +// 1.4 JSX Children + +/// JSX Child +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +pub enum JSXChild<'a> { + Text(JSXText), + Element(Box<'a, JSXElement<'a>>), + Fragment(Box<'a, JSXFragment<'a>>), + ExpressionContainer(JSXExpressionContainer<'a>), + Spread(JSXSpreadChild<'a>), +} + +#[derive(Debug, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct JSXSpreadChild<'a> { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub expression: Expression<'a>, +} + +/// JSX Text +#[derive(Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] +pub struct JSXText { + #[cfg_attr(feature = "serde", serde(flatten))] + pub span: Span, + pub value: Atom, +} diff --git a/crates/oxc_hir/src/lib.rs b/crates/oxc_hir/src/lib.rs index 6b2ea3a79..f4e2e8706 100644 --- a/crates/oxc_hir/src/lib.rs +++ b/crates/oxc_hir/src/lib.rs @@ -1,2 +1,4 @@ +#![feature(let_chains)] + pub mod hir; pub mod lower;