use std::fmt::Write as _;
use rolldown_utils::concat_string;
use serde_json::Value;
use super::constants::THRESHOLD_SIZE;
#[inline]
fn serialize_value(value: &Value) -> Result<String, serde_json::Error> {
let value_as_string = serde_json::to_string(value)?;
if value_as_string.len() > THRESHOLD_SIZE && value.is_object() {
let value = serde_json::to_string(&value_as_string)?;
Ok(concat_string!("/*#__PURE__*/ JSON.parse(", value, ")"))
} else {
Ok(value_as_string)
}
}
pub fn data_to_esm(data: &Value, named_exports: bool) -> String {
if !named_exports || !data.is_object() {
return concat_string!("export default ", data.to_string(), ";\n");
}
let data = data.as_object().unwrap();
if data.is_empty() {
return "export default {};\n".to_string();
}
let mut named_export_code = String::new();
let mut default_object_code = String::new();
for (key, value) in data {
let value = serialize_value(value).expect("Invalid JSON value");
if rolldown_utils::ecmascript::is_validate_assignee_identifier_name(key) {
writeln!(named_export_code, "export const {key} = {value};").unwrap();
writeln!(default_object_code, " {key},").unwrap();
} else {
let key = serde_json::to_string(key).unwrap();
writeln!(default_object_code, " {key}: {value},").unwrap();
}
}
default_object_code.truncate(default_object_code.len() - 2);
concat_string!(named_export_code, "export default {\n", default_object_code, "\n};")
}
#[cfg(test)]
mod test {
use super::data_to_esm;
#[test]
fn to_esm_named_exports_object() {
let data = serde_json::json!({"name": "name"});
assert_eq!(
"export const name = \"name\";\nexport default {\n name\n};",
data_to_esm(&data, true)
);
}
#[test]
fn to_esm_named_exports_literal() {
let data = serde_json::json!(1);
assert_eq!("export default 1;\n", data_to_esm(&data, true));
}
#[test]
fn to_esm_named_exports_forbidden_ident() {
let data = serde_json::json!({"true": true, "\\\"\n": 1234, "eval": 0, "arguments": 0});
assert_eq!(
"export default {\n \"true\": true,\n \"\\\\\\\"\\n\": 1234,\n \"eval\": 0,\n \"arguments\": 0\n};",
data_to_esm(&data, true)
);
}
#[test]
fn to_esm_named_exports_multiple_fields() {
let data = serde_json::json!({"foo": "foo", "bar": "bar"});
assert_eq!(
"export const foo = \"foo\";\nexport const bar = \"bar\";\nexport default {\n foo,\n bar\n};",
data_to_esm(&data, true)
);
}
}