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