mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
feat(transform): oxc_traverse crate (#3169)
First part of #3152. This adds a crate `oxc_traverse`, but doesn't connect it up to the transformer or anything else yet. I think we could merge this now - as it doesn't affect any code that's in use - and then iterate on it to add scopes before using it in transformer. Please see https://github.com/oxc-project/oxc/pull/3152#issuecomment-2094965406 for the broader picture.
This commit is contained in:
parent
0ceeec8cbe
commit
be87ca8419
30 changed files with 19626 additions and 4 deletions
101
Cargo.lock
generated
101
Cargo.lock
generated
|
|
@ -973,6 +973,15 @@ version = "2.7.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miette"
|
||||
version = "7.2.0"
|
||||
|
|
@ -1249,6 +1258,7 @@ dependencies = [
|
|||
"bitflags 2.5.0",
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
"oxc_ast_macros",
|
||||
"oxc_span",
|
||||
"oxc_syntax",
|
||||
"serde",
|
||||
|
|
@ -1258,6 +1268,10 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ast_macros"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "oxc_benchmark"
|
||||
version = "0.0.0"
|
||||
|
|
@ -1688,6 +1702,18 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oxc_traverse"
|
||||
version = "0.12.5"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
"oxc_span",
|
||||
"oxc_syntax",
|
||||
"trybuild",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oxc_wasm"
|
||||
version = "0.0.0"
|
||||
|
|
@ -2229,6 +2255,15 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
|
|
@ -2357,6 +2392,15 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.1"
|
||||
|
|
@ -2466,6 +2510,40 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
|
|
@ -2587,6 +2665,20 @@ dependencies = [
|
|||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trybuild"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a0e5d82932dfbf36df38de5df0cfe846d13430b3ae3fdc48b2e91ed692c8df7"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"termcolor",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tsify"
|
||||
version = "0.4.5"
|
||||
|
|
@ -3004,6 +3096,15 @@ version = "0.52.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "1.0.1"
|
||||
|
|
|
|||
|
|
@ -87,10 +87,12 @@ oxc_transformer = { version = "0.12.5", path = "crates/oxc_transformer" }
|
|||
oxc_sourcemap = { version = "0.12.5", path = "crates/oxc_sourcemap" }
|
||||
|
||||
# publish = false
|
||||
oxc_ast_macros = { path = "crates/oxc_ast_macros" }
|
||||
oxc_macros = { path = "crates/oxc_macros" }
|
||||
oxc_linter = { path = "crates/oxc_linter" }
|
||||
oxc_prettier = { path = "crates/oxc_prettier" }
|
||||
oxc_tasks_common = { path = "tasks/common" }
|
||||
oxc_traverse = { path = "crates/oxc_traverse" }
|
||||
|
||||
napi = "2"
|
||||
napi-derive = "2"
|
||||
|
|
@ -110,6 +112,7 @@ ignore = "0.4.22"
|
|||
itertools = "0.12.1"
|
||||
jemallocator = "0.5.4"
|
||||
lazy_static = "1.4.0"
|
||||
memoffset = "0.9.1"
|
||||
miette = { version = "7.2.0", features = ["fancy-no-syscall"] }
|
||||
mimalloc = "0.1.41"
|
||||
num-bigint = "0.4.4"
|
||||
|
|
@ -132,6 +135,7 @@ tempfile = "3.10.1"
|
|||
thiserror = "1.0.59"
|
||||
tokio = "1"
|
||||
tower-lsp = "0.20.0"
|
||||
trybuild = "1.0.93"
|
||||
unicode-id-start = "1.1.2"
|
||||
ureq = { version = "2.9.6", default-features = false }
|
||||
url = "2.5.0"
|
||||
|
|
@ -169,7 +173,7 @@ unicode-width = "0.1.12"
|
|||
saphyr = "0.0.1"
|
||||
|
||||
[workspace.metadata.cargo-shear]
|
||||
ignored = ["napi"]
|
||||
ignored = ["napi", "oxc_traverse"]
|
||||
|
||||
[profile.dev]
|
||||
# Disabling debug info speeds up local and CI builds,
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ workspace = true
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
oxc_allocator = { workspace = true }
|
||||
oxc_span = { workspace = true }
|
||||
oxc_syntax = { workspace = true }
|
||||
oxc_allocator = { workspace = true }
|
||||
oxc_ast_macros = { workspace = true }
|
||||
oxc_span = { workspace = true }
|
||||
oxc_syntax = { workspace = true }
|
||||
|
||||
bitflags = { workspace = true }
|
||||
num-bigint = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
// NB: `#[visited_node]` attribute on AST nodes does not do anything to the code in this file.
|
||||
// It is purely a marker for codegen used in `oxc_traverse`. See docs in that crate.
|
||||
|
||||
// Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]`
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use std::{cell::Cell, fmt, hash::Hash};
|
||||
|
||||
use oxc_allocator::{Box, Vec};
|
||||
use oxc_ast_macros::visited_node;
|
||||
use oxc_span::{Atom, CompactStr, SourceType, Span};
|
||||
use oxc_syntax::{
|
||||
operator::{
|
||||
|
|
@ -37,6 +41,7 @@ export interface FormalParameterRest extends Span {
|
|||
}
|
||||
"#;
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -65,6 +70,7 @@ inherit_variants! {
|
|||
/// Expression
|
||||
///
|
||||
/// Inherits variants from [`MemberExpression`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -389,6 +395,7 @@ impl<'a> Expression<'a> {
|
|||
}
|
||||
|
||||
/// Identifier Name
|
||||
#[visited_node]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename = "Identifier"))]
|
||||
|
|
@ -405,6 +412,7 @@ impl<'a> IdentifierName<'a> {
|
|||
}
|
||||
|
||||
/// Identifier Reference
|
||||
#[visited_node]
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename = "Identifier"))]
|
||||
|
|
@ -432,6 +440,7 @@ impl<'a> IdentifierReference<'a> {
|
|||
}
|
||||
|
||||
/// Binding Identifier
|
||||
#[visited_node]
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename = "Identifier"))]
|
||||
|
|
@ -457,6 +466,7 @@ impl<'a> BindingIdentifier<'a> {
|
|||
}
|
||||
|
||||
/// Label Identifier
|
||||
#[visited_node]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename = "Identifier"))]
|
||||
|
|
@ -467,6 +477,7 @@ pub struct LabelIdentifier<'a> {
|
|||
}
|
||||
|
||||
/// This Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -476,6 +487,7 @@ pub struct ThisExpression {
|
|||
}
|
||||
|
||||
/// <https://tc39.es/ecma262/#prod-ArrayLiteral>
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -494,6 +506,7 @@ inherit_variants! {
|
|||
/// Array Expression Element
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
|
|
@ -516,12 +529,14 @@ impl<'a> ArrayExpressionElement<'a> {
|
|||
|
||||
/// Array Expression Elision Element
|
||||
/// Serialized as `null` in JSON AST. See `serialize.rs`.
|
||||
#[visited_node]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub struct Elision {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// Object Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -540,6 +555,7 @@ impl<'a> ObjectExpression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -548,6 +564,7 @@ pub enum ObjectPropertyKind<'a> {
|
|||
SpreadProperty(Box<'a, SpreadElement<'a>>),
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -567,6 +584,7 @@ inherit_variants! {
|
|||
/// Property Key
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -646,6 +664,7 @@ pub enum PropertyKind {
|
|||
/// Template Literal
|
||||
///
|
||||
/// This is interpreted by interleaving the expression elements in between the quasi elements.
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -667,6 +686,7 @@ impl<'a> TemplateLiteral<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -678,6 +698,7 @@ pub struct TaggedTemplateExpression<'a> {
|
|||
pub type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -704,6 +725,7 @@ pub struct TemplateElementValue<'a> {
|
|||
}
|
||||
|
||||
/// <https://tc39.es/ecma262/#prod-MemberExpression>
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -812,6 +834,7 @@ impl<'a> MemberExpression<'a> {
|
|||
}
|
||||
|
||||
/// `MemberExpression[?Yield, ?Await] [ Expression[+In, ?Yield, ?Await] ]`
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -824,6 +847,7 @@ pub struct ComputedMemberExpression<'a> {
|
|||
}
|
||||
|
||||
/// `MemberExpression[?Yield, ?Await] . IdentifierName`
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -836,6 +860,7 @@ pub struct StaticMemberExpression<'a> {
|
|||
}
|
||||
|
||||
/// `MemberExpression[?Yield, ?Await] . PrivateIdentifier`
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -848,6 +873,7 @@ pub struct PrivateFieldExpression<'a> {
|
|||
}
|
||||
|
||||
/// Call Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -909,6 +935,7 @@ impl<'a> CallExpression<'a> {
|
|||
}
|
||||
|
||||
/// New Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -921,6 +948,7 @@ pub struct NewExpression<'a> {
|
|||
}
|
||||
|
||||
/// Meta Property `new.target` | `import.meta`
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -932,6 +960,7 @@ pub struct MetaProperty<'a> {
|
|||
}
|
||||
|
||||
/// Spread Element
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -945,6 +974,7 @@ inherit_variants! {
|
|||
/// Argument
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -963,6 +993,7 @@ impl Argument<'_> {
|
|||
}
|
||||
|
||||
/// Update Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -975,6 +1006,7 @@ pub struct UpdateExpression<'a> {
|
|||
}
|
||||
|
||||
/// Unary Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -986,6 +1018,7 @@ pub struct UnaryExpression<'a> {
|
|||
}
|
||||
|
||||
/// Binary Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -998,6 +1031,7 @@ pub struct BinaryExpression<'a> {
|
|||
}
|
||||
|
||||
/// Private Identifier in Shift Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1010,6 +1044,7 @@ pub struct PrivateInExpression<'a> {
|
|||
}
|
||||
|
||||
/// Binary Logical Operators
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1022,6 +1057,7 @@ pub struct LogicalExpression<'a> {
|
|||
}
|
||||
|
||||
/// Conditional Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1034,6 +1070,7 @@ pub struct ConditionalExpression<'a> {
|
|||
}
|
||||
|
||||
/// Assignment Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1049,6 +1086,7 @@ inherit_variants! {
|
|||
/// Destructuring Assignment
|
||||
///
|
||||
/// Inherits variants from [`SimpleAssignmentTarget`] and [`AssignmentTargetPattern`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -1084,6 +1122,7 @@ inherit_variants! {
|
|||
/// Simple Assignment Target
|
||||
///
|
||||
/// Inherits variants from [`MemberExpression`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -1128,6 +1167,7 @@ impl<'a> SimpleAssignmentTarget<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -1147,6 +1187,7 @@ macro_rules! match_assignment_target_pattern {
|
|||
pub use match_assignment_target_pattern;
|
||||
|
||||
// See serializer in serialize.rs
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1174,6 +1215,7 @@ impl<'a> ArrayAssignmentTarget<'a> {
|
|||
}
|
||||
|
||||
// See serializer in serialize.rs
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1206,6 +1248,7 @@ impl<'a> ObjectAssignmentTarget<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename = "RestElement"))]
|
||||
|
|
@ -1220,6 +1263,7 @@ inherit_variants! {
|
|||
/// Assignment Target Maybe Default
|
||||
///
|
||||
/// Inherits variants from [`AssignmentTarget`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -1247,6 +1291,7 @@ impl<'a> AssignmentTargetMaybeDefault<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1257,6 +1302,7 @@ pub struct AssignmentTargetWithDefault<'a> {
|
|||
pub init: Expression<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -1266,6 +1312,7 @@ pub enum AssignmentTargetProperty<'a> {
|
|||
}
|
||||
|
||||
/// Assignment Property - Identifier Reference
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1277,6 +1324,7 @@ pub struct AssignmentTargetPropertyIdentifier<'a> {
|
|||
}
|
||||
|
||||
/// Assignment Property - Property Name
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1288,6 +1336,7 @@ pub struct AssignmentTargetPropertyProperty<'a> {
|
|||
}
|
||||
|
||||
/// Sequence Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1297,6 +1346,7 @@ pub struct SequenceExpression<'a> {
|
|||
pub expressions: Vec<'a, Expression<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1306,6 +1356,7 @@ pub struct Super {
|
|||
}
|
||||
|
||||
/// Await Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1315,6 +1366,7 @@ pub struct AwaitExpression<'a> {
|
|||
pub argument: Expression<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1328,6 +1380,7 @@ inherit_variants! {
|
|||
/// Chain Element
|
||||
///
|
||||
/// Inherits variants from [`MemberExpression`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -1340,6 +1393,7 @@ pub enum ChainElement<'a> {
|
|||
}
|
||||
|
||||
/// Parenthesized Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1353,6 +1407,7 @@ inherit_variants! {
|
|||
/// Statement
|
||||
///
|
||||
/// Inherits variants from [`Declaration`] and [`ModuleDeclaration`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -1398,6 +1453,7 @@ impl<'a> Statement<'a> {
|
|||
}
|
||||
|
||||
/// Directive Prologue
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1412,6 +1468,7 @@ pub struct Directive<'a> {
|
|||
}
|
||||
|
||||
/// Hashbang
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1422,6 +1479,7 @@ pub struct Hashbang<'a> {
|
|||
}
|
||||
|
||||
/// Block Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1432,6 +1490,7 @@ pub struct BlockStatement<'a> {
|
|||
}
|
||||
|
||||
/// Declarations and the Variable Statement
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -1503,6 +1562,7 @@ impl<'a> Declaration<'a> {
|
|||
}
|
||||
|
||||
/// Variable Declaration
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -1559,6 +1619,7 @@ impl fmt::Display for VariableDeclarationKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1574,6 +1635,7 @@ pub struct VariableDeclarator<'a> {
|
|||
|
||||
/// Using Declaration
|
||||
/// * <https://github.com/tc39/proposal-explicit-resource-management>
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -1586,6 +1648,7 @@ pub struct UsingDeclaration<'a> {
|
|||
}
|
||||
|
||||
/// Empty Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1595,6 +1658,7 @@ pub struct EmptyStatement {
|
|||
}
|
||||
|
||||
/// Expression Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1605,6 +1669,7 @@ pub struct ExpressionStatement<'a> {
|
|||
}
|
||||
|
||||
/// If Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1617,6 +1682,7 @@ pub struct IfStatement<'a> {
|
|||
}
|
||||
|
||||
/// Do-While Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1628,6 +1694,7 @@ pub struct DoWhileStatement<'a> {
|
|||
}
|
||||
|
||||
/// While Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1639,6 +1706,7 @@ pub struct WhileStatement<'a> {
|
|||
}
|
||||
|
||||
/// For Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1655,6 +1723,7 @@ inherit_variants! {
|
|||
/// For Statement Init
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -1676,6 +1745,7 @@ impl<'a> ForStatementInit<'a> {
|
|||
}
|
||||
|
||||
/// For-In Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1688,6 +1758,7 @@ pub struct ForInStatement<'a> {
|
|||
}
|
||||
|
||||
/// For-Of Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1704,6 +1775,7 @@ inherit_variants! {
|
|||
/// For Statement Left
|
||||
///
|
||||
/// Inherits variants from [`AssignmentTarget`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -1725,6 +1797,7 @@ impl<'a> ForStatementLeft<'a> {
|
|||
}
|
||||
|
||||
/// Continue Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1735,6 +1808,7 @@ pub struct ContinueStatement<'a> {
|
|||
}
|
||||
|
||||
/// Break Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1745,6 +1819,7 @@ pub struct BreakStatement<'a> {
|
|||
}
|
||||
|
||||
/// Return Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1755,6 +1830,7 @@ pub struct ReturnStatement<'a> {
|
|||
}
|
||||
|
||||
/// With Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1766,6 +1842,7 @@ pub struct WithStatement<'a> {
|
|||
}
|
||||
|
||||
/// Switch Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1776,6 +1853,7 @@ pub struct SwitchStatement<'a> {
|
|||
pub cases: Vec<'a, SwitchCase<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1793,6 +1871,7 @@ impl<'a> SwitchCase<'a> {
|
|||
}
|
||||
|
||||
/// Labelled Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1804,6 +1883,7 @@ pub struct LabeledStatement<'a> {
|
|||
}
|
||||
|
||||
/// Throw Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1814,6 +1894,7 @@ pub struct ThrowStatement<'a> {
|
|||
}
|
||||
|
||||
/// Try Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1825,6 +1906,7 @@ pub struct TryStatement<'a> {
|
|||
pub finalizer: Option<Box<'a, BlockStatement<'a>>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1835,6 +1917,7 @@ pub struct CatchClause<'a> {
|
|||
pub body: Box<'a, BlockStatement<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1845,6 +1928,7 @@ pub struct CatchParameter<'a> {
|
|||
}
|
||||
|
||||
/// Debugger Statement
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1855,6 +1939,7 @@ pub struct DebuggerStatement {
|
|||
|
||||
/// Destructuring Binding Patterns
|
||||
/// * <https://tc39.es/ecma262/#prod-BindingPattern>
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
|
||||
|
|
@ -1880,6 +1965,7 @@ impl<'a> BindingPattern<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -1919,6 +2005,7 @@ impl<'a> BindingPatternKind<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1930,6 +2017,7 @@ pub struct AssignmentPattern<'a> {
|
|||
}
|
||||
|
||||
// See serializer in serialize.rs
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1952,6 +2040,7 @@ impl<'a> ObjectPattern<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1965,6 +2054,7 @@ pub struct BindingProperty<'a> {
|
|||
}
|
||||
|
||||
// See serializer in serialize.rs
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -1990,6 +2080,7 @@ impl<'a> ArrayPattern<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename = "RestElement"))]
|
||||
|
|
@ -2000,6 +2091,7 @@ pub struct BindingRestElement<'a> {
|
|||
}
|
||||
|
||||
/// Function Definitions
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
|
||||
|
|
@ -2078,6 +2170,7 @@ pub enum FunctionType {
|
|||
|
||||
/// <https://tc39.es/ecma262/#prod-FormalParameters>
|
||||
// See serializer in serialize.rs
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2100,6 +2193,7 @@ impl<'a> FormalParameters<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2145,6 +2239,7 @@ impl<'a> FormalParameters<'a> {
|
|||
}
|
||||
|
||||
/// <https://tc39.es/ecma262/#prod-FunctionBody>
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2162,6 +2257,7 @@ impl<'a> FunctionBody<'a> {
|
|||
}
|
||||
|
||||
/// Arrow Function Definitions
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -2192,6 +2288,7 @@ impl<'a> ArrowFunctionExpression<'a> {
|
|||
}
|
||||
|
||||
/// Generator Function Definitions
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2203,6 +2300,7 @@ pub struct YieldExpression<'a> {
|
|||
}
|
||||
|
||||
/// Class Definitions
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
|
||||
|
|
@ -2246,6 +2344,7 @@ pub enum ClassType {
|
|||
ClassExpression,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2255,6 +2354,7 @@ pub struct ClassBody<'a> {
|
|||
pub body: Vec<'a, ClassElement<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -2356,6 +2456,7 @@ impl<'a> ClassElement<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
|
||||
|
|
@ -2381,6 +2482,7 @@ pub enum MethodDefinitionType {
|
|||
TSAbstractMethodDefinition,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
|
||||
|
|
@ -2431,6 +2533,7 @@ impl MethodDefinitionKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2446,6 +2549,7 @@ impl<'a> PrivateIdentifier<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2455,6 +2559,7 @@ pub struct StaticBlock<'a> {
|
|||
pub body: Vec<'a, Statement<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -2534,6 +2639,7 @@ impl<'a> ModuleDeclaration<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2547,6 +2653,7 @@ pub struct AccessorProperty<'a> {
|
|||
pub decorators: Vec<'a, Decorator<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2557,6 +2664,7 @@ pub struct ImportExpression<'a> {
|
|||
pub arguments: Vec<'a, Expression<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -2572,6 +2680,7 @@ pub struct ImportDeclaration<'a> {
|
|||
pub import_kind: ImportOrExportKind,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -2587,6 +2696,7 @@ pub enum ImportDeclarationSpecifier<'a> {
|
|||
|
||||
// import {imported} from "source"
|
||||
// import {imported as local} from "source"
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -2599,6 +2709,7 @@ pub struct ImportSpecifier<'a> {
|
|||
}
|
||||
|
||||
// import local from "source"
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2609,6 +2720,7 @@ pub struct ImportDefaultSpecifier<'a> {
|
|||
}
|
||||
|
||||
// import * as local from "source"
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2618,6 +2730,7 @@ pub struct ImportNamespaceSpecifier<'a> {
|
|||
pub local: BindingIdentifier<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -2628,6 +2741,7 @@ pub struct WithClause<'a> {
|
|||
pub with_entries: Vec<'a, ImportAttribute<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2638,6 +2752,7 @@ pub struct ImportAttribute<'a> {
|
|||
pub value: StringLiteral<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -2655,6 +2770,7 @@ impl<'a> ImportAttributeKey<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -2681,6 +2797,7 @@ impl<'a> ExportNamedDeclaration<'a> {
|
|||
/// export default HoistableDeclaration
|
||||
/// export default ClassDeclaration
|
||||
/// export default AssignmentExpression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -2697,6 +2814,7 @@ impl<'a> ExportDefaultDeclaration<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -2715,6 +2833,7 @@ impl<'a> ExportAllDeclaration<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -2736,6 +2855,7 @@ inherit_variants! {
|
|||
/// Export Default Declaration Kind
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -2769,6 +2889,7 @@ impl<'a> ExportDefaultDeclarationKind<'a> {
|
|||
/// * `export {foo as "\0 any unicode"}`
|
||||
/// * es2022: <https://github.com/estree/estree/blob/master/es2022.md#modules>
|
||||
/// * <https://github.com/tc39/ecma262/pull/2154>
|
||||
#[visited_node]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
//! [JSX](https://facebook.github.io/jsx)
|
||||
|
||||
// NB: `#[visited_node]` attribute on AST nodes does not do anything to the code in this file.
|
||||
// It is purely a marker for codegen used in `oxc_traverse`. See docs in that crate.
|
||||
|
||||
// Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]`
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use oxc_allocator::{Box, Vec};
|
||||
use oxc_ast_macros::visited_node;
|
||||
use oxc_span::{Atom, Span};
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::Serialize;
|
||||
|
|
@ -17,6 +21,7 @@ use super::inherit_variants;
|
|||
// 1.2 JSX Elements
|
||||
|
||||
/// JSX Element
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -29,6 +34,7 @@ pub struct JSXElement<'a> {
|
|||
}
|
||||
|
||||
/// JSX Opening Element
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -42,6 +48,7 @@ pub struct JSXOpeningElement<'a> {
|
|||
}
|
||||
|
||||
/// JSX Closing Element
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -52,6 +59,7 @@ pub struct JSXClosingElement<'a> {
|
|||
}
|
||||
|
||||
/// JSX Fragment
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -80,6 +88,7 @@ pub struct JSXClosingFragment {
|
|||
}
|
||||
|
||||
/// JSX Element Name
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -93,6 +102,7 @@ pub enum JSXElementName<'a> {
|
|||
}
|
||||
|
||||
/// JSX Namespaced Name
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -110,6 +120,7 @@ impl<'a> std::fmt::Display for JSXNamespacedName<'a> {
|
|||
}
|
||||
|
||||
/// JSX Member Expression
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -129,6 +140,7 @@ impl<'a> JSXMemberExpression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -137,6 +149,7 @@ pub enum JSXMemberExpressionObject<'a> {
|
|||
MemberExpression(Box<'a, JSXMemberExpression<'a>>),
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -150,6 +163,7 @@ inherit_variants! {
|
|||
/// JSX Expression
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -168,6 +182,7 @@ impl<'a> JSXExpression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -179,6 +194,7 @@ pub struct JSXEmptyExpression {
|
|||
// 1.3 JSX Attributes
|
||||
|
||||
/// JSX Attributes
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -188,6 +204,7 @@ pub enum JSXAttributeItem<'a> {
|
|||
}
|
||||
|
||||
/// JSX Attribute
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -209,6 +226,7 @@ impl<'a> JSXAttribute<'a> {
|
|||
}
|
||||
|
||||
/// JSX Spread Attribute
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -219,6 +237,7 @@ pub struct JSXSpreadAttribute<'a> {
|
|||
}
|
||||
|
||||
/// JSX Attribute Name
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -228,6 +247,7 @@ pub enum JSXAttributeName<'a> {
|
|||
}
|
||||
|
||||
/// JSX Attribute Value
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -238,6 +258,7 @@ pub enum JSXAttributeValue<'a> {
|
|||
Fragment(Box<'a, JSXFragment<'a>>),
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -256,6 +277,7 @@ impl<'a> JSXIdentifier<'a> {
|
|||
// 1.4 JSX Children
|
||||
|
||||
/// JSX Child
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -267,6 +289,7 @@ pub enum JSXChild<'a> {
|
|||
Spread(Box<'a, JSXSpreadChild<'a>>),
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -276,6 +299,7 @@ pub struct JSXSpreadChild<'a> {
|
|||
pub expression: Expression<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
//! Literals
|
||||
|
||||
// NB: `#[visited_node]` attribute on AST nodes does not do anything to the code in this file.
|
||||
// It is purely a marker for codegen used in `oxc_traverse`. See docs in that crate.
|
||||
|
||||
// Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]`
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
|
|
@ -9,6 +12,7 @@ use std::{
|
|||
};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use oxc_ast_macros::visited_node;
|
||||
use oxc_span::{Atom, Span};
|
||||
use oxc_syntax::number::{BigintBase, NumberBase};
|
||||
#[cfg(feature = "serialize")]
|
||||
|
|
@ -16,6 +20,7 @@ use serde::Serialize;
|
|||
#[cfg(feature = "serialize")]
|
||||
use tsify::Tsify;
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -39,6 +44,7 @@ impl BooleanLiteral {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -59,6 +65,7 @@ impl NullLiteral {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -110,6 +117,7 @@ impl<'a> Hash for NumericLiteral<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -127,6 +135,7 @@ impl<'a> BigIntLiteral<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -234,6 +243,7 @@ impl fmt::Display for RegExpFlags {
|
|||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
pub struct EmptyObject;
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
|
|||
|
|
@ -3,10 +3,14 @@
|
|||
//! [AST Spec](https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/ast-spec)
|
||||
//! [Archived TypeScript spec](https://github.com/microsoft/TypeScript/blob/3c99d50da5a579d9fa92d02664b1b66d4ff55944/doc/spec-ARCHIVED.md)
|
||||
|
||||
// NB: `#[visited_node]` attribute on AST nodes does not do anything to the code in this file.
|
||||
// It is purely a marker for codegen used in `oxc_traverse`. See docs in that crate.
|
||||
|
||||
// Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]`
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use oxc_allocator::{Box, Vec};
|
||||
use oxc_ast_macros::visited_node;
|
||||
use oxc_span::{Atom, GetSpan, Span};
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::Serialize;
|
||||
|
|
@ -25,6 +29,7 @@ export interface TSIndexSignatureName extends Span {
|
|||
}
|
||||
"#;
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -38,6 +43,7 @@ pub struct TSThisParameter<'a> {
|
|||
/// Enum Declaration
|
||||
///
|
||||
/// `const_opt` enum `BindingIdentifier` { `EnumBody_opt` }
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -50,6 +56,7 @@ pub struct TSEnumDeclaration<'a> {
|
|||
pub modifiers: Modifiers<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -64,6 +71,7 @@ inherit_variants! {
|
|||
/// TS Enum Member Name
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -79,6 +87,7 @@ pub enum TSEnumMemberName<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -88,6 +97,7 @@ pub struct TSTypeAnnotation<'a> {
|
|||
pub type_annotation: TSType<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -97,6 +107,7 @@ pub struct TSLiteralType<'a> {
|
|||
pub literal: TSLiteral<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged, rename_all = "camelCase"))]
|
||||
|
|
@ -111,6 +122,7 @@ pub enum TSLiteral<'a> {
|
|||
UnaryExpression(Box<'a, UnaryExpression<'a>>),
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -219,6 +231,7 @@ impl<'a> TSType<'a> {
|
|||
/// `SomeType extends OtherType ? TrueType : FalseType;`
|
||||
///
|
||||
/// <https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#handbook-content>
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -234,6 +247,7 @@ pub struct TSConditionalType<'a> {
|
|||
/// string | string[] | (() => string) | { s: string }
|
||||
///
|
||||
/// <https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#unions>
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -246,6 +260,7 @@ pub struct TSUnionType<'a> {
|
|||
/// type `ColorfulCircle` = Colorful & Circle;
|
||||
///
|
||||
/// <https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types>
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -258,6 +273,7 @@ pub struct TSIntersectionType<'a> {
|
|||
/// keyof unique readonly
|
||||
///
|
||||
/// <https://www.typescriptlang.org/docs/handbook/2/keyof-types.html>
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -280,6 +296,7 @@ pub enum TSTypeOperatorOperator {
|
|||
/// `let myArray: string[] = ["hello", "world"];`
|
||||
///
|
||||
/// <https://www.typescriptlang.org/docs/handbook/2/objects.html#the-array-type>
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -292,6 +309,7 @@ pub struct TSArrayType<'a> {
|
|||
/// `type I1 = Person["age" | "name"];`
|
||||
///
|
||||
/// <https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html#handbook-content>
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -305,6 +323,7 @@ pub struct TSIndexedAccessType<'a> {
|
|||
/// type `StringNumberPair` = [string, number];
|
||||
///
|
||||
/// <https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types>
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -314,6 +333,7 @@ pub struct TSTupleType<'a> {
|
|||
pub element_types: Vec<'a, TSTupleElement<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -325,6 +345,7 @@ pub struct TSNamedTupleMember<'a> {
|
|||
pub optional: bool,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -334,6 +355,7 @@ pub struct TSOptionalType<'a> {
|
|||
pub type_annotation: TSType<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -347,6 +369,7 @@ inherit_variants! {
|
|||
/// TS Tuple Element
|
||||
///
|
||||
/// Inherits variants from [`TSType`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -361,6 +384,7 @@ pub enum TSTupleElement<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -369,6 +393,7 @@ pub struct TSAnyKeyword {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -377,6 +402,7 @@ pub struct TSStringKeyword {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -385,6 +411,7 @@ pub struct TSBooleanKeyword {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -393,6 +420,7 @@ pub struct TSNumberKeyword {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -401,6 +429,7 @@ pub struct TSNeverKeyword {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -409,6 +438,7 @@ pub struct TSUnknownKeyword {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -417,6 +447,7 @@ pub struct TSNullKeyword {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -425,6 +456,7 @@ pub struct TSUndefinedKeyword {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -433,6 +465,7 @@ pub struct TSVoidKeyword {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -441,6 +474,7 @@ pub struct TSSymbolKeyword {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -449,6 +483,7 @@ pub struct TSThisType {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -457,6 +492,7 @@ pub struct TSObjectKeyword {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||
|
|
@ -468,6 +504,7 @@ pub struct TSBigIntKeyword {
|
|||
/// type C = A;
|
||||
/// type D = B.a;
|
||||
/// type E = D.c.b.a;
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -481,6 +518,7 @@ pub struct TSTypeReference<'a> {
|
|||
/// TypeName:
|
||||
/// IdentifierReference
|
||||
/// NamespaceName . IdentifierReference
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -534,6 +572,7 @@ impl GetSpan for TSTypeName<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -544,6 +583,7 @@ pub struct TSQualifiedName<'a> {
|
|||
pub right: IdentifierName<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -553,6 +593,7 @@ pub struct TSTypeParameterInstantiation<'a> {
|
|||
pub params: Vec<'a, TSType<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -567,6 +608,7 @@ pub struct TSTypeParameter<'a> {
|
|||
pub r#const: bool,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -576,6 +618,7 @@ pub struct TSTypeParameterDeclaration<'a> {
|
|||
pub params: Vec<'a, TSTypeParameter<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -598,6 +641,7 @@ pub enum TSAccessibility {
|
|||
Public,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -611,6 +655,7 @@ pub struct TSClassImplements<'a> {
|
|||
/// Interface Declaration
|
||||
///
|
||||
/// interface `BindingIdentifier` `TypeParameters_opt` `InterfaceExtendsClause_opt` `ObjectType`
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -625,6 +670,7 @@ pub struct TSInterfaceDeclaration<'a> {
|
|||
pub modifiers: Modifiers<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -634,6 +680,7 @@ pub struct TSInterfaceBody<'a> {
|
|||
pub body: Vec<'a, TSSignature<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -647,6 +694,7 @@ pub struct TSPropertySignature<'a> {
|
|||
pub type_annotation: Option<Box<'a, TSTypeAnnotation<'a>>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged, rename_all = "camelCase"))]
|
||||
|
|
@ -658,6 +706,7 @@ pub enum TSSignature<'a> {
|
|||
TSMethodSignature(Box<'a, TSMethodSignature<'a>>),
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -669,6 +718,7 @@ pub struct TSIndexSignature<'a> {
|
|||
pub readonly: bool,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -690,6 +740,7 @@ pub enum TSMethodSignatureKind {
|
|||
Set,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -706,6 +757,7 @@ pub struct TSMethodSignature<'a> {
|
|||
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -717,6 +769,7 @@ pub struct TSConstructSignatureDeclaration<'a> {
|
|||
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(
|
||||
|
|
@ -730,6 +783,7 @@ pub struct TSIndexSignatureName<'a> {
|
|||
pub type_annotation: Box<'a, TSTypeAnnotation<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -740,6 +794,7 @@ pub struct TSInterfaceHeritage<'a> {
|
|||
pub type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -751,6 +806,7 @@ pub struct TSTypePredicate<'a> {
|
|||
pub type_annotation: Option<Box<'a, TSTypeAnnotation<'a>>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged, rename_all = "camelCase"))]
|
||||
|
|
@ -759,6 +815,7 @@ pub enum TSTypePredicateName<'a> {
|
|||
This(TSThisType),
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -790,6 +847,7 @@ pub enum TSModuleDeclarationKind {
|
|||
Namespace,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -807,6 +865,7 @@ impl<'a> TSModuleDeclarationName<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -815,6 +874,7 @@ pub enum TSModuleDeclarationBody<'a> {
|
|||
TSModuleBlock(Box<'a, TSModuleBlock<'a>>),
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -824,6 +884,7 @@ pub struct TSModuleBlock<'a> {
|
|||
pub body: Vec<'a, Statement<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -833,6 +894,7 @@ pub struct TSTypeLiteral<'a> {
|
|||
pub members: Vec<'a, TSSignature<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -842,6 +904,7 @@ pub struct TSInferType<'a> {
|
|||
pub type_parameter: Box<'a, TSTypeParameter<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -856,6 +919,7 @@ inherit_variants! {
|
|||
/// TS Type Query Expr Name
|
||||
///
|
||||
/// Inherits variants from [`TSTypeName`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -867,6 +931,7 @@ pub enum TSTypeQueryExprName<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -879,6 +944,7 @@ pub struct TSImportType<'a> {
|
|||
pub type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -888,6 +954,7 @@ pub struct TSImportAttributes<'a> {
|
|||
pub elements: Vec<'a, TSImportAttribute<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -898,6 +965,7 @@ pub struct TSImportAttribute<'a> {
|
|||
pub value: Expression<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
|
|
@ -906,6 +974,7 @@ pub enum TSImportAttributeName<'a> {
|
|||
StringLiteral(StringLiteral<'a>),
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -918,6 +987,7 @@ pub struct TSFunctionType<'a> {
|
|||
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -930,6 +1000,7 @@ pub struct TSConstructorType<'a> {
|
|||
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -955,6 +1026,7 @@ pub enum TSMappedTypeModifierOperator {
|
|||
None,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -965,6 +1037,7 @@ pub struct TSTemplateLiteralType<'a> {
|
|||
pub types: Vec<'a, TSType<'a>>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -975,6 +1048,7 @@ pub struct TSAsExpression<'a> {
|
|||
pub type_annotation: TSType<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -985,6 +1059,7 @@ pub struct TSSatisfiesExpression<'a> {
|
|||
pub type_annotation: TSType<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -995,6 +1070,7 @@ pub struct TSTypeAssertion<'a> {
|
|||
pub type_annotation: TSType<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -1010,6 +1086,7 @@ inherit_variants! {
|
|||
/// TS Module Reference
|
||||
///
|
||||
/// Inherits variants from [`TSTypeName`].
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
|
|
@ -1021,6 +1098,7 @@ pub enum TSModuleReference<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -1030,6 +1108,7 @@ pub struct TSExternalModuleReference<'a> {
|
|||
pub expression: StringLiteral<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -1039,6 +1118,7 @@ pub struct TSNonNullExpression<'a> {
|
|||
pub expression: Expression<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -1145,6 +1225,7 @@ impl<'a> Modifiers<'a> {
|
|||
/// Export Assignment in non-module files
|
||||
///
|
||||
/// `export = foo`
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -1157,6 +1238,7 @@ pub struct TSExportAssignment<'a> {
|
|||
/// Namespace Export Declaration in declaration files
|
||||
///
|
||||
/// `export as namespace foo`
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -1166,6 +1248,7 @@ pub struct TSNamespaceExportDeclaration<'a> {
|
|||
pub id: IdentifierName<'a>,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -1196,6 +1279,7 @@ impl ImportOrExportKind {
|
|||
|
||||
// [`JSDoc`](https://github.com/microsoft/TypeScript/blob/54a554d8af2657630307cbfa8a3e4f3946e36507/src/compiler/types.ts#L393)
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
@ -1206,6 +1290,7 @@ pub struct JSDocNullableType<'a> {
|
|||
pub postfix: bool,
|
||||
}
|
||||
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
|
|
|
|||
20
crates/oxc_ast_macros/Cargo.toml
Normal file
20
crates/oxc_ast_macros/Cargo.toml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
[package]
|
||||
name = "oxc_ast_macros"
|
||||
version = "0.0.0"
|
||||
publish = false
|
||||
authors.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
rust-version.workspace = true
|
||||
categories.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
doctest = false
|
||||
8
crates/oxc_ast_macros/src/lib.rs
Normal file
8
crates/oxc_ast_macros/src/lib.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
use proc_macro::TokenStream;
|
||||
|
||||
/// Attach to AST node type (struct or enum), to signal to codegen to create visitor for this type.
|
||||
/// Macro itself does nothing - just passes through the token stream unchanged.
|
||||
#[proc_macro_attribute]
|
||||
pub fn visited_node(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
||||
29
crates/oxc_traverse/Cargo.toml
Normal file
29
crates/oxc_traverse/Cargo.toml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
[package]
|
||||
name = "oxc_traverse"
|
||||
version = "0.12.5"
|
||||
authors.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
rust-version.workspace = true
|
||||
categories.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = true
|
||||
|
||||
[dependencies]
|
||||
oxc_allocator = { workspace = true }
|
||||
oxc_ast = { workspace = true }
|
||||
oxc_span = { workspace = true }
|
||||
oxc_syntax = { workspace = true }
|
||||
|
||||
memoffset = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
trybuild = { workspace = true }
|
||||
22
crates/oxc_traverse/build.rs
Normal file
22
crates/oxc_traverse/build.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
use std::{env, process::Command};
|
||||
|
||||
fn main() {
|
||||
// Re-run if NodeJS build script or AST types change
|
||||
println!("cargo:rerun-if-changed=scripts");
|
||||
println!("cargo:rerun-if-changed=../oxc_ast/src/ast");
|
||||
|
||||
// Exit if on CI.
|
||||
// The built files should be checked into git, so want to run tests etc on what's actually in repo,
|
||||
// rather than regenerating them.
|
||||
match env::var("CI") {
|
||||
Ok(value) if value == "true" => return,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Run NodeJS build script
|
||||
let status = Command::new("node")
|
||||
.arg("./scripts/build.mjs")
|
||||
.status()
|
||||
.expect("Failed to run NodeJS build script");
|
||||
assert!(status.success(), "Failed to run NodeJS build script");
|
||||
}
|
||||
40
crates/oxc_traverse/scripts/build.mjs
Normal file
40
crates/oxc_traverse/scripts/build.mjs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Codegen for `traverse`.
|
||||
*
|
||||
* Parses Rust AST type definitions from files in `crates/oxc_ast/src/ast`, and generates:
|
||||
* - `src/traverse.rs`
|
||||
* - `src/ancestor.rs`
|
||||
* - `src/walk.rs`
|
||||
*
|
||||
* This is a quick-and-dirty version written in JS for speed of implementation.
|
||||
* We should do this properly with a Rust build script using `syn` etc.
|
||||
*/
|
||||
|
||||
import {writeFile} from 'fs/promises';
|
||||
import {exec} from 'child_process';
|
||||
import {join as pathJoin} from 'path';
|
||||
import {fileURLToPath} from 'url';
|
||||
import {promisify} from 'util';
|
||||
import getTypesFromCode from './lib/parse.mjs';
|
||||
import generateTraverseTraitCode from './lib/traverse.mjs';
|
||||
import generateAncestorsCode from './lib/ancestor.mjs';
|
||||
import generateWalkFunctionsCode from './lib/walk.mjs';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
const PREAMBLE = '// Generated by `scripts/build.mjs`.\n\n';
|
||||
|
||||
const types = await getTypesFromCode();
|
||||
|
||||
const outputDirPath = pathJoin(fileURLToPath(import.meta.url), '../../src');
|
||||
await writeToFile('traverse.rs', generateTraverseTraitCode(types));
|
||||
await writeToFile('ancestor.rs', generateAncestorsCode(types));
|
||||
await writeToFile('walk.rs', generateWalkFunctionsCode(types));
|
||||
|
||||
async function writeToFile(filename, code) {
|
||||
code = `${PREAMBLE}${code}`;
|
||||
const path = pathJoin(outputDirPath, filename);
|
||||
console.log('Writing:', path);
|
||||
await writeFile(path, code);
|
||||
await execAsync(`rustfmt ${JSON.stringify(path)}`);
|
||||
}
|
||||
142
crates/oxc_traverse/scripts/lib/ancestor.mjs
Normal file
142
crates/oxc_traverse/scripts/lib/ancestor.mjs
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
import {camelToSnake, snakeToCamel} from './utils.mjs';
|
||||
|
||||
export default function generateAncestorsCode(types) {
|
||||
const variantNamesForEnums = Object.create(null);
|
||||
let enumVariants = '',
|
||||
isFunctions = '',
|
||||
ancestorTypes = '',
|
||||
discriminant = 1;
|
||||
for (const type of Object.values(types)) {
|
||||
if (type.kind === 'enum') continue;
|
||||
|
||||
const typeSnakeName = camelToSnake(type.name),
|
||||
typeScreamingName = typeSnakeName.toUpperCase();
|
||||
let offsetCode = '';
|
||||
for (const field of type.fields) {
|
||||
const offsetVarName = `OFFSET_${typeScreamingName}_${field.name.toUpperCase()}`;
|
||||
field.offsetVarName = offsetVarName;
|
||||
offsetCode += `pub(crate) const ${offsetVarName}: usize = `
|
||||
+ `offset_of!(${type.name}, ${field.rawName});\n`;
|
||||
}
|
||||
|
||||
const variantNames = [];
|
||||
let thisAncestorTypes = '';
|
||||
for (const field of type.fields) {
|
||||
const fieldTypeName = field.innerTypeName,
|
||||
fieldType = types[fieldTypeName];
|
||||
if (!fieldType) continue;
|
||||
|
||||
let methodsCode = '';
|
||||
for (const otherField of type.fields) {
|
||||
if (otherField === field) continue;
|
||||
|
||||
methodsCode += `
|
||||
#[inline]
|
||||
pub fn ${otherField.rawName}(&self) -> &${otherField.rawTypeName} {
|
||||
unsafe {
|
||||
&*(
|
||||
(self.0 as *const u8).add(${otherField.offsetVarName})
|
||||
as *const ${otherField.rawTypeName}
|
||||
)
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
const fieldNameCamel = snakeToCamel(field.name),
|
||||
lifetime = type.hasLifetime ? "<'a>" : '',
|
||||
structName = `${type.name}Without${fieldNameCamel}${lifetime}`;
|
||||
|
||||
thisAncestorTypes += `
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct ${structName}(
|
||||
pub(crate) *const ${type.name}${lifetime}
|
||||
);
|
||||
|
||||
impl${lifetime} ${structName} {
|
||||
${methodsCode}
|
||||
}
|
||||
`;
|
||||
|
||||
const variantName = `${type.name}${fieldNameCamel}`;
|
||||
variantNames.push(variantName);
|
||||
|
||||
enumVariants += `${variantName}(${structName}) = ${discriminant},\n`;
|
||||
field.ancestorDiscriminant = discriminant;
|
||||
discriminant++;
|
||||
|
||||
if (fieldType.kind === 'enum') {
|
||||
(variantNamesForEnums[fieldTypeName] || (variantNamesForEnums[fieldTypeName] = []))
|
||||
.push(variantName);
|
||||
}
|
||||
}
|
||||
|
||||
if (variantNames.length > 0) {
|
||||
ancestorTypes += `
|
||||
${offsetCode}
|
||||
${thisAncestorTypes}
|
||||
`;
|
||||
|
||||
isFunctions += `
|
||||
#[inline]
|
||||
pub fn is_${typeSnakeName}(&self) -> bool {
|
||||
matches!(self, ${variantNames.map(name => `Self::${name}(_)`).join(' | ')})
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
for (const [typeName, variantNames] of Object.entries(variantNamesForEnums)) {
|
||||
isFunctions += `
|
||||
#[inline]
|
||||
pub fn is_via_${camelToSnake(typeName)}(&self) -> bool {
|
||||
matches!(self, ${variantNames.map(name => `Self::${name}(_)`).join(' | ')})
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
const discriminantType = discriminant <= 256 ? 'u8' : 'u16';
|
||||
|
||||
return `
|
||||
#![allow(
|
||||
unsafe_code,
|
||||
clippy::missing_safety_doc,
|
||||
clippy::ptr_as_ptr,
|
||||
clippy::undocumented_unsafe_blocks,
|
||||
clippy::cast_ptr_alignment
|
||||
)]
|
||||
|
||||
use memoffset::offset_of;
|
||||
|
||||
use oxc_allocator::{Box, Vec};
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_span::{Atom, SourceType, Span};
|
||||
use oxc_syntax::operator::{
|
||||
AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator,
|
||||
};
|
||||
|
||||
pub(crate) type AncestorDiscriminant = ${discriminantType};
|
||||
|
||||
/// Ancestor type used in AST traversal.
|
||||
///
|
||||
/// Encodes both the type of the parent, and child's location in the parent.
|
||||
/// i.e. variants for \`BinaryExpressionLeft\` and \`BinaryExpressionRight\`, not just \`BinaryExpression\`.
|
||||
//
|
||||
// SAFETY: This type MUST be \`#[repr(u8)]\` or \`#[repr(u16)]\` (depending on number of variants)
|
||||
// to maintain the safety of \`TraverseCtx::retag_stack\`.
|
||||
#[repr(C, ${discriminantType})]
|
||||
#[derive(Debug)]
|
||||
pub enum Ancestor<'a> {
|
||||
None = 0,
|
||||
${enumVariants}
|
||||
}
|
||||
|
||||
impl<'a> Ancestor<'a> {
|
||||
${isFunctions}
|
||||
}
|
||||
|
||||
${ancestorTypes}
|
||||
`;
|
||||
}
|
||||
98
crates/oxc_traverse/scripts/lib/parse.mjs
Normal file
98
crates/oxc_traverse/scripts/lib/parse.mjs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import {readFile} from 'fs/promises';
|
||||
import {join as pathJoin} from 'path';
|
||||
import {fileURLToPath} from 'url';
|
||||
import assert from 'assert';
|
||||
import {typeAndWrappers} from './utils.mjs';
|
||||
|
||||
const FILENAMES = ['js.rs', 'jsx.rs', 'literal.rs', 'ts.rs'];
|
||||
|
||||
/**
|
||||
* Parse type defs from Rust files.
|
||||
*/
|
||||
export default async function getTypesFromCode() {
|
||||
const codeDirPath = pathJoin(fileURLToPath(import.meta.url), '../../../../oxc_ast/src/ast/');
|
||||
|
||||
const types = Object.create(null);
|
||||
for (const filename of FILENAMES) {
|
||||
const code = await readFile(`${codeDirPath}${filename}`, 'utf8');
|
||||
parseFile(code, filename, types);
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
function parseFile(code, filename, types) {
|
||||
const lines = code.split(/\r?\n/);
|
||||
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
||||
if (lines[lineIndex] !== '#[visited_node]') continue;
|
||||
|
||||
let match;
|
||||
while (true) {
|
||||
match = lines[++lineIndex].match(/^pub (enum|struct) (.+?)(<'a>)? \{/);
|
||||
if (match) break;
|
||||
}
|
||||
const [, kind, name, lifetimeStr] = match,
|
||||
hasLifetime = !!lifetimeStr,
|
||||
startLineIndex = lineIndex;
|
||||
|
||||
const itemLines = [];
|
||||
while (true) {
|
||||
const line = lines[++lineIndex].replace(/\/\/.*$/, '').replace(/\s+/g, ' ').trim();
|
||||
if (line === '}') break;
|
||||
if (line !== '') itemLines.push(line);
|
||||
}
|
||||
|
||||
if (kind === 'struct') {
|
||||
types[name] = parseStruct(name, hasLifetime, itemLines, filename, startLineIndex);
|
||||
} else {
|
||||
types[name] = parseEnum(name, hasLifetime, itemLines, filename, startLineIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseStruct(name, hasLifetime, lines, filename, startLineIndex) {
|
||||
const fields = [];
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
if (line.startsWith('#[')) {
|
||||
while (!lines[i].endsWith(']')) {
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const match = line.match(/^pub ((?:r#)?([a-z_]+)): (.+),$/);
|
||||
assert(
|
||||
match,
|
||||
`Cannot parse line ${startLineIndex + i} in '${filename}' as struct field: '${line}'`
|
||||
);
|
||||
const [, rawName, name, rawTypeName] = match,
|
||||
typeName = rawTypeName.replace(/<'a>/g, '').replace(/<'a, ?/g, '<'),
|
||||
{name: innerTypeName, wrappers} = typeAndWrappers(typeName);
|
||||
|
||||
fields.push({name, typeName, rawName, rawTypeName, innerTypeName, wrappers});
|
||||
}
|
||||
return {kind: 'struct', name, hasLifetime, fields};
|
||||
}
|
||||
|
||||
function parseEnum(name, hasLifetime, lines, filename, startLineIndex) {
|
||||
const variants = [],
|
||||
inherits = [];
|
||||
for (const [lineIndex, line] of lines.entries()) {
|
||||
const match = line.match(/^(.+?)\((.+?)\)(?: ?= ?(\d+))?,$/);
|
||||
if (match) {
|
||||
const [, name, rawTypeName, discriminantStr] = match,
|
||||
typeName = rawTypeName.replace(/<'a>/g, '').replace(/<'a,\s*/g, '<'),
|
||||
{name: innerTypeName, wrappers} = typeAndWrappers(typeName),
|
||||
discriminant = discriminantStr ? +discriminantStr : null;
|
||||
variants.push({name, typeName, rawTypeName, innerTypeName, wrappers, discriminant});
|
||||
} else {
|
||||
const match2 = line.match(/^@inherit ([A-Za-z]+)$/);
|
||||
assert(
|
||||
match2,
|
||||
`Cannot parse line ${startLineIndex + lineIndex} in '${filename}' as enum variant: '${line}'`
|
||||
);
|
||||
inherits.push(match2[1]);
|
||||
}
|
||||
}
|
||||
return {kind: 'enum', name, hasLifetime, variants, inherits};
|
||||
}
|
||||
33
crates/oxc_traverse/scripts/lib/traverse.mjs
Normal file
33
crates/oxc_traverse/scripts/lib/traverse.mjs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import {camelToSnake, toTypeName} from './utils.mjs';
|
||||
|
||||
export default function generateTraverseTraitCode(types) {
|
||||
let traverseMethods = '';
|
||||
for (const type of Object.values(types)) {
|
||||
const snakeName = camelToSnake(type.name),
|
||||
typeName = toTypeName(type);
|
||||
traverseMethods += `
|
||||
#[inline]
|
||||
fn enter_${snakeName}(&mut self, node: &mut ${typeName}, ctx: &TraverseCtx<'a>) {}
|
||||
#[inline]
|
||||
fn exit_${snakeName}(&mut self, node: &mut ${typeName}, ctx: &TraverseCtx<'a>) {}
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
use oxc_allocator::Vec;
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use oxc_ast::ast::*;
|
||||
|
||||
use crate::TraverseCtx;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub trait Traverse<'a> {
|
||||
${traverseMethods}
|
||||
|
||||
#[inline]
|
||||
fn enter_statements(&mut self, node: &mut Vec<'a, Statement<'a>>, ctx: &TraverseCtx<'a>) {}
|
||||
#[inline]
|
||||
fn exit_statements(&mut self, node: &mut Vec<'a, Statement<'a>>, ctx: &TraverseCtx<'a>) {}
|
||||
}
|
||||
`;
|
||||
}
|
||||
40
crates/oxc_traverse/scripts/lib/utils.mjs
Normal file
40
crates/oxc_traverse/scripts/lib/utils.mjs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
export function typeAndWrappers(name) {
|
||||
const wrappers = [];
|
||||
while (true) {
|
||||
const match = name.match(/^(.+?)<(.+)>$/);
|
||||
if (!match) break;
|
||||
wrappers.push(match[1]);
|
||||
name = match[2];
|
||||
}
|
||||
return {name, wrappers};
|
||||
}
|
||||
|
||||
export function toTypeName(type) {
|
||||
let ty = type.name;
|
||||
if (type.hasLifetime) ty += "<'a>";
|
||||
return ty;
|
||||
}
|
||||
|
||||
export function camelToSnake(name) {
|
||||
let prefixLen = 1;
|
||||
for (const prefix of ['TS', 'JSX', 'JS']) {
|
||||
if (name.startsWith(prefix)) {
|
||||
prefixLen = prefix.length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return name.slice(0, prefixLen).toLowerCase()
|
||||
+ name.slice(prefixLen).replace(/[A-Z]/g, c => `_${c.toLowerCase()}`);
|
||||
}
|
||||
|
||||
export function snakeToCamel(name) {
|
||||
let prefixLen = 0;
|
||||
for (const prefix of ['TS', 'JSX', 'JS']) {
|
||||
if (name.startsWith(`${prefix.toLowerCase()}_`)) {
|
||||
prefixLen = prefix.length + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return name.slice(0, prefixLen + 1).toUpperCase()
|
||||
+ name.slice(prefixLen + 1).replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
||||
}
|
||||
212
crates/oxc_traverse/scripts/lib/walk.mjs
Normal file
212
crates/oxc_traverse/scripts/lib/walk.mjs
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
import assert from 'assert';
|
||||
import {toTypeName, camelToSnake, snakeToCamel} from './utils.mjs';
|
||||
|
||||
export default function generateWalkFunctionsCode(types) {
|
||||
let walkMethods = '';
|
||||
for (const type of Object.values(types)) {
|
||||
if (type.kind === 'struct') {
|
||||
walkMethods += generateWalkForStruct(type, types);
|
||||
} else {
|
||||
walkMethods += generateWalkForEnum(type, types);
|
||||
}
|
||||
}
|
||||
|
||||
return `
|
||||
#![allow(
|
||||
unsafe_code,
|
||||
clippy::missing_safety_doc,
|
||||
clippy::missing_panics_doc,
|
||||
clippy::undocumented_unsafe_blocks,
|
||||
clippy::semicolon_if_nothing_returned,
|
||||
clippy::ptr_as_ptr,
|
||||
clippy::borrow_as_ptr,
|
||||
clippy::cast_ptr_alignment
|
||||
)]
|
||||
|
||||
use oxc_allocator::Vec;
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use oxc_ast::ast::*;
|
||||
|
||||
use crate::{ancestor, Ancestor, Traverse, TraverseCtx};
|
||||
|
||||
${walkMethods}
|
||||
|
||||
pub(crate) unsafe fn walk_statements<'a, Tr: Traverse<'a>>(
|
||||
traverser: &mut Tr,
|
||||
stmts: *mut Vec<'a, Statement<'a>>,
|
||||
ctx: &mut TraverseCtx<'a>
|
||||
) {
|
||||
traverser.enter_statements(&mut *stmts, ctx);
|
||||
for stmt in (*stmts).iter_mut() {
|
||||
walk_statement(traverser, stmt, ctx);
|
||||
}
|
||||
traverser.exit_statements(&mut *stmts, ctx);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
function generateWalkForStruct(type, types) {
|
||||
const visitedFields = type.fields.filter(field => field.innerTypeName in types);
|
||||
|
||||
const fieldsCodes = visitedFields.map((field, index) => {
|
||||
const fieldWalkName = `walk_${camelToSnake(field.innerTypeName)}`;
|
||||
|
||||
const retagCode = index === 0 ? '' : `ctx.retag_stack(${field.ancestorDiscriminant});`,
|
||||
fieldCode = `(node as *mut u8).add(ancestor::${field.offsetVarName}) as *mut ${field.typeName}`;
|
||||
|
||||
if (field.wrappers[0] === 'Option') {
|
||||
let walkCode;
|
||||
if (field.wrappers.length === 2 && field.wrappers[1] === 'Vec') {
|
||||
if (field.typeNameInner === 'Statement') {
|
||||
// Special case for `Option<Vec<Statement>>`
|
||||
walkCode = `walk_statements(traverser, field as *mut _, ctx);`;
|
||||
} else {
|
||||
walkCode = `
|
||||
for item in field.iter_mut() {
|
||||
${fieldWalkName}(traverser, item as *mut _, ctx);
|
||||
}
|
||||
`.trim();
|
||||
}
|
||||
} else if (field.wrappers.length === 2 && field.wrappers[1] === 'Box') {
|
||||
walkCode = `${fieldWalkName}(traverser, (&mut **field) as *mut _, ctx);`;
|
||||
} else {
|
||||
assert(field.wrappers.length === 1, `Cannot handle struct field with type ${field.typeName}`);
|
||||
walkCode = `${fieldWalkName}(traverser, field as *mut _, ctx);`;
|
||||
}
|
||||
|
||||
return `
|
||||
if let Some(field) = &mut *(${fieldCode}) {
|
||||
${retagCode}
|
||||
${walkCode}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
if (field.wrappers[0] === 'Vec') {
|
||||
let walkVecCode;
|
||||
if (field.wrappers.length === 1 && field.innerTypeName === 'Statement') {
|
||||
// Special case for `Vec<Statement>`
|
||||
walkVecCode = `walk_statements(traverser, ${fieldCode}, ctx);`
|
||||
} else {
|
||||
let walkCode = `${fieldWalkName}(traverser, item as *mut _, ctx);`,
|
||||
iterModifier = '';
|
||||
if (field.wrappers.length === 2 && field.wrappers[1] === 'Option') {
|
||||
iterModifier = '.flatten()';
|
||||
} else {
|
||||
assert(
|
||||
field.wrappers.length === 1,
|
||||
`Cannot handle struct field with type ${field.type}`
|
||||
);
|
||||
}
|
||||
walkVecCode = `
|
||||
for item in (*(${fieldCode})).iter_mut()${iterModifier} {
|
||||
${walkCode}
|
||||
}
|
||||
`.trim();
|
||||
}
|
||||
|
||||
return `
|
||||
${retagCode}
|
||||
${walkVecCode}
|
||||
`;
|
||||
}
|
||||
|
||||
if (field.wrappers.length === 1 && field.wrappers[0] === 'Box') {
|
||||
return `
|
||||
${retagCode}
|
||||
${fieldWalkName}(traverser, (&mut **(${fieldCode})) as *mut _, ctx);
|
||||
`;
|
||||
}
|
||||
|
||||
assert(field.wrappers.length === 0, `Cannot handle struct field with type: ${field.type}`);
|
||||
|
||||
return `
|
||||
${retagCode}
|
||||
${fieldWalkName}(traverser, ${fieldCode}, ctx);
|
||||
`;
|
||||
});
|
||||
|
||||
if (visitedFields.length > 0) {
|
||||
const field = visitedFields[0],
|
||||
fieldCamelName = snakeToCamel(field.name);
|
||||
fieldsCodes.unshift(`
|
||||
ctx.push_stack(
|
||||
Ancestor::${type.name}${fieldCamelName}(
|
||||
ancestor::${type.name}Without${fieldCamelName}(node)
|
||||
)
|
||||
);
|
||||
`);
|
||||
fieldsCodes.push('ctx.pop_stack();');
|
||||
}
|
||||
|
||||
const typeSnakeName = camelToSnake(type.name);
|
||||
return `
|
||||
pub(crate) unsafe fn walk_${typeSnakeName}<'a, Tr: Traverse<'a>>(
|
||||
traverser: &mut Tr,
|
||||
node: *mut ${toTypeName(type)},
|
||||
ctx: &mut TraverseCtx<'a>
|
||||
) {
|
||||
traverser.enter_${typeSnakeName}(&mut *node, ctx);
|
||||
${fieldsCodes.join('\n')}
|
||||
traverser.exit_${typeSnakeName}(&mut *node, ctx);
|
||||
}
|
||||
`.replace(/\n\s*\n+/g, '\n');
|
||||
}
|
||||
|
||||
function generateWalkForEnum(type, types) {
|
||||
const variantCodes = type.variants.map((variant) => {
|
||||
const variantType = types[variant.innerTypeName];
|
||||
assert(variantType, `Cannot handle enum variant with type: ${variant.type}`);
|
||||
|
||||
let nodeCode = 'node';
|
||||
if (variant.wrappers.length === 1 && variant.wrappers[0] === 'Box') {
|
||||
nodeCode = '(&mut **node)';
|
||||
} else {
|
||||
assert(variant.wrappers.length === 0, `Cannot handle enum variant with type: ${variant.type}`);
|
||||
}
|
||||
|
||||
return `${type.name}::${variant.name}(node) => `
|
||||
+ `walk_${camelToSnake(variant.innerTypeName)}(traverser, ${nodeCode} as *mut _, ctx),`;
|
||||
});
|
||||
|
||||
const missingVariants = [];
|
||||
for (const inheritedTypeName of type.inherits) {
|
||||
// Recurse into nested inherited types
|
||||
const variantMatches = [],
|
||||
inheritedFrom = [inheritedTypeName];
|
||||
for (let i = 0; i < inheritedFrom.length; i++) {
|
||||
const inheritedTypeName = inheritedFrom[i],
|
||||
inheritedType = types[inheritedTypeName];
|
||||
if (!inheritedType || inheritedType.kind !== 'enum') {
|
||||
missingVariants.push(inheritedTypeName);
|
||||
} else {
|
||||
variantMatches.push(...inheritedType.variants.map(
|
||||
variant => `${type.name}::${variant.name}(_)`
|
||||
));
|
||||
inheritedFrom.push(...inheritedType.inherits);
|
||||
}
|
||||
}
|
||||
|
||||
variantCodes.push(
|
||||
`${variantMatches.join(' | ')} => `
|
||||
+ `walk_${camelToSnake(inheritedTypeName)}(traverser, node as *mut _, ctx),`
|
||||
);
|
||||
}
|
||||
|
||||
assert(missingVariants.length === 0, `Missing enum variants: ${missingVariants.join(', ')}`);
|
||||
|
||||
const typeSnakeName = camelToSnake(type.name);
|
||||
return `
|
||||
pub(crate) unsafe fn walk_${typeSnakeName}<'a, Tr: Traverse<'a>>(
|
||||
traverser: &mut Tr,
|
||||
node: *mut ${toTypeName(type)},
|
||||
ctx: &mut TraverseCtx<'a>
|
||||
) {
|
||||
traverser.enter_${typeSnakeName}(&mut *node, ctx);
|
||||
match &mut *node {
|
||||
${variantCodes.join('\n')}
|
||||
}
|
||||
traverser.exit_${typeSnakeName}(&mut *node, ctx);
|
||||
}
|
||||
`;
|
||||
}
|
||||
5
crates/oxc_traverse/scripts/package.json
Normal file
5
crates/oxc_traverse/scripts/package.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "oxc_ast_scripts",
|
||||
"version": "0.0.0",
|
||||
"type": "module"
|
||||
}
|
||||
10943
crates/oxc_traverse/src/ancestor.rs
Normal file
10943
crates/oxc_traverse/src/ancestor.rs
Normal file
File diff suppressed because it is too large
Load diff
143
crates/oxc_traverse/src/context.rs
Normal file
143
crates/oxc_traverse/src/context.rs
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
use oxc_allocator::{Allocator, Box};
|
||||
use oxc_ast::AstBuilder;
|
||||
|
||||
use crate::ancestor::{Ancestor, AncestorDiscriminant};
|
||||
|
||||
const INITIAL_STACK_CAPACITY: usize = 64;
|
||||
|
||||
/// Traverse context.
|
||||
///
|
||||
/// Passed to all AST visitor functions.
|
||||
///
|
||||
/// Provides ability to:
|
||||
/// * Query parent/ancestor of current node via [`parent`], [`ancestor`], [`find_ancestor`].
|
||||
/// * Create AST nodes via AST builder [`ast`].
|
||||
/// * Allocate into arena via [`alloc`].
|
||||
///
|
||||
/// [`parent`]: `TraverseCtx::parent`
|
||||
/// [`ancestor`]: `TraverseCtx::ancestor`
|
||||
/// [`find_ancestor`]: `TraverseCtx::find_ancestor`
|
||||
/// [`ast`]: `TraverseCtx::ast`
|
||||
/// [`alloc`]: `TraverseCtx::alloc`
|
||||
pub struct TraverseCtx<'a> {
|
||||
stack: Vec<Ancestor<'a>>,
|
||||
pub ast: AstBuilder<'a>,
|
||||
}
|
||||
|
||||
/// Return value when using [`TraverseCtx::find_ancestor`].
|
||||
pub enum FinderRet<T> {
|
||||
Found(T),
|
||||
Stop,
|
||||
Continue,
|
||||
}
|
||||
|
||||
// Public methods
|
||||
impl<'a> TraverseCtx<'a> {
|
||||
/// Create new traversal context.
|
||||
pub fn new(allocator: &'a Allocator) -> Self {
|
||||
let mut stack = Vec::with_capacity(INITIAL_STACK_CAPACITY);
|
||||
stack.push(Ancestor::None);
|
||||
Self { stack, ast: AstBuilder::new(allocator) }
|
||||
}
|
||||
|
||||
/// Allocate a node in the arena.
|
||||
/// Returns a [`Box<T>`].
|
||||
#[inline]
|
||||
pub fn alloc<T>(&self, node: T) -> Box<'a, T> {
|
||||
self.ast.alloc(node)
|
||||
}
|
||||
|
||||
/// Get parent of current node.
|
||||
#[inline]
|
||||
#[allow(unsafe_code)]
|
||||
pub fn parent(&self) -> &Ancestor<'a> {
|
||||
// SAFETY: Stack contains 1 entry initially. Entries are pushed as traverse down the AST,
|
||||
// and popped as go back up. So even when visiting `Program`, the initial entry is in the stack.
|
||||
unsafe { self.stack.last().unwrap_unchecked() }
|
||||
}
|
||||
|
||||
/// Get ancestor of current node.
|
||||
/// `level` is number of levels above.
|
||||
/// `ancestor(1).unwrap()` is equivalent to `parent()`.
|
||||
#[inline]
|
||||
pub fn ancestor(&self, level: usize) -> Option<&Ancestor<'a>> {
|
||||
self.stack.get(self.stack.len() - level)
|
||||
}
|
||||
|
||||
/// Walk up trail of ancestors to find a node.
|
||||
///
|
||||
/// `finder` should return:
|
||||
/// * `FinderRet::Found(value)` to stop walking and return `Some(value)`.
|
||||
/// * `FinderRet::Stop` to stop walking and return `None`.
|
||||
/// * `FinderRet::Continue` to continue walking up.
|
||||
pub fn find_ancestor<F, O>(&self, finder: F) -> Option<O>
|
||||
where
|
||||
F: Fn(&Ancestor<'a>) -> FinderRet<O>,
|
||||
{
|
||||
for ancestor in self.stack.iter().rev() {
|
||||
match finder(ancestor) {
|
||||
FinderRet::Found(res) => return Some(res),
|
||||
FinderRet::Stop => return None,
|
||||
FinderRet::Continue => {}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Get depth of ancestry stack.
|
||||
/// i.e. How many nodes above this one in the tree.
|
||||
///
|
||||
/// NB: A "no parent" ancestor above `Program` counts towards this total.
|
||||
/// The current node does not.
|
||||
#[inline]
|
||||
pub fn ancestors_depth(&self) -> usize {
|
||||
self.stack.len()
|
||||
}
|
||||
}
|
||||
|
||||
// Methods used internally within crate
|
||||
impl<'a> TraverseCtx<'a> {
|
||||
/// Push item onto stack.
|
||||
#[inline]
|
||||
pub(crate) fn push_stack(&mut self, ancestor: Ancestor<'a>) {
|
||||
self.stack.push(ancestor);
|
||||
}
|
||||
|
||||
/// Pop last item off stack.
|
||||
/// # SAFETY
|
||||
/// * Stack must not be empty.
|
||||
/// * Each `pop_stack` call must correspond to a `push_stack` call for same type.
|
||||
#[inline]
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) unsafe fn pop_stack(&mut self) {
|
||||
self.stack.pop().unwrap_unchecked();
|
||||
}
|
||||
|
||||
/// Retag last item on stack.
|
||||
///
|
||||
/// i.e. Alter discriminant of `Ancestor` enum, without changing the "payload" it contains
|
||||
/// of pointer to the ancestor node.
|
||||
///
|
||||
/// This is purely a performance optimization. If the last item on stack already contains the
|
||||
/// correct pointer, then `ctx.retag_stack(3)` is equivalent to:
|
||||
///
|
||||
/// ```nocompile
|
||||
/// ctx.pop_stack();
|
||||
/// ctx.push_stack(Ancestor::ProgramBody(ProgramWithoutBody(node_ptr)));
|
||||
/// ```
|
||||
///
|
||||
/// (3 is the discriminant for `Ancestor::ProgramBody`)
|
||||
///
|
||||
/// `retag_stack` is only a single 2-byte write operation.
|
||||
///
|
||||
/// # SAFETY
|
||||
/// * Stack must not be empty.
|
||||
/// * `discriminant` must be valid discriminant value for `Ancestor` enum.
|
||||
/// * Last item on stack must contain pointer to type corresponding to provided discriminant.
|
||||
#[inline]
|
||||
#[allow(unsafe_code, clippy::ptr_as_ptr, clippy::ref_as_ptr)]
|
||||
pub(crate) unsafe fn retag_stack(&mut self, discriminant: AncestorDiscriminant) {
|
||||
*(self.stack.last_mut().unwrap_unchecked() as *mut _ as *mut AncestorDiscriminant) =
|
||||
discriminant;
|
||||
}
|
||||
}
|
||||
149
crates/oxc_traverse/src/lib.rs
Normal file
149
crates/oxc_traverse/src/lib.rs
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
//! AST traversal with ability to read up the tree from visitors.
|
||||
//!
|
||||
//! Please see [`traverse_mut`] for an explanation of API.
|
||||
//!
|
||||
//! # Implementation details
|
||||
//!
|
||||
//! Most of the code in this crate is generated by a codegen.
|
||||
//! Codegen is currently written in JavaScript (`scripts/build.mjs`).
|
||||
//!
|
||||
//! Do not edit those files, as they'll be over-written by the build script on next run.
|
||||
//!
|
||||
//! The scheme which allows reading up the tree is based on making it statically impossible
|
||||
//! to violate Rust's aliasing rules.
|
||||
//!
|
||||
//! Rust's aliasing rules are (roughly):
|
||||
//! 1. For any object, you can have as many immutable `&` references simultaneously as you like.
|
||||
//! 2. For any object, you cannot obtain a mutable `&mut` reference if any other references
|
||||
//! (immutable or mutable) to that same object exist.
|
||||
//! 3. A `&`/`&mut` ref covers the object itself and the entire tree below it.
|
||||
//! i.e. you can't hold a `&mut` to child and any reference to parent at same time (except by
|
||||
//! "re-borrowing").
|
||||
//!
|
||||
//! This poses a problem for reading back up the tree in a mutating visitor.
|
||||
//! In a visitor you hold a `&mut` reference to a node, so therefore cannot obtain a `&` ref to
|
||||
//! its parent, because the parent owns the node. If you had a `&` ref to the parent, that also acts
|
||||
//! as a `&` ref to the current node = holding `&` and `&mut` refs to same node simultaneously.
|
||||
//! Disaster!
|
||||
//!
|
||||
//! The solution this crate uses is:
|
||||
//! 1. Don't create references while traversing down the AST in `walk_*` functions.
|
||||
//! Use raw pointers instead. `&mut` references are only created in the `enter_*` / `exit_*` methods.
|
||||
//! 2. Don't allow `enter_*` / `exit_*` to access its entire parent or ancestor, only *other branches*
|
||||
//! of the tree which lead from the parent/ancestor. The parts of the tree above current node
|
||||
//! which can be accessed via `ctx.parent()` etc **do not overlap** the part of the tree which
|
||||
//! is available via `&mut` ref inside `enter_*` / `exit_*`. This makes it impossible to obtain
|
||||
//! 2 references to same AST node at same time.
|
||||
//! 3. Again, don't create transient references while getting the fields of ancestors. Use raw pointers
|
||||
//! to go to the field directly, before creating a `&` ref.
|
||||
//!
|
||||
//! The mechanism for this is the `Ancestor` enum. Each AST node type has several `Ancestor` variants
|
||||
//! e.g. `ProgramWithoutDirectives`, `ProgramWithoutHashbang`, `ProgramWithoutBody`.
|
||||
//! As the names suggest, each of these types grants access to all the fields of `Program` except one.
|
||||
//!
|
||||
//! As `walk_*` functions walk down the tree, they add to the stack of `Ancestors` the appropriate type
|
||||
//! to prevent access to the path which is being walked down.
|
||||
//!
|
||||
//! `walk_*` uses `TraverseCtx::retag_stack` to make it as cheap as possible to update the ancestry
|
||||
//! stack, but this is purely a performance optimization, not essential to the safety of the scheme.
|
||||
//!
|
||||
//! # SAFETY
|
||||
//! This crate contains a great deal of unsafe code. The entirety of `walk.rs` is unsafe functions
|
||||
//! using raw pointers.
|
||||
//!
|
||||
//! To avoid a drain on compile time asking Rust to parse 1000s of `# SAFETY` comments, the codegen-ed
|
||||
//! files do not contain comments explaining the safety of every unsafe operation.
|
||||
//! But everything works according to the principles outlined above.
|
||||
//!
|
||||
//! Almost all the code is currently codegen-ed. I (@overlookmotel) would recommend continuing to
|
||||
//! exclusively use a codegen, and not manually editing these files for "special cases". The safety
|
||||
//! scheme could very easily be derailed entirely by a single mistake, so in my opinion, it's unwise
|
||||
//! to edit by hand.
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
|
||||
use oxc_ast::ast::Program;
|
||||
|
||||
pub mod ancestor;
|
||||
pub use ancestor::Ancestor;
|
||||
mod context;
|
||||
pub use context::{FinderRet, TraverseCtx};
|
||||
#[allow(clippy::module_inception)]
|
||||
mod traverse;
|
||||
pub use traverse::Traverse;
|
||||
mod walk;
|
||||
|
||||
/// Traverse AST with a [`Traverse`] impl.
|
||||
///
|
||||
/// This allows:
|
||||
/// 1. Reading and mutating down the tree (i.e. children, children's children, ...)
|
||||
/// 2. Reading up the tree (i.e. parent, grandparent, ...)
|
||||
///
|
||||
/// `traverser`'s `enter_*` and `exit_*` methods will be called with a `&mut` ref to current AST node
|
||||
/// and a [`TraverseCtx`] object.
|
||||
///
|
||||
/// [`TraverseCtx`] can be used to access parent or ancestors further up the tree.
|
||||
/// [`TraverseCtx::parent`] and [`TraverseCtx::ancestor`] return an [`Ancestor`] type.
|
||||
///
|
||||
/// [`Ancestor`] is an enum, whose discriminant encodes both the *type* of the parent,
|
||||
/// and *location* of the child within the parent.
|
||||
/// e.g. `Ancestor` has variants for `BinaryExpressionLeft` and `BinaryExpressionRight`,
|
||||
/// not just `BinaryExpression`.
|
||||
///
|
||||
/// To avoid violating Rust's aliasing rules, you cannot access the property of the parent
|
||||
/// which current node is the child of.
|
||||
///
|
||||
/// Or, to state the rule more generally: You can read from any branch of the AST *except*
|
||||
/// the one you are on.
|
||||
///
|
||||
/// A silly analogy: You are a tree surgeon working on pruning an old oak tree. You are sitting
|
||||
/// on a branch high up in the tree. From that position, you can cut off other branches of the tree
|
||||
/// no problem, but it would be unwise to saw off the branch that you are sitting on.
|
||||
///
|
||||
/// In practice: For this JS code:
|
||||
///
|
||||
/// ```js
|
||||
/// x == 1
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use oxc_ast::ast::*;
|
||||
/// use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
|
||||
///
|
||||
/// struct MyTransform;
|
||||
///
|
||||
/// impl<'a> Traverse<'a> for MyTransform {
|
||||
/// fn enter_numeric_literal(&mut self, node: &mut NumericLiteral<'a>, ctx: &TraverseCtx<'a>) {
|
||||
/// // Read parent
|
||||
/// if let Ancestor::BinaryExpressionRight(bin_expr_ref) = ctx.parent() {
|
||||
/// // This is legal
|
||||
/// if let Expression::Identifier(id) = bin_expr_ref.left() {
|
||||
/// println!("left side is ID: {}", &id.name);
|
||||
/// }
|
||||
///
|
||||
/// // This would be a compile failure, because the right side is where we came from
|
||||
/// // dbg!(bin_expr_ref.right());
|
||||
/// }
|
||||
///
|
||||
/// // Read grandparent
|
||||
/// if let Some(Ancestor::ExpressionStatementExpression(stmt_ref)) = ctx.ancestor(2) {
|
||||
/// // This is legal
|
||||
/// println!("expression stmt's span: {:?}", stmt_ref.span());
|
||||
///
|
||||
/// // This would be a compile failure, because the expression is where we came from
|
||||
/// // dbg!(stmt_ref.expression());
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[allow(unsafe_code)]
|
||||
pub fn traverse_mut<'a, Tr: Traverse<'a>>(
|
||||
traverser: &mut Tr,
|
||||
program: &mut Program<'a>,
|
||||
allocator: &'a Allocator,
|
||||
) {
|
||||
let mut ctx = TraverseCtx::new(allocator);
|
||||
// SAFETY: Walk functions are constructed to avoid unsoundness
|
||||
unsafe { walk::walk_program(traverser, program as *mut Program, &mut ctx) };
|
||||
debug_assert!(ctx.ancestors_depth() == 1);
|
||||
}
|
||||
1993
crates/oxc_traverse/src/traverse.rs
Normal file
1993
crates/oxc_traverse/src/traverse.rs
Normal file
File diff suppressed because it is too large
Load diff
5302
crates/oxc_traverse/src/walk.rs
Normal file
5302
crates/oxc_traverse/src/walk.rs
Normal file
File diff suppressed because it is too large
Load diff
5
crates/oxc_traverse/tests/compile_fail.rs
Normal file
5
crates/oxc_traverse/tests/compile_fail.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#[test]
|
||||
fn compile_fail() {
|
||||
let t = trybuild::TestCases::new();
|
||||
t.compile_fail("tests/compile_fail/*.rs");
|
||||
}
|
||||
18
crates/oxc_traverse/tests/compile_fail/ancestor_lifetime1.rs
Normal file
18
crates/oxc_traverse/tests/compile_fail/ancestor_lifetime1.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
use oxc_ast::ast::IdentifierReference;
|
||||
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
|
||||
|
||||
struct Trans<'a, 'b> {
|
||||
ancestor: Option<&'b Ancestor<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
fn enter_identifier_reference(
|
||||
&mut self,
|
||||
_node: &mut IdentifierReference<'a>,
|
||||
ctx: &TraverseCtx<'a>,
|
||||
) {
|
||||
self.ancestor = Some(ctx.parent());
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
error: lifetime may not live long enough
|
||||
--> tests/compile_fail/ancestor_lifetime1.rs:14:9
|
||||
|
|
||||
8 | impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
| -- lifetime `'b` defined here
|
||||
...
|
||||
12 | ctx: &TraverseCtx<'a>,
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
13 | ) {
|
||||
14 | self.ancestor = Some(ctx.parent());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'b`
|
||||
20
crates/oxc_traverse/tests/compile_fail/ancestor_lifetime2.rs
Normal file
20
crates/oxc_traverse/tests/compile_fail/ancestor_lifetime2.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
use oxc_ast::ast::IdentifierReference;
|
||||
use oxc_traverse::{ancestor::ProgramWithoutDirectives, Ancestor, Traverse, TraverseCtx};
|
||||
|
||||
struct Trans<'a, 'b> {
|
||||
program: Option<&'b ProgramWithoutDirectives<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
fn enter_identifier_reference(
|
||||
&mut self,
|
||||
_node: &mut IdentifierReference<'a>,
|
||||
ctx: &TraverseCtx<'a>,
|
||||
) {
|
||||
if let Ancestor::ProgramDirectives(program) = ctx.parent() {
|
||||
self.program = Some(program);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
error: lifetime may not live long enough
|
||||
--> tests/compile_fail/ancestor_lifetime2.rs:15:13
|
||||
|
|
||||
8 | impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
| -- lifetime `'b` defined here
|
||||
...
|
||||
12 | ctx: &TraverseCtx<'a>,
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
...
|
||||
15 | self.program = Some(program);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'b`
|
||||
21
crates/oxc_traverse/tests/compile_fail/ancestor_lifetime3.rs
Normal file
21
crates/oxc_traverse/tests/compile_fail/ancestor_lifetime3.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
use oxc_allocator::Vec;
|
||||
use oxc_ast::ast::{IdentifierReference, Statement};
|
||||
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
|
||||
|
||||
struct Trans<'a, 'b> {
|
||||
program_body: Option<&'b Vec<'a, Statement<'a>>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
fn enter_identifier_reference(
|
||||
&mut self,
|
||||
_node: &mut IdentifierReference<'a>,
|
||||
ctx: &TraverseCtx<'a>,
|
||||
) {
|
||||
if let Ancestor::ProgramDirectives(program) = ctx.parent() {
|
||||
self.program_body = Some(program.body());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
error: lifetime may not live long enough
|
||||
--> tests/compile_fail/ancestor_lifetime3.rs:16:13
|
||||
|
|
||||
9 | impl<'a, 'b> Traverse<'a> for Trans<'a, 'b> {
|
||||
| -- lifetime `'b` defined here
|
||||
...
|
||||
13 | ctx: &TraverseCtx<'a>,
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
...
|
||||
16 | self.program_body = Some(program.body());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'b`
|
||||
Loading…
Reference in a new issue