@terrygonguet/utils 0.11.0 → 0.12.0

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.
@@ -1,25 +1,26 @@
1
+ //#region src/async.d.ts
1
2
  declare function pause(ms: number): Promise<void>;
2
3
  interface RetryOptions {
3
- count?: number;
4
- delay?: number | ((retryCount: number, error: any) => number);
4
+ count?: number;
5
+ delay?: number | ((retryCount: number, error: any) => number);
5
6
  }
6
7
  declare function retry(options: RetryOptions): <T>(provider: () => Promise<T>) => Promise<T>;
7
8
  declare function retry<T>(provider: () => Promise<T>, options?: RetryOptions): Promise<T>;
8
9
  interface AsyncMapOptions<FailFast extends boolean = false, WithSourceIndexes extends boolean = false> {
9
- concurrent?: number;
10
- failFast?: FailFast;
11
- withSourceIndexes?: WithSourceIndexes;
10
+ concurrent?: number;
11
+ failFast?: FailFast;
12
+ withSourceIndexes?: WithSourceIndexes;
12
13
  }
13
14
  interface AsyncMapResultWithIndexes<U> {
14
- results: [i: number, value: U][];
15
- errors: [i: number, error: unknown][];
15
+ results: [i: number, value: U][];
16
+ errors: [i: number, error: unknown][];
16
17
  }
17
18
  interface AsyncMapResult<U> {
18
- results: U[];
19
- errors: unknown[];
19
+ results: U[];
20
+ errors: unknown[];
20
21
  }
21
22
  type AsyncMapFn<T, U> = (el: T, i: number, data: T[]) => Promise<U>;
22
23
  declare function asyncMap<T, U, FailFast extends boolean = false, WithSourceIndexes extends boolean = false>(f: AsyncMapFn<T, U>, options?: AsyncMapOptions<FailFast, WithSourceIndexes>): (data: T[]) => Promise<FailFast extends true ? WithSourceIndexes extends true ? [i: number, value: U][] : U[] : WithSourceIndexes extends true ? AsyncMapResultWithIndexes<U> : AsyncMapResult<U>>;
23
24
  declare function asyncMap<T, U, FailFast extends boolean = false, WithSourceIndexes extends boolean = false>(data: T[], f: AsyncMapFn<T, U>, options?: AsyncMapOptions<FailFast, WithSourceIndexes>): Promise<FailFast extends true ? WithSourceIndexes extends true ? [i: number, value: U][] : U[] : WithSourceIndexes extends true ? AsyncMapResultWithIndexes<U> : AsyncMapResult<U>>;
