shelving 1.82.1 → 1.83.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.
Files changed (71) hide show
  1. package/constraint/QueryConstraints.js +3 -3
  2. package/feedback/Feedback.d.ts +2 -2
  3. package/feedback/Feedback.js +3 -2
  4. package/firestore/client/FirestoreClientProvider.js +2 -2
  5. package/firestore/lite/FirestoreLiteProvider.js +2 -2
  6. package/firestore/server/FirestoreServerProvider.js +2 -2
  7. package/package.json +1 -1
  8. package/provider/MemoryProvider.d.ts +1 -1
  9. package/provider/MemoryProvider.js +3 -3
  10. package/provider/ValidationProvider.js +2 -2
  11. package/schema/AllowSchema.d.ts +25 -24
  12. package/schema/AllowSchema.js +25 -29
  13. package/schema/ArraySchema.d.ts +2 -2
  14. package/schema/BooleanSchema.d.ts +2 -2
  15. package/schema/DataSchema.d.ts +2 -2
  16. package/schema/DataSchema.js +2 -2
  17. package/schema/DateSchema.d.ts +2 -2
  18. package/schema/DictionarySchema.d.ts +19 -0
  19. package/schema/{ObjectSchema.js → DictionarySchema.js} +6 -6
  20. package/schema/LinkSchema.d.ts +2 -2
  21. package/schema/NumberSchema.d.ts +2 -2
  22. package/schema/Schema.d.ts +10 -8
  23. package/schema/Schema.js +1 -1
  24. package/schema/StringSchema.d.ts +12 -10
  25. package/schema/index.d.ts +1 -1
  26. package/schema/index.js +1 -1
  27. package/state/DataState.js +3 -3
  28. package/state/DictionaryState.d.ts +15 -0
  29. package/state/{ObjectState.js → DictionaryState.js} +6 -6
  30. package/state/index.d.ts +2 -2
  31. package/state/index.js +2 -2
  32. package/test/basics.js +1 -1
  33. package/update/DataUpdate.d.ts +2 -0
  34. package/update/DataUpdate.js +4 -2
  35. package/update/DictionaryUpdate.d.ts +29 -0
  36. package/update/{ObjectUpdate.js → DictionaryUpdate.js} +14 -14
  37. package/update/hydrations.js +2 -2
  38. package/update/index.d.ts +1 -1
  39. package/update/index.js +1 -1
  40. package/util/clone.d.ts +2 -2
  41. package/util/clone.js +5 -5
  42. package/util/data.d.ts +13 -52
  43. package/util/data.js +6 -1
  44. package/util/dictionary.d.ts +39 -0
  45. package/util/dictionary.js +33 -0
  46. package/util/diff.d.ts +3 -3
  47. package/util/entry.d.ts +7 -5
  48. package/util/entry.js +8 -6
  49. package/util/filter.d.ts +0 -5
  50. package/util/filter.js +0 -3
  51. package/util/hydrate.d.ts +2 -2
  52. package/util/hydrate.js +7 -8
  53. package/util/index.d.ts +1 -0
  54. package/util/index.js +1 -0
  55. package/util/map.d.ts +18 -4
  56. package/util/map.js +10 -6
  57. package/util/merge.d.ts +3 -6
  58. package/util/merge.js +4 -6
  59. package/util/object.d.ts +77 -49
  60. package/util/object.js +22 -31
  61. package/util/template.d.ts +3 -3
  62. package/util/template.js +3 -3
  63. package/util/transform.d.ts +21 -44
  64. package/util/transform.js +21 -39
  65. package/util/units.d.ts +6 -12
  66. package/util/units.js +9 -5
  67. package/util/validate.d.ts +4 -3
  68. package/util/validate.js +3 -2
  69. package/schema/ObjectSchema.d.ts +0 -19
  70. package/state/ObjectState.d.ts +0 -16
  71. package/update/ObjectUpdate.d.ts +0 -29
@@ -1,4 +1,4 @@
1
- import { getObjectProp } from "../util/object.js";
1
+ import { getProp } from "../util/object.js";
2
2
  import { assert } from "../util/assert.js";
3
3
  import { limitItems } from "../util/iterate.js";
4
4
  import { FilterConstraints } from "./FilterConstraints.js";
@@ -96,7 +96,7 @@ function* _getAfterFilters(sorts, item) {
96
96
  for (const sort of sorts) {
97
97
  const { key, direction } = sort;
98
98
  const filterKey = direction === "ASC" ? (sort === lastSort ? `${key}>` : `${key}>=`) : sort === lastSort ? `${key}<` : `${key}<=`;
99
- yield new FilterConstraint(filterKey, getObjectProp(item, key));
99
+ yield new FilterConstraint(filterKey, getProp(item, key));
100
100
  }
101
101
  }
