turbopack_ecmascript/references/
constant_value.rs1use anyhow::Result;
2use bincode::{Decode, Encode};
3use swc_core::{
4 common::{DUMMY_SP, FileName, SourceMap, sync::Lrc},
5 ecma::{
6 ast::{
7 ArrayLit, EsVersion, Expr, KeyValueProp, Lit, ObjectLit, Prop, PropName, Regex, Str,
8 },
9 parser::{Syntax, parse_file_as_expr},
10 visit::fields::PropField,
11 },
12 quote,
13};
14use turbo_rcstr::RcStr;
15use turbo_tasks::{NonLocalValue, Vc, debug::ValueDebugFormat};
16use turbopack_core::{chunk::ChunkingContext, compile_time_info::CompileTimeDefineValue};
17
18use crate::{
19 ast_path_trie::{AstPathId, AstPathTrie},
20 code_gen::{CodeGen, CodeGeneration},
21 create_visitor,
22};
23
24#[derive(Clone, Debug, PartialEq, Eq, Hash, ValueDebugFormat, NonLocalValue, Encode, Decode)]
25pub struct ConstantValueCodeGen {
26 value: CompileTimeDefineValue,
27 path: AstPathId,
28}
29
30impl ConstantValueCodeGen {
31 pub fn new(value: CompileTimeDefineValue, path: AstPathId) -> Self {
32 ConstantValueCodeGen { value, path }
33 }
34 pub async fn code_generation(
35 &self,
36 trie: &AstPathTrie,
37 _chunking_context: Vc<Box<dyn ChunkingContext>>,
38 ) -> Result<CodeGeneration> {
39 let value = self.value.clone();
40 let mut visitors = Vec::new();
41
42 if matches!(
43 trie.get(self.path),
44 Some(swc_core::ecma::visit::AstParentKind::Prop(
45 PropField::Shorthand
46 ))
47 ) {
48 let ast_path = trie.parent_or_root(self.path);
49 visitors.push(create_visitor!(
50 exact,
51 trie,
52 ast_path,
53 visit_mut_prop,
54 |prop: &mut Prop| {
55 if let Prop::Shorthand(ident) = prop {
56 *prop = Prop::KeyValue(KeyValueProp {
57 key: PropName::Ident(ident.clone().into()),
58 value: value_to_expr(&value).into(),
59 });
60 }
61 }
62 ));
63 } else {
64 visitors.push(create_visitor!(
65 trie,
66 self.path,
67 visit_mut_expr,
68 |expr: &mut Expr| {
69 *expr = value_to_expr(&value);
70 }
71 ));
72 }
73
74 Ok(CodeGeneration::visitors(visitors))
75 }
76}
77
78impl From<ConstantValueCodeGen> for CodeGen {
79 fn from(val: ConstantValueCodeGen) -> Self {
80 CodeGen::ConstantValueCodeGen(val)
81 }
82}
83
84fn value_to_expr(value: &CompileTimeDefineValue) -> Expr {
85 match value {
86 CompileTimeDefineValue::Undefined => {
87 quote!("(\"TURBOPACK compile-time value\", void 0)" as Expr)
88 }
89 CompileTimeDefineValue::Null => {
90 quote!("(\"TURBOPACK compile-time value\", null)" as Expr)
91 }
92 CompileTimeDefineValue::Bool(true) => {
93 quote!("(\"TURBOPACK compile-time value\", true)" as Expr)
94 }
95 CompileTimeDefineValue::Bool(false) => {
96 quote!("(\"TURBOPACK compile-time value\", false)" as Expr)
97 }
98 CompileTimeDefineValue::Number(n) => {
99 quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = n
100 .as_f64()
101 .expect("unreachable: serde-json has arbitrary_precision disabled")
102 .into())
103 }
104 CompileTimeDefineValue::String(s) => {
105 quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = s.as_str().into())
106 }
107 CompileTimeDefineValue::BigInt(n) => {
108 quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = Expr::Lit(Lit::BigInt(n.as_ref().clone().into())))
109 }
110 CompileTimeDefineValue::Regex(pattern, flags) => {
111 quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = Expr::Lit(Lit::Regex(Regex {
112 span: DUMMY_SP,
113 exp: pattern.as_str().into(),
114 flags: flags.as_str().into(),
115 })))
116 }
117 CompileTimeDefineValue::Array(a) => {
118 quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = Expr::Array(ArrayLit {
119 span: DUMMY_SP,
120 elems: a.iter().map(|i| Some(value_to_expr(i).into())).collect(),
121 }))
122 }
123 CompileTimeDefineValue::Object(m) => {
124 quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = Expr::Object(ObjectLit {
125 span: DUMMY_SP,
126 props: m
127 .iter()
128 .map(|(k, v)| {
129 swc_core::ecma::ast::PropOrSpread::Prop(
130 Prop::KeyValue(KeyValueProp {
131 key: PropName::Str(Str::from(k.as_str())),
132 value: value_to_expr(v).into(),
133 })
134 .into(),
135 )
136 })
137 .collect(),
138 }))
139 }
140 CompileTimeDefineValue::Evaluate(s) => parse_single_expr_lit(s),
141 }
142}
143
144pub(crate) fn parse_single_expr_lit(expr_lit: &RcStr) -> Expr {
145 let cm = Lrc::new(SourceMap::default());
146 let fm = cm.new_source_file(FileName::Anon.into(), expr_lit.clone());
147 parse_file_as_expr(
148 &fm,
149 Syntax::Es(Default::default()),
150 EsVersion::latest(),
151 None,
152 &mut vec![],
153 )
154 .map_or(
155 quote!("(\"Failed parsed TURBOPACK compile-time value\", $s)" as Expr, s: Expr = expr_lit.as_str().into()),
156 |expr| quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = *expr),
157 )
158}