mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 12:51:57 +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 IdentifierReference extends Span { type: "Identifier", name: Atom }
|
||||||
export interface IdentifierName 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 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)]
|
#[derive(Debug, Hash)]
|
||||||
|
|
@ -970,13 +978,18 @@ pub enum AssignmentTargetPattern<'a> {
|
||||||
ObjectAssignmentTarget(Box<'a, ObjectAssignmentTarget<'a>>),
|
ObjectAssignmentTarget(Box<'a, ObjectAssignmentTarget<'a>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See serializer in serialize.rs
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))]
|
|
||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||||
pub struct ArrayAssignmentTarget<'a> {
|
pub struct ArrayAssignmentTarget<'a> {
|
||||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
#[cfg_attr(feature = "wasm", serde(flatten))]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "wasm",
|
||||||
|
tsify(type = "Array<AssignmentTargetMaybeDefault | AssignmentTargetRest | null>")
|
||||||
|
)]
|
||||||
pub elements: Vec<'a, Option<AssignmentTargetMaybeDefault<'a>>>,
|
pub elements: Vec<'a, Option<AssignmentTargetMaybeDefault<'a>>>,
|
||||||
|
#[cfg_attr(feature = "wasm", serde(skip))]
|
||||||
pub rest: Option<AssignmentTargetRest<'a>>,
|
pub rest: Option<AssignmentTargetRest<'a>>,
|
||||||
pub trailing_comma: Option<Span>,
|
pub trailing_comma: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
@ -990,13 +1003,18 @@ impl<'a> ArrayAssignmentTarget<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See serializer in serialize.rs
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
|
||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||||
pub struct ObjectAssignmentTarget<'a> {
|
pub struct ObjectAssignmentTarget<'a> {
|
||||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
#[cfg_attr(feature = "wasm", serde(flatten))]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "wasm",
|
||||||
|
tsify(type = "Array<AssignmentTargetProperty | AssignmentTargetRest>")
|
||||||
|
)]
|
||||||
pub properties: Vec<'a, AssignmentTargetProperty<'a>>,
|
pub properties: Vec<'a, AssignmentTargetProperty<'a>>,
|
||||||
|
#[cfg_attr(feature = "wasm", serde(skip))]
|
||||||
pub rest: Option<AssignmentTargetRest<'a>>,
|
pub rest: Option<AssignmentTargetRest<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1018,11 +1036,11 @@ impl<'a> ObjectAssignmentTarget<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename = "RestElement"))]
|
||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
|
||||||
pub struct AssignmentTargetRest<'a> {
|
pub struct AssignmentTargetRest<'a> {
|
||||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
#[cfg_attr(feature = "serde", serde(rename = "argument"))]
|
||||||
pub target: AssignmentTarget<'a>,
|
pub target: AssignmentTarget<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1623,6 +1641,7 @@ impl<'a> BindingPattern<'a> {
|
||||||
|
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))]
|
#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))]
|
||||||
|
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||||
pub enum BindingPatternKind<'a> {
|
pub enum BindingPatternKind<'a> {
|
||||||
/// `const a = 1`
|
/// `const a = 1`
|
||||||
BindingIdentifier(Box<'a, BindingIdentifier<'a>>),
|
BindingIdentifier(Box<'a, BindingIdentifier<'a>>),
|
||||||
|
|
@ -1661,13 +1680,15 @@ pub struct AssignmentPattern<'a> {
|
||||||
pub right: Expression<'a>,
|
pub right: Expression<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See serializer in serialize.rs
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
|
||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||||
pub struct ObjectPattern<'a> {
|
pub struct ObjectPattern<'a> {
|
||||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
#[cfg_attr(feature = "wasm", serde(flatten))]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
#[cfg_attr(feature = "wasm", tsify(type = "Array<BindingProperty | BindingRestElement>"))]
|
||||||
pub properties: Vec<'a, BindingProperty<'a>>,
|
pub properties: Vec<'a, BindingProperty<'a>>,
|
||||||
|
#[cfg_attr(feature = "wasm", serde(skip))]
|
||||||
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
|
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1693,13 +1714,18 @@ pub struct BindingProperty<'a> {
|
||||||
pub computed: bool,
|
pub computed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See serializer in serialize.rs
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
|
||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||||
pub struct ArrayPattern<'a> {
|
pub struct ArrayPattern<'a> {
|
||||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
#[cfg_attr(feature = "wasm", serde(flatten))]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "wasm",
|
||||||
|
tsify(type = "Array<BindingPattern | BindingRestElement | null>")
|
||||||
|
)]
|
||||||
pub elements: Vec<'a, Option<BindingPattern<'a>>>,
|
pub elements: Vec<'a, Option<BindingPattern<'a>>>,
|
||||||
|
#[cfg_attr(feature = "wasm", serde(skip))]
|
||||||
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
|
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1714,8 +1740,7 @@ impl<'a> ArrayPattern<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename = "RestElement"))]
|
||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
|
||||||
pub struct BindingRestElement<'a> {
|
pub struct BindingRestElement<'a> {
|
||||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -1799,14 +1824,16 @@ pub enum FunctionType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://tc39.es/ecma262/#prod-FormalParameters>
|
/// <https://tc39.es/ecma262/#prod-FormalParameters>
|
||||||
|
// See serializer in serialize.rs
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
|
||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||||
pub struct FormalParameters<'a> {
|
pub struct FormalParameters<'a> {
|
||||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
#[cfg_attr(feature = "wasm", serde(flatten))]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub kind: FormalParameterKind,
|
pub kind: FormalParameterKind,
|
||||||
|
#[cfg_attr(feature = "wasm", tsify(type = "Array<FormalParameter | FormalParameterRest>"))]
|
||||||
pub items: Vec<'a, FormalParameter<'a>>,
|
pub items: Vec<'a, FormalParameter<'a>>,
|
||||||
|
#[cfg_attr(feature = "wasm", serde(skip))]
|
||||||
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
|
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,16 @@
|
||||||
use serde::{
|
use serde::{
|
||||||
ser::{SerializeStruct, Serializer},
|
ser::{SerializeSeq, SerializeStruct, Serializer},
|
||||||
Serialize,
|
Serialize,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::ast::{
|
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};
|
use oxc_span::{Atom, Span};
|
||||||
|
|
||||||
pub struct EcmaFormatter;
|
pub struct EcmaFormatter;
|
||||||
|
|
@ -92,3 +97,143 @@ impl<'a> Serialize for LabelIdentifier<'a> {
|
||||||
serialize_identifier(serializer, "LabelIdentifier", self.span, &self.name)
|
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