@terrygonguet/utils 0.10.1 → 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.
- package/dist/{async.d.ts → async.d.mts} +12 -11
- package/dist/async.mjs +82 -0
- package/dist/{index.d.ts → index.d.mts} +5 -4
- package/dist/index.mjs +66 -0
- package/dist/{json.d.ts → json.d.mts} +11 -18
- package/dist/json.mjs +87 -0
- package/dist/option.d.mts +52 -0
- package/dist/option.mjs +142 -0
- package/dist/{random.d.ts → random.d.mts} +3 -2
- package/dist/random.mjs +79 -0
- package/dist/result.d.mts +57 -0
- package/dist/result.mjs +129 -0
- package/dist/tableau.d.mts +41 -0
- package/dist/tableau.mjs +91 -0
- package/dist/task.d.mts +38 -0
- package/dist/task.mjs +178 -0
- package/package.json +80 -75
- package/dist/async.js +0 -105
- package/dist/index.js +0 -85
- package/dist/json.js +0 -63
- package/dist/option.d.ts +0 -45
- package/dist/option.js +0 -163
- package/dist/random.js +0 -86
- package/dist/result.d.ts +0 -39
- package/dist/result.js +0 -106
- package/dist/tableau.d.ts +0 -63
- package/dist/tableau.js +0 -125
|
@@ -1,25 +1,26 @@
|
|
|
1
|
+
//#region src/async.d.ts
|
|
1
2
|
declare function pause(ms: number): Promise<void>;
|
|
2
3
|
interface RetryOptions {
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
concurrent?: number;
|
|
11
|
+
failFast?: FailFast;
|
|
12
|
+
withSourceIndexes?: WithSourceIndexes;
|
|
12
13
|
}
|
|
13
14
|
interface AsyncMapResultWithIndexes<U> {
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
results: [i: number, value: U][];
|
|
16
|
+
errors: [i: number, error: unknown][];
|
|
16
17
|
}
|
|
17
18
|
interface AsyncMapResult<U> {
|
|
18
|
-
|
|
19
|
-
|
|
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
|
*/
|
|
@@ -11,7 +12,7 @@ declare function yesno(value?: string): boolean;
|
|
|
11
12
|
declare function mapListPush<Key, T>(map: Map<Key, T[]>, key: Key, value: T): Map<Key, T[]>;
|
|
12
13
|
declare function recordListPush<Key extends string, T>(record: Record<Key, T[]>, key: Key, value: T): Record<Key, T[]>;
|
|
13
14
|
type ExecResult<T, Err = Error> = [null, T] | [Err, null];
|
|
14
|
-
declare function tryCatch<F extends (...args: any) => any>(f: F, ...args: Parameters<F>): ReturnType<F> extends Promise<
|
|
15
|
-
declare function tryCatch<Err, F extends (...args: any) => any>(f: F, ...args: Parameters<F>): ReturnType<F> extends Promise<
|
|
16
|
-
|
|
17
|
-
export {
|
|
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>>;
|
|
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>;
|
|
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
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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 };
|
package/dist/option.mjs
ADDED
|
@@ -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 };
|
package/dist/random.mjs
ADDED
|
@@ -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 };
|