1use std::mem::take;
2
3use anyhow::Result;
4use turbo_rcstr::rcstr;
5use turbo_tasks::Vc;
6use turbopack_core::compile_time_info::CompileTimeInfo;
7use url::Url;
8
9use super::{
10 ConstantValue, JsValue, JsValueUrlKind, ModuleValue, WellKnownFunctionKind, WellKnownObjectKind,
11};
12use crate::analyzer::RequireContextValue;
13
14pub async fn replace_well_known(
15 value: JsValue,
16 compile_time_info: Vc<CompileTimeInfo>,
17 allow_project_root_tracing: bool,
18) -> Result<(JsValue, bool)> {
19 Ok(match value {
20 JsValue::Call(_, call) if matches!(call.callee(), JsValue::WellKnownFunction(_)) => {
21 let (callee, args) = call.into_parts();
22 let JsValue::WellKnownFunction(kind) = callee else {
23 unreachable!()
24 };
25 (
26 well_known_function_call(
27 kind,
28 JsValue::unknown_empty(false, rcstr!("this is not analyzed yet")),
29 args,
30 compile_time_info,
31 allow_project_root_tracing,
32 )
33 .await?,
34 true,
35 )
36 }
37 JsValue::Call(total, call) => {
38 if call.args().len() == 1
41 && let JsValue::WellKnownObject(_) = &call.args()[0]
42 {
43 return Ok((call.args()[0].clone(), true));
44 }
45 (JsValue::Call(total, call), false)
46 }
47 JsValue::Member(_, box JsValue::WellKnownObject(kind), box prop) => {
48 well_known_object_member(kind, prop, compile_time_info).await?
49 }
50 JsValue::Member(_, box JsValue::WellKnownFunction(kind), box prop) => {
51 well_known_function_member(kind, prop)
52 }
53 JsValue::Member(_, box JsValue::Array { .. }, box ref prop) => match prop.as_str() {
54 Some("filter") => (
55 JsValue::WellKnownFunction(WellKnownFunctionKind::ArrayFilter),
56 true,
57 ),
58 Some("forEach") => (
59 JsValue::WellKnownFunction(WellKnownFunctionKind::ArrayForEach),
60 true,
61 ),
62 Some("map") => (
63 JsValue::WellKnownFunction(WellKnownFunctionKind::ArrayMap),
64 true,
65 ),
66 _ => (value, false),
67 },
68 JsValue::Member(_, box JsValue::FreeVar(ref name), box ref prop)
70 if &**name == "module"
71 && prop.as_str() == Some("hot")
72 && compile_time_info.await?.hot_module_replacement_enabled =>
73 {
74 (
75 JsValue::WellKnownObject(WellKnownObjectKind::ModuleHot),
76 true,
77 )
78 }
79 _ => (value, false),
80 })
81}
82
83pub async fn well_known_function_call(
84 kind: WellKnownFunctionKind,
85 _this: JsValue,
86 args: Vec<JsValue>,
87 compile_time_info: Vc<CompileTimeInfo>,
88 allow_project_root_tracing: bool,
89) -> Result<JsValue> {
90 Ok(match kind {
91 WellKnownFunctionKind::ObjectAssign => object_assign(args),
92 WellKnownFunctionKind::PathJoin => path_join(args),
93 WellKnownFunctionKind::PathDirname => path_dirname(args),
94 WellKnownFunctionKind::PathResolve(cwd) => path_resolve(*cwd, args),
95 WellKnownFunctionKind::Import => import(args),
96 WellKnownFunctionKind::Require => require(args),
97 WellKnownFunctionKind::RequireContextRequire(value) => {
98 require_context_require(value, args)?
99 }
100 WellKnownFunctionKind::RequireContextRequireKeys(value) => {
101 require_context_require_keys(value, args)?
102 }
103 WellKnownFunctionKind::RequireContextRequireResolve(value) => {
104 require_context_require_resolve(value, args)?
105 }
106 WellKnownFunctionKind::PathToFileUrl => path_to_file_url(args),
107 WellKnownFunctionKind::OsArch => compile_time_info
108 .environment()
109 .compile_target()
110 .await?
111 .arch
112 .as_str()
113 .into(),
114 WellKnownFunctionKind::OsPlatform => compile_time_info
115 .environment()
116 .compile_target()
117 .await?
118 .platform
119 .as_str()
120 .into(),
121 WellKnownFunctionKind::ProcessCwd => {
122 if allow_project_root_tracing
123 && let Some(cwd) = &*compile_time_info.environment().cwd().await?
124 {
125 format!("/ROOT/{}", cwd.path).into()
126 } else {
127 JsValue::unknown(
128 JsValue::call_from_parts(JsValue::WellKnownFunction(kind), args),
129 true,
130 rcstr!("process.cwd is not specified in the environment"),
131 )
132 }
133 }
134 WellKnownFunctionKind::OsEndianness => compile_time_info
135 .environment()
136 .compile_target()
137 .await?
138 .endianness
139 .as_str()
140 .into(),
141 WellKnownFunctionKind::NodeExpress => {
142 JsValue::WellKnownObject(WellKnownObjectKind::NodeExpressApp)
143 }
144 WellKnownFunctionKind::NodeResolveFrom => {
146 JsValue::WellKnownFunction(WellKnownFunctionKind::NodeResolveFrom)
147 }
148
149 _ => JsValue::unknown(
150 JsValue::call_from_parts(JsValue::WellKnownFunction(kind), args),
151 true,
152 rcstr!("unsupported function"),
153 ),
154 })
155}
156
157fn object_assign(args: Vec<JsValue>) -> JsValue {
158 if args.iter().all(|arg| matches!(arg, JsValue::Object { .. })) {
159 if let Some(mut merged_object) = args.into_iter().reduce(|mut acc, cur| {
160 if let JsValue::Object { parts, mutable, .. } = &mut acc
161 && let JsValue::Object {
162 parts: next_parts,
163 mutable: next_mutable,
164 ..
165 } = &cur
166 {
167 parts.extend_from_slice(next_parts);
168 *mutable |= *next_mutable;
169 }
170 acc
171 }) {
172 merged_object.update_total_nodes();
173 merged_object
174 } else {
175 JsValue::unknown(
176 JsValue::call_from_iter(
177 JsValue::WellKnownFunction(WellKnownFunctionKind::ObjectAssign),
178 [],
179 ),
180 true,
181 rcstr!("empty arguments for Object.assign"),
182 )
183 }
184 } else {
185 JsValue::unknown(
186 JsValue::call_from_parts(
187 JsValue::WellKnownFunction(WellKnownFunctionKind::ObjectAssign),
188 args,
189 ),
190 true,
191 rcstr!("only const object assign is supported"),
192 )
193 }
194}
195
196fn path_join(args: Vec<JsValue>) -> JsValue {
197 if args.is_empty() {
198 return rcstr!(".").into();
199 }
200 let mut parts = Vec::new();
201 for item in args {
202 if let Some(str) = item.as_str() {
203 let split = str.split('/');
204 parts.extend(split.map(|s| s.into()));
205 } else {
206 parts.push(item);
207 }
208 }
209 let mut results_final = Vec::new();
210 let mut results: Vec<JsValue> = Vec::new();
211 for item in parts {
212 if let Some(str) = item.as_str() {
213 match str {
214 "" | "." => {
215 if results_final.is_empty() && results.is_empty() {
216 results_final.push(item);
217 }
218 }
219 ".." => {
220 if results.pop().is_none() {
221 results_final.push(item);
222 }
223 }
224 _ => results.push(item),
225 }
226 } else {
227 results_final.append(&mut results);
228 results_final.push(item);
229 }
230 }
231 results_final.append(&mut results);
232 let mut iter = results_final.into_iter();
233 let first = iter.next().unwrap();
234 let mut last_is_str = first.as_str().is_some();
235 results.push(first);
236 for part in iter {
237 let is_str = part.as_str().is_some();
238 if last_is_str && is_str {
239 results.push(rcstr!("/").into());
240 } else {
241 results.push(JsValue::alternatives(vec![
242 rcstr!("/").into(),
243 rcstr!("").into(),
244 ]));
245 }
246 results.push(part);
247 last_is_str = is_str;
248 }
249 JsValue::concat(results)
250}
251
252fn path_resolve(cwd: JsValue, mut args: Vec<JsValue>) -> JsValue {
253 if args.is_empty() {
256 return JsValue::unknown_empty(false, rcstr!("cwd is not static analyzable"));
257 }
258 if args.len() == 1 {
259 return args.into_iter().next().unwrap();
260 }
261
262 for (idx, arg) in args.iter().enumerate().rev() {
264 if idx != 0
265 && let Some(str) = arg.as_str()
266 && str.starts_with('/')
267 {
268 return path_resolve(cwd, args.drain(idx..).collect());
269 }
270 }
271
272 let mut results_final = Vec::new();
273 let mut results: Vec<JsValue> = Vec::new();
274 for item in args {
275 if let Some(str) = item.as_str() {
276 for str in str.split('/') {
277 match str {
278 "" | "." => {
279 if results_final.is_empty() && results.is_empty() {
280 results_final.push(str.into());
281 }
282 }
283 ".." => {
284 if results.pop().is_none() {
285 results_final.push(rcstr!("..").into());
286 }
287 }
288 _ => results.push(str.into()),
289 }
290 }
291 } else {
292 results_final.append(&mut results);
293 results_final.push(item);
294 }
295 }
296 results_final.append(&mut results);
297 let mut iter = results_final.into_iter();
298 let first = iter.next().unwrap();
299
300 let is_already_absolute =
301 first.is_empty_string() == Some(true) || first.starts_with("/") == Some(true);
302
303 let mut last_was_str = first.as_str().is_some();
304
305 if !is_already_absolute {
306 results.push(cwd);
307 }
308
309 results.push(first);
310 for part in iter {
311 let is_str = part.as_str().is_some();
312 if last_was_str && is_str {
313 results.push(rcstr!("/").into());
314 } else {
315 results.push(JsValue::alternatives(vec![
316 rcstr!("/").into(),
317 rcstr!("").into(),
318 ]));
319 }
320 results.push(part);
321 last_was_str = is_str;
322 }
323
324 JsValue::concat(results)
325}
326
327fn path_dirname(mut args: Vec<JsValue>) -> JsValue {
328 if let Some(arg) = args.iter_mut().next() {
329 if let Some(str) = arg.as_str() {
330 if let Some(i) = str.rfind('/') {
331 return JsValue::Constant(ConstantValue::Str(str[..i].to_string().into()));
332 } else {
333 return JsValue::Constant(ConstantValue::Str(rcstr!("").into()));
334 }
335 } else if let JsValue::Concat(_, items) = arg
336 && let Some(last) = items.last_mut()
337 && let Some(str) = last.as_str()
338 && let Some(i) = str.rfind('/')
339 {
340 *last = JsValue::Constant(ConstantValue::Str(str[..i].to_string().into()));
341 return take(arg);
342 }
343 }
344 JsValue::unknown(
345 JsValue::call_from_parts(
346 JsValue::WellKnownFunction(WellKnownFunctionKind::PathDirname),
347 args,
348 ),
349 true,
350 rcstr!("path.dirname with unsupported arguments"),
351 )
352}
353
354pub fn import(args: Vec<JsValue>) -> JsValue {
357 match &args[..] {
358 [JsValue::Constant(ConstantValue::Str(v))] => {
359 JsValue::promise(JsValue::Module(ModuleValue {
360 module: v.as_atom().into_owned().into(),
361 annotations: None,
362 }))
363 }
364 _ => JsValue::unknown(
365 JsValue::call_from_parts(
366 JsValue::WellKnownFunction(WellKnownFunctionKind::Import),
367 args,
368 ),
369 true,
370 rcstr!("only a single constant argument is supported"),
371 ),
372 }
373}
374
375fn require(args: Vec<JsValue>) -> JsValue {
378 if args.len() == 1 {
379 if let Some(s) = args[0].as_str() {
380 JsValue::Module(ModuleValue {
381 module: s.into(),
382 annotations: None,
383 })
384 } else {
385 JsValue::unknown(
386 JsValue::call_from_parts(
387 JsValue::WellKnownFunction(WellKnownFunctionKind::Require),
388 args,
389 ),
390 true,
391 rcstr!("only constant argument is supported"),
392 )
393 }
394 } else {
395 JsValue::unknown(
396 JsValue::call_from_parts(
397 JsValue::WellKnownFunction(WellKnownFunctionKind::Require),
398 args,
399 ),
400 true,
401 rcstr!("only a single argument is supported"),
402 )
403 }
404}
405
406fn require_context_require(val: Box<RequireContextValue>, args: Vec<JsValue>) -> Result<JsValue> {
408 if args.is_empty() {
409 return Ok(JsValue::unknown(
410 JsValue::call_from_parts(
411 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContextRequire(val)),
412 args,
413 ),
414 true,
415 rcstr!(
416 "require.context(...).require() requires an argument specifying the module path"
417 ),
418 ));
419 }
420
421 let Some(s) = args[0].as_str() else {
422 return Ok(JsValue::unknown(
423 JsValue::call_from_parts(
424 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContextRequire(val)),
425 args,
426 ),
427 true,
428 rcstr!(
429 "require.context(...).require() only accepts a single, constant string argument"
430 ),
431 ));
432 };
433
434 let Some(m) = val.0.get(s) else {
435 return Ok(JsValue::unknown(
436 JsValue::call_from_parts(
437 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContextRequire(val)),
438 args,
439 ),
440 true,
441 rcstr!(
442 "require.context(...).require() can only be called with an argument that's in the \
443 context"
444 ),
445 ));
446 };
447
448 Ok(JsValue::Module(ModuleValue {
449 module: m.to_string().into(),
450 annotations: None,
451 }))
452}
453
454fn require_context_require_keys(
456 val: Box<RequireContextValue>,
457 args: Vec<JsValue>,
458) -> Result<JsValue> {
459 Ok(if args.is_empty() {
460 JsValue::array(val.0.keys().cloned().map(|k| k.into()).collect())
461 } else {
462 JsValue::unknown(
463 JsValue::call_from_parts(
464 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContextRequireKeys(val)),
465 args,
466 ),
467 true,
468 rcstr!("require.context(...).keys() does not accept arguments"),
469 )
470 })
471}
472
473fn require_context_require_resolve(
475 val: Box<RequireContextValue>,
476 args: Vec<JsValue>,
477) -> Result<JsValue> {
478 if args.len() != 1 {
479 return Ok(JsValue::unknown(
480 JsValue::call_from_parts(
481 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContextRequireResolve(
482 val,
483 )),
484 args,
485 ),
486 true,
487 rcstr!(
488 "require.context(...).resolve() only accepts a single, constant string argument"
489 ),
490 ));
491 }
492
493 let Some(s) = args[0].as_str() else {
494 return Ok(JsValue::unknown(
495 JsValue::call_from_parts(
496 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContextRequireResolve(
497 val,
498 )),
499 args,
500 ),
501 true,
502 rcstr!(
503 "require.context(...).resolve() only accepts a single, constant string argument"
504 ),
505 ));
506 };
507
508 let Some(m) = val.0.get(s) else {
509 return Ok(JsValue::unknown(
510 JsValue::call_from_parts(
511 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContextRequireResolve(
512 val,
513 )),
514 args,
515 ),
516 true,
517 rcstr!(
518 "require.context(...).resolve() can only be called with an argument that's in the \
519 context"
520 ),
521 ));
522 };
523
524 Ok(m.as_str().into())
525}
526
527fn path_to_file_url(args: Vec<JsValue>) -> JsValue {
528 if args.len() == 1 {
529 if let Some(path) = args[0].as_str() {
530 Url::from_file_path(path)
531 .map(|url| JsValue::Url(String::from(url).into(), JsValueUrlKind::Absolute))
532 .unwrap_or_else(|_| {
533 JsValue::unknown(
534 JsValue::call_from_parts(
535 JsValue::WellKnownFunction(WellKnownFunctionKind::PathToFileUrl),
536 args,
537 ),
538 true,
539 rcstr!("url not parseable: path is relative or has an invalid prefix"),
540 )
541 })
542 } else {
543 JsValue::unknown(
544 JsValue::call_from_parts(
545 JsValue::WellKnownFunction(WellKnownFunctionKind::PathToFileUrl),
546 args,
547 ),
548 true,
549 rcstr!("only constant argument is supported"),
550 )
551 }
552 } else {
553 JsValue::unknown(
554 JsValue::call_from_parts(
555 JsValue::WellKnownFunction(WellKnownFunctionKind::PathToFileUrl),
556 args,
557 ),
558 true,
559 rcstr!("only a single argument is supported"),
560 )
561 }
562}
563
564fn well_known_function_member(kind: WellKnownFunctionKind, prop: JsValue) -> (JsValue, bool) {
565 let new_value = match (kind, prop.as_str()) {
566 (WellKnownFunctionKind::Require, Some("resolve")) => {
567 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireResolve)
568 }
569 (WellKnownFunctionKind::Require, Some("cache")) => {
570 JsValue::WellKnownObject(WellKnownObjectKind::RequireCache)
571 }
572 (WellKnownFunctionKind::Require, Some("context")) => {
573 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContext)
574 }
575 (WellKnownFunctionKind::RequireContextRequire(val), Some("resolve")) => {
576 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContextRequireResolve(val))
577 }
578 (WellKnownFunctionKind::RequireContextRequire(val), Some("keys")) => {
579 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContextRequireKeys(val))
580 }
581 (WellKnownFunctionKind::NodeStrongGlobalize, Some("SetRootDir")) => {
582 JsValue::WellKnownFunction(WellKnownFunctionKind::NodeStrongGlobalizeSetRootDir)
583 }
584 (WellKnownFunctionKind::NodeResolveFrom, Some("silent")) => {
585 JsValue::WellKnownFunction(WellKnownFunctionKind::NodeResolveFrom)
586 }
587 (WellKnownFunctionKind::Import, Some("meta")) => {
588 JsValue::WellKnownObject(WellKnownObjectKind::ImportMeta)
589 }
590 #[allow(unreachable_patterns)]
591 (kind, _) => {
592 return (
593 JsValue::member(Box::new(JsValue::WellKnownFunction(kind)), Box::new(prop)),
594 false,
595 );
596 }
597 };
598 (new_value, true)
599}
600
601async fn well_known_object_member(
602 kind: WellKnownObjectKind,
603 prop: JsValue,
604 compile_time_info: Vc<CompileTimeInfo>,
605) -> Result<(JsValue, bool)> {
606 let new_value = match kind {
607 WellKnownObjectKind::GlobalObject => global_object(prop),
608 WellKnownObjectKind::PathModule | WellKnownObjectKind::PathModuleDefault => {
609 path_module_member(kind, prop, compile_time_info).await?
610 }
611 WellKnownObjectKind::FsModule
612 | WellKnownObjectKind::FsModuleDefault
613 | WellKnownObjectKind::FsModulePromises => fs_module_member(kind, prop),
614 WellKnownObjectKind::FsExtraModule | WellKnownObjectKind::FsExtraModuleDefault => {
615 fs_extra_module_member(kind, prop)
616 }
617 WellKnownObjectKind::ModuleModule | WellKnownObjectKind::ModuleModuleDefault => {
618 module_module_member(kind, prop)
619 }
620 WellKnownObjectKind::UrlModule | WellKnownObjectKind::UrlModuleDefault => {
621 url_module_member(kind, prop)
622 }
623 WellKnownObjectKind::WorkerThreadsModule
624 | WellKnownObjectKind::WorkerThreadsModuleDefault => {
625 worker_threads_module_member(kind, prop)
626 }
627 WellKnownObjectKind::ChildProcessModule
628 | WellKnownObjectKind::ChildProcessModuleDefault => child_process_module_member(kind, prop),
629 WellKnownObjectKind::OsModule | WellKnownObjectKind::OsModuleDefault => {
630 os_module_member(kind, prop)
631 }
632 WellKnownObjectKind::NodeProcessModule => {
633 node_process_member(prop, compile_time_info).await?
634 }
635 WellKnownObjectKind::NodePreGyp => node_pre_gyp(prop),
636 WellKnownObjectKind::NodeExpressApp => express(prop),
637 WellKnownObjectKind::NodeProtobufLoader => protobuf_loader(prop),
638 WellKnownObjectKind::ImportMeta => match prop.as_str() {
639 Some("turbopackHot") if compile_time_info.await?.hot_module_replacement_enabled => {
641 JsValue::WellKnownObject(WellKnownObjectKind::ModuleHot)
642 }
643 Some("glob") => JsValue::WellKnownFunction(WellKnownFunctionKind::ImportMetaGlob),
647 _ => {
648 return Ok((
649 JsValue::member(Box::new(JsValue::WellKnownObject(kind)), Box::new(prop)),
650 false,
651 ));
652 }
653 },
654 WellKnownObjectKind::ModuleHot => match prop.as_str() {
655 Some("accept") => JsValue::WellKnownFunction(WellKnownFunctionKind::ModuleHotAccept),
656 Some("decline") => JsValue::WellKnownFunction(WellKnownFunctionKind::ModuleHotDecline),
657 _ => {
658 return Ok((
659 JsValue::unknown(
660 JsValue::member(Box::new(JsValue::WellKnownObject(kind)), Box::new(prop)),
661 true,
662 rcstr!("unsupported property on module.hot"),
663 ),
664 true,
665 ));
666 }
667 },
668 #[allow(unreachable_patterns)]
669 _ => {
670 return Ok((
671 JsValue::member(Box::new(JsValue::WellKnownObject(kind)), Box::new(prop)),
672 false,
673 ));
674 }
675 };
676 Ok((new_value, true))
677}
678
679fn global_object(prop: JsValue) -> JsValue {
680 match prop.as_str() {
681 Some("assign") => JsValue::WellKnownFunction(WellKnownFunctionKind::ObjectAssign),
682 _ => JsValue::unknown(
683 JsValue::member(
684 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::GlobalObject)),
685 Box::new(prop),
686 ),
687 true,
688 rcstr!("unsupported property on global Object"),
689 ),
690 }
691}
692
693async fn path_module_member(
694 kind: WellKnownObjectKind,
695 prop: JsValue,
696 compile_time_info: Vc<CompileTimeInfo>,
697) -> Result<JsValue> {
698 Ok(match (kind, prop.as_str()) {
699 (.., Some("join")) => JsValue::WellKnownFunction(WellKnownFunctionKind::PathJoin),
700 (.., Some("dirname")) => JsValue::WellKnownFunction(WellKnownFunctionKind::PathDirname),
701 (.., Some("resolve")) => {
702 JsValue::WellKnownFunction(WellKnownFunctionKind::PathResolve(Box::new(JsValue::from(
704 "",
705 ))))
706 }
707 (.., Some("sep")) => compile_time_info
708 .environment()
709 .compile_target()
710 .await?
711 .platform
712 .path_separator()
713 .into(),
714 (WellKnownObjectKind::PathModule, Some("default")) => {
715 JsValue::WellKnownObject(WellKnownObjectKind::PathModuleDefault)
716 }
717 _ => JsValue::unknown(
718 JsValue::member(
719 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::PathModule)),
720 Box::new(prop),
721 ),
722 true,
723 rcstr!("unsupported property on Node.js path module"),
724 ),
725 })
726}
727
728fn fs_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
729 if let Some(word) = prop.as_str() {
730 match (kind, word) {
731 (
732 ..,
733 "realpath" | "realpathSync" | "stat" | "statSync" | "existsSync"
734 | "createReadStream" | "exists" | "open" | "openSync" | "readFile" | "readFileSync",
735 ) => {
736 return JsValue::WellKnownFunction(WellKnownFunctionKind::FsReadMethod(
737 word.into(),
738 ));
739 }
740 (.., "readdir" | "readdirSync") => {
741 return JsValue::WellKnownFunction(WellKnownFunctionKind::FsReadDir);
742 }
743 (WellKnownObjectKind::FsModule | WellKnownObjectKind::FsModuleDefault, "promises") => {
744 return JsValue::WellKnownObject(WellKnownObjectKind::FsModulePromises);
745 }
746 (WellKnownObjectKind::FsModule, "default") => {
747 return JsValue::WellKnownObject(WellKnownObjectKind::FsModuleDefault);
748 }
749 _ => {}
750 }
751 }
752 JsValue::unknown(
753 JsValue::member(
754 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::FsModule)),
755 Box::new(prop),
756 ),
757 true,
758 rcstr!("unsupported property on Node.js fs module"),
759 )
760}
761
762fn fs_extra_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
763 if let Some(word) = prop.as_str() {
764 match (kind, word) {
765 (
767 ..,
768 "realpath" | "realpathSync" | "stat" | "statSync" | "existsSync"
769 | "createReadStream" | "exists" | "open" | "openSync" | "readFile" | "readFileSync",
770 ) => {
771 return JsValue::WellKnownFunction(WellKnownFunctionKind::FsReadMethod(
772 word.into(),
773 ));
774 }
775 (
777 ..,
778 "pathExists" | "pathExistsSync" | "readJson" | "readJSON" | "readJsonSync"
779 | "readJSONSync",
780 ) => {
781 return JsValue::WellKnownFunction(WellKnownFunctionKind::FsReadMethod(
782 word.into(),
783 ));
784 }
785 (WellKnownObjectKind::FsExtraModule, "default") => {
786 return JsValue::WellKnownObject(WellKnownObjectKind::FsExtraModuleDefault);
787 }
788 _ => {}
789 }
790 }
791 JsValue::unknown(
792 JsValue::member(
793 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::FsExtraModule)),
794 Box::new(prop),
795 ),
796 true,
797 rcstr!("unsupported property on fs-extra module"),
798 )
799}
800
801fn module_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
802 match (kind, prop.as_str()) {
803 (.., Some("createRequire")) => {
804 JsValue::WellKnownFunction(WellKnownFunctionKind::CreateRequire)
805 }
806 (WellKnownObjectKind::ModuleModule, Some("default")) => {
807 JsValue::WellKnownObject(WellKnownObjectKind::ModuleModuleDefault)
808 }
809 _ => JsValue::unknown(
810 JsValue::member(
811 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::ModuleModule)),
812 Box::new(prop),
813 ),
814 true,
815 rcstr!("unsupported property on Node.js `module` module"),
816 ),
817 }
818}
819
820fn url_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
821 match (kind, prop.as_str()) {
822 (.., Some("pathToFileURL")) => {
823 JsValue::WellKnownFunction(WellKnownFunctionKind::PathToFileUrl)
824 }
825 (WellKnownObjectKind::UrlModule, Some("default")) => {
826 JsValue::WellKnownObject(WellKnownObjectKind::UrlModuleDefault)
827 }
828 _ => JsValue::unknown(
829 JsValue::member(
830 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::UrlModule)),
831 Box::new(prop),
832 ),
833 true,
834 rcstr!("unsupported property on Node.js url module"),
835 ),
836 }
837}
838
839fn worker_threads_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
840 match (kind, prop.as_str()) {
841 (.., Some("Worker")) => {
842 JsValue::WellKnownFunction(WellKnownFunctionKind::NodeWorkerConstructor)
843 }
844 (WellKnownObjectKind::WorkerThreadsModule, Some("default")) => {
845 JsValue::WellKnownObject(WellKnownObjectKind::WorkerThreadsModuleDefault)
846 }
847 _ => JsValue::unknown(
848 JsValue::member(
849 Box::new(JsValue::WellKnownObject(
850 WellKnownObjectKind::WorkerThreadsModule,
851 )),
852 Box::new(prop),
853 ),
854 true,
855 rcstr!("unsupported property on Node.js worker_threads module"),
856 ),
857 }
858}
859
860fn child_process_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
861 let prop_str = prop.as_str();
862 match (kind, prop_str) {
863 (.., Some("spawn" | "spawnSync" | "execFile" | "execFileSync")) => {
864 JsValue::WellKnownFunction(WellKnownFunctionKind::ChildProcessSpawnMethod(
865 prop_str.unwrap().into(),
866 ))
867 }
868 (.., Some("fork")) => JsValue::WellKnownFunction(WellKnownFunctionKind::ChildProcessFork),
869 (WellKnownObjectKind::ChildProcessModule, Some("default")) => {
870 JsValue::WellKnownObject(WellKnownObjectKind::ChildProcessModuleDefault)
871 }
872
873 _ => JsValue::unknown(
874 JsValue::member(
875 Box::new(JsValue::WellKnownObject(
876 WellKnownObjectKind::ChildProcessModule,
877 )),
878 Box::new(prop),
879 ),
880 true,
881 rcstr!("unsupported property on Node.js child_process module"),
882 ),
883 }
884}
885
886fn os_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
887 match (kind, prop.as_str()) {
888 (.., Some("platform")) => JsValue::WellKnownFunction(WellKnownFunctionKind::OsPlatform),
889 (.., Some("arch")) => JsValue::WellKnownFunction(WellKnownFunctionKind::OsArch),
890 (.., Some("endianness")) => JsValue::WellKnownFunction(WellKnownFunctionKind::OsEndianness),
891 (WellKnownObjectKind::OsModule, Some("default")) => {
892 JsValue::WellKnownObject(WellKnownObjectKind::OsModuleDefault)
893 }
894 _ => JsValue::unknown(
895 JsValue::member(
896 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::OsModule)),
897 Box::new(prop),
898 ),
899 true,
900 rcstr!("unsupported property on Node.js os module"),
901 ),
902 }
903}
904
905async fn node_process_member(
906 prop: JsValue,
907 compile_time_info: Vc<CompileTimeInfo>,
908) -> Result<JsValue> {
909 Ok(match prop.as_str() {
910 Some("arch") => compile_time_info
911 .environment()
912 .compile_target()
913 .await?
914 .arch
915 .as_str()
916 .into(),
917 Some("platform") => compile_time_info
918 .environment()
919 .compile_target()
920 .await?
921 .platform
922 .as_str()
923 .into(),
924 Some("cwd") => JsValue::WellKnownFunction(WellKnownFunctionKind::ProcessCwd),
925 Some("argv") => JsValue::WellKnownObject(WellKnownObjectKind::NodeProcessArgv),
926 Some("env") => JsValue::WellKnownObject(WellKnownObjectKind::NodeProcessEnv),
927 _ => JsValue::unknown(
928 JsValue::member(
929 Box::new(JsValue::WellKnownObject(
930 WellKnownObjectKind::NodeProcessModule,
931 )),
932 Box::new(prop),
933 ),
934 true,
935 rcstr!("unsupported property on Node.js process object"),
936 ),
937 })
938}
939
940fn node_pre_gyp(prop: JsValue) -> JsValue {
941 match prop.as_str() {
942 Some("find") => JsValue::WellKnownFunction(WellKnownFunctionKind::NodePreGypFind),
943 _ => JsValue::unknown(
944 JsValue::member(
945 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::NodePreGyp)),
946 Box::new(prop),
947 ),
948 true,
949 rcstr!("unsupported property on @mapbox/node-pre-gyp module"),
950 ),
951 }
952}
953
954fn express(prop: JsValue) -> JsValue {
955 match prop.as_str() {
956 Some("set") => JsValue::WellKnownFunction(WellKnownFunctionKind::NodeExpressSet),
957 _ => JsValue::unknown(
958 JsValue::member(
959 Box::new(JsValue::WellKnownObject(
960 WellKnownObjectKind::NodeExpressApp,
961 )),
962 Box::new(prop),
963 ),
964 true,
965 rcstr!("unsupported property on require('express')() object"),
966 ),
967 }
968}
969
970fn protobuf_loader(prop: JsValue) -> JsValue {
971 match prop.as_str() {
972 Some("load") | Some("loadSync") => {
973 JsValue::WellKnownFunction(WellKnownFunctionKind::NodeProtobufLoad)
974 }
975 _ => JsValue::unknown(
976 JsValue::member(
977 Box::new(JsValue::WellKnownObject(
978 WellKnownObjectKind::NodeProtobufLoader,
979 )),
980 Box::new(prop),
981 ),
982 true,
983 rcstr!("unsupported property on require('@grpc/proto-loader') object"),
984 ),
985 }
986}