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 let Some(out) = super::with(&elements, f64v(abi_arg(params, 1)?), *abi_arg(params, 2)?)
662 else {
663 crate::runtime::fuel::charge(&mut *caller, crate::runtime::fuel::PARSE, 1)?;
664 return Err(crate::runtime::host::range_error(format!(
665 "index {} is out of range (length {})",
666 crate::runtime::number::format_number_js(f64v(abi_arg(params, 1)?)),
667 elements.len()
668 )));
669 };
670 *abi_result(results, 0)? = super::build_array(caller, &out)?;
671 Ok(())
672 },
673 )?;
674
675 let iterator_ret = object_ref(&intr);
677 register_host_fn(
678 linker,
679 MODULE_NAME,
680 method_key("keys"),
681 ft(vec![array.clone()], vec![iterator_ret.clone()]),
682 |caller, params, results| {
683 *abi_result(results, 0)? = super::keys(caller, abi_arg(params, 0)?)?;
684 Ok(())
685 },
686 )?;
687 register_host_fn(
688 linker,
689 MODULE_NAME,
690 method_key("values"),
691 ft(vec![array.clone()], vec![iterator_ret.clone()]),
692 |caller, params, results| {
693 *abi_result(results, 0)? = super::values(caller, abi_arg(params, 0)?)?;
694 Ok(())
695 },
696 )?;
697 register_host_fn(
698 linker,
699 MODULE_NAME,
700 method_key("entries"),
701 ft(vec![array.clone()], vec![iterator_ret.clone()]),
702 |caller, params, results| {
703 *abi_result(results, 0)? = super::entries(caller, abi_arg(params, 0)?)?;
704 Ok(())
705 },
706 )?;
707
708 for (name, slot) in [("toString", 0usize), ("toJson", 1usize)] {
711 register_host_fn_async(
712 linker,
713 MODULE_NAME,
714 method_key(name),
715 ft(vec![array.clone()], vec![string.clone()]),
716 move |caller, params, results| {
717 Box::pin(async move {
718 *abi_result(results, 0)? =
719 crate::runtime::prelude::vtable::dispatch_vtable_slot(
720 caller,
721 abi_arg(params, 0)?,
722 slot,
723 &[],
724 )
725 .await?;
726 Ok(())
727 })
728 },
729 )?;
730 }
731
732 register_host_fn(
735 linker,
736 MODULE_NAME,
737 ctor_key("isArray"),
738 ft(vec![elem.clone()], vec![boolean]),
739 |caller, params, results| {
740 *abi_result(results, 0)? =
741 wasmtime::Val::I32(super::is_array(caller, abi_arg(params, 0)?)? as i32);
742 Ok(())
743 },
744 )?;
745 register_host_fn(
748 linker,
749 MODULE_NAME,
750 ctor_key("of"),
751 ft(vec![array.clone()], vec![array.clone()]),
752 |caller, params, results| {
753 let items = super::read_array(caller, abi_arg(params, 0)?, "Array.of")?;
754 *abi_result(results, 0)? = super::build_array(caller, &items)?;
755 Ok(())
756 },
757 )?;
758 register_host_fn_async(
761 linker,
762 MODULE_NAME,
763 ctor_key("from"),
764 ft(
765 vec![object_ref(&intr), object_ref(&intr)],
766 vec![array.clone()],
767 ),
768 |caller, params, results| {
769 Box::pin(async move {
770 *abi_result(results, 0)? =
771 super::from(caller, abi_arg(params, 0)?, abi_arg(params, 1)?).await?;
772 Ok(())
773 })
774 },
775 )?;
776 Ok(())
777}
778
779pub(crate) fn array_like_type() -> Type {
782 Type::Object {
783 fields: std::collections::BTreeMap::from([(
784 "length".to_string(),
785 crate::ObjectField {
786 ty: Type::Number,
787 optional: false,
788 readonly: true,
789 method: false,
790 },
791 )]),
792 index: None,
793 }
794}
795
796pub fn declare(defs: &mut PackageDeclaration) {
797 let t = || Type::TypeVar("T".to_string());
798 let u = || Type::TypeVar("U".to_string());
799 let arr_ty = || Type::Array(Box::new(t()));
800 let arr = || Param::new("arr", arr_ty());
801 let elem = || Param::new("v", t());
802 let n = |name: &str| Param::new(name, Type::Number);
803 let t_or_undefined = || Type::Union(vec![t(), Type::Undefined]);
804 let iter = |item: Type| Type::prelude_interface("Iterator".to_string(), vec![item]);
805 let func = |params: Vec<Type>, ret: Type| Type::Function {
806 optional: 0,
807 params,
808 ret: Box::new(ret),
809 predicate: None,
810 has_rest: false,
811 };
812 let callback = || Param::new("f", Type::Unknown);
815 let comparator_or_undefined =
816 || Type::Union(vec![func(vec![t(), t()], Type::Number), Type::Undefined]);
817
818 let m = |defs: &mut PackageDeclaration, name: &str, params: Vec<Param>, ret: Type| {
819 declare_method(defs, name, method_key(name), params, ret);
820 };
821
822 m(defs, "at", vec![arr(), n("index")], t_or_undefined());
823 m(defs, "slice", vec![arr(), n("start"), n("end")], arr_ty());
824 m(
825 defs,
826 "concat",
827 vec![
828 arr(),
829 Param::new(
830 "items",
831 Type::Array(Box::new(Type::union(vec![
832 t(),
833 Type::Readonly(Box::new(arr_ty())),
834 ]))),
835 ),
836 ],
837 arr_ty(),
838 );
839 m(
840 defs,
841 "join",
842 vec![arr(), Param::new("sep", Type::String)],
843 Type::String,
844 );
845 m(
846 defs,
847 "indexOf",
848 vec![arr(), elem(), n("fromIndex")],
849 Type::Number,
850 );
851 m(
852 defs,
853 "lastIndexOf",
854 vec![arr(), elem(), n("fromIndex")],
855 Type::Number,
856 );
857 m(
858 defs,
859 "includes",
860 vec![arr(), elem(), n("fromIndex")],
861 Type::Boolean,
862 );
863
864 m(
865 defs,
866 "push",
867 vec![arr(), Param::new("items", arr_ty())],
868 Type::Number,
869 );
870 m(defs, "pop", vec![arr()], t_or_undefined());
871 m(
872 defs,
873 &crate::mangle::property_setter("length"),
874 vec![arr(), Param::new("value", Type::Number)],
875 Type::Void,
876 );
877 m(defs, "shift", vec![arr()], t_or_undefined());
878 m(
879 defs,
880 "unshift",
881 vec![arr(), Param::new("items", arr_ty())],
882 Type::Number,
883 );
884 m(defs, "reverse", vec![arr()], arr_ty());
885 m(
886 defs,
887 "fill",
888 vec![arr(), elem(), n("start"), n("end")],
889 arr_ty(),
890 );
891 m(
892 defs,
893 "copyWithin",
894 vec![arr(), n("target"), n("start"), n("end")],
895 arr_ty(),
896 );
897 m(
898 defs,
899 "splice",
900 vec![
901 arr(),
902 n("start"),
903 n("deleteCount"),
904 Param::new("items", arr_ty()),
905 ],
906 arr_ty(),
907 );
908 m(
909 defs,
910 "sort",
911 vec![arr(), Param::new("compareFn", comparator_or_undefined())],
912 arr_ty(),
913 );
914
915 m(defs, "forEach", vec![arr(), callback()], Type::Void);
916 m(
917 defs,
918 "map",
919 vec![arr(), callback()],
920 Type::Array(Box::new(u())),
921 );
922 m(defs, "filter", vec![arr(), callback()], arr_ty());
923 m(
924 defs,
925 "reduce",
926 vec![arr(), callback(), Param::new("initial", u())],
927 u(),
928 );
929 m(
930 defs,
931 "reduceRight",
932 vec![arr(), callback(), Param::new("initial", u())],
933 u(),
934 );
935 for name in ["find", "findLast"] {
936 m(defs, name, vec![arr(), callback()], t_or_undefined());
937 }
938 for name in ["findIndex", "findLastIndex"] {
939 m(defs, name, vec![arr(), callback()], Type::Number);
940 }
941 m(defs, "some", vec![arr(), callback()], Type::Boolean);
942 m(defs, "every", vec![arr(), callback()], Type::Boolean);
943 m(defs, "flat", vec![arr(), n("depth")], arr_ty());
944 m(
945 defs,
946 "flatMap",
947 vec![arr(), callback()],
948 Type::Array(Box::new(u())),
949 );
950
951 m(defs, "toReversed", vec![arr()], arr_ty());
952 m(
953 defs,
954 "toSorted",
955 vec![arr(), Param::new("compareFn", comparator_or_undefined())],
956 arr_ty(),
957 );
958 m(
959 defs,
960 "toSpliced",
961 vec![
962 arr(),
963 n("start"),
964 n("deleteCount"),
965 Param::new("items", arr_ty()),
966 ],
967 arr_ty(),
968 );
969 m(defs, "with", vec![arr(), n("index"), elem()], arr_ty());
970
971 m(defs, "keys", vec![arr()], iter(Type::Number));
972 m(defs, "values", vec![arr()], iter(t()));
973 m(
974 defs,
975 "entries",
976 vec![arr()],
977 iter(Type::Tuple(vec![Type::Number, t()].into())),
978 );
979 m(defs, "toString", vec![arr()], Type::String);
980 m(defs, "toJson", vec![arr()], Type::String);
981 declare_method(
982 defs,
983 "isArray",
984 ctor_key("isArray"),
985 vec![Param::new("value", t())],
986 Type::Boolean,
987 );
988
989 declare_method(
990 defs,
991 "of",
992 ctor_key("of"),
993 vec![Param::new("items", arr_ty())],
994 arr_ty(),
995 );
996 declare_method(
997 defs,
998 "from",
999 ctor_key("from"),
1000 vec![
1001 Param::new(
1002 "src",
1003 Type::union(vec![
1004 Type::Readonly(Box::new(arr_ty())),
1005 iter(t()),
1006 Type::prelude_interface("Iterable".to_string(), vec![t()]),
1007 array_like_type(),
1008 ]),
1009 ),
1010 Param::new(
1011 "mapFn",
1012 Type::Union(vec![func(vec![t(), Type::Number], u()), Type::Undefined]),
1013 ),
1014 ],
1015 arr_ty(),
1016 );
1017}
1018
1019#[allow(clippy::too_many_lines)]
1022pub(crate) fn declare_types(defs: &mut crate::PackageDeclaration) {
1023 use crate::runtime::prelude::declaration::doc;
1024 use crate::{
1025 Dispatch, MethodSig, Param, PropertySig, Span, Type, TypeKind, TypeSymbol, ValueKind,
1026 ValueSymbol,
1027 };
1028 use std::collections::BTreeMap;
1029 defs.types.insert(
1030 "Array".to_string(),
1031 TypeSymbol {
1032 name: "Array".to_string(),
1033 mangled_name: crate::mangle::prelude("Array"),
1034 declaration_span: Span::at(crate::FileId::PRELUDE),
1035 kind: TypeKind::Interface { index: None,
1036 generics: crate::GenericParameters::unconstrained(vec!["T".to_string()]),
1037 methods: BTreeMap::from([
1038 (
1039 "toString".to_string(),
1040 MethodSig {
1041 optional: false,
1042 generics: Default::default(),
1043 params: Vec::new(),
1044 ret: Type::String,
1045 predicate: None,
1046 doc: doc("/** Returns the elements joined with commas. */"),
1047 },
1048 ),
1049 (
1050 "toJson".to_string(),
1051 MethodSig {
1052 optional: false,
1053 generics: Default::default(),
1054 params: Vec::new(),
1055 ret: Type::String,
1056 predicate: None,
1057 doc: doc(
1058 "/** Returns the JSON representation of this array — `\"[\"` + elements' `toJson()` joined with `\",\"` + `\"]\"`. */",
1059 ),
1060 },
1061 ),
1062 (
1063 "join".to_string(),
1064 MethodSig {
1065 optional: false,
1066 generics: Default::default(),
1067 params: vec![Param::with_default(
1068 "separator",
1069 Type::String,
1070 crate::DefaultValue::String(",".to_string()),
1071 )],
1072 ret: Type::String,
1073 predicate: None,
1074 doc: doc(
1075 "/**\n * Joins the elements using `separator`.\n * @param separator The string inserted between elements. Defaults to `\",\"`.\n */",
1076 ),
1077 },
1078 ),
1079 (
1080 "keys".to_string(),
1081 MethodSig {
1082 optional: false,
1083 generics: Default::default(),
1084 params: Vec::new(),
1085 ret: Type::prelude_interface("Iterator".to_string(), vec![Type::Number]),
1086 predicate: None,
1087 doc: doc(
1088 "/** Returns a live `Iterator<number>` of the indices — length is re-read on every step. */",
1089 ),
1090 },
1091 ),
1092 (
1093 "values".to_string(),
1094 MethodSig {
1095 optional: false,
1096 generics: Default::default(),
1097 params: Vec::new(),
1098 ret: Type::prelude_interface("Iterator".to_string(), vec![Type::TypeVar("T".to_string())]),
1099 predicate: None,
1100 doc: doc(
1101 "/** Returns a live `Iterator<T>` over the elements — unlike Map/Set cursors it sees pushes made during iteration. */",
1102 ),
1103 },
1104 ),
1105 (
1106 "entries".to_string(),
1107 MethodSig {
1108 optional: false,
1109 generics: Default::default(),
1110 params: Vec::new(),
1111 ret: Type::prelude_interface("Iterator".to_string(), vec![Type::Tuple(vec![
1112 Type::Number,
1113 Type::TypeVar("T".to_string()),
1114 ].into())]),
1115 predicate: None,
1116 doc: doc(
1117 "/** Returns a live `Iterator<[number, T]>` of index/element pairs. */",
1118 ),
1119 },
1120 ),
1121
1122 (
1123 "map".to_string(),
1124 MethodSig {
1125 optional: false,
1126 generics: crate::GenericParameters::unconstrained(vec!["U".to_string()]),
1127 params: vec![Param::new(
1128 "callback",
1129 Type::Function {
1130 optional: 0,
1131 params: element_callback_params(Vec::new()),
1132 ret: Box::new(Type::TypeVar("U".to_string())),
1133 predicate: None,
1134 has_rest: false,
1135 },
1136 )],
1137 ret: Type::Array(Box::new(Type::TypeVar("U".to_string()))),
1138 predicate: None,
1139 doc: doc(
1140 "/**\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 */",
1141 ),
1142 },
1143 ),
1144 (
1145 "push".to_string(),
1146 MethodSig {
1147 optional: false,
1148 generics: Default::default(),
1149 params: vec![Param::rest(
1150 "items",
1151 Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1152 )],
1153 ret: Type::Number,
1154 predicate: None,
1155 doc: doc(
1156 "/**\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 */",
1157 ),
1158 },
1159 ),
1160 (
1163 "pop".to_string(),
1164 MethodSig {
1165 optional: false,
1166 generics: Default::default(),
1167 params: Vec::new(),
1168 ret: Type::Union(vec![
1169 Type::TypeVar("T".to_string()),
1170 Type::Undefined,
1171 ]),
1172 predicate: None,
1173 doc: doc(
1174 "/**\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 */",
1175 ),
1176 },
1177 ),
1178 (
1179 "at".to_string(),
1180 MethodSig {
1181 optional: false,
1182 generics: Default::default(),
1183 params: vec![Param::new("index", Type::Number)],
1184 ret: Type::Union(vec![
1185 Type::TypeVar("T".to_string()),
1186 Type::Undefined,
1187 ]),
1188 predicate: None,
1189 doc: doc(
1190 "/**\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 */",
1191 ),
1192 },
1193 ),
1194 (
1195 "find".to_string(),
1196 MethodSig {
1197 optional: false,
1198 generics: Default::default(),
1199 params: vec![Param::new(
1200 "callback",
1201 Type::Function {
1202 optional: 0,
1203 params: element_callback_params(Vec::new()),
1204 ret: Box::new(Type::Unknown),
1205 predicate: None,
1206 has_rest: false,
1207 },
1208 )],
1209 ret: Type::Union(vec![
1210 Type::TypeVar("T".to_string()),
1211 Type::Undefined,
1212 ]),
1213 predicate: None,
1214 doc: doc(
1215 "/**\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 */",
1216 ),
1217 },
1218 ),
1219 (
1220 "findLast".to_string(),
1221 MethodSig {
1222 optional: false,
1223 generics: Default::default(),
1224 params: vec![Param::new(
1225 "callback",
1226 Type::Function {
1227 optional: 0,
1228 params: element_callback_params(Vec::new()),
1229 ret: Box::new(Type::Unknown),
1230 predicate: None,
1231 has_rest: false,
1232 },
1233 )],
1234 ret: Type::Union(vec![
1235 Type::TypeVar("T".to_string()),
1236 Type::Undefined,
1237 ]),
1238 predicate: None,
1239 doc: doc(
1240 "/**\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 */",
1241 ),
1242 },
1243 ),
1244 (
1245 "findIndex".to_string(),
1246 MethodSig {
1247 optional: false,
1248 generics: Default::default(),
1249 params: vec![Param::new(
1250 "callback",
1251 Type::Function {
1252 optional: 0,
1253 params: element_callback_params(Vec::new()),
1254 ret: Box::new(Type::Unknown),
1255 predicate: None,
1256 has_rest: false,
1257 },
1258 )],
1259 ret: Type::Number,
1260 predicate: None,
1261 doc: doc(
1262 "/**\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 */",
1263 ),
1264 },
1265 ),
1266 (
1267 "findLastIndex".to_string(),
1268 MethodSig {
1269 optional: false,
1270 generics: Default::default(),
1271 params: vec![Param::new(
1272 "callback",
1273 Type::Function {
1274 optional: 0,
1275 params: element_callback_params(Vec::new()),
1276 ret: Box::new(Type::Unknown),
1277 predicate: None,
1278 has_rest: false,
1279 },
1280 )],
1281 ret: Type::Number,
1282 predicate: None,
1283 doc: doc(
1284 "/**\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 */",
1285 ),
1286 },
1287 ),
1288 (
1291 "flat".to_string(),
1292 MethodSig {
1293 optional: false,
1294 generics: Default::default(),
1295 params: vec![Param::with_default(
1296 "depth",
1297 Type::Number,
1298 crate::DefaultValue::Number(1.0),
1299 )],
1300 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1301 predicate: None,
1302 doc: doc(
1303 "/**\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 */",
1304 ),
1305 },
1306 ),
1307 (
1308 "flatMap".to_string(),
1309 MethodSig {
1310 optional: false,
1311 generics: crate::GenericParameters::unconstrained(vec!["U".to_string()]),
1312 params: vec![Param::new(
1313 "callback",
1314 Type::Function {
1315 optional: 0,
1316 params: element_callback_params(Vec::new()),
1317 ret: Box::new(Type::Array(Box::new(Type::TypeVar(
1318 "U".to_string(),
1319 )))),
1320 predicate: None,
1321 has_rest: false,
1322 },
1323 )],
1324 ret: Type::Array(Box::new(Type::TypeVar("U".to_string()))),
1325 predicate: None,
1326 doc: doc(
1327 "/**\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 */",
1328 ),
1329 },
1330 ),
1331 (
1332 "slice".to_string(),
1333 MethodSig {
1334 optional: false,
1335 generics: Default::default(),
1336 params: vec![
1337 Param::with_default(
1338 "start",
1339 Type::Number,
1340 crate::DefaultValue::Number(0.0),
1341 ),
1342 Param::with_default(
1349 "end",
1350 Type::Number,
1351 crate::DefaultValue::Number(f64::INFINITY),
1352 ),
1353 ],
1354 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1355 predicate: None,
1356 doc: doc(
1357 "/**\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 */",
1358 ),
1359 },
1360 ),
1361 (
1362 "indexOf".to_string(),
1363 MethodSig {
1364 optional: false,
1365 generics: Default::default(),
1366 params: vec![
1367 Param::new("elem", Type::TypeVar("T".to_string())),
1368 Param::with_default(
1369 "fromIndex",
1370 Type::Number,
1371 crate::DefaultValue::Number(0.0),
1372 ),
1373 ],
1374 ret: Type::Number,
1375 predicate: None,
1376 doc: doc(
1377 "/**\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 */",
1378 ),
1379 },
1380 ),
1381 (
1382 "includes".to_string(),
1383 MethodSig {
1384 optional: false,
1385 generics: Default::default(),
1386 params: vec![
1387 Param::new("elem", Type::TypeVar("T".to_string())),
1388 Param::with_default(
1389 "fromIndex",
1390 Type::Number,
1391 crate::DefaultValue::Number(0.0),
1392 ),
1393 ],
1394 ret: Type::Boolean,
1395 predicate: None,
1396 doc: doc(
1397 "/**\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 */",
1398 ),
1399 },
1400 ),
1401 (
1402 "concat".to_string(),
1403 MethodSig {
1404 optional: false,
1405 generics: Default::default(),
1406 params: vec![Param::rest(
1410 "items",
1411 Type::Array(Box::new(Type::union(vec![
1412 Type::TypeVar("T".to_string()),
1413 Type::Readonly(Box::new(Type::Array(Box::new(
1414 Type::TypeVar("T".to_string()),
1415 )))),
1416 ]))),
1417 )],
1418 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1419 predicate: None,
1420 doc: doc(
1421 "/**\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 */",
1422 ),
1423 },
1424 ),
1425 (
1426 "reverse".to_string(),
1427 MethodSig {
1428 optional: false,
1429 generics: Default::default(),
1430 params: Vec::new(),
1431 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1432 predicate: None,
1433 doc: doc(
1434 "/**\n * Reverses the array in place and returns it.\n */",
1435 ),
1436 },
1437 ),
1438 (
1446 "filter".to_string(),
1447 MethodSig {
1448 optional: false,
1449 generics: Default::default(),
1450 params: vec![Param::new(
1451 "predicate",
1452 Type::Function {
1453 optional: 0,
1454 params: element_callback_params(Vec::new()),
1455 ret: Box::new(Type::Unknown),
1456 predicate: None,
1457 has_rest: false,
1458 },
1459 )],
1460 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1461 predicate: None,
1462 doc: doc(
1463 "/**\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 */",
1464 ),
1465 },
1466 ),
1467 (
1468 "reduce".to_string(),
1469 MethodSig {
1470 optional: false,
1471 generics: crate::GenericParameters::unconstrained(vec!["U".to_string()]),
1472 params: vec![
1473 Param::new(
1474 "callback",
1475 Type::Function {
1476 optional: 0,
1477 params: element_callback_params(vec![Type::TypeVar("U".to_string())]),
1478 ret: Box::new(Type::TypeVar("U".to_string())),
1479 predicate: None,
1480 has_rest: false,
1481 },
1482 ),
1483 Param::new("initial", Type::TypeVar("U".to_string())),
1484 ],
1485 ret: Type::TypeVar("U".to_string()),
1486 predicate: None,
1487 doc: doc(
1488 "/**\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 */",
1489 ),
1490 },
1491 ),
1492 (
1493 "forEach".to_string(),
1494 MethodSig {
1495 optional: false,
1496 generics: Default::default(),
1497 params: vec![Param::new(
1498 "callback",
1499 Type::Function {
1500 optional: 0,
1501 params: element_callback_params(Vec::new()),
1502 ret: Box::new(Type::Void),
1503 predicate: None,
1504 has_rest: false,
1505 },
1506 )],
1507 ret: Type::Void,
1508 predicate: None,
1509 doc: doc(
1510 "/**\n * Calls `callback(value, index, array)` once for each element in order.\n * @param callback Function called once per element.\n */",
1511 ),
1512 },
1513 ),
1514 (
1515 "some".to_string(),
1516 MethodSig {
1517 optional: false,
1518 generics: Default::default(),
1519 params: vec![Param::new(
1520 "predicate",
1521 Type::Function {
1522 optional: 0,
1523 params: element_callback_params(Vec::new()),
1524 ret: Box::new(Type::Unknown),
1525 predicate: None,
1526 has_rest: false,
1527 },
1528 )],
1529 ret: Type::Boolean,
1530 predicate: None,
1531 doc: doc(
1532 "/**\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 */",
1533 ),
1534 },
1535 ),
1536 (
1537 "every".to_string(),
1538 MethodSig {
1539 optional: false,
1540 generics: Default::default(),
1541 params: vec![Param::new(
1542 "predicate",
1543 Type::Function {
1544 optional: 0,
1545 params: element_callback_params(Vec::new()),
1546 ret: Box::new(Type::Unknown),
1547 predicate: None,
1548 has_rest: false,
1549 },
1550 )],
1551 ret: Type::Boolean,
1552 predicate: None,
1553 doc: doc(
1554 "/**\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 */",
1555 ),
1556 },
1557 ),
1558 (
1559 "sort".to_string(),
1560 MethodSig {
1561 optional: false,
1562 generics: Default::default(),
1563 params: vec![Param::with_default(
1564 "compareFn",
1565 Type::Union(vec![
1566 Type::Function {
1567 optional: 0,
1568 params: vec![
1569 Type::TypeVar("T".to_string()),
1570 Type::TypeVar("T".to_string()),
1571 ],
1572 ret: Box::new(Type::Number),
1573 predicate: None,
1574 has_rest: false,
1575 },
1576 Type::Undefined,
1577 ]),
1578 crate::DefaultValue::Undefined,
1579 )],
1580 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1581 predicate: None,
1582 doc: doc(
1583 "/**\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 */",
1584 ),
1585 },
1586 ),
1587 (
1588 "lastIndexOf".to_string(),
1589 MethodSig {
1590 optional: false,
1591 generics: Default::default(),
1592 params: vec![
1593 Param::new("elem", Type::TypeVar("T".to_string())),
1594 Param::with_default(
1595 "fromIndex",
1596 Type::Number,
1597 crate::DefaultValue::OmittedNumber {
1598 omitted: f64::INFINITY,
1599 undefined: 0.0,
1600 },
1601 ),
1602 ],
1603 ret: Type::Number,
1604 predicate: None,
1605 doc: doc(
1606 "/**\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 */",
1607 ),
1608 },
1609 ),
1610 (
1611 "reduceRight".to_string(),
1612 MethodSig {
1613 optional: false,
1614 generics: crate::GenericParameters::unconstrained(vec!["U".to_string()]),
1615 params: vec![
1616 Param::new(
1617 "callback",
1618 Type::Function {
1619 optional: 0,
1620 params: element_callback_params(vec![Type::TypeVar("U".to_string())]),
1621 ret: Box::new(Type::TypeVar("U".to_string())),
1622 predicate: None,
1623 has_rest: false,
1624 },
1625 ),
1626 Param::new("initial", Type::TypeVar("U".to_string())),
1627 ],
1628 ret: Type::TypeVar("U".to_string()),
1629 predicate: None,
1630 doc: doc(
1631 "/**\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 */",
1632 ),
1633 },
1634 ),
1635 (
1636 "fill".to_string(),
1637 MethodSig {
1638 optional: false,
1639 generics: Default::default(),
1640 params: vec![
1641 Param::new("value", Type::TypeVar("T".to_string())),
1642 Param::with_default(
1643 "start",
1644 Type::Number,
1645 crate::DefaultValue::Number(0.0),
1646 ),
1647 Param::with_default(
1648 "end",
1649 Type::Number,
1650 crate::DefaultValue::Number(f64::INFINITY),
1651 ),
1652 ],
1653 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1654 predicate: None,
1655 doc: doc(
1656 "/**\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 */",
1657 ),
1658 },
1659 ),
1660 (
1661 "copyWithin".to_string(),
1662 MethodSig {
1663 optional: false,
1664 generics: Default::default(),
1665 params: vec![
1666 Param::new("target", Type::Number),
1667 Param::with_default(
1668 "start",
1669 Type::Number,
1670 crate::DefaultValue::Number(0.0),
1671 ),
1672 Param::with_default(
1673 "end",
1674 Type::Number,
1675 crate::DefaultValue::Number(f64::INFINITY),
1676 ),
1677 ],
1678 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1679 predicate: None,
1680 doc: doc(
1681 "/**\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 */",
1682 ),
1683 },
1684 ),
1685 (
1686 "toReversed".to_string(),
1687 MethodSig {
1688 optional: false,
1689 generics: Default::default(),
1690 params: Vec::new(),
1691 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1692 predicate: None,
1693 doc: doc(
1694 "/**\n * Returns a new array with the elements in reverse order; the receiver is not modified.\n */",
1695 ),
1696 },
1697 ),
1698 (
1699 "toSorted".to_string(),
1700 MethodSig {
1701 optional: false,
1702 generics: Default::default(),
1703 params: vec![Param::with_default(
1704 "compareFn",
1705 Type::Union(vec![
1706 Type::Function {
1707 optional: 0,
1708 params: vec![
1709 Type::TypeVar("T".to_string()),
1710 Type::TypeVar("T".to_string()),
1711 ],
1712 ret: Box::new(Type::Number),
1713 predicate: None,
1714 has_rest: false,
1715 },
1716 Type::Undefined,
1717 ]),
1718 crate::DefaultValue::Undefined,
1719 )],
1720 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1721 predicate: None,
1722 doc: doc(
1723 "/**\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 */",
1724 ),
1725 },
1726 ),
1727 (
1728 "toSpliced".to_string(),
1729 MethodSig {
1730 optional: false,
1731 generics: Default::default(),
1732 params: vec![
1733 Param::new("start", Type::Number),
1734 Param::with_default(
1735 "deleteCount",
1736 Type::Number,
1737 crate::DefaultValue::OmittedNumber {
1738 omitted: f64::INFINITY,
1739 undefined: 0.0,
1740 },
1741 ),
1742 Param::rest(
1743 "items",
1744 Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1745 ),
1746 ],
1747 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1748 predicate: None,
1749 doc: doc(
1750 "/**\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 */",
1751 ),
1752 },
1753 ),
1754 (
1755 "with".to_string(),
1756 MethodSig {
1757 optional: false,
1758 generics: Default::default(),
1759 params: vec![
1760 Param::new("index", Type::Number),
1761 Param::new("value", Type::TypeVar("T".to_string())),
1762 ],
1763 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1764 predicate: None,
1765 doc: doc(
1766 "/**\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 */",
1767 ),
1768 },
1769 ),
1770 (
1771 "shift".to_string(),
1772 MethodSig {
1773 optional: false,
1774 generics: Default::default(),
1775 params: Vec::new(),
1776 ret: Type::Union(vec![
1777 Type::TypeVar("T".to_string()),
1778 Type::Undefined,
1779 ]),
1780 predicate: None,
1781 doc: doc(
1782 "/**\n * Removes and returns the first element, shifting the rest forward.\n * Returns `undefined` when the array is empty.\n */",
1783 ),
1784 },
1785 ),
1786 (
1787 "unshift".to_string(),
1788 MethodSig {
1789 optional: false,
1790 generics: Default::default(),
1791 params: vec![Param::rest(
1792 "items",
1793 Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1794 )],
1795 ret: Type::Number,
1796 predicate: None,
1797 doc: doc(
1798 "/**\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 */",
1799 ),
1800 },
1801 ),
1802 (
1803 "splice".to_string(),
1804 MethodSig {
1805 optional: false,
1806 generics: Default::default(),
1807 params: vec![
1808 Param::new("start", Type::Number),
1809 Param::with_default(
1810 "deleteCount",
1811 Type::Number,
1812 crate::DefaultValue::OmittedNumber {
1813 omitted: f64::INFINITY,
1814 undefined: 0.0,
1815 },
1816 ),
1817 Param::rest(
1818 "items",
1819 Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1820 ),
1821 ],
1822 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1823 predicate: None,
1824 doc: doc(
1825 "/**\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 */",
1826 ),
1827 },
1828 ),
1829 ]),
1830 properties: BTreeMap::from([(
1831 "length".to_string(),
1832 PropertySig {
1833 ty: Type::Number,
1834 readonly: false,
1835 intrinsic: true,
1836 optional: false,
1837 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. */"),
1838 },
1839 )]),
1840 dispatch: Dispatch::Direct,
1841 doc: doc("/** A homogeneous array of `T`. */"),
1842 },
1843 },
1844 );
1845 defs.types.insert(
1846 "ArrayConstructor".to_string(),
1847 TypeSymbol {
1848 name: "ArrayConstructor".to_string(),
1849 mangled_name: crate::mangle::prelude("ArrayConstructor"),
1850 declaration_span: Span::at(crate::FileId::PRELUDE),
1851 kind: TypeKind::Interface { index: None,
1852 generics: Default::default(),
1853 methods: BTreeMap::from([(
1854 "from".to_string(),
1855 MethodSig {
1856 optional: false,
1857 generics: crate::GenericParameters::unconstrained(vec!["T".to_string(), "U".to_string()]),
1858 params: vec![
1859 Param::new(
1860 "src",
1861 Type::union(vec![
1862 Type::Readonly(Box::new(Type::Array(Box::new(Type::TypeVar("T".to_string()))))),
1863 Type::prelude_interface(
1864 "Iterator".to_string(),
1865 vec![Type::TypeVar("T".to_string())],
1866 ),
1867 Type::prelude_interface(
1868 "Iterable".to_string(),
1869 vec![Type::TypeVar("T".to_string())],
1870 ),
1871 array_like_type(),
1872 ]),
1873 ),
1874 Param::with_default(
1875 "mapFn",
1876 Type::union(vec![
1877 Type::Function {
1878 optional: 0,
1879 params: vec![Type::TypeVar("T".to_string()), Type::Number],
1880 ret: Box::new(Type::TypeVar("U".to_string())),
1881 predicate: None,
1882 has_rest: false,
1883 },
1884 Type::Undefined,
1885 ]),
1886 crate::DefaultValue::Undefined,
1887 ),
1888 ],
1889 ret: Type::Array(Box::new(Type::TypeVar("U".to_string()))),
1890 predicate: None,
1891 doc: doc(
1892 "/**\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 */",
1893 ),
1894 },
1895 ), (
1896 "of".to_string(),
1897 MethodSig {
1898 optional: false,
1899 generics: crate::GenericParameters::unconstrained(vec!["T".to_string()]),
1900 params: vec![Param::rest(
1901 "items",
1902 Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1903 )],
1904 ret: Type::Array(Box::new(Type::TypeVar("T".to_string()))),
1905 predicate: None,
1906 doc: doc(
1907 "/** Builds an array from its arguments — `Array.of(1, 2, 3)` is `[1, 2, 3]`. */",
1908 ),
1909 },
1910 ), (
1911 "isArray".to_string(),
1912 MethodSig {
1913 optional: false,
1914 generics: crate::GenericParameters::unconstrained(vec!["T".to_string()]),
1915 params: vec![Param::new("value", Type::TypeVar("T".to_string()))],
1916 ret: Type::Boolean,
1917 predicate: Some(crate::TypePredicate {
1918 parameter_index: 0,
1919 asserted_type: Type::Array(Box::new(Type::Unknown)),
1920 }),
1921 doc: doc(
1922 "/**\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 */",
1923 ),
1924 },
1925 )]),
1926 properties: BTreeMap::new(),
1927 dispatch: Dispatch::Static,
1928 doc: doc(
1929 "/** Constructor object for `Array`. Accessed via the global `Array` binding. */",
1930 ),
1931 },
1932 },
1933 );
1934
1935 defs.values.insert(
1936 "Array".to_string(),
1937 ValueSymbol {
1938 name: "Array".to_string(),
1939 mangled_name: crate::mangle::prelude("Array"),
1940 declaration_span: Span::at(crate::FileId::PRELUDE),
1941 kind: ValueKind::Const {
1942 ty: Type::prelude_interface("ArrayConstructor".to_string(), Vec::new()),
1943 doc: doc(
1944 "/** The `Array` constructor — call `Array.isArray(x)` to runtime-check whether a value is an array. */",
1945 ),
1946 },
1947 },
1948 );
1949}