1use crate::host::{with_host, JsObj};
19use fusevm::Value;
20
21pub mod assert;
22pub mod async_hooks;
23pub mod buffer;
24pub mod child_process;
25pub mod cluster;
26pub mod console;
27pub mod crypto;
28pub mod date;
29pub mod dgram;
30pub mod diagnostics_channel;
31pub mod dns;
32pub mod domain;
33pub mod events;
34pub mod fs;
35pub mod fs_promises;
36pub mod http;
37pub mod http2;
38pub mod https;
39pub mod net;
40pub mod node_module;
41pub mod os;
42pub mod path;
43pub mod perf_hooks;
44pub mod process;
45pub mod punycode;
46pub mod querystring;
47pub mod readline;
48pub mod repl;
49pub mod stream;
50pub mod stream_consumers;
51pub mod stream_promises;
52pub mod stream_web;
53pub mod string_decoder;
54pub mod timers;
55pub mod tls;
56pub mod trace_events;
57pub mod tty;
58pub mod typedarray;
59pub mod url;
60pub mod util;
61pub mod util_types;
62pub mod v8;
63pub mod vm;
64pub mod worker_threads;
65pub mod zlib;
66
67pub const UNIMPLEMENTED_MODULES: &[&str] = &["inspector", "wasi"];
74
75pub fn is_unimplemented(ns: &str) -> bool {
77 UNIMPLEMENTED_MODULES.contains(&ns)
78}
79
80pub fn resolve(spec: &str) -> Option<&'static str> {
83 match spec.strip_prefix("node:").unwrap_or(spec) {
84 "fs" => Some("fs"),
85 "path" => Some("path"),
86 "os" => Some("os"),
87 "util" => Some("util"),
88 "assert" => Some("assert"),
89 "crypto" => Some("crypto"),
90 "buffer" => Some("buffer"),
91 "url" => Some("url"),
92 "process" => Some("process"),
93 "net" => Some("net"),
94 "http" => Some("http"),
95 "stream" => Some("stream"),
96 "tty" => Some("tty"),
97 "events" => Some("EventEmitter"),
100 "string_decoder" => Some("string_decoder"),
101 "zlib" => Some("zlib"),
102 "querystring" => Some("querystring"),
103 "console" => Some("console"),
104 "path/posix" => Some("path"),
107 "path/win32" => Some("path"),
108 "sys" => Some("util"),
110 "assert/strict" => Some("assert"),
111 "child_process" => Some("child_process"),
112 "dns" => Some("dns"),
113 "punycode" => Some("punycode"),
114 "timers" => Some("timers"),
115 "timers/promises" => Some("timers/promises"),
116 "perf_hooks" => Some("perf_hooks"),
117 "async_hooks" => Some("async_hooks"),
118 "util/types" => Some("util/types"),
119 "diagnostics_channel" => Some("diagnostics_channel"),
120 "v8" => Some("v8"),
121 "readline" => Some("readline"),
122 "vm" => Some("vm"),
123 "fs/promises" => Some("fs/promises"),
124 "dgram" => Some("dgram"),
125 "dns/promises" => Some("dns/promises"),
126 "worker_threads" => Some("worker_threads"),
127 "tls" => Some("tls"),
128 "https" => Some("https"),
129 "repl" => Some("repl"),
130 "cluster" => Some("cluster"),
131 "domain" => Some("domain"),
132 "http2" => Some("http2"),
133 "trace_events" => Some("trace_events"),
134 "module" => Some("module"),
135 "stream/consumers" => Some("stream/consumers"),
136 "stream/promises" => Some("stream/promises"),
137 "stream/web" => Some("stream/web"),
138 other => UNIMPLEMENTED_MODULES.iter().copied().find(|&m| m == other),
139 }
140}
141
142pub fn is_method(qualified: &str) -> bool {
145 let Some((ns, m)) = qualified.split_once('.') else {
146 return qualified == "assert";
147 };
148 match ns {
149 "fs" => fs::METHODS.contains(&m),
150 "path" => path::METHODS.contains(&m),
151 "os" => os::METHODS.contains(&m),
152 "util" => util::METHODS.contains(&m),
153 "assert" => assert::METHODS.contains(&m),
154 "assertStrict" => assert::METHODS.contains(&m),
155 "crypto" => crypto::METHODS.contains(&m),
156 "Buffer" => buffer::STATIC_METHODS.contains(&m),
157 "buffer" => m == "Buffer" || buffer::MODULE_METHODS.contains(&m),
158 "Date" => date::STATIC_METHODS.contains(&m),
159 "TextEncoder" | "TextDecoder" => false,
160 n if typedarray::is_ctor(n) => typedarray::STATIC_METHODS.contains(&m),
161 "url" => url::MODULE_METHODS.contains(&m) || m == "URL",
162 "net" => net::MODULE_METHODS.contains(&m),
163 "http" => http::MODULE_METHODS.contains(&m),
164 "stream" => stream::METHODS.contains(&m),
165 "worker_threads" => worker_threads::METHODS.contains(&m),
166 "zlib" => zlib::MODULE_METHODS.contains(&m),
167 "querystring" => querystring::METHODS.contains(&m),
168 "tty" => tty::METHODS.contains(&m),
169 "process" => process::METHODS.contains(&m),
170 "EventEmitter" => m == "EventEmitter" || events::STATIC_METHODS.contains(&m),
171 "console" => console::METHODS.contains(&m),
172 "child_process" => child_process::METHODS.contains(&m),
173 "dns" => dns::METHODS.contains(&m),
174 "punycode" => punycode::METHODS.contains(&m),
175 "timers" => timers::METHODS.contains(&m),
176 "timers/promises" => timers::PROMISES_METHODS.contains(&m),
177 "perf_hooks" | "performance" => perf_hooks::METHODS.contains(&m),
178 "async_hooks" => async_hooks::METHODS.contains(&m),
179 "util/types" => util_types::METHODS.contains(&m),
180 "diagnostics_channel" => diagnostics_channel::METHODS.contains(&m),
181 "v8" => v8::METHODS.contains(&m),
182 "readline" => readline::METHODS.contains(&m),
183 "vm" => vm::METHODS.contains(&m),
184 "fs/promises" => fs_promises::METHODS.contains(&m),
185 "dgram" => dgram::MODULE_METHODS.contains(&m),
186 "dns/promises" => matches!(
187 m,
188 "lookup"
189 | "lookupService"
190 | "resolve"
191 | "resolve4"
192 | "resolve6"
193 | "resolveMx"
194 | "resolveTxt"
195 | "resolveCname"
196 | "resolveNs"
197 | "resolvePtr"
198 | "resolveSrv"
199 | "resolveSoa"
200 | "resolveNaptr"
201 | "resolveCaa"
202 | "resolveTlsa"
203 | "resolveAny"
204 | "reverse"
205 | "getServers"
206 | "setServers"
207 | "getDefaultResultOrder"
208 | "setDefaultResultOrder"
209 ),
210 "tls" => tls::MODULE_METHODS.contains(&m),
211 "https" => https::MODULE_METHODS.contains(&m),
212 "repl" => repl::METHODS.contains(&m),
213 "cluster" => cluster::METHODS.contains(&m),
214 "domain" => domain::METHODS.contains(&m),
215 "http2" => http2::METHODS.contains(&m),
216 "trace_events" => trace_events::METHODS.contains(&m),
217 "module" => node_module::METHODS.contains(&m),
218 "Module" => node_module::MODULE_STATIC_METHODS.contains(&m),
219 "stream/consumers" => stream_consumers::METHODS.contains(&m),
220 "stream/promises" => stream_promises::is_method(m),
221 _ if is_unimplemented(ns) => true,
225 _ => false,
226 }
227}
228
229pub fn call(name: &str, args: &[Value]) -> Option<Result<Value, String>> {
233 if name == "assert" {
234 return Some(assert::assert_ok(args));
235 }
236 let (ns, m) = name.split_once('.')?;
237 Some(match ns {
238 "fs" => fs::call(m, args)?,
239 "path" => path::call(m, args)?,
240 "os" => os::call(m, args)?,
241 "util" => util::call(m, args)?,
242 "assert" => assert::call(m, args)?,
243 "assertStrict" => assert::strict_call(m, args)?,
244 "crypto" => crypto::call(m, args)?,
245 "Buffer" => buffer::static_call(m, args)?,
246 "buffer" if m == "Buffer" => Ok(with_host(|h| h.alloc(JsObj::Builtin("Buffer".into())))),
247 "buffer" => buffer::module_call(m, args)?,
248 "Date" => date::static_call(m, args)?,
249 n if typedarray::is_ctor(n) => typedarray::static_call(n, m, args)?,
250 "url" if m == "URL" => Ok(with_host(|h| h.alloc(JsObj::Builtin("URL".into())))),
251 "url" => url::call(m, args)?,
252 "net" => net::call(m, args)?,
253 "http" => http::call(m, args)?,
254 "stream" => stream::call(m, args)?,
255 "worker_threads" => worker_threads::call(m, args)?,
256 "zlib" => zlib::call(m, args)?,
257 "querystring" => querystring::call(m, args)?,
258 "tty" => tty::call(m, args)?,
259 "process" => process::call(m, args)?,
260 "EventEmitter" if m == "EventEmitter" => Ok(with_host(|h| {
261 h.alloc(JsObj::Builtin("EventEmitter".into()))
262 })),
263 "EventEmitter" => events::static_call(m, args)?,
264 "console" => console::call(m, args)?,
265 "child_process" => child_process::call(m, args)?,
266 "dns" => dns::call(m, args)?,
267 "punycode" => punycode::call(m, args)?,
268 "timers" => timers::call(m, args)?,
269 "timers/promises" => timers::promises_call(m, args)?,
270 "perf_hooks" | "performance" => perf_hooks::call(m, args)?,
271 "async_hooks" => async_hooks::call(m, args)?,
272 "util/types" => util_types::call(m, args)?,
273 "diagnostics_channel" => diagnostics_channel::call(m, args)?,
274 "v8" => v8::call(m, args)?,
275 "readline" => readline::call(m, args)?,
276 "vm" => vm::call(m, args)?,
277 "fs/promises" => fs_promises::call(m, args)?,
278 "dgram" => dgram::call(m, args)?,
279 "dns/promises" => match m {
282 "getServers" | "setServers" | "getDefaultResultOrder" | "setDefaultResultOrder" => {
283 dns::call(m, args)?
284 }
285 _ => {
286 let mut pm = String::from("promise");
287 let mut cs = m.chars();
288 if let Some(c) = cs.next() {
289 pm.extend(c.to_uppercase());
290 pm.push_str(cs.as_str());
291 }
292 dns::call(&pm, args)?
293 }
294 },
295 "tls" => tls::call(m, args)?,
296 "https" => https::call(m, args)?,
297 "repl" => repl::call(m, args)?,
298 "cluster" => cluster::call(m, args)?,
299 "domain" => domain::call(m, args)?,
300 "http2" => http2::call(m, args)?,
301 "trace_events" => trace_events::call(m, args)?,
302 "module" => node_module::call(m, args)?,
303 "Module" => node_module::static_call(m, args)?,
304 "stream/consumers" => stream_consumers::call(m, args)?,
305 "stream/promises" => stream_promises::call(m, args)?,
306 _ if is_unimplemented(ns) => Err(format!("Error: {ns}.{m} is not implemented in node-js")),
307 _ => return None,
308 })
309}
310
311pub fn constant(ns: &str, name: &str) -> Option<Value> {
314 match ns {
315 "path" if name == "posix" || name == "win32" => {
318 Some(with_host(|h| h.alloc(JsObj::Builtin("path".into()))))
319 }
320 "path" => path::constant(name),
321 "os" => os::constant(name),
322 "buffer" if name == "Buffer" => {
323 Some(with_host(|h| h.alloc(JsObj::Builtin("Buffer".into()))))
324 }
325 "buffer" if matches!(name, "Blob" | "File") => {
326 Some(with_host(|h| h.alloc(JsObj::Builtin(name.into()))))
327 }
328 "url" if name == "URL" => Some(with_host(|h| h.alloc(JsObj::Builtin("URL".into())))),
329 "net" => net::constant(name),
330 "tty" => tty::constant(name),
331 "repl" => repl::constant(name),
332 "readline" => readline::constant(name),
333 "diagnostics_channel" => diagnostics_channel::constant(name),
334 "v8" => v8::constant(name),
335 "console" if name == "Console" => {
336 Some(with_host(|h| h.alloc(JsObj::Builtin("Console".into()))))
337 }
338 "assert" if name == "AssertionError" => Some(with_host(|h| {
339 h.alloc(JsObj::Builtin("AssertionError".into()))
340 })),
341 "assert" if name == "strict" => Some(with_host(|h| {
342 h.alloc(JsObj::Builtin("assertStrict".into()))
343 })),
344 "stream" => stream::constant(name),
345 "http" => http::constant(name),
346 "string_decoder" if name == "StringDecoder" => Some(with_host(|h| {
347 h.alloc(JsObj::Builtin("StringDecoder".into()))
348 })),
349 "process" => process::constant(name),
350 "EventEmitter" if name == "EventEmitter" => Some(with_host(|h| {
351 h.alloc(JsObj::Builtin("EventEmitter".into()))
352 })),
353 "perf_hooks" | "performance" => perf_hooks::constant(name),
354 "dns" => dns::constant(name),
355 "punycode" => punycode::constant(name),
356 "async_hooks" if matches!(name, "AsyncLocalStorage" | "AsyncResource") => {
357 Some(with_host(|h| h.alloc(JsObj::Builtin(name.into()))))
358 }
359 "vm" if name == "Script" => Some(with_host(|h| h.alloc(JsObj::Builtin("Script".into())))),
360 "url" if name == "URLSearchParams" => Some(with_host(|h| {
361 h.alloc(JsObj::Builtin("URLSearchParams".into()))
362 })),
363 "fs" if name == "promises" => {
364 Some(with_host(|h| h.alloc(JsObj::Builtin("fs/promises".into()))))
365 }
366 "worker_threads" => worker_threads::constant(name),
367 "https" => https::constant(name),
368 "cluster" => cluster::constant(name),
369 "domain" => domain::constant(name),
370 "http2" => http2::constant(name),
371 "module" => node_module::constant(name),
372 "Module" => node_module::static_constant(name),
373 "stream/web" => stream_web::constant(name),
374 "util" => util::constant(name),
376 "crypto"
379 if matches!(
380 name,
381 "Sign"
382 | "Verify"
383 | "KeyObject"
384 | "DiffieHellman"
385 | "ECDH"
386 | "X509Certificate"
387 | "Hash"
388 | "Hmac"
389 | "Cipheriv"
390 | "Decipheriv"
391 ) =>
392 {
393 Some(with_host(|h| h.alloc(JsObj::Builtin(name.into()))))
394 }
395 _ => None,
396 }
397}
398
399pub fn construct(name: &str, args: &[Value]) -> Option<Result<Value, String>> {
403 match name {
404 "URL" => Some(url::construct(args)),
405 "EventEmitter" => Some(Ok(events::new_emitter())),
406 "Buffer" => Some(buffer::static_call("from", args).unwrap_or(Ok(Value::Undef))),
407 "Date" => Some(date::construct(args)),
408 "StringDecoder" => Some(string_decoder::construct(args)),
409 "WeakRef" => Some(typedarray::construct_weakref(args)),
410 "FinalizationRegistry" => Some(typedarray::construct_finalization_registry(args)),
411 "TextEncoder" => Some(typedarray::construct_text_encoder()),
412 "TextDecoder" => Some(typedarray::construct_text_decoder(args)),
413 n if typedarray::is_ctor(n) => Some(typedarray::construct(n, args)),
414 n if stream::is_class(n) => Some(Ok(stream::construct(n))),
415 "AsyncLocalStorage" | "AsyncResource" => async_hooks::construct(name, args),
416 "Script" => Some(vm::construct(args)),
417 "URLSearchParams" => Some(url::construct_search_params(args)),
418 "Worker" => Some(worker_threads::construct_worker(args)),
419 "Domain" => Some(domain::construct(args)),
420 "Tracing" => Some(trace_events::construct(args)),
421 "Blob" => Some(buffer::construct_blob(args)),
422 "File" => Some(buffer::construct_file(args)),
423 "AssertionError" => Some(Ok(assert::construct_assertion_error(args))),
424 "X509Certificate" => Some(crypto::construct_x509(args)),
425 "MIMEType" => Some(util::construct_mime_type(args)),
426 "MIMEParams" => Some(util::construct_mime_params(args)),
427 "Resolver" => Some(Ok(dns::construct_resolver(args))),
428 "ReadStream" | "WriteStream" => Some(Ok(tty::construct(name, args))),
429 "MessageChannel" => Some(worker_threads::construct_message_channel(args)),
430 "BroadcastChannel" => Some(worker_threads::construct_broadcast_channel(args)),
431 "PerformanceObserver" => Some(perf_hooks::construct(name, args)),
432 "REPLServer" | "Recoverable" => Some(repl::construct(name, args)),
433 "Interface" => Some(readline::construct(args)),
434 "Console" => Some(console::construct(args)),
435 "Serializer" | "DefaultSerializer" | "Deserializer" | "DefaultDeserializer" => {
436 Some(v8::construct(name, args))
437 }
438 "Socket" | "Stream" | "Server" | "SocketAddress" | "BlockList" => {
440 net::construct(name, args)
441 }
442 "Agent" | "http.Server" => http::construct(name, args),
443 n if stream_web::is_class(n) => stream_web::construct(n, args),
445 _ => None,
446 }
447}
448
449pub fn native_tag(recv: &Value) -> Option<String> {
452 with_host(|h| match h.get(recv) {
453 Some(JsObj::Object(p)) => p.get("@@native").map(|v| h.str_of(v)),
454 _ => None,
455 })
456}
457
458pub fn instance_has_method(tag: &str, name: &str) -> bool {
463 const EMITTER: &[&str] = &[
465 "on",
466 "once",
467 "emit",
468 "addListener",
469 "prependListener",
470 "prependOnceListener",
471 "removeListener",
472 "off",
473 "removeAllListeners",
474 "listeners",
475 "listenerCount",
476 "eventNames",
477 "setMaxListeners",
478 "getMaxListeners",
479 ];
480 let base: &[&str] = match tag {
481 "Server" => &["listen", "close", "address"],
482 "Socket" => &[
483 "write",
484 "end",
485 "destroy",
486 "pause",
487 "resume",
488 "setEncoding",
489 "setKeepAlive",
490 "setNoDelay",
491 "setTimeout",
492 "ref",
493 "unref",
494 "connect",
495 ],
496 "ServerResponse" => &[
497 "writeHead",
498 "setHeader",
499 "getHeader",
500 "getHeaderNames",
501 "getHeaders",
502 "hasHeader",
503 "removeHeader",
504 "write",
505 "end",
506 "flushHeaders",
507 ],
508 "IncomingMessage" => &["pause", "resume", "setEncoding", "destroy"],
509 "Buffer" => &[
510 "toString",
511 "toJSON",
512 "equals",
513 "slice",
514 "subarray",
515 "readUInt8",
516 "includes",
517 "indexOf",
518 "lastIndexOf",
519 "write",
520 "copy",
521 "fill",
522 "compare",
523 "readUInt16BE",
524 "readUInt16LE",
525 "writeUInt8",
526 "writeUInt16BE",
527 "writeUInt16LE",
528 ],
529 "Readable" | "Writable" | "Duplex" | "Transform" | "PassThrough" | "Stream" => &[
530 "read",
531 "write",
532 "end",
533 "pipe",
534 "pause",
535 "resume",
536 "setEncoding",
537 "destroy",
538 "push",
539 ],
540 "URL" => &["toString", "toJSON"],
541 "AsyncLocalStorage" => async_hooks::ALS_METHODS,
542 "AsyncHook" => async_hooks::HOOK_METHODS,
543 "Channel" => &["subscribe", "unsubscribe", "publish"],
544 "WriteStream" => &[
545 "write",
546 "end",
547 "on",
548 "once",
549 "removeListener",
550 "cork",
551 "uncork",
552 "setEncoding",
553 ],
554 "Hmac" => &["update", "digest"],
555 "Interface" => readline::INTERFACE_METHODS,
556 "Script" => vm::SCRIPT_METHODS,
557 "URLSearchParams" => url::SEARCH_PARAMS_METHODS,
558 "UdpSocket" => dgram::SOCKET_METHODS,
559 "Worker" => worker_threads::WORKER_METHODS,
560 "MessagePort" => worker_threads::PORT_METHODS,
561 "TLSServer" => tls::SERVER_METHODS,
562 "TLSSocket" => tls::SOCKET_METHODS,
563 "HTTPSServerResponse" => https::RESPONSE_METHODS,
564 "HTTPSClientRequest" => https::CLIENT_REQUEST_METHODS,
565 "REPLServer" => repl::REPLSERVER_METHODS,
566 "ClusterWorker" => cluster::WORKER_METHODS,
567 "Domain" => domain::DOMAIN_METHODS,
568 "Tracing" => trace_events::TRACING_METHODS,
569 "Http2Server" => http2::SERVER_METHODS,
570 "Http2Stream" => http2::STREAM_METHODS,
571 "Http2Session" => http2::SESSION_METHODS,
572 "Cipheriv" | "Decipheriv" => &["update", "final", "setAutoPadding"],
573 "BlockList" => net::BLOCKLIST_METHODS,
574 "ClientRequest" => http::CLIENT_REQUEST_METHODS,
575 "Agent" => &["destroy", "getName"],
576 "Blob" | "File" => buffer::BLOB_METHODS,
577 "ReadStream" => tty::READ_STREAM_METHODS,
578 "Dirent" => fs::DIRENT_METHODS,
579 "Dir" => fs::DIR_METHODS,
580 "FSReadStream" => fs::READ_STREAM_METHODS,
581 "FSWriteStream" => fs::WRITE_STREAM_METHODS,
582 "Resolver" => dns::RESOLVER_METHODS,
583 "Histogram" => perf_hooks::HISTOGRAM_METHODS,
584 "PerformanceObserver" => perf_hooks::PERFORMANCE_OBSERVER_METHODS,
585 "PerformanceObserverEntryList" => perf_hooks::OBSERVER_ENTRY_LIST_METHODS,
586 "BroadcastChannel" => worker_threads::BROADCAST_CHANNEL_METHODS,
587 "TracingChannel" => diagnostics_channel::TRACING_CHANNEL_METHODS,
588 "Serializer" => v8::SERIALIZER_METHODS,
589 "Deserializer" => v8::DESERIALIZER_METHODS,
590 "Console" => console::CONSOLE_METHODS,
591 "ChildProcess" => child_process::CHILD_PROCESS_METHODS,
592 "Sign" => &["update", "sign"],
593 "Verify" => &["update", "verify"],
594 "KeyObject" => &["export", "equals"],
595 "DiffieHellman" => &[
596 "generateKeys",
597 "computeSecret",
598 "getPrime",
599 "getGenerator",
600 "getPublicKey",
601 "getPrivateKey",
602 "setPublicKey",
603 "setPrivateKey",
604 ],
605 "ECDH" => &[
606 "generateKeys",
607 "computeSecret",
608 "getPublicKey",
609 "getPrivateKey",
610 "setPrivateKey",
611 ],
612 "X509Certificate" => &["toString"],
613 "FinalizationRegistry" => &["register", "unregister"],
614 "MIMEType" => util::MIME_TYPE_METHODS,
615 "MIMEParams" => util::MIME_PARAMS_METHODS,
616 t if stream_web::is_class(t) => stream_web::methods_for(t),
617 _ => &[],
618 };
619 let is_emitter = matches!(
620 tag,
621 "Server"
622 | "Socket"
623 | "ServerResponse"
624 | "IncomingMessage"
625 | "EventEmitter"
626 | "Readable"
627 | "Writable"
628 | "Duplex"
629 | "Transform"
630 | "PassThrough"
631 | "Stream"
632 | "UdpSocket"
633 | "Worker"
634 | "MessagePort"
635 | "TLSServer"
636 | "TLSSocket"
637 | "HTTPSServerResponse"
638 | "HTTPSClientRequest"
639 | "ClusterWorker"
640 | "Domain"
641 | "Http2Server"
642 | "Http2Stream"
643 | "Http2Session"
644 | "ClientRequest"
645 | "FSReadStream"
646 | "FSWriteStream"
647 | "ChildProcess"
648 );
649 base.contains(&name) || (is_emitter && EMITTER.contains(&name))
650}
651
652pub fn instance_call(
656 tag: &str,
657 recv: &Value,
658 method: &str,
659 args: Vec<Value>,
660) -> Result<Value, String> {
661 match tag {
662 "Buffer" => buffer::instance_call(recv, method, &args),
663 "Date" => date::instance_call(recv, method, &args),
664 "StringDecoder" => string_decoder::instance_call(recv, method, &args),
665 "WeakRef" => typedarray::weakref_call(recv, method),
666 "FinalizationRegistry" => typedarray::finalization_registry_call(recv, method, &args),
667 "TextEncoder" => typedarray::text_encoder_call(recv, method, &args),
668 "TextDecoder" => typedarray::text_decoder_call(recv, method, &args),
669 "TypedArray" => typedarray::instance_call(recv, method, &args),
670 "Hash" => crypto::instance_call(recv, method, &args),
671 "Hmac" => crypto::hmac_instance_call(recv, method, &args),
672 "Interface" => readline::instance_call(recv, method, args),
673 "Script" => vm::instance_call(recv, method, args),
674 "URLSearchParams" => url::search_params_call(recv, method, &args),
675 "UdpSocket" => dgram::instance_call(recv, method, args),
676 "Worker" | "MessagePort" | "BroadcastChannel" => {
677 worker_threads::instance_call(tag, recv, method, args)
678 }
679 "TLSServer" | "TLSSocket" => tls::instance_call(tag, recv, method, args),
680 "HTTPSServerResponse" | "HTTPSClientRequest" => {
681 https::instance_call(tag, recv, method, args)
682 }
683 "REPLServer" => repl::instance_call(recv, method, args),
684 "ClusterWorker" => cluster::instance_call(recv, method, args),
685 "Domain" => domain::instance_call(recv, method, args),
686 "Tracing" => trace_events::instance_call(recv, method, args),
687 "Http2Server" | "Http2Stream" | "Http2Session" => {
688 http2::instance_call(tag, recv, method, args)
689 }
690 "EventEmitter" => events::instance_call(recv, method, args),
691 "URL" => url::instance_call(recv, method, &args),
692 "Stats" => fs::stats_call(recv, method),
693 "Dirent" => fs::dirent_call(recv, method),
694 "Dir" => fs::dir_call(recv, method, args),
695 "FSReadStream" => fs::read_stream_call(recv, method, args),
696 "FSWriteStream" => fs::write_stream_call(recv, method, args),
697 "Server" | "Socket" | "BlockList" => net::instance_call(tag, recv, method, args),
698 "IncomingMessage" | "ServerResponse" | "ClientRequest" | "Agent" => {
699 http::instance_call(tag, recv, method, args)
700 }
701 "Readable" | "Writable" | "Duplex" | "Transform" | "PassThrough" | "Stream" => {
702 stream::instance_call(tag, recv, method, args)
703 }
704 "Cipheriv" | "Decipheriv" => crypto::cipher_instance_call(tag, recv, method, &args),
705 "Sign" | "Verify" => crypto::sign_verify_instance_call(tag, recv, method, &args),
706 "KeyObject" => crypto::key_object_instance_call(recv, method, &args),
707 "DiffieHellman" => crypto::dh_instance_call(recv, method, &args),
708 "ECDH" => crypto::ecdh_instance_call(recv, method, &args),
709 "X509Certificate" => crypto::x509_instance_call(recv, method, &args),
710 "MIMEType" => util::mime_type_instance_call(recv, method, &args),
711 "MIMEParams" => util::mime_params_instance_call(recv, method, &args),
712 "Blob" | "File" => buffer::blob_call(recv, method, &args),
713 "ReadStream" => tty::instance_call(recv, method, &args),
714 "Resolver" => dns::resolver_instance_call(recv, method, args),
715 "Histogram" => perf_hooks::histogram_instance_call(recv, method, &args),
716 "PerformanceObserver" => perf_hooks::observer_instance_call(recv, method, &args),
717 "PerformanceObserverEntryList" => perf_hooks::entry_list_instance_call(recv, method, &args),
718 "TracingChannel" => diagnostics_channel::tracing_instance_call(recv, method, &args),
719 "Serializer" | "Deserializer" => v8::instance_call(tag, recv, method, args),
720 "Console" => console::instance_call(recv, method, args),
721 "ChildProcess" => child_process::instance_call(recv, method, args),
722 t if stream_web::is_class(t) => stream_web::instance_call(t, recv, method, args),
723 "AsyncLocalStorage" | "AsyncHook" => async_hooks::instance_call(tag, recv, method, args),
724 "Channel" => diagnostics_channel::instance_call(recv, method, &args),
725 "WriteStream" => process::stream_instance_call(recv, method, &args),
726 _ => Err(crate::host::type_error(&format!(
727 "{method} is not a function"
728 ))),
729 }
730}
731
732pub(crate) fn arg_str(args: &[Value], i: usize) -> String {
736 with_host(|h| args.get(i).map(|v| h.str_of(v)).unwrap_or_default())
737}
738
739pub(crate) fn arg_num(args: &[Value], i: usize) -> f64 {
741 with_host(|h| args.get(i).map(|v| h.to_number(v)).unwrap_or(f64::NAN))
742}
743
744pub(crate) fn to_hex(bytes: &[u8]) -> String {
746 let mut s = String::with_capacity(bytes.len() * 2);
747 for b in bytes {
748 s.push(char::from_digit((b >> 4) as u32, 16).unwrap());
749 s.push(char::from_digit((b & 0xf) as u32, 16).unwrap());
750 }
751 s
752}
753
754pub(crate) fn from_hex(s: &str) -> Vec<u8> {
756 let digits: Vec<u8> = s
757 .bytes()
758 .filter_map(|c| (c as char).to_digit(16).map(|d| d as u8))
759 .collect();
760 digits
761 .chunks(2)
762 .filter(|c| c.len() == 2)
763 .map(|c| (c[0] << 4) | c[1])
764 .collect()
765}
766
767const B64: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
768
769pub(crate) fn to_base64(bytes: &[u8]) -> String {
771 let mut out = String::new();
772 for chunk in bytes.chunks(3) {
773 let b = [
774 chunk[0],
775 *chunk.get(1).unwrap_or(&0),
776 *chunk.get(2).unwrap_or(&0),
777 ];
778 let n = ((b[0] as u32) << 16) | ((b[1] as u32) << 8) | (b[2] as u32);
779 out.push(B64[((n >> 18) & 63) as usize] as char);
780 out.push(B64[((n >> 12) & 63) as usize] as char);
781 out.push(if chunk.len() > 1 {
782 B64[((n >> 6) & 63) as usize] as char
783 } else {
784 '='
785 });
786 out.push(if chunk.len() > 2 {
787 B64[(n & 63) as usize] as char
788 } else {
789 '='
790 });
791 }
792 out
793}
794
795pub(crate) fn from_base64(s: &str) -> Vec<u8> {
797 let rev = |c: u8| -> Option<u32> { B64.iter().position(|&x| x == c).map(|p| p as u32) };
798 let vals: Vec<u32> = s.bytes().filter_map(rev).collect();
799 let mut out = Vec::new();
800 for chunk in vals.chunks(4) {
801 if chunk.len() < 2 {
802 break;
803 }
804 let n = (chunk[0] << 18)
805 | (chunk[1] << 12)
806 | (chunk.get(2).copied().unwrap_or(0) << 6)
807 | chunk.get(3).copied().unwrap_or(0);
808 out.push((n >> 16) as u8);
809 if chunk.len() > 2 {
810 out.push((n >> 8) as u8);
811 }
812 if chunk.len() > 3 {
813 out.push(n as u8);
814 }
815 }
816 out
817}