fix(es/ast): Fix json deserialization of AssignExpr (#5179)

This commit is contained in:
overlookmotel 2022-08-09 15:15:45 +01:00 committed by GitHub
parent 65595830f3
commit 53627aff44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,6 +1,10 @@
#![allow(clippy::vec_box)]
use is_macro::Is;
use serde::{self, Deserialize, Serialize};
use serde::{
self,
de::{self, MapAccess, Visitor},
Deserialize, Deserializer, Serialize,
};
use string_enum::StringEnum;
use swc_atoms::Atom;
use swc_common::{ast_node, util::take::Take, BytePos, EqIgnoreSpan, Span, Spanned, DUMMY_SP};
@ -446,7 +450,24 @@ impl Take for ClassExpr {
}
}
}
#[ast_node("AssignmentExpression")]
#[derive(Spanned, Clone, Debug, PartialEq, Serialize)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(
feature = "rkyv",
archive(bound(
serialize = "__S: rkyv::ser::Serializer + rkyv::ser::ScratchSpace + \
rkyv::ser::SharedSerializeRegistry",
deserialize = "__D: rkyv::de::SharedDeserializeRegistry"
))
)]
#[cfg_attr(feature = "rkyv", archive_attr(repr(C), derive(bytecheck::CheckBytes)))]
#[serde(tag = "type")]
#[serde(rename_all = "camelCase")]
#[serde(rename = "AssignmentExpression")]
#[derive(Eq, Hash, EqIgnoreSpan)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct AssignExpr {
@ -471,6 +492,91 @@ impl Take for AssignExpr {
}
}
// Custom deserializer to convert `PatOrExpr::Pat(Box<Pat::Ident>)`
// to `PatOrExpr::Expr(Box<Expr::Ident>)` when `op` is not `=`.
// Same logic as parser:
// https://github.com/swc-project/swc/blob/b87e3b0d4f46e6aea1ee7745f0bb3d129ef12b9c/crates/swc_ecma_parser/src/parser/pat.rs#L602-L610
impl<'de> Deserialize<'de> for AssignExpr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct AssignExprVisitor;
impl<'de> Visitor<'de> for AssignExprVisitor {
type Value = AssignExpr;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("struct AssignExpr")
}
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut span_field: Option<Span> = None;
let mut op_field: Option<AssignOp> = None;
let mut left_field: Option<PatOrExpr> = None;
let mut right_field: Option<Box<Expr>> = None;
while let Some(key) = map.next_key()? {
match key {
"span" => {
if span_field.is_some() {
return Err(de::Error::duplicate_field("span"));
}
span_field = Some(map.next_value()?);
}
"operator" => {
if op_field.is_some() {
return Err(de::Error::duplicate_field("operator"));
}
op_field = Some(map.next_value()?);
}
"left" => {
if left_field.is_some() {
return Err(de::Error::duplicate_field("left"));
}
left_field = Some(map.next_value()?);
}
"right" => {
if right_field.is_some() {
return Err(de::Error::duplicate_field("right"));
}
right_field = Some(map.next_value()?);
}
_ => {
let _: de::IgnoredAny = map.next_value()?;
}
}
}
let span = span_field.ok_or_else(|| de::Error::missing_field("span"))?;
let op = op_field.ok_or_else(|| de::Error::missing_field("operator"))?;
let mut left = left_field.ok_or_else(|| de::Error::missing_field("left"))?;
let right = right_field.ok_or_else(|| de::Error::missing_field("right"))?;
if op != AssignOp::Assign {
if let PatOrExpr::Pat(ref pat) = left {
if let Pat::Ident(ident) = &**pat {
left = PatOrExpr::Expr(Box::new(Expr::Ident(ident.id.clone())));
}
}
}
Ok(AssignExpr {
span,
op,
left,
right,
})
}
}
deserializer.deserialize_map(AssignExprVisitor)
}
}
#[ast_node("MemberExpression")]
#[derive(Eq, Hash, EqIgnoreSpan)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]