shelving 1.150.4 → 1.150.6

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/db/Change.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { ImmutableArray } from "../util/array.js";
2
2
  import type { DataKey, Database } from "../util/data.js";
3
3
  import type { ItemQuery } from "../util/item.js";
4
- import { type Optional } from "../util/optional.js";
4
+ import { type Nullish } from "../util/null.js";
5
5
  import type { Updates } from "../util/update.js";
6
6
  import type { AsyncProvider, Provider } from "./Provider.js";
7
7
  /** A change to a database. */
@@ -68,8 +68,8 @@ export type DatabaseChanges<T extends Database> = ImmutableArray<DatabaseChange<
68
68
  /** Write a single change to a synchronous provider and return an array of the changes that were written. */
69
69
  export declare function writeChange<T extends Database>(provider: Provider<T>, change: DatabaseChange<T>): DatabaseChange<T>;
70
70
  /** Write a set of changes to a synchronous provider. */
71
- export declare function writeChanges<T extends Database>(provider: Provider<T>, ...changes: Optional<DatabaseChange<T>>[]): DatabaseChanges<T>;
71
+ export declare function writeChanges<T extends Database>(provider: Provider<T>, ...changes: Nullish<DatabaseChange<T>>[]): DatabaseChanges<T>;
72
72
  /** Write a single change to an asynchronous provider and return the change that was written. */
73
73
  export declare function writeAsyncChange<T extends Database>(provider: AsyncProvider<T>, change: DatabaseChange<T>): Promise<DatabaseChange<T>>;
74
74
  /** Write a set of changes to an asynchronous provider. */
75
- export declare function writeAsyncChanges<T extends Database>(provider: AsyncProvider<T>, ...changes: Optional<DatabaseChange<T>>[]): Promise<DatabaseChanges<T>>;
75
+ export declare function writeAsyncChanges<T extends Database>(provider: AsyncProvider<T>, ...changes: Nullish<DatabaseChange<T>>[]): Promise<DatabaseChanges<T>>;
package/db/Change.js CHANGED
@@ -1,4 +1,4 @@
1
- import { notOptional } from "../util/optional.js";
1
+ import { notNullish } from "../util/null.js";
2
2
  /** Write a single change to a synchronous provider and return an array of the changes that were written. */
