import {HyperValue} from '../core/core'; import {AutoScope} from './auto'; import {CastScope} from './cast'; import {mixSome, Mixin} from '../utils/mixin'; export interface IteratorFn { (value: T, index: number, array: T[]): R; } export interface Reducer { (acc: R, value: T, index: number, array: T[]): R; } export const Base = mixSome(AutoScope, CastScope) as Mixin; export class ArrayScope extends Base { length(hv: HyperValue): HyperValue { return this.auto(() => { return hv.$.length; }); } map(hv: HyperValue, mapFn: IteratorFn): HyperValue { return this.auto(() => { return hv.$.map(mapFn); }); } every(hv: HyperValue, mapFn: IteratorFn): HyperValue { return this.auto(() => { return hv.$.every(mapFn); }); } some(hv: HyperValue, mapFn: IteratorFn): HyperValue { return this.auto(() => { return hv.$.some(mapFn); }); } filter(hv: HyperValue, mapFn: IteratorFn): HyperValue { return this.auto(() => { return hv.$.filter(mapFn); }); } reduce(hv: HyperValue, reducer: Reducer): HyperValue; reduce(hv: HyperValue, reducer: Reducer, initial: R): HyperValue; reduce(hv: HyperValue, reducer: Reducer, initial?: R): HyperValue { return this.auto(() => { return initial !== undefined ? hv.$.reduce(reducer, initial) : hv.$.reduce(reducer as any as Reducer) as any as R; }); } find(hv: HyperValue, fn: IteratorFn): HyperValue { return this.auto(() => { const array = hv.$; for (let i = 0; i < array.length; i++) { if (fn(array[i], i, array)) { return array[i]; } } return null; }); } findIndex(hv: HyperValue, fn: IteratorFn): HyperValue { return this.auto(() => { const array = hv.$; for (let i = 0; i < array.length; i++) { if (fn(array[i], i, array)) { return i; } } return -1; }); } concat(hv1: HyperValue): HyperValue; concat(hv1: HyperValue, hv2: HyperValue): HyperValue<(T1 | T2)[]>; concat(hv1: HyperValue, hv2: HyperValue, hv3: HyperValue): HyperValue<(T1 | T2 | T3)[]>; concat(...hvs: HyperValue[]): HyperValue { return this.auto(() => { const arrays = hvs.map(hv => hv.$); return Array.prototype.concat.apply([], [...arrays]); }); } slice(hv: HyperValue, start?: number | HyperValue, end?: number | HyperValue): HyperValue { return this.auto(() => { const array = hv.$; const s = start === undefined ? 0 : this.read(start); const e = end === undefined ? array.length : this.read(end); return array.slice(s, e); }); } insert(hv: HyperValue, index: number, elems: T | T[]) { const array = hv.$; if (index < 0) { index = array.length + index; } const newArray = ([] as T[]).concat( array.slice(0, index), elems, array.slice(index) ); hv.$ = newArray; } remove(hv: HyperValue, index: number, length: number) { const array = hv.$; if (index < 0) { index = array.length + index; } const newArray = ([] as any[]).concat(array.slice(0, index), array.slice(index + length)); hv.$ = newArray; } sort(hv: HyperValue, sortFn?: (a: T, b: T) => number): HyperValue { return this.auto(() => { const array = hv.$.slice(); array.sort(sortFn); return array; }); } }