shelving 1.49.1 → 1.50.1
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/package.json +11 -11
- package/stream/DataState.js +3 -3
- package/update/DataUpdate.js +2 -2
- package/util/color.d.ts +2 -1
- package/util/color.js +8 -6
- package/util/function.d.ts +2 -2
- package/util/iterate.d.ts +5 -0
- package/util/iterate.js +6 -0
- package/util/number.js +1 -1
- package/util/random.d.ts +2 -1
- package/util/random.js +4 -3
- package/util/string.d.ts +2 -2
- package/util/string.js +7 -7
- package/util/transform.d.ts +1 -8
- package/util/transform.js +8 -8
- package/util/undefined.js +1 -1
- package/util/validate.d.ts +2 -10
- package/util/validate.js +16 -15
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"state-management",
|
|
12
12
|
"query-builder"
|
|
13
13
|
],
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.50.1",
|
|
15
15
|
"repository": "https://github.com/dhoulb/shelving",
|
|
16
16
|
"author": "Dave Houlbrooke <dave@shax.com>",
|
|
17
17
|
"license": "0BSD",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"./db": "./db/index.js",
|
|
26
26
|
"./error": "./error/index.js",
|
|
27
27
|
"./feedback": "./feedback/index.js",
|
|
28
|
-
"./firestore/client": "./firestore
|
|
29
|
-
"./firestore/lite": "./firestore
|
|
30
|
-
"./firestore/server": "./firestore
|
|
28
|
+
"./firestore/client": "./firestore/client/index.js",
|
|
29
|
+
"./firestore/lite": "./firestore/lite/index.js",
|
|
30
|
+
"./firestore/server": "./firestore/server/index.js",
|
|
31
31
|
"./markup": "./markup/index.js",
|
|
32
32
|
"./provider": "./provider/index.js",
|
|
33
33
|
"./query": "./query/index.js",
|
|
@@ -61,22 +61,22 @@
|
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@google-cloud/firestore": "^4.15.1",
|
|
63
63
|
"@types/jest": "^27.4.0",
|
|
64
|
-
"@types/react": "^17.0.
|
|
64
|
+
"@types/react": "^17.0.39",
|
|
65
65
|
"@types/react-dom": "^17.0.11",
|
|
66
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
67
|
-
"@typescript-eslint/parser": "^5.
|
|
68
|
-
"eslint": "^8.
|
|
66
|
+
"@typescript-eslint/eslint-plugin": "^5.10.2",
|
|
67
|
+
"@typescript-eslint/parser": "^5.10.2",
|
|
68
|
+
"eslint": "^8.8.0",
|
|
69
69
|
"eslint-config-prettier": "^8.3.0",
|
|
70
70
|
"eslint-plugin-import": "^2.25.4",
|
|
71
71
|
"eslint-plugin-prettier": "^4.0.0",
|
|
72
|
-
"firebase": "^9.6.
|
|
73
|
-
"jest": "^27.
|
|
72
|
+
"firebase": "^9.6.6",
|
|
73
|
+
"jest": "^27.5.0",
|
|
74
74
|
"jest-ts-webcompat-resolver": "^1.0.0",
|
|
75
75
|
"prettier": "^2.5.1",
|
|
76
76
|
"react": "^17.0.2",
|
|
77
77
|
"react-dom": "^17.0.2",
|
|
78
78
|
"ts-jest": "^27.1.3",
|
|
79
|
-
"typescript": "^4.5.
|
|
79
|
+
"typescript": "^4.5.5"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|
|
82
82
|
"@google-cloud/firestore": ">=4.0.0",
|
package/stream/DataState.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { withProp,
|
|
1
|
+
import { withProp, transformData, NOERROR, LOADING, awaitNext, getData } from "../util/index.js";
|
|
2
2
|
import { State } from "./State.js";
|
|
3
3
|
/** State that stores a data object and has additional methods to help with that. */
|
|
4
4
|
export class DataState extends State {
|
|
@@ -12,7 +12,7 @@ export class DataState extends State {
|
|
|
12
12
|
}
|
|
13
13
|
/** Update several props in this object. */
|
|
14
14
|
update(updates) {
|
|
15
|
-
this.next(
|
|
15
|
+
this.next(transformData(this.data, updates));
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
/** State that stores an optional data object and has additional methods to help with that. */
|
|
@@ -35,7 +35,7 @@ export class ResultState extends State {
|
|
|
35
35
|
}
|
|
36
36
|
/** Update several props in this object. */
|
|
37
37
|
update(updates) {
|
|
38
|
-
this.next(
|
|
38
|
+
this.next(transformData(this.data, updates));
|
|
39
39
|
}
|
|
40
40
|
/** Delete this result. */
|
|
41
41
|
delete() {
|
package/update/DataUpdate.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { transformData, isNullish } from "../util/index.js";
|
|
2
2
|
import { Update } from "./Update.js";
|
|
3
3
|
/** Update that can be applied to a data object to update its props. */
|
|
4
4
|
export class DataUpdate extends Update {
|
|
@@ -11,7 +11,7 @@ export class DataUpdate extends Update {
|
|
|
11
11
|
return new DataUpdate(!isNullish(key) ? { [key]: value } : {});
|
|
12
12
|
}
|
|
13
13
|
transform(existing) {
|
|
14
|
-
return
|
|
14
|
+
return transformData(existing, this.updates);
|
|
15
15
|
}
|
|
16
16
|
/** Return a data update with a specific prop marked for update. */
|
|
17
17
|
with(key, value) {
|
package/util/color.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Things that can be converted to a `Color` instance. */
|
|
2
2
|
export declare type PossibleColor = Color | string;
|
|
3
|
+
export declare type PossibleOptionalColor = PossibleColor | null;
|
|
3
4
|
/** Represent a color. */
|
|
4
5
|
export declare class Color {
|
|
5
6
|
readonly r: number;
|
|
@@ -20,7 +21,7 @@ export declare class Color {
|
|
|
20
21
|
/** Convert a number or string to a color channel number that's within bounds (strings like `0a` or `ff` are parsed as hexadecimal). */
|
|
21
22
|
export declare function getColorChannel(channel: number | string): number;
|
|
22
23
|
/** Convert a possible color to a `Color` instance or `null` */
|
|
23
|
-
export declare function toColor(color:
|
|
24
|
+
export declare function toColor(color: unknown): Color | null;
|
|
24
25
|
/** Convert a possible color to a `Color` instance */
|
|
25
26
|
export declare function getColor(input: PossibleColor): Color;
|
|
26
27
|
/** Is a color light? */
|
package/util/color.js
CHANGED
|
@@ -49,12 +49,14 @@ export function getColorChannel(channel) {
|
|
|
49
49
|
export function toColor(color) {
|
|
50
50
|
if (color instanceof Color)
|
|
51
51
|
return color;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
if (typeof color === "string") {
|
|
53
|
+
const hex3 = color.match(HEX3);
|
|
54
|
+
if (hex3)
|
|
55
|
+
return new Color(hex3[1], hex3[2], hex3[3]);
|
|
56
|
+
const hex6 = color.match(HEX6);
|
|
57
|
+
if (hex6)
|
|
58
|
+
return new Color(hex6[1], hex6[2], hex6[3], hex6[4]);
|
|
59
|
+
}
|
|
58
60
|
return null;
|
|
59
61
|
}
|
|
60
62
|
/** Convert a possible color to a `Color` instance */
|
package/util/function.d.ts
CHANGED
|
@@ -13,8 +13,8 @@ export declare type Dispatcher<T extends Arguments = []> = (...value: T) => void
|
|
|
13
13
|
/** Function that receives a dispatched value. */
|
|
14
14
|
export declare type AsyncDispatcher<T extends Arguments = []> = (...value: T) => void | PromiseLike<void>;
|
|
15
15
|
/** Safely dispatch a value to a dispatcher function. */
|
|
16
|
-
export declare function dispatch<T extends Arguments>(dispatcher:
|
|
16
|
+
export declare function dispatch<T extends Arguments>(dispatcher: AsyncDispatcher<T>, ...value: T): void;
|
|
17
17
|
/** Safely dispatch a value to a dispatcher method on an object. */
|
|
18
18
|
export declare function dispatchMethod<T extends Arguments, M extends string | symbol>(obj: {
|
|
19
|
-
[K in M]:
|
|
19
|
+
[K in M]: AsyncDispatcher<T>;
|
|
20
20
|
}, key: M, ...value: T): void;
|
package/util/iterate.d.ts
CHANGED
|
@@ -52,6 +52,11 @@ export declare function yieldRange(start: number, end: number): Generator<number
|
|
|
52
52
|
* - Checks `items.size` or `items.length` first to see if the limit is necessary.
|
|
53
53
|
*/
|
|
54
54
|
export declare function limitItems<T>(items: Iterable<T>, limit: number): TypedIterable<T, void, void>;
|
|
55
|
+
/**
|
|
56
|
+
* Reduce an iterable set of items using a reducer function.
|
|
57
|
+
*/
|
|
58
|
+
export declare function reduceItems<T, R>(items: Iterable<T>, reducer: (previous: R, item: T) => R, initial: R): R;
|
|
59
|
+
export declare function reduceItems<T, R>(items: Iterable<T>, reducer: (previous: R | undefined, item: T) => R, initial?: R): R | undefined;
|
|
55
60
|
/** Yield items from a source iterable until we hit a maximum iteration count. */
|
|
56
61
|
export declare function yieldUntilLimit<T>(source: Iterable<T>, limit: number): Generator<T, void, void>;
|
|
57
62
|
/** Infinite iterator that yields the result of calling a function with a given set of arguments. */
|
package/util/iterate.js
CHANGED
|
@@ -70,6 +70,12 @@ export function limitItems(items, limit) {
|
|
|
70
70
|
const size = (_a = getKnownSize(items)) !== null && _a !== void 0 ? _a : Infinity;
|
|
71
71
|
return size <= limit ? items : yieldUntilLimit(items, limit);
|
|
72
72
|
}
|
|
73
|
+
export function reduceItems(items, reducer, initial) {
|
|
74
|
+
let current = initial;
|
|
75
|
+
for (const item of items)
|
|
76
|
+
current = reducer(current, item);
|
|
77
|
+
return current;
|
|
78
|
+
}
|
|
73
79
|
/** Yield items from a source iterable until we hit a maximum iteration count. */
|
|
74
80
|
export function* yieldUntilLimit(source, limit) {
|
|
75
81
|
const iterator = source[Symbol.iterator]();
|
package/util/number.js
CHANGED
|
@@ -17,7 +17,7 @@ export const isNumber = (v) => typeof v === "number";
|
|
|
17
17
|
*/
|
|
18
18
|
export function toNumber(value) {
|
|
19
19
|
if (typeof value === "number")
|
|
20
|
-
return Number.isFinite(value) ? value :
|
|
20
|
+
return !Number.isFinite(value) ? null : value === 0 ? 0 : value;
|
|
21
21
|
else if (typeof value === "string")
|
|
22
22
|
return toNumber(parseFloat(value.replace(NUMERIC, "")));
|
|
23
23
|
else if (value instanceof Date)
|
package/util/random.d.ts
CHANGED
|
@@ -2,9 +2,10 @@ import type { ImmutableArray } from "./array.js";
|
|
|
2
2
|
/** Generate a random integer between two numbers. */
|
|
3
3
|
export declare const getRandom: (min: number, max: number) => number;
|
|
4
4
|
/**
|
|
5
|
-
* Make a random key, e.g.
|
|
5
|
+
* Make a random key, e.g. `xs23r34hhsdx` or `e4m29klrugef`
|
|
6
6
|
* - Not designed to be cryptographically random!
|
|
7
7
|
* - Will probably clash — if you're making a random ID, check for existence of the record before saving.
|
|
8
|
+
* - Designed to be semi-readable, doesn't use capital letters or `i` or `o` or `l` or `u`
|
|
8
9
|
*/
|
|
9
10
|
export declare const getRandomKey: (length?: number) => string;
|
|
10
11
|
/** Get a random character from a string. */
|
package/util/random.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { yieldUntilLimit, yieldCall } from "./iterate.js";
|
|
2
|
-
import {
|
|
2
|
+
import { joinStrings } from "./string.js";
|
|
3
3
|
import { getDefined } from "./undefined.js";
|
|
4
4
|
/** Generate a random integer between two numbers. */
|
|
5
5
|
export const getRandom = (min, max) => Math.round(Math.random() * (max - min) + min);
|
|
6
6
|
/**
|
|
7
|
-
* Make a random key, e.g.
|
|
7
|
+
* Make a random key, e.g. `xs23r34hhsdx` or `e4m29klrugef`
|
|
8
8
|
* - Not designed to be cryptographically random!
|
|
9
9
|
* - Will probably clash — if you're making a random ID, check for existence of the record before saving.
|
|
10
|
+
* - Designed to be semi-readable, doesn't use capital letters or `i` or `o` or `l` or `u`
|
|
10
11
|
*/
|
|
11
|
-
export const getRandomKey = (length =
|
|
12
|
+
export const getRandomKey = (length = 12) => joinStrings(yieldUntilLimit(yieldCall(getRandomCharacter, KEY_CHARS), length));
|
|
12
13
|
const KEY_CHARS = "0123456789abcdefghjkmnpqrstvwxyz";
|
|
13
14
|
/** Get a random character from a string. */
|
|
14
15
|
export const getRandomCharacter = (str) => str[getRandom(0, str.length - 1)];
|
package/util/string.d.ts
CHANGED
|
@@ -16,8 +16,6 @@ export declare const isString: (v: unknown) => v is string;
|
|
|
16
16
|
* -
|
|
17
17
|
*/
|
|
18
18
|
export declare function toString(value: unknown): string;
|
|
19
|
-
/** Concatenate a set of potential strings together. */
|
|
20
|
-
export declare function concatStrings(values: Iterable<unknown>): string;
|
|
21
19
|
/**
|
|
22
20
|
* Convert an unknown value into a title string for user-facing use.
|
|
23
21
|
* - Strings return the string.
|
|
@@ -32,6 +30,8 @@ export declare function concatStrings(values: Iterable<unknown>): string;
|
|
|
32
30
|
* - Everything else returns `"Unknown"`
|
|
33
31
|
*/
|
|
34
32
|
export declare function toTitle(value: unknown): string;
|
|
33
|
+
/** Concatenate an iterable set of strings together. */
|
|
34
|
+
export declare function joinStrings(strs: Iterable<string>, joiner?: string): string;
|
|
35
35
|
/**
|
|
36
36
|
* Sanitize unexpected characters from a string by:
|
|
37
37
|
* - Stripping control characters.
|
package/util/string.js
CHANGED
|
@@ -32,13 +32,6 @@ export function toString(value) {
|
|
|
32
32
|
return value.name || "function";
|
|
33
33
|
return typeof value; // "symbol" etc.
|
|
34
34
|
}
|
|
35
|
-
/** Concatenate a set of potential strings together. */
|
|
36
|
-
export function concatStrings(values) {
|
|
37
|
-
let output = "";
|
|
38
|
-
for (const value of values)
|
|
39
|
-
output += toString(value);
|
|
40
|
-
return output;
|
|
41
|
-
}
|
|
42
35
|
/**
|
|
43
36
|
* Convert an unknown value into a title string for user-facing use.
|
|
44
37
|
* - Strings return the string.
|
|
@@ -73,6 +66,13 @@ export function toTitle(value) {
|
|
|
73
66
|
return "None";
|
|
74
67
|
return "Unknown";
|
|
75
68
|
}
|
|
69
|
+
/** Concatenate an iterable set of strings together. */
|
|
70
|
+
export function joinStrings(strs, joiner = "") {
|
|
71
|
+
let output = "";
|
|
72
|
+
for (const str of strs)
|
|
73
|
+
output += `${output.length ? joiner : ""}${str}`;
|
|
74
|
+
return output;
|
|
75
|
+
}
|
|
76
76
|
/**
|
|
77
77
|
* Sanitize unexpected characters from a string by:
|
|
78
78
|
* - Stripping control characters.
|
package/util/transform.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Entry } from "./entry.js";
|
|
2
1
|
import type { ArrayType, ImmutableArray } from "./array.js";
|
|
3
2
|
import type { ImmutableMap } from "./map.js";
|
|
4
3
|
import { ImmutableObject } from "./object.js";
|
|
@@ -35,12 +34,6 @@ export declare function yieldTransformed<I, O>(items: Iterable<I>, transformer:
|
|
|
35
34
|
export declare function transformArray<T extends ImmutableArray>(arr: T, transformer: Transformer<ArrayType<T>, ArrayType<T>>): T;
|
|
36
35
|
export declare function transformArray<I, O>(arr: Iterable<I>, transformer: (v: I) => O): ImmutableArray<O>;
|
|
37
36
|
export declare function transformArray<I, O>(arr: Iterable<I>, transformer: Transformer<I, O>): ImmutableArray<O>;
|
|
38
|
-
/**
|
|
39
|
-
* Transform the _values_ of a set of entries using a transformer.
|
|
40
|
-
* @yield Transformed entry after calling transforming the new value for each entry.
|
|
41
|
-
*/
|
|
42
|
-
export declare function yieldTransformedValues<I, O>(entries: Iterable<Entry<I>>, transformer: (v: I) => O): Iterable<Entry<O>>;
|
|
43
|
-
export declare function yieldTransformedValues<I, O>(entries: Iterable<Entry<I>>, transformer: Transformer<I, O>): Iterable<Entry<O>>;
|
|
44
37
|
/**
|
|
45
38
|
* Transform the _values_ of a map using a transformer.
|
|
46
39
|
* @return New map after transforming its values.
|
|
@@ -65,7 +58,7 @@ export declare type PropTransformers<T extends Data> = {
|
|
|
65
58
|
* Transform the props of a data object using a set of transformers for its props.
|
|
66
59
|
* @returns New object with changed props (or the same object if no changes were made).
|
|
67
60
|
*/
|
|
68
|
-
export declare function
|
|
61
|
+
export declare function transformData<T extends Data>(existing: T, transformers: PropTransformers<T>): T;
|
|
69
62
|
/** Set of named transformers for a a map-like object. */
|
|
70
63
|
export declare type EntryTransformers<T> = ImmutableObject<Transformer<T | undefined, T>>;
|
|
71
64
|
/** Transform some of the entries of a map-like object using a set of named transformers. */
|
package/util/transform.js
CHANGED
|
@@ -16,18 +16,18 @@ export function* yieldTransformed(items, transformer) {
|
|
|
16
16
|
export function transformArray(arr, transformer) {
|
|
17
17
|
return Array.from(yieldTransformed(arr, transformer));
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
function* _yieldTransformedValues(entries, transformer) {
|
|
20
20
|
for (const [k, v] of entries)
|
|
21
21
|
yield [k, transform(v, transformer)];
|
|
22
22
|
}
|
|
23
23
|
export function transformMap(map, transformer) {
|
|
24
|
-
return new Map(
|
|
24
|
+
return new Map(_yieldTransformedValues(map, transformer));
|
|
25
25
|
}
|
|
26
26
|
export function transformObject(obj, transformer) {
|
|
27
|
-
return Object.fromEntries(
|
|
27
|
+
return Object.fromEntries(_yieldTransformedValues(Object.entries(obj), transformer));
|
|
28
28
|
}
|
|
29
29
|
/** Apply transformers to the props of a data object and yield any props that changed. */
|
|
30
|
-
function*
|
|
30
|
+
function* _yieldTransformedProps(existing, transformers) {
|
|
31
31
|
for (const [k, v] of toProps(transformers))
|
|
32
32
|
yield [k, transform(existing[k], v)];
|
|
33
33
|
}
|
|
@@ -35,15 +35,15 @@ function* yieldTransformedProps(existing, transformers) {
|
|
|
35
35
|
* Transform the props of a data object using a set of transformers for its props.
|
|
36
36
|
* @returns New object with changed props (or the same object if no changes were made).
|
|
37
37
|
*/
|
|
38
|
-
export function
|
|
39
|
-
return Object.fromEntries(yieldMerged(toProps(existing),
|
|
38
|
+
export function transformData(existing, transformers) {
|
|
39
|
+
return Object.fromEntries(yieldMerged(toProps(existing), _yieldTransformedProps(existing, transformers)));
|
|
40
40
|
}
|
|
41
41
|
/** Apply named transformers to the entries of a map-like object and yield any entries that changed. */
|
|
42
|
-
function*
|
|
42
|
+
function* _yieldTransformedEntries(existing, updates) {
|
|
43
43
|
for (const [k, t] of Object.entries(updates))
|
|
44
44
|
yield [k, transform(existing[k], t)];
|
|
45
45
|
}
|
|
46
46
|
/** Transform some of the entries of a map-like object using a set of named transformers. */
|
|
47
47
|
export function transformEntries(existing, updates, deletes) {
|
|
48
|
-
return Object.fromEntries(yieldFiltered(yieldMerged(Object.entries(existing),
|
|
48
|
+
return Object.fromEntries(yieldFiltered(yieldMerged(Object.entries(existing), _yieldTransformedEntries(existing, updates)), isKeyInArray, deletes));
|
|
49
49
|
}
|
package/util/undefined.js
CHANGED
package/util/validate.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Entry } from "./entry.js";
|
|
2
|
-
import { Data,
|
|
2
|
+
import { Data, Result } from "./data.js";
|
|
3
3
|
/** Object that can validate an unknown value with its `validate()` method. */
|
|
4
4
|
export interface Validatable<T> {
|
|
5
5
|
/**
|
|
@@ -50,14 +50,6 @@ export declare function validateItems<T>(unsafeItems: Iterable<unknown>, validat
|
|
|
50
50
|
* - `feedback.details` will contain an entry for each invalid item (keyed by their count in the input iterable).
|
|
51
51
|
*/
|
|
52
52
|
export declare function validateValues<T>(unsafeValues: Iterable<Entry>, validator: Validator<T>): Generator<Entry<T>, void>;
|
|
53
|
-
/**
|
|
54
|
-
* Validate a set of object props with a set of validators.
|
|
55
|
-
*
|
|
56
|
-
* @yield Valid entries for each specified validator.
|
|
57
|
-
* @throw InvalidFeedback if one or more entries did not validate.
|
|
58
|
-
* - `feedback.details` will contain an entry for each invalid item (keyed by their count in the input iterable).
|
|
59
|
-
*/
|
|
60
|
-
export declare function validateProps<T extends Data>(unsafeData: Data, validators: Validators<T>): Generator<Prop<T>, void>;
|
|
61
53
|
/**
|
|
62
54
|
* Validate an entire object with a set of validators.
|
|
63
55
|
* - Defined props in the object will be validated against the corresponding validator.
|
|
@@ -69,7 +61,7 @@ export declare function validateProps<T extends Data>(unsafeData: Data, validato
|
|
|
69
61
|
*/
|
|
70
62
|
export declare function validateData<T extends Data>(unsafeData: Data, validators: Validators<T>): T;
|
|
71
63
|
/**
|
|
72
|
-
* Validate a data result.
|
|
64
|
+
* Validate a data result against a validator for that data.
|
|
73
65
|
* @return Valid object or `null`
|
|
74
66
|
*/
|
|
75
67
|
export declare function validateResult<T extends Data>(unsafeResult: unknown, validator: Validator<T>): Result<T>;
|
package/util/validate.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Feedback, InvalidFeedback } from "../feedback/index.js";
|
|
2
2
|
import { isData, toProps } from "./data.js";
|
|
3
|
+
import { isNullish } from "./null.js";
|
|
3
4
|
/** Is a given value a validator? */
|
|
4
5
|
export const isValidator = (v) => typeof v === "function" || (isData(v) && typeof v.validate === "function");
|
|
5
6
|
/** Validate an unknown value with a validator. */
|
|
@@ -56,6 +57,18 @@ export function* validateValues(unsafeValues, validator) {
|
|
|
56
57
|
if (invalid)
|
|
57
58
|
throw new InvalidFeedback("Invalid items", details);
|
|
58
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Validate an entire object with a set of validators.
|
|
62
|
+
* - Defined props in the object will be validated against the corresponding validator.
|
|
63
|
+
* - `undefined` props in the object will be set to the default value of that prop.
|
|
64
|
+
*
|
|
65
|
+
* @return Valid object.
|
|
66
|
+
* @throw InvalidFeedback if one or more entries did not validate.
|
|
67
|
+
* - `feedback.details` will contain an entry for each invalid item (keyed by their count in the input iterable).
|
|
68
|
+
*/
|
|
69
|
+
export function validateData(unsafeData, validators) {
|
|
70
|
+
return Object.fromEntries(_yieldValidatedProps(unsafeData, validators));
|
|
71
|
+
}
|
|
59
72
|
/**
|
|
60
73
|
* Validate a set of object props with a set of validators.
|
|
61
74
|
*
|
|
@@ -63,7 +76,7 @@ export function* validateValues(unsafeValues, validator) {
|
|
|
63
76
|
* @throw InvalidFeedback if one or more entries did not validate.
|
|
64
77
|
* - `feedback.details` will contain an entry for each invalid item (keyed by their count in the input iterable).
|
|
65
78
|
*/
|
|
66
|
-
|
|
79
|
+
function* _yieldValidatedProps(unsafeData, validators) {
|
|
67
80
|
let invalid = false;
|
|
68
81
|
const details = {};
|
|
69
82
|
for (const [k, validator] of toProps(validators)) {
|
|
@@ -83,21 +96,9 @@ export function* validateProps(unsafeData, validators) {
|
|
|
83
96
|
throw new InvalidFeedback("Invalid data", details);
|
|
84
97
|
}
|
|
85
98
|
/**
|
|
86
|
-
* Validate
|
|
87
|
-
* - Defined props in the object will be validated against the corresponding validator.
|
|
88
|
-
* - `undefined` props in the object will be set to the default value of that prop.
|
|
89
|
-
*
|
|
90
|
-
* @return Valid object.
|
|
91
|
-
* @throw InvalidFeedback if one or more entries did not validate.
|
|
92
|
-
* - `feedback.details` will contain an entry for each invalid item (keyed by their count in the input iterable).
|
|
93
|
-
*/
|
|
94
|
-
export function validateData(unsafeData, validators) {
|
|
95
|
-
return Object.fromEntries(validateProps(unsafeData, validators));
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Validate a data result.
|
|
99
|
+
* Validate a data result against a validator for that data.
|
|
99
100
|
* @return Valid object or `null`
|
|
100
101
|
*/
|
|
101
102
|
export function validateResult(unsafeResult, validator) {
|
|
102
|
-
return unsafeResult
|
|
103
|
+
return !isNullish(unsafeResult) ? validate(unsafeResult, validator) : null;
|
|
103
104
|
}
|