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/feedback/Feedback.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { debug } from "../util/debug.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getTitle } from "../util/string.js";
|
|
3
3
|
/**
|
|
4
4
|
* The `Feedback` class represents a feedback message that should be shown to the user.
|
|
5
5
|
* - Basic `Feedback` is neither good nor bad, `SuccessFeedback` indicates good news, and `ErrorFeedback` indicates bad news.
|
|
@@ -27,7 +27,7 @@ export class Feedback {
|
|
|
27
27
|
if (v instanceof Feedback)
|
|
28
28
|
messages[k] = v.feedback;
|
|
29
29
|
else
|
|
30
|
-
messages[k] =
|
|
30
|
+
messages[k] = getTitle(v);
|
|
31
31
|
}
|
|
32
32
|
return messages;
|
|
33
33
|
}
|
|
@@ -2,9 +2,9 @@ import type { Firestore } from "firebase/firestore";
|
|
|
2
2
|
import type { DocumentReference, QueryReference } from "../../db/Reference.js";
|
|
3
3
|
import type { Data, Entities, OptionalEntity } from "../../util/data.js";
|
|
4
4
|
import type { Unsubscribe } from "../../observe/Observable.js";
|
|
5
|
+
import { Observer } from "../../observe/Observer.js";
|
|
5
6
|
import { AsynchronousProvider, Provider } from "../../provider/Provider.js";
|
|
6
7
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
7
|
-
import { Observer } from "../../observe/Observer.js";
|
|
8
8
|
/**
|
|
9
9
|
* Firestore client database provider.
|
|
10
10
|
* - Works with the Firebase JS SDK.
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { orderBy as firestoreOrderBy, where as firestoreWhere, limit as firestoreLimit, increment as firestoreIncrement, arrayUnion as firestoreArrayUnion, arrayRemove as firestoreArrayRemove, deleteField as firestoreDeleteField, collection as firestoreCollection, doc as firestoreDocument, query as firestoreQuery, onSnapshot, addDoc, setDoc, updateDoc, deleteDoc, getDoc, getDocs, } from "firebase/firestore";
|
|
2
|
+
import { dispatchError, dispatchNext } from "../../observe/Observer.js";
|
|
2
3
|
import { UnsupportedError } from "../../error/UnsupportedError.js";
|
|
3
4
|
import { Provider } from "../../provider/Provider.js";
|
|
4
5
|
import { ArrayUpdate } from "../../update/ArrayUpdate.js";
|
|
5
6
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
6
7
|
import { Increment } from "../../update/Increment.js";
|
|
7
8
|
import { ObjectUpdate } from "../../update/ObjectUpdate.js";
|
|
8
|
-
import {
|
|
9
|
+
import { Delete } from "../../update/Delete.js";
|
|
10
|
+
import { Update } from "../../update/Update.js";
|
|
9
11
|
// Constants.
|
|
10
12
|
// const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
|
|
11
13
|
const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
|
|
@@ -60,7 +62,9 @@ function getOptionalEntity(snapshot) {
|
|
|
60
62
|
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
61
63
|
function* yieldFieldValues(updates, prefix = "") {
|
|
62
64
|
for (const [key, update] of updates) {
|
|
63
|
-
if (update
|
|
65
|
+
if (!(update instanceof Update))
|
|
66
|
+
yield [`${prefix}${key}`, update];
|
|
67
|
+
else if (update instanceof Delete)
|
|
64
68
|
yield [`${prefix}${key}`, firestoreDeleteField()];
|
|
65
69
|
else if (update instanceof Increment)
|
|
66
70
|
yield [`${prefix}${key}`, firestoreIncrement(update.amount)];
|
|
@@ -75,7 +79,7 @@ function* yieldFieldValues(updates, prefix = "") {
|
|
|
75
79
|
yield [`${prefix}${key}`, firestoreArrayRemove(...update.deletes)];
|
|
76
80
|
}
|
|
77
81
|
else
|
|
78
|
-
yield [`${prefix}${key}`, update];
|
|
82
|
+
yield [`${prefix}${key}`, update.transform()];
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
/**
|
|
@@ -5,6 +5,8 @@ import { ArrayUpdate } from "../../update/ArrayUpdate.js";
|
|
|
5
5
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
6
6
|
import { Increment } from "../../update/Increment.js";
|
|
7
7
|
import { ObjectUpdate } from "../../update/ObjectUpdate.js";
|
|
8
|
+
import { Update } from "../../update/Update.js";
|
|
9
|
+
import { Delete } from "../../update/Delete.js";
|
|
8
10
|
// Constants.
|
|
9
11
|
// const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
|
|
10
12
|
const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
|
|
@@ -59,7 +61,9 @@ function getOptionalData(snapshot) {
|
|
|
59
61
|
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
60
62
|
function* yieldFieldValues(updates, prefix = "") {
|
|
61
63
|
for (const [key, update] of updates) {
|
|
62
|
-
if (update
|
|
64
|
+
if (!(update instanceof Update))
|
|
65
|
+
yield [`${prefix}${key}`, update];
|
|
66
|
+
else if (update instanceof Delete)
|
|
63
67
|
yield [`${prefix}${key}`, firestoreDeleteField()];
|
|
64
68
|
else if (update instanceof Increment)
|
|
65
69
|
yield [`${prefix}${key}`, firestoreIncrement(update.amount)];
|
|
@@ -74,7 +78,7 @@ function* yieldFieldValues(updates, prefix = "") {
|
|
|
74
78
|
yield [`${prefix}${key}`, firestoreArrayRemove(...update.deletes)];
|
|
75
79
|
}
|
|
76
80
|
else
|
|
77
|
-
yield [`${prefix}${key}`, update];
|
|
81
|
+
yield [`${prefix}${key}`, update.transform()];
|
|
78
82
|
}
|
|
79
83
|
}
|
|
80
84
|
/**
|
|
@@ -2,9 +2,9 @@ import { Firestore } from "@google-cloud/firestore";
|
|
|
2
2
|
import type { DocumentReference, QueryReference } from "../../db/Reference.js";
|
|
3
3
|
import type { Data, Entities, OptionalEntity } from "../../util/data.js";
|
|
4
4
|
import type { Unsubscribe } from "../../observe/Observable.js";
|
|
5
|
+
import { Observer } from "../../observe/Observer.js";
|
|
5
6
|
import { AsynchronousProvider, Provider } from "../../provider/Provider.js";
|
|
6
7
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
7
|
-
import { Observer } from "../../observe/Observer.js";
|
|
8
8
|
/**
|
|
9
9
|
* Firestore server database provider.
|
|
10
10
|
* - Works with the Firebase Admin SDK for Node.JS
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Firestore, FieldValue } from "@google-cloud/firestore";
|
|
2
|
+
import { dispatchError, dispatchNext } from "../../observe/Observer.js";
|
|
2
3
|
import { UnsupportedError } from "../../error/UnsupportedError.js";
|
|
3
4
|
import { Provider } from "../../provider/Provider.js";
|
|
4
5
|
import { ArrayUpdate } from "../../update/ArrayUpdate.js";
|
|
5
6
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
6
7
|
import { Increment } from "../../update/Increment.js";
|
|
7
8
|
import { ObjectUpdate } from "../../update/ObjectUpdate.js";
|
|
8
|
-
import {
|
|
9
|
+
import { Delete } from "../../update/Delete.js";
|
|
10
|
+
import { Update } from "../../update/Update.js";
|
|
9
11
|
// Constants.
|
|
10
12
|
// const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
|
|
11
13
|
const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
|
|
@@ -60,7 +62,9 @@ function getOptionalEntity(snapshot) {
|
|
|
60
62
|
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
61
63
|
function* yieldFieldValues(updates, prefix = "") {
|
|
62
64
|
for (const [key, update] of updates) {
|
|
63
|
-
if (update
|
|
65
|
+
if (!(update instanceof Update))
|
|
66
|
+
yield [`${prefix}${key}`, update];
|
|
67
|
+
else if (update instanceof Delete)
|
|
64
68
|
yield [`${prefix}${key}`, FieldValue.delete()];
|
|
65
69
|
else if (update instanceof Increment)
|
|
66
70
|
yield [`${prefix}${key}`, FieldValue.increment(update.amount)];
|
|
@@ -75,7 +79,7 @@ function* yieldFieldValues(updates, prefix = "") {
|
|
|
75
79
|
yield [`${prefix}${key}`, FieldValue.arrayRemove(...update.deletes)];
|
|
76
80
|
}
|
|
77
81
|
else
|
|
78
|
-
yield [`${prefix}${key}`, update];
|
|
82
|
+
yield [`${prefix}${key}`, update.transform()];
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
/**
|
package/package.json
CHANGED
|
@@ -31,5 +31,7 @@ export interface SynchronousThroughProvider extends SynchronousProvider {
|
|
|
31
31
|
export interface AsynchronousThroughProvider extends AsynchronousProvider {
|
|
32
32
|
new (source: AsynchronousProvider): AsynchronousProvider;
|
|
33
33
|
}
|
|
34
|
-
/** Find a
|
|
35
|
-
export declare function
|
|
34
|
+
/** Find a possible source provider in a database's provider stack (if it exists). */
|
|
35
|
+
export declare function getOptionalSourceProvider<P extends Provider>(provider: Provider, type: Class<P>): P | undefined;
|
|
36
|
+
/** Find a source provider in a database's provider stack. */
|
|
37
|
+
export declare function getSourceProvider<P extends Provider>(provider: Provider, type: Class<P>): P;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AssertionError } from "../error/AssertionError.js";
|
|
1
2
|
import { Provider } from "./Provider.js";
|
|
2
3
|
/**
|
|
3
4
|
* Pass all reads and writes through to a source provider.
|
|
@@ -41,10 +42,17 @@ export class ThroughProvider extends Provider {
|
|
|
41
42
|
return this.source.deleteQuery(ref);
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
|
-
/** Find a
|
|
45
|
-
export function
|
|
45
|
+
/** Find a possible source provider in a database's provider stack (if it exists). */
|
|
46
|
+
export function getOptionalSourceProvider(provider, type) {
|
|
46
47
|
if (provider instanceof type)
|
|
47
48
|
return provider;
|
|
48
49
|
if (provider instanceof ThroughProvider)
|
|
49
|
-
return
|
|
50
|
+
return getSourceProvider(provider.source, type);
|
|
51
|
+
}
|
|
52
|
+
/** Find a source provider in a database's provider stack. */
|
|
53
|
+
export function getSourceProvider(provider, type) {
|
|
54
|
+
const source = getOptionalSourceProvider(provider, type);
|
|
55
|
+
if (!source)
|
|
56
|
+
throw new AssertionError(`Source provider ${type.name} not found`, provider);
|
|
57
|
+
return source;
|
|
50
58
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { callAsync } from "../util/async.js";
|
|
2
2
|
import { validate } from "../util/validate.js";
|
|
3
|
-
import { validateUpdate } from "../update/util.js";
|
|
4
3
|
import { Feedback } from "../feedback/Feedback.js";
|
|
5
4
|
import { ValidationError } from "../error/ValidationError.js";
|
|
6
5
|
import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
|
|
@@ -21,7 +20,7 @@ export class ValidationProvider extends ThroughProvider {
|
|
|
21
20
|
return super.setDocument(ref, validate(value, ref.validator));
|
|
22
21
|
}
|
|
23
22
|
updateDocument(ref, update) {
|
|
24
|
-
return super.updateDocument(ref,
|
|
23
|
+
return super.updateDocument(ref, update.validate(ref.validator));
|
|
25
24
|
}
|
|
26
25
|
getQuery(ref) {
|
|
27
26
|
return callAsync(_validateEntities, super.getQuery(ref), ref);
|
|
@@ -33,7 +32,7 @@ export class ValidationProvider extends ThroughProvider {
|
|
|
33
32
|
return super.setQuery(ref, validate(value, ref.validator));
|
|
34
33
|
}
|
|
35
34
|
updateQuery(ref, update) {
|
|
36
|
-
return super.updateQuery(ref,
|
|
35
|
+
return super.updateQuery(ref, update.validate(ref.validator));
|
|
37
36
|
}
|
|
38
37
|
}
|
|
39
38
|
/** Validate an entity for a document reference. */
|
package/react/useDocument.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { reduceMapItem } from "../util/map.js";
|
|
2
2
|
import { getDocumentData } from "../db/Reference.js";
|
|
3
3
|
import { CacheProvider } from "../provider/CacheProvider.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getOptionalSourceProvider } from "../provider/ThroughProvider.js";
|
|
5
5
|
import { State } from "../state/State.js";
|
|
6
6
|
import { BooleanState } from "../state/BooleanState.js";
|
|
7
7
|
import { ConditionError } from "../error/ConditionError.js";
|
|
@@ -12,7 +12,7 @@ import { useCache } from "./useCache.js";
|
|
|
12
12
|
export class DocumentState extends State {
|
|
13
13
|
constructor(ref) {
|
|
14
14
|
var _a;
|
|
15
|
-
const table = (_a =
|
|
15
|
+
const table = (_a = getOptionalSourceProvider(ref.db.provider, CacheProvider)) === null || _a === void 0 ? void 0 : _a.memory.getTable(ref);
|
|
16
16
|
const time = table ? table.getDocumentTime(ref.id) : null;
|
|
17
17
|
const isCached = typeof time === "number";
|
|
18
18
|
super(table && isCached ? table.getDocument(ref.id) : NOVALUE);
|
|
@@ -63,7 +63,7 @@ export class DocumentState extends State {
|
|
|
63
63
|
/** Subscribe this state to any `CacheProvider` that exists in the provider chain. */
|
|
64
64
|
connectCache() {
|
|
65
65
|
var _a;
|
|
66
|
-
const table = (_a =
|
|
66
|
+
const table = (_a = getOptionalSourceProvider(this.ref.db.provider, CacheProvider)) === null || _a === void 0 ? void 0 : _a.memory.getTable(this.ref);
|
|
67
67
|
table && this.connect(() => table.subscribeCachedDocument(this.ref.id, this));
|
|
68
68
|
}
|
|
69
69
|
// Override to subscribe to the cache when an observer is added.
|
package/react/useQuery.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { reduceMapItem } from "../util/map.js";
|
|
2
2
|
import { getQueryFirstData, getQueryFirstValue } from "../db/Reference.js";
|
|
3
3
|
import { CacheProvider } from "../provider/CacheProvider.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getOptionalSourceProvider } from "../provider/ThroughProvider.js";
|
|
5
5
|
import { State } from "../state/State.js";
|
|
6
6
|
import { ConditionError } from "../error/ConditionError.js";
|
|
7
7
|
import { BooleanState } from "../state/BooleanState.js";
|
|
@@ -12,7 +12,7 @@ import { useCache } from "./useCache.js";
|
|
|
12
12
|
export class QueryState extends State {
|
|
13
13
|
constructor(ref) {
|
|
14
14
|
var _a, _b;
|
|
15
|
-
const table = (_a =
|
|
15
|
+
const table = (_a = getOptionalSourceProvider(ref.db.provider, CacheProvider)) === null || _a === void 0 ? void 0 : _a.memory.getTable(ref);
|
|
16
16
|
const time = table ? table.getQueryTime(ref) : null;
|
|
17
17
|
const isCached = typeof time === "number";
|
|
18
18
|
super(table && isCached ? table.getQuery(ref) : NOVALUE);
|
|
@@ -96,7 +96,7 @@ export class QueryState extends State {
|
|
|
96
96
|
/** Subscribe this state to any `CacheProvider` that exists in the provider chain. */
|
|
97
97
|
connectCache() {
|
|
98
98
|
var _a;
|
|
99
|
-
const table = (_a =
|
|
99
|
+
const table = (_a = getOptionalSourceProvider(this.ref.db.provider, CacheProvider)) === null || _a === void 0 ? void 0 : _a.memory.getTable(this.ref);
|
|
100
100
|
return table && this.connect(() => table.subscribeCachedQuery(this.ref, this));
|
|
101
101
|
}
|
|
102
102
|
// Override to subscribe to the cache when an observer is added.
|
package/schema/AllowSchema.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getString } from "../util/string.js";
|
|
3
3
|
import { isItem } from "../util/array.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getOptionalNumber } from "../util/number.js";
|
|
5
5
|
import { isKey } from "../util/object.js";
|
|
6
6
|
import { Schema } from "./Schema.js";
|
|
7
7
|
/** Validate a value against a specific set of allowed values. */
|
|
@@ -27,13 +27,13 @@ export class AllowSchema extends Schema {
|
|
|
27
27
|
/** Define a valid string from an allowed set of strings. */
|
|
28
28
|
export class AllowStringSchema extends AllowSchema {
|
|
29
29
|
validate(unsafeValue = this.value) {
|
|
30
|
-
return validateAllowed(
|
|
30
|
+
return validateAllowed(getString(unsafeValue), this.allow);
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
/** Define a valid number from an allowed set of numbers. */
|
|
34
34
|
export class AllowNumberSchema extends AllowSchema {
|
|
35
35
|
validate(unsafeValue = this.value) {
|
|
36
|
-
return validateAllowed(
|
|
36
|
+
return validateAllowed(getOptionalNumber(unsafeValue), this.allow);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
/** Valid string from an allowed set of strings. */
|
package/schema/ArraySchema.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { uniqueArray } from "../util/array.js";
|
|
3
|
+
import { validateArray } from "../util/validate.js";
|
|
4
4
|
import { Schema } from "./Schema.js";
|
|
5
5
|
/**
|
|
6
6
|
* Define a valid array.
|
|
@@ -41,7 +41,7 @@ export class ArraySchema extends Schema {
|
|
|
41
41
|
validate(unsafeValue = this.value) {
|
|
42
42
|
if (!(unsafeValue instanceof Array))
|
|
43
43
|
throw new InvalidFeedback("Must be array", { value: unsafeValue });
|
|
44
|
-
const safeArray =
|
|
44
|
+
const safeArray = validateArray(unsafeValue, this.items);
|
|
45
45
|
const dedupedArray = this.unique ? uniqueArray(safeArray) : safeArray;
|
|
46
46
|
if (typeof this.min === "number" && dedupedArray.length < this.min)
|
|
47
47
|
throw new InvalidFeedback(dedupedArray.length ? `Minimum ${this.min} items` : "Required", { value: dedupedArray });
|
package/schema/DateSchema.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getOptionalDate, getYmd } from "../util/date.js";
|
|
2
2
|
import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
|
|
3
3
|
import { Schema } from "./Schema.js";
|
|
4
4
|
import { OPTIONAL } from "./OptionalSchema.js";
|
|
@@ -11,13 +11,13 @@ export class DateSchema extends Schema {
|
|
|
11
11
|
this.max = max;
|
|
12
12
|
}
|
|
13
13
|
validate(unsafeValue = this.value) {
|
|
14
|
-
const date =
|
|
14
|
+
const date = getOptionalDate(unsafeValue);
|
|
15
15
|
if (!date)
|
|
16
16
|
throw new InvalidFeedback(unsafeValue ? "Invalid date" : "Required", { value: unsafeValue });
|
|
17
|
-
const minDate =
|
|
17
|
+
const minDate = getOptionalDate(this.min);
|
|
18
18
|
if (minDate && date.getTime() < minDate.getTime())
|
|
19
19
|
throw new InvalidFeedback(`Minimum ${minDate.toLocaleDateString()}`, { value: date });
|
|
20
|
-
const maxDate =
|
|
20
|
+
const maxDate = getOptionalDate(this.max);
|
|
21
21
|
if (maxDate && date.getTime() > maxDate.getTime())
|
|
22
22
|
throw new InvalidFeedback(`Maximum ${maxDate.toLocaleDateString()}`, { value: date });
|
|
23
23
|
return getYmd(date);
|
package/schema/NumberSchema.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getOptionalNumber, roundStep } from "../util/number.js";
|
|
2
2
|
import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
|
|
3
3
|
import { Schema } from "./Schema.js";
|
|
4
4
|
import { OPTIONAL } from "./OptionalSchema.js";
|
|
@@ -12,7 +12,7 @@ export class NumberSchema extends Schema {
|
|
|
12
12
|
this.step = step;
|
|
13
13
|
}
|
|
14
14
|
validate(unsafeValue = this.value) {
|
|
15
|
-
const unsafeNumber =
|
|
15
|
+
const unsafeNumber = getOptionalNumber(unsafeValue);
|
|
16
16
|
if (typeof unsafeNumber !== "number")
|
|
17
17
|
throw new InvalidFeedback("Must be number", { value: unsafeValue });
|
|
18
18
|
const safeNumber = typeof this.step === "number" ? roundStep(unsafeNumber, this.step) : unsafeNumber;
|
package/schema/SlugSchema.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getSlug } from "../util/string.js";
|
|
2
2
|
import { OPTIONAL } from "./OptionalSchema.js";
|
|
3
3
|
import { StringSchema } from "./StringSchema.js";
|
|
4
4
|
/**
|
|
@@ -16,7 +16,7 @@ export class SlugSchema extends StringSchema {
|
|
|
16
16
|
this.max = 32;
|
|
17
17
|
}
|
|
18
18
|
sanitize(unsafeString) {
|
|
19
|
-
return
|
|
19
|
+
return getSlug(unsafeString);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
/** Valid slug, e.g. `this-is-a-slug` */
|
|
@@ -7,5 +7,7 @@ export declare abstract class ThroughSchema<T> extends Schema<T> {
|
|
|
7
7
|
});
|
|
8
8
|
validate(unsafeValue: unknown): T;
|
|
9
9
|
}
|
|
10
|
-
/** Find a
|
|
11
|
-
export declare function
|
|
10
|
+
/** Find a possible source schema in a schema (if it exists). */
|
|
11
|
+
export declare function getOptionalSourceSchema<X extends Schema>(schema: Schema, type: Class<X>): X | undefined;
|
|
12
|
+
/** Find a source schema in a schema. */
|
|
13
|
+
export declare function getSourceSchema<X extends Schema>(schema: Schema, type: Class<X>): X;
|
package/schema/ThroughSchema.js
CHANGED
|
@@ -9,11 +9,17 @@ export class ThroughSchema extends Schema {
|
|
|
9
9
|
return this.source.validate(unsafeValue);
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
-
/** Find a
|
|
13
|
-
export function
|
|
12
|
+
/** Find a possible source schema in a schema (if it exists). */
|
|
13
|
+
export function getOptionalSourceSchema(schema, type) {
|
|
14
14
|
if (schema instanceof type)
|
|
15
15
|
return schema;
|
|
16
16
|
if (schema instanceof ThroughSchema)
|
|
17
|
-
return
|
|
18
|
-
|
|
17
|
+
return getSourceSchema(schema.source, type);
|
|
18
|
+
}
|
|
19
|
+
/** Find a source schema in a schema. */
|
|
20
|
+
export function getSourceSchema(schema, type) {
|
|
21
|
+
const source = getOptionalSourceSchema(schema, type);
|
|
22
|
+
if (!source)
|
|
23
|
+
throw new AssertionError(`Source schema "${type.name}" not found`, schema);
|
|
24
|
+
return source;
|
|
19
25
|
}
|
package/update/ArrayUpdate.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ImmutableArray } from "../util/array.js";
|
|
2
|
+
import { Validator } from "../util/validate.js";
|
|
2
3
|
import { Update } from "./Update.js";
|
|
3
4
|
/** Update that can be applied to an array to add/remove items. */
|
|
4
5
|
export declare class ArrayUpdate<T> extends Update<ImmutableArray<T>> {
|
|
@@ -9,8 +10,8 @@ export declare class ArrayUpdate<T> extends Update<ImmutableArray<T>> {
|
|
|
9
10
|
readonly adds: ImmutableArray<T>;
|
|
10
11
|
readonly deletes: ImmutableArray<T>;
|
|
11
12
|
constructor(adds?: ImmutableArray<T>, deletes?: ImmutableArray<T>);
|
|
12
|
-
/** Transform an array using this array update. */
|
|
13
13
|
transform(arr?: ImmutableArray<T>): ImmutableArray<T>;
|
|
14
|
+
validate(validator: Validator<ImmutableArray<T>>): this;
|
|
14
15
|
/** Return an array update with an additional item marked for addition. */
|
|
15
16
|
with(...adds: T[]): this;
|
|
16
17
|
/** Return an array update with an additional item marked for deletion. */
|
package/update/ArrayUpdate.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { ArraySchema } from "../schema/ArraySchema.js";
|
|
1
2
|
import { withItems, withoutItems } from "../util/array.js";
|
|
3
|
+
import { validateArray } from "../util/validate.js";
|
|
2
4
|
import { Update } from "./Update.js";
|
|
3
5
|
/** Update that can be applied to an array to add/remove items. */
|
|
4
6
|
export class ArrayUpdate extends Update {
|
|
@@ -15,16 +17,33 @@ export class ArrayUpdate extends Update {
|
|
|
15
17
|
static without(...deletes) {
|
|
16
18
|
return new ArrayUpdate([], deletes);
|
|
17
19
|
}
|
|
18
|
-
/** Transform an array using this array update. */
|
|
19
20
|
transform(arr = []) {
|
|
20
21
|
return withoutItems(withItems(arr, this.adds), this.deletes);
|
|
21
22
|
}
|
|
23
|
+
validate(validator) {
|
|
24
|
+
if (!(validator instanceof ArraySchema))
|
|
25
|
+
return super.validate(validator);
|
|
26
|
+
return {
|
|
27
|
+
__proto__: Object.getPrototypeOf(this),
|
|
28
|
+
...this,
|
|
29
|
+
adds: validateArray(this.adds, validator.items),
|
|
30
|
+
deletes: validateArray(this.deletes, validator.items),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
22
33
|
/** Return an array update with an additional item marked for addition. */
|
|
23
34
|
with(...adds) {
|
|
24
|
-
return {
|
|
35
|
+
return {
|
|
36
|
+
__proto__: Object.getPrototypeOf(this),
|
|
37
|
+
...this,
|
|
38
|
+
adds: [...this.adds, ...adds],
|
|
39
|
+
};
|
|
25
40
|
}
|
|
26
41
|
/** Return an array update with an additional item marked for deletion. */
|
|
27
42
|
without(...deletes) {
|
|
28
|
-
return {
|
|
43
|
+
return {
|
|
44
|
+
__proto__: Object.getPrototypeOf(this),
|
|
45
|
+
...this,
|
|
46
|
+
deletes: [...this.deletes, ...deletes],
|
|
47
|
+
};
|
|
29
48
|
}
|
|
30
49
|
}
|
package/update/DataUpdate.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Data, Key, Prop } from "../util/data.js";
|
|
2
2
|
import { Nullish } from "../util/null.js";
|
|
3
3
|
import { Transformable } from "../util/transform.js";
|
|
4
|
+
import { Validator } from "../util/validate.js";
|
|
4
5
|
import { Update } from "./Update.js";
|
|
5
6
|
/**
|
|
6
7
|
* Set of named transforms for the props of a data object.
|
|
@@ -18,8 +19,8 @@ export declare class DataUpdate<T extends Data> extends Update<T> implements Ite
|
|
|
18
19
|
static with<X extends Data, K extends Key<X>>(key: Nullish<K>, value: X[K] | Update<X[K]>): DataUpdate<X>;
|
|
19
20
|
readonly updates: PropUpdates<T>;
|
|
20
21
|
constructor(props: PropUpdates<T>);
|
|
21
|
-
/** Transform a a data object using this update. */
|
|
22
22
|
transform(data: T): T;
|
|
23
|
+
validate(validator: Validator<T>): this;
|
|
23
24
|
/** Return a data update with a specific prop marked for update. */
|
|
24
25
|
with<K extends Key<T>>(key: Nullish<K>, value: T[K] | Update<T[K]>): this;
|
|
25
26
|
/** Iterate over the transforms in this object. */
|
package/update/DataUpdate.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { Feedback } from "../feedback/Feedback.js";
|
|
2
|
+
import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
|
|
3
|
+
import { DataSchema } from "../schema/DataSchema.js";
|
|
4
|
+
import { getProps } from "../util/data.js";
|
|
1
5
|
import { isNullish } from "../util/null.js";
|
|
2
6
|
import { transformData } from "../util/transform.js";
|
|
7
|
+
import { validate } from "../util/validate.js";
|
|
3
8
|
import { Update } from "./Update.js";
|
|
4
9
|
/** Update that can be applied to a data object to update its props. */
|
|
5
10
|
export class DataUpdate extends Update {
|
|
@@ -11,18 +16,53 @@ export class DataUpdate extends Update {
|
|
|
11
16
|
static with(key, value) {
|
|
12
17
|
return new DataUpdate(!isNullish(key) ? { [key]: value } : {});
|
|
13
18
|
}
|
|
14
|
-
/** Transform a a data object using this update. */
|
|
15
19
|
transform(data) {
|
|
16
20
|
return transformData(data, this.updates);
|
|
17
21
|
}
|
|
22
|
+
validate(validator) {
|
|
23
|
+
if (!(validator instanceof DataSchema))
|
|
24
|
+
return super.validate(validator);
|
|
25
|
+
return {
|
|
26
|
+
__proto__: Object.getPrototypeOf(this),
|
|
27
|
+
...this,
|
|
28
|
+
updates: Object.fromEntries(_validateUpdates(this.updates, validator.props)),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
18
31
|
/** Return a data update with a specific prop marked for update. */
|
|
19
32
|
with(key, value) {
|
|
20
33
|
if (isNullish(key))
|
|
21
34
|
return this;
|
|
22
|
-
return {
|
|
35
|
+
return {
|
|
36
|
+
__proto__: Object.getPrototypeOf(this),
|
|
37
|
+
...this,
|
|
38
|
+
updates: { ...this.updates, [key]: value },
|
|
39
|
+
};
|
|
23
40
|
}
|
|
24
41
|
/** Iterate over the transforms in this object. */
|
|
25
42
|
[Symbol.iterator]() {
|
|
26
43
|
return Object.entries(this.updates).values();
|
|
27
44
|
}
|
|
28
45
|
}
|
|
46
|
+
/** Validate a set of transforms against a set of validators. */
|
|
47
|
+
function* _validateUpdates(unsafeUpdates, validators) {
|
|
48
|
+
let invalid = false;
|
|
49
|
+
const details = {};
|
|
50
|
+
for (const [k, validator] of getProps(validators)) {
|
|
51
|
+
const unsafeUpdate = unsafeUpdates[k];
|
|
52
|
+
if (unsafeUpdate !== undefined) {
|
|
53
|
+
try {
|
|
54
|
+
yield [k, unsafeUpdate instanceof Update ? unsafeUpdate.validate(validator) : validate(unsafeUpdate, validator)];
|
|
55
|
+
}
|
|
56
|
+
catch (thrown) {
|
|
57
|
+
if (thrown instanceof Feedback) {
|
|
58
|
+
invalid = true;
|
|
59
|
+
details[k] = thrown;
|
|
60
|
+
}
|
|
61
|
+
else
|
|
62
|
+
throw thrown;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (invalid)
|
|
67
|
+
throw new InvalidFeedback("Invalid updates", details);
|
|
68
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Update } from "./Update.js";
|
|
2
|
+
/**
|
|
3
|
+
* Delete update: an object that deletes a value.
|
|
4
|
+
* - Hint: you can use negative numbers to decrement the number too!
|
|
5
|
+
*/
|
|
6
|
+
export declare class Delete extends Update<undefined> {
|
|
7
|
+
transform(): undefined;
|
|
8
|
+
validate(): this;
|
|
9
|
+
}
|
|
10
|
+
/** Update that deletes any value. */
|
|
11
|
+
export declare const DELETE: Delete;
|
package/update/Delete.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Update } from "./Update.js";
|
|
2
|
+
/**
|
|
3
|
+
* Delete update: an object that deletes a value.
|
|
4
|
+
* - Hint: you can use negative numbers to decrement the number too!
|
|
5
|
+
*/
|
|
6
|
+
export class Delete extends Update {
|
|
7
|
+
transform() {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
validate() {
|
|
11
|
+
return this;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** Update that deletes any value. */
|
|
15
|
+
export const DELETE = new Delete();
|
package/update/Increment.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Update } from "./Update.js";
|
|
2
2
|
/**
|
|
3
|
-
* Increment
|
|
3
|
+
* Increment update: an object that increments/decrements a value.
|
|
4
4
|
* - Hint: you can use negative numbers to decrement the number too!
|
|
5
5
|
*/
|
|
6
6
|
export declare class Increment extends Update<number> {
|
|
@@ -8,11 +8,11 @@ export declare class Increment extends Update<number> {
|
|
|
8
8
|
constructor(amount: number);
|
|
9
9
|
transform(existing?: unknown): number;
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
11
|
+
/** Update that increments a value by one. */
|
|
12
12
|
export declare const INCREMENT: Increment;
|
|
13
|
-
/**
|
|
13
|
+
/** Update that increments a value by a specific amount. */
|
|
14
14
|
export declare const INCREMENT_BY: (amount: number) => Increment;
|
|
15
|
-
/**
|
|
15
|
+
/** Update that decrements a value by one. */
|
|
16
16
|
export declare const DECREMENT: Increment;
|
|
17
|
-
/**
|
|
17
|
+
/** Update that decrements a value by a specific amount. */
|
|
18
18
|
export declare const DECREMENT_BY: (amount: number) => Increment;
|
package/update/Increment.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Update } from "./Update.js";
|
|
2
2
|
/**
|
|
3
|
-
* Increment
|
|
3
|
+
* Increment update: an object that increments/decrements a value.
|
|
4
4
|
* - Hint: you can use negative numbers to decrement the number too!
|
|
5
5
|
*/
|
|
6
6
|
export class Increment extends Update {
|
|
@@ -12,11 +12,11 @@ export class Increment extends Update {
|
|
|
12
12
|
return typeof existing === "number" ? existing + this.amount : this.amount;
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
15
|
+
/** Update that increments a value by one. */
|
|
16
16
|
export const INCREMENT = new Increment(1);
|
|
17
|
-
/**
|
|
17
|
+
/** Update that increments a value by a specific amount. */
|
|
18
18
|
export const INCREMENT_BY = (amount) => new Increment(amount);
|
|
19
|
-
/**
|
|
19
|
+
/** Update that decrements a value by one. */
|
|
20
20
|
export const DECREMENT = new Increment(-1);
|
|
21
|
-
/**
|
|
21
|
+
/** Update that decrements a value by a specific amount. */
|
|
22
22
|
export const DECREMENT_BY = (amount) => new Increment(0 - amount);
|