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(),
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::ChildProcess | WellKnownObjectKind::ChildProcessDefault => {
613 child_process_module_member(kind, prop)
614 }
615 WellKnownObjectKind::OsModule | WellKnownObjectKind::OsModuleDefault => {
616 os_module_member(kind, prop)
617 }
618 WellKnownObjectKind::NodeProcess => node_process_member(prop, compile_time_info).await?,
619 WellKnownObjectKind::NodePreGyp => node_pre_gyp(prop),
620 WellKnownObjectKind::NodeExpressApp => express(prop),
621 WellKnownObjectKind::NodeProtobufLoader => protobuf_loader(prop),
622 #[allow(unreachable_patterns)]
623 _ => {
624 return Ok((
625 JsValue::member(Box::new(JsValue::WellKnownObject(kind)), Box::new(prop)),
626 false,
627 ));
628 }
629 };
630 Ok((new_value, true))
631}
632
633fn global_object(prop: JsValue) -> JsValue {
634 match prop.as_str() {
635 Some("assign") => JsValue::WellKnownFunction(WellKnownFunctionKind::ObjectAssign),
636 _ => JsValue::unknown(
637 JsValue::member(
638 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::GlobalObject)),
639 Box::new(prop),
640 ),
641 true,
642 "unsupported property on global Object",
643 ),
644 }
645}
646
647fn path_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
648 match (kind, prop.as_str()) {
649 (.., Some("join")) => JsValue::WellKnownFunction(WellKnownFunctionKind::PathJoin),
650 (.., Some("dirname")) => JsValue::WellKnownFunction(WellKnownFunctionKind::PathDirname),
651 (.., Some("resolve")) => {
652 JsValue::WellKnownFunction(WellKnownFunctionKind::PathResolve(Box::new(JsValue::from(
654 "",
655 ))))
656 }
657 (WellKnownObjectKind::PathModule, Some("default")) => {
658 JsValue::WellKnownObject(WellKnownObjectKind::PathModuleDefault)
659 }
660 _ => JsValue::unknown(
661 JsValue::member(
662 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::PathModule)),
663 Box::new(prop),
664 ),
665 true,
666 "unsupported property on Node.js path module",
667 ),
668 }
669}
670
671fn fs_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
672 if let Some(word) = prop.as_str() {
673 match (kind, word) {
674 (
675 ..,
676 "realpath" | "realpathSync" | "stat" | "statSync" | "existsSync"
677 | "createReadStream" | "exists" | "open" | "openSync" | "readFile" | "readFileSync",
678 ) => {
679 return JsValue::WellKnownFunction(WellKnownFunctionKind::FsReadMethod(
680 word.into(),
681 ));
682 }
683 (WellKnownObjectKind::FsModule | WellKnownObjectKind::FsModuleDefault, "promises") => {
684 return JsValue::WellKnownObject(WellKnownObjectKind::FsModulePromises);
685 }
686 (WellKnownObjectKind::FsModule, "default") => {
687 return JsValue::WellKnownObject(WellKnownObjectKind::FsModuleDefault);
688 }
689 _ => {}
690 }
691 }
692 JsValue::unknown(
693 JsValue::member(
694 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::FsModule)),
695 Box::new(prop),
696 ),
697 true,
698 "unsupported property on Node.js fs module",
699 )
700}
701
702fn fs_extra_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
703 if let Some(word) = prop.as_str() {
704 match (kind, word) {
705 (
707 ..,
708 "realpath" | "realpathSync" | "stat" | "statSync" | "existsSync"
709 | "createReadStream" | "exists" | "open" | "openSync" | "readFile" | "readFileSync",
710 ) => {
711 return JsValue::WellKnownFunction(WellKnownFunctionKind::FsReadMethod(
712 word.into(),
713 ));
714 }
715 (
717 ..,
718 "pathExists" | "pathExistsSync" | "readJson" | "readJSON" | "readJsonSync"
719 | "readJSONSync",
720 ) => {
721 return JsValue::WellKnownFunction(WellKnownFunctionKind::FsReadMethod(
722 word.into(),
723 ));
724 }
725 (WellKnownObjectKind::FsExtraModule, "default") => {
726 return JsValue::WellKnownObject(WellKnownObjectKind::FsExtraModuleDefault);
727 }
728 _ => {}
729 }
730 }
731 JsValue::unknown(
732 JsValue::member(
733 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::FsExtraModule)),
734 Box::new(prop),
735 ),
736 true,
737 "unsupported property on fs-extra module",
738 )
739}
740
741fn module_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
742 match (kind, prop.as_str()) {
743 (.., Some("createRequire")) => {
744 JsValue::WellKnownFunction(WellKnownFunctionKind::CreateRequire)
745 }
746 (WellKnownObjectKind::ModuleModule, Some("default")) => {
747 JsValue::WellKnownObject(WellKnownObjectKind::ModuleModuleDefault)
748 }
749 _ => JsValue::unknown(
750 JsValue::member(
751 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::ModuleModule)),
752 Box::new(prop),
753 ),
754 true,
755 "unsupported property on Node.js `module` module",
756 ),
757 }
758}
759
760fn url_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
761 match (kind, prop.as_str()) {
762 (.., Some("pathToFileURL")) => {
763 JsValue::WellKnownFunction(WellKnownFunctionKind::PathToFileUrl)
764 }
765 (WellKnownObjectKind::UrlModuleDefault, Some("default")) => {
766 JsValue::WellKnownObject(WellKnownObjectKind::UrlModuleDefault)
767 }
768 _ => JsValue::unknown(
769 JsValue::member(
770 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::UrlModule)),
771 Box::new(prop),
772 ),
773 true,
774 "unsupported property on Node.js url module",
775 ),
776 }
777}
778
779fn child_process_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
780 let prop_str = prop.as_str();
781 match (kind, prop_str) {
782 (.., Some("spawn" | "spawnSync" | "execFile" | "execFileSync")) => {
783 JsValue::WellKnownFunction(WellKnownFunctionKind::ChildProcessSpawnMethod(
784 prop_str.unwrap().into(),
785 ))
786 }
787 (.., Some("fork")) => JsValue::WellKnownFunction(WellKnownFunctionKind::ChildProcessFork),
788 (WellKnownObjectKind::ChildProcess, Some("default")) => {
789 JsValue::WellKnownObject(WellKnownObjectKind::ChildProcessDefault)
790 }
791
792 _ => JsValue::unknown(
793 JsValue::member(
794 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::ChildProcess)),
795 Box::new(prop),
796 ),
797 true,
798 "unsupported property on Node.js child_process module",
799 ),
800 }
801}
802
803fn os_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
804 match (kind, prop.as_str()) {
805 (.., Some("platform")) => JsValue::WellKnownFunction(WellKnownFunctionKind::OsPlatform),
806 (.., Some("arch")) => JsValue::WellKnownFunction(WellKnownFunctionKind::OsArch),
807 (.., Some("endianness")) => JsValue::WellKnownFunction(WellKnownFunctionKind::OsEndianness),
808 (WellKnownObjectKind::OsModule, Some("default")) => {
809 JsValue::WellKnownObject(WellKnownObjectKind::OsModuleDefault)
810 }
811 _ => JsValue::unknown(
812 JsValue::member(
813 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::OsModule)),
814 Box::new(prop),
815 ),
816 true,
817 "unsupported property on Node.js os module",
818 ),
819 }
820}
821
822async fn node_process_member(
823 prop: JsValue,
824 compile_time_info: Vc<CompileTimeInfo>,
825) -> Result<JsValue> {
826 Ok(match prop.as_str() {
827 Some("arch") => compile_time_info
828 .environment()
829 .compile_target()
830 .await?
831 .arch
832 .as_str()
833 .into(),
834 Some("platform") => compile_time_info
835 .environment()
836 .compile_target()
837 .await?
838 .platform
839 .as_str()
840 .into(),
841 Some("cwd") => JsValue::WellKnownFunction(WellKnownFunctionKind::ProcessCwd),
842 Some("argv") => JsValue::WellKnownObject(WellKnownObjectKind::NodeProcessArgv),
843 Some("env") => JsValue::WellKnownObject(WellKnownObjectKind::NodeProcessEnv),
844 _ => JsValue::unknown(
845 JsValue::member(
846 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::NodeProcess)),
847 Box::new(prop),
848 ),
849 true,
850 "unsupported property on Node.js process object",
851 ),
852 })
853}
854
855fn node_pre_gyp(prop: JsValue) -> JsValue {
856 match prop.as_str() {
857 Some("find") => JsValue::WellKnownFunction(WellKnownFunctionKind::NodePreGypFind),
858 _ => JsValue::unknown(
859 JsValue::member(
860 Box::new(JsValue::WellKnownObject(WellKnownObjectKind::NodePreGyp)),
861 Box::new(prop),
862 ),
863 true,
864 "unsupported property on @mapbox/node-pre-gyp module",
865 ),
866 }
867}
868
869fn express(prop: JsValue) -> JsValue {
870 match prop.as_str() {
871 Some("set") => JsValue::WellKnownFunction(WellKnownFunctionKind::NodeExpressSet),
872 _ => JsValue::unknown(
873 JsValue::member(
874 Box::new(JsValue::WellKnownObject(
875 WellKnownObjectKind::NodeExpressApp,
876 )),
877 Box::new(prop),
878 ),
879 true,
880 "unsupported property on require('express')() object",
881 ),
882 }
883}
884
885fn protobuf_loader(prop: JsValue) -> JsValue {
886 match prop.as_str() {
887 Some("load") | Some("loadSync") => {
888 JsValue::WellKnownFunction(WellKnownFunctionKind::NodeProtobufLoad)
889 }
890 _ => JsValue::unknown(
891 JsValue::member(
892 Box::new(JsValue::WellKnownObject(
893 WellKnownObjectKind::NodeProtobufLoader,
894 )),
895 Box::new(prop),
896 ),
897 true,
898 "unsupported property on require('@grpc/proto-loader') object",
899 ),
900 }
901}