102
102
  function* _getBeforeFilters(sorts, item) {
@@ -105,6 +105,6 @@ function* _getBeforeFilters(sorts, item) {
105
105
  for (const sort of sorts) {
106
106
  const { key, direction } = sort;
107
107
  const filterKey = direction === "ASC" ? (sort === lastSort ? `${key}<` : `${key}<=`) : sort === lastSort ? `${key}>` : `${key}>=`;
108
- yield new FilterConstraint(filterKey, getObjectProp(item, key));
108
+ yield new FilterConstraint(filterKey, getProp(item, key));
109
109
  }
110
110
  }
@@ -1,4 +1,4 @@
1
- import { ImmutableObject } from "../util/object.js";
1
+ import type { ImmutableDictionary } from "../util/dictionary.js";
2
2
  /**
3
3
  * The `Feedback` class represents a feedback message that should be shown to the user.
4
4
  * - Basic `Feedback` is neither good nor bad, `SuccessFeedback` indicates good news, and `ErrorFeedback` indicates bad news.
@@ -24,4 +24,4 @@ export declare const isFeedback: <T extends Feedback<unknown>>(v: unknown) => v
24
24
  * Get an object of sub-messages in `{ key: message }` format from a feedback's value.
25
25
  * - Takes the `.value` property from a `Feedback` instance and looks for keyed `Feedback` instances in either `{ key: Feedback }`. `Feedback[]`, or `Map<key, Feedback>` formats.
26
26
  */
27
- export declare const getFeedbackMessages: ({ value }: Feedback) => ImmutableObject<string>;
27
+ export declare const getFeedbackMessages: ({ value }: Feedback) => ImmutableDictionary<string>;
@@ -4,9 +4,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { isObject } from "../util/object.js";
8
7
  import { getEntries } from "../util/entry.js";
9
8
  import { setPrototype } from "../util/class.js";
9
+ import { isObject } from "../util/object.js";
10
+ import { getString } from "../util/string.js";
10
11
  /**
11
12
  * The `Feedback` class represents a feedback message that should be shown to the user.
12
13
  * - Basic `Feedback` is neither good nor bad, `SuccessFeedback` indicates good news, and `ErrorFeedback` indicates bad news.
@@ -38,5 +39,5 @@ function* _yieldFeedbackMessages(value) {
38
39
  if (isObject(value))
39
40
  for (const [k, v] of getEntries(value))
40
41
  if (isFeedback(v))
41
- yield [k, v.message];
42
+ yield [getString(k), v.message];
42
43
  }
@@ -1,6 +1,6 @@
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
2
  import { LazyDeferredSequence } from "../../sequence/LazyDeferredSequence.js";
3
- import { ArrayUpdate, DataUpdate, Increment, ObjectUpdate, Delete, Update } from "../../update/index.js";
3
+ import { ArrayUpdate, DataUpdate, Increment, DictionaryUpdate, Delete, Update } from "../../update/index.js";
4
4
  // Constants.
5
5
  // const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
6
6
  const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
@@ -47,7 +47,7 @@ function _getItemValue(snapshot) {
47
47
  /** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
48
48
  function* _getFieldValues(updates, prefix = "") {
49
49
  for (const [key, update] of updates) {
50
- if (update instanceof DataUpdate || update instanceof ObjectUpdate) {
50
+ if (update instanceof DataUpdate || update instanceof DictionaryUpdate) {
51
51
  yield* _getFieldValues(update, `${prefix}${key}.`);
52
52
  }
53
53
  else if (update instanceof ArrayUpdate) {
@@ -1,6 +1,6 @@
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, setDoc, addDoc, updateDoc, deleteDoc, getDoc, getDocs, } from "firebase/firestore/lite";
2
2
  import { UnsupportedError } from "../../error/UnsupportedError.js";
3
- import { ArrayUpdate, DataUpdate, Increment, ObjectUpdate, Delete, Update } from "../../update/index.js";
3
+ import { ArrayUpdate, DataUpdate, Increment, DictionaryUpdate, Delete, Update } from "../../update/index.js";
4
4
  // Constants.
5
5
  // const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
6
6
  const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
@@ -47,7 +47,7 @@ function _getItemValue(snapshot) {
47
47
  /** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
48
48
  function* _getFieldValues(updates, prefix = "") {
49
49
  for (const [key, update] of updates) {
50
- if (update instanceof DataUpdate || update instanceof ObjectUpdate) {
50
+ if (update instanceof DataUpdate || update instanceof DictionaryUpdate) {
51
51
  yield* _getFieldValues(update, `${prefix}${key}.`);
52
52
  }
53
53
  else if (update instanceof ArrayUpdate) {
@@ -1,6 +1,6 @@
1
1
  import { Firestore, FieldValue as FirestoreFieldValue } from "@google-cloud/firestore";
2
2
  import { LazyDeferredSequence } from "../../sequence/LazyDeferredSequence.js";
3
- import { ArrayUpdate, DataUpdate, Increment, ObjectUpdate, Delete, Update } from "../../update/index.js";
3
+ import { ArrayUpdate, DataUpdate, Increment, DictionaryUpdate, Delete, Update } from "../../update/index.js";
4
4
  // Constants.
5
5
  // const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
6
6
  const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
@@ -47,7 +47,7 @@ function _getItemValue(snapshot) {
47
47
  /** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
48
48
  function* _getFieldValues(updates, prefix = "") {
49
49
  for (const [key, update] of updates) {
50
- if (update instanceof DataUpdate || update instanceof ObjectUpdate) {
50
+ if (update instanceof DataUpdate || update instanceof DictionaryUpdate) {
51
51
  yield* _getFieldValues(update, `${prefix}${key}.`);
52
52
  }
53
53
  else if (update instanceof ArrayUpdate) {
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.82.1",
14
+ "version": "1.83.0",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
@@ -1,6 +1,6 @@
1
1
  import type { Data, Datas, DataKey } from "../util/data.js";
2
2
  import type { ItemArray, ItemValue, ItemData, ItemConstraints } from "../db/Item.js";
3
- import type { Updates } from "../update/DataUpdate.js";
3
+ import { Updates } from "../update/DataUpdate.js";
4
4
  import { DeferredSequence } from "../sequence/DeferredSequence.js";
5
5
  import type { Provider } from "./Provider.js";
6
6
  /**
@@ -1,9 +1,9 @@
1
+ import { updateData } from "../update/DataUpdate.js";
1
2
  import { QueryConstraints } from "../constraint/QueryConstraints.js";
2
3
  import { getRandomKey } from "../util/random.js";
3
4
  import { isArrayEqual } from "../util/equal.js";
4
5
  import { RequiredError } from "../error/RequiredError.js";
5
6
  import { getArray } from "../util/array.js";
6
- import { transformData } from "../util/transform.js";
7
7
  import { DeferredSequence } from "../sequence/DeferredSequence.js";
8
8
  /**
9
9
  * Fast in-memory store for data.
@@ -135,7 +135,7 @@ export class MemoryTable {
135
135
  const item = this._data.get(id);
136
136
  if (!item)
137
137
  throw new RequiredError(`Document "${id}" does not exist`);
138
- this._data.set(id, { ...transformData(item, updates), id });
138
+ this._data.set(id, { ...updateData(item, updates), id });
139
139
  this._times.set(id, Date.now());
140
140
  this._changed.resolve();
141
141
  }
@@ -231,7 +231,7 @@ export class MemoryTable {
231
231
  let count = 0;
232
232
  for (const item of _getWriteConstraints(constraints).transform(this._data.values())) {
233
233
  const id = item.id;
234
- this._data.set(id, { ...transformData(item, updates), id });
234
+ this._data.set(id, { ...updateData(item, updates), id });
235
235
  this._times.set(id, now);
236
236
  count++;
237
237
  }
@@ -103,9 +103,9 @@ function _validateItem(collection, unsafeEntity, schema) {
103
103
  }
104
104
  /** Validate a set of entities for this query reference. */
105
105
  function _validateItems(collection, unsafeEntities, schema) {
106
- return Array.from(_yieldItems(collection, unsafeEntities, schema));
106
+ return Array.from(_yieldValidItems(collection, unsafeEntities, schema));
107
107
  }
108
- function* _yieldItems(collection, unsafeEntities, schema) {
108
+ function* _yieldValidItems(collection, unsafeEntities, schema) {
109
109
  let invalid = false;
110
110
  const details = {};
111
111
  for (const unsafeEntity of unsafeEntities) {
@@ -1,28 +1,29 @@
1
- import { Schema } from "./Schema.js";
2
- /** Specify a specific list of allowed values. */
3
- export declare type Allowed<T extends string | number> = ReadonlyArray<T> | {
4
- readonly [K in T]: unknown;
1
+ import type { Entry } from "../util/entry.js";
2
+ import { ImmutableRequiredMap, PossibleMap, PossibleStringMap } from "../util/map.js";
3
+ import { Schema, SchemaOptions } from "./Schema.js";
4
+ /** Options for an `AllowSchema` instance. */
5
+ declare type AllowSchemaOptions<K, T> = SchemaOptions & {
6
+ allow: PossibleMap<K, T>;
7
+ value?: K | null;
5
8
  };
6
- /** Validate a value against a specific set of allowed values. */
7
- export declare function validateAllowed<T extends string | number>(value: unknown, allowed: Allowed<T>): T;
8
9
  /** Define a valid value from an allowed set of values. */
9
- export declare abstract class AllowSchema<T extends string | number> extends Schema<T> {
10
- readonly value: T | null;
11
- readonly allow: Allowed<T>;
12
- constructor({ allow, value, ...options }: ConstructorParameters<typeof Schema>[0] & {
13
- allow: Allowed<T>;
14
- value?: T | null;
15
- });
16
- }
17
- /** Define a valid string from an allowed set of strings. */
18
- export declare class AllowStringSchema<T extends string> extends AllowSchema<T> {
19
- validate(unsafeValue?: unknown): T;
10
+ export declare class AllowSchema<K, T> extends Schema<K> implements Iterable<Entry<K, T>> {
11
+ readonly value: K | null;
12
+ readonly allow: ImmutableRequiredMap<K, T>;
13
+ constructor({ allow, value, ...options }: AllowSchemaOptions<K, T>);
14
+ validate(value?: unknown): K;
15
+ /** Iterate over the the allowed options in `[key, value]` format. */
16
+ [Symbol.iterator](): Iterator<Entry<K, T>>;
20
17
  }
21
- /** Define a valid number from an allowed set of numbers. */
22
- export declare class AllowNumberSchema<T extends number> extends AllowSchema<T> {
23
- validate(unsafeValue?: unknown): T;
18
+ /** Define a valid string value from an allowed set of values. */
19
+ export declare class AllowStringSchema<K extends string, T> extends AllowSchema<K, T> {
20
+ constructor({ allow, ...options }: SchemaOptions & {
21
+ allow: PossibleStringMap<K, T>;
22
+ });
23
+ validator(value?: unknown): K;
24
24
  }
25
- /** Valid string from an allowed set of strings. */
26
- export declare const ALLOW_STRING: <T extends string>(allow: Allowed<T>) => AllowStringSchema<T>;
27
- /** Valid string from an allowed set of numbers. */
28
- export declare const ALLOW_NUMBER: <T extends number>(allow: Allowed<T>) => AllowNumberSchema<T>;
25
+ /** Valid value from an allowed set of values. */
26
+ export declare function ALLOW<K, T>(allow: PossibleMap<K, T>): AllowSchema<K, T>;
27
+ /** Valid string from an allowed set of values. */
28
+ export declare function ALLOW_STRING<K extends string, T>(allow: PossibleStringMap<K, T>): AllowSchema<K, T>;
29
+ export {};
@@ -1,42 +1,38 @@
1
- import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
2
1
  import { getString } from "../util/string.js";
3
- import { isArray, isArrayItem } from "../util/array.js";
4
- import { getOptionalNumber } from "../util/number.js";
5
- import { isObjectKey } from "../util/object.js";
2
+ import { getRequiredMap, isMapKey } from "../util/map.js";
3
+ import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
6
4
  import { Schema } from "./Schema.js";
7
- /** Validate a value against a specific set of allowed values. */
8
- export function validateAllowed(value, allowed) {
9
- if (isArray(allowed)) {
10
- if (isArrayItem(allowed, value))
11
- return value;
12
- }
13
- else {
14
- if (isObjectKey(allowed, value))
15
- return value;
16
- }
17
- throw new InvalidFeedback("Unknown value", { value });
18
- }
19
5
  /** Define a valid value from an allowed set of values. */
20
6
  export class AllowSchema extends Schema {
21
7
  constructor({ allow, value = null, ...options }) {
22
8
  super(options);
23
- this.allow = allow;
9
+ this.allow = getRequiredMap(allow);
24
10
  this.value = value;
25
11
  }
12
+ validate(value = this.value) {
13
+ if (isMapKey(this.allow, value))
14
+ return value;
15
+ throw new InvalidFeedback("Unknown value", { value });
16
+ }
17
+ /** Iterate over the the allowed options in `[key, value]` format. */
18
+ [Symbol.iterator]() {
19
+ return this.allow[Symbol.iterator]();
20
+ }
26
21
  }
27
- /** Define a valid string from an allowed set of strings. */
22
+ /** Define a valid string value from an allowed set of values. */
28
23
  export class AllowStringSchema extends AllowSchema {
29
- validate(unsafeValue = this.value) {
30
- return validateAllowed(getString(unsafeValue), this.allow);
24
+ constructor({ allow, ...options }) {
25
+ super({ allow: getRequiredMap(allow), ...options });
31
26
  }
32
- }
33
- /** Define a valid number from an allowed set of numbers. */
34
- export class AllowNumberSchema extends AllowSchema {
35
- validate(unsafeValue = this.value) {
36
- return validateAllowed(getOptionalNumber(unsafeValue), this.allow);
27
+ validator(value = this.value) {
28
+ return super.validate(getString(value));
37
29
  }
38
30
  }
39
- /** Valid string from an allowed set of strings. */
40
- export const ALLOW_STRING = (allow) => new AllowStringSchema({ allow });
41
- /** Valid string from an allowed set of numbers. */
42
- export const ALLOW_NUMBER = (allow) => new AllowNumberSchema({ allow });
31
+ /** Valid value from an allowed set of values. */
32
+ export function ALLOW(allow) {
33
+ return new AllowSchema({ allow });
34
+ }
35
+ /** Valid string from an allowed set of values. */
36
+ export function ALLOW_STRING(allow) {
37
+ return new AllowStringSchema({ allow });
38
+ }
@@ -1,6 +1,6 @@
1
1
  import { ImmutableArray } from "../util/array.js";
2
2
  import { Validator } from "../util/validate.js";
3
- import { Schema } from "./Schema.js";
3
+ import { Schema, SchemaOptions } from "./Schema.js";
4
4
  /**
5
5
  * Define a valid array.
6
6
  *
@@ -34,7 +34,7 @@ export declare class ArraySchema<T> extends Schema<ImmutableArray<T>> {
34
34
  readonly unique: boolean;
35
35
  readonly min: number;
36
36
  readonly max: number | null;
37
- constructor({ value, items, unique, min, max, ...options }: ConstructorParameters<typeof Schema>[0] & {
37
+ constructor({ value, items, unique, min, max, ...options }: SchemaOptions & {
38
38
  readonly value?: ImmutableArray;
39
39
  readonly items: Validator<T>;
40
40
  readonly min?: number;
@@ -1,8 +1,8 @@
1
- import { Schema } from "./Schema.js";
1
+ import { Schema, SchemaOptions } from "./Schema.js";
2
2
  /** Define a valid boolean. */
3
3
  export declare class BooleanSchema extends Schema<boolean> {
4
4
  readonly value: boolean;
5
- constructor({ value, ...options }: ConstructorParameters<typeof Schema>[0] & {
5
+ constructor({ value, ...options }: SchemaOptions & {
6
6
  readonly value?: boolean;
7
7
  });
8
8
  validate(unsafeValue?: unknown): boolean;
@@ -1,12 +1,12 @@
1
1
  import type { Data, Datas } from "../util/data.js";
2
2
  import { Validators } from "../util/validate.js";
3
3
  import { OptionalSchema } from "./OptionalSchema.js";
4
- import { Schema } from "./Schema.js";
4
+ import { Schema, SchemaOptions } from "./Schema.js";
5
5
  /** Validate a data object. */
6
6
  export declare class DataSchema<T extends Data> extends Schema<T> {
7
7
  readonly value: Partial<T>;
8
8
  readonly props: Validators<T>;
9
- constructor({ value, props, ...options }: ConstructorParameters<typeof Schema>[0] & {
9
+ constructor({ value, props, ...options }: SchemaOptions & {
10
10
  readonly props: Validators<T>;
11
11
  readonly value?: Partial<T>;
12
12
  });
@@ -1,6 +1,6 @@
1
1
  import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
2
2
  import { validateData } from "../util/validate.js";
3
- import { isObject } from "../util/object.js";
3
+ import { isData } from "../util/data.js";
4
4
  import { OPTIONAL } from "./OptionalSchema.js";
5
5
  import { Schema } from "./Schema.js";
6
6
  /** Validate a data object. */
@@ -11,7 +11,7 @@ export class DataSchema extends Schema {
11
11
  this.value = value;
12
12
  }
13
13
  validate(unsafeValue = this.value) {
14
- if (!isObject(unsafeValue))
14
+ if (!isData(unsafeValue))
15
15
  throw new InvalidFeedback("Must be object", { value: unsafeValue });
16
16
  return validateData(unsafeValue, this.props);
17
17
  }
@@ -1,11 +1,11 @@
1
1
  import { PossibleDate } from "../util/date.js";
2
- import { Schema } from "./Schema.js";
2
+ import { Schema, SchemaOptions } from "./Schema.js";
3
3
  /** Define a valid date, e.g. `2005-09-12` */
4
4
  export declare class DateSchema extends Schema<string> {
5
5
  readonly value: PossibleDate;
6
6
  readonly min: PossibleDate | null;
7
7
  readonly max: PossibleDate | null;
8
- constructor({ value, min, max, ...options }: ConstructorParameters<typeof Schema>[0] & {
8
+ constructor({ value, min, max, ...options }: SchemaOptions & {
9
9
  readonly value?: PossibleDate;
10
10
  readonly min?: PossibleDate | null;
11
11
  readonly max?: PossibleDate | null;
@@ -0,0 +1,19 @@
1
+ import { ImmutableDictionary } from "../util/dictionary.js";
2
+ import { Validator } from "../util/validate.js";
3
+ import { Schema, SchemaOptions } from "./Schema.js";
4
+ /** Validate a dictionary object (whose props are all the same with string keys). */
5
+ export declare class DictionarySchema<T> extends Schema<ImmutableDictionary<T>> {
6
+ readonly value: ImmutableDictionary;
7
+ readonly items: Validator<T>;
8
+ readonly min: number | null;
9
+ readonly max: number | null;
10
+ constructor({ value, items, min, max, ...rest }: SchemaOptions & {
11
+ readonly items: Validator<T>;
12
+ readonly value?: ImmutableDictionary;
13
+ readonly min?: number | null;
14
+ readonly max?: number | null;
15
+ });
16
+ validate(unsafeValue?: unknown): ImmutableDictionary<T>;
17
+ }
18
+ /** Valid dictionary object with specifed items. */
19
+ export declare const DICTIONARY: <T>(items: Validator<T>) => DictionarySchema<T>;
@@ -1,9 +1,9 @@
1
- import { isObject } from "../util/object.js";
1
+ import { isDictionary } from "../util/dictionary.js";
2
2
  import { validateEntries } from "../util/validate.js";
3
3
  import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
4
4
  import { Schema } from "./Schema.js";
5
- /** Validate a map-like object (whose props are all the same). */
6
- export class ObjectSchema extends Schema {
5
+ /** Validate a dictionary object (whose props are all the same with string keys). */
6
+ export class DictionarySchema extends Schema {
7
7
  constructor({ value = {}, items, min = null, max = null, ...rest }) {
8
8
  super(rest);
9
9
  this.min = null;
@@ -14,7 +14,7 @@ export class ObjectSchema extends Schema {
14
14
  this.max = max;
15
15
  }
16
16
  validate(unsafeValue = this.value) {
17
- if (!isObject(unsafeValue))
17
+ if (!isDictionary(unsafeValue))
18
18
  throw new InvalidFeedback("Must be object", { value: unsafeValue });
19
19
  const unsafeEntries = Object.entries(unsafeValue);
20
20
  const safeObject = Object.fromEntries(validateEntries(unsafeEntries, this.items));
@@ -25,5 +25,5 @@ export class ObjectSchema extends Schema {
25
25
  return safeObject;
26
26
  }
27
27
  }
28
- /** Valid map-like object with specifed items. */
29
- export const OBJECT = (items) => new ObjectSchema({ items });
28
+ /** Valid dictionary object with specifed items. */
29
+ export const DICTIONARY = (items) => new DictionarySchema({ items });
@@ -1,4 +1,4 @@
1
- import { StringSchema } from "./StringSchema.js";
1
+ import { StringSchema, StringSchemaOptions } from "./StringSchema.js";
2
2
  /**
3
3
  * Type of `StringSchema` that defines a valid URL.
4
4
  * - Checks URL scheme against a whitelist (always), and checks URL domain against a whitelist (optional).
@@ -11,7 +11,7 @@ export declare class LinkSchema extends StringSchema {
11
11
  readonly max = 512;
12
12
  readonly schemes: string[];
13
13
  readonly hosts: string[] | null;
14
- constructor({ schemes, hosts, ...rest }: ConstructorParameters<typeof StringSchema>[0] & {
14
+ constructor({ schemes, hosts, ...rest }: StringSchemaOptions & {
15
15
  readonly schemes?: string[];
16
16
  readonly hosts?: string[] | null;
17
17
  });
@@ -1,11 +1,11 @@
1
- import { Schema } from "./Schema.js";
1
+ import { Schema, SchemaOptions } from "./Schema.js";
2
2
  /** Schema that defines a valid number. */
3
3
  export declare class NumberSchema extends Schema<number> {
4
4
  readonly value: number | null;
5
5
  readonly min: number | null;
6
6
  readonly max: number | null;
7
7
  readonly step: number | null;
8
- constructor({ value, min, max, step, ...rest }: ConstructorParameters<typeof Schema>[0] & {
8
+ constructor({ value, min, max, step, ...rest }: SchemaOptions & {
9
9
  readonly value?: number | null;
10
10
  readonly min?: number | null;
11
11
  readonly max?: number | null;
@@ -1,4 +1,13 @@
1
1
  import type { Validatable } from "../util/validate.js";
2
+ /** Options allowed by a `Schema` instance. */
3
+ export declare type SchemaOptions = {
4
+ /** Title of the schema, e.g. for using as the title of a corresponding field. */
5
+ readonly title?: string;
6
+ /** Description of the schema, e.g. for using as a description in a corresponding field. */
7
+ readonly description?: string;
8
+ /** Placeholder of the schema, e.g. for using as a placeholder in a corresponding field. */
9
+ readonly placeholder?: string;
10
+ };
2
11
  /**
3
12
  * Schema is an object instance with a `validate()` method.
4
13
  * - Type `T` represents the type of value `validate()` returns.
@@ -13,14 +22,7 @@ export declare abstract class Schema<T extends unknown = unknown> implements Val
13
22
  readonly placeholder: string;
14
23
  /** Default value. */
15
24
  readonly value: unknown;
16
- constructor({ title, description, placeholder, }: {
17
- /** Title of the schema, e.g. for using as the title of a corresponding field. */
18
- readonly title?: string;
19
- /** Description of the schema, e.g. for using as a description in a corresponding field. */
20
- readonly description?: string;
21
- /** Placeholder of the schema, e.g. for using as a placeholder in a corresponding field. */
22
- readonly placeholder?: string;
23
- });
25
+ constructor({ title, description, placeholder }: SchemaOptions);
24
26
  /** Every schema must implement a `validate()` method. */
25
27
  abstract validate(unsafeValue: unknown): T;
26
28
  }
package/schema/Schema.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * - `validate()` returns `Invalid` if value was not valid.
5
5
  */
6
6
  export class Schema {
7
- constructor({ title = "", description = "", placeholder = "", }) {
7
+ constructor({ title = "", description = "", placeholder = "" }) {
8
8
  this.title = title;
9
9
  this.description = description;
10
10
  this.placeholder = placeholder;
@@ -1,8 +1,18 @@
1
- import { Schema } from "./Schema.js";
1
+ import { Schema, SchemaOptions } from "./Schema.js";
2
2
  /** `type=""` prop for HTML `<input />` tags that are relevant for strings. */
3
3
  export declare type HtmlInputType = "text" | "password" | "color" | "date" | "email" | "number" | "tel" | "search" | "url";
4
4
  /** Function that sanitizes a string. */
5
5
  export declare type Sanitizer = (str: string) => string;
6
+ /** Options for `StringSchema` */
7
+ export declare type StringSchemaOptions = SchemaOptions & {
8
+ readonly value?: string;
9
+ readonly type?: HtmlInputType;
10
+ readonly min?: number;
11
+ readonly max?: number | null;
12
+ readonly match?: RegExp | null;
13
+ readonly sanitizer?: Sanitizer | null;
14
+ readonly multiline?: boolean;
15
+ };
6
16
  /**
7
17
  * Schema that defines a valid string.
8
18
  *
@@ -31,15 +41,7 @@ export declare class StringSchema extends Schema<string> {
31
41
  readonly match: RegExp | null;
32
42
  readonly sanitizer: Sanitizer | null;
33
43
  readonly multiline: boolean;
34
- constructor({ value, type, min, max, match, sanitizer, multiline, ...rest }: ConstructorParameters<typeof Schema>[0] & {
35
- readonly value?: string;
36
- readonly type?: HtmlInputType;
37
- readonly min?: number;
38
- readonly max?: number | null;
39
- readonly match?: RegExp | null;
40
- readonly sanitizer?: Sanitizer | null;
41
- readonly multiline?: boolean;
42
- });
44
+ constructor({ value, type, min, max, match, sanitizer, multiline, ...rest }: StringSchemaOptions);
43
45
  validate(unsafeValue?: unknown): string;
44
46
  /**
45
47
  * Clean a string by removing characters that aren't digits.
package/schema/index.d.ts CHANGED
@@ -5,11 +5,11 @@ export * from "./BooleanSchema.js";
5
5
  export * from "./ColorSchema.js";
6
6
  export * from "./DataSchema.js";
7
7
  export * from "./DateSchema.js";
8
+ export * from "./DictionarySchema.js";
8
9
  export * from "./EmailSchema.js";
9
10
  export * from "./KeySchema.js";
10
11
  export * from "./LinkSchema.js";
11
12
  export * from "./NumberSchema.js";
12
- export * from "./ObjectSchema.js";
13
13
  export * from "./OptionalSchema.js";
14
14
  export * from "./PhoneSchema.js";
15
15
  export * from "./RequiredSchema.js";
package/schema/index.js CHANGED
@@ -5,11 +5,11 @@ export * from "./BooleanSchema.js";
5
5
  export * from "./ColorSchema.js";
6
6
  export * from "./DataSchema.js";
7
7
  export * from "./DateSchema.js";
8
+ export * from "./DictionarySchema.js";
8
9
  export * from "./EmailSchema.js";
9
10
  export * from "./KeySchema.js";
10
11
  export * from "./LinkSchema.js";
11
12
  export * from "./NumberSchema.js";
12
- export * from "./ObjectSchema.js";
13
13
  export * from "./OptionalSchema.js";
14
14
  export * from "./PhoneSchema.js";
15
15
  export * from "./RequiredSchema.js";
@@ -1,5 +1,5 @@
1
1
  import { getData } from "../util/data.js";
2
- import { transformData } from "../util/transform.js";
2
+ import { transformObject } from "../util/transform.js";
3
3
  import { State } from "./State.js";
4
4
  /** State that stores a data object and has additional methods to help with that. */
5
5
  export class DataState extends State {
@@ -9,7 +9,7 @@ export class DataState extends State {
9
9
  }
10
10
  /** Update several props in this data. */
11
11
  update(updates) {
12
- this.set(transformData(this.data, updates));
12
+ this.set(transformObject(this.data, updates));
13
13
  }
14
14
  }
15
15
  /** State that stores an optional data object and has additional methods to help with that. */
@@ -24,7 +24,7 @@ export class OptionalDataState extends State {
24
24
  }
25
25
  /** Update several props in this data. */
26
26
  update(updates) {
27
- this.set(transformData(this.data, updates));
27
+ this.set(transformObject(this.data, updates));
28
28
  }
29
29
  /** Set the data to `null`. */
30
30
  unset() {
@@ -0,0 +1,15 @@
1
+ import { DictionaryItem, ImmutableDictionary } from "../util/dictionary.js";
2
+ import { Transformers } from "../util/transform.js";
3
+ import { State } from "./State.js";
4
+ /** State that stores a dictionary object and has additional methods to help with that. */
5
+ export declare class DictionaryState<T> extends State<ImmutableDictionary<T>> implements Iterable<DictionaryItem<T>> {
6
+ constructor(initial?: ImmutableDictionary<T>);
7
+ /** Get the length of the current value of this state. */
8
+ get count(): number;
9
+ /** Set a named entry in this object with a different value. */
10
+ update(updates: Transformers<ImmutableDictionary<T>>): void;
11
+ /** Remove a named entry from this object. */
12
+ delete(...keys: string[]): void;
13
+ /** Iterate over the entries of the object. */
14
+ [Symbol.iterator](): Iterator<DictionaryItem<T>>;
15
+ }
@@ -1,8 +1,8 @@
1
- import { withoutObjectProps } from "../util/object.js";
2
- import { transformData } from "../util/transform.js";
1
+ import { withoutDictionaryItems } from "../util/dictionary.js";
2
+ import { transformDictionary } from "../util/transform.js";
3
3
  import { State } from "./State.js";
4
- /** State that stores a map-like object and has additional methods to help with that. */
5
- export class ObjectState extends State {
4
+ /** State that stores a dictionary object and has additional methods to help with that. */
5
+ export class DictionaryState extends State {
6
6
  constructor(initial = {}) {
7
7
  super(initial);
8
8
  }
@@ -12,11 +12,11 @@ export class ObjectState extends State {
12
12
  }
13
13
  /** Set a named entry in this object with a different value. */
14
14
  update(updates) {
15
- this.set(transformData(this.value, updates));
15
+ this.set(transformDictionary(this.value, updates));
16
16
  }
17
17
  /** Remove a named entry from this object. */
18
18
  delete(...keys) {
19
- this.set(withoutObjectProps(this.value, ...keys));
19
+ this.set(withoutDictionaryItems(this.value, ...keys));
20
20
  }
21
21
  /** Iterate over the entries of the object. */
22
22
  [Symbol.iterator]() {