24
-
25
- export { asyncMap, pause, retry };
25
+ //#endregion
26
+ export { asyncMap, pause, retry };
package/dist/async.mjs ADDED
@@ -0,0 +1,82 @@
1
+ //#region src/async.ts
2
+ function pause(ms) {
3
+ return new Promise((resolve) => setTimeout(resolve, ms));
4
+ }
5
+ function retry(providerOrOptions, options) {
6
+ if (typeof providerOrOptions == "function") return _retry(providerOrOptions, options);
7
+ else return (provider) => _retry(provider, providerOrOptions);
8
+ }
9
+ async function _retry(provider, { count = Infinity, delay } = {}) {
10
+ let retryCount = 0;
11
+ let lastError;
12
+ do
13
+ try {
14
+ return await provider();
15
+ } catch (error) {
16
+ lastError = error;
17
+ retryCount++;
18
+ switch (typeof delay) {
19
+ case "number":
20
+ await pause(delay);
21
+ break;
22
+ case "function":
23
+ await pause(delay(retryCount, error));
24
+ break;
25
+ }
26
+ }
27
+ while (retryCount <= count);
28
+ throw lastError;
29
+ }
30
+ function asyncMap(dataOrF, ForOptions, options) {
31
+ if (typeof dataOrF == "function" && typeof ForOptions != "function") {
32
+ const f = dataOrF;
33
+ const options = ForOptions;
34
+ return (data) => asyncMap_(data, f, options);
35
+ } else if (Array.isArray(dataOrF) && typeof ForOptions == "function") return asyncMap_(dataOrF, ForOptions, options);
36
+ else throw new Error("Invalid arguments passed to asyncMap");
37
+ }
38
+ async function asyncMap_(data, f, { concurrent = 5, failFast = false, withSourceIndexes = false } = {}) {
39
+ return new Promise((resolve, reject) => {
40
+ const resolved = [];
41
+ const errors = [];
42
+ const inFlight = /* @__PURE__ */ new Map();
43
+ let next = 0;
44
+ let stop = false;
45
+ /** @param {number} i */
46
+ function queue(i) {
47
+ if (!stop && i > 0 && inFlight.size == 0) return finish();
48
+ if (stop || i >= data.length) return;
49
+ inFlight.set(i, f(data[i], i, data).then((result) => void resolved.push([i, result]), (error) => {
50
+ if (!failFast) errors.push([i, error]);
51
+ else {
52
+ stop = true;
53
+ reject(error);
54
+ }
55
+ }).finally(() => {
56
+ inFlight.delete(i);
57
+ queue(next);
58
+ }));
59
+ next++;
60
+ }
61
+ function finish() {
62
+ resolved.sort(([a], [b]) => a - b);
63
+ if (failFast) if (withSourceIndexes) resolve(resolved);
64
+ else resolve(resolved.map(([, value]) => value));
65
+ else {
66
+ errors.sort(([a], [b]) => a - b);
67
+ if (withSourceIndexes) resolve({
68
+ results: resolved,
69
+ errors
70
+ });
71
+ else resolve({
72
+ results: resolved.map(([, value]) => value),
73
+ errors: errors.map(([, error]) => error)
74
+ });
75
+ }
76
+ }
77
+ if (data.length == 0) finish();
78
+ else for (let i = 0; i < concurrent; i++) queue(next);
79
+ });
80
+ }
81
+ //#endregion
82
+ export { asyncMap, pause, retry };
@@ -1,3 +1,4 @@
1
+ //#region src/index.d.ts
1
2
  /**
2
3
  * Behaviour is undefined when max < min
3
4
  */
