mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
fix(ast): correct JSON serialization of TSModuleBlock (#3858)
Fix #3848. #3830 added a `directives` field to `TSModuleBlock`. ESTree AST treats directives in module blocks as `StringLiteral`s. Add a custom `Serialize` impl to combine any directives back into `body` in JS AST. NB: `#[serde(skip)]` attr on `directives` field is for benefit of `Tsify` derive macro, so TS defs match the actual JSON AST.
This commit is contained in:
parent
66f404c2f3
commit
063cfdeb40
2 changed files with 55 additions and 3 deletions
|
|
@ -832,13 +832,15 @@ pub enum TSModuleDeclarationBody<'a> {
|
|||
TSModuleBlock(Box<'a, TSModuleBlock<'a>>),
|
||||
}
|
||||
|
||||
// See serializer in serialize.rs
|
||||
#[visited_node]
|
||||
#[derive(Debug, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
#[cfg_attr(feature = "serialize", derive(Tsify))]
|
||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||
pub struct TSModuleBlock<'a> {
|
||||
#[cfg_attr(feature = "serialize", serde(flatten))]
|
||||
pub span: Span,
|
||||
#[cfg_attr(feature = "serialize", serde(skip))]
|
||||
pub directives: Vec<'a, Directive<'a>>,
|
||||
pub body: Vec<'a, Statement<'a>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ use serde::{
|
|||
use crate::ast::{
|
||||
ArrayAssignmentTarget, ArrayPattern, AssignmentTargetMaybeDefault, AssignmentTargetProperty,
|
||||
AssignmentTargetRest, BindingPattern, BindingPatternKind, BindingProperty, BindingRestElement,
|
||||
Elision, FormalParameter, FormalParameterKind, FormalParameters, ObjectAssignmentTarget,
|
||||
ObjectPattern, Program, RegExpFlags, TSTypeAnnotation,
|
||||
Directive, Elision, FormalParameter, FormalParameterKind, FormalParameters,
|
||||
ObjectAssignmentTarget, ObjectPattern, Program, RegExpFlags, Statement, StringLiteral,
|
||||
TSModuleBlock, TSTypeAnnotation,
|
||||
};
|
||||
|
||||
pub struct EcmaFormatter;
|
||||
|
|
@ -199,3 +200,52 @@ impl<'a, 'b, E: Serialize, R: Serialize> Serialize for ElementsAndRest<'a, 'b, E
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize `TSModuleBlock` to be ESTree compatible, with `body` and `directives` fields combined,
|
||||
/// and directives output as `StringLiteral` expression statements
|
||||
impl<'a> Serialize for TSModuleBlock<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let converted = SerTSModuleBlock {
|
||||
span: self.span,
|
||||
body: DirectivesAndStatements { directives: &self.directives, body: &self.body },
|
||||
};
|
||||
converted.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type", rename = "TSModuleBlock")]
|
||||
struct SerTSModuleBlock<'a, 'b> {
|
||||
#[serde(flatten)]
|
||||
span: Span,
|
||||
body: DirectivesAndStatements<'a, 'b>,
|
||||
}
|
||||
|
||||
struct DirectivesAndStatements<'a, 'b> {
|
||||
directives: &'b [Directive<'a>],
|
||||
body: &'b [Statement<'a>],
|
||||
}
|
||||
|
||||
impl<'a, 'b> Serialize for DirectivesAndStatements<'a, 'b> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut seq = serializer.serialize_seq(Some(self.directives.len() + self.body.len()))?;
|
||||
for directive in self.directives {
|
||||
seq.serialize_element(&DirectiveAsStatement {
|
||||
span: directive.span,
|
||||
expression: &directive.expression,
|
||||
})?;
|
||||
}
|
||||
for stmt in self.body {
|
||||
seq.serialize_element(stmt)?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type", rename = "ExpressionStatement")]
|
||||
struct DirectiveAsStatement<'a, 'b> {
|
||||
#[serde(flatten)]
|
||||
span: Span,
|
||||
expression: &'b StringLiteral<'a>,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue