From f6709e4737c9339413b16485be9c9e974b9ec687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Mon, 4 Mar 2024 15:53:33 +0100 Subject: [PATCH] feat(ast): serialize identifiers to ESTree (#2521) --- crates/oxc_ast/src/ast/js.rs | 28 ++++++++------- crates/oxc_ast/src/serialize.rs | 62 +++++++++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 14 deletions(-) diff --git a/crates/oxc_ast/src/ast/js.rs b/crates/oxc_ast/src/ast/js.rs index 5f3cb751e..89500f597 100644 --- a/crates/oxc_ast/src/ast/js.rs +++ b/crates/oxc_ast/src/ast/js.rs @@ -15,6 +15,18 @@ use serde::Serialize; #[allow(clippy::wildcard_imports)] use crate::ast::*; +#[cfg_attr( + all(feature = "serde", feature = "wasm"), + wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section) +)] +#[allow(dead_code)] +const TS_APPEND_CONTENT: &'static str = r#" +export interface BindingIdentifier extends Span { type: "Identifier", name: Atom } +export interface IdentifierReference extends Span { type: "Identifier", name: Atom } +export interface IdentifierName extends Span { type: "Identifier", name: Atom } +export interface LabelIdentifier extends Span { type: "Identifier", name: Atom } +"#; + #[derive(Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] #[cfg_attr(all(feature = "serde", feature = "wasm"), derive(tsify::Tsify))] @@ -298,11 +310,9 @@ impl<'a> Expression<'a> { } /// Identifier Name +// See serializer in serialize.rs #[derive(Debug, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] -#[cfg_attr(all(feature = "serde", feature = "wasm"), derive(tsify::Tsify))] pub struct IdentifierName<'a> { - #[cfg_attr(feature = "serde", serde(flatten))] pub span: Span, pub name: Atom<'a>, } @@ -314,11 +324,9 @@ impl<'a> IdentifierName<'a> { } /// Identifier Reference +// See serializer in serialize.rs #[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] -#[cfg_attr(all(feature = "serde", feature = "wasm"), derive(tsify::Tsify))] pub struct IdentifierReference<'a> { - #[cfg_attr(feature = "serde", serde(flatten))] pub span: Span, pub name: Atom<'a>, pub reference_id: Cell>, @@ -339,11 +347,9 @@ impl<'a> IdentifierReference<'a> { } /// Binding Identifier +// See serializer in serialize.rs #[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] -#[cfg_attr(all(feature = "serde", feature = "wasm"), derive(tsify::Tsify))] pub struct BindingIdentifier<'a> { - #[cfg_attr(feature = "serde", serde(flatten))] pub span: Span, pub name: Atom<'a>, pub symbol_id: Cell>, @@ -363,11 +369,9 @@ impl<'a> BindingIdentifier<'a> { } /// Label Identifier +// See serializer in serialize.rs #[derive(Debug, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] -#[cfg_attr(all(feature = "serde", feature = "wasm"), derive(tsify::Tsify))] pub struct LabelIdentifier<'a> { - #[cfg_attr(feature = "serde", serde(flatten))] pub span: Span, pub name: Atom<'a>, } diff --git a/crates/oxc_ast/src/serialize.rs b/crates/oxc_ast/src/serialize.rs index 09fa4b90e..3af0a3e31 100644 --- a/crates/oxc_ast/src/serialize.rs +++ b/crates/oxc_ast/src/serialize.rs @@ -1,6 +1,12 @@ -use serde::{ser::Serializer, Serialize}; +use serde::{ + ser::{SerializeStruct, Serializer}, + Serialize, +}; -use crate::ast::{Program, RegExpFlags}; +use crate::ast::{ + BindingIdentifier, IdentifierName, IdentifierReference, LabelIdentifier, Program, RegExpFlags, +}; +use oxc_span::{Atom, Span}; pub struct EcmaFormatter; @@ -34,3 +40,55 @@ impl Serialize for RegExpFlags { serializer.serialize_str(&self.to_string()) } } + +/// Serialize `BindingIdentifier`, `IdentifierReference`, `IdentifierName` and `LabelIdentifier` +/// to be estree compatible with the `type` set to "Identifier". +fn serialize_identifier( + serializer: S, + struct_name: &'static str, + span: Span, + name: &Atom, +) -> Result { + let mut state = serializer.serialize_struct(struct_name, 4)?; + state.serialize_field("type", "Identifier")?; + state.serialize_field("start", &span.start)?; + state.serialize_field("end", &span.end)?; + state.serialize_field("name", name)?; + state.end() +} + +impl<'a> Serialize for BindingIdentifier<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serialize_identifier(serializer, "BindingIdentifier", self.span, &self.name) + } +} + +impl<'a> Serialize for IdentifierReference<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serialize_identifier(serializer, "IdentifierReference", self.span, &self.name) + } +} + +impl<'a> Serialize for IdentifierName<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serialize_identifier(serializer, "IdentifierName", self.span, &self.name) + } +} + +impl<'a> Serialize for LabelIdentifier<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serialize_identifier(serializer, "LabelIdentifier", self.span, &self.name) + } +}