@@ -13,5 +14,5 @@ declare function recordListPush<Key extends string, T>(record: Record<Key, T[]>,
13
14
  type ExecResult<T, Err = Error> = [null, T] | [Err, null];
14
15
  declare function tryCatch<F extends (...args: any) => any>(f: F, ...args: Parameters<F>): ReturnType<F> extends Promise<infer T> ? Promise<ExecResult<T>> : ExecResult<ReturnType<F>>;
15
16
  declare function tryCatch<Err, F extends (...args: any) => any>(f: F, ...args: Parameters<F>): ReturnType<F> extends Promise<infer T> ? Promise<ExecResult<T, Err>> : ExecResult<ReturnType<F>, Err>;
16
-
17
- export { type ExecResult, clamp, createNoopProxy, exhaustive, hash, mapListPush, noop, range, recordListPush, tryCatch, yesno };
17
+ //#endregion
18
+ export { ExecResult, clamp, createNoopProxy, exhaustive, hash, mapListPush, noop, range, recordListPush, tryCatch, yesno };
package/dist/index.mjs ADDED
@@ -0,0 +1,66 @@
1
+ //#region src/index.ts
2
+ /**
3
+ * Behaviour is undefined when max < min
4
+ */
5
+ function clamp(value, min, max) {
6
+ return Math.min(Math.max(value, min), max);
7
+ }
8
+ function createNoopProxy() {
9
+ const noop = () => proxy;
10
+ const no = () => false;
11
+ const yes = () => true;
12
+ const proxy = new Proxy(() => {}, {
13
+ get: noop,
14
+ set: noop,
15
+ apply: noop,
16
+ construct: noop,
17
+ deleteProperty: yes,
18
+ has: yes,
19
+ preventExtensions: no,
20
+ defineProperty: no
21
+ });
22
+ return proxy;
23
+ }
24
+ function noop() {}
25
+ function exhaustive(_) {
26
+ throw new Error("This should never be called");
27
+ }
28
+ async function hash(message) {
29
+ const data = new TextEncoder().encode(message);
30
+ return await crypto.subtle.digest("SHA-1", data);
31
+ }
32
+ function* range(start, end, step = 1) {
33
+ for (let i = start; i < end; i += step) yield i;
34
+ }
35
+ function yesno(value) {
36
+ switch (value?.toLowerCase()) {
37
+ case "1":
38
+ case "y":
39
+ case "yes":
40
+ case "true":
41
+ case "on": return true;
42
+ default: return false;
43
+ }
44
+ }
45
+ function mapListPush(map, key, value) {
46
+ const arr = map.get(key) ?? [];
47
+ arr.push(value);
48
+ return map.set(key, arr);
49
+ }
50
+ function recordListPush(record, key, value) {
51
+ const arr = record[key] ?? [];
52
+ arr.push(value);
53
+ record[key] = arr;
54
+ return record;
55
+ }
56
+ function tryCatch(f, ...args) {
57
+ try {
58
+ const promiseOrResult = f(...args);
59
+ if (promiseOrResult instanceof Promise) return promiseOrResult.then((result) => [null, result], (error) => [error, null]);
60
+ else return [null, promiseOrResult];
61
+ } catch (error) {
62
+ return [error, null];
63
+ }
64
+ }
65
+ //#endregion
66
+ export { clamp, createNoopProxy, exhaustive, hash, mapListPush, noop, range, recordListPush, tryCatch, yesno };
@@ -1,28 +1,21 @@
1
- import { StandardSchemaV1 } from '@standard-schema/spec';
1
+ import { StandardSchemaV1 } from "@standard-schema/spec";
2
2
 
3
+ //#region src/json.d.ts
3
4
  /**
4
5
  * This function does no runtime type checking,
5
6
  * make sure that the parsed value is valid
6
7
  */
7
8
  declare function safeParse<T>(str: string, defaultValue: T, reviver?: (key: string, value: any) => any): T;
8
- type SchemaParseReturn<Schema extends StandardSchemaV1> = [parseError: Error, validationFailure: null, output: null] | [
9
- parseError: null,
10
- validationFailure: StandardSchemaV1.FailureResult,
11
- output: null
12
- ] | [
13
- parseError: null,
14
- validationFailure: null,
15
- output: StandardSchemaV1.InferOutput<Schema>
16
- ];
9
+ type SchemaParseReturn<Schema extends StandardSchemaV1> = [parseError: Error, validationFailure: null, output: null] | [parseError: null, validationFailure: StandardSchemaV1.FailureResult, output: null] | [parseError: null, validationFailure: null, output: StandardSchemaV1.InferOutput<Schema>];
17
10
  declare function schemaParse<Schema extends StandardSchemaV1, Async extends boolean = false>(schema: Schema, str: string, options?: {
18
- reviver?(key: string, value: any): any;
19
- async?: Async;
11
+ reviver?(key: string, value: any): any;
12
+ async?: Async;
20
13
  }): Async extends true ? Promise<SchemaParseReturn<Schema>> : SchemaParseReturn<Schema>;
21
14
  declare function schemaParseWithDefault<Schema extends StandardSchemaV1, Async extends boolean = false>(schema: Schema, str: string, defaultValue: StandardSchemaV1.InferOutput<Schema>, options?: {
22
- reviver?(key: string, value: any): any;
23
- async?: Async;
24
- out_parseError?: Error[];
25
- out_validationFailure?: StandardSchemaV1.FailureResult[];
15
+ reviver?(key: string, value: any): any;
16
+ async?: Async;
17
+ out_parseError?: Error[];
18
+ out_validationFailure?: StandardSchemaV1.FailureResult[];
26
19
  }): Async extends true ? Promise<StandardSchemaV1.InferOutput<Schema>> : StandardSchemaV1.InferOutput<Schema>;
27
-
28
- export { safeParse, schemaParse, schemaParseWithDefault };
20
+ //#endregion
21
+ export { safeParse, schemaParse, schemaParseWithDefault };
package/dist/json.mjs ADDED
@@ -0,0 +1,87 @@
1
+ //#region src/json.ts
2
+ /**
3
+ * This function does no runtime type checking,
4
+ * make sure that the parsed value is valid
5
+ */
6
+ function safeParse(str, defaultValue, reviver) {
7
+ try {
8
+ return JSON.parse(str, reviver);
9
+ } catch (_) {
10
+ return defaultValue;
11
+ }
12
+ }
13
+ /**
14
+ * ! HACK relax type constraints because TS has trouble with options.async for some reason
15
+ */
16
+ function schemaParse(schema, str, options) {
17
+ try {
18
+ const parsed = JSON.parse(str, options?.reviver);
19
+ const result = schema["~standard"].validate(parsed);
20
+ if (options?.async) if (result instanceof Promise) return result.then((result) => result.issues ? [
21
+ null,
22
+ result,
23
+ null
24
+ ] : [
25
+ null,
26
+ null,
27
+ result.value
28
+ ], (err) => [
29
+ err,
30
+ null,
31
+ null
32
+ ]);
33
+ else return Promise.resolve(result.issues ? [
34
+ null,
35
+ result,
36
+ null
37
+ ] : [
38
+ null,
39
+ null,
40
+ result.value
41
+ ]);
42
+ else if (result instanceof Promise) throw new Error("Function schemaParse() whas called with an async schema but without the async flag");
43
+ else if (result.issues) return [
44
+ null,
45
+ result,
46
+ null
47
+ ];
48
+ else return [
49
+ null,
50
+ null,
51
+ result.value
52
+ ];
53
+ } catch (error) {
54
+ return [
55
+ error,
56
+ null,
57
+ null
58
+ ];
59
+ }
60
+ }
61
+ /**
62
+ * ! HACK relax type constraints because TS has trouble with options.async for some reason
63
+ */
64
+ function schemaParseWithDefault(schema, str, defaultValue, options) {
65
+ const result = schemaParse(schema, str, options);
66
+ if (result instanceof Promise) return result.then(([error, failure, value]) => {
67
+ if (failure) {
68
+ options?.out_validationFailure?.push(failure);
69
+ return defaultValue;
70
+ } else if (error) {
71
+ options?.out_parseError?.push(error);
72
+ return defaultValue;
73
+ } else return value;
74
+ });
75
+ else {
76
+ const [error, failure, value] = result;
77
+ if (failure) {
78
+ options?.out_validationFailure?.push(failure);
79
+ return defaultValue;
80
+ } else if (error) {
81
+ options?.out_parseError?.push(error);
82
+ return defaultValue;
83
+ } else return value;
84
+ }
85
+ }
86
+ //#endregion
87
+ export { safeParse, schemaParse, schemaParseWithDefault };
@@ -0,0 +1,52 @@
1
+ //#region src/option.d.ts
2
+ declare class Option<T> {
3
+ #private;
4
+ readonly _kind: "Some" | "None";
5
+ readonly value: T;
6
+ private constructor();
7
+ [Symbol.iterator](): Iterator<Option<T>, T>;
8
+ static do<T>(f: () => Iterator<Option<any>, T, any>): Option<T>;
9
+ static from<T>(maybeValue: unknown, {
10
+ allowOptionLikePOJO
11
+ }?: {
12
+ allowOptionLikePOJO?: boolean | undefined;
13
+ }): Option<T>;
14
+ static wrapFunction<T, Args extends any[]>(f: (...args: Args) => T | undefined | null, {
15
+ allowOptionLikePOJO
16
+ }?: {
17
+ allowOptionLikePOJO?: boolean | undefined;
18
+ }): (...args: Args) => Option<T>;
19
+ static isOption<T>(maybeOption: unknown): maybeOption is Option<T>;
20
+ static Some<T>(value: T): Option<T>;
21
+ static None<T>(): Option<T>;
22
+ [Symbol.toPrimitive](): string;
23
+ isSome(): boolean;
24
+ isNone(): boolean;
25
+ equals(other: Option<T>): boolean;
26
+ map<U>(f: (value: T) => U, {
27
+ coalesce
28
+ }?: {
29
+ coalesce?: boolean | undefined;
30
+ }): Option<U>;
31
+ flatMap<U>(f: (value: T) => Option<U>): Option<U>;
32
+ flatten(): T extends Option<infer U> ? Option<U> : Option<T>;
33
+ orDefault(defaultValue: T): T;
34
+ orNull(): T | null;
35
+ orUndefined(): T | undefined;
36
+ or<U>(other: Option<U>): Option<T> | Option<U>;
37
+ unwrap(): T;
38
+ filter<U extends T>(predicate: (value: T) => value is U): Option<U>;
39
+ filter(predicate: (value: T) => boolean): Option<T>;
40
+ toString(): string;
41
+ }
42
+ declare function arrayGet<T>(arr: T[], i: number): Option<T>;
43
+ declare function arrayFind<T>(arr: T[], predicate: (item: T, i: number, arr: T[]) => boolean, thisArg?: any): Option<T>;
44
+ declare function arrayFindLast<T>(arr: T[], predicate: (item: T, i: number, arr: T[]) => boolean, thisArg?: any): Option<T>;
45
+ declare function arrayFindIndex<T>(arr: T[], predicate: (item: T, i: number, arr: T[]) => boolean, thisArg?: any): Option<number>;
46
+ declare function arrayFindLastIndex<T>(arr: T[], predicate: (item: T, i: number, arr: T[]) => boolean, thisArg?: any): Option<number>;
47
+ declare function arrayIndexOf<T>(arr: T[], item: T, fromIndex?: number): Option<number>;
48
+ declare function arrayLastIndexOf<T>(arr: T[], item: T, fromIndex?: number): Option<number>;
49
+ declare function arrPop<T>(arr: T[]): Option<T>;
50
+ declare function arrShift<T>(arr: T[]): Option<T>;
51
+ //#endregion
52
+ export { Option, arrPop, arrShift, arrayFind, arrayFindIndex, arrayFindLast, arrayFindLastIndex, arrayGet, arrayIndexOf, arrayLastIndexOf };
@@ -0,0 +1,142 @@
1
+ //#region src/option.ts
2
+ var Option = class Option {
3
+ _kind;
4
+ value;
5
+ constructor(_kind, value = void 0) {
6
+ this._kind = _kind;
7
+ this.value = value;
8
+ }
9
+ *[Symbol.iterator]() {
10
+ yield this;
11
+ if (this.isNone()) throw new Error("Tried to unwrap a None() via its iterator");
12
+ else return this.value;
13
+ }
14
+ static do(f) {
15
+ const gen = f();
16
+ let iter = gen.next();
17
+ while (!iter.done) switch (iter.value._kind) {
18
+ case "Some":
19
+ iter = gen.next(iter.value.value);
20
+ break;
21
+ case "None":
22
+ gen.return?.(void 0);
23
+ return Option.None();
24
+ }
25
+ return Option.Some(iter.value);
26
+ }
27
+ static from(maybeValue, { allowOptionLikePOJO = false } = {}) {
28
+ if (maybeValue === void 0 || maybeValue === null) return Option.None();
29
+ else if (Option.isOption(maybeValue)) return maybeValue;
30
+ else if (allowOptionLikePOJO && maybeValue && typeof maybeValue == "object" && "_kind" in maybeValue && (maybeValue._kind == "Some" || maybeValue._kind == "None")) return new Option(maybeValue._kind, maybeValue.value);
31
+ else return Option.Some(maybeValue);
32
+ }
33
+ static wrapFunction(f, { allowOptionLikePOJO = false } = {}) {
34
+ return (...args) => Option.from(f(...args), { allowOptionLikePOJO });
35
+ }
36
+ static isOption(maybeOption) {
37
+ return maybeOption instanceof Option;
38
+ }
39
+ static Some(value) {
40
+ return new Option("Some", value);
41
+ }
42
+ static #None = new Option("None");
43
+ static None() {
44
+ return this.#None;
45
+ }
46
+ [Symbol.toPrimitive]() {
47
+ return this.toString();
48
+ }
49
+ isSome() {
50
+ return this._kind == "Some";
51
+ }
52
+ isNone() {
53
+ return this._kind == "None";
54
+ }
55
+ equals(other) {
56
+ if (this.isNone()) return other.isNone();
57
+ else if (other.isNone()) return false;
58
+ else return this.value == other.value;
59
+ }
60
+ map(f, { coalesce = false } = {}) {
61
+ if (this.isNone()) return Option.None();
62
+ else if (coalesce) return Option.from(f(this.value));
63
+ else return Option.Some(f(this.value));
64
+ }
65
+ flatMap(f) {
66
+ if (this.isNone()) return Option.None();
67
+ else return f(this.value);
68
+ }
69
+ flatten() {
70
+ if (this.isNone()) return Option.None();
71
+ else return Option.isOption(this.value) ? this.value : this;
72
+ }
73
+ orDefault(defaultValue) {
74
+ if (this.isNone()) return defaultValue;
75
+ else return this.value;
76
+ }
77
+ orNull() {
78
+ if (this.isNone()) return null;
79
+ else return this.value;
80
+ }
81
+ orUndefined() {
82
+ if (this.isNone()) return void 0;
83
+ else return this.value;
84
+ }
85
+ or(other) {
86
+ if (this.isNone()) return other;
87
+ else return this;
88
+ }
89
+ unwrap() {
90
+ if (this.isNone()) throw new Error("Tried to unwrap a None()");
91
+ else return this.value;
92
+ }
93
+ filter(predicate) {
94
+ if (this.isNone()) return this;
95
+ else return predicate(this.value) ? this : Option.None();
96
+ }
97
+ toString() {
98
+ if (this.isNone()) return "None()";
99
+ switch (typeof this.value) {
100
+ case "string": return `Some("${this.value}")`;
101
+ case "function":
102
+ case "object": return `Some(${JSON.stringify(this.value)})`;
103
+ default: return `Some(${this.value})`;
104
+ }
105
+ }
106
+ };
107
+ function arrayGet(arr, i) {
108
+ if (i >= arr.length || i < 0) return Option.None();
109
+ else return Option.Some(arr[i]);
110
+ }
111
+ function arrayFind(arr, predicate, thisArg) {
112
+ return Option.from(arr.find(predicate, thisArg));
113
+ }
114
+ function arrayFindLast(arr, predicate, thisArg) {
115
+ return Option.from(arr.findLast(predicate, thisArg));
116
+ }
117
+ function arrayFindIndex(arr, predicate, thisArg) {
118
+ const idx = arr.findIndex(predicate, thisArg);
119
+ return idx == -1 ? Option.None() : Option.Some(idx);
120
+ }
121
+ function arrayFindLastIndex(arr, predicate, thisArg) {
122
+ const idx = arr.findLastIndex(predicate, thisArg);
123
+ return idx == -1 ? Option.None() : Option.Some(idx);
124
+ }
125
+ function arrayIndexOf(arr, item, fromIndex) {
126
+ const idx = arr.indexOf(item, fromIndex);
127
+ return idx == -1 ? Option.None() : Option.Some(idx);
128
+ }
129
+ function arrayLastIndexOf(arr, item, fromIndex) {
130
+ const idx = arr.lastIndexOf(item, fromIndex);
131
+ return idx == -1 ? Option.None() : Option.Some(idx);
132
+ }
133
+ function arrPop(arr) {
134
+ if (arr.length == 0) return Option.None();
135
+ else return Option.Some(arr.pop());
136
+ }
137
+ function arrShift(arr) {
138
+ if (arr.length == 0) return Option.None();
139
+ else return Option.Some(arr.shift());
140
+ }
141
+ //#endregion
142
+ export { Option, arrPop, arrShift, arrayFind, arrayFindIndex, arrayFindLast, arrayFindLastIndex, arrayGet, arrayIndexOf, arrayLastIndexOf };
@@ -1,3 +1,4 @@
1
+ //#region src/random.d.ts
1
2
  /**
2
3
  * Generates a random integer between `0` (inclusive) and `max` (exlusive)
3
4
  */
@@ -19,5 +20,5 @@ declare function make_randi(prng: typeof Math.random): typeof randi;
19
20
  declare function make_randf(prng: typeof Math.random): (minOrMax: number, max?: number) => number;
20
21
  declare function make_shuffle(prng: typeof Math.random): <T>(arr: T[]) => T[];
21
22
  declare function seeded(seed: string | number): typeof Math.random;
22
-
23
- export { make_randf, make_randi, make_shuffle, randf, randi, seeded, shuffle };
23
+ //#endregion
24
+ export { make_randf, make_randi, make_shuffle, randf, randi, seeded, shuffle };
@@ -0,0 +1,79 @@
1
+ //#region src/random.ts
2
+ const base_randi = make_randi(Math.random);
3
+ function randi(minOrMax, max) {
4
+ if (typeof max == "number") return base_randi(minOrMax, max);
5
+ else return base_randi(minOrMax);
6
+ }
7
+ const base_randf = make_randf(Math.random);
8
+ function randf(minOrMax, max) {
9
+ if (typeof max == "number") return base_randf(minOrMax, max);
10
+ else return base_randf(minOrMax);
11
+ }
12
+ const shuffle = make_shuffle(Math.random);
13
+ function make_randi(prng) {
14
+ return function randi(minOrMax, max) {
15
+ if (typeof max == "number") {
16
+ const min = minOrMax;
17
+ const delta = max - min;
18
+ return min + Math.floor(prng() * delta);
19
+ } else return Math.floor(prng() * minOrMax);
20
+ };
21
+ }
22
+ function make_randf(prng) {
23
+ return function randf(minOrMax, max) {
24
+ if (typeof max == "number") {
25
+ const min = minOrMax;
26
+ const delta = max - min;
27
+ return min + prng() * delta;
28
+ } else return prng() * minOrMax;
29
+ };
30
+ }
31
+ function make_shuffle(prng) {
32
+ const randi = make_randi(prng);
33
+ return function shuffle(arr) {
34
+ const clone = Array.from(arr);
35
+ for (let i = 0; i < clone.length - 2; i++) {
36
+ const j = randi(i, clone.length);
37
+ const temp = clone[i];
38
+ clone[i] = clone[j];
39
+ clone[j] = temp;
40
+ }
41
+ return clone;
42
+ };
43
+ }
44
+ function seeded(seed) {
45
+ if (typeof seed == "string") seed = cyrb128(seed);
46
+ else seed ^= 3735928559;
47
+ const prng = splitmix32(seed);
48
+ for (let i = 0; i < 15; i++) prng();
49
+ return prng;
50
+ }
51
+ function cyrb128(str) {
52
+ let h1 = 1779033703, h2 = 3144134277, h3 = 1013904242, h4 = 2773480762;
53
+ for (let i = 0, k; i < str.length; i++) {
54
+ k = str.charCodeAt(i);
55
+ h1 = h2 ^ Math.imul(h1 ^ k, 597399067);
56
+ h2 = h3 ^ Math.imul(h2 ^ k, 2869860233);
57
+ h3 = h4 ^ Math.imul(h3 ^ k, 951274213);
58
+ h4 = h1 ^ Math.imul(h4 ^ k, 2716044179);
59
+ }
60
+ h1 = Math.imul(h3 ^ h1 >>> 18, 597399067);
61
+ h2 = Math.imul(h4 ^ h2 >>> 22, 2869860233);
62
+ h3 = Math.imul(h1 ^ h3 >>> 17, 951274213);
63
+ h4 = Math.imul(h2 ^ h4 >>> 19, 2716044179);
64
+ h1 ^= h2 ^ h3 ^ h4;
65
+ return h1 >>> 0;
66
+ }
67
+ function splitmix32(a) {
68
+ return function() {
69
+ a |= 0;
70
+ a = a + 2654435769 | 0;
71
+ let t = a ^ a >>> 16;
72
+ t = Math.imul(t, 569420461);
73
+ t = t ^ t >>> 15;
74
+ t = Math.imul(t, 1935289751);
75
+ return ((t = t ^ t >>> 15) >>> 0) / 4294967296;
76
+ };
77
+ }
78
+ //#endregion
79
+ export { make_randf, make_randi, make_shuffle, randf, randi, seeded, shuffle };
@@ -0,0 +1,57 @@
1
+ import { StandardSchemaV1 } from "@standard-schema/spec";
2
+
3
+ //#region src/result.d.ts
4
+ declare class Result<Err extends Error, T> {
5
+ value: T | null;
6
+ error: Err | null;
7
+ constructor(value: null, error: Err);
8
+ constructor(value: T, error: null);
9
+ asTuple(): [Err, null] | [null, T];
10
+ asObject(): {
11
+ value: null;
12
+ error: Err;
13
+ } | {
14
+ value: T;
15
+ error: null;
16
+ };
17
+ andThen<Err2 extends Error, F extends (value: T) => any>(f: F): ReturnType<F> extends Promise<infer U> ? AsyncResult<Err | Err2, U> : Result<Err | Err2, ReturnType<F>>;
18
+ match(onValue: (value: T) => void): void;
19
+ match<U>(onValue: (value: T) => U, onError: (error: Err) => U): U;
20
+ recover<Err2 extends Error, F extends (error: Err) => T | Promise<T>>(f: F): ReturnType<F> extends Promise<T> ? AsyncResult<Err2, T> : Result<Err2, T>;
21
+ unwrap(): T;
22
+ unwrapErr(): Err;
23
+ }
24
+ declare class AsyncResult<Err extends Error, T> {
25
+ promise: Promise<T>;
26
+ constructor(promise: Promise<T>);
27
+ asTuple(): Promise<[Err, null] | [null, T]>;
28
+ asObject(): Promise<{
29
+ value: null;
30
+ error: Err;
31
+ } | {
32
+ value: T;
33
+ error: null;
34
+ }>;
35
+ then<U>(cb: (value: Result<Err, T>) => U | Promise<U>): Promise<U>;
36
+ andThen<Err2 extends Error, F extends (value: T) => any>(f: F): AsyncResult<Err | Err2, Awaited<ReturnType<F>>>;
37
+ match(onValue: (value: T) => void): Promise<void>;
38
+ match<U>(onValue: (value: T) => U, onError: (error: Err) => U): Promise<U>;
39
+ recover<Err2 extends Error, F extends (error: Err) => T | Promise<T>>(f: F): AsyncResult<Err2, T>;
40
+ unwrap(): Promise<T>;
41
+ unwrapErr(): Promise<Err>;
42
+ }
43
+ declare function safe<Err extends Error, T>(promise: Promise<T>): AsyncResult<Error, T>;
44
+ declare function safe<Err extends Error, F extends (...args: any) => Promise<any>>(f: F, ...args: Parameters<F>): AsyncResult<Err, Awaited<ReturnType<F>>>;
45
+ declare function safe<Err extends Error, F extends (...args: any) => any>(f: F, ...args: Parameters<F>): Result<Err, ReturnType<F>>;
46
+ declare class SafeFunctionValidationError extends Error {
47
+ name: string;
48
+ issues: StandardSchemaV1.FailureResult["issues"];
49
+ constructor(message: string, issues: StandardSchemaV1.FailureResult["issues"], options?: ErrorOptions);
50
+ }
51
+ interface MakeSafeFnOptions<ParamsSchema extends StandardSchemaV1 | undefined, ReturnSchema extends StandardSchemaV1 | undefined> {
52
+ paramsSchema?: ParamsSchema;
53
+ returnSchema?: ReturnSchema;
54
+ }
55
+ declare function makeSafeFn<Err extends Error, ParamsSchema extends StandardSchemaV1 | undefined, ReturnSchema extends StandardSchemaV1 | undefined, F extends (...args: ParamsSchema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<ParamsSchema> : any) => ReturnSchema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<ReturnSchema> : any>(f: F, options?: MakeSafeFnOptions<ParamsSchema, ReturnSchema>): (...args: Parameters<F>) => Result<Err, ReturnType<F>>;
56
+ //#endregion
57
+ export { AsyncResult, Result, SafeFunctionValidationError, makeSafeFn, safe };