@cgtk/std 0.0.195 → 0.0.197
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/array.d.ts +2 -1
- package/array.js +2 -1
- package/async.d.ts +5 -6
- package/async.js +10 -12
- package/buffer.d.ts +7 -14
- package/buffer.js +25 -51
- package/bytes.d.ts +14 -0
- package/bytes.js +54 -0
- package/channel.d.ts +37 -0
- package/channel.js +82 -0
- package/checks.d.ts +4 -0
- package/checks.js +7 -3
- package/dom.d.ts +20 -2
- package/dom.js +62 -4
- package/fn.d.ts +6 -8
- package/fn.js +11 -8
- package/iterable.d.ts +1 -11
- package/iterable.js +5 -15
- package/math.d.ts +1 -0
- package/math.js +4 -0
- package/package.json +4 -4
- package/port.d.ts +2 -2
- package/port.js +8 -8
- package/schedule.d.ts +3 -3
- package/schedule.js +8 -6
- package/scope.d.ts +19 -0
- package/scope.js +41 -0
- package/string.d.ts +1 -0
- package/string.js +1 -0
- package/types.d.ts +3 -5
- package/resource.d.ts +0 -15
- package/resource.js +0 -34
- package/signal.d.ts +0 -37
- package/signal.js +0 -89
package/array.d.ts
CHANGED
|
@@ -7,7 +7,8 @@ export declare const pop: <T>(xs: T[]) => T[];
|
|
|
7
7
|
export declare const shift: <T>(xs: T[]) => T[];
|
|
8
8
|
export declare const first: <T>(xs: T[]) => T;
|
|
9
9
|
export declare const cap: <T>(n: number, f: Fn<T[]>) => Fn<T[], T[]>;
|
|
10
|
-
export declare const
|
|
10
|
+
export declare const sliding: <T>(n: number, xs?: T[]) => (x: T) => T[];
|
|
11
|
+
export declare const dropping: <T>(n: number, xs?: T[]) => (x: T) => T[];
|
|
11
12
|
export declare const tuple: <T, N extends number>(...xs: T[] & {
|
|
12
13
|
length: N;
|
|
13
14
|
}) => Tuple<T, N>;
|
package/array.js
CHANGED
|
@@ -11,7 +11,8 @@ export const cap = (n, f) => xs => {
|
|
|
11
11
|
f(xs);
|
|
12
12
|
return xs;
|
|
13
13
|
};
|
|
14
|
-
export const
|
|
14
|
+
export const sliding = (n, xs = []) => comp(scan((push), xs), cap(n, shift));
|
|
15
|
+
export const dropping = (n, xs = []) => comp(scan((push), xs), cap(n, pop));
|
|
15
16
|
export const tuple = (...xs) => xs;
|
|
16
17
|
export const seek = (arr, vals, offset = 0) => {
|
|
17
18
|
for (let i = offset, n = arr.length; i < n; i++)
|
package/async.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare const
|
|
1
|
+
import type { Lazy, Maybe, Dispose, MaybePromise, Promisified, AsyncDispose } from "./types.js";
|
|
2
|
+
export declare const RESOLVED: Promise<void>;
|
|
3
|
+
export declare const timeout: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
3
4
|
export declare const delay: (ms: number, signal?: AbortSignal) => <T>(x: T) => Promise<T>;
|
|
4
5
|
export declare const probing: <T>(p: Promise<T>) => Lazy<Maybe<T>>;
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const
|
|
7
|
-
export declare const then: <T>(p: Promise<T>) => <R>(f: Fn<T, R>) => Promise<R>;
|
|
8
|
-
export declare const dispose: (p: Promise<Dispose>) => Dispose;
|
|
6
|
+
export declare const promisify: <T>(x: MaybePromise<T>) => Promisified<T>;
|
|
7
|
+
export declare const dispose: (p: Promise<Dispose>) => AsyncDispose;
|
package/async.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { noop, then } from "./fn.js";
|
|
2
|
+
import { isPromise } from "./checks.js";
|
|
3
|
+
export const RESOLVED = Promise.resolve();
|
|
3
4
|
export const timeout = (ms, signal) => new Promise((resolve, reject) => {
|
|
4
5
|
if (signal?.aborted)
|
|
5
6
|
reject(signal.reason);
|
|
@@ -8,7 +9,7 @@ export const timeout = (ms, signal) => new Promise((resolve, reject) => {
|
|
|
8
9
|
if (signal?.aborted)
|
|
9
10
|
reject(signal.reason);
|
|
10
11
|
else
|
|
11
|
-
resolve(
|
|
12
|
+
resolve();
|
|
12
13
|
}, ms);
|
|
13
14
|
signal?.addEventListener("abort", () => (clearTimeout(t), reject(signal.reason)), { once: true });
|
|
14
15
|
}
|
|
@@ -19,13 +20,10 @@ export const probing = (p) => {
|
|
|
19
20
|
p.then(x => value = x);
|
|
20
21
|
return () => value;
|
|
21
22
|
};
|
|
22
|
-
export const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
export const promisify = (x) => (isPromise(x) ? x : Promise.resolve(x));
|
|
24
|
+
export const dispose = (p) => {
|
|
25
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
26
|
+
let dispose = noop, disposed = false;
|
|
27
|
+
p.then(d => (dispose = then(d, resolve), disposed && dispose()));
|
|
28
|
+
return () => (disposed = true, dispose(), promise);
|
|
28
29
|
};
|
|
29
|
-
export const promise = (x) => (x instanceof Promise) ? x : Promise.resolve(x);
|
|
30
|
-
export const then = (p) => (f) => p.then(f);
|
|
31
|
-
export const dispose = (p) => disposable(async (dispose) => dispose(await p));
|
package/buffer.d.ts
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
i8: Fn<void, number>;
|
|
9
|
-
i16: Fn<boolean, number>;
|
|
10
|
-
i32: Fn<boolean, number>;
|
|
11
|
-
f32: Fn<boolean, number>;
|
|
12
|
-
f64: Fn<boolean, number>;
|
|
13
|
-
}
|
|
14
|
-
export declare const bufReader: (data: Uint8Array, offset?: number) => BufReader;
|
|
1
|
+
import type { Maybe } from "./types.js";
|
|
2
|
+
export declare const fifo: <T>(n?: number) => {
|
|
3
|
+
put(x: T): Promise<number>;
|
|
4
|
+
take(): Promise<T>;
|
|
5
|
+
readonly size: number;
|
|
6
|
+
peek(): Maybe<T>;
|
|
7
|
+
};
|
package/buffer.js
CHANGED
|
@@ -1,54 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
1
|
+
import { isDefined } from "./checks.js";
|
|
2
|
+
export const fifo = (n = 1) => {
|
|
3
|
+
const data = [];
|
|
4
|
+
const pushes = [];
|
|
5
|
+
const takes = [];
|
|
5
6
|
return {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return x;
|
|
27
|
-
},
|
|
28
|
-
i8() {
|
|
29
|
-
const x = dv.getInt8(offset);
|
|
30
|
-
offset += 1;
|
|
31
|
-
return x;
|
|
32
|
-
},
|
|
33
|
-
i16(littleEndian = true) {
|
|
34
|
-
const x = dv.getInt16(offset, littleEndian);
|
|
35
|
-
offset += 2;
|
|
36
|
-
return x;
|
|
37
|
-
},
|
|
38
|
-
i32(littleEndian = true) {
|
|
39
|
-
const x = dv.getInt32(offset, littleEndian);
|
|
40
|
-
offset += 4;
|
|
41
|
-
return x;
|
|
42
|
-
},
|
|
43
|
-
f32(littleEndian = true) {
|
|
44
|
-
const x = dv.getFloat32(offset, littleEndian);
|
|
45
|
-
offset += 4;
|
|
46
|
-
return x;
|
|
47
|
-
},
|
|
48
|
-
f64(littleEndian = true) {
|
|
49
|
-
const x = dv.getFloat64(offset, littleEndian);
|
|
50
|
-
offset += 8;
|
|
51
|
-
return x;
|
|
52
|
-
},
|
|
7
|
+
async put(x) {
|
|
8
|
+
if (data.length >= n)
|
|
9
|
+
return new Promise(resolve => pushes.push(() => (data.push(x), resolve(data.length))));
|
|
10
|
+
const len = data.push(x);
|
|
11
|
+
const f = takes.shift();
|
|
12
|
+
if (isDefined(f))
|
|
13
|
+
f(x);
|
|
14
|
+
return Promise.resolve(len);
|
|
15
|
+
},
|
|
16
|
+
async take() {
|
|
17
|
+
if (data.length == 0)
|
|
18
|
+
return new Promise(resolve => takes.push(resolve));
|
|
19
|
+
const x = data.shift();
|
|
20
|
+
const f = pushes.shift();
|
|
21
|
+
if (isDefined(f))
|
|
22
|
+
f();
|
|
23
|
+
return Promise.resolve(x);
|
|
24
|
+
},
|
|
25
|
+
get size() { return data.length; },
|
|
26
|
+
peek() { return data[0]; }
|
|
53
27
|
};
|
|
54
28
|
};
|
package/bytes.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Fn } from "./types.js";
|
|
2
|
+
export interface BufReader {
|
|
3
|
+
offset: number;
|
|
4
|
+
line: Fn<void, string>;
|
|
5
|
+
u8: Fn<void, number>;
|
|
6
|
+
u16: Fn<boolean, number>;
|
|
7
|
+
u32: Fn<boolean, number>;
|
|
8
|
+
i8: Fn<void, number>;
|
|
9
|
+
i16: Fn<boolean, number>;
|
|
10
|
+
i32: Fn<boolean, number>;
|
|
11
|
+
f32: Fn<boolean, number>;
|
|
12
|
+
f64: Fn<boolean, number>;
|
|
13
|
+
}
|
|
14
|
+
export declare const bufReader: (data: Uint8Array, offset?: number) => BufReader;
|
package/bytes.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readLine } from './string.js';
|
|
2
|
+
export const bufReader = (data, offset = 0) => {
|
|
3
|
+
const rl = readLine();
|
|
4
|
+
const dv = new DataView(data.buffer, data.byteOffset);
|
|
5
|
+
return {
|
|
6
|
+
get offset() { return offset; },
|
|
7
|
+
set offset(x) { offset = x; },
|
|
8
|
+
line() {
|
|
9
|
+
const line = rl(data, offset);
|
|
10
|
+
offset += line.length;
|
|
11
|
+
return line;
|
|
12
|
+
},
|
|
13
|
+
u8() {
|
|
14
|
+
const x = dv.getUint8(offset);
|
|
15
|
+
offset += 1;
|
|
16
|
+
return x;
|
|
17
|
+
},
|
|
18
|
+
u16(littleEndian = true) {
|
|
19
|
+
const x = dv.getUint16(offset, littleEndian);
|
|
20
|
+
offset += 2;
|
|
21
|
+
return x;
|
|
22
|
+
},
|
|
23
|
+
u32(littleEndian = true) {
|
|
24
|
+
const x = dv.getUint16(offset, littleEndian);
|
|
25
|
+
offset += 4;
|
|
26
|
+
return x;
|
|
27
|
+
},
|
|
28
|
+
i8() {
|
|
29
|
+
const x = dv.getInt8(offset);
|
|
30
|
+
offset += 1;
|
|
31
|
+
return x;
|
|
32
|
+
},
|
|
33
|
+
i16(littleEndian = true) {
|
|
34
|
+
const x = dv.getInt16(offset, littleEndian);
|
|
35
|
+
offset += 2;
|
|
36
|
+
return x;
|
|
37
|
+
},
|
|
38
|
+
i32(littleEndian = true) {
|
|
39
|
+
const x = dv.getInt32(offset, littleEndian);
|
|
40
|
+
offset += 4;
|
|
41
|
+
return x;
|
|
42
|
+
},
|
|
43
|
+
f32(littleEndian = true) {
|
|
44
|
+
const x = dv.getFloat32(offset, littleEndian);
|
|
45
|
+
offset += 4;
|
|
46
|
+
return x;
|
|
47
|
+
},
|
|
48
|
+
f64(littleEndian = true) {
|
|
49
|
+
const x = dv.getFloat64(offset, littleEndian);
|
|
50
|
+
offset += 8;
|
|
51
|
+
return x;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
};
|
package/channel.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Fn, FnV, Dispose, Structure, Pred } from "./types.js";
|
|
2
|
+
export interface Channel<T> {
|
|
3
|
+
next: Fn<T>;
|
|
4
|
+
on(next: Fn<T>, done?: Dispose): Dispose;
|
|
5
|
+
done: Dispose;
|
|
6
|
+
stateful(f: Fn<T, Dispose>, done?: Dispose): Dispose;
|
|
7
|
+
to<S>(f: Fn<Channel<T>, Channel<S>>): Channel<S>;
|
|
8
|
+
}
|
|
9
|
+
export declare const create: <T>(subs?: Set<{
|
|
10
|
+
next: Fn<T>;
|
|
11
|
+
done: Dispose;
|
|
12
|
+
}>) => Channel<T>;
|
|
13
|
+
export declare const cached: <T>(ch?: Channel<T>) => Channel<T>;
|
|
14
|
+
export interface Value<T> extends Channel<T> {
|
|
15
|
+
value: T;
|
|
16
|
+
}
|
|
17
|
+
export declare const value: <T>(x: T, ch?: Channel<T>) => Value<T>;
|
|
18
|
+
export declare const pipe: <T, S>(f: Fn<Fn<S>, Fn<T>>, ch?: Channel<S>) => Fn<Channel<T>, Channel<S>>;
|
|
19
|
+
export declare const map: <T, S>(f: Fn<T, S>, ch?: Channel<S>) => Fn<Channel<T>, Channel<S>>;
|
|
20
|
+
export declare const filter: <T>(p: Pred<T>, ch?: Channel<T>) => Fn<Channel<T>, Channel<T>>;
|
|
21
|
+
export declare const then: <T>(ch?: Channel<T>) => Fn<Channel<Promise<T>>, Channel<T>>;
|
|
22
|
+
export declare const dedup: <T, S = T>(key?: Fn<T, S>, ch?: Channel<T>) => Fn<Channel<T>, Channel<T>>;
|
|
23
|
+
export declare const gen: <T>(f: FnV<[Fn<T>, Dispose], Dispose | void>, ch?: Channel<T>) => Channel<T>;
|
|
24
|
+
export declare const reduce: <T, S>(f: FnV<[S, T], S>, a: S, ch?: Channel<S>) => (c: Channel<T>) => Channel<S>;
|
|
25
|
+
export declare const flatten: <T>(ch?: Channel<T>) => (cs: Channel<Channel<T>>) => Channel<T>;
|
|
26
|
+
export declare const latest: <T>(ch?: Channel<T>) => (cs: Channel<Channel<T>>) => Channel<T>;
|
|
27
|
+
export declare const microOn: <T>(ch?: Channel<T>) => Channel<T>;
|
|
28
|
+
type F2C<T> = T extends Fn<infer U> ? Channel<U> : T extends readonly (infer U)[] ? readonly F2C<U>[] : {
|
|
29
|
+
[K in keyof T]: F2C<T[K]>;
|
|
30
|
+
};
|
|
31
|
+
export declare const derive: <T, F extends Structure<Fn<any>>>(cs: F2C<F>, f: Fn<Fn<T>, F>, ch?: Channel<T>) => Channel<T>;
|
|
32
|
+
export interface Reactive<T> extends Value<T> {
|
|
33
|
+
set: Fn<T | Fn<T, T>>;
|
|
34
|
+
update: Fn<Fn<T>>;
|
|
35
|
+
}
|
|
36
|
+
export declare const reactive: <T>(x: T) => Reactive<T>;
|
|
37
|
+
export {};
|
package/channel.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as F from "./fn.js";
|
|
2
|
+
import { isFunction } from "./checks.js";
|
|
3
|
+
import { add } from "./set.js";
|
|
4
|
+
const channel = (next, on, done = F.noop) => ({
|
|
5
|
+
next, on, done,
|
|
6
|
+
to(f) { return f(this); },
|
|
7
|
+
stateful(next, done = F.noop) {
|
|
8
|
+
const swap = F.swapping();
|
|
9
|
+
return on(swap(next), swap(done));
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
export const create = (subs = new Set()) => channel((x) => subs.forEach(s => s.next(x)), (next, done = F.noop) => {
|
|
13
|
+
const del = add(subs, { next, done });
|
|
14
|
+
return () => del() && done();
|
|
15
|
+
}, () => (subs.forEach(s => s.done()), subs.clear()));
|
|
16
|
+
const None = Symbol('None');
|
|
17
|
+
export const cached = (ch = create()) => {
|
|
18
|
+
let x = None;
|
|
19
|
+
return channel(y => ch.next(x = y), (next, done) => {
|
|
20
|
+
if (x !== None)
|
|
21
|
+
next(x);
|
|
22
|
+
return ch.on(next, done);
|
|
23
|
+
}, ch.done);
|
|
24
|
+
};
|
|
25
|
+
export const value = (x, ch = create()) => Object.defineProperties(channel(y => ch.next(x = y), (next, done) => (next(x), ch.on(next, done)), ch.done), {
|
|
26
|
+
value: {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: () => x,
|
|
29
|
+
set: (y) => x = y
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
export const pipe = (f, ch = create()) => c => channel(ch.next, ch.on, c.on(f(ch.next), ch.done));
|
|
33
|
+
export const map = (f, ch) => pipe(F.bind(F.comp, f), ch);
|
|
34
|
+
export const filter = (p, ch) => pipe(F.bind(F.filter, p), ch);
|
|
35
|
+
export const then = (ch) => pipe(next => p => p.then(next), ch);
|
|
36
|
+
export const dedup = (key = F.identity, ch) => pipe(next => {
|
|
37
|
+
let x = None;
|
|
38
|
+
return (y) => {
|
|
39
|
+
const k = key(y);
|
|
40
|
+
if (k !== x)
|
|
41
|
+
next(y);
|
|
42
|
+
x = k;
|
|
43
|
+
};
|
|
44
|
+
}, ch);
|
|
45
|
+
export const gen = (f, ch = create()) => {
|
|
46
|
+
let ended = false;
|
|
47
|
+
let done = () => { ended = true; };
|
|
48
|
+
done = F.forEach(f(ch.next, () => done()) ?? F.noop, ch.done);
|
|
49
|
+
return ended ? channel(F.noop, F.constantly(F.noop)) : channel(ch.next, ch.on, done);
|
|
50
|
+
};
|
|
51
|
+
export const reduce = (f, a, ch = create()) => (c) => channel(F.noop, ch.on, c.on(F.scan(f, a), F.forEach(() => ch.next(a), ch.done)));
|
|
52
|
+
export const flatten = (ch = create()) => (cs) => {
|
|
53
|
+
const ds = new Set();
|
|
54
|
+
return channel(ch.next, ch.on, cs.on(c => (ds.add(c.done), c.on(ch.next)), F.forEach(ch.done, () => ds.forEach(d => d()))));
|
|
55
|
+
};
|
|
56
|
+
export const latest = (ch = create()) => (cs) => channel(ch.next, ch.on, cs.stateful(c => c.on(ch.next, c.done), ch.done));
|
|
57
|
+
export const microOn = (ch = create()) => channel(ch.next, (next, done = F.noop) => {
|
|
58
|
+
const ctrl = new AbortController();
|
|
59
|
+
let off = () => (ctrl.abort(), done());
|
|
60
|
+
queueMicrotask(() => off = ctrl.signal.aborted ? F.noop : ch.on(next, done));
|
|
61
|
+
return () => off();
|
|
62
|
+
}, ch.done);
|
|
63
|
+
const isChannel = (c) => Object.hasOwn(c, "next") && isFunction(c.next) && Object.hasOwn(c, "on") && isFunction(c.on) && Object.hasOwn(c, "next") && isFunction(c.next);
|
|
64
|
+
export const derive = (cs, f, ch = create()) => {
|
|
65
|
+
let done = F.noop;
|
|
66
|
+
const rec = (cs, fs) => {
|
|
67
|
+
if (isFunction(fs) && isChannel(cs))
|
|
68
|
+
return cs.on(fs, () => done());
|
|
69
|
+
else if (Array.isArray(cs) && Array.isArray(fs))
|
|
70
|
+
return F.forEach(...cs.map((c, i) => rec(c, fs[i])));
|
|
71
|
+
return F.forEach(...Object.entries(cs).map(([k, v]) => rec(v, fs[k])));
|
|
72
|
+
};
|
|
73
|
+
done = F.forEach(rec(cs, f(ch.next)), ch.done);
|
|
74
|
+
return channel(ch.next, ch.on, done);
|
|
75
|
+
};
|
|
76
|
+
export const reactive = (x) => {
|
|
77
|
+
const ch = value(x);
|
|
78
|
+
return Object.assign(ch, {
|
|
79
|
+
set: (y) => ch.next(isFunction(y) ? y(ch.value) : y),
|
|
80
|
+
update: (f) => (f(ch.value), ch.next(ch.value)),
|
|
81
|
+
});
|
|
82
|
+
};
|
package/checks.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { TypedArray, NumberArray, BigIntArray, Pred, TPred, Maybe } from ".
|
|
|
2
2
|
export declare const isTypedArray: (x: any) => x is TypedArray;
|
|
3
3
|
export declare const isNumberArray: (x: any) => x is NumberArray;
|
|
4
4
|
export declare const isBigIntArray: (x: any) => x is BigIntArray;
|
|
5
|
+
export declare const isBoolean: (x: any) => x is boolean;
|
|
5
6
|
export declare const isUndefined: (x: any) => x is undefined;
|
|
6
7
|
export declare const isNull: (x: any) => x is null;
|
|
7
8
|
export declare const isDefined: <T>(x: Maybe<T>) => x is T;
|
|
@@ -27,3 +28,6 @@ export declare const isEmpty: (x: {
|
|
|
27
28
|
length: number;
|
|
28
29
|
}) => boolean;
|
|
29
30
|
export declare const counted: (n: number) => () => boolean;
|
|
31
|
+
export declare const isBitSet: (x: number, n: number) => boolean;
|
|
32
|
+
export declare const isPromise: <T = any>(x: any) => x is Promise<T>;
|
|
33
|
+
export declare const isPromiseLike: <T = any>(x: any) => x is PromiseLike<T>;
|
package/checks.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { comp, not, apply, and } from "./fn.js";
|
|
2
|
-
import {
|
|
2
|
+
import { sliding } from "./array.js";
|
|
3
3
|
export const isTypedArray = (x) => x && (x instanceof Uint8Array || x instanceof Uint8ClampedArray ||
|
|
4
4
|
x instanceof Uint16Array || x instanceof Uint32Array ||
|
|
5
5
|
x instanceof Int8Array || x instanceof Int16Array || x instanceof Int32Array ||
|
|
@@ -10,6 +10,7 @@ export const isNumberArray = (x) => x && (x instanceof Uint8Array || x instanceo
|
|
|
10
10
|
x instanceof Int8Array || x instanceof Int16Array || x instanceof Int32Array ||
|
|
11
11
|
x instanceof Float16Array || x instanceof Float32Array || x instanceof Float64Array);
|
|
12
12
|
export const isBigIntArray = (x) => x && (x instanceof BigUint64Array || x instanceof BigInt64Array);
|
|
13
|
+
export const isBoolean = (x) => typeof x === "boolean";
|
|
13
14
|
export const isUndefined = (x) => x === undefined;
|
|
14
15
|
export const isNull = (x) => x === null;
|
|
15
16
|
export const isDefined = (x) => !isUndefined(x);
|
|
@@ -28,8 +29,8 @@ export const isclose = (a, b, eps = Number.EPSILON) => Math.abs(a - b) < eps;
|
|
|
28
29
|
export const allclose = (a, b, eps) => a.length == b.length && a.every((x, i) => isclose(x, b[i], eps));
|
|
29
30
|
export const equal = (a, b) => a == b;
|
|
30
31
|
export const strictEqual = (a, b) => a === b;
|
|
31
|
-
export const isDiffPrev = (eq = (strictEqual)) => comp(
|
|
32
|
-
export const isLonger = (delta) => comp((x) => [performance.now(), x],
|
|
32
|
+
export const isDiffPrev = (eq = (strictEqual)) => comp(sliding(2), not(apply(eq)));
|
|
33
|
+
export const isLonger = (delta) => comp((x) => [performance.now(), x], sliding(2), (xs) => xs.length < 2 || xs[1][0] - xs[0][0] > delta);
|
|
33
34
|
export const isFunction = (x) => typeof x === "function";
|
|
34
35
|
export const isAborted = (signal) => () => signal.aborted;
|
|
35
36
|
export const isArrayBufferLike = (x) => x instanceof ArrayBuffer || x instanceof SharedArrayBuffer;
|
|
@@ -42,3 +43,6 @@ export const counted = (n) => {
|
|
|
42
43
|
let m = 0;
|
|
43
44
|
return () => m++ < n;
|
|
44
45
|
};
|
|
46
|
+
export const isBitSet = (x, n) => (x & (1 << n)) !== 0;
|
|
47
|
+
export const isPromise = (x) => x instanceof Promise;
|
|
48
|
+
export const isPromiseLike = (x) => x instanceof Promise;
|
package/dom.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Fn, Dispose, RecordOf, Maybe } from "./types.js";
|
|
1
|
+
import type { Fn, FnV, Dispose, RecordOf, Maybe } from "./types.js";
|
|
2
2
|
export declare const customEvent: <T>(type: string, detail: T, { composed, bubbles, cancelable }?: EventInit) => CustomEvent<T>;
|
|
3
3
|
type ListenOpts = boolean | AddEventListenerOptions;
|
|
4
4
|
export declare const on: {
|
|
@@ -36,16 +36,34 @@ export declare const onAll: {
|
|
|
36
36
|
type DragHandlers = Record<'down' | 'move' | 'up', Fn<PointerEvent>>;
|
|
37
37
|
export declare const onDrag: {
|
|
38
38
|
(el: HTMLElement, fns: Partial<DragHandlers>): Dispose;
|
|
39
|
-
(el:
|
|
39
|
+
(el: SVGElement, fns: Partial<DragHandlers>): Dispose;
|
|
40
40
|
};
|
|
41
|
+
export declare const onDragX: (el: HTMLElement, f: Fn<number>) => Dispose;
|
|
41
42
|
export declare const onDragMove: {
|
|
42
43
|
(el: HTMLElement, f: Fn<PointerEvent>): Dispose;
|
|
43
44
|
(el: SVGGraphicsElement, f: Fn<PointerEvent>): Dispose;
|
|
44
45
|
};
|
|
45
46
|
export declare const onResize: (el: Element, f: Fn<ResizeObserverEntry[]>, options?: ResizeObserverOptions) => Dispose;
|
|
47
|
+
export declare const onSelectChange: <T extends string>(el: HTMLSelectElement, f: FnV<[T, number]>, opts?: ListenOpts) => Dispose;
|
|
46
48
|
export declare const preventDefault: <T extends Event>(e: T) => void;
|
|
47
49
|
export declare const loadImage: (img: HTMLImageElement, src: string) => Promise<HTMLImageElement>;
|
|
48
50
|
export declare const pushState: (path: string, query?: RecordOf<string>, data?: any) => void;
|
|
49
51
|
export declare const qs: (search?: string) => Maybe<RecordOf<string>>;
|
|
50
52
|
export declare const imageData: (img: HTMLImageElement) => ImageData;
|
|
53
|
+
export type Child = ChildNode | string;
|
|
54
|
+
export declare const append: (el: ParentNode, ...children: Child[]) => () => void;
|
|
55
|
+
export type Attribs = Record<string, string | number | boolean>;
|
|
56
|
+
export declare const setAttrs: (el: Element, attrs: Attribs) => void;
|
|
57
|
+
export declare const css: (styles: Record<string, {
|
|
58
|
+
toString(): string;
|
|
59
|
+
}>) => string;
|
|
60
|
+
export declare const style: <E extends HTMLElement>(el: E, props: Record<string, {
|
|
61
|
+
toString(): string;
|
|
62
|
+
}>) => E;
|
|
63
|
+
type Tags<T> = {
|
|
64
|
+
[K in keyof T]: (attrs?: Attribs | Child, ...rest: Child[]) => T[K];
|
|
65
|
+
};
|
|
66
|
+
export declare const h: Tags<HTMLElementTagNameMap>;
|
|
67
|
+
export declare const s: Tags<SVGElementTagNameMap>;
|
|
68
|
+
export declare const m: Tags<MathMLElementTagNameMap>;
|
|
51
69
|
export {};
|
package/dom.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { isDefined } from "./checks.js";
|
|
1
|
+
import * as F from "./fn.js";
|
|
2
|
+
import { isDefined, isString, isBoolean } from "./checks.js";
|
|
3
3
|
import { EMPTY } from "./constants.js";
|
|
4
4
|
export const customEvent = (type, detail, { composed = false, bubbles = false, cancelable = false } = EMPTY.OBJ) => new CustomEvent(type, { bubbles, cancelable, composed, detail });
|
|
5
5
|
export const on = (el, name, listener, opts = false) => {
|
|
6
6
|
el.addEventListener(name, listener, opts);
|
|
7
7
|
return () => el.removeEventListener(name, listener, opts);
|
|
8
8
|
};
|
|
9
|
-
export const onAll = (el, fs, opts) => forEach(...Object.keys(fs).map(k => on(el, k, fs[k], opts)));
|
|
10
|
-
export const onDrag = (el, { down = noop, move = noop, up = noop }) => on(el, 'pointerdown', e => {
|
|
9
|
+
export const onAll = (el, fs, opts) => F.forEach(...Object.keys(fs).map(k => on(el, k, fs[k], opts)));
|
|
10
|
+
export const onDrag = (el, { down = F.noop, move = F.noop, up = F.noop }) => on(el, 'pointerdown', e => {
|
|
11
11
|
const pointerId = e.pointerId;
|
|
12
12
|
el.setPointerCapture(pointerId);
|
|
13
13
|
down(e);
|
|
@@ -19,12 +19,18 @@ export const onDrag = (el, { down = noop, move = noop, up = noop }) => on(el, 'p
|
|
|
19
19
|
offUp();
|
|
20
20
|
});
|
|
21
21
|
});
|
|
22
|
+
export const onDragX = (el, f) => onDrag(el, {
|
|
23
|
+
down: e => f(e.offsetX / el.clientWidth),
|
|
24
|
+
move: e => f(e.offsetX / el.clientWidth),
|
|
25
|
+
up: e => f(e.offsetX / el.clientWidth),
|
|
26
|
+
});
|
|
22
27
|
export const onDragMove = (el, move) => onDrag(el, { move });
|
|
23
28
|
export const onResize = (el, f, options) => {
|
|
24
29
|
const ro = new ResizeObserver(f);
|
|
25
30
|
ro.observe(el, options);
|
|
26
31
|
return () => ro.disconnect();
|
|
27
32
|
};
|
|
33
|
+
export const onSelectChange = (el, f, opts) => on(el, "change", () => f(el.value, el.selectedIndex), opts);
|
|
28
34
|
export const preventDefault = (e) => e.preventDefault();
|
|
29
35
|
export const loadImage = (img, src) => new Promise((resolve) => {
|
|
30
36
|
const off = on(img, "load", () => (off(), resolve(img)));
|
|
@@ -39,3 +45,55 @@ export const imageData = (img) => {
|
|
|
39
45
|
ctx.drawImage(img, 0, 0);
|
|
40
46
|
return ctx.getImageData(0, 0, img.width, img.height);
|
|
41
47
|
};
|
|
48
|
+
export const append = (el, ...children) => {
|
|
49
|
+
const els = children.map(x => isString(x) ? document.createTextNode(x) : x);
|
|
50
|
+
el.append(...els);
|
|
51
|
+
return () => els.forEach(x => x.remove());
|
|
52
|
+
};
|
|
53
|
+
export const setAttrs = (el, attrs) => Object.entries(attrs).forEach(([k, v]) => {
|
|
54
|
+
if (isBoolean(v)) {
|
|
55
|
+
if (el instanceof HTMLInputElement) {
|
|
56
|
+
if (k === "checked")
|
|
57
|
+
el.checked = v;
|
|
58
|
+
if (k === "disabled")
|
|
59
|
+
el.disabled = v;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
el.toggleAttribute(k, v);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else
|
|
66
|
+
el.setAttribute(k, v.toString());
|
|
67
|
+
});
|
|
68
|
+
export const css = (styles) => Object.entries(styles).map(([prop, value]) => `${prop}: ${value};`).join('');
|
|
69
|
+
export const style = (el, props) => (Object.entries(props).forEach(([k, v]) => el.style.setProperty(k, v.toString())), el);
|
|
70
|
+
const isAttrs = (obj) => (obj !== null &&
|
|
71
|
+
typeof obj === 'object' &&
|
|
72
|
+
!(obj instanceof Node) &&
|
|
73
|
+
!Array.isArray(obj));
|
|
74
|
+
const element = (el, attrs, ...rest) => {
|
|
75
|
+
if (isDefined(attrs)) {
|
|
76
|
+
let children = rest;
|
|
77
|
+
if (isAttrs(attrs))
|
|
78
|
+
setAttrs(el, attrs);
|
|
79
|
+
else
|
|
80
|
+
children = [attrs, ...children];
|
|
81
|
+
append(el, ...children);
|
|
82
|
+
}
|
|
83
|
+
return el;
|
|
84
|
+
};
|
|
85
|
+
const NS = {
|
|
86
|
+
HTML: "http://www.w3.org/1999/xhtml",
|
|
87
|
+
SVG: "http://www.w3.org/2000/svg",
|
|
88
|
+
MathML: "http://www.w3.org/1998/Math/MathML",
|
|
89
|
+
};
|
|
90
|
+
const tag = (ns, name) => document.createElementNS(NS[ns], name);
|
|
91
|
+
export const h = new Proxy({}, ({
|
|
92
|
+
get: (_, name) => F.bind((element), tag("HTML", name))
|
|
93
|
+
}));
|
|
94
|
+
export const s = new Proxy({}, {
|
|
95
|
+
get: (_, name) => F.bind((element), tag("SVG", name))
|
|
96
|
+
});
|
|
97
|
+
export const m = new Proxy({}, {
|
|
98
|
+
get: (_, name) => F.bind((element), tag("MathML", name))
|
|
99
|
+
});
|
package/fn.d.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import type { Fn, FnV, FnF, Pred,
|
|
1
|
+
import type { Fn, FnV, FnF, Pred, Last, Lazy, Dispose, Reactive, Promisified, MaybePromise } from "./types.js";
|
|
2
2
|
export declare const tee: <T>(f: Fn<T, void>) => Fn<T, T>;
|
|
3
|
-
export declare const comp: <Fs extends Fn[]>(...fs: Fs) => (x:
|
|
3
|
+
export declare const comp: <Fs extends Fn[]>(...fs: Fs) => (x: Fs[0] extends Fn<infer T> ? T : never) => Last<Fs> extends Fn<any, infer R> ? R : never;
|
|
4
4
|
export declare const pipe: <T, Fs extends [Fn<T>, ...Fn[]]>(x: T, ...fs: Fs) => Last<Fs> extends Fn<any, infer R> ? R : never;
|
|
5
5
|
export declare const forEach: <T, R = any>(...fs: Fn<T, R>[]) => (x: T) => void;
|
|
6
|
-
export declare const map: <T, S, U>(f: Fn<T, S>, g: Fn<S, U>) => Fn<T, U>;
|
|
7
6
|
export declare const and: <T>(...fs: Pred<T>[]) => (x: T) => boolean;
|
|
8
7
|
export declare const or: <T>(...fs: Pred<T>[]) => (x: T) => boolean;
|
|
9
8
|
export declare const not: <T>(p: Pred<T>) => (x: T) => boolean;
|
|
10
|
-
export declare const comb: <C extends FnV<Fn[]>>(c: C) => (...fs: Fn<FirstParam<FirstParam<C>>, ReturnType<FirstParam<C>>>[]) => (x: FirstParam<FirstParam<C>>) => ReturnType<C>;
|
|
11
9
|
export declare const noop: () => void;
|
|
12
10
|
export declare const identity: <S, T = S>(x: S) => T;
|
|
13
11
|
export declare const constantly: <T>(x: T) => Lazy<T>;
|
|
@@ -19,14 +17,14 @@ export declare const where: <T, U, V>(p: Pred<T>, f: Fn<T, U>, g: Fn<T, V>) => (
|
|
|
19
17
|
export declare const before: <F extends Fn<void>>(f: F) => FnF;
|
|
20
18
|
export declare const after: <F extends Fn<void>>(f: F) => FnF;
|
|
21
19
|
export declare const filter: <T>(p: Pred<T>, f: Fn<T>) => (x: T) => void;
|
|
22
|
-
export declare const filterT: <T>(p: TPred<T>, f: Fn<T>) => <S>(x: S) => void;
|
|
23
20
|
export declare const scan: <T, S>(f: FnV<[S, T], S>, a: S) => Fn<T, S>;
|
|
24
21
|
export declare const memoize: <T extends any[], K, V>(f: FnV<T, V>, key?: FnV<T, K>, cache?: Map<K, V>) => (...xs: T) => NonNullable<V>;
|
|
25
22
|
export declare const abortable: <T = any>(f: Fn<AbortSignal>) => (reason?: T) => void;
|
|
26
23
|
export declare const disposable: (f: Fn<Fn<Dispose, Dispose>>, disposes?: Set<Dispose>) => Dispose;
|
|
27
|
-
export declare const
|
|
28
|
-
export declare const disposeWith: <T>(f: Fn<T, Dispose>) => (g: Fn<Fn<T>>) => Dispose;
|
|
24
|
+
export declare const swapping: () => <F extends FnV<any[], Dispose | void>>(f: F) => FnV<Parameters<F>, Dispose>;
|
|
29
25
|
export declare const idemp: <F extends FnV<any[], Dispose | void>>(d: Fn<Dispose, Dispose>, f: F) => FnV<Parameters<F>, Dispose>;
|
|
30
|
-
export declare const toggler: (f: Fn<void, Dispose>) =>
|
|
26
|
+
export declare const toggler: (f: Fn<void, Dispose>) => Fn<boolean, Dispose>;
|
|
31
27
|
export declare const voidify: <F extends FnV>(f: F) => (...xs: Parameters<F>) => void;
|
|
32
28
|
export declare const effectual: <T>(f: Reactive<T>, g: Fn<T>) => Dispose;
|
|
29
|
+
export declare const promisify: <F extends FnV>(f: F) => (...xs: Parameters<F>) => Promisified<ReturnType<F>>;
|
|
30
|
+
export declare const then: <T, F extends FnV<any, MaybePromise<any>>>(f: F, g?: Fn<Awaited<ReturnType<F>>, T>) => (...xs: Parameters<F>) => Promise<T>;
|
package/fn.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { add } from "./set.js";
|
|
2
|
+
import * as Async from "./async.js";
|
|
3
|
+
import { isPromise } from "./checks.js";
|
|
2
4
|
export const tee = f => x => (f(x), x);
|
|
3
5
|
export const comp = (...fs) => (x) => fs.reduce((x, f) => f(x), x);
|
|
4
6
|
export const pipe = (x, ...fs) => fs.reduce((x, f) => f(x), x);
|
|
5
7
|
export const forEach = (...fs) => (x) => fs.forEach(f => f(x));
|
|
6
|
-
export const map = (f, g) => comp(f, g);
|
|
7
8
|
export const and = (...fs) => (x) => fs.reduce((a, f) => a && f(x), true);
|
|
8
9
|
export const or = (...fs) => (x) => fs.reduce((a, f) => a || f(x), false);
|
|
9
10
|
export const not = (p) => (x) => !p(x);
|
|
10
|
-
export const comb = (c) => (...fs) => (x) => c(...fs.map(f => f(x)));
|
|
11
11
|
export const noop = () => { };
|
|
12
12
|
export const identity = (x) => x;
|
|
13
13
|
export const constantly = (x) => () => x;
|
|
@@ -24,8 +24,6 @@ export const after = (f) => g => (...xs) => {
|
|
|
24
24
|
};
|
|
25
25
|
export const filter = (p, f) => (x) => { if (p(x))
|
|
26
26
|
f(x); };
|
|
27
|
-
export const filterT = (p, f) => (x) => { if (p(x))
|
|
28
|
-
f(x); };
|
|
29
27
|
export const scan = (f, a) => (x) => a = f(a, x);
|
|
30
28
|
export const memoize = (f, key = (...xs) => xs[0], cache = new Map()) => (...xs) => {
|
|
31
29
|
const k = key(...xs);
|
|
@@ -42,19 +40,24 @@ export const disposable = (f, disposes = new Set()) => {
|
|
|
42
40
|
f(bind(add, disposes));
|
|
43
41
|
return () => (disposes.forEach(g => g()), disposes.clear());
|
|
44
42
|
};
|
|
45
|
-
export const
|
|
43
|
+
export const swapping = () => {
|
|
46
44
|
let dispose = noop;
|
|
47
45
|
const stop = () => dispose();
|
|
48
46
|
return (f) => (...xs) => (stop(), dispose = f(...xs) ?? noop, stop);
|
|
49
47
|
};
|
|
50
|
-
export const
|
|
51
|
-
export const idemp = (d, f) => disposing()((...xs) => {
|
|
48
|
+
export const idemp = (d, f) => swapping()((...xs) => {
|
|
52
49
|
const cleanup = f(...xs) ?? noop;
|
|
53
50
|
return forEach(cleanup, d(cleanup));
|
|
54
51
|
});
|
|
55
52
|
export const toggler = (f) => {
|
|
56
53
|
let cancel = noop;
|
|
57
|
-
|
|
54
|
+
const stop = () => cancel();
|
|
55
|
+
return (x) => (stop(), (cancel = x ? f() : noop), stop);
|
|
58
56
|
};
|
|
59
57
|
export const voidify = (f) => (...xs) => { f(...xs); };
|
|
60
58
|
export const effectual = (f, g) => disposable(d => d(f(idemp(d, g))));
|
|
59
|
+
export const promisify = (f) => (...xs) => Async.promisify(f(...xs));
|
|
60
|
+
export const then = (f, g = identity) => (...xs) => {
|
|
61
|
+
const r = f(...xs);
|
|
62
|
+
return isPromise(r) ? r.then(g) : Promise.resolve(g(r));
|
|
63
|
+
};
|
package/iterable.d.ts
CHANGED
|
@@ -5,23 +5,13 @@ export declare const just: <T>(x: T) => IteratorObject<T>;
|
|
|
5
5
|
export declare const enumerate: (n?: number) => <T>(x: T) => Indexed<T>;
|
|
6
6
|
export declare function empty(): Generator<never, void, unknown>;
|
|
7
7
|
export declare function concat<T>(...xxs: ReadonlyArray<IteratorObject<T>>): Generator<T, void, unknown>;
|
|
8
|
-
export declare const toArray: <T>(xs: IteratorObject<T>) => T[];
|
|
9
8
|
export declare const map: <T, U = T>(f: Fn<T, U>) => (xs: IteratorObject<T>) => IteratorObject<U, undefined, unknown>;
|
|
10
|
-
export declare const filter: <T>(f: Pred<T>) => (xs: IteratorObject<T>) => IteratorObject<T, undefined, unknown>;
|
|
11
|
-
export declare const drop: (n: number) => <T>(xs: IteratorObject<T>) => IteratorObject<T, undefined, unknown>;
|
|
12
|
-
export declare const flatMap: <T, U = Iterable<T>>(f: Fn<T, Iterator<U> | Iterable<U>>) => (xs: IteratorObject<T>) => IteratorObject<U, undefined, unknown>;
|
|
13
|
-
export declare const forEach: <T>(f?: Fn<T>) => (xs: IteratorObject<T>) => void;
|
|
14
|
-
export declare const some: <T>(f: Pred<T>) => (xs: IteratorObject<T>) => boolean;
|
|
15
|
-
export declare const every: <T>(f: Pred<T>) => (xs: IteratorObject<T>) => boolean;
|
|
16
|
-
export declare const find: <T>(f: Pred<T>) => (xs: IteratorObject<T>) => T | undefined;
|
|
17
|
-
export declare const flat: <T>(xs: IteratorObject<IteratorObject<T>>) => IteratorObject<T, undefined, unknown>;
|
|
18
9
|
export declare const prepend: <A>(ys: IteratorObject<A>) => (xs: IteratorObject<A>) => Generator<A, void, unknown>;
|
|
19
10
|
export declare const append: <A>(ys: IteratorObject<A>) => (xs: IteratorObject<A>) => Generator<A, void, unknown>;
|
|
20
11
|
export declare const first: <T>(xs: IteratorObject<T>) => T | undefined;
|
|
21
12
|
export declare const reduce: <T, S>(f: FnV<[S, T, number], S>, a: S) => (xs: IteratorObject<T>) => S;
|
|
22
13
|
export declare const reduceRec: <T, A, R>(xs: IteratorObject<T>, f: FnV<[A, T, Fn<A>], R>, o: A, result: Fn<A, R>) => R;
|
|
23
|
-
export declare const
|
|
24
|
-
export declare const take: (n: number) => <T>(xs: IteratorObject<T>) => Generator<T>;
|
|
14
|
+
export declare const take: <T>(n: number, xs: IteratorObject<T>) => Generator<T, void, unknown>;
|
|
25
15
|
export declare function arange(a: number, b?: number, s?: number): Generator<number, void, unknown>;
|
|
26
16
|
export declare const linspace: (a: number, b: number, n: number) => Generator<number, void, unknown>;
|
|
27
17
|
export declare const steps: (a: number, b: number, s?: number, o?: number, eps?: number) => Generator<number, void, unknown>;
|
package/iterable.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { assert, isDefined } from "./checks.js";
|
|
2
|
-
import { pipe, comp, scan, apply, noop,
|
|
2
|
+
import { bind, pipe, comp, scan, apply, noop, constantly } from "./fn.js";
|
|
3
3
|
import { set } from "./map.js";
|
|
4
4
|
export const next = (xs) => {
|
|
5
5
|
const { done, value } = xs.next();
|
|
@@ -15,16 +15,7 @@ export function* empty() { }
|
|
|
15
15
|
export function* concat(...xxs) { for (const xs of xxs)
|
|
16
16
|
yield* xs; }
|
|
17
17
|
;
|
|
18
|
-
export const toArray = (xs) => xs.toArray();
|
|
19
18
|
export const map = (f) => (xs) => xs.map(f);
|
|
20
|
-
export const filter = (f) => (xs) => xs.filter(f);
|
|
21
|
-
export const drop = (n) => (xs) => xs.drop(n);
|
|
22
|
-
export const flatMap = (f) => (xs) => xs.flatMap(f);
|
|
23
|
-
export const forEach = (f = noop) => (xs) => xs.forEach(f);
|
|
24
|
-
export const some = (f) => (xs) => xs.some(f);
|
|
25
|
-
export const every = (f) => (xs) => xs.every(f);
|
|
26
|
-
export const find = (f) => (xs) => xs.find(f);
|
|
27
|
-
export const flat = (xs) => xs.flatMap(identity);
|
|
28
19
|
export const prepend = (ys) => (xs) => concat(ys, xs);
|
|
29
20
|
export const append = (ys) => (xs) => concat(xs, ys);
|
|
30
21
|
export const first = (xs) => xs.find(constantly(true));
|
|
@@ -39,8 +30,7 @@ export const reduceRec = (xs, f, o, result) => {
|
|
|
39
30
|
};
|
|
40
31
|
return next(o);
|
|
41
32
|
};
|
|
42
|
-
export const
|
|
43
|
-
export const take = n => function* (xs) {
|
|
33
|
+
export const take = function* (n, xs) {
|
|
44
34
|
for (let i = 0; i < n; i++) {
|
|
45
35
|
const { done, value } = xs.next();
|
|
46
36
|
if (done)
|
|
@@ -146,8 +136,8 @@ export const reduceA = (f, a) => async (xs) => {
|
|
|
146
136
|
export const race = (n) => async function* (xs) {
|
|
147
137
|
const it = pipe(xs, map(enumerate()), map(([i, x]) => [i, x.then(y => [i, y])]));
|
|
148
138
|
const accum = reduce((set), new Map());
|
|
149
|
-
const tasks = pipe(it, (take
|
|
150
|
-
const next = comp((take
|
|
139
|
+
const tasks = pipe(it, bind((take), n), accum);
|
|
140
|
+
const next = comp(bind((take), 1), accum);
|
|
151
141
|
while (tasks.size > 0) {
|
|
152
142
|
const [i, x] = await Promise.race(tasks.values());
|
|
153
143
|
tasks.delete(i);
|
|
@@ -155,4 +145,4 @@ export const race = (n) => async function* (xs) {
|
|
|
155
145
|
next(it);
|
|
156
146
|
}
|
|
157
147
|
};
|
|
158
|
-
export const zmap = (f) => (...xs) => forEach(apply(f))
|
|
148
|
+
export const zmap = (f) => (...xs) => zip(...xs).forEach(apply(f));
|
package/math.d.ts
CHANGED
|
@@ -33,3 +33,4 @@ export declare const align: (x: number, b: number) => number;
|
|
|
33
33
|
export declare const sign11: (x: number) => 1 | -1;
|
|
34
34
|
export declare const nudge: (x: number, v?: number, eps?: number) => number;
|
|
35
35
|
export declare const divCeil: (a: number, b: number) => number;
|
|
36
|
+
export declare const trunc: (num: number, precision: number) => number;
|
package/math.js
CHANGED
|
@@ -42,3 +42,7 @@ export const align = (x, b) => (x + b - 1) & -b;
|
|
|
42
42
|
export const sign11 = (x) => x >= 0 ? 1 : -1;
|
|
43
43
|
export const nudge = (x, v = 0, eps = EPS) => isclose(x, v, eps) ? sign11(x - v) * eps + v : x;
|
|
44
44
|
export const divCeil = (a, b) => Math.ceil(a / b);
|
|
45
|
+
export const trunc = (num, precision) => {
|
|
46
|
+
const factor = Math.pow(10, precision);
|
|
47
|
+
return Math.trunc(num * factor) / factor;
|
|
48
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cgtk/std",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.197",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"exports": {
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
"./checks": "./checks.js",
|
|
10
10
|
"./fn": "./fn.js",
|
|
11
11
|
"./object": "./object.js",
|
|
12
|
-
"./signal": "./signal.js",
|
|
13
12
|
"./assign": "./assign.js",
|
|
14
13
|
"./map": "./map.js",
|
|
15
14
|
"./set": "./set.js",
|
|
@@ -25,6 +24,7 @@
|
|
|
25
24
|
"./stream": "./stream.js",
|
|
26
25
|
"./progress": "./progress.js",
|
|
27
26
|
"./constants": "./constants.js",
|
|
27
|
+
"./channel": "./channel.js",
|
|
28
28
|
"./http": "./http.js",
|
|
29
29
|
"./json": "./json.js",
|
|
30
30
|
"./dom": "./dom.js",
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"./math": "./math.js",
|
|
33
33
|
"./basen": "./basen.js",
|
|
34
34
|
"./struct": "./struct.js",
|
|
35
|
-
"./
|
|
35
|
+
"./bytes": "./bytes.js",
|
|
36
36
|
"./base64": "./base64.js",
|
|
37
37
|
"./npy": "./npy.js",
|
|
38
38
|
"./port": "./port.js",
|
|
39
39
|
"./rect": "./rect.js",
|
|
40
|
-
"./
|
|
40
|
+
"./scope": "./scope.js",
|
|
41
41
|
"./utils": "./utils.js"
|
|
42
42
|
},
|
|
43
43
|
"publishConfig": {
|
package/port.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Dispose, Fn, Fns, FnV, RecordOf, MaybePromise, Reactive } from "./types.js";
|
|
1
|
+
import type { Dispose, Fn, Fns, FnV, RecordOf, MaybePromise, Reactive, AsyncDispose } from "./types.js";
|
|
2
2
|
export interface Message<K, V> {
|
|
3
3
|
type: K;
|
|
4
4
|
payload: V;
|
|
@@ -25,6 +25,6 @@ interface TransferableFnV<T extends any[], R> {
|
|
|
25
25
|
}
|
|
26
26
|
export declare const client: <S extends RecordOf<any>, T = Worker>(target: Port & MessageEventTarget<T>) => { [k in keyof S]: TransferableFnV<Parameters<S[k]>, Promise<ReturnType<S[k]>>>; };
|
|
27
27
|
export declare const server: <S extends RecordOf<any>, T = Worker>(target: Port & MessageEventTarget<T>) => { [k in keyof S]: Fn<FnV<Parameters<S[k]>, MaybePromise<ReturnType<S[k]>>>, Dispose>; };
|
|
28
|
-
export declare const startClient: (worker: Worker, f: Fn<Worker, Dispose | void>) => Promise<
|
|
28
|
+
export declare const startClient: (worker: Worker, f: Fn<Worker, Dispose | void>) => Promise<AsyncDispose>;
|
|
29
29
|
export declare const startServer: (worker: Worker, f: Fn<Worker, MaybePromise<Dispose>>) => Promise<Dispose>;
|
|
30
30
|
export {};
|
package/port.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { noop, bind, then } from "./fn.js";
|
|
2
2
|
import { isDefined } from "./checks.js";
|
|
3
3
|
import { on } from "./dom.js";
|
|
4
|
-
import {
|
|
4
|
+
import { promisify } from "./async.js";
|
|
5
5
|
;
|
|
6
6
|
export const onMessages = (target, fs) => on(target, "message", ({ data: { type, payload } }) => (type in fs) && fs[type](payload));
|
|
7
7
|
export const onMessage = (target, name, f) => on(target, "message", ({ data: { type, payload } }) => type == name && f(payload));
|
|
@@ -39,18 +39,18 @@ export const server = (target) => {
|
|
|
39
39
|
onMessage(target, "rpc", async ({ id, name, args }) => {
|
|
40
40
|
const f = fns.get(name);
|
|
41
41
|
if (isDefined(f))
|
|
42
|
-
rpc({ id, result: await
|
|
42
|
+
rpc({ id, result: await promisify(f(...args)) });
|
|
43
43
|
});
|
|
44
44
|
return new Proxy({}, {
|
|
45
45
|
get: (_, k) => (f) => (fns.set(k, f), () => fns.delete(k))
|
|
46
46
|
});
|
|
47
47
|
};
|
|
48
48
|
export const startClient = async (worker, f) => {
|
|
49
|
-
const
|
|
50
|
-
await
|
|
51
|
-
return
|
|
49
|
+
const { start, stop } = client(worker);
|
|
50
|
+
await start();
|
|
51
|
+
return then(stop, f(worker) ?? noop);
|
|
52
52
|
};
|
|
53
53
|
export const startServer = async (worker, f) => {
|
|
54
|
-
const
|
|
55
|
-
return
|
|
54
|
+
const { start, stop } = server(worker);
|
|
55
|
+
return start(async () => { stop(await promisify(f(worker))); });
|
|
56
56
|
};
|
package/schedule.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Dispose, Fn, FnV, Reactive } from './types.js';
|
|
2
2
|
export declare const raf: Reactive<number>;
|
|
3
|
-
export declare const timeout: (ms
|
|
3
|
+
export declare const timeout: (ms?: number) => Reactive<void>;
|
|
4
4
|
export declare const schedule: <T>(s: Reactive<T>) => <F extends FnV>(f: F) => FnV<Parameters<F>, Dispose>;
|
|
5
5
|
export declare const idempotent: <T>(s: Reactive<T>, d: Fn<Dispose, Dispose>) => <F extends FnV>(f: F) => FnV<Parameters<F>, Dispose>;
|
|
6
6
|
export declare const debounce: <T>(sched?: Reactive<T>) => Reactive<T>;
|
|
7
7
|
export declare const reset: <T>(sched?: Reactive<T>) => Reactive<T>;
|
|
8
|
-
export declare const repeatedly: <T>(f: Fn<
|
|
8
|
+
export declare const repeatedly: <T = number>(sched?: Reactive<T>) => (f: Fn<T, boolean | void>) => () => any;
|
|
9
9
|
export declare const delayAfter: <F extends FnV<any>>(delta: number, n: number, f: F) => (x: any) => any;
|
|
10
|
-
export declare const micro: <F extends FnV>(f: F) => (...xs: Parameters<F>) => void;
|
|
10
|
+
export declare const micro: <F extends FnV>(f: F) => (...xs: Parameters<F>) => (reason?: any) => void;
|
package/schedule.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { isUndefined, isDefined, counted } from './checks.js';
|
|
2
|
-
import { comp, lazy, bind, apply, call, where,
|
|
2
|
+
import { comp, lazy, bind, apply, call, where, swapping, noop, abortable } from './fn.js';
|
|
3
3
|
export const raf = f => bind(cancelAnimationFrame, requestAnimationFrame(f));
|
|
4
|
-
export const timeout = (ms) => f => bind(clearTimeout, setTimeout(f, ms));
|
|
4
|
+
export const timeout = (ms = 0) => f => bind(clearTimeout, setTimeout(f, ms));
|
|
5
5
|
export const schedule = (s) => (f) => call(comp(apply(bind((lazy), f)), s));
|
|
6
|
-
export const idempotent = (s, d) => (f) =>
|
|
6
|
+
export const idempotent = (s, d) => (f) => swapping()((...xs) => d(s(() => f(...xs))));
|
|
7
7
|
export const debounce = (sched = raf) => {
|
|
8
8
|
let cancel;
|
|
9
9
|
const stop = () => { if (isDefined(cancel))
|
|
@@ -23,11 +23,13 @@ export const reset = (sched = raf) => {
|
|
|
23
23
|
return stop;
|
|
24
24
|
};
|
|
25
25
|
};
|
|
26
|
-
export const repeatedly = (
|
|
26
|
+
export const repeatedly = (sched = raf) => (f) => {
|
|
27
27
|
let cancel;
|
|
28
|
-
const g = () => (f()
|
|
28
|
+
const g = (x) => { if (f(x) !== false)
|
|
29
|
+
cancel = sched(g); };
|
|
29
30
|
cancel = sched(g);
|
|
30
31
|
return () => cancel();
|
|
31
32
|
};
|
|
32
33
|
export const delayAfter = (delta, n, f) => where(counted(n), f, schedule(reset(timeout(delta)))(f));
|
|
33
|
-
export const micro = (f) => (...xs) => queueMicrotask(() =>
|
|
34
|
+
export const micro = (f) => (...xs) => abortable(signal => queueMicrotask(() => { if (!signal.aborted)
|
|
35
|
+
f(...xs); }));
|
package/scope.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Fn, FnV, Dispose, AsyncDispose, MaybePromise, Structure } from "./types.js";
|
|
2
|
+
type Result = Dispose | AsyncDispose | void;
|
|
3
|
+
export type Scope<T> = Dispose & {
|
|
4
|
+
value: T;
|
|
5
|
+
dispose: Dispose;
|
|
6
|
+
map<S>(f: Fn<T, S>): Scope<S>;
|
|
7
|
+
use(f: Fn<T, MaybePromise<Result>>): Scope<T>;
|
|
8
|
+
};
|
|
9
|
+
export declare const scope: <T>(value: T, dispose?: Dispose) => Scope<T>;
|
|
10
|
+
type Unwrapped<T> = T extends Scope<infer U> ? U : {
|
|
11
|
+
[K in keyof T]: Unwrapped<T[K]>;
|
|
12
|
+
};
|
|
13
|
+
export declare const compose: <R extends Structure<Scope<any>>>(rs: R) => Scope<Unwrapped<R>>;
|
|
14
|
+
export declare const of: <T>(x: T, f: Fn<T, Dispose>) => Scope<T>;
|
|
15
|
+
type Use = <T>(r: Scope<T>) => T;
|
|
16
|
+
export declare const gen: <R>(f: FnV<[Use, Fn<Dispose, Dispose>], R>) => Scope<R>;
|
|
17
|
+
export declare const consume: (f: Fn<Use, Dispose | void>) => Dispose;
|
|
18
|
+
export declare const worker: (w: Worker) => Scope<Worker>;
|
|
19
|
+
export {};
|
package/scope.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as F from "./fn.js";
|
|
2
|
+
import * as Async from "./async.js";
|
|
3
|
+
import { isPromise, isFunction } from "./checks.js";
|
|
4
|
+
import { add } from "./set.js";
|
|
5
|
+
export const scope = (value, dispose = F.noop) => {
|
|
6
|
+
const s = (() => dispose());
|
|
7
|
+
s.value = value;
|
|
8
|
+
s.dispose = dispose;
|
|
9
|
+
s.map = f => scope(f(value), dispose);
|
|
10
|
+
s.use = f => {
|
|
11
|
+
const r = f(value);
|
|
12
|
+
const d = isPromise(r) ?
|
|
13
|
+
Async.dispose(r.then(d => F.then(d ?? F.noop, dispose))) :
|
|
14
|
+
F.then(r ?? F.noop, dispose);
|
|
15
|
+
return scope(value, d);
|
|
16
|
+
};
|
|
17
|
+
return s;
|
|
18
|
+
};
|
|
19
|
+
const iLeaf = (r) => Object.hasOwn(r, "value") && Object.hasOwn(r, "dispose") && isFunction(r["dispose"]);
|
|
20
|
+
export const compose = (rs) => {
|
|
21
|
+
const disposes = [];
|
|
22
|
+
const rec = (rs) => {
|
|
23
|
+
if (iLeaf(rs)) {
|
|
24
|
+
disposes.push(rs.dispose);
|
|
25
|
+
return rs.value;
|
|
26
|
+
}
|
|
27
|
+
else if (Array.isArray(rs)) {
|
|
28
|
+
return rs.map(rec);
|
|
29
|
+
}
|
|
30
|
+
return Object.fromEntries(Object.entries(rs).map(([k, v]) => [k, rec(v)]));
|
|
31
|
+
};
|
|
32
|
+
const value = rec(rs);
|
|
33
|
+
return scope(value, F.forEach(...disposes));
|
|
34
|
+
};
|
|
35
|
+
export const of = (x, f) => scope(x, f(x));
|
|
36
|
+
export const gen = (f) => {
|
|
37
|
+
const res = new Set();
|
|
38
|
+
return scope(f(r => (res.add(r.dispose), r.value), F.bind(add, res)), () => res.forEach(f => f()));
|
|
39
|
+
};
|
|
40
|
+
export const consume = (f) => F.disposable(use => use(f(r => (use(r.dispose), r.value)) ?? F.noop));
|
|
41
|
+
export const worker = (w) => of(w, x => x.terminate.bind(x));
|
package/string.d.ts
CHANGED
|
@@ -6,3 +6,4 @@ export declare const objectURL: (data: Uint8Array<ArrayBuffer>, type: string) =>
|
|
|
6
6
|
export declare const decode: (label?: string, opts?: TextDecoderOptions) => (x: Uint8Array, stream?: boolean) => string;
|
|
7
7
|
export declare const readLine: (delims?: Set<number>) => (data: Uint8Array, offset?: number) => string;
|
|
8
8
|
export declare const DATA_URL: RegExp;
|
|
9
|
+
export declare const came2kebab: (s: string) => string;
|
package/string.js
CHANGED
|
@@ -27,3 +27,4 @@ export const readLine = (delims = new Set([0x0A])) => {
|
|
|
27
27
|
};
|
|
28
28
|
};
|
|
29
29
|
export const DATA_URL = /^data:(?<mime>[\w/\-\+]+)?(;(?<params>[\w\-]+\=[^;,\s]+)*)?(;(?<encoding>base64))?,(?<data>.*)$/;
|
|
30
|
+
export const came2kebab = (s) => s.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
|
package/types.d.ts
CHANGED
|
@@ -6,9 +6,6 @@ export type Structure<T> = T | readonly Structure<T>[] | RecordOf<Structure<T>>;
|
|
|
6
6
|
export type Optional<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>> & Partial<Pick<T, K>>;
|
|
7
7
|
export type Tuple<T, N extends number, R extends T[] = []> = R['length'] extends N ? R : Tuple<T, N, [T, ...R]>;
|
|
8
8
|
export type Elements<A extends readonly unknown[]> = A extends readonly (infer T)[] ? T : never;
|
|
9
|
-
export type MaybeFirst<T extends unknown[], S = void> = T extends {
|
|
10
|
-
length: 0;
|
|
11
|
-
} ? S : T[0];
|
|
12
9
|
export type FnV<T extends any[] = any[], R = any> = (...x: T) => R;
|
|
13
10
|
export type Fn<T = any, R = any> = FnV<[T], R>;
|
|
14
11
|
export type FnP<T = any, R = any> = (x: T) => Promise<R>;
|
|
@@ -17,10 +14,11 @@ export type Fns<T> = {
|
|
|
17
14
|
};
|
|
18
15
|
export type FnF = <F extends FnV>(f: F) => (...xs: Parameters<F>) => ReturnType<F>;
|
|
19
16
|
export type Dispose = Fn<void>;
|
|
17
|
+
export type AsyncDispose = Fn<void, Promise<void>>;
|
|
20
18
|
export type Reactive<T = unknown, R = any> = Fn<Fn<T, R>, Dispose>;
|
|
21
19
|
export type Lazy<T> = () => T;
|
|
22
|
-
export type
|
|
23
|
-
export type
|
|
20
|
+
export type MaybePromise<T = unknown> = T | Promise<T>;
|
|
21
|
+
export type Promisified<T> = T extends Promise<any> ? T : Promise<T>;
|
|
24
22
|
export type Last<T extends any[]> = T extends [...any, infer Rest] ? Rest : never;
|
|
25
23
|
export type Tail<T extends any[]> = T extends [any, ...(infer Rest)] ? Rest : never;
|
|
26
24
|
export type Push<T extends any[], V> = [...T, V];
|
package/resource.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Fn, Dispose, Structure, Reactive } from "./types.js";
|
|
2
|
-
export type Resource<T> = Reactive<T, Dispose | void> & {
|
|
3
|
-
value: T;
|
|
4
|
-
dispose: Dispose;
|
|
5
|
-
map<S>(f: Fn<T, S>): Resource<S>;
|
|
6
|
-
flatMap<S>(f: Fn<T, Resource<S>>): Resource<S>;
|
|
7
|
-
promise(f: Fn<T, Promise<Dispose | void>>): Promise<Dispose>;
|
|
8
|
-
};
|
|
9
|
-
export declare const resource: <T>(value: T, dispose?: Dispose) => Resource<T>;
|
|
10
|
-
export declare const awaited: <T>({ value, dispose }: Resource<Promise<T>>) => Promise<Resource<Awaited<T>>>;
|
|
11
|
-
type Unwrapped<T> = T extends Resource<infer U> ? U : {
|
|
12
|
-
[K in keyof T]: Unwrapped<T[K]>;
|
|
13
|
-
};
|
|
14
|
-
export declare const compose: <R extends Structure<Resource<any>>>(rs: R) => Resource<Unwrapped<R>>;
|
|
15
|
-
export {};
|
package/resource.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { forEach, noop } from "./fn.js";
|
|
2
|
-
import { isFunction } from "./checks.js";
|
|
3
|
-
export const resource = (value, dispose = noop) => {
|
|
4
|
-
const res = ((f) => forEach(f(value) ?? noop, dispose));
|
|
5
|
-
res.value = value;
|
|
6
|
-
res.dispose = dispose;
|
|
7
|
-
res.map = (f) => resource(f(value), dispose);
|
|
8
|
-
res.flatMap = (f) => {
|
|
9
|
-
const res = f(value);
|
|
10
|
-
return resource(res.value, forEach(res.dispose, dispose));
|
|
11
|
-
};
|
|
12
|
-
res.promise = async (f) => forEach((await f(value)) ?? noop, dispose);
|
|
13
|
-
return res;
|
|
14
|
-
};
|
|
15
|
-
export const awaited = async ({ value, dispose }) => resource(await value, dispose);
|
|
16
|
-
const isResource = (r) => isFunction(r)
|
|
17
|
-
&& Object.hasOwn(r, "value")
|
|
18
|
-
&& Object.hasOwn(r, "dispose")
|
|
19
|
-
&& isFunction(r["dispose"]);
|
|
20
|
-
export const compose = (rs) => {
|
|
21
|
-
const disposes = [];
|
|
22
|
-
const rec = (rs) => {
|
|
23
|
-
if (isResource(rs)) {
|
|
24
|
-
disposes.push(rs.dispose);
|
|
25
|
-
return rs.value;
|
|
26
|
-
}
|
|
27
|
-
else if (Array.isArray(rs)) {
|
|
28
|
-
return rs.map(rec);
|
|
29
|
-
}
|
|
30
|
-
return Object.fromEntries(Object.entries(rs).map(([k, v]) => [k, rec(v)]));
|
|
31
|
-
};
|
|
32
|
-
const value = rec(rs);
|
|
33
|
-
return resource(value, forEach(...disposes));
|
|
34
|
-
};
|
package/signal.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { Fn, FnV, Fns, Pred, Reactive, RecordOf, Structure } from "./types.js";
|
|
2
|
-
export type Signal<T> = Fn<T> & {
|
|
3
|
-
on: Reactive<T>;
|
|
4
|
-
};
|
|
5
|
-
export declare const create: <T>(f: Fn<T>, on: Reactive<T>) => Signal<T>;
|
|
6
|
-
export declare const signal: <T>(fns?: Set<Fn<T>>) => Signal<T>;
|
|
7
|
-
export declare const map: <T, S>(source: Reactive<T>, f: Fn<T, S>) => Reactive<S>;
|
|
8
|
-
export declare const filter: <T>(source: Reactive<T>, p: Pred<T>) => Reactive<T>;
|
|
9
|
-
export declare const cache: <T>(source: Reactive<T>) => Reactive<T>;
|
|
10
|
-
export interface ValueLike<T> {
|
|
11
|
-
value: T;
|
|
12
|
-
on: Reactive<T>;
|
|
13
|
-
}
|
|
14
|
-
export interface Box<T, F extends RecordOf<FnV>> extends ValueLike<T> {
|
|
15
|
-
ops: F;
|
|
16
|
-
}
|
|
17
|
-
export interface Value<T> extends ValueLike<T> {
|
|
18
|
-
op: <F extends FnV>(f: Fn<T, F>) => F;
|
|
19
|
-
ops: <F extends RecordOf<FnV>>(f: Fn<T, F>) => F;
|
|
20
|
-
set: Fn<T>;
|
|
21
|
-
update(): void;
|
|
22
|
-
map<S>(f: Fn<T, S>): Reactive<S>;
|
|
23
|
-
box: <F extends RecordOf<FnV>>(f: Fn<T, F>) => Box<T, F>;
|
|
24
|
-
}
|
|
25
|
-
export declare const value: <T>(x: T, fs?: Set<Fn<T>>) => Value<T>;
|
|
26
|
-
export type Values<T extends RecordOf<any>> = {
|
|
27
|
-
[k in keyof T]: Value<T[k]>;
|
|
28
|
-
};
|
|
29
|
-
export declare const values: <T extends RecordOf<any>>(vals: T) => Values<T>;
|
|
30
|
-
type Unwrapped<T> = T extends ValueLike<infer U> ? U : {
|
|
31
|
-
[K in keyof T]: Unwrapped<T[K]>;
|
|
32
|
-
};
|
|
33
|
-
export declare const compose: <T extends Structure<ValueLike<any>>, S = Unwrapped<T>>(xs: T, transform?: Fn<Unwrapped<T>, S>) => Reactive<S>;
|
|
34
|
-
export declare const mux: <I extends RecordOf<any>, O extends RecordOf<any>>(init: Fn<Fns<O>, Fns<I>>) => Fns<I> & {
|
|
35
|
-
on: { [k in keyof O]: Reactive<O[k]>; };
|
|
36
|
-
};
|
|
37
|
-
export {};
|
package/signal.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { after, constantly, noop, bind, comp, forEach, filter as filter_, identity } from "./fn.js";
|
|
2
|
-
import { mapValues } from "./object.js";
|
|
3
|
-
import { isDefined, isFunction } from "./checks.js";
|
|
4
|
-
import { add } from "./set.js";
|
|
5
|
-
export const create = (f, on) => {
|
|
6
|
-
const g = f;
|
|
7
|
-
g.on = on;
|
|
8
|
-
return g;
|
|
9
|
-
};
|
|
10
|
-
export const signal = (fns = new Set()) => create((x) => fns.forEach(f => f(x)), bind(add, fns));
|
|
11
|
-
export const map = (source, f) => g => source(comp(f, g));
|
|
12
|
-
export const filter = (source, p) => f => source(filter_(p, f));
|
|
13
|
-
export const cache = (source) => {
|
|
14
|
-
let x;
|
|
15
|
-
source(y => x = y);
|
|
16
|
-
return f => {
|
|
17
|
-
if (isDefined(x))
|
|
18
|
-
f(x);
|
|
19
|
-
return source(f);
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
;
|
|
23
|
-
;
|
|
24
|
-
const isValueLike = (v) => Object.hasOwn(v, "value") && Object.hasOwn(v, "on") && isFunction(v.on);
|
|
25
|
-
export const value = (x, fs = new Set()) => {
|
|
26
|
-
const sig = signal(fs);
|
|
27
|
-
const notify = after(() => sig(x));
|
|
28
|
-
const op = (f) => notify(f(x));
|
|
29
|
-
const on = (f) => (f(x), sig.on(f));
|
|
30
|
-
const ops = (f) => mapValues(f(x), notify);
|
|
31
|
-
return {
|
|
32
|
-
get value() { return x; },
|
|
33
|
-
set value(y) { sig(x = y); },
|
|
34
|
-
op, on, ops,
|
|
35
|
-
set: op(constantly((y) => x = y)),
|
|
36
|
-
update: op(constantly(noop)),
|
|
37
|
-
map: bind(map, on),
|
|
38
|
-
box: (f) => ({
|
|
39
|
-
on,
|
|
40
|
-
get value() { return x; },
|
|
41
|
-
ops: ops(f),
|
|
42
|
-
})
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
export const values = (vals) => mapValues(vals, v => value(v));
|
|
46
|
-
export const compose = (xs, transform = identity) => f => {
|
|
47
|
-
const collect = (vs) => {
|
|
48
|
-
if (isValueLike(vs)) {
|
|
49
|
-
return vs.value;
|
|
50
|
-
}
|
|
51
|
-
else if (Array.isArray(vs)) {
|
|
52
|
-
return vs.map(collect);
|
|
53
|
-
}
|
|
54
|
-
return Object.fromEntries(Object.entries(vs).map(([k, v]) => [k, collect(v)]));
|
|
55
|
-
};
|
|
56
|
-
const notify = () => f(transform(collect(xs)));
|
|
57
|
-
let ready = false;
|
|
58
|
-
const sub = (vs) => {
|
|
59
|
-
if (isValueLike(vs)) {
|
|
60
|
-
return vs.on(() => { if (ready)
|
|
61
|
-
notify(); });
|
|
62
|
-
}
|
|
63
|
-
else if (Array.isArray(vs)) {
|
|
64
|
-
return forEach(...vs.map(sub));
|
|
65
|
-
}
|
|
66
|
-
return forEach(...Object.values(vs).map(sub));
|
|
67
|
-
};
|
|
68
|
-
const off = sub(xs);
|
|
69
|
-
ready = true;
|
|
70
|
-
notify();
|
|
71
|
-
return off;
|
|
72
|
-
};
|
|
73
|
-
export const mux = (init) => {
|
|
74
|
-
const sigs = {};
|
|
75
|
-
const ins = init(new Proxy({}, {
|
|
76
|
-
get: (_, k) => (x) => {
|
|
77
|
-
const f = sigs[k];
|
|
78
|
-
if (isDefined(f))
|
|
79
|
-
f(x);
|
|
80
|
-
}
|
|
81
|
-
}));
|
|
82
|
-
ins.on = new Proxy({}, {
|
|
83
|
-
get: (_, k) => f => {
|
|
84
|
-
const sig = sigs[k] ??= signal();
|
|
85
|
-
return sig.on(f);
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
return ins;
|
|
89
|
-
};
|