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 },
11 quote,
12};
13use turbo_rcstr::RcStr;
14use turbo_tasks::{NonLocalValue, Vc, debug::ValueDebugFormat, trace::TraceRawVcs};
15use turbopack_core::{chunk::ChunkingContext, compile_time_info::CompileTimeDefineValue};
16
17use crate::{
18 code_gen::{CodeGen, CodeGeneration},
19 create_visitor,
20 references::AstPath,
21};
22
23#[derive(
24 Clone, Debug, PartialEq, Eq, Hash, TraceRawVcs, ValueDebugFormat, NonLocalValue, Encode, Decode,
25)]
26pub struct ConstantValueCodeGen {
27 value: CompileTimeDefineValue,
28 path: AstPath,
29}
30
31impl ConstantValueCodeGen {
32 pub fn new(value: CompileTimeDefineValue, path: AstPath) -> Self {
33 ConstantValueCodeGen { value, path }
34 }
35 pub async fn code_generation(
36 &self,
37 _chunking_context: Vc<Box<dyn ChunkingContext>>,
38 ) -> Result<CodeGeneration> {
39 let value = self.value.clone();
40
41 let visitor = create_visitor!(self.path, visit_mut_expr, |expr: &mut Expr| {
42 *expr = value_to_expr(&value);
43 });
44
45 Ok(CodeGeneration::visitors(vec![visitor]))
46 }
47}
48
49impl From<ConstantValueCodeGen> for CodeGen {
50 fn from(val: ConstantValueCodeGen) -> Self {
51 CodeGen::ConstantValueCodeGen(val)
52 }
53}
54
55fn value_to_expr(value: &CompileTimeDefineValue) -> Expr {
56 match value {
57 CompileTimeDefineValue::Undefined => {
58 quote!("(\"TURBOPACK compile-time value\", void 0)" as Expr)
59 }
60 CompileTimeDefineValue::Null => {
61 quote!("(\"TURBOPACK compile-time value\", null)" as Expr)
62 }
63 CompileTimeDefineValue::Bool(true) => {
64 quote!("(\"TURBOPACK compile-time value\", true)" as Expr)
65 }
66 CompileTimeDefineValue::Bool(false) => {
67 quote!("(\"TURBOPACK compile-time value\", false)" as Expr)
68 }
69 CompileTimeDefineValue::Number(n) => {
70 quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = (**n).into())
71 }
72 CompileTimeDefineValue::String(s) => {
73 quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = s.as_str().into())
74 }
75 CompileTimeDefineValue::BigInt(n) => {
76 quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = Expr::Lit(Lit::BigInt(n.as_ref().clone().into())))
77 }
78 CompileTimeDefineValue::Regex(pattern, flags) => {
79 quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = Expr::Lit(Lit::Regex(Regex {
80 span: DUMMY_SP,
81 exp: pattern.as_str().into(),
82 flags: flags.as_str().into(),
83 })))
84 }
85 CompileTimeDefineValue::Array(a) => {
86 quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = Expr::Array(ArrayLit {
87 span: DUMMY_SP,
88 elems: a.iter().map(|i| Some(value_to_expr(i).into())).collect(),
89 }))
90 }
91 CompileTimeDefineValue::Object(m) => {
92 quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = Expr::Object(ObjectLit {
93 span: DUMMY_SP,
94 props: m
95 .iter()
96 .map(|(k, v)| {
97 swc_core::ecma::ast::PropOrSpread::Prop(
98 Prop::KeyValue(KeyValueProp {
99 key: PropName::Str(Str::from(k.as_str())),
100 value: value_to_expr(v).into(),
101 })
102 .into(),
103 )
104 })
105 .collect(),
106 }))
107 }
108 CompileTimeDefineValue::Evaluate(s) => parse_single_expr_lit(s),
109 }
110}
111
112pub(crate) fn parse_single_expr_lit(expr_lit: &RcStr) -> Expr {
113 let cm = Lrc::new(SourceMap::default());
114 let fm = cm.new_source_file(FileName::Anon.into(), expr_lit.clone());
115 parse_file_as_expr(
116 &fm,
117 Syntax::Es(Default::default()),
118 EsVersion::latest(),
119 None,
120 &mut vec![],
121 )
122 .map_or(
123 quote!("(\"Failed parsed TURBOPACK compile-time value\", $s)" as Expr, s: Expr = expr_lit.as_str().into()),
124 |expr| quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = *expr),
125 )
126}