shelving 1.68.2 → 1.68.3
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/feedback/Feedback.js +2 -2
- package/firestore/client/FirestoreClientProvider.d.ts +1 -1
- package/firestore/client/FirestoreClientProvider.js +7 -3
- package/firestore/lite/FirestoreLiteProvider.js +6 -2
- package/firestore/server/FirestoreServerProvider.d.ts +1 -1
- package/firestore/server/FirestoreServerProvider.js +7 -3
- package/package.json +1 -1
- package/provider/ThroughProvider.d.ts +4 -2
- package/provider/ThroughProvider.js +11 -3
- package/provider/ValidationProvider.js +2 -3
- package/react/useDocument.js +3 -3
- package/react/useQuery.js +3 -3
- package/schema/AllowSchema.js +4 -4
- package/schema/ArraySchema.js +3 -3
- package/schema/DateSchema.js +4 -4
- package/schema/NumberSchema.js +2 -2
- package/schema/SlugSchema.js +2 -2
- package/schema/ThroughSchema.d.ts +4 -2
- package/schema/ThroughSchema.js +10 -4
- package/update/ArrayUpdate.d.ts +2 -1
- package/update/ArrayUpdate.js +22 -3
- package/update/DataUpdate.d.ts +3 -2
- package/update/DataUpdate.js +42 -2
- package/update/Delete.d.ts +11 -0
- package/update/Delete.js +15 -0
- package/update/Increment.d.ts +5 -5
- package/update/Increment.js +5 -5
- package/update/ObjectUpdate.d.ts +8 -8
- package/update/ObjectUpdate.js +38 -18
- package/update/Update.d.ts +4 -1
- package/update/Update.js +6 -0
- package/update/hydrations.js +3 -1
- package/update/index.d.ts +2 -2
- package/update/index.js +2 -2
- package/util/color.d.ts +6 -2
- package/util/color.js +17 -11
- package/util/constants.d.ts +0 -2
- package/util/constants.js +0 -2
- package/util/data.d.ts +6 -6
- package/util/data.js +3 -3
- package/util/date.d.ts +5 -5
- package/util/date.js +19 -19
- package/util/number.d.ts +3 -3
- package/util/number.js +5 -5
- package/util/search.js +2 -2
- package/util/string.d.ts +4 -4
- package/util/string.js +7 -7
- package/util/transform.js +2 -2
- package/util/validate.d.ts +9 -0
- package/util/validate.js +13 -2
- package/update/util.d.ts +0 -7
- package/update/util.js +0 -44
package/update/ObjectUpdate.d.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import type { Entry } from "../util/entry.js";
|
|
2
|
-
import type { ImmutableArray } from "../util/array.js";
|
|
3
2
|
import { Nullish } from "../util/null.js";
|
|
4
3
|
import { ImmutableObject } from "../util/object.js";
|
|
4
|
+
import { Validator } from "../util/validate.js";
|
|
5
5
|
import { Update } from "./Update.js";
|
|
6
|
+
import { Delete } from "./Delete.js";
|
|
6
7
|
/** Set of named transforms for the entries of a map-like object. */
|
|
7
|
-
export declare type EntryUpdates<T> = ImmutableObject<T | Update<T
|
|
8
|
+
export declare type EntryUpdates<T> = ImmutableObject<T | Update<T> | Delete>;
|
|
8
9
|
/** Update that can be applied to a map-like object to add/remove/update its entries. */
|
|
9
|
-
export declare class ObjectUpdate<T> extends Update<ImmutableObject<T>> implements Iterable<Entry<T | Update<T> |
|
|
10
|
+
export declare class ObjectUpdate<T> extends Update<ImmutableObject<T>> implements Iterable<Entry<T | Update<T> | Delete>> {
|
|
10
11
|
/** Return an object update with a specific entry marked for update. */
|
|
11
|
-
static with<X>(key: Nullish<string>, value: X | Update<X>): ObjectUpdate<X>;
|
|
12
|
+
static with<X>(key: Nullish<string>, value: X | Update<X> | Delete): ObjectUpdate<X>;
|
|
12
13
|
/** Return an object update with a specific entry marked for deletion. */
|
|
13
14
|
static without<X>(key: Nullish<string>): ObjectUpdate<X>;
|
|
14
15
|
readonly updates: EntryUpdates<T>;
|
|
15
|
-
|
|
16
|
-
constructor(updates?: EntryUpdates<T>, deletes?: ImmutableArray<string>);
|
|
17
|
-
/** Transform an object with this object transform. */
|
|
16
|
+
constructor(updates?: EntryUpdates<T>);
|
|
18
17
|
transform(obj?: ImmutableObject<T>): ImmutableObject<T>;
|
|
18
|
+
validate(validator: Validator<ImmutableObject<T>>): this;
|
|
19
19
|
/** Return an object update with a specific entry marked for update. */
|
|
20
20
|
with(key: Nullish<string>, value: T | Update<T>): this;
|
|
21
21
|
/** Return an object update with a specific entry marked for deletion. */
|
|
@@ -25,5 +25,5 @@ export declare class ObjectUpdate<T> extends Update<ImmutableObject<T>> implemen
|
|
|
25
25
|
* - Updates are yielded first, then deletes.
|
|
26
26
|
* - Entries whose value is `undefined` indicate deletion.
|
|
27
27
|
*/
|
|
28
|
-
[Symbol.iterator](): Iterator<Entry<T | Update<T> |
|
|
28
|
+
[Symbol.iterator](): Iterator<Entry<T | Update<T> | Delete>, void>;
|
|
29
29
|
}
|
package/update/ObjectUpdate.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { isNullish } from "../util/null.js";
|
|
2
2
|
import { transform } from "../util/transform.js";
|
|
3
|
+
import { ObjectSchema } from "../schema/ObjectSchema.js";
|
|
4
|
+
import { validate } from "../util/validate.js";
|
|
3
5
|
import { Update } from "./Update.js";
|
|
6
|
+
import { Delete, DELETE } from "./Delete.js";
|
|
4
7
|
/** Update that can be applied to a map-like object to add/remove/update its entries. */
|
|
5
8
|
export class ObjectUpdate extends Update {
|
|
6
|
-
constructor(updates = {}
|
|
9
|
+
constructor(updates = {}) {
|
|
7
10
|
super();
|
|
8
11
|
this.updates = updates;
|
|
9
|
-
this.deletes = deletes;
|
|
10
12
|
}
|
|
11
13
|
/** Return an object update with a specific entry marked for update. */
|
|
12
14
|
static with(key, value) {
|
|
@@ -14,23 +16,39 @@ export class ObjectUpdate extends Update {
|
|
|
14
16
|
}
|
|
15
17
|
/** Return an object update with a specific entry marked for deletion. */
|
|
16
18
|
static without(key) {
|
|
17
|
-
return new ObjectUpdate(
|
|
19
|
+
return new ObjectUpdate(isNullish(key) ? {} : { [key]: DELETE });
|
|
18
20
|
}
|
|
19
|
-
/** Transform an object with this object transform. */
|
|
20
21
|
transform(obj = {}) {
|
|
21
|
-
return Object.fromEntries(
|
|
22
|
+
return Object.fromEntries(_transformEntries(obj, this.updates));
|
|
23
|
+
}
|
|
24
|
+
validate(validator) {
|
|
25
|
+
if (!(validator instanceof ObjectSchema))
|
|
26
|
+
return super.validate(validator);
|
|
27
|
+
return {
|
|
28
|
+
__proto__: Object.getPrototypeOf(this),
|
|
29
|
+
...this,
|
|
30
|
+
updates: Object.fromEntries(_validateUpdates(this.updates, validator.items)),
|
|
31
|
+
};
|
|
22
32
|
}
|
|
23
33
|
/** Return an object update with a specific entry marked for update. */
|
|
24
34
|
with(key, value) {
|
|
25
35
|
if (isNullish(key))
|
|
26
36
|
return this;
|
|
27
|
-
return {
|
|
37
|
+
return {
|
|
38
|
+
__proto__: Object.getPrototypeOf(this),
|
|
39
|
+
...this,
|
|
40
|
+
updates: { ...this.updates, [key]: value },
|
|
41
|
+
};
|
|
28
42
|
}
|
|
29
43
|
/** Return an object update with a specific entry marked for deletion. */
|
|
30
44
|
without(key) {
|
|
31
45
|
if (isNullish(key))
|
|
32
46
|
return this;
|
|
33
|
-
return {
|
|
47
|
+
return {
|
|
48
|
+
__proto__: Object.getPrototypeOf(this),
|
|
49
|
+
...this,
|
|
50
|
+
updates: { ...this.updates, [key]: DELETE },
|
|
51
|
+
};
|
|
34
52
|
}
|
|
35
53
|
/**
|
|
36
54
|
* Iterate over the changes in this object.
|
|
@@ -40,17 +58,19 @@ export class ObjectUpdate extends Update {
|
|
|
40
58
|
*[Symbol.iterator]() {
|
|
41
59
|
for (const entry of Object.entries(this.updates))
|
|
42
60
|
yield entry;
|
|
43
|
-
for (const key of this.deletes)
|
|
44
|
-
yield [key, undefined];
|
|
45
61
|
}
|
|
46
62
|
}
|
|
47
|
-
function*
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
function* _transformEntries(obj, updates) {
|
|
64
|
+
for (const [k, v] of Object.entries({ ...obj, ...updates })) {
|
|
65
|
+
if (v instanceof Delete)
|
|
66
|
+
continue;
|
|
67
|
+
yield [k, transform(obj[k], v)];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function* _validateUpdates(updates, validator) {
|
|
71
|
+
for (const [k, v] of Object.entries(updates)) {
|
|
72
|
+
if (v instanceof Delete)
|
|
73
|
+
continue;
|
|
74
|
+
yield [k, v instanceof Update ? v.validate(validator) : validate(v, validator)];
|
|
75
|
+
}
|
|
56
76
|
}
|
package/update/Update.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { Transformable } from "../util/transform.js";
|
|
2
|
+
import { Validator, Validatable } from "../util/validate.js";
|
|
2
3
|
/**
|
|
3
4
|
* An object that represents an update of an existing value.
|
|
4
5
|
* - Implements `Transformable` for applying that update with its `transform()` method.
|
|
5
6
|
*/
|
|
6
|
-
export declare abstract class Update<T> implements Transformable<T, T
|
|
7
|
+
export declare abstract class Update<T> implements Transformable<T, T>, Validatable<Update<T>> {
|
|
7
8
|
/** Apply this update to a value. */
|
|
8
9
|
abstract transform(value?: unknown): T;
|
|
10
|
+
/** Validate this update's values against a validator. */
|
|
11
|
+
validate(validator: Validator<T>): this;
|
|
9
12
|
}
|
package/update/Update.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import { validate } from "../util/validate.js";
|
|
1
2
|
/**
|
|
2
3
|
* An object that represents an update of an existing value.
|
|
3
4
|
* - Implements `Transformable` for applying that update with its `transform()` method.
|
|
4
5
|
*/
|
|
5
6
|
export class Update {
|
|
7
|
+
/** Validate this update's values against a validator. */
|
|
8
|
+
validate(validator) {
|
|
9
|
+
validate(this.transform(), validator);
|
|
10
|
+
return this;
|
|
11
|
+
}
|
|
6
12
|
}
|
package/update/hydrations.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { Delete } from "./Delete.js";
|
|
2
|
+
import { Increment } from "./Increment.js";
|
|
1
3
|
import { ArrayUpdate } from "./ArrayUpdate.js";
|
|
2
4
|
import { ObjectUpdate } from "./ObjectUpdate.js";
|
|
3
|
-
import { Increment } from "./Increment.js";
|
|
4
5
|
import { DataUpdate } from "./DataUpdate.js";
|
|
5
6
|
/** Set of hydrations for all transform classes. */
|
|
6
7
|
export const TRANSFORM_HYDRATIONS = {
|
|
7
8
|
Increment,
|
|
9
|
+
Delete,
|
|
8
10
|
ArrayUpdate,
|
|
9
11
|
ObjectUpdate,
|
|
10
12
|
DataUpdate,
|
package/update/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from "./Update.js";
|
|
2
|
+
export * from "./Delete.js";
|
|
2
3
|
export * from "./Increment.js";
|
|
3
|
-
export * from "./DataUpdate.js";
|
|
4
4
|
export * from "./ArrayUpdate.js";
|
|
5
5
|
export * from "./ObjectUpdate.js";
|
|
6
|
+
export * from "./DataUpdate.js";
|
|
6
7
|
export * from "./hydrations.js";
|
|
7
|
-
export * from "./util.js";
|
package/update/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from "./Update.js";
|
|
2
|
+
export * from "./Delete.js";
|
|
2
3
|
export * from "./Increment.js";
|
|
3
|
-
export * from "./DataUpdate.js";
|
|
4
4
|
export * from "./ArrayUpdate.js";
|
|
5
5
|
export * from "./ObjectUpdate.js";
|
|
6
|
+
export * from "./DataUpdate.js";
|
|
6
7
|
export * from "./hydrations.js";
|
|
7
|
-
export * from "./util.js";
|
package/util/color.d.ts
CHANGED
|
@@ -18,12 +18,16 @@ export declare class Color {
|
|
|
18
18
|
get luminance(): number;
|
|
19
19
|
toString(): string;
|
|
20
20
|
}
|
|
21
|
+
/** Is an unknown value a `Color` instance. */
|
|
22
|
+
export declare const isColor: (v: Color | unknown) => v is Color;
|
|
23
|
+
/** Assert that an unknown value is a `Color` instance. */
|
|
24
|
+
export declare function assertColor(v: Color | unknown): asserts v is Color;
|
|
21
25
|
/** Convert a number or string to a color channel number that's within bounds (strings like `0a` or `ff` are parsed as hexadecimal). */
|
|
22
26
|
export declare function getColorChannel(channel: number | string): number;
|
|
23
27
|
/** Convert a possible color to a `Color` instance or `null` */
|
|
24
|
-
export declare function
|
|
28
|
+
export declare function getOptionalColor(possibleColor: unknown): Color | null;
|
|
25
29
|
/** Convert a possible color to a `Color` instance */
|
|
26
|
-
export declare function getColor(
|
|
30
|
+
export declare function getColor(possibleColor: PossibleColor): Color;
|
|
27
31
|
/** Is a color light? */
|
|
28
32
|
export declare const isLight: (input: PossibleColor) => boolean;
|
|
29
33
|
/** Is a color dark? */
|
package/util/color.js
CHANGED
|
@@ -38,6 +38,13 @@ export class Color {
|
|
|
38
38
|
}
|
|
39
39
|
/** Convert number channel to a hex string (results will be unpredictable if number is outside 0-MAX). */
|
|
40
40
|
const _hex = (channel) => channel.toString(16).padStart(2, "00");
|
|
41
|
+
/** Is an unknown value a `Color` instance. */
|
|
42
|
+
export const isColor = (v) => v instanceof Color;
|
|
43
|
+
/** Assert that an unknown value is a `Color` instance. */
|
|
44
|
+
export function assertColor(v) {
|
|
45
|
+
if (!isColor(v))
|
|
46
|
+
throw new AssertionError("Invalid color", v);
|
|
47
|
+
}
|
|
41
48
|
/** Convert a number or string to a color channel number that's within bounds (strings like `0a` or `ff` are parsed as hexadecimal). */
|
|
42
49
|
export function getColorChannel(channel) {
|
|
43
50
|
const num = typeof channel === "string" ? parseInt(channel.padStart(2, "00"), 16) : Math.round(channel);
|
|
@@ -46,25 +53,24 @@ export function getColorChannel(channel) {
|
|
|
46
53
|
throw new AssertionError("Invalid color channel", channel);
|
|
47
54
|
}
|
|
48
55
|
/** Convert a possible color to a `Color` instance or `null` */
|
|
49
|
-
export function
|
|
50
|
-
if (
|
|
51
|
-
return
|
|
52
|
-
if (typeof
|
|
53
|
-
const hex3 =
|
|
56
|
+
export function getOptionalColor(possibleColor) {
|
|
57
|
+
if (possibleColor instanceof Color)
|
|
58
|
+
return possibleColor;
|
|
59
|
+
if (typeof possibleColor === "string") {
|
|
60
|
+
const hex3 = possibleColor.match(HEX3);
|
|
54
61
|
if (hex3)
|
|
55
62
|
return new Color(hex3[1], hex3[2], hex3[3]);
|
|
56
|
-
const hex6 =
|
|
63
|
+
const hex6 = possibleColor.match(HEX6);
|
|
57
64
|
if (hex6)
|
|
58
65
|
return new Color(hex6[1], hex6[2], hex6[3], hex6[4]);
|
|
59
66
|
}
|
|
60
67
|
return null;
|
|
61
68
|
}
|
|
62
69
|
/** Convert a possible color to a `Color` instance */
|
|
63
|
-
export function getColor(
|
|
64
|
-
const color =
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
throw new AssertionError("Invalid color", color);
|
|
70
|
+
export function getColor(possibleColor) {
|
|
71
|
+
const color = getOptionalColor(possibleColor);
|
|
72
|
+
assertColor(color);
|
|
73
|
+
return color;
|
|
68
74
|
}
|
|
69
75
|
/** Is a color light? */
|
|
70
76
|
export const isLight = (input) => getColor(input).luminance > DARK;
|
package/util/constants.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/** The SAME symbol indicates sameness. */
|
|
2
2
|
export declare const SAME: unique symbol;
|
|
3
|
-
/** The SKIP symbol indicates something that should be skipped. */
|
|
4
|
-
export declare const SKIP: unique symbol;
|
|
5
3
|
/** The LOADING symbol indicates loading. */
|
|
6
4
|
export declare const LOADING: unique symbol;
|
|
7
5
|
/** The DONE symbol indicates doneness. */
|
package/util/constants.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/** The SAME symbol indicates sameness. */
|
|
2
2
|
export const SAME = Symbol("shelving/SAME");
|
|
3
|
-
/** The SKIP symbol indicates something that should be skipped. */
|
|
4
|
-
export const SKIP = Symbol("shelving/SKIP");
|
|
5
3
|
/** The LOADING symbol indicates loading. */
|
|
6
4
|
export const LOADING = Symbol("shelving/LOADING");
|
|
7
5
|
/** The DONE symbol indicates doneness. */
|
package/util/data.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ export declare type OptionalEntity<T extends Data = Data> = Entity<T> | null;
|
|
|
26
26
|
/** Is an unknown value a data object? */
|
|
27
27
|
export declare const isData: <T extends Data>(value: unknown) => value is T;
|
|
28
28
|
/** Turn a data object into an array of entries (if it isn't one already). */
|
|
29
|
-
export declare function
|
|
30
|
-
export declare function
|
|
29
|
+
export declare function getProps<T extends Data>(data: T): ImmutableArray<Prop<T>>;
|
|
30
|
+
export declare function getProps<T extends Data>(data: Partial<T>): ImmutableArray<Prop<T>>;
|
|
31
31
|
/** Get the data of a result (returns data or throws `RequiredError` if value is `null` or `undefined`). */
|
|
32
32
|
export declare function getData<T extends Data>(result: OptionalData<T>): T;
|
|
33
33
|
/**
|
|
@@ -53,10 +53,10 @@ export declare function getProp<T extends Data, K1 extends keyof T>(obj: T, k1:
|
|
|
53
53
|
* @param k3 The sub-sub-key of the prop in the object to get.
|
|
54
54
|
* @param k4 The sub-sub-sub-key of the prop in the object to get.
|
|
55
55
|
*/
|
|
56
|
-
export declare function
|
|
57
|
-
export declare function
|
|
58
|
-
export declare function
|
|
59
|
-
export declare function
|
|
56
|
+
export declare function yieldProps<T extends Data, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2], K4 extends keyof T[K1][K2][K3]>(items: Iterable<T>, k1: K1, k2: K2, k3: K3, k4: K4): Iterable<T[K1][K2][K3][K4]>;
|
|
57
|
+
export declare function yieldProps<T extends Data, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(items: Iterable<T>, k1: K1, k2: K2, k3: K3): Iterable<T[K1][K2][K3]>;
|
|
58
|
+
export declare function yieldProps<T extends Data, K1 extends keyof T, K2 extends keyof T[K1]>(items: Iterable<T>, k1: K1, k2: K2): Iterable<T[K1][K2]>;
|
|
59
|
+
export declare function yieldProps<T extends Data, K1 extends keyof T>(items: Iterable<T>, k1: K1): Iterable<T[K1]>;
|
|
60
60
|
/** Get the ID of an entity. */
|
|
61
61
|
export declare const getID: <T extends Data>({ id }: Entity<T>) => string;
|
|
62
62
|
/** Yield the IDs of an iterable set of entities. */
|
package/util/data.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RequiredError } from "../error/RequiredError.js";
|
|
2
2
|
/** Is an unknown value a data object? */
|
|
3
3
|
export const isData = (value) => typeof value === "object" && value !== null;
|
|
4
|
-
export function
|
|
4
|
+
export function getProps(data) {
|
|
5
5
|
return Object.entries(data);
|
|
6
6
|
}
|
|
7
7
|
/** Get the data of a result (returns data or throws `RequiredError` if value is `null` or `undefined`). */
|
|
@@ -13,7 +13,7 @@ export function getData(result) {
|
|
|
13
13
|
export function getProp(data, k1, k2, k3, k4) {
|
|
14
14
|
return !k2 ? data[k1] : !k3 ? data[k1][k2] : !k4 ? data[k1][k2][k3] : data[k1][k2][k3][k4];
|
|
15
15
|
}
|
|
16
|
-
export function*
|
|
16
|
+
export function* yieldProps(items, k1, k2, k3, k4) {
|
|
17
17
|
for (const data of items)
|
|
18
18
|
yield !k2 ? data[k1] : !k3 ? data[k1][k2] : !k4 ? data[k1][k2][k3] : data[k1][k2][k3][k4];
|
|
19
19
|
}
|
|
@@ -65,6 +65,6 @@ export function setProp(data, key, value) {
|
|
|
65
65
|
* @param props An object containing new props to set on the object.
|
|
66
66
|
*/
|
|
67
67
|
export function setProps(data, props) {
|
|
68
|
-
for (const [k, v] of
|
|
68
|
+
for (const [k, v] of getProps(props))
|
|
69
69
|
data[k] = v;
|
|
70
70
|
}
|
package/util/date.d.ts
CHANGED
|
@@ -21,16 +21,16 @@ export declare type PossibleOptionalDate = Date | number | string | null | (() =
|
|
|
21
21
|
* - Numbers are return the corresponding date (using `new Date(number)`, i.e. milliseconds since 01/01/1970).
|
|
22
22
|
* - Anything else is converted to `null`
|
|
23
23
|
*
|
|
24
|
-
* @param
|
|
24
|
+
* @param possibleDate Any value that we want to parse as a valid date.
|
|
25
25
|
* @returns `Date` instance if the value could be converted to a valid date, and `null` if not.
|
|
26
26
|
*/
|
|
27
|
-
export declare function
|
|
27
|
+
export declare function getOptionalDate(possibleDate: unknown): Date | null;
|
|
28
28
|
/** Convert a possible date to a `Date` instance, or throw `AssertionError` if it couldn't be converted. */
|
|
29
|
-
export declare function getDate(
|
|
29
|
+
export declare function getDate(possibleDate?: PossibleDate): Date;
|
|
30
30
|
/** Convert an unknown value to a YMD date string like "2015-09-12", or `null` if it couldn't be converted. */
|
|
31
|
-
export declare function
|
|
31
|
+
export declare function getOptionalYmd(possibleDate: unknown): string | null;
|
|
32
32
|
/** Convert a `Date` instance to a YMD string like "2015-09-12", or throw `AssertionError` if it couldn't be converted. */
|
|
33
|
-
export declare function getYmd(
|
|
33
|
+
export declare function getYmd(possibleDate?: PossibleDate): string;
|
|
34
34
|
/** List of day-of-week strings. */
|
|
35
35
|
export declare const days: readonly ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
|
|
36
36
|
/** Type listing day-of-week strings. */
|
package/util/date.js
CHANGED
|
@@ -22,42 +22,42 @@ export function assertDate(v) {
|
|
|
22
22
|
* - Numbers are return the corresponding date (using `new Date(number)`, i.e. milliseconds since 01/01/1970).
|
|
23
23
|
* - Anything else is converted to `null`
|
|
24
24
|
*
|
|
25
|
-
* @param
|
|
25
|
+
* @param possibleDate Any value that we want to parse as a valid date.
|
|
26
26
|
* @returns `Date` instance if the value could be converted to a valid date, and `null` if not.
|
|
27
27
|
*/
|
|
28
|
-
export function
|
|
29
|
-
if (
|
|
28
|
+
export function getOptionalDate(possibleDate) {
|
|
29
|
+
if (possibleDate === undefined || possibleDate === "now")
|
|
30
30
|
return new Date();
|
|
31
|
-
if (
|
|
32
|
-
return !Number.isNaN(
|
|
33
|
-
if (
|
|
31
|
+
if (possibleDate instanceof Date)
|
|
32
|
+
return !Number.isNaN(possibleDate.getTime()) ? possibleDate : null;
|
|
33
|
+
if (possibleDate === "today")
|
|
34
34
|
return getMidnight();
|
|
35
|
-
if (
|
|
35
|
+
if (possibleDate === "tomorrow")
|
|
36
36
|
return addDays(1, getMidnight());
|
|
37
|
-
if (
|
|
37
|
+
if (possibleDate === "yesterday")
|
|
38
38
|
return addDays(-1, getMidnight());
|
|
39
|
-
if (
|
|
39
|
+
if (possibleDate === null || possibleDate === "")
|
|
40
40
|
return null; // We know empty string is always an invalid date.
|
|
41
|
-
if (typeof
|
|
42
|
-
return
|
|
43
|
-
if (typeof
|
|
44
|
-
return
|
|
41
|
+
if (typeof possibleDate === "string" || typeof possibleDate === "number")
|
|
42
|
+
return getOptionalDate(new Date(possibleDate));
|
|
43
|
+
if (typeof possibleDate === "function")
|
|
44
|
+
return getOptionalDate(possibleDate());
|
|
45
45
|
return null;
|
|
46
46
|
}
|
|
47
47
|
/** Convert a possible date to a `Date` instance, or throw `AssertionError` if it couldn't be converted. */
|
|
48
|
-
export function getDate(
|
|
49
|
-
const date =
|
|
48
|
+
export function getDate(possibleDate = "now") {
|
|
49
|
+
const date = getOptionalDate(possibleDate);
|
|
50
50
|
assertDate(date);
|
|
51
51
|
return date;
|
|
52
52
|
}
|
|
53
53
|
/** Convert an unknown value to a YMD date string like "2015-09-12", or `null` if it couldn't be converted. */
|
|
54
|
-
export function
|
|
55
|
-
const date =
|
|
54
|
+
export function getOptionalYmd(possibleDate) {
|
|
55
|
+
const date = getOptionalDate(possibleDate);
|
|
56
56
|
return date ? date.toISOString().slice(0, 10) : null;
|
|
57
57
|
}
|
|
58
58
|
/** Convert a `Date` instance to a YMD string like "2015-09-12", or throw `AssertionError` if it couldn't be converted. */
|
|
59
|
-
export function getYmd(
|
|
60
|
-
return getDate(
|
|
59
|
+
export function getYmd(possibleDate = "now") {
|
|
60
|
+
return getDate(possibleDate).toISOString().slice(0, 10);
|
|
61
61
|
}
|
|
62
62
|
/** List of day-of-week strings. */
|
|
63
63
|
export const days = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
|
package/util/number.d.ts
CHANGED
|
@@ -12,16 +12,16 @@ export declare function assertMax(v: number | unknown, max: number): asserts v i
|
|
|
12
12
|
/** Assert that a value is a number less than. */
|
|
13
13
|
export declare function assertMin(v: number | unknown, min: number): asserts v is number;
|
|
14
14
|
/**
|
|
15
|
-
* Convert an unknown value to a number or `null`
|
|
15
|
+
* Convert an unknown value to a finite number or `null`
|
|
16
16
|
* - Note: numbers can be non-finite numbers like `NaN` or `Infinity`. These are detected and will always return `null`
|
|
17
17
|
*
|
|
18
18
|
* Conversion rules:
|
|
19
|
-
* - Numbers (except `NaN`) return numbers.
|
|
19
|
+
* - Numbers (except `NaN` and `+Infinity` and `-Infinity`) return numbers.
|
|
20
20
|
* - Strings are parsed as numbers.
|
|
21
21
|
* - Dates return their milliseconds (e.g. `date.getTime()`)
|
|
22
22
|
* - Everything else returns `null`
|
|
23
23
|
*/
|
|
24
|
-
export declare function
|
|
24
|
+
export declare function getOptionalNumber(value: unknown): number | null;
|
|
25
25
|
/**
|
|
26
26
|
* Assertively convert an unknown value to a finite number.
|
|
27
27
|
* @throws `AssertionError` if the value cannot be converted.
|
package/util/number.js
CHANGED
|
@@ -26,20 +26,20 @@ export function assertMin(v, min) {
|
|
|
26
26
|
throw new AssertionError(`Must be number with minimum ${min}`, v);
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
* Convert an unknown value to a number or `null`
|
|
29
|
+
* Convert an unknown value to a finite number or `null`
|
|
30
30
|
* - Note: numbers can be non-finite numbers like `NaN` or `Infinity`. These are detected and will always return `null`
|
|
31
31
|
*
|
|
32
32
|
* Conversion rules:
|
|
33
|
-
* - Numbers (except `NaN`) return numbers.
|
|
33
|
+
* - Numbers (except `NaN` and `+Infinity` and `-Infinity`) return numbers.
|
|
34
34
|
* - Strings are parsed as numbers.
|
|
35
35
|
* - Dates return their milliseconds (e.g. `date.getTime()`)
|
|
36
36
|
* - Everything else returns `null`
|
|
37
37
|
*/
|
|
38
|
-
export function
|
|
38
|
+
export function getOptionalNumber(value) {
|
|
39
39
|
if (typeof value === "number")
|
|
40
40
|
return !Number.isFinite(value) ? null : value === 0 ? 0 : value;
|
|
41
41
|
else if (typeof value === "string")
|
|
42
|
-
return
|
|
42
|
+
return getOptionalNumber(parseFloat(value.replace(NUMERIC, "")));
|
|
43
43
|
else if (value instanceof Date)
|
|
44
44
|
return value.getTime();
|
|
45
45
|
return null;
|
|
@@ -50,7 +50,7 @@ const NUMERIC = /[^0-9-.]/g;
|
|
|
50
50
|
* @throws `AssertionError` if the value cannot be converted.
|
|
51
51
|
*/
|
|
52
52
|
export function getNumber(value) {
|
|
53
|
-
const num =
|
|
53
|
+
const num = getOptionalNumber(value);
|
|
54
54
|
assertNumber(num);
|
|
55
55
|
return num;
|
|
56
56
|
}
|
package/util/search.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getWords, normalizeString } from "./string.js";
|
|
2
2
|
// Regular expressions.
|
|
3
3
|
export const MATCH_SPACE = /\s+/; // Match the first run of one or more space characters.
|
|
4
4
|
export const MATCH_SPACES = /\s+/g; // Match all runs of one or more space characters.
|
|
@@ -34,7 +34,7 @@ export const getWrapRegExp = (chars, middle = MATCH_WORDS.source) => new RegExp(
|
|
|
34
34
|
* - Unquoted words match partially (starting with a word boundary).
|
|
35
35
|
* - Quoted phrases match fully (starting and ending with a word boundary).
|
|
36
36
|
*/
|
|
37
|
-
export const toWordRegExps = (query) =>
|
|
37
|
+
export const toWordRegExps = (query) => getWords(query).map(toWordRegExp);
|
|
38
38
|
/** Convert a string to a regular expression matching the start of a word boundary. */
|
|
39
39
|
export const toWordRegExp = (word) => new RegExp(`\\b${escapeRegExp(normalizeString(word))}`, "i");
|
|
40
40
|
/**
|
package/util/string.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare function assertString(value: unknown): asserts value is string;
|
|
|
15
15
|
* - Primitives return `true`, `false`, `null`, `undefined`
|
|
16
16
|
* - Numbers return the stringified number.
|
|
17
17
|
*/
|
|
18
|
-
export declare function
|
|
18
|
+
export declare function getString(value: unknown): string;
|
|
19
19
|
/**
|
|
20
20
|
* Convert an unknown value into a title string for user-facing use.
|
|
21
21
|
* - Strings return the string.
|
|
@@ -29,7 +29,7 @@ export declare function toString(value: unknown): string;
|
|
|
29
29
|
* - Falsy values like `null` and `undefined` return `"None"`
|
|
30
30
|
* - Everything else returns `"Unknown"`
|
|
31
31
|
*/
|
|
32
|
-
export declare function
|
|
32
|
+
export declare function getTitle(value: unknown): string;
|
|
33
33
|
/** Concatenate an iterable set of strings together. */
|
|
34
34
|
export declare const joinStrings: (strs: Iterable<string>, joiner?: string) => string;
|
|
35
35
|
/**
|
|
@@ -65,7 +65,7 @@ export declare const normalizeString: (str: string) => string;
|
|
|
65
65
|
* - Remove any characters not in the range `[a-z0-9-]`
|
|
66
66
|
* - Change all spaces/separators/hyphens/dashes/underscores to `-` single hyphen.
|
|
67
67
|
*/
|
|
68
|
-
export declare const
|
|
68
|
+
export declare const getSlug: (str: string) => string;
|
|
69
69
|
/**
|
|
70
70
|
* Split a string into its separate words.
|
|
71
71
|
* - Words enclosed "in quotes" are a single word.
|
|
@@ -74,7 +74,7 @@ export declare const toSlug: (str: string) => string;
|
|
|
74
74
|
* @param str The input string, e.g. `yellow dog "Golden Retriever"`
|
|
75
75
|
* @returns Array of the found words, e.g. `["yellow", "dog", "Golden Retriever"
|
|
76
76
|
*/
|
|
77
|
-
export declare const
|
|
77
|
+
export declare const getWords: (str: string) => ImmutableArray<string>;
|
|
78
78
|
/** Find and iterate over the words in a string. */
|
|
79
79
|
export declare function yieldWords(value: string): Generator<string, void, void>;
|
|
80
80
|
/** Is the first character of a string an uppercase letter? */
|
package/util/string.js
CHANGED
|
@@ -23,7 +23,7 @@ export function assertString(value) {
|
|
|
23
23
|
* - Primitives return `true`, `false`, `null`, `undefined`
|
|
24
24
|
* - Numbers return the stringified number.
|
|
25
25
|
*/
|
|
26
|
-
export function
|
|
26
|
+
export function getString(value) {
|
|
27
27
|
if (typeof value === "string")
|
|
28
28
|
return value;
|
|
29
29
|
if (typeof value === "number")
|
|
@@ -49,7 +49,7 @@ export function toString(value) {
|
|
|
49
49
|
* - Falsy values like `null` and `undefined` return `"None"`
|
|
50
50
|
* - Everything else returns `"Unknown"`
|
|
51
51
|
*/
|
|
52
|
-
export function
|
|
52
|
+
export function getTitle(value) {
|
|
53
53
|
if (typeof value === "string")
|
|
54
54
|
return value ? value : "None";
|
|
55
55
|
if (typeof value === "boolean")
|
|
@@ -59,12 +59,12 @@ export function toTitle(value) {
|
|
|
59
59
|
if (value instanceof Date)
|
|
60
60
|
return formatDate(value);
|
|
61
61
|
if (isArray(value))
|
|
62
|
-
return value.map(
|
|
62
|
+
return value.map(getTitle).join(", ");
|
|
63
63
|
if (isData(value)) {
|
|
64
64
|
if ("name" in value)
|
|
65
|
-
return
|
|
65
|
+
return getTitle(value.name);
|
|
66
66
|
if ("title" in value)
|
|
67
|
-
return
|
|
67
|
+
return getTitle(value.title);
|
|
68
68
|
}
|
|
69
69
|
if (!value)
|
|
70
70
|
return "None";
|
|
@@ -113,7 +113,7 @@ const NORMAL_STRIP = /[^\p{L}\p{N}\s]+/gu; // Anything except letters, numbers,
|
|
|
113
113
|
* - Remove any characters not in the range `[a-z0-9-]`
|
|
114
114
|
* - Change all spaces/separators/hyphens/dashes/underscores to `-` single hyphen.
|
|
115
115
|
*/
|
|
116
|
-
export const
|
|
116
|
+
export const getSlug = (str) => str.toLowerCase().normalize("NFD").replace(SLUG_HYPHENS, "-").replace(SLUG_STRIP, "");
|
|
117
117
|
const SLUG_HYPHENS = /[\s\-–—_]+/gu; // Runs of spaces and hyphens.
|
|
118
118
|
const SLUG_STRIP = /^[^a-z0-9]+|[^a-z0-9]+$|[^a-z0-9-]+/g; // Non-alphanumeric or hyphen anywhere, or non-alphanumeric at start and end.
|
|
119
119
|
/**
|
|
@@ -124,7 +124,7 @@ const SLUG_STRIP = /^[^a-z0-9]+|[^a-z0-9]+$|[^a-z0-9-]+/g; // Non-alphanumeric o
|
|
|
124
124
|
* @param str The input string, e.g. `yellow dog "Golden Retriever"`
|
|
125
125
|
* @returns Array of the found words, e.g. `["yellow", "dog", "Golden Retriever"
|
|
126
126
|
*/
|
|
127
|
-
export const
|
|
127
|
+
export const getWords = (str) => Array.from(yieldWords(str));
|
|
128
128
|
/** Find and iterate over the words in a string. */
|
|
129
129
|
export function* yieldWords(value) {
|
|
130
130
|
for (const matches of value.matchAll(MATCH_WORD)) {
|
package/util/transform.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isFunction } from "./function.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getProps, isData } from "./data.js";
|
|
3
3
|
/** Is an unknown value a derivable. */
|
|
4
4
|
export const isTransformable = (v) => isData(v) && typeof v.transform === "function";
|
|
5
5
|
export function transform(input, transformer) {
|
|
@@ -17,7 +17,7 @@ export function transformData(data, transforms) {
|
|
|
17
17
|
* @yield Transformed prop entry after calling the corresponding prop transformer.
|
|
18
18
|
*/
|
|
19
19
|
export function* transformProps(data, transforms) {
|
|
20
|
-
for (const [k, v] of
|
|
20
|
+
for (const [k, v] of getProps(transforms))
|
|
21
21
|
yield [k, transform(data[k], v)];
|
|
22
22
|
}
|
|
23
23
|
export function* mapEntries(entries, transformer) {
|
package/util/validate.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Entry } from "./entry.js";
|
|
2
2
|
import type { ImmutableObject } from "./object.js";
|
|
3
3
|
import { Data, Prop } from "./data.js";
|
|
4
|
+
import { ImmutableArray } from "./array.js";
|
|
4
5
|
/** Object that can validate an unknown value with its `validate()` method. */
|
|
5
6
|
export interface Validatable<T> {
|
|
6
7
|
/**
|
|
@@ -31,6 +32,14 @@ export declare type ValidatorsType<T> = {
|
|
|
31
32
|
};
|
|
32
33
|
/** Validate an unknown value with a validator. */
|
|
33
34
|
export declare function validate<T>(unsafeValue: unknown, validator: Validator<T>): T;
|
|
35
|
+
/**
|
|
36
|
+
* Validate an array of items.
|
|
37
|
+
*
|
|
38
|
+
* @return Array with valid items.
|
|
39
|
+
* @throw InvalidFeedback if one or more entry values did not validate.
|
|
40
|
+
* - `feedback.details` will contain an entry for each invalid item (keyed by their count in the input iterable).
|
|
41
|
+
*/
|
|
42
|
+
export declare function validateArray<T>(unsafeItems: Iterable<unknown>, validator: Validator<T>): ImmutableArray<T>;
|
|
34
43
|
/**
|
|
35
44
|
* Validate an iterable set of items with a validator.
|
|
36
45
|
*
|