Skip to content

Commit ebb80b3

Browse files
committed
feat(ast): add node_id field to all AST struct nodes (#18138)
## Summary - Add `pub node_id: NodeId` as the first field in all AST structs (~190 structs across js.rs, ts.rs, jsx.rs, literal.rs) - Update codegen to special-case `node_id`: - `Dummy`: Use `NodeId::DUMMY` instead of `Dummy::dummy(allocator)` - `CloneIn`: Use `NodeId::DUMMY` for regular clone, preserve ID for semantic clone - `ContentEq`: Skip `node_id` from equality comparisons - `ESTree`: Skip `node_id` from serialization - `AstBuilder`: Exclude `node_id` from builder parameters, use `NodeId::DUMMY` - Update pattern matching in minifier and transformer to use `..` for new field - Update traverse script to include `NodeId` import This is the foundational step for assigning unique IDs to AST nodes. The `node_id` defaults to `NodeId::DUMMY` (value 0) for uninitialized nodes. ## Test plan - [x] `cargo build` succeeds - [x] `cargo test` passes - [x] `just ast` regenerates code correctly 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent 7d19c65 commit ebb80b3

File tree

54 files changed

+13133
-2994
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+13133
-2994
lines changed

apps/oxlint/src-js/generated/deserialize.js

Lines changed: 137 additions & 130 deletions
Large diffs are not rendered by default.

crates/oxc_ast/src/ast/js.rs

Lines changed: 95 additions & 3 deletions
Large diffs are not rendered by default.

crates/oxc_ast/src/ast/jsx.rs

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
// They are purely markers for codegen used in `tasks/ast_tools`. See docs in that crate.
55
// Read [`macro@oxc_ast_macros::ast`] for more information.
66

7+
use std::cell::Cell;
8+
79
use oxc_allocator::{Box, CloneIn, Dummy, GetAddress, TakeIn, UnstableAddress, Vec};
810
use oxc_ast_macros::ast;
911
use oxc_estree::ESTree;
1012
use oxc_span::{Atom, ContentEq, GetSpan, GetSpanMut, Span};
13+
use oxc_syntax::node::NodeId;
1114

1215
use super::{inherit_variants, js::*, literal::*, ts::*};
1316

@@ -34,7 +37,9 @@ use super::{inherit_variants, js::*, literal::*, ts::*};
3437
#[derive(Debug)]
3538
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
3639
pub struct JSXElement<'a> {
37-
/// Node location in source code
40+
/// Unique identifier for this AST node.
41+
pub node_id: Cell<NodeId>,
42+
/// Node location in source code.
3843
pub span: Span,
3944
/// Opening tag of the element.
4045
#[estree(via = JSXElementOpeningElement)]
@@ -67,7 +72,9 @@ pub struct JSXElement<'a> {
6772
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
6873
#[estree(add_fields(selfClosing = JSXOpeningElementSelfClosing))]
6974
pub struct JSXOpeningElement<'a> {
70-
/// Node location in source code
75+
/// Unique identifier for this AST node.
76+
pub node_id: Cell<NodeId>,
77+
/// Node location in source code.
7178
pub span: Span,
7279
/// The possibly-namespaced tag name, e.g. `Foo` in `<Foo />`.
7380
pub name: JSXElementName<'a>,
@@ -93,7 +100,9 @@ pub struct JSXOpeningElement<'a> {
93100
#[derive(Debug)]
94101
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
95102
pub struct JSXClosingElement<'a> {
96-
/// Node location in source code
103+
/// Unique identifier for this AST node.
104+
pub node_id: Cell<NodeId>,
105+
/// Node location in source code.
97106
pub span: Span,
98107
/// The tag name, e.g. `Foo` in `</Foo>`.
99108
pub name: JSXElementName<'a>,
@@ -111,7 +120,9 @@ pub struct JSXClosingElement<'a> {
111120
#[derive(Debug)]
112121
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
113122
pub struct JSXFragment<'a> {
114-
/// Node location in source code
123+
/// Unique identifier for this AST node.
124+
pub node_id: Cell<NodeId>,
125+
/// Node location in source code.
115126
pub span: Span,
116127
/// `<>`
117128
pub opening_fragment: JSXOpeningFragment,
@@ -127,7 +138,9 @@ pub struct JSXFragment<'a> {
127138
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
128139
#[estree(add_fields(attributes = JsEmptyArray, selfClosing = JsFalse))]
129140
pub struct JSXOpeningFragment {
130-
/// Node location in source code
141+
/// Unique identifier for this AST node.
142+
pub node_id: Cell<NodeId>,
143+
/// Node location in source code.
131144
pub span: Span,
132145
}
133146

@@ -136,7 +149,9 @@ pub struct JSXOpeningFragment {
136149
#[derive(Debug)]
137150
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
138151
pub struct JSXClosingFragment {
139-
/// Node location in source code
152+
/// Unique identifier for this AST node.
153+
pub node_id: Cell<NodeId>,
154+
/// Node location in source code.
140155
pub span: Span,
141156
}
142157

@@ -170,7 +185,9 @@ pub enum JSXElementName<'a> {
170185
#[derive(Debug)]
171186
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
172187
pub struct JSXNamespacedName<'a> {
173-
/// Node location in source code
188+
/// Unique identifier for this AST node.
189+
pub node_id: Cell<NodeId>,
190+
/// Node location in source code.
174191
pub span: Span,
175192
/// Namespace portion of the name, e.g. `Apple` in `<Apple:Orange />`
176193
pub namespace: JSXIdentifier<'a>,
@@ -197,7 +214,9 @@ pub struct JSXNamespacedName<'a> {
197214
#[derive(Debug)]
198215
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
199216
pub struct JSXMemberExpression<'a> {
200-
/// Node location in source code
217+
/// Unique identifier for this AST node.
218+
pub node_id: Cell<NodeId>,
219+
/// Node location in source code.
201220
pub span: Span,
202221
/// The object being accessed. This is everything before the last `.`.
203222
pub object: JSXMemberExpressionObject<'a>,
@@ -252,7 +271,9 @@ pub enum JSXMemberExpressionObject<'a> {
252271
#[derive(Debug)]
253272
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
254273
pub struct JSXExpressionContainer<'a> {
255-
/// Node location in source code
274+
/// Unique identifier for this AST node.
275+
pub node_id: Cell<NodeId>,
276+
/// Node location in source code.
256277
pub span: Span,
257278
/// The expression inside the container.
258279
pub expression: JSXExpression<'a>,
@@ -287,7 +308,9 @@ pub enum JSXExpression<'a> {
287308
#[derive(Debug)]
288309
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
289310
pub struct JSXEmptyExpression {
290-
/// Node location in source code
311+
/// Unique identifier for this AST node.
312+
pub node_id: Cell<NodeId>,
313+
/// Node location in source code.
291314
pub span: Span,
292315
}
293316

@@ -327,7 +350,9 @@ pub enum JSXAttributeItem<'a> {
327350
#[derive(Debug)]
328351
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
329352
pub struct JSXAttribute<'a> {
330-
/// Node location in source code
353+
/// Unique identifier for this AST node.
354+
pub node_id: Cell<NodeId>,
355+
/// Node location in source code.
331356
pub span: Span,
332357
/// The name of the attribute. This is a prop in React-like applications.
333358
pub name: JSXAttributeName<'a>,
@@ -348,7 +373,9 @@ pub struct JSXAttribute<'a> {
348373
#[derive(Debug)]
349374
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
350375
pub struct JSXSpreadAttribute<'a> {
351-
/// Node location in source code
376+
/// Unique identifier for this AST node.
377+
pub node_id: Cell<NodeId>,
378+
/// Node location in source code.
352379
pub span: Span,
353380
/// The expression being spread.
354381
pub argument: Expression<'a>,
@@ -420,7 +447,9 @@ pub enum JSXAttributeValue<'a> {
420447
#[derive(Debug)]
421448
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
422449
pub struct JSXIdentifier<'a> {
423-
/// Node location in source code
450+
/// Unique identifier for this AST node.
451+
pub node_id: Cell<NodeId>,
452+
/// Node location in source code.
424453
pub span: Span,
425454
/// The name of the identifier.
426455
#[estree(json_safe)]
@@ -455,7 +484,9 @@ pub enum JSXChild<'a> {
455484
#[derive(Debug)]
456485
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
457486
pub struct JSXSpreadChild<'a> {
458-
/// Node location in source code
487+
/// Unique identifier for this AST node.
488+
pub node_id: Cell<NodeId>,
489+
/// Node location in source code.
459490
pub span: Span,
460491
/// The expression being spread.
461492
pub expression: Expression<'a>,
@@ -475,7 +506,9 @@ pub struct JSXSpreadChild<'a> {
475506
#[derive(Debug)]
476507
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
477508
pub struct JSXText<'a> {
478-
/// Node location in source code
509+
/// Unique identifier for this AST node.
510+
pub node_id: Cell<NodeId>,
511+
/// Node location in source code.
479512
pub span: Span,
480513
/// The text content.
481514
pub value: Atom<'a>,

crates/oxc_ast/src/ast/literal.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@
44
// They are purely markers for codegen used in `tasks/ast_tools`. See docs in that crate.
55
// Read [`macro@oxc_ast_macros::ast`] for more information.
66

7-
use std::hash::Hash;
7+
use std::{cell::Cell, hash::Hash};
88

99
use bitflags::bitflags;
1010
use oxc_allocator::{Box, CloneIn, Dummy, TakeIn, UnstableAddress};
1111
use oxc_ast_macros::ast;
1212
use oxc_estree::ESTree;
1313
use oxc_regular_expression::ast::Pattern;
1414
use oxc_span::{Atom, ContentEq, GetSpan, GetSpanMut, Span};
15-
use oxc_syntax::number::{BigintBase, NumberBase};
15+
use oxc_syntax::{
16+
node::NodeId,
17+
number::{BigintBase, NumberBase},
18+
};
1619

1720
/// Boolean literal
1821
///
@@ -22,7 +25,9 @@ use oxc_syntax::number::{BigintBase, NumberBase};
2225
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
2326
#[estree(rename = "Literal", add_fields(raw = BooleanLiteralRaw))]
2427
pub struct BooleanLiteral {
25-
/// Node location in source code
28+
/// Unique identifier for this AST node.
29+
pub node_id: Cell<NodeId>,
30+
/// Node location in source code.
2631
pub span: Span,
2732
/// The boolean value itself
2833
pub value: bool,
@@ -36,7 +41,9 @@ pub struct BooleanLiteral {
3641
#[generate_derive(CloneIn, Dummy, TakeIn, GetSpan, GetSpanMut, ContentEq, ESTree, UnstableAddress)]
3742
#[estree(rename = "Literal", add_fields(value = Null, raw = NullLiteralRaw))]
3843
pub struct NullLiteral {
39-
/// Node location in source code
44+
/// Unique identifier for this AST node.
45+
pub node_id: Cell<NodeId>,
46+
/// Node location in source code.
4047
pub span: Span,
4148
}
4249

@@ -48,7 +55,9 @@ pub struct NullLiteral {
4855
#[generate_derive(CloneIn, Dummy, TakeIn, ContentEq, GetSpan, GetSpanMut, ESTree, UnstableAddress)]
4956
#[estree(rename = "Literal")]
5057
pub struct NumericLiteral<'a> {
51-
/// Node location in source code
58+
/// Unique identifier for this AST node.
59+
pub node_id: Cell<NodeId>,
60+
/// Node location in source code.
5261
pub span: Span,
5362
/// The value of the number, converted into base 10
5463
pub value: f64,
@@ -72,7 +81,9 @@ pub struct NumericLiteral<'a> {
7281
#[generate_derive(CloneIn, Dummy, TakeIn, ContentEq, GetSpan, GetSpanMut, ESTree, UnstableAddress)]
7382
#[estree(rename = "Literal")]
7483
pub struct StringLiteral<'a> {
75-
/// Node location in source code
84+
/// Unique identifier for this AST node.
85+
pub node_id: Cell<NodeId>,
86+
/// Node location in source code.
7687
pub span: Span,
7788
/// The value of the string.
7889
///
@@ -102,7 +113,9 @@ pub struct StringLiteral<'a> {
102113
#[generate_derive(CloneIn, Dummy, TakeIn, ContentEq, GetSpan, GetSpanMut, ESTree, UnstableAddress)]
103114
#[estree(rename = "Literal", add_fields(bigint = BigIntLiteralBigint))]
104115
pub struct BigIntLiteral<'a> {
105-
/// Node location in source code
116+
/// Unique identifier for this AST node.
117+
pub node_id: Cell<NodeId>,
118+
/// Node location in source code.
106119
pub span: Span,
107120
/// Bigint value in base 10 with no underscores
108121
#[estree(via = BigIntLiteralValue)]
@@ -129,7 +142,9 @@ pub struct BigIntLiteral<'a> {
129142
field_order(value, raw, regex, span),
130143
)]
131144
pub struct RegExpLiteral<'a> {
132-
/// Node location in source code
145+
/// Unique identifier for this AST node.
146+
pub node_id: Cell<NodeId>,
147+
/// Node location in source code.
133148
pub span: Span,
134149
/// The parsed regular expression. See [`oxc_regular_expression`] for more
135150
/// details.

0 commit comments

Comments
 (0)