turbopack_ecmascript/references/
constant_value.rs

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