Skip to main content

turbopack_ecmascript/references/
constant_value.rs

1use 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
71                .as_f64()
72                .expect("unreachable: serde-json has arbitrary_precision disabled")
73                .into())
74        }
75        CompileTimeDefineValue::String(s) => {
76            quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = s.as_str().into())
77        }
78        CompileTimeDefineValue::BigInt(n) => {
79            quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = Expr::Lit(Lit::BigInt(n.as_ref().clone().into())))
80        }
81        CompileTimeDefineValue::Regex(pattern, flags) => {
82            quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = Expr::Lit(Lit::Regex(Regex {
83               span: DUMMY_SP,
84               exp: pattern.as_str().into(),
85               flags: flags.as_str().into(),
86            })))
87        }
88        CompileTimeDefineValue::Array(a) => {
89            quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = Expr::Array(ArrayLit {
90                span: DUMMY_SP,
91                elems: a.iter().map(|i| Some(value_to_expr(i).into())).collect(),
92            }))
93        }
94        CompileTimeDefineValue::Object(m) => {
95            quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = Expr::Object(ObjectLit {
96                span: DUMMY_SP,
97                props: m
98                    .iter()
99                    .map(|(k, v)| {
100                        swc_core::ecma::ast::PropOrSpread::Prop(
101                            Prop::KeyValue(KeyValueProp {
102                                key: PropName::Str(Str::from(k.as_str())),
103                                value: value_to_expr(v).into(),
104                            })
105                            .into(),
106                        )
107                    })
108                    .collect(),
109            }))
110        }
111        CompileTimeDefineValue::Evaluate(s) => parse_single_expr_lit(s),
112    }
113}
114
115pub(crate) fn parse_single_expr_lit(expr_lit: &RcStr) -> Expr {
116    let cm = Lrc::new(SourceMap::default());
117    let fm = cm.new_source_file(FileName::Anon.into(), expr_lit.clone());
118    parse_file_as_expr(
119        &fm,
120        Syntax::Es(Default::default()),
121        EsVersion::latest(),
122        None,
123        &mut vec![],
124    )
125    .map_or(
126        quote!("(\"Failed parsed TURBOPACK compile-time value\", $s)" as Expr, s: Expr = expr_lit.as_str().into()),
127        |expr| quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = *expr),
128    )
129}