mirror of
https://github.com/danbulant/oxc
synced 2026-05-23 06:08:47 +00:00
fix(ast): add RestElements in serialized AST to elements array (#2567)
A step towards #2463. This PR adds `rest` onto end of `elements` / `properties` array in JSON AST for `ObjectPattern`, `ArrayPattern`, `ObjectAssignmentTarget`, `ArrayAssignmentTarget` and `FormalParameters`.
This commit is contained in:
parent
2609e9021b
commit
88f94bb6f6
2 changed files with 188 additions and 16 deletions
|
|
@ -21,6 +21,14 @@ 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 }
|
||||
export interface AssignmentTargetRest extends Span { type: "RestElement", target: AssignmentTarget }
|
||||
export interface BindingRestElement extends Span { type: "RestElement", argument: BindingPattern }
|
||||
export interface FormalParameterRest extends Span {
|
||||
type: "RestElement",
|
||||
argument: BindingPatternKind,
|
||||
typeAnnotation?: TSTypeAnnotation,
|
||||
optional: boolean,
|
||||
}
|
||||
"#;
|
||||
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -970,13 +978,18 @@ pub enum AssignmentTargetPattern<'a> {
|
|||
ObjectAssignmentTarget(Box<'a, ObjectAssignmentTarget<'a>>),
|
||||
}
|
||||
|
||||
// See serializer in serialize.rs
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||
pub struct ArrayAssignmentTarget<'a> {
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
#[cfg_attr(feature = "wasm", serde(flatten))]
|
||||
pub span: Span,
|
||||
#[cfg_attr(
|
||||
feature = "wasm",
|
||||
tsify(type = "Array<AssignmentTargetMaybeDefault | AssignmentTargetRest | null>")
|
||||
)]
|
||||
pub elements: Vec<'a, Option<AssignmentTargetMaybeDefault<'a>>>,
|
||||
#[cfg_attr(feature = "wasm", serde(skip))]
|
||||
pub rest: Option<AssignmentTargetRest<'a>>,
|
||||
pub trailing_comma: Option<Span>,
|
||||
}
|
||||
|
|
@ -990,13 +1003,18 @@ impl<'a> ArrayAssignmentTarget<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// See serializer in serialize.rs
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||
pub struct ObjectAssignmentTarget<'a> {
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
#[cfg_attr(feature = "wasm", serde(flatten))]
|
||||
pub span: Span,
|
||||
#[cfg_attr(
|
||||
feature = "wasm",
|
||||
tsify(type = "Array<AssignmentTargetProperty | AssignmentTargetRest>")
|
||||
)]
|
||||
pub properties: Vec<'a, AssignmentTargetProperty<'a>>,
|
||||
#[cfg_attr(feature = "wasm", serde(skip))]
|
||||
pub rest: Option<AssignmentTargetRest<'a>>,
|
||||
}
|
||||
|
||||
|
|
@ -1018,11 +1036,11 @@ impl<'a> ObjectAssignmentTarget<'a> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename = "RestElement"))]
|
||||
pub struct AssignmentTargetRest<'a> {
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
pub span: Span,
|
||||
#[cfg_attr(feature = "serde", serde(rename = "argument"))]
|
||||
pub target: AssignmentTarget<'a>,
|
||||
}
|
||||
|
||||
|
|
@ -1623,6 +1641,7 @@ impl<'a> BindingPattern<'a> {
|
|||
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||
pub enum BindingPatternKind<'a> {
|
||||
/// `const a = 1`
|
||||
BindingIdentifier(Box<'a, BindingIdentifier<'a>>),
|
||||
|
|
@ -1661,13 +1680,15 @@ pub struct AssignmentPattern<'a> {
|
|||
pub right: Expression<'a>,
|
||||
}
|
||||
|
||||
// See serializer in serialize.rs
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||
pub struct ObjectPattern<'a> {
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
#[cfg_attr(feature = "wasm", serde(flatten))]
|
||||
pub span: Span,
|
||||
#[cfg_attr(feature = "wasm", tsify(type = "Array<BindingProperty | BindingRestElement>"))]
|
||||
pub properties: Vec<'a, BindingProperty<'a>>,
|
||||
#[cfg_attr(feature = "wasm", serde(skip))]
|
||||
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
|
||||
}
|
||||
|
||||
|
|
@ -1693,13 +1714,18 @@ pub struct BindingProperty<'a> {
|
|||
pub computed: bool,
|
||||
}
|
||||
|
||||
// See serializer in serialize.rs
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||
pub struct ArrayPattern<'a> {
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
#[cfg_attr(feature = "wasm", serde(flatten))]
|
||||
pub span: Span,
|
||||
#[cfg_attr(
|
||||
feature = "wasm",
|
||||
tsify(type = "Array<BindingPattern | BindingRestElement | null>")
|
||||
)]
|
||||
pub elements: Vec<'a, Option<BindingPattern<'a>>>,
|
||||
#[cfg_attr(feature = "wasm", serde(skip))]
|
||||
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
|
||||
}
|
||||
|
||||
|
|
@ -1714,8 +1740,7 @@ impl<'a> ArrayPattern<'a> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename = "RestElement"))]
|
||||
pub struct BindingRestElement<'a> {
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
pub span: Span,
|
||||
|
|
@ -1799,14 +1824,16 @@ pub enum FunctionType {
|
|||
}
|
||||
|
||||
/// <https://tc39.es/ecma262/#prod-FormalParameters>
|
||||
// See serializer in serialize.rs
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||
pub struct FormalParameters<'a> {
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
#[cfg_attr(feature = "wasm", serde(flatten))]
|
||||
pub span: Span,
|
||||
pub kind: FormalParameterKind,
|
||||
#[cfg_attr(feature = "wasm", tsify(type = "Array<FormalParameter | FormalParameterRest>"))]
|
||||
pub items: Vec<'a, FormalParameter<'a>>,
|
||||
#[cfg_attr(feature = "wasm", serde(skip))]
|
||||
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
use serde::{
|
||||
ser::{SerializeStruct, Serializer},
|
||||
ser::{SerializeSeq, SerializeStruct, Serializer},
|
||||
Serialize,
|
||||
};
|
||||
|
||||
use crate::ast::{
|
||||
BindingIdentifier, IdentifierName, IdentifierReference, LabelIdentifier, Program, RegExpFlags,
|
||||
ArrayAssignmentTarget, ArrayPattern, AssignmentTargetMaybeDefault, AssignmentTargetProperty,
|
||||
AssignmentTargetRest, BindingIdentifier, BindingPattern, BindingPatternKind, BindingProperty,
|
||||
BindingRestElement, FormalParameter, FormalParameterKind, FormalParameters, IdentifierName,
|
||||
IdentifierReference, LabelIdentifier, ObjectAssignmentTarget, ObjectPattern, Program,
|
||||
RegExpFlags, TSTypeAnnotation,
|
||||
};
|
||||
use oxc_allocator::{Box, Vec};
|
||||
use oxc_span::{Atom, Span};
|
||||
|
||||
pub struct EcmaFormatter;
|
||||
|
|
@ -92,3 +97,143 @@ impl<'a> Serialize for LabelIdentifier<'a> {
|
|||
serialize_identifier(serializer, "LabelIdentifier", self.span, &self.name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize `ArrayAssignmentTarget`, `ObjectAssignmentTarget`, `ObjectPattern`, `ArrayPattern`
|
||||
/// to be estree compatible, with `elements`/`properties` and `rest` fields combined.
|
||||
|
||||
impl<'a> Serialize for ArrayAssignmentTarget<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let converted = SerArrayAssignmentTarget {
|
||||
span: self.span,
|
||||
elements: ElementsAndRest::new(&self.elements, &self.rest),
|
||||
trailing_comma: self.trailing_comma,
|
||||
};
|
||||
converted.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type", rename = "ArrayAssignmentTarget", rename_all = "camelCase")]
|
||||
struct SerArrayAssignmentTarget<'a, 'b> {
|
||||
#[serde(flatten)]
|
||||
span: Span,
|
||||
elements:
|
||||
ElementsAndRest<'a, 'b, Option<AssignmentTargetMaybeDefault<'a>>, AssignmentTargetRest<'a>>,
|
||||
trailing_comma: Option<Span>,
|
||||
}
|
||||
|
||||
impl<'a> Serialize for ObjectAssignmentTarget<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let converted = SerObjectAssignmentTarget {
|
||||
span: self.span,
|
||||
properties: ElementsAndRest::new(&self.properties, &self.rest),
|
||||
};
|
||||
converted.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type", rename = "ObjectAssignmentTarget")]
|
||||
struct SerObjectAssignmentTarget<'a, 'b> {
|
||||
#[serde(flatten)]
|
||||
span: Span,
|
||||
properties: ElementsAndRest<'a, 'b, AssignmentTargetProperty<'a>, AssignmentTargetRest<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Serialize for ObjectPattern<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let converted = SerObjectPattern {
|
||||
span: self.span,
|
||||
properties: ElementsAndRest::new(&self.properties, &self.rest),
|
||||
};
|
||||
converted.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type", rename = "ObjectPattern")]
|
||||
struct SerObjectPattern<'a, 'b> {
|
||||
#[serde(flatten)]
|
||||
span: Span,
|
||||
properties: ElementsAndRest<'a, 'b, BindingProperty<'a>, Box<'a, BindingRestElement<'a>>>,
|
||||
}
|
||||
|
||||
impl<'a> Serialize for ArrayPattern<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let converted = SerArrayPattern {
|
||||
span: self.span,
|
||||
elements: ElementsAndRest::new(&self.elements, &self.rest),
|
||||
};
|
||||
converted.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type", rename = "ArrayPattern")]
|
||||
struct SerArrayPattern<'a, 'b> {
|
||||
#[serde(flatten)]
|
||||
span: Span,
|
||||
elements: ElementsAndRest<'a, 'b, Option<BindingPattern<'a>>, Box<'a, BindingRestElement<'a>>>,
|
||||
}
|
||||
|
||||
/// Serialize `FormalParameters`, to be estree compatible, with `items` and `rest` fields combined
|
||||
/// and `argument` field flattened.
|
||||
impl<'a> Serialize for FormalParameters<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let converted_rest = self.rest.as_ref().map(|rest| SerFormalParameterRest {
|
||||
span: rest.span,
|
||||
argument: &rest.argument.kind,
|
||||
type_annotation: &rest.argument.type_annotation,
|
||||
optional: rest.argument.optional,
|
||||
});
|
||||
let converted = SerFormalParameters {
|
||||
span: self.span,
|
||||
kind: self.kind,
|
||||
items: ElementsAndRest::new(&self.items, &converted_rest),
|
||||
};
|
||||
converted.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type", rename = "FormalParameters")]
|
||||
struct SerFormalParameters<'a, 'b> {
|
||||
#[serde(flatten)]
|
||||
span: Span,
|
||||
kind: FormalParameterKind,
|
||||
items: ElementsAndRest<'a, 'b, FormalParameter<'a>, SerFormalParameterRest<'a, 'b>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type", rename = "RestElement", rename_all = "camelCase")]
|
||||
struct SerFormalParameterRest<'a, 'b> {
|
||||
#[serde(flatten)]
|
||||
span: Span,
|
||||
argument: &'b BindingPatternKind<'a>,
|
||||
type_annotation: &'b Option<Box<'a, TSTypeAnnotation<'a>>>,
|
||||
optional: bool,
|
||||
}
|
||||
|
||||
pub struct ElementsAndRest<'a, 'b, E, R> {
|
||||
elements: &'b Vec<'a, E>,
|
||||
rest: &'b Option<R>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, E, R> ElementsAndRest<'a, 'b, E, R> {
|
||||
pub fn new(elements: &'b Vec<'a, E>, rest: &'b Option<R>) -> Self {
|
||||
Self { elements, rest }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, E: Serialize, R: Serialize> Serialize for ElementsAndRest<'a, 'b, E, R> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut seq = serializer.serialize_seq(Some(self.elements.len() + 1))?;
|
||||
for element in self.elements {
|
||||
seq.serialize_element(element)?;
|
||||
}
|
||||
if let Some(rest) = self.rest {
|
||||
seq.serialize_element(rest)?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue