1use crate::runtime::host::{abi_arg, abi_result};
7use wasmtime::{FuncType, HeapType, Linker, RefType, StructType, Val, ValType};
8
9use crate::runtime::StoreData;
10use crate::runtime::host::{
11 intrinsic_array_type, intrinsic_string_type, register_host_fn, register_host_fn_async,
12 write_submilli_string_struct_units,
13};
14use crate::runtime::intrinsic_types::{IntrinsicTypes, build_intrinsic_types};
15use crate::runtime::prelude::vtable::read_string_units;
16use crate::runtime::prelude::{MODULE_NAME, closure, declare_method};
17use crate::{MangledName, PackageDeclaration, Param, Type};
18
19fn method_key(method: &str) -> MangledName {
21 crate::mangle::extend(&crate::mangle::prelude("Array"), method)
22}
23
24fn ctor_key(method: &str) -> MangledName {
26 crate::mangle::extend(&crate::mangle::prelude("ArrayConstructor"), method)
27}
28
29fn element_callback_params(leading: Vec<Type>) -> Vec<Type> {
32 let t = Type::TypeVar("T".to_string());
33 leading
34 .into_iter()
35 .chain([t.clone(), Type::Number, Type::Array(Box::new(t))])
36 .collect()
37}
38
39fn ref_to(struct_ty: StructType) -> ValType {
40 ValType::Ref(RefType::new(false, HeapType::ConcreteStruct(struct_ty)))
41}
42
43fn object_ref(intr: &IntrinsicTypes) -> ValType {
47 ValType::Ref(RefType::new(
48 true,
49 HeapType::ConcreteStruct(intr.object.clone()),
50 ))
51}
52
53fn f64v(v: &Val) -> f64 {
54 match v {
55 Val::F64(bits) => f64::from_bits(*bits),
56 _ => f64::NAN,
57 }
58}
59
60#[allow(clippy::too_many_lines)]
61pub fn install(linker: &mut Linker<StoreData>) -> wasmtime::Result<()> {
62 let engine = linker.engine().clone();
63 let intr = build_intrinsic_types(&engine)?;
64 let array = ref_to(intrinsic_array_type(&engine)?);
65 let string = ref_to(intrinsic_string_type(&engine)?);
66 let elem = object_ref(&intr);
67 let num = ValType::F64;
68 let boolean = ValType::I32;
69 let callback = elem.clone();
72
73 let ft = |params: Vec<ValType>, results: Vec<ValType>| FuncType::new(&engine, params, results);
74
75 register_host_fn(
77 linker,
78 MODULE_NAME,
79 method_key("at"),
80 ft(vec![array.clone(), num.clone()], vec![elem.clone()]),
81 true,
82 |caller, params, results| {
83 *abi_result(results, 0)? =
84 super::at(caller, abi_arg(params, 0)?, f64v(abi_arg(params, 1)?))?;
85 Ok(())
86 },
87 )?;
88 register_host_fn(
89 linker,
90 MODULE_NAME,
91 method_key("slice"),
92 ft(
93 vec![array.clone(), num.clone(), num.clone()],
94 vec![array.clone()],
95 ),
96 true,
97 |caller, params, results| {
98 let out = super::slice(
99 caller,
100 abi_arg(params, 0)?,
101 f64v(abi_arg(params, 1)?),
102 f64v(abi_arg(params, 2)?),
103 )?;
104 *abi_result(results, 0)? = super::build_array(caller, &out)?;
105 Ok(())
106 },
107 )?;
108 register_host_fn(
109 linker,
110 MODULE_NAME,
111 method_key("concat"),
112 ft(vec![array.clone(), array.clone()], vec![array.clone()]),
113 true,
114 |caller, params, results| {
115 let self_elems = super::read_array(caller, abi_arg(params, 0)?, "Array#concat")?;
116 let out = super::concat(caller, self_elems, abi_arg(params, 1)?)?;
117 *abi_result(results, 0)? = super::build_array(caller, &out)?;
118 Ok(())
119 },
120 )?;
121 register_host_fn_async(
122 linker,
123 MODULE_NAME,
124 method_key("join"),
125 ft(vec![array.clone(), string.clone()], vec![string.clone()]),
126 true,
127 |caller, params, results| {
128 Box::pin(async move {
129 let elements = super::read_kept_array(caller, abi_arg(params, 0)?, "Array#join")?;
130 let sep = read_string_units(caller, abi_arg(params, 1)?, "Array#join separator")?;
131 let out = super::join(caller, elements, sep).await?;
132 let st = write_submilli_string_struct_units(caller, &out)?;
133 *abi_result(results, 0)? = Val::AnyRef(Some(st.to_anyref()));
134 Ok(())
135 })
136 },
137 )?;
138 register_host_fn_async(
139 linker,
140 MODULE_NAME,
141 method_key("indexOf"),
142 ft(
143 vec![array.clone(), elem.clone(), num.clone()],
144 vec![num.clone()],
145 ),
146 true,
147 |caller, params, results| {
148 Box::pin(async move {
149 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#indexOf")?;
150 let r = super::index_of(
151 caller,
152 elements,
153 *abi_arg(params, 1)?,
154 f64v(abi_arg(params, 2)?),
155 )
156 .await?;
157 *abi_result(results, 0)? = Val::F64(r.to_bits());
158 Ok(())
159 })
160 },
161 )?;
162 register_host_fn_async(
163 linker,
164 MODULE_NAME,
165 method_key("lastIndexOf"),
166 ft(
167 vec![array.clone(), elem.clone(), num.clone()],
168 vec![num.clone()],
169 ),
170 true,
171 |caller, params, results| {
172 Box::pin(async move {
173 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#lastIndexOf")?;
174 let r = super::last_index_of(
175 caller,
176 elements,
177 *abi_arg(params, 1)?,
178 f64v(abi_arg(params, 2)?),
179 )
180 .await?;
181 *abi_result(results, 0)? = Val::F64(r.to_bits());
182 Ok(())
183 })
184 },
185 )?;
186 register_host_fn_async(
187 linker,
188 MODULE_NAME,
189 method_key("includes"),
190 ft(
191 vec![array.clone(), elem.clone(), num.clone()],
192 vec![boolean.clone()],
193 ),
194 true,
195 |caller, params, results| {
196 Box::pin(async move {
197 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#includes")?;
198 let r = super::includes(
199 caller,
200 elements,
201 *abi_arg(params, 1)?,
202 f64v(abi_arg(params, 2)?),
203 )
204 .await?;
205 *abi_result(results, 0)? = Val::I32(i32::from(r));
206 Ok(())
207 })
208 },
209 )?;
210
211 register_host_fn(
213 linker,
214 MODULE_NAME,
215 method_key("push"),
216 ft(vec![array.clone(), elem.clone()], vec![num.clone()]),
217 true,
218 |caller, params, results| {
219 let [receiver, element] = params else {
220 return Err(crate::runtime::host::fatal_host_error(
221 "invalid Array#push arguments",
222 ));
223 };
224 let [result] = results else {
225 return Err(crate::runtime::host::fatal_host_error(
226 "invalid Array#push result slot",
227 ));
228 };
229 let n = super::push(caller, receiver, *element)?;
230 *result = Val::F64(n.to_bits());
231 Ok(())
232 },
233 )?;
234 register_host_fn(
235 linker,
236 MODULE_NAME,
237 method_key("pop"),
238 ft(vec![array.clone()], vec![elem.clone()]),
239 true,
240 |caller, params, results| {
241 *abi_result(results, 0)? = super::pop(caller, abi_arg(params, 0)?)?;
242 Ok(())
243 },
244 )?;
245 register_host_fn(
246 linker,
247 MODULE_NAME,
248 method_key("shift"),
249 ft(vec![array.clone()], vec![elem.clone()]),
250 true,
251 |caller, params, results| {
252 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#shift")?;
253 *abi_result(results, 0)? = super::shift(caller, abi_arg(params, 0)?, elements)?;
254 Ok(())
255 },
256 )?;
257 register_host_fn(
258 linker,
259 MODULE_NAME,
260 method_key("unshift"),
261 ft(vec![array.clone(), array.clone()], vec![num.clone()]),
262 true,
263 |caller, params, results| {
264 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#unshift")?;
265 let items = super::read_array(caller, abi_arg(params, 1)?, "Array#unshift")?;
266 let n = super::unshift(caller, abi_arg(params, 0)?, elements, items)?;
267 *abi_result(results, 0)? = Val::F64(n.to_bits());
268 Ok(())
269 },
270 )?;
271 register_host_fn(
272 linker,
273 MODULE_NAME,
274 method_key("reverse"),
275 ft(vec![array.clone()], vec![array.clone()]),
276 true,
277 |caller, params, results| {
278 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#reverse")?;
279 *abi_result(results, 0)? = super::reverse(caller, abi_arg(params, 0)?, elements)?;
280 Ok(())
281 },
282 )?;
283 register_host_fn(
284 linker,
285 MODULE_NAME,
286 method_key("fill"),
287 ft(
288 vec![array.clone(), elem.clone(), num.clone(), num.clone()],
289 vec![array.clone()],
290 ),
291 true,
292 |caller, params, results| {
293 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#fill")?;
294 *abi_result(results, 0)? = super::fill(
295 caller,
296 abi_arg(params, 0)?,
297 elements,
298 *abi_arg(params, 1)?,
299 f64v(abi_arg(params, 2)?),
300 f64v(abi_arg(params, 3)?),
301 )?;
302 Ok(())
303 },
304 )?;
305 register_host_fn(
306 linker,
307 MODULE_NAME,
308 method_key("copyWithin"),
309 ft(
310 vec![array.clone(), num.clone(), num.clone(), num.clone()],
311 vec![array.clone()],
312 ),
313 true,
314 |caller, params, results| {
315 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#copyWithin")?;
316 *abi_result(results, 0)? = super::copy_within(
317 caller,
318 abi_arg(params, 0)?,
319 elements,
320 f64v(abi_arg(params, 1)?),
321 f64v(abi_arg(params, 2)?),
322 f64v(abi_arg(params, 3)?),
323 )?;
324 Ok(())
325 },
326 )?;
327 register_host_fn(
328 linker,
329 MODULE_NAME,
330 method_key("splice"),
331 ft(
332 vec![array.clone(), num.clone(), num.clone(), array.clone()],
333 vec![array.clone()],
334 ),
335 true,
336 |caller, params, results| {
337 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#splice")?;
338 let items = super::read_array(caller, abi_arg(params, 3)?, "Array#splice")?;
339 *abi_result(results, 0)? = super::splice(
340 caller,
341 abi_arg(params, 0)?,
342 elements,
343 f64v(abi_arg(params, 1)?),
344 f64v(abi_arg(params, 2)?),
345 items,
346 )?;
347 Ok(())
348 },
349 )?;
350 register_host_fn_async(
351 linker,
352 MODULE_NAME,
353 method_key("sort"),
354 ft(vec![array.clone(), elem.clone()], vec![array.clone()]),
355 true,
356 |caller, params, results| {
357 Box::pin(async move {
358 let elements = super::read_kept_array(caller, abi_arg(params, 0)?, "Array#sort")?;
359 let cmp = if crate::runtime::prelude::undefined::is_undefined(
360 caller,
361 abi_arg(params, 1)?,
362 )? {
363 None
364 } else {
365 Some(closure::read_callback(
366 caller,
367 abi_arg(params, 1)?,
368 "Array#sort comparator",
369 )?)
370 };
371 *abi_result(results, 0)? =
372 super::sort(caller, abi_arg(params, 0)?, elements, cmp).await?;
373 Ok(())
374 })
375 },
376 )?;
377
378 register_host_fn_async(
380 linker,
381 MODULE_NAME,
382 method_key("forEach"),
383 ft(vec![array.clone(), callback.clone()], vec![]),
384 true,
385 |caller, params, _results| {
386 Box::pin(async move {
387 let elements =
388 super::read_kept_array(caller, abi_arg(params, 0)?, "Array#forEach receiver")?;
389 let f =
390 closure::read_callback(caller, abi_arg(params, 1)?, "Array#forEach callback")?;
391 super::for_each(caller, *abi_arg(params, 0)?, elements, &f).await
392 })
393 },
394 )?;
395 register_host_fn_async(
396 linker,
397 MODULE_NAME,
398 method_key("map"),
399 ft(vec![array.clone(), callback.clone()], vec![array.clone()]),
400 true,
401 |caller, params, results| {
402 Box::pin(async move {
403 let elements = super::read_kept_array(caller, abi_arg(params, 0)?, "Array#map")?;
404 let f = closure::read_callback(caller, abi_arg(params, 1)?, "Array#map callback")?;
405 let out = super::map(caller, *abi_arg(params, 0)?, elements, &f).await?;
406 *abi_result(results, 0)? = super::build_array(caller, &out)?;
407 Ok(())
408 })
409 },
410 )?;
411 register_host_fn_async(
412 linker,
413 MODULE_NAME,
414 method_key("filter"),
415 ft(vec![array.clone(), callback.clone()], vec![array.clone()]),
416 true,
417 |caller, params, results| {
418 Box::pin(async move {
419 let elements = super::read_kept_array(caller, abi_arg(params, 0)?, "Array#filter")?;
420 let f =
421 closure::read_callback(caller, abi_arg(params, 1)?, "Array#filter predicate")?;
422 let out = super::filter(caller, *abi_arg(params, 0)?, elements, &f).await?;
423 *abi_result(results, 0)? = super::build_array(caller, &out)?;
424 Ok(())
425 })
426 },
427 )?;
428 register_host_fn_async(
429 linker,
430 MODULE_NAME,
431 method_key("reduce"),
432 ft(
433 vec![array.clone(), callback.clone(), elem.clone()],
434 vec![elem.clone()],
435 ),
436 true,
437 |caller, params, results| {
438 Box::pin(async move {
439 let elements = super::read_kept_array(caller, abi_arg(params, 0)?, "Array#reduce")?;
440 let f =
441 closure::read_callback(caller, abi_arg(params, 1)?, "Array#reduce callback")?;
442 *abi_result(results, 0)? = super::reduce(
443 caller,
444 *abi_arg(params, 0)?,
445 elements,
446 &f,
447 *abi_arg(params, 2)?,
448 false,
449 )
450 .await?;
451 Ok(())
452 })
453 },
454 )?;
455 register_host_fn_async(
456 linker,
457 MODULE_NAME,
458 method_key("reduceRight"),
459 ft(
460 vec![array.clone(), callback.clone(), elem.clone()],
461 vec![elem.clone()],
462 ),
463 true,
464 |caller, params, results| {
465 Box::pin(async move {
466 let elements =
467 super::read_kept_array(caller, abi_arg(params, 0)?, "Array#reduceRight")?;
468 let f = closure::read_callback(
469 caller,
470 abi_arg(params, 1)?,
471 "Array#reduceRight callback",
472 )?;
473 *abi_result(results, 0)? = super::reduce(
474 caller,
475 *abi_arg(params, 0)?,
476 elements,
477 &f,
478 *abi_arg(params, 2)?,
479 true,
480 )
481 .await?;
482 Ok(())
483 })
484 },
485 )?;
486 for (name, reverse) in [("find", false), ("findLast", true)] {
487 register_host_fn_async(
488 linker,
489 MODULE_NAME,
490 method_key(name),
491 ft(vec![array.clone(), callback.clone()], vec![elem.clone()]),
492 true,
493 move |caller, params, results| {
494 Box::pin(async move {
495 let elements =
496 super::read_kept_array(caller, abi_arg(params, 0)?, "Array#find")?;
497 let pred = closure::read_callback(
498 caller,
499 abi_arg(params, 1)?,
500 "Array#find predicate",
501 )?;
502 *abi_result(results, 0)? = match super::find_match(
503 caller,
504 *abi_arg(params, 0)?,
505 &elements,
506 &pred,
507 reverse,
508 )
509 .await?
510 {
511 Some(i) => *elements.get(i).ok_or_else(|| {
512 crate::runtime::host::fatal_host_error(
513 "Array#find: invalid result index",
514 )
515 })?,
516 None => crate::runtime::prelude::undefined::value(caller)?,
517 };
518 Ok(())
519 })
520 },
521 )?;
522 }
523 for (name, reverse) in [("findIndex", false), ("findLastIndex", true)] {
524 register_host_fn_async(
525 linker,
526 MODULE_NAME,
527 method_key(name),
528 ft(vec![array.clone(), callback.clone()], vec![num.clone()]),
529 true,
530 move |caller, params, results| {
531 Box::pin(async move {
532 let elements =
533 super::read_kept_array(caller, abi_arg(params, 0)?, "Array#findIndex")?;
534 let pred = closure::read_callback(
535 caller,
536 abi_arg(params, 1)?,
537 "Array#findIndex predicate",
538 )?;
539 let idx =
540 super::find_match(caller, *abi_arg(params, 0)?, &elements, &pred, reverse)
541 .await?;
542 let r = idx.map_or(-1.0, |i| i as f64);
543 *abi_result(results, 0)? = Val::F64(r.to_bits());
544 Ok(())
545 })
546 },
547 )?;
548 }
549 register_host_fn_async(
550 linker,
551 MODULE_NAME,
552 method_key("some"),
553 ft(vec![array.clone(), callback.clone()], vec![boolean.clone()]),
554 true,
555 |caller, params, results| {
556 Box::pin(async move {
557 let elements = super::read_kept_array(caller, abi_arg(params, 0)?, "Array#some")?;
558 let pred =
559 closure::read_callback(caller, abi_arg(params, 1)?, "Array#some predicate")?;
560 let r = super::some(caller, *abi_arg(params, 0)?, elements, &pred).await?;
561 *abi_result(results, 0)? = Val::I32(i32::from(r));
562 Ok(())
563 })
564 },
565 )?;
566 register_host_fn_async(
567 linker,
568 MODULE_NAME,
569 method_key("every"),
570 ft(vec![array.clone(), callback.clone()], vec![boolean.clone()]),
571 true,
572 |caller, params, results| {
573 Box::pin(async move {
574 let elements = super::read_kept_array(caller, abi_arg(params, 0)?, "Array#every")?;
575 let pred =
576 closure::read_callback(caller, abi_arg(params, 1)?, "Array#every predicate")?;
577 let r = super::every(caller, *abi_arg(params, 0)?, elements, &pred).await?;
578 *abi_result(results, 0)? = Val::I32(i32::from(r));
579 Ok(())
580 })
581 },
582 )?;
583 register_host_fn(
584 linker,
585 MODULE_NAME,
586 method_key("flat"),
587 ft(vec![array.clone(), num.clone()], vec![array.clone()]),
588 true,
589 |caller, params, results| {
590 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#flat")?;
591 let depth = f64v(abi_arg(params, 1)?) as i32;
592 let mut out = Vec::new();
593 super::flat_into(caller, elements, depth, &mut out)?;
594 *abi_result(results, 0)? = super::build_array(caller, &out)?;
595 Ok(())
596 },
597 )?;
598 register_host_fn_async(
599 linker,
600 MODULE_NAME,
601 method_key("flatMap"),
602 ft(vec![array.clone(), callback.clone()], vec![array.clone()]),
603 true,
604 |caller, params, results| {
605 Box::pin(async move {
606 let elements =
607 super::read_kept_array(caller, abi_arg(params, 0)?, "Array#flatMap")?;
608 let f =
609 closure::read_callback(caller, abi_arg(params, 1)?, "Array#flatMap callback")?;
610 let out = super::flat_map(caller, *abi_arg(params, 0)?, elements, &f).await?;
611 *abi_result(results, 0)? = super::build_array(caller, &out)?;
612 Ok(())
613 })
614 },
615 )?;
616
617 register_host_fn(
619 linker,
620 MODULE_NAME,
621 method_key("toReversed"),
622 ft(vec![array.clone()], vec![array.clone()]),
623 true,
624 |caller, params, results| {
625 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#toReversed")?;
626 let out = super::to_reversed(elements);
627 *abi_result(results, 0)? = super::build_array(caller, &out)?;
628 Ok(())
629 },
630 )?;
631 register_host_fn_async(
632 linker,
633 MODULE_NAME,
634 method_key("toSorted"),
635 ft(vec![array.clone(), elem.clone()], vec![array.clone()]),
636 true,
637 |caller, params, results| {
638 Box::pin(async move {
639 let elements =
640 super::read_kept_array(caller, abi_arg(params, 0)?, "Array#toSorted")?;
641 let cmp = if crate::runtime::prelude::undefined::is_undefined(
642 caller,
643 abi_arg(params, 1)?,
644 )? {
645 None
646 } else {
647 Some(closure::read_callback(
648 caller,
649 abi_arg(params, 1)?,
650 "Array#toSorted comparator",
651 )?)
652 };
653 let out = super::to_sorted(caller, elements, cmp).await?;
654 *abi_result(results, 0)? = super::build_array(caller, &out)?;
655 Ok(())
656 })
657 },
658 )?;
659 register_host_fn(
660 linker,
661 MODULE_NAME,
662 method_key("toSpliced"),
663 ft(
664 vec![array.clone(), num.clone(), num.clone(), array.clone()],
665 vec![array.clone()],
666 ),
667 true,
668 |caller, params, results| {
669 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#toSpliced")?;
670 let items = super::read_array(caller, abi_arg(params, 3)?, "Array#toSpliced")?;
671 let (_, result) = super::splice_parts(
672 &elements,
673 f64v(abi_arg(params, 1)?),
674 f64v(abi_arg(params, 2)?),
675 items,
676 );
677 *abi_result(results, 0)? = super::build_array(caller, &result)?;
678 Ok(())
679 },
680 )?;
681 register_host_fn(
682 linker,
683 MODULE_NAME,
684 method_key("with"),
685 ft(
686 vec![array.clone(), num.clone(), elem.clone()],
687 vec![array.clone()],
688 ),
689 true,
690 |caller, params, results| {
691 let elements = super::read_array(caller, abi_arg(params, 0)?, "Array#with")?;
692 match super::with(&elements, f64v(abi_arg(params, 1)?), *abi_arg(params, 2)?) {
693 Some(out) => {
694 *abi_result(results, 0)? = super::build_array(caller, &out)?;
695 Ok(())
696 }
697 None => Err(crate::runtime::host::range_error("index out of range")),
698 }
699 },
700 )?;
701
702 let iterator_ret = object_ref(&intr);
704 register_host_fn(
705 linker,
706 MODULE_NAME,
707 method_key("keys"),
708 ft(vec![array.clone()], vec![iterator_ret.clone()]),
709 true,
710 |caller, params, results| {
711 *abi_result(results, 0)? = super::keys(caller, abi_arg(params, 0)?)?;
712 Ok(())
713 },
714 )?;
715 register_host_fn(
716 linker,
717 MODULE_NAME,
718 method_key("values"),
719 ft(vec![array.clone()], vec![iterator_ret.clone()]),
720 true,
721 |caller, params, results| {
722 *abi_result(results, 0)? = super::values(caller, abi_arg(params, 0)?)?;
723 Ok(())
724 },
725 )?;
726 register_host_fn(
727 linker,
728 MODULE_NAME,
729 method_key("entries"),
730 ft(vec![array.clone()], vec![iterator_ret.clone()]),
731 true,
732 |caller, params, results| {
733 *abi_result(results, 0)? = super::entries(caller, abi_arg(params, 0)?)?;
734 Ok(())
735 },
736 )?;
737
738 for (name, slot) in [("toString", 0usize), ("toJson", 1usize)] {
741 register_host_fn_async(
742 linker,
743 MODULE_NAME,
744 method_key(name),
745 ft(vec![array.clone()], vec![string.clone()]),
746 true,
747 move |caller, params, results| {
748 Box::pin(async move {
749 *abi_result(results, 0)? =
750 crate::runtime::prelude::vtable::dispatch_vtable_slot(
751 caller,
752 abi_arg(params, 0)?,
753 slot,
754 &[],
755 )
756 .await?;
757 Ok(())
758 })
759 },
760 )?;
761 }
762
763 register_host_fn(
766 linker,
767 MODULE_NAME,
768 ctor_key("isArray"),
769 ft(vec![elem.clone()], vec![boolean]),
770 true,
771 |caller, params, results| {
772 *abi_result(results, 0)? =
773 wasmtime::Val::I32(super::is_array(caller, abi_arg(params, 0)?)? as i32);
774 Ok(())
775 },
776 )?;
777 register_host_fn(
780 linker,
781 MODULE_NAME,
782 ctor_key("of"),
783 ft(vec![array.clone()], vec![array.clone()]),
784 true,
785 |caller, params, results| {
786 let items = super::read_array(caller, abi_arg(params, 0)?, "Array.of")?;
787 *abi_result(results, 0)? = super::build_array(caller, &items)?;
788 Ok(())
789 },
790 )?;
791 register_host_fn_async(
794 linker,
795 MODULE_NAME,
796 ctor_key("from"),
797 ft(
798 vec![object_ref(&intr), object_ref(&intr)],
799 vec![array.clone()],
800 ),
801 true,
802 |caller, params, results| {
803 Box::pin(async move {
804 *abi_result(results, 0)? =
805 super::from(caller, abi_arg(params, 0)?, abi_arg(params, 1)?).await?;
806 Ok(())
807 })
808 },
809 )?;
810 Ok(())
811}
812
813pub(crate) fn array_like_type() -> Type {
816 Type::Object {
817 fields: std::collections::BTreeMap::from([(
818 "length".to_string(),
819 crate::ObjectField {
820 ty: Type::Number,
821 optional: false,
822 readonly: true,
823 method: false,
824 },
825 )]),
826 index: None,
827 }
828}
829
830pub fn declare(defs: &mut PackageDeclaration) {
831 let t = || Type::TypeVar("T".to_string());
832 let u = || Type::TypeVar("U".to_string());
833 let arr_ty = || Type::Array(Box::new(t()));
834 let arr = || Param::new("arr", arr_ty());
835 let elem = || Param::new("v", t());
836 let n = |name: &str| Param::new(name, Type::Number);
837 let t_or_undefined = || Type::Union(vec![t(), Type::Undefined]);
838 let iter = |item: Type| Type::prelude_interface("Iterator".to_string(), vec![item]);
839 let func = |params: Vec<Type>, ret: Type| Type::Function {
840 optional: 0,
841 params,
842 ret: Box::new(ret),
843 predicate: None,
844 has_rest: false,
845 };
846 let callback = || Param::new("f", Type::Unknown);
849 let comparator_or_undefined =
850 || Type::Union(vec![func(vec![t(), t()], Type::Number), Type::Undefined]);
851
852 let m = |defs: &mut PackageDeclaration, name: &str, params: Vec<Param>, ret: Type| {
853 declare_method(defs, name, method_key(name), params, ret);
854 };
855
856 m(defs, "at", vec![arr(), n("index")], t_or_undefined());
857 m(defs, "slice", vec![arr(), n("start"), n("end")], arr_ty());
858 m(
859 defs,
860 "concat",
861 vec![
862 arr(),
863 Param::new(
864 "others",
865 Type::Array(Box::new(Type::Readonly(Box::new(arr_ty())))),
866 ),
867 ],
868 arr_ty(),
869 );
870 m(
871 defs,
872 "join",
873 vec![arr(), Param::new("sep", Type::String)],
874 Type::String,
875 );
876 m(
877 defs,
878 "indexOf",
879 vec![arr(), elem(), n("fromIndex")],
880 Type::Number,
881 );
882 m(
883 defs,
884 "lastIndexOf",
885 vec![arr(), elem(), n("fromIndex")],
886 Type::Number,
887 );
888 m(
889 defs,
890 "includes",
891 vec![arr(), elem(), n("fromIndex")],
892 Type::Boolean,
893 );
894
895 m(defs, "push", vec![arr(), elem()], Type::Number);
896 m(defs, "pop", vec![arr()], t_or_undefined());
897 m(defs, "shift", vec![arr()], t_or_undefined());
898 m(
899 defs,
900 "unshift",
901 vec![arr(), Param::new("items", arr_ty())],
902 Type::Number,
903 );
904 m(defs, "reverse", vec![arr()], arr_ty());
905 m(
906 defs,
907 "fill",
908 vec![arr(), elem(), n("start"), n("end")],
909 arr_ty(),
910 );
911 m(
912 defs,
913 "copyWithin",
914 vec![arr(), n("target"), n("start"), n("end")],
915 arr_ty(),
916 );
917 m(
918 defs,
919 "splice",
920 vec![
921 arr(),
922 n("start"),
923 n("deleteCount"),
924 Param::new("items", arr_ty()),
925 ],
926 arr_ty(),
927 );
928 m(
929 defs,
930 "sort",
931 vec![arr(), Param::new("compareFn", comparator_or_undefined())],
932 arr_ty(),
933 );
934
935 m(defs, "forEach", vec![arr(), callback()], Type::Void);
936 m(
937 defs,
938 "map",
939 vec![arr(), callback()],
940 Type::Array(Box::new(u())),
941 );
942 m(defs, "filter", vec![arr(), callback()], arr_ty());
943 m(
944 defs,
945 "reduce",
946 vec![arr(), callback(), Param::new("initial", u())],
947 u(),
948 );
949 m(
950 defs,
951 "reduceRight",
952 vec![arr(), callback(), Param::new("initial", u())],
953 u(),
954 );
955 for name in ["find", "findLast"] {
956 m(defs, name, vec![arr(), callback()], t_or_undefined());
957 }
958 for name in ["findIndex", "findLastIndex"] {
959 m(defs, name, vec![arr(), callback()], Type::Number);
960 }
961 m(defs, "some", vec![arr(), callback()], Type::Boolean);
962 m(defs, "every", vec![arr(), callback()], Type::Boolean);
963 m(defs, "flat", vec![arr(), n("depth")], arr_ty());
964 m(
965 defs,
966 "flatMap",
967 vec![arr(), callback()],
968 Type::Array(Box::new(u())),
969 );
970
971 m(defs, "toReversed", vec![arr()], arr_ty());
972 m(
973 defs,
974 "toSorted",
975 vec![arr(), Param::new("compareFn", comparator_or_undefined())],
976 arr_ty(),
977 );
978 m(
979 defs,
980 "toSpliced",
981 vec![
982 arr(),
983 n("start"),
984 n("deleteCount"),
985 Param::new("items", arr_ty()),
986 ],
987 arr_ty(),
988 );
989 m(defs, "with", vec![arr(), n("index"), elem()], arr_ty());
990
991 m(defs, "keys", vec![arr()], iter(Type::Number));
992 m(defs, "values", vec![arr()], iter(t()));
993 m(
994 defs,
995 "entries",
996 vec![arr()],
997 iter(Type::Tuple(vec![Type::Number, t()].into())),
998 );
999 m(defs, "toString", vec![arr()], Type::String);
1000 m(defs, "toJson", vec![arr()], Type::String);
1001 declare_method(
1002 defs,
1003 "isArray",
1004 ctor_key("isArray"),
1005 vec![Param::new("value", t())],
1006 Type::Boolean,
1007 );
1008
1009 declare_method(
1010 defs,
1011 "of",
1012 ctor_key("of"),
1013 vec![Param::new("items", arr_ty())],
1014 arr_ty(),
1015 );
1016 declare_method(
1017 defs,
1018 "from",
1019 ctor_key("from"),
1020 vec![
1021 Param::new(
1022 "src",
1023 Type::union(vec![
1024 Type::Readonly(Box::new(arr_ty())),
1025 iter(t()),
1026 Type::prelude_interface("Iterable".to_string(), vec![t()]),
1027 array_like_type(),
1028 ]),
1029 ),
1030 Param::new(
1031 "mapFn",
1032 Type::Union(vec![func(vec![t(), Type::Number], u()), Type::Undefined]),
1033 ),
1034 ],
1035 arr_ty(),
1036 );
1037}
1038
1039#[allow(clippy::too_many_lines)]
1042pub(crate) fn declare_types(defs: &mut crate::PackageDeclaration) {
1043 use crate::runtime::prelude::declaration::doc;
1044 use crate::{
1045 Dispatch, MethodSig, Param, PropertySig, Span, Type, TypeKind, TypeSymbol, ValueKind,
1046 ValueSymbol,
1047 };
1048 use std::collections::BTreeMap;
1049 defs.types.insert(
1050 "Array".to_string(),
1051 TypeSymbol {
1052 name: "Array".to_string(),
1053 mangled_name: crate::mangle::prelude("Array"),
1054 declaration_span: Span::at(crate::FileId::PRELUDE),
1055 kind: TypeKind::Interface { index: None,
1056 generics: vec!["T".to_string()],
1057 methods: BTreeMap::from([
1058 (
1059 "toString".to_string(),
1060 MethodSig {
1061 optional: false,
1062 generics: Vec::new(),
1063 params: Vec::new(),
1064 ret: Type::String,
1065 predicate: None,
1066 doc: doc("/** Returns the elements joined with commas. */"),
1067 },
1068 ),
1069 (
1070 "toJson".to_string(),
1071 MethodSig {
1072 optional: false,
1073 generics: Vec::new(),
1074 params: Vec::new(),
1075 ret: Type::String,
1076 predicate: None,
1077 doc: doc(
1078 "/** Returns the JSON representation of this array — `\"[\"` + elements' `toJson()` joined with `\",\"` + `\"]\"`. */",
1079 ),
1080 },
1081 ),
1082 (
1083 "join".to_string(),
1084 MethodSig {
1085 optional: false,
1086 generics: Vec::new(),
1087 params: vec![Param::with_default(
1088 "separator",
1089 Type::String,
1090 crate::DefaultValue::String(",".to_string()),
1091 )],
1092 ret: Type::String,
1093 predicate: None,
1094 doc: doc(
1095 "/**\n * Joins the elements using `separator`.\n * @param separator The string inserted between elements. Defaults to `\",\"`.\n */",
1096 ),
1097 },
1098 ),
1099 (
1100 "keys".to_string(),
1101 MethodSig {
1102 optional: false,
1103 generics: Vec::new(),
1104 params: Vec::new(),
1105 ret: Type::prelude_interface("Iterator".to_string(), vec![Type::Number]),
1106 predicate: None,
1107 doc: doc(
1108 "/** Returns a live `Iterator<number>` of the indices — length is re-read on every step. */",
1109 ),
1110 },
1111 ),
1112 (
1113 "values".to_string(),
1114 MethodSig {
1115 optional: false,
1116 generics: Vec::new(),
1117 params: Vec::new(),
1118 ret: Type::prelude_interface("Iterator".to_string(), vec![Type::TypeVar("T".to_string())]),
1119 predicate: None,
1120 doc: doc(
1121 "/** Returns a live `Iterator<T>` over the elements — unlike Map/Set cursors it sees pushes made during iteration. */",
1122 ),
1123 },
1124 ),
1125 (
1126 "entries".to_string(),
1127 MethodSig {
1128 optional: false,
1129 generics: Vec::new(),
1130 params: Vec::new(),
1131 ret: Type::prelude_interface("Iterator".to_string(), vec![Type::Tuple(vec![
1132 Type::Number,
1133 Type::TypeVar("T".to_string()),
1134 ].into())]),
1135 predicate: None,
1136 doc: doc(
1137 "/** Returns a live `Iterator<[number, T]>` of index/element pairs. */",
1138 ),
1139 },
1140 ),
1141
1142 (
1143 "map".to_string(),
1144 MethodSig {
1145 optional: false,
1146 generics: vec!["U".to_string()],
1147 params: vec![Param::new(
1148 "callback",
1149 Type::Function {
1150 optional: 0,
1151 params: element_callback_params(Vec::new()),
1152 ret: Box::new(Type::TypeVar("U".to_string())),
1153 predicate: None,
1154 has_rest: false,
1155 },
1156 )],
1157 ret: Type::Array(Box::new(Type::TypeVar("U".to_string()))),
1158 predicate: None,
1159 doc: doc(
1160 "/**\n * Returns a new array produced by applying `callback` to each element.\n * @param callback Function called with `(value, index, array)` for each element.\n * @returns A new array of length equal to this array.\n */",
1161 ),
1162 },
1163 ),
1164 (
1165 "push".to_string(),
1166 MethodSig {
1167 optional: false,
1168 generics: Vec::new(),
1169 params: vec![Param::new("elem", Type::TypeVar("T".to_string()))],
1170 ret: Type::Number,
1171 predicate: None,
1172 doc: doc(
1173 "/**\n * Appends `elem` to the end of the array.\n * @param elem The value to add.\n * @returns The new length of the array.\n */",
1174 ),
1175 },
1176 ),
1177 (
1180 "pop".to_string(),
1181 MethodSig {
1182 optional: false,
1183 generics: Vec::new(),
1184 params: Vec::new(),
1185 ret: Type::Union(vec![
1186 Type::TypeVar("T".to_string()),
1187 Type::Undefined,
1188 ]),
1189 predicate: None,
1190 doc: doc(
1191 "/**\n * Removes the last element and returns it, or `undefined` if the array is empty.\n * Shortens the array by one when non-empty.\n */",
1192 ),
1193 },
1194 ),
1195 (
1196 "at".to_string(),
1197 MethodSig {
1198 optional: false,
1199 generics: Vec::new(),
1200 params: vec![Param::new("index", Type::Number)],
1201 ret: Type::Union(vec![
1202 Type::TypeVar("T".to_string()),
1203 Type::Undefined,
1204 ]),
1205 predicate: None,
1206 doc: doc(
1207 "/**\n * Returns the element at `index`, or `undefined` if out of range.\n * Negative indices count from the end (`-1` is the last element).\n * @param index Zero-based index, JS negative-index semantics apply.\n */",
1208 ),
1209 },
1210 ),
1211 (
1212 "find".to_string(),
1213 MethodSig {
1214 optional: false,
1215 generics: Vec::new(),
1216 params: vec![Param::new(
1217 "callback",
1218 Type::Function {
1219 optional: 0,
1220 params: element_callback_params(Vec::new()),
1221 ret: Box::new(Type::Unknown),
1222 predicate: None,
1223 has_rest: false,
1224 },
1225 )],
1226 ret: Type::Union(vec![
1227 Type::TypeVar("T".to_string()),
1228 Type::Undefined,
1229 ]),
1230 predicate: None,
1231 doc: doc(
1232 "/**\n * Returns the first element for which `callback` returns a truthy value, or `undefined` if none match.\n * Short-circuits on the first match.\n * @param callback Function called with `(value, index, array)` for each element until it returns a truthy value.\n */",
1233 ),
1234 },
1235 ),
1236 (
1237 "findLast".to_string(),
1238 MethodSig {
1239 optional: false,
1240 generics: Vec::new(),
1241 params: vec![Param::new(
1242 "callback",
1243 Type::Function {
1244 optional: 0,
1245 params: element_callback_params(Vec::new()),
1246 ret: Box::new(Type::Unknown),
1247 predicate: None,
1248 has_rest: false,
1249 },
1250 )],
1251 ret: Type::Union(vec![
1252 Type::TypeVar("T".to_string()),
1253 Type::Undefined,
1254 ]),
1255 predicate: None,
1256 doc: doc(
1257 "/**\n * Returns the last element for which `callback` returns a truthy value, or `undefined` if none match.\n * Scans from the end; short-circuits on the first match.\n * @param callback Function called with `(value, index, array)` for each element until it returns a truthy value.\n */",
1258 ),
1259 },
1260 ),
1261 (
1262 "findIndex".to_string(),
1263 MethodSig {
1264 optional: false,
1265 generics: Vec::new(),
1266 params: vec![Param::new(
1267 "callback",
1268 Type::Function {
1269 optional: 0,
1270 params: element_callback_params(Vec::new()),
1271 ret: Box::new(Type::Unknown),
1272 predicate: None,
1273 has_rest: false,
1274 },
1275 )],
1276 ret: Type::Number,
1277 predicate: None,
1278 doc: doc(
1279 "/**\n * Returns the index of the first element for which `callback` returns a truthy value, or `-1` if none match.\n * @param callback Function called with `(value, index, array)` for each element until it returns a truthy value.\n */",
1280 ),
1281 },
1282 ),
1283 (
1284 "findLastIndex".to_string(),
1285 MethodSig {
1286 optional: false,
1287 generics: Vec::new(),
1288 params: vec![Param::new(
1289 "callback",
1290 Type::Function {
1291 optional: 0,
1292 params: element_callback_params(Vec::new()),
1293 ret: Box::new(Type::Unknown),
1294 predicate: None,
1295 has_rest: false,
1296 },
1297 )],
1298 ret: Type::Number,
1299 predicate: None,
1300 doc: doc(
1301 "/**\n * Returns the index of the last element for which `callback` returns a truthy value, or `-1` if none match.\n * Scans from the end.\n * @param callback Function called with `(value, index, array)` for each element until it returns a truthy value.\n */",
1302 ),
1303 },
1304 ),
1305 (
1308 "flat".to_string(),
1309 MethodSig {
1310 optional: false,
1311 generics: Vec::new(),
1312 params: vec![Param::with_default(
1313 "depth",
1314 Type::Number,
1315 crate::DefaultValue::Number(1.0),
1316 )],
1317 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1318 predicate: None,
1319 doc: doc(
1320 "/**\n * Flattens nested arrays up to `depth` levels into a new array.\n * `depth` must be an integer literal (default `1`); for deeper flattening pass a larger literal or chain `.flat()`.\n */",
1321 ),
1322 },
1323 ),
1324 (
1325 "flatMap".to_string(),
1326 MethodSig {
1327 optional: false,
1328 generics: vec!["U".to_string()],
1329 params: vec![Param::new(
1330 "callback",
1331 Type::Function {
1332 optional: 0,
1333 params: element_callback_params(Vec::new()),
1334 ret: Box::new(Type::Array(Box::new(Type::TypeVar(
1335 "U".to_string(),
1336 )))),
1337 predicate: None,
1338 has_rest: false,
1339 },
1340 )],
1341 ret: Type::Array(Box::new(Type::TypeVar("U".to_string()))),
1342 predicate: None,
1343 doc: doc(
1344 "/**\n * Maps each element to an array via `callback`, then flattens the results one level.\n * @param callback Function called with `(value, index, array)`, returning an array for each element.\n */",
1345 ),
1346 },
1347 ),
1348 (
1349 "slice".to_string(),
1350 MethodSig {
1351 optional: false,
1352 generics: Vec::new(),
1353 params: vec![
1354 Param::with_default(
1355 "start",
1356 Type::Number,
1357 crate::DefaultValue::Number(0.0),
1358 ),
1359 Param::with_default(
1366 "end",
1367 Type::Number,
1368 crate::DefaultValue::Number(f64::INFINITY),
1369 ),
1370 ],
1371 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1372 predicate: None,
1373 doc: doc(
1374 "/**\n * Returns a new array of the elements from `start` (inclusive) to `end` (exclusive).\n * The receiver is not modified.\n * @param start First index to copy. Defaults to `0`.\n * @param end Index one past the last to copy. Defaults to the array length.\n */",
1375 ),
1376 },
1377 ),
1378 (
1379 "indexOf".to_string(),
1380 MethodSig {
1381 optional: false,
1382 generics: Vec::new(),
1383 params: vec![
1384 Param::new("elem", Type::TypeVar("T".to_string())),
1385 Param::with_default(
1386 "fromIndex",
1387 Type::Number,
1388 crate::DefaultValue::Number(0.0),
1389 ),
1390 ],
1391 ret: Type::Number,
1392 predicate: None,
1393 doc: doc(
1394 "/**\n * Returns the index of the first element equal to `elem` at or after `fromIndex`, or `-1` if not present.\n * Equality dispatches through each element's `equals`.\n * @param elem The value to search for.\n * @param fromIndex Index to begin searching from. Negative counts from the end. Defaults to `0`.\n */",
1395 ),
1396 },
1397 ),
1398 (
1399 "includes".to_string(),
1400 MethodSig {
1401 optional: false,
1402 generics: Vec::new(),
1403 params: vec![
1404 Param::new("elem", Type::TypeVar("T".to_string())),
1405 Param::with_default(
1406 "fromIndex",
1407 Type::Number,
1408 crate::DefaultValue::Number(0.0),
1409 ),
1410 ],
1411 ret: Type::Boolean,
1412 predicate: None,
1413 doc: doc(
1414 "/**\n * Returns `true` if some element at or after `fromIndex` equals `elem`.\n * Equality dispatches through each element's `equals`.\n * @param elem The value to search for.\n * @param fromIndex Index to begin searching from. Negative counts from the end. Defaults to `0`.\n */",
1415 ),
1416 },
1417 ),
1418 (
1419 "concat".to_string(),
1420 MethodSig {
1421 optional: false,
1422 generics: Vec::new(),
1423 params: vec![Param::rest(
1431 "others",
1432 Type::Array(Box::new(Type::Readonly(Box::new(Type::Array(
1433 Box::new(Type::TypeVar("T".to_string())),
1434 ))))),
1435 )],
1436 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1437 predicate: None,
1438 doc: doc(
1439 "/**\n * Returns a new array containing this array's elements followed by every element of each `others` array, in order.\n * Neither this array nor any input is modified.\n * @param others Zero or more arrays whose elements are appended.\n */",
1440 ),
1441 },
1442 ),
1443 (
1444 "reverse".to_string(),
1445 MethodSig {
1446 optional: false,
1447 generics: Vec::new(),
1448 params: Vec::new(),
1449 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1450 predicate: None,
1451 doc: doc(
1452 "/**\n * Reverses the array in place and returns it.\n */",
1453 ),
1454 },
1455 ),
1456 (
1464 "filter".to_string(),
1465 MethodSig {
1466 optional: false,
1467 generics: Vec::new(),
1468 params: vec![Param::new(
1469 "predicate",
1470 Type::Function {
1471 optional: 0,
1472 params: element_callback_params(Vec::new()),
1473 ret: Box::new(Type::Unknown),
1474 predicate: None,
1475 has_rest: false,
1476 },
1477 )],
1478 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1479 predicate: None,
1480 doc: doc(
1481 "/**\n * Returns a new array of the elements for which `predicate` returned a truthy value.\n * Order is preserved; the receiver is not modified.\n * @param predicate Function called with `(value, index, array)` for each element.\n */",
1482 ),
1483 },
1484 ),
1485 (
1486 "reduce".to_string(),
1487 MethodSig {
1488 optional: false,
1489 generics: vec!["U".to_string()],
1490 params: vec![
1491 Param::new(
1492 "callback",
1493 Type::Function {
1494 optional: 0,
1495 params: element_callback_params(vec![Type::TypeVar("U".to_string())]),
1496 ret: Box::new(Type::TypeVar("U".to_string())),
1497 predicate: None,
1498 has_rest: false,
1499 },
1500 ),
1501 Param::new("initial", Type::TypeVar("U".to_string())),
1502 ],
1503 ret: Type::TypeVar("U".to_string()),
1504 predicate: None,
1505 doc: doc(
1506 "/**\n * Reduces the array to a single value.\n * Calls `callback(acc, value, index, array)` for each element left-to-right, threading the result as the next `acc`.\n * @param callback Combining function; receives the accumulator, the current element, its index, and the array.\n * @param initial Starting accumulator value.\n * @returns The final accumulator.\n */",
1507 ),
1508 },
1509 ),
1510 (
1511 "forEach".to_string(),
1512 MethodSig {
1513 optional: false,
1514 generics: Vec::new(),
1515 params: vec![Param::new(
1516 "callback",
1517 Type::Function {
1518 optional: 0,
1519 params: element_callback_params(Vec::new()),
1520 ret: Box::new(Type::Void),
1521 predicate: None,
1522 has_rest: false,
1523 },
1524 )],
1525 ret: Type::Void,
1526 predicate: None,
1527 doc: doc(
1528 "/**\n * Calls `callback(value, index, array)` once for each element in order.\n * @param callback Function called once per element.\n */",
1529 ),
1530 },
1531 ),
1532 (
1533 "some".to_string(),
1534 MethodSig {
1535 optional: false,
1536 generics: Vec::new(),
1537 params: vec![Param::new(
1538 "predicate",
1539 Type::Function {
1540 optional: 0,
1541 params: element_callback_params(Vec::new()),
1542 ret: Box::new(Type::Unknown),
1543 predicate: None,
1544 has_rest: false,
1545 },
1546 )],
1547 ret: Type::Boolean,
1548 predicate: None,
1549 doc: doc(
1550 "/**\n * Returns `true` if `predicate` returned a truthy value for at least one element.\n * Short-circuits on the first match.\n * @param predicate Function called with `(value, index, array)` for each element until it returns a truthy value.\n */",
1551 ),
1552 },
1553 ),
1554 (
1555 "every".to_string(),
1556 MethodSig {
1557 optional: false,
1558 generics: Vec::new(),
1559 params: vec![Param::new(
1560 "predicate",
1561 Type::Function {
1562 optional: 0,
1563 params: element_callback_params(Vec::new()),
1564 ret: Box::new(Type::Unknown),
1565 predicate: None,
1566 has_rest: false,
1567 },
1568 )],
1569 ret: Type::Boolean,
1570 predicate: None,
1571 doc: doc(
1572 "/**\n * Returns `true` if `predicate` returned a truthy value for every element.\n * Short-circuits on the first falsy one. An empty array returns `true`.\n * @param predicate Function called with `(value, index, array)` for each element until it returns a falsy value.\n */",
1573 ),
1574 },
1575 ),
1576 (
1577 "sort".to_string(),
1578 MethodSig {
1579 optional: false,
1580 generics: Vec::new(),
1581 params: vec![Param::with_default(
1582 "compareFn",
1583 Type::Union(vec![
1584 Type::Function {
1585 optional: 0,
1586 params: vec![
1587 Type::TypeVar("T".to_string()),
1588 Type::TypeVar("T".to_string()),
1589 ],
1590 ret: Box::new(Type::Number),
1591 predicate: None,
1592 has_rest: false,
1593 },
1594 Type::Undefined,
1595 ]),
1596 crate::DefaultValue::Undefined,
1597 )],
1598 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1599 predicate: None,
1600 doc: doc(
1601 "/**\n * Sorts the array in place and returns it. With no `compareFn`, elements are\n * compared by their string form (`[1, 2, 10]` sorts to `[1, 10, 2]`) — pass\n * `(a, b) => a - b` for numeric order.\n * `compareFn(a, b)` should return a negative number when `a` sorts before `b`, positive when after, and `0` when equal.\n * @param compareFn Element-pair comparator. Omit for default string-order comparison.\n */",
1602 ),
1603 },
1604 ),
1605 (
1606 "lastIndexOf".to_string(),
1607 MethodSig {
1608 optional: false,
1609 generics: Vec::new(),
1610 params: vec![
1611 Param::new("elem", Type::TypeVar("T".to_string())),
1612 Param::with_default(
1613 "fromIndex",
1614 Type::Number,
1615 crate::DefaultValue::OmittedNumber {
1616 omitted: f64::INFINITY,
1617 undefined: 0.0,
1618 },
1619 ),
1620 ],
1621 ret: Type::Number,
1622 predicate: None,
1623 doc: doc(
1624 "/**\n * Returns the index of the last element equal to `elem`, or `-1`.\n * Scans backwards from `fromIndex` (inclusive).\n * @param elem The value to search for.\n * @param fromIndex Index to begin the backward scan from. Negative counts from the end. Defaults to the last index.\n */",
1625 ),
1626 },
1627 ),
1628 (
1629 "reduceRight".to_string(),
1630 MethodSig {
1631 optional: false,
1632 generics: vec!["U".to_string()],
1633 params: vec![
1634 Param::new(
1635 "callback",
1636 Type::Function {
1637 optional: 0,
1638 params: element_callback_params(vec![Type::TypeVar("U".to_string())]),
1639 ret: Box::new(Type::TypeVar("U".to_string())),
1640 predicate: None,
1641 has_rest: false,
1642 },
1643 ),
1644 Param::new("initial", Type::TypeVar("U".to_string())),
1645 ],
1646 ret: Type::TypeVar("U".to_string()),
1647 predicate: None,
1648 doc: doc(
1649 "/**\n * Reduces the array right-to-left.\n * Calls `callback(acc, value, index, array)` for each element from the last to the first, threading the result as the next `acc`.\n * @param callback Combining function; receives the accumulator, the current element, its index, and the array.\n * @param initial Starting accumulator value.\n * @returns The final accumulator.\n */",
1650 ),
1651 },
1652 ),
1653 (
1654 "fill".to_string(),
1655 MethodSig {
1656 optional: false,
1657 generics: Vec::new(),
1658 params: vec![
1659 Param::new("value", Type::TypeVar("T".to_string())),
1660 Param::with_default(
1661 "start",
1662 Type::Number,
1663 crate::DefaultValue::Number(0.0),
1664 ),
1665 Param::with_default(
1666 "end",
1667 Type::Number,
1668 crate::DefaultValue::Number(f64::INFINITY),
1669 ),
1670 ],
1671 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1672 predicate: None,
1673 doc: doc(
1674 "/**\n * Sets every slot in `[start, end)` to `value`, in place, and returns the array.\n * @param value The value written into each slot.\n * @param start First index to fill. Negative counts from the end. Defaults to `0`.\n * @param end Index to stop before. Negative counts from the end. Defaults to the array length.\n */",
1675 ),
1676 },
1677 ),
1678 (
1679 "copyWithin".to_string(),
1680 MethodSig {
1681 optional: false,
1682 generics: Vec::new(),
1683 params: vec![
1684 Param::new("target", Type::Number),
1685 Param::with_default(
1686 "start",
1687 Type::Number,
1688 crate::DefaultValue::Number(0.0),
1689 ),
1690 Param::with_default(
1691 "end",
1692 Type::Number,
1693 crate::DefaultValue::Number(f64::INFINITY),
1694 ),
1695 ],
1696 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1697 predicate: None,
1698 doc: doc(
1699 "/**\n * Copies the slots `[start, end)` to `target`, in place (overlap-safe), and returns the array.\n * The length never changes; the copy is truncated at the end of the array.\n * @param target Destination index. Negative counts from the end.\n * @param start First source index. Negative counts from the end. Defaults to `0`.\n * @param end Source index to stop before. Negative counts from the end. Defaults to the array length.\n */",
1700 ),
1701 },
1702 ),
1703 (
1704 "toReversed".to_string(),
1705 MethodSig {
1706 optional: false,
1707 generics: Vec::new(),
1708 params: Vec::new(),
1709 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1710 predicate: None,
1711 doc: doc(
1712 "/**\n * Returns a new array with the elements in reverse order; the receiver is not modified.\n */",
1713 ),
1714 },
1715 ),
1716 (
1717 "toSorted".to_string(),
1718 MethodSig {
1719 optional: false,
1720 generics: Vec::new(),
1721 params: vec![Param::with_default(
1722 "compareFn",
1723 Type::Union(vec![
1724 Type::Function {
1725 optional: 0,
1726 params: vec![
1727 Type::TypeVar("T".to_string()),
1728 Type::TypeVar("T".to_string()),
1729 ],
1730 ret: Box::new(Type::Number),
1731 predicate: None,
1732 has_rest: false,
1733 },
1734 Type::Undefined,
1735 ]),
1736 crate::DefaultValue::Undefined,
1737 )],
1738 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1739 predicate: None,
1740 doc: doc(
1741 "/**\n * Returns a new sorted array; the receiver is not modified.\n * Comparator semantics match `sort`: no `compareFn` compares by string form — pass `(a, b) => a - b` for numeric order.\n * @param compareFn Element-pair comparator. Omit for default string-order comparison.\n */",
1742 ),
1743 },
1744 ),
1745 (
1746 "toSpliced".to_string(),
1747 MethodSig {
1748 optional: false,
1749 generics: Vec::new(),
1750 params: vec![
1751 Param::new("start", Type::Number),
1752 Param::with_default(
1753 "deleteCount",
1754 Type::Number,
1755 crate::DefaultValue::OmittedNumber {
1756 omitted: f64::INFINITY,
1757 undefined: 0.0,
1758 },
1759 ),
1760 Param::rest(
1761 "items",
1762 Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1763 ),
1764 ],
1765 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1766 predicate: None,
1767 doc: doc(
1768 "/**\n * Returns a new array with `deleteCount` elements removed at `start` and `items` inserted there; the receiver is not modified.\n * @param start Index where the change begins. Negative counts from the end.\n * @param deleteCount How many elements to drop. Defaults to all elements from `start` to the end.\n * @param items Zero or more replacement elements.\n */",
1769 ),
1770 },
1771 ),
1772 (
1773 "with".to_string(),
1774 MethodSig {
1775 optional: false,
1776 generics: Vec::new(),
1777 params: vec![
1778 Param::new("index", Type::Number),
1779 Param::new("value", Type::TypeVar("T".to_string())),
1780 ],
1781 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1782 predicate: None,
1783 doc: doc(
1784 "/**\n * Returns a copy of the array with the slot at `index` replaced by `value`; the receiver is not modified.\n * Negative `index` counts from the end. An out-of-range index throws a `RangeError`.\n * @param index The slot to replace.\n * @param value The replacement value.\n */",
1785 ),
1786 },
1787 ),
1788 (
1789 "shift".to_string(),
1790 MethodSig {
1791 optional: false,
1792 generics: Vec::new(),
1793 params: Vec::new(),
1794 ret: Type::Union(vec![
1795 Type::TypeVar("T".to_string()),
1796 Type::Undefined,
1797 ]),
1798 predicate: None,
1799 doc: doc(
1800 "/**\n * Removes and returns the first element, shifting the rest forward.\n * Returns `undefined` when the array is empty.\n */",
1801 ),
1802 },
1803 ),
1804 (
1805 "unshift".to_string(),
1806 MethodSig {
1807 optional: false,
1808 generics: Vec::new(),
1809 params: vec![Param::rest(
1810 "items",
1811 Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1812 )],
1813 ret: Type::Number,
1814 predicate: None,
1815 doc: doc(
1816 "/**\n * Prepends `items` (keeping their argument order) and returns the new length.\n * @param items One or more elements to add at the front.\n */",
1817 ),
1818 },
1819 ),
1820 (
1821 "splice".to_string(),
1822 MethodSig {
1823 optional: false,
1824 generics: Vec::new(),
1825 params: vec![
1826 Param::new("start", Type::Number),
1827 Param::with_default(
1828 "deleteCount",
1829 Type::Number,
1830 crate::DefaultValue::OmittedNumber {
1831 omitted: f64::INFINITY,
1832 undefined: 0.0,
1833 },
1834 ),
1835 Param::rest(
1836 "items",
1837 Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1838 ),
1839 ],
1840 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1841 predicate: None,
1842 doc: doc(
1843 "/**\n * Removes `deleteCount` elements at `start`, inserts `items` there (in place), and returns the removed elements.\n * @param start Index where the change begins. Negative counts from the end.\n * @param deleteCount How many elements to remove. Defaults to all elements from `start` to the end.\n * @param items Zero or more elements to insert at `start`.\n */",
1844 ),
1845 },
1846 ),
1847 ]),
1848 properties: BTreeMap::from([(
1849 "length".to_string(),
1850 PropertySig {
1851 ty: Type::Number,
1852 readonly: true,
1853 intrinsic: true,
1854 optional: false,
1855 doc: doc("/** The number of elements in the array. */"),
1856 },
1857 )]),
1858 dispatch: Dispatch::Direct,
1859 doc: doc("/** A homogeneous array of `T`. */"),
1860 },
1861 },
1862 );
1863 defs.types.insert(
1864 "ArrayConstructor".to_string(),
1865 TypeSymbol {
1866 name: "ArrayConstructor".to_string(),
1867 mangled_name: crate::mangle::prelude("ArrayConstructor"),
1868 declaration_span: Span::at(crate::FileId::PRELUDE),
1869 kind: TypeKind::Interface { index: None,
1870 generics: Vec::new(),
1871 methods: BTreeMap::from([(
1872 "from".to_string(),
1873 MethodSig {
1874 optional: false,
1875 generics: vec!["T".to_string(), "U".to_string()],
1876 params: vec![
1877 Param::new(
1878 "src",
1879 Type::union(vec![
1880 Type::Readonly(Box::new(Type::Array(Box::new(Type::TypeVar("T".to_string()))))),
1881 Type::prelude_interface(
1882 "Iterator".to_string(),
1883 vec![Type::TypeVar("T".to_string())],
1884 ),
1885 Type::prelude_interface(
1886 "Iterable".to_string(),
1887 vec![Type::TypeVar("T".to_string())],
1888 ),
1889 array_like_type(),
1890 ]),
1891 ),
1892 Param::with_default(
1893 "mapFn",
1894 Type::union(vec![
1895 Type::Function {
1896 optional: 0,
1897 params: vec![Type::TypeVar("T".to_string()), Type::Number],
1898 ret: Box::new(Type::TypeVar("U".to_string())),
1899 predicate: None,
1900 has_rest: false,
1901 },
1902 Type::Undefined,
1903 ]),
1904 crate::DefaultValue::Undefined,
1905 ),
1906 ],
1907 ret: Type::Array(Box::new(Type::TypeVar("U".to_string()))),
1908 predicate: None,
1909 doc: doc(
1910 "/**\n * Materializes any iterable — an array, string (code points), `Iterator<T>`, or `Iterable<T>` — into a fresh array.\n * @param src The iterable source.\n * @param mapFn Optional per-element transform applied while collecting.\n */",
1911 ),
1912 },
1913 ), (
1914 "of".to_string(),
1915 MethodSig {
1916 optional: false,
1917 generics: vec!["T".to_string()],
1918 params: vec![Param::rest(
1919 "items",
1920 Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1921 )],
1922 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1923 predicate: None,
1924 doc: doc(
1925 "/** Builds an array from its arguments — `Array.of(1, 2, 3)` is `[1, 2, 3]`. */",
1926 ),
1927 },
1928 ), (
1929 "isArray".to_string(),
1930 MethodSig {
1931 optional: false,
1932 generics: vec!["T".to_string()],
1933 params: vec![Param::new("value", Type::TypeVar("T".to_string()))],
1934 ret: Type::Boolean,
1935 predicate: Some(crate::TypePredicate {
1936 parameter_index: 0,
1937 asserted_type: Type::Array(Box::new(Type::Unknown)),
1938 }),
1939 doc: doc(
1940 "/**\n * Returns `true` when `value` is an array. Element type is erased at runtime; the static-typed true-branch sees `value` narrowed to the call site's array variant.\n * @param value The value to test.\n */",
1941 ),
1942 },
1943 )]),
1944 properties: BTreeMap::new(),
1945 dispatch: Dispatch::Static,
1946 doc: doc(
1947 "/** Constructor object for `Array`. Accessed via the global `Array` binding. */",
1948 ),
1949 },
1950 },
1951 );
1952
1953 defs.values.insert(
1954 "Array".to_string(),
1955 ValueSymbol {
1956 name: "Array".to_string(),
1957 mangled_name: crate::mangle::prelude("Array"),
1958 declaration_span: Span::at(crate::FileId::PRELUDE),
1959 kind: ValueKind::Const {
1960 ty: Type::prelude_interface("ArrayConstructor".to_string(), Vec::new()),
1961 doc: doc(
1962 "/** The `Array` constructor — call `Array.isArray(x)` to runtime-check whether a value is an array. */",
1963 ),
1964 },
1965 },
1966 );
1967}