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