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