Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1,071 changes: 178 additions & 893 deletions crates/oxc_ast/src/generated/derive_estree.rs

Large diffs are not rendered by default.

24 changes: 4 additions & 20 deletions crates/oxc_ast/src/serialize/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,7 @@ impl ESTree for BindingPatternKindAndTsFields<'_, '_> {
state.serialize_field("optional", &self.optional);
state.serialize_field("typeAnnotation", &self.type_annotation);

state.serialize_field("start", &span.start);
state.serialize_field("end", &span.end);
if state.ranges() {
state.serialize_field("range", &[span.start, span.end]);
}
state.serialize_span(span);

state.end();
}
Expand Down Expand Up @@ -174,11 +170,7 @@ impl ESTree for FormalParametersRest<'_, '_> {
state.serialize_ts_field("optional", &rest.argument.optional);
state.serialize_ts_field("typeAnnotation", &rest.argument.type_annotation);
state.serialize_ts_field("value", &Null(()));
state.serialize_field("start", &rest.span.start);
state.serialize_field("end", &rest.span.end);
if state.ranges() {
state.serialize_field("range", &[rest.span.start, rest.span.end]);
}
state.serialize_span(rest.span);
state.end();
}
}
Expand Down Expand Up @@ -238,11 +230,7 @@ impl ESTree for FormalParameterConverter<'_, '_> {
state.serialize_field("parameter", &param.pattern);
state.serialize_field("readonly", &param.readonly);
state.serialize_field("static", &false);
state.serialize_field("start", &param.span.start);
state.serialize_field("end", &param.span.end);
if state.ranges() {
state.serialize_field("range", &[param.span.start, param.span.end]);
}
state.serialize_span(param.span);
state.end();
} else {
BindingPatternKindAndTsFields {
Expand Down Expand Up @@ -452,11 +440,7 @@ impl ESTree for AssignmentTargetPropertyIdentifierInit<'_> {
state.serialize_field("right", init);
state.serialize_ts_field("optional", &false);
state.serialize_ts_field("typeAnnotation", &Null(()));
state.serialize_field("start", &self.0.span.start);
state.serialize_field("end", &self.0.span.end);
if state.ranges() {
state.serialize_field("range", &[self.0.span.start, self.0.span.end]);
}
state.serialize_span(self.0.span);
state.end();
} else {
self.0.binding.serialize(serializer);
Expand Down
6 changes: 1 addition & 5 deletions crates/oxc_ast/src/serialize/jsx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ impl ESTree for JSXElementOpeningElement<'_, '_> {
state.serialize_ts_field("typeArguments", &opening_element.type_arguments);
state.serialize_field("attributes", &opening_element.attributes);
state.serialize_field("selfClosing", &element.closing_element.is_none());
state.serialize_field("start", &opening_element.span.start);
state.serialize_field("end", &opening_element.span.end);
if state.ranges() {
state.serialize_field("range", &[opening_element.span.start, opening_element.span.end]);
}
state.serialize_span(opening_element.span);
state.end();
}
}
Expand Down
7 changes: 1 addition & 6 deletions crates/oxc_ast/src/serialize/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,7 @@ impl ESTree for TemplateElementConverter<'_, '_> {
span.start -= 1;
span.end += if element.tail { 1 } else { 2 };
}

state.serialize_field("start", &span.start);
state.serialize_field("end", &span.end);
if state.ranges() {
state.serialize_field("range", &[span.start, span.end]);
}
state.serialize_span(span);

state.end();
}
Expand Down
13 changes: 6 additions & 7 deletions crates/oxc_ast/src/serialize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,12 @@ impl ESTree for ProgramConverter<'_, '_> {
state.serialize_field("sourceType", &program.source_type.module_kind());
state.serialize_field("hashbang", &program.hashbang);

let span_start =
if S::INCLUDE_TS_FIELDS { get_ts_start_span(program) } else { program.span.start };
state.serialize_field("start", &span_start);
state.serialize_field("end", &program.span.end);
if state.ranges() {
state.serialize_field("range", &[span_start, program.span.end]);
}
let span = if S::INCLUDE_TS_FIELDS {
Span::new(get_ts_start_span(program), program.span.end)
} else {
program.span
};
state.serialize_span(span);

state.end();
}
Expand Down
20 changes: 4 additions & 16 deletions crates/oxc_ast/src/serialize/ts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,7 @@ impl ESTree for TSModuleDeclarationConverter<'_, '_> {
state.serialize_field("declare", &module.declare);
state.serialize_field("global", &TSModuleDeclarationGlobal(module));

state.serialize_field("start", &module.span.start);
state.serialize_field("end", &module.span.end);
if state.ranges() {
state.serialize_field("range", &[module.span.start, module.span.end]);
}
state.serialize_span(module.span);

state.end();
}
Expand Down Expand Up @@ -188,12 +184,8 @@ impl ESTree for TSModuleDeclarationIdParts<'_, '_> {

state.serialize_field("right", last);

let span_start = parts[0].span.start;
state.serialize_field("start", &span_start);
state.serialize_field("end", &last.span.end);
if state.ranges() {
state.serialize_field("range", &[span_start, last.span.end]);
}
let span = Span::new(parts[0].span.start, last.span.end);
state.serialize_span(span);

state.end();
}
Expand Down Expand Up @@ -357,11 +349,7 @@ impl ESTree for TSTypeNameAsMemberExpression<'_, '_> {
state.serialize_field("property", &name.right);
state.serialize_field("optional", &false);
state.serialize_field("computed", &false);
state.serialize_field("start", &name.span.start);
state.serialize_field("end", &name.span.end);
if state.ranges() {
state.serialize_field("range", &[name.span.start, name.span.end]);
}
state.serialize_span(name.span);
state.end();
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_estree/src/serialize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use structs::ESTreeStructSerializer;
pub use concat::{Concat2, Concat3, ConcatElement};
pub use sequences::SequenceSerializer;
pub use strings::{JsonSafeString, LoneSurrogatesString};
pub use structs::{FlatStructSerializer, StructSerializer};
pub use structs::{ESTreeSpan, FlatStructSerializer, StructSerializer};

/// Trait for types which can be serialized to ESTree.
pub trait ESTree {
Expand Down
35 changes: 35 additions & 0 deletions crates/oxc_estree/src/serialize/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ pub trait StructSerializer {
/// `key` must not contain any characters which require escaping in JSON.
fn serialize_ts_field<T: ESTree + ?Sized>(&mut self, key: &'static str, value: &T);

/// Serialize `Span`.
///
/// * If `serializer.ranges() == true`, outputs `start`, `end`, and `range` fields.
/// * Otherwise, outputs only `start` and `end`.
fn serialize_span<S: ESTreeSpan>(&mut self, span: S);

/// Finish serializing struct.
fn end(self);

Expand Down Expand Up @@ -131,6 +137,19 @@ impl<C: Config, F: Formatter> StructSerializer for ESTreeStructSerializer<'_, C,
}
}

/// Serialize `Span`.
///
/// * If `serializer.ranges() == true`, outputs `start`, `end`, and `range` fields.
/// * Otherwise, outputs only `start` and `end`.
fn serialize_span<S: ESTreeSpan>(&mut self, span: S) {
let range = span.range();
self.serialize_field("start", &range[0]);
self.serialize_field("end", &range[1]);
if self.serializer.ranges() {
self.serialize_field("range", &range);
}
}

/// Finish serializing struct.
fn end(self) {
let mut serializer = self.serializer;
Expand Down Expand Up @@ -291,6 +310,14 @@ impl<P: StructSerializer> StructSerializer for FlatStructSerializer<'_, P> {
self.0.serialize_ts_field(key, value);
}

/// Serialize `Span`.
///
/// * If `serializer.ranges() == true`, outputs `start`, `end`, and `range` fields.
/// * Otherwise, outputs only `start` and `end`.
fn serialize_span<S: ESTreeSpan>(&mut self, span: S) {
self.0.serialize_span(span);
}

/// Finish serializing struct.
fn end(self) {
// No-op - there may be more fields to be added to the struct in the parent
Expand All @@ -303,6 +330,14 @@ impl<P: StructSerializer> StructSerializer for FlatStructSerializer<'_, P> {
}
}

/// Trait for `Span` to implement.
///
/// This is a workaround to avoid circular dependency. `oxc_span` crate depends on `oxc_estree` crate,
/// so we can't import `Span` directly from `oxc_span` here.
pub trait ESTreeSpan: Copy {
fn range(self) -> [u32; 2];
}

#[cfg(test)]
mod tests {
use super::super::{
Expand Down
12 changes: 12 additions & 0 deletions crates/oxc_span/src/span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ use oxc_allocator::{Allocator, CloneIn, Dummy};
use oxc_ast_macros::ast;
use oxc_estree::ESTree;

#[cfg(feature = "serialize")]
use oxc_estree::ESTreeSpan;

/// An empty span.
///
/// Should be used for newly created new AST nodes.
Expand Down Expand Up @@ -564,6 +567,15 @@ impl Serialize for Span {
}
}

#[cfg(feature = "serialize")]
impl ESTreeSpan for Span {
#[expect(clippy::inline_always)] // `#[inline(always)]` because it's a no-op
#[inline(always)]
fn range(self) -> [u32; 2] {
[self.start, self.end]
}
}

/// Zero-sized type which has pointer alignment (8 on 64-bit, 4 on 32-bit).
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
Expand Down
18 changes: 3 additions & 15 deletions crates/oxc_syntax/src/generated/derive_estree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ impl ESTree for NameSpan<'_> {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut state = serializer.serialize_struct();
state.serialize_field("value", &self.name);
state.serialize_field("start", &self.span.start);
state.serialize_field("end", &self.span.end);
if state.ranges() {
state.serialize_field("range", &[self.span.start, self.span.end]);
}
state.serialize_span(self.span);
state.end();
}
}
Expand Down Expand Up @@ -55,11 +51,7 @@ impl ESTree for ExportEntry<'_> {
state.serialize_field("exportName", &self.export_name);
state.serialize_field("localName", &self.local_name);
state.serialize_field("isType", &self.is_type);
state.serialize_field("start", &self.span.start);
state.serialize_field("end", &self.span.end);
if state.ranges() {
state.serialize_field("range", &[self.span.start, self.span.end]);
}
state.serialize_span(self.span);
state.end();
}
}
Expand Down Expand Up @@ -103,11 +95,7 @@ impl ESTree for DynamicImport {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut state = serializer.serialize_struct();
state.serialize_field("moduleRequest", &self.module_request);
state.serialize_field("start", &self.span.start);
state.serialize_field("end", &self.span.end);
if state.ranges() {
state.serialize_field("range", &[self.span.start, self.span.end]);
}
state.serialize_span(self.span);
state.end();
}
}
Expand Down
18 changes: 3 additions & 15 deletions napi/parser/src/generated/derive_estree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,7 @@ impl ESTree for ErrorLabel<'_> {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut state = serializer.serialize_struct();
state.serialize_field("message", &self.message);
state.serialize_field("start", &self.span.start);
state.serialize_field("end", &self.span.end);
if state.ranges() {
state.serialize_field("range", &[self.span.start, self.span.end]);
}
state.serialize_span(self.span);
state.end();
}
}
Expand All @@ -72,11 +68,7 @@ impl ESTree for StaticImport<'_> {
let mut state = serializer.serialize_struct();
state.serialize_field("moduleRequest", &self.module_request);
state.serialize_field("entries", &self.entries);
state.serialize_field("start", &self.span.start);
state.serialize_field("end", &self.span.end);
if state.ranges() {
state.serialize_field("range", &[self.span.start, self.span.end]);
}
state.serialize_span(self.span);
state.end();
}
}
Expand All @@ -85,11 +77,7 @@ impl ESTree for StaticExport<'_> {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut state = serializer.serialize_struct();
state.serialize_field("entries", &self.entries);
state.serialize_field("start", &self.span.start);
state.serialize_field("end", &self.span.end);
if state.ranges() {
state.serialize_field("range", &[self.span.start, self.span.end]);
}
state.serialize_span(self.span);
state.end();
}
}
20 changes: 7 additions & 13 deletions tasks/ast_tools/src/derives/estree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,24 +376,11 @@ fn generate_body_for_struct(struct_def: &StructDef, schema: &Schema) -> TokenStr
quote!()
};

// Check if struct has a span field for range support
let has_span_field = struct_def.fields.iter().any(|field| field.name() == "span");
let range_field = if has_span_field {
quote! {
if state.ranges() {
state.serialize_field("range", &[self.span.start, self.span.end]);
}
}
} else {
quote!()
};

let stmts = g.stmts;
quote! {
let mut state = serializer.serialize_struct();
#type_field
#stmts
#range_field
state.end();
}
}
Expand Down Expand Up @@ -447,6 +434,13 @@ impl<'s> StructSerializerGenerator<'s> {
return;
}

if field.name() == "span" {
self.stmts.extend(quote! {
state.serialize_span(#self_path.span);
});
return;
}

let field_name_ident = field.ident();

if should_flatten_field(field, self.schema) {
Expand Down
Loading