1use anyhow::Result;
2use serde::{Deserialize, Serialize};
3use turbo_rcstr::RcStr;
4use turbo_tasks::{FxIndexMap, NonLocalValue, ResolvedVc, Vc, trace::TraceRawVcs};
5use turbo_tasks_fs::FileSystemPath;
6
7use crate::environment::Environment;
8
9#[macro_export]
10macro_rules! definable_name_map_pattern_internal {
11 ($name:ident) => {
12 [stringify!($name).into()]
13 };
14 ($name:ident typeof) => {
15 [stringify!($name).into(), $crate::compile_time_info::DefinableNameSegment::TypeOf]
16 };
17 ($name:ident . $($more:ident).+ typeof) => {
19 $crate::definable_name_map_pattern_internal!($($more).+ typeof, [stringify!($name).into()])
20 };
21 ($name:ident . $($more:ident).+) => {
22 $crate::definable_name_map_pattern_internal!($($more).+, [stringify!($name).into()])
23 };
24 ($name:ident, [$($array:expr),+]) => {
26 [$($array),+, stringify!($name).into()]
27 };
28 ($name:ident . $($more:ident).+, [$($array:expr),+]) => {
29 $crate::definable_name_map_pattern_internal!($($more).+, [$($array),+, stringify!($name).into()])
30 };
31 ($name:ident typeof, [$($array:expr),+]) => {
32 [$($array),+, stringify!($name).into(), $crate::compile_time_info::DefinableNameSegment::TypeOf]
33 };
34 ($name:ident . $($more:ident).+ typeof, [$($array:expr),+]) => {
35 $crate::definable_name_map_pattern_internal!($($more).+ typeof, [$($array),+, stringify!($name).into()])
36 };
37}
38
39#[macro_export]
41macro_rules! definable_name_map_internal {
42 ($map:ident, .. $value:expr) => {
44 for (key, value) in $value {
45 $map.insert(
46 key.into(),
47 value.into()
48 );
49 }
50 };
51 ($map:ident, .. $value:expr, $($more:tt)+) => {
52 $crate::definable_name_map_internal!($map, .. $value);
53 $crate::definable_name_map_internal!($map, $($more)+);
54 };
55 ($map:ident, typeof $($name:ident).+ = $value:expr $(,)?) => {
57 $map.insert(
58 $crate::definable_name_map_pattern_internal!($($name).+ typeof).into(),
59 $value.into()
60 );
61 };
62 ($map:ident, $($name:ident).+ = $value:expr $(,)?) => {
63 $map.insert(
64 $crate::definable_name_map_pattern_internal!($($name).+).into(),
65 $value.into()
66 );
67 };
68 ($map:ident, typeof $($name:ident).+ = $value:expr, $($more:tt)+) => {
70 $crate::definable_name_map_internal!($map, typeof $($name).+ = $value);
71 $crate::definable_name_map_internal!($map, $($more)+);
72 };
73 ($map:ident, $($name:ident).+ = $value:expr, $($more:tt)+) => {
74 $crate::definable_name_map_internal!($map, $($name).+ = $value);
75 $crate::definable_name_map_internal!($map, $($more)+);
76 };
77
78}
79
80#[macro_export]
81macro_rules! compile_time_defines {
82 ($($more:tt)+) => {
83 {
84 let mut map = $crate::__private::FxIndexMap::default();
85 $crate::definable_name_map_internal!(map, $($more)+);
86 $crate::compile_time_info::CompileTimeDefines(map)
87 }
88 };
89}
90
91#[macro_export]
92macro_rules! free_var_references {
93 ($($more:tt)+) => {
94 {
95 let mut map = $crate::__private::FxIndexMap::default();
96 $crate::definable_name_map_internal!(map, $($more)+);
97 $crate::compile_time_info::FreeVarReferences(map)
98 }
99 };
100}
101
102#[turbo_tasks::value]
105#[derive(Debug, Clone, Hash)]
106pub enum CompileTimeDefineValue {
107 Null,
108 Bool(bool),
109 Number(RcStr),
110 String(RcStr),
111 Array(Vec<CompileTimeDefineValue>),
112 Object(Vec<(RcStr, CompileTimeDefineValue)>),
113 Undefined,
114 Evaluate(RcStr),
115}
116
117impl From<bool> for CompileTimeDefineValue {
118 fn from(value: bool) -> Self {
119 Self::Bool(value)
120 }
121}
122
123impl From<RcStr> for CompileTimeDefineValue {
124 fn from(value: RcStr) -> Self {
125 Self::String(value)
126 }
127}
128
129impl From<String> for CompileTimeDefineValue {
130 fn from(value: String) -> Self {
131 Self::String(value.into())
132 }
133}
134
135impl From<&str> for CompileTimeDefineValue {
136 fn from(value: &str) -> Self {
137 Self::String(value.into())
138 }
139}
140
141impl From<serde_json::Value> for CompileTimeDefineValue {
142 fn from(value: serde_json::Value) -> Self {
143 match value {
144 serde_json::Value::Null => Self::Null,
145 serde_json::Value::Bool(b) => Self::Bool(b),
146 serde_json::Value::Number(n) => Self::Number(n.to_string().into()),
147 serde_json::Value::String(s) => Self::String(s.into()),
148 serde_json::Value::Array(a) => Self::Array(a.into_iter().map(|i| i.into()).collect()),
149 serde_json::Value::Object(m) => {
150 Self::Object(m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
151 }
152 }
153 }
154}
155
156#[turbo_tasks::value]
157#[derive(Debug, Clone, Hash, PartialOrd, Ord)]
158pub enum DefinableNameSegment {
159 Name(RcStr),
160 TypeOf,
161}
162
163impl From<RcStr> for DefinableNameSegment {
164 fn from(value: RcStr) -> Self {
165 DefinableNameSegment::Name(value)
166 }
167}
168
169impl From<&str> for DefinableNameSegment {
170 fn from(value: &str) -> Self {
171 DefinableNameSegment::Name(value.into())
172 }
173}
174
175impl From<String> for DefinableNameSegment {
176 fn from(value: String) -> Self {
177 DefinableNameSegment::Name(value.into())
178 }
179}
180
181#[turbo_tasks::value(transparent)]
182#[derive(Debug, Clone)]
183pub struct CompileTimeDefines(pub FxIndexMap<Vec<DefinableNameSegment>, CompileTimeDefineValue>);
184
185#[turbo_tasks::value(transparent)]
186#[derive(Debug, Clone)]
187pub struct CompileTimeDefinesIndividual(
188 pub FxIndexMap<Vec<DefinableNameSegment>, ResolvedVc<CompileTimeDefineValue>>,
189);
190
191impl IntoIterator for CompileTimeDefines {
192 type Item = (Vec<DefinableNameSegment>, CompileTimeDefineValue);
193 type IntoIter = indexmap::map::IntoIter<Vec<DefinableNameSegment>, CompileTimeDefineValue>;
194
195 fn into_iter(self) -> Self::IntoIter {
196 self.0.into_iter()
197 }
198}
199
200#[turbo_tasks::value_impl]
201impl CompileTimeDefines {
202 #[turbo_tasks::function]
203 pub fn empty() -> Vc<Self> {
204 Vc::cell(FxIndexMap::default())
205 }
206
207 #[turbo_tasks::function]
208 pub fn individual(&self) -> Vc<CompileTimeDefinesIndividual> {
209 let mut map: FxIndexMap<Vec<DefinableNameSegment>, ResolvedVc<CompileTimeDefineValue>> =
210 self.0
211 .iter()
212 .map(|(key, value)| (key.clone(), value.clone().resolved_cell()))
213 .collect();
214
215 map.sort_keys();
217
218 Vc::cell(map)
219 }
220}
221
222#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs, NonLocalValue)]
223pub enum InputRelativeConstant {
224 DirName,
226 FileName,
228}
229
230#[turbo_tasks::value]
231#[derive(Debug, Clone)]
232pub enum FreeVarReference {
233 EcmaScriptModule {
234 request: RcStr,
235 lookup_path: Option<FileSystemPath>,
236 export: Option<RcStr>,
237 },
238 Ident(RcStr),
239 Member(RcStr, RcStr),
240 Value(CompileTimeDefineValue),
241 InputRelative(InputRelativeConstant),
242 Error(RcStr),
243}
244
245impl From<bool> for FreeVarReference {
246 fn from(value: bool) -> Self {
247 Self::Value(value.into())
248 }
249}
250
251impl From<String> for FreeVarReference {
252 fn from(value: String) -> Self {
253 Self::Value(value.into())
254 }
255}
256impl From<RcStr> for FreeVarReference {
257 fn from(value: RcStr) -> Self {
258 Self::Value(value.into())
259 }
260}
261
262impl From<&str> for FreeVarReference {
263 fn from(value: &str) -> Self {
264 Self::Value(value.into())
265 }
266}
267
268impl From<CompileTimeDefineValue> for FreeVarReference {
269 fn from(value: CompileTimeDefineValue) -> Self {
270 Self::Value(value)
271 }
272}
273
274#[turbo_tasks::value(transparent)]
275#[derive(Debug, Clone)]
276pub struct FreeVarReferences(pub FxIndexMap<Vec<DefinableNameSegment>, FreeVarReference>);
277
278#[turbo_tasks::value(transparent)]
280#[derive(Debug, Clone)]
281pub struct FreeVarReferencesIndividual(
282 pub FxIndexMap<
283 DefinableNameSegment,
284 FxIndexMap<Vec<DefinableNameSegment>, ResolvedVc<FreeVarReference>>,
285 >,
286);
287
288#[turbo_tasks::value_impl]
289impl FreeVarReferences {
290 #[turbo_tasks::function]
291 pub fn empty() -> Vc<Self> {
292 Vc::cell(FxIndexMap::default())
293 }
294
295 #[turbo_tasks::function]
296 pub fn individual(&self) -> Vc<FreeVarReferencesIndividual> {
297 let mut result: FxIndexMap<
298 DefinableNameSegment,
299 FxIndexMap<Vec<DefinableNameSegment>, ResolvedVc<FreeVarReference>>,
300 > = FxIndexMap::default();
301
302 for (key, value) in &self.0 {
303 let (last_key, key) = key.split_last().unwrap();
304 result
305 .entry(last_key.clone())
306 .or_default()
307 .insert(key.to_vec(), value.clone().resolved_cell());
308 }
309
310 result.sort_keys();
312 result.iter_mut().for_each(|(_, inner)| inner.sort_keys());
313
314 Vc::cell(result)
315 }
316}
317
318#[turbo_tasks::value(shared)]
319#[derive(Debug, Clone)]
320pub struct CompileTimeInfo {
321 pub environment: ResolvedVc<Environment>,
322 pub defines: ResolvedVc<CompileTimeDefines>,
323 pub free_var_references: ResolvedVc<FreeVarReferences>,
324}
325
326impl CompileTimeInfo {
327 pub fn builder(environment: ResolvedVc<Environment>) -> CompileTimeInfoBuilder {
328 CompileTimeInfoBuilder {
329 environment,
330 defines: None,
331 free_var_references: None,
332 }
333 }
334}
335
336#[turbo_tasks::value_impl]
337impl CompileTimeInfo {
338 #[turbo_tasks::function]
339 pub async fn new(environment: ResolvedVc<Environment>) -> Result<Vc<Self>> {
340 Ok(CompileTimeInfo {
341 environment,
342 defines: CompileTimeDefines::empty().to_resolved().await?,
343 free_var_references: FreeVarReferences::empty().to_resolved().await?,
344 }
345 .cell())
346 }
347
348 #[turbo_tasks::function]
349 pub fn environment(&self) -> Vc<Environment> {
350 *self.environment
351 }
352}
353
354pub struct CompileTimeInfoBuilder {
355 environment: ResolvedVc<Environment>,
356 defines: Option<ResolvedVc<CompileTimeDefines>>,
357 free_var_references: Option<ResolvedVc<FreeVarReferences>>,
358}
359
360impl CompileTimeInfoBuilder {
361 pub fn defines(mut self, defines: ResolvedVc<CompileTimeDefines>) -> Self {
362 self.defines = Some(defines);
363 self
364 }
365
366 pub fn free_var_references(
367 mut self,
368 free_var_references: ResolvedVc<FreeVarReferences>,
369 ) -> Self {
370 self.free_var_references = Some(free_var_references);
371 self
372 }
373
374 pub async fn build(self) -> Result<CompileTimeInfo> {
375 Ok(CompileTimeInfo {
376 environment: self.environment,
377 defines: match self.defines {
378 Some(defines) => defines,
379 None => CompileTimeDefines::empty().to_resolved().await?,
380 },
381 free_var_references: match self.free_var_references {
382 Some(free_var_references) => free_var_references,
383 None => FreeVarReferences::empty().to_resolved().await?,
384 },
385 })
386 }
387
388 pub async fn cell(self) -> Result<Vc<CompileTimeInfo>> {
389 Ok(self.build().await?.cell())
390 }
391}
392
393#[cfg(test)]
394mod test {
395 use turbo_rcstr::rcstr;
396 use turbo_tasks::FxIndexMap;
397
398 use crate::compile_time_info::{DefinableNameSegment, FreeVarReference, FreeVarReferences};
399
400 #[test]
401 fn macro_parser() {
402 assert_eq!(
403 free_var_references!(
404 FOO = "bar",
405 FOO = false,
406 Buffer = FreeVarReference::EcmaScriptModule {
407 request: rcstr!("node:buffer"),
408 lookup_path: None,
409 export: Some(rcstr!("Buffer")),
410 },
411 ),
412 FreeVarReferences(FxIndexMap::from_iter(vec![
413 (
414 vec![rcstr!("FOO").into()],
415 FreeVarReference::Value(rcstr!("bar").into())
416 ),
417 (
418 vec![rcstr!("FOO").into()],
419 FreeVarReference::Value(false.into())
420 ),
421 (
422 vec![rcstr!("Buffer").into()],
423 FreeVarReference::EcmaScriptModule {
424 request: rcstr!("node:buffer"),
425 lookup_path: None,
426 export: Some(rcstr!("Buffer")),
427 }
428 ),
429 ]))
430 );
431 }
432
433 #[test]
434 fn macro_parser_typeof() {
435 assert_eq!(
436 free_var_references!(
437 typeof x = "a",
438 typeof x.y = "b",
439 typeof x.y.z = "c"
440 ),
441 FreeVarReferences(FxIndexMap::from_iter(vec![
442 (
443 vec![rcstr!("x").into(), DefinableNameSegment::TypeOf],
444 FreeVarReference::Value(rcstr!("a").into())
445 ),
446 (
447 vec![
448 rcstr!("x").into(),
449 rcstr!("y").into(),
450 DefinableNameSegment::TypeOf
451 ],
452 FreeVarReference::Value(rcstr!("b").into())
453 ),
454 (
455 vec![
456 rcstr!("x").into(),
457 rcstr!("y").into(),
458 rcstr!("z").into(),
459 DefinableNameSegment::TypeOf
460 ],
461 FreeVarReference::Value(rcstr!("b").into())
462 ),
463 (
464 vec![
465 rcstr!("x").into(),
466 rcstr!("y").into(),
467 rcstr!("z").into(),
468 DefinableNameSegment::TypeOf
469 ],
470 FreeVarReference::Value(rcstr!("c").into())
471 )
472 ]))
473 );
474 }
475}