113 lines
2.8 KiB
TypeScript
113 lines
2.8 KiB
TypeScript
import { Arr, Function, KeyOfType, Tail } from "./types.ts";
|
|
import { map } from "./iter.ts";
|
|
|
|
export class Chain<T extends Arr> {
|
|
run;
|
|
|
|
constructor(run: () => T) {
|
|
this.run = run;
|
|
}
|
|
|
|
static from<T>(value: T) {
|
|
return new Chain(() => [value] as [T]);
|
|
}
|
|
|
|
to<A extends Arr, O>(map: Function<[...T, ...A], O>, ...args: A) {
|
|
const this_run = this.run;
|
|
return new Chain(() => [map(...this_run(), ...args)] as [O]);
|
|
}
|
|
|
|
front<I extends Arr>(...values: I) {
|
|
const this_run = this.run;
|
|
return new Chain(() => [...values, ...this_run()] as [...I, ...T]);
|
|
}
|
|
|
|
back<I extends Arr>(...values: I) {
|
|
const this_run = this.run;
|
|
return new Chain(() => [...this_run(), ...values] as [...T, ...I]);
|
|
}
|
|
|
|
nth<Index extends number>(index: Index) {
|
|
const this_run = this.run;
|
|
return new Chain(() => [this_run()[index]] as T[Index]);
|
|
}
|
|
|
|
call<
|
|
A extends Arr,
|
|
Arg extends [...Tail<T>, ...A],
|
|
M extends KeyOfType<T[0], Function<Arg>>,
|
|
O extends ReturnType<T[0][M]>,
|
|
>(method: M, ...args: A) {
|
|
const this_run = this.run;
|
|
return new Chain(() => {
|
|
const [instance, ...rest] = this_run();
|
|
return [instance[method](...rest, ...args)] as [O];
|
|
});
|
|
}
|
|
|
|
call_ignore<
|
|
A extends Arr,
|
|
Arg extends [...Tail<T>, ...A],
|
|
M extends KeyOfType<T[0], Function<Arg>>,
|
|
>(method: M, ...args: A) {
|
|
const this_run = this.run;
|
|
return new Chain(() => {
|
|
const res1: T = this_run();
|
|
const [instance, ...rest] = res1;
|
|
instance[method](...rest, ...args);
|
|
return res1;
|
|
});
|
|
}
|
|
|
|
call_keep<
|
|
A extends Arr,
|
|
Arg extends [...Tail<T>, ...A],
|
|
M extends KeyOfType<T[0], Function<Arg>>,
|
|
O extends ReturnType<T[0][M]>,
|
|
>(method: M, ...args: A) {
|
|
const this_run = this.run;
|
|
return new Chain(() => {
|
|
const res1 = this_run();
|
|
const [instance, ...rest] = res1;
|
|
const res2: O = instance[method](...rest, ...args);
|
|
return [...res1, res2] as [...T, O];
|
|
});
|
|
}
|
|
|
|
construct<
|
|
A extends Arr,
|
|
C extends new (...args: [...T, ...A]) => unknown,
|
|
O extends InstanceType<C>,
|
|
>(class_: C, ...args: A) {
|
|
const this_run = this.run;
|
|
return new Chain(() => [new class_(...this_run(), ...args)] as [O]);
|
|
}
|
|
}
|
|
Deno.test("example", async () => {
|
|
const { assertEquals } = await import("https://deno.land/std@0.224.0/assert/mod.ts");
|
|
|
|
function times_2(num: number) {
|
|
return num * 2;
|
|
}
|
|
|
|
// type: number
|
|
const [_o1] = Chain.from(3).to(times_2).run();
|
|
// type: number
|
|
const [_o2] = Chain.from(3).front(2, 5).to(Math.max).run();
|
|
|
|
function parse_and_add(text: string, num: number) {
|
|
return parseInt(text) + num;
|
|
}
|
|
|
|
// type: string
|
|
const [_o3] = Chain.from(3).front("5").to(parse_and_add).call("toString").run();
|
|
|
|
// type: Set<number>
|
|
const [_o4] = Chain.from([1, 2, 3])
|
|
.call_keep("push", 7)
|
|
.construct(Set<number>)
|
|
.call_ignore("add", 8)
|
|
.to(map, (item: number) => item.toString())
|
|
.run();
|
|
assertEquals([..._o4], ["1", "2", "3", "7", "8"]);
|
|
});
|