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