3
3
  export function writeChange(provider, change) {
4
4
  const { action, collection, id, query } = change;
@@ -26,7 +26,7 @@ export function writeChange(provider, change) {
26
26
  }
27
27
  /** Write a set of changes to a synchronous provider. */
28
28
  export function writeChanges(provider, ...changes) {
29
- return changes.filter(notOptional).map(change => writeChange(provider, change));
29
+ return changes.filter(notNullish).map(change => writeChange(provider, change));
30
30
  }
31
31
  /** Write a single change to an asynchronous provider and return the change that was written. */
32
32
  export async function writeAsyncChange(provider, change) {
@@ -55,5 +55,5 @@ export async function writeAsyncChange(provider, change) {
55
55
  }
56
56
  /** Write a set of changes to an asynchronous provider. */
57
57
  export function writeAsyncChanges(provider, ...changes) {
58
- return Promise.all(changes.filter(notOptional).map(change => writeAsyncChange(provider, change)));
58
+ return Promise.all(changes.filter(notNullish).map(change => writeAsyncChange(provider, change)));
59
59
  }
@@ -1,2 +1 @@
1
1
  export * from "./Feedback.js";
2
- export * from "./Feedbacks.js";
package/feedback/index.js CHANGED
@@ -1,2 +1 @@
1
1
  export * from "./Feedback.js";
2
- export * from "./Feedbacks.js";
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.150.4",
14
+ "version": "1.150.6",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
@@ -4,14 +4,14 @@ import type { AbstractProvider } from "../db/Provider.js";
4
4
  import { QueryStore } from "../db/QueryStore.js";
5
5
  import type { DataKey, Database } from "../util/data.js";
6
6
  import type { ItemQuery } from "../util/item.js";
7
- import type { Optional } from "../util/optional.js";
7
+ import type { Nullish } from "../util/null.js";
8
8
  export interface DataContext<T extends Database> {
9
9
  /** Get an `ItemStore` for the specified collection item in the current `DataProvider` context and subscribe to any changes in it. */
10
10
  useItem<K extends DataKey<T>>(this: void, collection: K, id: string): ItemStore<T, K>;
11
- useItem<K extends DataKey<T>>(this: void, collection: Optional<K>, id: Optional<string>): ItemStore<T, K> | undefined;
11
+ useItem<K extends DataKey<T>>(this: void, collection: Nullish<K>, id: Nullish<string>): ItemStore<T, K> | undefined;
12
12
  /** Get an `QueryStore` for the specified collection query in the current `DataProvider` context and subscribe to any changes in it. */
13
13
  useQuery<K extends DataKey<T>>(this: void, collection: K, query: ItemQuery<T[K]>): QueryStore<T, K>;
14
- useQuery<K extends DataKey<T>>(this: void, collection: Optional<K>, query: Optional<ItemQuery<T[K]>>): QueryStore<T, K> | undefined;
14
+ useQuery<K extends DataKey<T>>(this: void, collection: Nullish<K>, query: Nullish<ItemQuery<T[K]>>): QueryStore<T, K> | undefined;
15
15
  readonly DataContext: ({ children }: {
16
16
  children: ReactNode;
17
17
  }) => ReactElement;
@@ -1,12 +1,12 @@
1
1
  import type { PossibleDate } from "../util/date.js";
2
- import type { Optional } from "../util/optional.js";
2
+ import type { Nullish } from "../util/null.js";
3
3
  import type { SchemaOptions } from "./Schema.js";
4
4
  import { Schema } from "./Schema.js";
5
5
  /** Allowed options for `DateSchema` */
6
6
  export interface DateSchemaOptions extends SchemaOptions {
7
7
  readonly value?: PossibleDate | undefined;
8
- readonly min?: Optional<PossibleDate> | undefined;
9
- readonly max?: Optional<PossibleDate> | undefined;
8
+ readonly min?: Nullish<PossibleDate>;
9
+ readonly max?: Nullish<PossibleDate>;
10
10
  }
11
11
  /** Define a valid date in YMD format, e.g. `2005-09-12` */
12
12
  export declare class DateSchema extends Schema<string> {
@@ -1,4 +1,4 @@
1
- import type { Optional } from "../util/optional.js";
1
+ import type { Nullish } from "../util/null.js";
2
2
  import type { PossibleTime } from "../util/time.js";
3
3
  import { Time } from "../util/time.js";
4
4
  import type { SchemaOptions } from "./Schema.js";
@@ -6,8 +6,8 @@ import { Schema } from "./Schema.js";
6
6
  /** Allowed options for `TimeSchama` */
7
7
  export interface TimeSchemaOptions extends SchemaOptions {
8
8
  readonly value?: PossibleTime | undefined;
9
- readonly min?: Optional<PossibleTime> | undefined;
10
- readonly max?: Optional<PossibleTime> | undefined;
9
+ readonly min?: Nullish<PossibleTime>;
10
+ readonly max?: Nullish<PossibleTime>;
11
11
  readonly step?: number | undefined;
12
12
  }
13
13
  /** Define a valid time in 24h hh:mm:ss.fff format, e.g. `23:59` or `24:00 */
@@ -1,4 +1,5 @@
1
1
  import type { Data, DataKey } from "../util/data.js";
2
+ import type { AnyCaller } from "../util/function.js";
2
3
  import type { Updates } from "../util/update.js";
3
4
  import { Store } from "./Store.js";
4
5
  /** Store a data object. */
@@ -22,6 +23,8 @@ export declare class OptionalDataStore<T extends Data> extends Store<T | undefin
22
23
  set data(data: T);
23
24
  /** Does the data exist or not? */
24
25
  get exists(): boolean;
26
+ /** Return the data for this data store, or throw `RequiredError` if it is not set. */
27
+ requireData(caller?: AnyCaller): T;
25
28
  /** Update several props in this data. */
26
29
  update(updates: Updates<T>): void;
27
30
  /** Update a single named prop in this data. */
@@ -1,5 +1,6 @@
1
+ import { RequiredError } from "../error/RequiredError.js";
2
+ import { getGetter } from "../util/class.js";
1
3
  import { withProp } from "../util/object.js";
2
- import { getRequired } from "../util/optional.js";
3
4
  import { updateData } from "../util/update.js";
4
5
  import { Store } from "./Store.js";
5
6
  /** Store a data object. */
@@ -29,7 +30,7 @@ export class DataStore extends Store {
29
30
  export class OptionalDataStore extends Store {
30
31
  /** Get current data value of this store (or throw `Promise` that resolves to the next required value). */
31
32
  get data() {
32
- return getRequired(this.value);
33
+ return this.requireData(getGetter(this, "data"));
33
34
  }
34
35
  /** Set the data of this store. */
35
36
  set data(data) {
@@ -39,17 +40,24 @@ export class OptionalDataStore extends Store {
39
40
  get exists() {
40
41
  return !!this.value;
41
42
  }
43
+ /** Return the data for this data store, or throw `RequiredError` if it is not set. */
44
+ requireData(caller = this.requireData) {
45
+ const data = this.value;
46
+ if (!data)
47
+ throw new RequiredError("Data is empty", { caller });
48
+ return data;
49
+ }
42
50
  /** Update several props in this data. */
43
51
  update(updates) {
44
- this.value = updateData(this.data, updates);
52
+ this.value = updateData(this.requireData(this.update), updates);
45
53
  }
46
54
  /** Update a single named prop in this data. */
47
55
  getProp(name) {
48
- return this.data[name];
56
+ return this.requireData(this.getProp)[name];
49
57
  }
50
58
  /** Update a single named prop in this data. */
51
59
  setProp(name, value) {
52
- this.value = withProp(this.data, name, value);
60
+ this.value = withProp(this.requireData(this.setProp), name, value);
53
61
  }
54
62
  /** Set the data to `undefined`. */
55
63
  unset() {
package/util/entity.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { AnyCaller } from "./function.js";
2
- import type { Optional } from "./optional.js";
2
+ import type { Nullish } from "./null.js";
3
3
  /** Entity strings combine a type and ID, e.g. `challenge:a1b2c3` */
4
4
  export type Entity<T extends string = string> = `${T}:${string}`;
5
5
  /** Extract the type from an `Entity` string. */
@@ -10,8 +10,8 @@ export type EmptyEntity = [type: undefined, id: undefined];
10
10
  export declare const EMPTY_ENTITY: EmptyEntity;
11
11
  /** Split an optional entity tag like `challenge:a1b2c3` into `["challenge", "a1b2c3"]`, or return `EmptyEntity` if the entity was invalid. */
12
12
  export declare function getEntity<T extends string>(entity: Entity<T>): [type: T, id: string];
13
- export declare function getEntity<T extends string>(entity: Optional<Entity<T>>): [type: T, id: string] | EmptyEntity;
14
- export declare function getEntity(entity: Optional<string>): [type: string, id: string] | EmptyEntity;
13
+ export declare function getEntity<T extends string>(entity: Nullish<Entity<T>>): [type: T, id: string] | EmptyEntity;
14
+ export declare function getEntity(entity: Nullish<string>): [type: string, id: string] | EmptyEntity;
15
15
  /** Split an entity tag like `challenge:a1b2c3` into `type` and `id`, or throw `RequiredError` if the entity tag was invalid. */
16
16
  export declare function requireEntity<T extends string>(entity: Entity<T>, caller?: AnyCaller): [type: T, id: string];
17
17
  export declare function requireEntity(entity: string, caller?: AnyCaller): [type: string, id: string];
package/util/error.d.ts CHANGED
@@ -1,6 +1,23 @@
1
+ import type { ImmutableDictionary } from "./dictionary.js";
2
+ import type { AnyCaller } from "./function.js";
1
3
  /** Log an error to the console. */
2
4
  export declare function logError(reason: unknown): void;
3
5
  /** Is an unknown value an `Error` instance? */
4
6
  export declare function isError(v: unknown): v is Error & {
5
7
  readonly code?: string | undefined;
6
8
  };
9
+ /** Things that can be a message. */
10
+ export type PossibleMessage = {
11
+ message: string;
12
+ } | string;
13
+ /** Return the string message from an unknown value, or return `undefined` if it could not be found. */
14
+ export declare function getMessage(input: unknown): string | undefined;
15
+ /** Require a message from an unknown value, or throw `RequiredError` if it could not be found. */
16
+ export declare function requireMessage(input: PossibleMessage, caller?: AnyCaller): string;
17
+ /**
18
+ * Split a string message into lines, look for prefixes like `name:`, and return a dictionary of those named messages.
19
+ * - Full messages strings can have multiple lines separated by `\n` newline.
20
+ * - Named messages are extracted into their own entries in the dictionary.
21
+ * - Unnamed messages are combined into a single entry with the key `""` (empty string).
22
+ */
23
+ export declare function splitMessage(input: PossibleMessage): ImmutableDictionary<string>;
package/util/error.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { RequiredError } from "../error/RequiredError.js";
2
+ import { isObject } from "./object.js";
1
3
  /** Log an error to the console. */
2
4
  export function logError(reason) {
3
5
  console.error(reason);
@@ -6,3 +8,43 @@ export function logError(reason) {
6
8
  export function isError(v) {
7
9
  return typeof Error.isError === "function" ? Error.isError(v) : v instanceof Error;
8
10
  }
11
+ /** Return the string message from an unknown value, or return `undefined` if it could not be found. */
12
+ export function getMessage(input) {
13
+ return typeof input === "string" ? input : isObject(input) && typeof input.message === "string" ? input.message : undefined;
14
+ }
15
+ /** Require a message from an unknown value, or throw `RequiredError` if it could not be found. */
16
+ export function requireMessage(input, caller = requireMessage) {
17
+ const message = getMessage(input);
18
+ if (message === undefined)
19
+ throw new RequiredError("Message is required", { received: input, caller });
20
+ return message;
21
+ }
22
+ /**
23
+ * Split a string message into lines, look for prefixes like `name:`, and return a dictionary of those named messages.
24
+ * - Full messages strings can have multiple lines separated by `\n` newline.
25
+ * - Named messages are extracted into their own entries in the dictionary.
26
+ * - Unnamed messages are combined into a single entry with the key `""` (empty string).
27
+ */
28
+ export function splitMessage(input) {
29
+ const messages = requireMessage(input, splitMessage).split("\n");
30
+ const output = {};
31
+ for (const line of messages) {
32
+ const i = line.indexOf(": ");
33
+ if (i >= 0) {
34
+ const name = line.slice(0, i).trim();
35
+ const message = line.slice(i + 2).trim();
36
+ if (Object.hasOwn(output, name))
37
+ output[name] += `\n${message}`;
38
+ else
39
+ output[name] = message;
40
+ }
41
+ else {
42
+ const message = line.trim();
43
+ if (Object.hasOwn(output, ""))
44
+ output[""] += `\n${message}`;
45
+ else
46
+ output[""] = message;
47
+ }
48
+ }
49
+ return output;
50
+ }
package/util/index.d.ts CHANGED
@@ -39,7 +39,6 @@ export * from "./merge.js";
39
39
  export * from "./null.js";
40
40
  export * from "./number.js";
41
41
  export * from "./object.js";
42
- export * from "./optional.js";
43
42
  export * from "./path.js";
44
43
  export * from "./query.js";
45
44
  export * from "./random.js";
package/util/index.js CHANGED
@@ -39,7 +39,6 @@ export * from "./merge.js";
39
39
  export * from "./null.js";
40
40
  export * from "./number.js";
41
41
  export * from "./object.js";
42
- export * from "./optional.js";
43
42
  export * from "./path.js";
44
43
  export * from "./query.js";
45
44
  export * from "./random.js";
package/util/link.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { ImmutableArray } from "./array.js";
2
2
  import type { AnyCaller } from "./function.js";
3
- import type { Optional } from "./optional.js";
3
+ import type { Nullish } from "./null.js";
4
4
  import type { Path } from "./path.js";
5
5
  import { type PossibleURL } from "./url.js";
6
6
  /**
@@ -53,7 +53,7 @@ export declare function isLinkURL(value: unknown, schemes?: LinkSchemes, hosts?:
53
53
  * Convert a possible URL to a link URL, or return `undefined` if conversion fails.
54
54
  * - A valid link URL is a `URL` instance with a scheme matching the `schemes` array, and `host` matching the optional `hosts` array.
55
55
  */
56
- export declare function getLinkURL(value: Optional<PossibleURL>, base?: AbsoluteLinkURL | AbsoluteLink, schemes?: LinkSchemes, hosts?: LinkHosts): AbsoluteLinkURL | undefined;
56
+ export declare function getLinkURL(value: Nullish<PossibleURL>, base?: AbsoluteLinkURL | AbsoluteLink, schemes?: LinkSchemes, hosts?: LinkHosts): AbsoluteLinkURL | undefined;
57
57
  /**
58
58
  * Convert a possible URL to a link URL, or throw `RequiredError` if conversion fails.
59
59
  * - A valid link URL is a `URL` instance with a scheme matching the `schemes` array, and `host` matching the optional `hosts` array.
@@ -63,7 +63,7 @@ export declare function requireLinkURL(value: PossibleURL, base?: AbsoluteLinkUR
63
63
  * Convert a possible URL to an link URL string, or return `undefined` if conversion fails.
64
64
  * - A valid link URL string is an absolute URL string with a scheme matching the `schemes` array, and `host` matching the optional `hosts` array.
65
65
  */
66
- export declare function getLink(value: Optional<PossibleURL>, base?: AbsoluteLinkURL | AbsoluteLink, schemes?: LinkSchemes, hosts?: LinkHosts): AbsoluteLink | undefined;
66
+ export declare function getLink(value: Nullish<PossibleURL>, base?: AbsoluteLinkURL | AbsoluteLink, schemes?: LinkSchemes, hosts?: LinkHosts): AbsoluteLink | undefined;
67
67
  /**
68
68
  * Convert a possible URL to an link URL string, or throw `RequiredError` if conversion fails.
69
69
  * - A valid link URL string is an absolute URL string with a scheme matching the `schemes` array, and `host` matching the optional `hosts` array.
package/util/path.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { AnyCaller } from "./function.js";
2
- import { type Optional } from "./optional.js";
2
+ import { type Nullish } from "./null.js";
3
3
  /** Absolute path string starts with `/` slash. */
4
4
  export type AbsolutePath = `/` | `/${string}`;
5
5
  /** Relative path string starts with `./` or `../` */
@@ -19,7 +19,7 @@ export declare function isRelativePath(path: string): path is RelativePath;
19
19
  * @param base Absolute path used for resolving relative paths in `possible`
20
20
  * @return Absolute path with a leading trailing slash, e.g. `/a/c/b`
21
21
  */
22
- export declare function getPath(value: Optional<string | URL>, base?: AbsolutePath | undefined): AbsolutePath | undefined;
22
+ export declare function getPath(value: Nullish<string | URL>, base?: AbsolutePath | undefined): AbsolutePath | undefined;
23
23
  /**
24
24
  * Resolve a relative or absolute path and return the path, or throw `RequiredError` if not a valid path.
25
25
  * - Internally uses `new URL` to do path processing but shouldn't ever reveal that fact.
package/util/path.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RequiredError } from "../error/RequiredError.js";
2
- import { notOptional } from "./optional.js";
2
+ import { notNullish } from "./null.js";
3
3
  /** Is a string path an absolute path? */
4
4
  export function isAbsolutePath(path) {
5
5
  return path.startsWith("/");
@@ -23,7 +23,7 @@ function _cleanPath(path) {
23
23
  * @return Absolute path with a leading trailing slash, e.g. `/a/c/b`
24
24
  */
25
25
  export function getPath(value, base = "/") {
26
- if (notOptional(value)) {
26
+ if (notNullish(value)) {
27
27
  try {
28
28
  const { pathname, search, hash } = new URL(value, `http://j.com${base}/`);
29
29
  if (isAbsolutePath(pathname))
package/util/string.d.ts CHANGED
@@ -101,3 +101,7 @@ export declare function splitString(str: string, separator: string, min: 2, max?
101
101
  export declare function splitString(str: string, separator: string, min: 3, max?: number, caller?: AnyCaller): readonly [string, string, string, ...string[]];
102
102
  export declare function splitString(str: string, separator: string, min: 4, max?: number, caller?: AnyCaller): readonly [string, string, string, string, ...string[]];
103
103
  export declare function splitString(str: string, separator: string, min?: number, max?: number, caller?: AnyCaller): ImmutableArray<string>;
104
+ /** Trim a string (as a function, so it can be used in mapping. */
105
+ export declare function trimString(str: string): string;
106
+ /** Does a string have length? */
107
+ export declare function isNonEmptyString(str: string): boolean;
package/util/string.js CHANGED
@@ -167,3 +167,11 @@ export function splitString(str, separator, min = 1, max = Number.POSITIVE_INFIN
167
167
  });
168
168
  return segments;
169
169
  }
170
+ /** Trim a string (as a function, so it can be used in mapping. */
171
+ export function trimString(str) {
172
+ return str.trim();
173
+ }
174
+ /** Does a string have length? */
175
+ export function isNonEmptyString(str) {
176
+ return str.length > 0;
177
+ }
package/util/url.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { AnyCaller } from "./function.js";
2
- import { type Optional } from "./optional.js";
2
+ import { type Nullish } from "./null.js";
3
3
  /** Values that can be converted to a URL instance. */
4
4
  export type PossibleURL = string | URL;
5
5
  /** Is an unknown value a URL object? */
@@ -7,6 +7,6 @@ export declare function isURL(value: unknown): value is URL;
7
7
  /** Assert that an unknown value is a URL object. */
8
8
  export declare function assertURL(value: unknown, caller?: AnyCaller): asserts value is URL;
9
9
  /** Convert a possible URL to a URL, or return `undefined` if conversion fails. */
10
- export declare function getURL(possible: Optional<PossibleURL>, base?: PossibleURL | undefined): URL | undefined;
10
+ export declare function getURL(possible: Nullish<PossibleURL>, base?: PossibleURL | undefined): URL | undefined;
11
11
  /** Convert a possible URL to a URL, or throw `RequiredError` if conversion fails. */
12
12
  export declare function requireURL(possible: PossibleURL, base?: PossibleURL, caller?: AnyCaller): URL;
package/util/url.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RequiredError } from "../error/RequiredError.js";
2
- import { notOptional } from "./optional.js";
2
+ import { notNullish } from "./null.js";
3
3
  /** Is an unknown value a URL object? */
4
4
  export function isURL(value) {
5
5
  return value instanceof URL;
@@ -11,7 +11,7 @@ export function assertURL(value, caller = assertURL) {
11
11
  }
12
12
  /** Convert a possible URL to a URL, or return `undefined` if conversion fails. */
13
13
  export function getURL(possible, base = _BASE) {
14
- if (notOptional(possible)) {
14
+ if (notNullish(possible)) {
15
15
  try {
16
16
  return isURL(possible) ? possible : new URL(possible, base);
17
17
  }
package/util/validate.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { ValueError } from "../error/ValueError.js";
2
- import { Feedback } from "../feedback/Feedback.js";
3
- import { ValueFeedbacks } from "../feedback/Feedbacks.js";
2
+ import { Feedback, ValueFeedback } from "../feedback/Feedback.js";
4
3
  import { isArray } from "./array.js";
5
4
  import { getDataKeys, getDataProps } from "./data.js";
6
5
  import { getDictionaryItems } from "./dictionary.js";
@@ -30,8 +29,7 @@ export function getValid(value, validator, ErrorConstructor = ValueError, caller
30
29
  */
31
30
  export function* validateItems(unsafeItems, validator) {
32
31
  let index = 0;
33
- let valid = true;
34
- const messages = {};
32
+ const messages = [];
35
33
  for (const unsafeItem of unsafeItems) {
36
34
  try {
37
35
  yield validator.validate(unsafeItem);
@@ -39,13 +37,12 @@ export function* validateItems(unsafeItems, validator) {
39
37
  catch (thrown) {
40
38
  if (!(thrown instanceof Feedback))
41
39
  throw thrown;
42
- messages[index] = thrown.message;
43
- valid = false;
40
+ messages.push(`${index}: ${thrown.message}`);
44
41
  }
45
42
  index++;
46
43
  }
47
- if (!valid)
48
- throw new ValueFeedbacks(messages, unsafeItems);
44
+ if (messages.length)
45
+ throw new ValueFeedback(messages.join("\n"), unsafeItems);
49
46
  }
50
47
  /**
51
48
  * Validate an array of items.
@@ -56,10 +53,9 @@ export function* validateItems(unsafeItems, validator) {
56
53
  */
57
54
  export function validateArray(unsafeArray, validator) {
58
55
  let index = 0;
59
- let valid = true;
60
56
  let changed = false; // start false so we can reuse original if nothing changes
61
57
  const safeArray = [];
62
- const messages = {};
58
+ const messages = [];
63
59
  for (const unsafeItem of unsafeArray) {
64
60
  try {
65
61
  const safeItem = validator.validate(unsafeItem);
@@ -70,13 +66,12 @@ export function validateArray(unsafeArray, validator) {
70
66
  catch (thrown) {
71
67
  if (!(thrown instanceof Feedback))
72
68
  throw thrown;
73
- messages[index] = thrown.message;
74
- valid = false;
69
+ messages.push(`${index}: ${thrown.message}`);
75
70
  }
76
71
  index++;
77
72
  }
78
- if (!valid)
79
- throw new ValueFeedbacks(messages, unsafeArray);
73
+ if (messages.length)
74
+ throw new ValueFeedback(messages.join("\n"), unsafeArray);
80
75
  return changed || !isArray(unsafeArray) ? safeArray : unsafeArray;
81
76
  }
82
77
  /**
@@ -86,10 +81,9 @@ export function validateArray(unsafeArray, validator) {
86
81
  * - `feedback.details` will contain an entry for each invalid item (keyed by their count in the input iterable).
87
82
  */
88
83
  export function validateDictionary(unsafeDictionary, validator) {
89
- let valid = true;
90
84
  let changed = false;
91
85
  const safeDictionary = {};
92
- const messages = {};
86
+ const messages = [];
93
87
  for (const [key, unsafeValue] of getDictionaryItems(unsafeDictionary)) {
94
88
  try {
95
89
  const safeValue = validator.validate(unsafeValue);
@@ -100,21 +94,19 @@ export function validateDictionary(unsafeDictionary, validator) {
100
94
  catch (thrown) {
101
95
  if (!(thrown instanceof Feedback))
102
96
  throw thrown;
103
- messages[key] = thrown.message;
104
- valid = false;
97
+ messages.push(`${key}: ${thrown.message}`);
105
98
  }
106
99
  }
107
- if (!valid)
108
- throw new ValueFeedbacks(messages, unsafeDictionary);
100
+ if (messages.length)
101
+ throw new ValueFeedback(messages.join("\n"), unsafeDictionary);
109
102
  return changed || isIterable(unsafeDictionary) ? safeDictionary : unsafeDictionary;
110
103
  }
111
104
  /** Keep track of whether we're doing a deep-partial match or not. */
112
105
  let isDeeplyPartial = false;
113
106
  export function validateData(unsafeData, validators, partial = isDeeplyPartial) {
114
- let valid = true;
115
107
  let changed = false;
116
108
  const safeData = {};
117
- const messages = {};
109
+ const messages = [];
118
110
  try {
119
111
  isDeeplyPartial = partial;
120
112
  const props = getDataProps(validators);
@@ -132,12 +124,11 @@ export function validateData(unsafeData, validators, partial = isDeeplyPartial)
132
124
  catch (thrown) {
133
125
  if (!(thrown instanceof Feedback))
134
126
  throw thrown;
135
- messages[key] = thrown.message;
136
- valid = false;
127
+ messages.push(`${key}: ${thrown.message}`);
137
128
  }
138
129
  }
139
- if (!valid)
140
- throw new ValueFeedbacks(messages, unsafeData);
130
+ if (messages.length)
131
+ throw new ValueFeedback(messages.join("\n"), unsafeData);
141
132
  if (changed || getDataKeys(unsafeData).length > props.length)
142
133
  return safeData;
143
134
  return unsafeData;
@@ -1,13 +0,0 @@
1
- import type { ImmutableDictionary } from "../util/dictionary.js";
2
- import { Feedback } from "./Feedback.js";
3
- /** Feedback with a set of named messages. */
4
- export declare class Feedbacks extends Feedback {
5
- /** List of named messages. */
6
- readonly messages: ImmutableDictionary<string>;
7
- constructor(messages: ImmutableDictionary<string>);
8
- }
9
- /** Feedbacks with a known and typed `.value` field. */
10
- export declare class ValueFeedbacks<T> extends Feedbacks {
11
- readonly value: T;
12
- constructor(messages: ImmutableDictionary<string>, value: T);
13
- }
@@ -1,18 +0,0 @@
1
- import { Feedback } from "./Feedback.js";
2
- /** Feedback with a set of named messages. */
3
- export class Feedbacks extends Feedback {
4
- /** List of named messages. */
5
- messages;
6
- constructor(messages) {
7
- super(Object.values(messages).join("\n"));
8
- this.messages = messages;
9
- }
10
- }
11
- /** Feedbacks with a known and typed `.value` field. */
12
- export class ValueFeedbacks extends Feedbacks {
13
- value;
14
- constructor(messages, value) {
15
- super(messages);
16
- this.value = value;
17
- }
18
- }
@@ -1,7 +0,0 @@
1
- import type { AnyCaller } from "./function.js";
2
- /** Optional is the value or `null` or `undefined` (synonym for `Nullish`). */
3
- export type Optional<T> = T | null | undefined;
4
- /** Get a required value. */
5
- export declare function getRequired<T>(value: Optional<T>, caller?: AnyCaller): T;
6
- /** Is a value not optional? */
7
- export declare function notOptional<T>(value: Optional<T>): value is T;
package/util/optional.js DELETED
@@ -1,11 +0,0 @@
1
- import { RequiredError } from "../error/RequiredError.js";
2
- /** Get a required value. */
3
- export function getRequired(value, caller = getRequired) {
4
- if (value === null || value === undefined)
5
- throw new RequiredError("Value is required", { received: value, caller });
6
- return value;
7
- }
8
- /** Is a value not optional? */
9
- export function notOptional(value) {
10
- return value !== null && value !== undefined;
11
- }