Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
d65061e
feat: add loc and range fields
bacarybruno Jun 15, 2025
cb6fa21
chore: cleanup
bacarybruno Jun 15, 2025
2407a0c
chore: cleanup
bacarybruno Jun 15, 2025
b2ad337
Merge branch 'main' into oxc-10307-ast-loc-range
bacarybruno Jun 15, 2025
dbfc16c
Merge branch 'main' into oxc-10307-ast-loc-range
bacarybruno Jun 16, 2025
1e9a466
[autofix.ci] apply automated fixes
autofix-ci[bot] Jun 16, 2025
208bd1f
chore: remove loc
bacarybruno Jun 16, 2025
363ac7c
Merge branch 'main' into oxc-10307-ast-loc-range
bacarybruno Jun 16, 2025
4012c79
feat: move range configuration from serializer to config types
bacarybruno Jun 16, 2025
7663b54
chore: move to config
bacarybruno Jun 17, 2025
274a335
chore: range as array
bacarybruno Jun 17, 2025
d1ecb1c
chore: format
bacarybruno Jun 17, 2025
2a63d18
chore: start cleanup
bacarybruno Jun 17, 2025
f3a8837
chore: cleanup
bacarybruno Jun 18, 2025
1ecdbdf
chore: format
bacarybruno Jun 18, 2025
862db6c
feat: program range
bacarybruno Jun 18, 2025
7ebb757
chore: regerenrate
bacarybruno Jun 18, 2025
038d4aa
chore: 16 to 32
bacarybruno Jun 18, 2025
3b54cb1
chore: unnecessary wrapping
bacarybruno Jun 18, 2025
5d3177c
chore: unnecessary wrapping
bacarybruno Jun 18, 2025
307f59a
chore: last self review
bacarybruno Jun 18, 2025
1f1d625
chore: rename to range array
bacarybruno Jun 18, 2025
8bf2ce6
Merge branch 'main' into oxc-10307-ast-loc-range
bacarybruno Jun 18, 2025
ce553aa
Merge branch 'main' into oxc-10307-ast-loc-range
bacarybruno Jun 19, 2025
be74d9f
Merge branch 'main' into oxc-10307-ast-loc-range
bacarybruno Jun 20, 2025
92a5a52
chore: revert generated code
bacarybruno Jun 20, 2025
2657bba
chore: keep only parser and serializers options for now
bacarybruno Jun 20, 2025
84af829
feat: update serializer
bacarybruno Jun 20, 2025
3181b9d
chore: format
bacarybruno Jun 20, 2025
5d10c65
chore: remove unnecessary
bacarybruno Jun 20, 2025
fbeea43
chore: remove unnecessary custom serializerss updates
bacarybruno Jun 20, 2025
09daca0
chore: avoid multiplying the configs
bacarybruno Jun 20, 2025
fe16f2c
chore: fmt
bacarybruno Jun 20, 2025
26e67db
chore: try to simplify
bacarybruno Jun 20, 2025
1088610
chore: revert generated code
bacarybruno Jun 20, 2025
f168938
Merge branch 'main' into oxc-10307-ast-loc-range
bacarybruno Jun 20, 2025
ffb1396
Update generated code
overlookmotel Jun 24, 2025
8a37a12
Restore line break
overlookmotel Jun 24, 2025
4938016
Rename `range` to `ranges`
overlookmotel Jun 24, 2025
fc46eb8
Reformat `quote!` macro usage
overlookmotel Jun 24, 2025
461753c
Restore comment
overlookmotel Jun 24, 2025
8e7fa9c
`to_estree_js_json` etc take `ranges` param
overlookmotel Jun 24, 2025
336b7cf
`CompactJSSerializer` etc `new` and `with_capacity` take `ranges` option
overlookmotel Jun 24, 2025
c0a4687
`oxc_estree` do not expose `Config` trait and types
overlookmotel Jun 24, 2025
010c67e
Tweak comment
overlookmotel Jun 24, 2025
fb9be85
Regenerate NAPI parser types
overlookmotel Jun 24, 2025
333b6fe
`ESTreeStructSerializer` call parent serializer `ranges` method
overlookmotel Jun 24, 2025
afcb64f
Ignore TS errors in tests
overlookmotel Jun 24, 2025
b02d526
Fix test name
overlookmotel Jun 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/oxc_allocator/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ mod test {
let allocator = Allocator::default();
let b = Box::new_in("x", &allocator);

let mut serializer = CompactTSSerializer::new();
let mut serializer = CompactTSSerializer::new(false);
b.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(s, r#""x""#);
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_allocator/src/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ mod test {
let mut v = Vec::new_in(&allocator);
v.push("x");

let mut serializer = CompactTSSerializer::new();
let mut serializer = CompactTSSerializer::new(false);
v.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(s, r#"["x"]"#);
Expand Down
716 changes: 716 additions & 0 deletions crates/oxc_ast/src/generated/derive_estree.rs

Large diffs are not rendered by default.

36 changes: 20 additions & 16 deletions crates/oxc_ast/src/serialize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,62 +47,62 @@ const JSON_CAPACITY_RATIO_PRETTY: usize = 80;

impl Program<'_> {
/// Serialize AST to ESTree JSON, including TypeScript fields.
pub fn to_estree_ts_json(&self) -> String {
pub fn to_estree_ts_json(&self, ranges: bool) -> String {
let capacity = self.source_text.len() * JSON_CAPACITY_RATIO_COMPACT;
let mut serializer = CompactTSSerializer::with_capacity(capacity);
let mut serializer = CompactTSSerializer::with_capacity(capacity, ranges);
self.serialize(&mut serializer);
serializer.into_string()
}

/// Serialize AST to ESTree JSON, without TypeScript fields.
pub fn to_estree_js_json(&self) -> String {
pub fn to_estree_js_json(&self, ranges: bool) -> String {
let capacity = self.source_text.len() * JSON_CAPACITY_RATIO_COMPACT;
let mut serializer = CompactJSSerializer::with_capacity(capacity);
let mut serializer = CompactJSSerializer::with_capacity(capacity, ranges);
self.serialize(&mut serializer);
serializer.into_string()
}

/// Serialize AST to pretty-printed ESTree JSON, including TypeScript fields.
pub fn to_pretty_estree_ts_json(&self) -> String {
pub fn to_pretty_estree_ts_json(&self, ranges: bool) -> String {
let capacity = self.source_text.len() * JSON_CAPACITY_RATIO_PRETTY;
let mut serializer = PrettyTSSerializer::with_capacity(capacity);
let mut serializer = PrettyTSSerializer::with_capacity(capacity, ranges);
self.serialize(&mut serializer);
serializer.into_string()
}

/// Serialize AST to pretty-printed ESTree JSON, without TypeScript fields.
pub fn to_pretty_estree_js_json(&self) -> String {
pub fn to_pretty_estree_js_json(&self, ranges: bool) -> String {
let capacity = self.source_text.len() * JSON_CAPACITY_RATIO_PRETTY;
let mut serializer = PrettyJSSerializer::with_capacity(capacity);
let mut serializer = PrettyJSSerializer::with_capacity(capacity, ranges);
self.serialize(&mut serializer);
serializer.into_string()
}

/// Serialize AST to ESTree JSON, including TypeScript fields, with list of fixes.
pub fn to_estree_ts_json_with_fixes(&self) -> String {
pub fn to_estree_ts_json_with_fixes(&self, ranges: bool) -> String {
let capacity = self.source_text.len() * JSON_CAPACITY_RATIO_COMPACT;
let serializer = CompactFixesTSSerializer::with_capacity(capacity);
let serializer = CompactFixesTSSerializer::with_capacity(capacity, ranges);
serializer.serialize_with_fixes(self)
}

/// Serialize AST to ESTree JSON, without TypeScript fields, with list of fixes.
pub fn to_estree_js_json_with_fixes(&self) -> String {
pub fn to_estree_js_json_with_fixes(&self, ranges: bool) -> String {
let capacity = self.source_text.len() * JSON_CAPACITY_RATIO_COMPACT;
let serializer = CompactFixesJSSerializer::with_capacity(capacity);
let serializer = CompactFixesJSSerializer::with_capacity(capacity, ranges);
serializer.serialize_with_fixes(self)
}

/// Serialize AST to pretty-printed ESTree JSON, including TypeScript fields, with list of fixes.
pub fn to_pretty_estree_ts_json_with_fixes(&self) -> String {
pub fn to_pretty_estree_ts_json_with_fixes(&self, ranges: bool) -> String {
let capacity = self.source_text.len() * JSON_CAPACITY_RATIO_PRETTY;
let serializer = PrettyFixesTSSerializer::with_capacity(capacity);
let serializer = PrettyFixesTSSerializer::with_capacity(capacity, ranges);
serializer.serialize_with_fixes(self)
}

/// Serialize AST to pretty-printed ESTree JSON, without TypeScript fields, with list of fixes.
pub fn to_pretty_estree_js_json_with_fixes(&self) -> String {
pub fn to_pretty_estree_js_json_with_fixes(&self, ranges: bool) -> String {
let capacity = self.source_text.len() * JSON_CAPACITY_RATIO_PRETTY;
let serializer = PrettyFixesJSSerializer::with_capacity(capacity);
let serializer = PrettyFixesJSSerializer::with_capacity(capacity, ranges);
serializer.serialize_with_fixes(self)
}
}
Expand Down Expand Up @@ -168,13 +168,17 @@ impl ESTree for ProgramConverter<'_, '_> {
let span_start =
if S::INCLUDE_TS_FIELDS { get_ts_start_span(program) } else { program.span.start };

let ranges = serializer.ranges();
let mut state = serializer.serialize_struct();
state.serialize_field("type", &JsonSafeString("Program"));
state.serialize_field("start", &span_start);
state.serialize_field("end", &program.span.end);
state.serialize_field("body", &Concat2(&program.directives, &program.body));
state.serialize_field("sourceType", &program.source_type.module_kind());
state.serialize_field("hashbang", &program.hashbang);
if ranges {
state.serialize_field("range", &[span_start, program.span.end]);
}
state.end();
}
}
Expand Down
8 changes: 4 additions & 4 deletions crates/oxc_estree/src/serialize/blanket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ mod tests {
let cases = [(&"foo", r#""foo""#), (&&"bar", r#""bar""#)];

for (input, output) in cases {
let mut serializer = CompactTSSerializer::new();
let mut serializer = CompactTSSerializer::new(false);
input.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(&s, output);
Expand All @@ -69,7 +69,7 @@ mod tests {
let cases = [(&mut "foo", r#""foo""#), (&mut &mut "bar", r#""bar""#)];

for (input, output) in cases {
let mut serializer = CompactTSSerializer::new();
let mut serializer = CompactTSSerializer::new(false);
input.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(&s, output);
Expand All @@ -81,7 +81,7 @@ mod tests {
let cases = [(None, "null"), (Some(123.0f64), "123")];

for (input, output) in cases {
let mut serializer = CompactTSSerializer::new();
let mut serializer = CompactTSSerializer::new(false);
input.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(&s, output);
Expand All @@ -94,7 +94,7 @@ mod tests {
[(Cow::Borrowed("foo"), r#""foo""#), (Cow::Owned("bar".to_string()), r#""bar""#)];

for (input, output) in cases {
let mut serializer = CompactTSSerializer::new();
let mut serializer = CompactTSSerializer::new(false);
input.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(&s, output);
Expand Down
59 changes: 45 additions & 14 deletions crates/oxc_estree/src/serialize/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,88 @@ pub trait Config {
/// `true` if should record paths to `Literal` nodes that need fixing on JS side
const FIXES: bool;

fn new() -> Self;
fn new(ranges: bool) -> Self;

/// Whether to include range information in the serialized output
fn ranges(&self) -> bool;
}

/// Config for serializing AST with TypeScript fields,
pub struct ConfigTS;
/// Config for serializing AST with TypeScript fields.
pub struct ConfigTS {
ranges: bool,
}

impl Config for ConfigTS {
const INCLUDE_TS_FIELDS: bool = true;
const FIXES: bool = false;

#[inline(always)]
fn new() -> Self {
Self
fn new(ranges: bool) -> Self {
Self { ranges }
}

#[inline(always)]
fn ranges(&self) -> bool {
self.ranges
}
}

/// Config for serializing AST without TypeScript fields.
pub struct ConfigJS;
pub struct ConfigJS {
ranges: bool,
}

impl Config for ConfigJS {
const INCLUDE_TS_FIELDS: bool = false;
const FIXES: bool = false;

#[inline(always)]
fn new() -> Self {
Self
fn new(ranges: bool) -> Self {
Self { ranges }
}

#[inline(always)]
fn ranges(&self) -> bool {
self.ranges
}
}

/// Config for serializing AST with TypeScript fields, with fixes.
pub struct ConfigFixesTS;
pub struct ConfigFixesTS {
ranges: bool,
}

impl Config for ConfigFixesTS {
const INCLUDE_TS_FIELDS: bool = true;
const FIXES: bool = true;

#[inline(always)]
fn new() -> Self {
Self
fn new(ranges: bool) -> Self {
Self { ranges }
}

#[inline(always)]
fn ranges(&self) -> bool {
self.ranges
}
}

/// Config for serializing AST without TypeScript fields, with fixes.
pub struct ConfigFixesJS;
pub struct ConfigFixesJS {
ranges: bool,
}

impl Config for ConfigFixesJS {
const INCLUDE_TS_FIELDS: bool = false;
const FIXES: bool = true;

#[inline(always)]
fn new() -> Self {
Self
fn new(ranges: bool) -> Self {
Self { ranges }
}

#[inline(always)]
fn ranges(&self) -> bool {
self.ranges
}
}
17 changes: 11 additions & 6 deletions crates/oxc_estree/src/serialize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ pub trait Serializer: SerializerPrivate {
/// Type of sequence serializer this serializer uses.
type SequenceSerializer: SequenceSerializer;

fn ranges(&self) -> bool;

/// Serialize struct.
fn serialize_struct(self) -> Self::StructSerializer;

Expand Down Expand Up @@ -100,30 +102,29 @@ pub struct ESTreeSerializer<C: Config, F: Formatter> {
formatter: F,
trace_path: NonEmptyStack<TracePathPart>,
fixes_buffer: CodeBuffer,
#[expect(unused)]
config: C,
}

impl<C: Config, F: Formatter> ESTreeSerializer<C, F> {
/// Create new [`ESTreeSerializer`].
pub fn new() -> Self {
pub fn new(ranges: bool) -> Self {
Self {
buffer: CodeBuffer::new(),
formatter: F::new(),
trace_path: NonEmptyStack::new(TracePathPart::Index(0)),
fixes_buffer: CodeBuffer::new(),
config: C::new(),
config: C::new(ranges),
}
}

/// Create new [`ESTreeSerializer`] with specified buffer capacity.
pub fn with_capacity(capacity: usize) -> Self {
pub fn with_capacity(capacity: usize, ranges: bool) -> Self {
Self {
buffer: CodeBuffer::with_capacity(capacity),
formatter: F::new(),
trace_path: NonEmptyStack::new(TracePathPart::Index(0)),
fixes_buffer: CodeBuffer::new(),
config: C::new(),
config: C::new(ranges),
}
}

Expand Down Expand Up @@ -168,7 +169,7 @@ impl<C: Config, F: Formatter> ESTreeSerializer<C, F> {
impl<C: Config, F: Formatter> Default for ESTreeSerializer<C, F> {
#[inline(always)]
fn default() -> Self {
Self::new()
Self::new(false)
}
}

Expand All @@ -179,6 +180,10 @@ impl<'s, C: Config, F: Formatter> Serializer for &'s mut ESTreeSerializer<C, F>
type StructSerializer = ESTreeStructSerializer<'s, C, F>;
type SequenceSerializer = ESTreeSequenceSerializer<'s, C, F>;

fn ranges(&self) -> bool {
self.config.ranges()
}

/// Serialize struct.
#[inline(always)]
fn serialize_struct(self) -> ESTreeStructSerializer<'s, C, F> {
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_estree/src/serialize/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ mod tests {

fn run_test<T: ESTree>(cases: &[(T, &str)]) {
for (input, output) in cases {
let mut serializer = CompactTSSerializer::new();
let mut serializer = CompactTSSerializer::new(false);
input.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(&s, output);
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_estree/src/serialize/sequences.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@ mod tests {

let foo = Foo { none: &[], one: &["one"], two: ["two one", "two two"] };

let mut serializer = CompactTSSerializer::new();
let mut serializer = CompactTSSerializer::new(false);
foo.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(&s, r#"{"none":[],"one":["one"],"two":["two one","two two"]}"#);

let mut serializer = PrettyTSSerializer::new();
let mut serializer = PrettyTSSerializer::new(false);
foo.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(
Expand Down
8 changes: 4 additions & 4 deletions crates/oxc_estree/src/serialize/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ mod tests {
];

for (input, output) in cases {
let mut serializer = CompactTSSerializer::new();
let mut serializer = CompactTSSerializer::new(false);
input.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(&s, output);
Expand All @@ -495,7 +495,7 @@ mod tests {
let cases = [(String::new(), r#""""#), ("foobar".to_string(), r#""foobar""#)];

for (input, output) in cases {
let mut serializer = CompactTSSerializer::new();
let mut serializer = CompactTSSerializer::new(false);
input.to_string().serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(&s, output);
Expand All @@ -507,7 +507,7 @@ mod tests {
let cases = [("", r#""""#), ("a", r#""a""#), ("abc", r#""abc""#)];

for (input, output) in cases {
let mut serializer = CompactTSSerializer::new();
let mut serializer = CompactTSSerializer::new(false);
JsonSafeString(input).serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(&s, output);
Expand All @@ -530,7 +530,7 @@ mod tests {
];

for (input, output) in cases {
let mut serializer = CompactTSSerializer::new();
let mut serializer = CompactTSSerializer::new(false);
LoneSurrogatesString(input).serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(&s, output);
Expand Down
Loading
Loading