use std::borrow::Cow;
use serde::{ser::SerializeMap, Deserialize, Serialize};
use swc_atoms::{Atom, JsWord};
use swc_common::ast_serde;
use crate::{common::BaseNode, expr::Expression, flavor::Flavor, typescript::TSType};
#[derive(Debug, Clone, PartialEq)]
pub enum Literal {
String(StringLiteral),
Numeric(NumericLiteral),
Null(NullLiteral),
Boolean(BooleanLiteral),
RegExp(RegExpLiteral),
Template(TemplateLiteral),
BigInt(BigIntLiteral),
Decimal(DecimalLiteral),
}
#[derive(Serialize)]
struct AcornRegex<'a> {
flags: &'a str,
pattern: &'a str,
}
#[derive(Serialize)]
struct Empty {}
impl Serialize for Literal {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match Flavor::current() {
Flavor::Babel => {
let b = match self {
Literal::String(l) => BabelLiteral::String(l.clone()),
Literal::Numeric(l) => BabelLiteral::Numeric(l.clone()),
Literal::Null(l) => BabelLiteral::Null(l.clone()),
Literal::Boolean(l) => BabelLiteral::Boolean(l.clone()),
Literal::RegExp(l) => BabelLiteral::RegExp(l.clone()),
Literal::Template(l) => BabelLiteral::Template(l.clone()),
Literal::BigInt(l) => BabelLiteral::BigInt(l.clone()),
Literal::Decimal(l) => BabelLiteral::Decimal(l.clone()),
};
BabelLiteral::serialize(&b, serializer)
}
Flavor::Acorn { .. } => {
let (base, value, raw) = match self {
Literal::String(l) => (
&l.base,
AcornLiteralValue::String(l.value.clone()),
Cow::Owned(l.raw.to_string()),
),
Literal::Numeric(l) => (
&l.base,
AcornLiteralValue::Numeric(l.value),
Cow::Owned(l.value.to_string()),
),
Literal::Null(l) => (
&l.base,
AcornLiteralValue::Null(None),
Cow::Borrowed("null"),
),
Literal::Boolean(l) => (
&l.base,
AcornLiteralValue::Boolean(l.value),
if l.value {
Cow::Borrowed("true")
} else {
Cow::Borrowed("false")
},
),
Literal::RegExp(l) => {
let mut s = serializer.serialize_map(None)?;
{
l.base
.serialize(serde::__private::ser::FlatMapSerializer(&mut s))?;
}
s.serialize_entry("type", "Literal")?;
s.serialize_entry(
"regex",
&AcornRegex {
flags: &l.flags,
pattern: &l.pattern,
},
)?;
s.serialize_entry("value", &Empty {})?;
return s.end();
}
Literal::Template(..) => todo!(),
Literal::BigInt(l) => (
&l.base,
AcornLiteralValue::BigInt(l.value.clone()),
Cow::Owned(l.value.to_string()),
),
Literal::Decimal(l) => (
&l.base,
AcornLiteralValue::Decimal(l.value.clone()),
Cow::Owned(l.value.to_string()),
),
};
let acorn = AcornLiteral {
type_: "Literal",
raw: &raw,
base,
value,
};
AcornLiteral::serialize(&acorn, serializer)
}
}
}
}
impl<'de> Deserialize<'de> for Literal {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
BabelLiteral::deserialize(deserializer).map(|b| match b {
BabelLiteral::String(l) => Literal::String(l),
BabelLiteral::Numeric(l) => Literal::Numeric(l),
BabelLiteral::Null(l) => Literal::Null(l),
BabelLiteral::Boolean(l) => Literal::Boolean(l),
BabelLiteral::RegExp(l) => Literal::RegExp(l),
BabelLiteral::Template(l) => Literal::Template(l),
BabelLiteral::BigInt(l) => Literal::BigInt(l),
BabelLiteral::Decimal(l) => Literal::Decimal(l),
})
}
}
#[ast_serde]
enum BabelLiteral {
#[tag("StringLiteral")]
String(StringLiteral),
#[tag("NumericLiteral")]
Numeric(NumericLiteral),
#[tag("NullLiteral")]
Null(NullLiteral),
#[tag("BooleanLiteral")]
Boolean(BooleanLiteral),
#[tag("RegExpLiteral")]
RegExp(RegExpLiteral),
#[tag("TemplateLiteral")]
Template(TemplateLiteral),
#[tag("BigIntLiteral")]
BigInt(BigIntLiteral),
#[tag("DecimalLiteral")]
Decimal(DecimalLiteral),
}
#[derive(Serialize)]
struct AcornLiteral<'a> {
#[serde(rename = "type")]
type_: &'a str,
raw: &'a str,
#[serde(flatten)]
base: &'a BaseNode,
value: AcornLiteralValue,
}
#[derive(Serialize)]
#[serde(untagged)]
enum AcornLiteralValue {
String(JsWord),
Numeric(f64),
Null(Option<()>),
Boolean(bool),
BigInt(String),
Decimal(Atom),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "type")]
pub struct StringLiteral {
#[serde(flatten)]
pub base: BaseNode,
pub value: JsWord,
pub raw: Atom,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type")]
pub struct NumericLiteral {
#[serde(flatten)]
pub base: BaseNode,
pub value: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type")]
pub struct NumberLiteral {
#[serde(flatten)]
pub base: BaseNode,
pub value: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "type")]
pub struct NullLiteral {
#[serde(flatten)]
pub base: BaseNode,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "type")]
pub struct BooleanLiteral {
#[serde(flatten)]
pub base: BaseNode,
pub value: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "type")]
pub struct RegExpLiteral {
#[serde(flatten)]
pub base: BaseNode,
pub pattern: Atom,
#[serde(default)]
pub flags: Atom,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "type")]
pub struct RegexLiteral {
#[serde(flatten)]
pub base: BaseNode,
pub pattern: JsWord,
#[serde(default)]
pub flags: JsWord,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct TemplateElVal {
#[serde(default)]
pub raw: Atom,
#[serde(default)]
pub cooked: Option<Atom>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "type")]
pub struct TemplateElement {
#[serde(flatten)]
pub base: BaseNode,
pub value: TemplateElVal,
#[serde(default)]
pub tail: bool,
}
#[derive(Debug, Clone, PartialEq)]
#[ast_serde]
pub enum TemplateLiteralExpr {
#[tag("TSAnyKeyword")]
#[tag("TSBooleanKeyword")]
#[tag("TSBigIntKeyword")]
#[tag("TSIntrinsicKeyword")]
#[tag("TSNeverKeyword")]
#[tag("TSNullKeyword")]
#[tag("TSNumberKeyword")]
#[tag("TSObjectKeyword")]
#[tag("TSStringKeyword")]
#[tag("TSSymbolKeyword")]
#[tag("TSUndefinedKeyword")]
#[tag("TSUnknownKeyword")]
#[tag("TSVoidKeyword")]
#[tag("TSThisType")]
#[tag("TSFunctionType")]
#[tag("TSConstructorType")]
#[tag("TSTypeReference")]
#[tag("TSTypePredicate")]
#[tag("TSTypeQuery")]
#[tag("TSTypeLiteral")]
#[tag("TSArrayType")]
#[tag("TSTupleType")]
#[tag("TSOptionalType")]
#[tag("TSRestType")]
#[tag("TSUnionType")]
#[tag("TSIntersectionType")]
#[tag("TSConditionalType")]
#[tag("TSInferType")]
#[tag("TSParenthesizedType")]
#[tag("TSTypeOperator")]
#[tag("TSIndexedAccessType")]
#[tag("TSMappedType")]
#[tag("TSLiteralType")]
#[tag("TSExpressionWithTypeArguments")]
#[tag("TSImportType")]
TSType(TSType),
#[tag("*")]
Expr(Box<Expression>),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type")]
pub struct TemplateLiteral {
#[serde(flatten)]
pub base: BaseNode,
#[serde(default)]
pub quasis: Vec<TemplateElement>,
#[serde(default)]
pub expressions: Vec<TemplateLiteralExpr>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "type")]
pub struct BigIntLiteral {
#[serde(flatten)]
pub base: BaseNode,
#[serde(default)]
pub value: String,
#[serde(default)]
pub raw: Atom,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "type")]
pub struct DecimalLiteral {
#[serde(flatten)]
pub base: BaseNode,
#[serde(default)]
pub value: Atom,
}