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