shelving 1.186.1 → 1.187.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/api/store/EndpointStore.d.ts +0 -1
  2. package/firestore/server/FirestoreServerProvider.d.ts +0 -1
  3. package/package.json +7 -6
  4. package/schema/AddressSchema.d.ts +2 -1
  5. package/schema/AddressSchema.js +4 -0
  6. package/schema/ArraySchema.d.ts +1 -0
  7. package/schema/ArraySchema.js +4 -0
  8. package/schema/BooleanSchema.d.ts +1 -0
  9. package/schema/BooleanSchema.js +4 -0
  10. package/schema/ChoiceSchema.d.ts +19 -15
  11. package/schema/ChoiceSchema.js +9 -26
  12. package/schema/ColorSchema.d.ts +4 -1
  13. package/schema/CountrySchema.d.ts +1 -1
  14. package/schema/CurrencyAmountSchema.d.ts +3 -1
  15. package/schema/CurrencyAmountSchema.js +5 -2
  16. package/schema/DataSchema.d.ts +1 -0
  17. package/schema/DataSchema.js +4 -0
  18. package/schema/DateSchema.d.ts +2 -5
  19. package/schema/DateSchema.js +6 -5
  20. package/schema/DateTimeSchema.d.ts +2 -1
  21. package/schema/DateTimeSchema.js +5 -2
  22. package/schema/DictionarySchema.d.ts +1 -0
  23. package/schema/DictionarySchema.js +4 -0
  24. package/schema/EntitySchema.d.ts +1 -1
  25. package/schema/KeySchema.d.ts +1 -1
  26. package/schema/KeySchema.js +2 -2
  27. package/schema/NullableSchema.d.ts +1 -0
  28. package/schema/NullableSchema.js +3 -0
  29. package/schema/NumberSchema.d.ts +1 -1
  30. package/schema/NumberSchema.js +3 -2
  31. package/schema/OptionalSchema.d.ts +1 -0
  32. package/schema/OptionalSchema.js +3 -0
  33. package/schema/PasswordSchema.d.ts +9 -0
  34. package/schema/PasswordSchema.js +11 -0
  35. package/schema/Schema.d.ts +5 -3
  36. package/schema/Schema.js +32 -8
  37. package/schema/StringSchema.d.ts +1 -2
  38. package/schema/StringSchema.js +5 -4
  39. package/schema/ThroughSchema.d.ts +1 -0
  40. package/schema/ThroughSchema.js +3 -0
  41. package/schema/TimeSchema.d.ts +2 -1
  42. package/schema/TimeSchema.js +5 -2
  43. package/schema/URISchema.d.ts +2 -1
  44. package/schema/URISchema.js +4 -0
  45. package/schema/URLSchema.d.ts +2 -1
  46. package/schema/URLSchema.js +4 -0
  47. package/schema/index.d.ts +1 -0
  48. package/schema/index.js +1 -0
  49. package/util/duration.d.ts +29 -21
  50. package/util/duration.js +51 -11
  51. package/util/format.d.ts +51 -48
  52. package/util/format.js +50 -75
  53. package/util/units.d.ts +10 -13
  54. package/util/units.js +1 -16
  55. package/util/validate.d.ts +2 -2
@@ -35,7 +35,6 @@ export declare class EndpointStore<P, R> extends Store<R> implements Disposable
35
35
  refreshStale(maxAge: number): void;
36
36
  /** Abort any in-flight request now. */
37
37
  private abort;
38
- /** Fetch the result from the API endpoint now. */
39
38
  private _fetch;
40
39
  [Symbol.dispose](): void;
41
40
  }
@@ -16,7 +16,6 @@ export declare class FirestoreServerProvider<I extends string = string, T extend
16
16
  private _getCollection;
17
17
  /** Create a corresponding `FirestoreQuery` reference from a collection and query. */
18
18
  private _getQuery;
19
- /** Perform a bulk update on a set of documents using a `BulkWriter` */
20
19
  private _bulkWrite;
21
20
  getItem<II extends I, TT extends T>(collection: Collection<string, II, TT>, id: II): Promise<OptionalItem<II, TT>>;
22
21
  getItemSequence<II extends I, TT extends T>(c: Collection<string, II, TT>, id: II): AsyncIterable<OptionalItem<II, TT>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shelving",
3
- "version": "1.186.1",
3
+ "version": "1.187.1",
4
4
  "author": "Dave Houlbrooke <dave@shax.com>",
5
5
  "repository": {
6
6
  "type": "git",
@@ -9,11 +9,12 @@
9
9
  "main": "./index.js",
10
10
  "module": "./index.js",
11
11
  "devDependencies": {
12
- "@biomejs/biome": "^2.4.11",
13
- "@google-cloud/firestore": "^8.3.0",
12
+ "@biomejs/biome": "^2.4.12",
13
+ "@google-cloud/firestore": "^8.5.0",
14
14
  "@types/bun": "^1.3.12",
15
15
  "@types/react": "^19.2.14",
16
16
  "@types/react-dom": "^19.2.3",
17
+ "@typescript/native-preview": "^7.0.0-dev.20260417.1",
17
18
  "firebase": "^12.12.0",
18
19
  "react": "^19.2.5",
19
20
  "react-dom": "^19.2.5",
@@ -62,14 +63,14 @@
62
63
  "scripts": {
63
64
  "test": "bun run --parallel test:*",
64
65
  "test:lint": "biome check .",
65
- "test:type": "tsc --noEmit",
66
- "test:unit": "bun test --concurrent",
66
+ "test:type": "tsgo --noEmit",
67
+ "test:unit": "bun test --concurrent --only-failures",
67
68
  "fix": "bun run --sequential fix:*",
68
69
  "fix:lint": "biome check --write .",
69
70
  "build": "bun run build:setup && bun run build:copy && bun run build:emit && bun run build:test:syntax && bun run build:test:unit",
70
71
  "build:setup": "rm -rf ./dist && mkdir -p ./dist",
71
72
  "build:copy": "cp package.json dist/package.json && cp LICENSE.md dist/LICENSE.md && cp README.md dist/README.md && cp .npmignore dist/.npmignore",
72
- "build:emit": "tsc",
73
+ "build:emit": "tsgo",
73
74
  "build:test:syntax": "bun run ./dist/index.js",
74
75
  "build:test:unit": "bun test ./dist/**/*.test.js --bail"
75
76
  },
@@ -1,4 +1,4 @@
1
- import type { AddressData } from "../util/geo.js";
1
+ import { type AddressData } from "../util/geo.js";
2
2
  import { DataSchema, type DataSchemaOptions } from "./DataSchema.js";
3
3
  /** Allowed options for `AddressSchema` */
4
4
  export interface AddressSchemaOptions extends Omit<DataSchemaOptions<AddressData>, "props"> {
@@ -6,6 +6,7 @@ export interface AddressSchemaOptions extends Omit<DataSchemaOptions<AddressData
6
6
  /** Schema that validates a postal address. */
7
7
  export declare class AddressSchema extends DataSchema<AddressData> {
8
8
  constructor({ one, title, ...options }?: AddressSchemaOptions);
9
+ format(value: AddressData): string;
9
10
  }
10
11
  /** Valid postal address data. */
11
12
  export declare const ADDRESS: AddressSchema;
@@ -1,3 +1,4 @@
1
+ import { formatAddress } from "../util/geo.js";
1
2
  import { COUNTRY } from "./CountrySchema.js";
2
3
  import { DataSchema } from "./DataSchema.js";
3
4
  import { NULLABLE } from "./NullableSchema.js";
@@ -15,6 +16,9 @@ export class AddressSchema extends DataSchema {
15
16
  constructor({ one = "address", title = "Address", ...options } = {}) {
16
17
  super({ one, title, props: ADDRESS_PROPS, ...options });
17
18
  }
19
+ format(value) {
20
+ return formatAddress(value);
21
+ }
18
22
  }
19
23
  /** Valid postal address data. */
20
24
  export const ADDRESS = new AddressSchema({});
@@ -45,6 +45,7 @@ export declare class ArraySchema<T> extends Schema<ImmutableArray<T>> {
45
45
  readonly separator: string | RegExp;
46
46
  constructor({ items, one, many, title, placeholder, unique, min, max, separator, value, ...options }: ArraySchemaOptions<T>);
47
47
  validate(unsafeValue?: unknown): ImmutableArray<T>;
48
+ format(arr: ImmutableArray<T>): string;
48
49
  }
49
50
  /** Valid array with specifed items. */
50
51
  export declare const ARRAY: <T>(items: Schema<T>) => ArraySchema<T>;
@@ -1,4 +1,5 @@
1
1
  import { getUniqueArray, isArray } from "../util/array.js";
2
+ import { formatArray } from "../util/format.js";
2
3
  import { validateArray } from "../util/validate.js";
3
4
  import { Schema } from "./Schema.js";
4
5
  /**
@@ -47,6 +48,9 @@ export class ArraySchema extends Schema {
47
48
  throw `Maximum ${this.max} ${this.many}`;
48
49
  return uniqueArray;
49
50
  }
51
+ format(arr) {
52
+ return formatArray(arr.map(v => this.items.format(v)), undefined, this.format);
53
+ }
50
54
  }
51
55
  /** Valid array with specifed items. */
52
56
  export const ARRAY = (items) => new ArraySchema({ items });
@@ -11,6 +11,7 @@ export declare class BooleanSchema extends Schema<boolean> {
11
11
  readonly required: boolean;
12
12
  constructor({ value, required, ...options }: BooleanSchemaOptions);
13
13
  validate(unsafeValue?: unknown): boolean;
14
+ format(value: boolean): string;
14
15
  }
15
16
  /** Valid boolean. */
16
17
  export declare const BOOLEAN: BooleanSchema;
@@ -1,3 +1,4 @@
1
+ import { formatBoolean } from "../util/format.js";
1
2
  import { Schema } from "./Schema.js";
2
3
  const NEGATIVE = ["", "false", "0", "no", "n", "off"];
3
4
  /** Define a valid boolean. */
@@ -12,6 +13,9 @@ export class BooleanSchema extends Schema {
12
13
  throw "Required";
13
14
  return value;
14
15
  }
16
+ format(value) {
17
+ return formatBoolean(value);
18
+ }
15
19
  }
16
20
  /** Valid boolean. */
17
21
  export const BOOLEAN = new BooleanSchema({});
@@ -1,32 +1,36 @@
1
1
  import { type ImmutableArray } from "../util/array.js";
2
2
  import type { SchemaOptions } from "./Schema.js";
3
3
  import { Schema } from "./Schema.js";
4
- export type ChoiceOptions<K extends string> = ImmutableArray<K> | {
5
- readonly [KK in K]: unknown;
4
+ /**
5
+ * Set of options for a `ChoiceSchema` can be either:
6
+ * - Dictionary of string options in `{ key: title }` format.
7
+ */
8
+ export type ChoiceOptions<K extends string> = {
9
+ readonly [KK in K]: string;
6
10
  };
7
- export type ChoiceOption<K extends string> = readonly [K, unknown];
8
- /** Get the options for a choice field as an array. */
9
- export declare function getChoiceEntries<K extends string>(options: ChoiceOptions<K>): ImmutableArray<ChoiceOption<K>>;
10
- /** Get the keys for a choice field as an array. */
11
- export declare function getChoiceKeys<K extends string>(options: ChoiceOptions<K>): ImmutableArray<K>;
12
- /** Get the options for a choice field as an array. */
13
- export declare function isOption<K extends string>(options: ChoiceOptions<K>, option: string): option is K;
11
+ /**
12
+ * Things that can be converted to a choice options dictionary.
13
+ * - Array of string options in `[key]` format (`key` will be used as the `title` too).
14
+ */
15
+ export type PossibleChoiceOptions<K extends string> = ImmutableArray<K> | ChoiceOptions<K>;
16
+ /** A single tuple for a choice option in `[key, title]` format. */
17
+ export type ChoiceOption<K extends string> = readonly [title: K, title: string];
18
+ /** Get a `ChoiceOptions` object for a set of `PossibleChoiceOptions`. */
19
+ export declare function getChoiceOptions<K extends string>(options: PossibleChoiceOptions<K>): ChoiceOptions<K>;
14
20
  /** Allowed options for `ChoiceSchema` */
15
21
  export interface ChoiceSchemaOptions<K extends string> extends Omit<SchemaOptions, "value"> {
16
22
  /** Specify correct options using a dictionary of entries. */
17
- readonly options: ChoiceOptions<K>;
23
+ readonly options: PossibleChoiceOptions<K>;
18
24
  /** Default option for the value. */
19
25
  readonly value?: K;
20
26
  }
21
27
  /** Choose from an allowed set of values. */
22
- export declare class ChoiceSchema<K extends string> extends Schema<K> implements Iterable<ChoiceOption<K>> {
28
+ export declare class ChoiceSchema<K extends string> extends Schema<K> {
23
29
  readonly value: K | undefined;
24
30
  readonly options: ChoiceOptions<K>;
25
31
  constructor({ one, title, placeholder, options, value, ...rest }: ChoiceSchemaOptions<K>);
26
32
  validate(unsafeValue?: unknown): K;
27
- [Symbol.iterator](): Iterator<ChoiceOption<K>>;
28
- keys(): ImmutableArray<K>;
29
- entries(): ImmutableArray<ChoiceOption<K>>;
33
+ format(value: K): string;
30
34
  }
31
35
  /** Choose from an allowed set of values. */
32
- export declare function CHOICE<K extends string>(options: ChoiceOptions<K>): ChoiceSchema<K>;
36
+ export declare function CHOICE<K extends string>(options: PossibleChoiceOptions<K> | ImmutableArray<K>): ChoiceSchema<K>;
@@ -1,44 +1,27 @@
1
1
  import { isArray } from "../util/array.js";
2
- import { getKeys, getProps, isProp } from "../util/object.js";
2
+ import { isProp } from "../util/object.js";
3
3
  import { Schema } from "./Schema.js";
4
- /** Get the options for a choice field as an array. */
5
- export function getChoiceEntries(options) {
6
- return isArray(options) ? options.map(_makeKeyEntry) : getProps(options);
4
+ /** Get a `ChoiceOptions` object for a set of `PossibleChoiceOptions`. */
5
+ export function getChoiceOptions(options) {
6
+ return isArray(options) ? Object.fromEntries(options.map(_getChoiceOption)) : options;
7
7
  }
8
- function _makeKeyEntry(k) {
8
+ function _getChoiceOption(k) {
9
9
  return [k, k];
10
10
  }
11
- /** Get the keys for a choice field as an array. */
12
- export function getChoiceKeys(options) {
13
- return isArray(options) ? options : getKeys(options);
14
- }
15
- /** Get the options for a choice field as an array. */
16
- export function isOption(options, option) {
17
- return isArray(options) ? options.includes(option) : isProp(options, option);
18
- }
19
11
  /** Choose from an allowed set of values. */
20
12
  export class ChoiceSchema extends Schema {
21
13
  options;
22
14
  constructor({ one = "choice", title = "Choice", placeholder = `No ${one}`, options, value, ...rest }) {
23
15
  super({ one, title, value, placeholder, ...rest });
24
- this.options = options;
16
+ this.options = getChoiceOptions(options);
25
17
  }
26
18
  validate(unsafeValue = this.value) {
27
- if (typeof unsafeValue === "string" && isOption(this.options, unsafeValue))
19
+ if (typeof unsafeValue === "string" && isProp(this.options, unsafeValue))
28
20
  return unsafeValue;
29
21
  throw unsafeValue ? `Unknown ${this.one}` : "Required";
30
22
  }
31
- // Implement iterable.
32
- *[Symbol.iterator]() {
33
- yield* getChoiceEntries(this.options);
34
- }
35
- // Get the current list of keys for this choice.
36
- keys() {
37
- return getChoiceKeys(this.options);
38
- }
39
- // Get the current list of entries for this choice.
40
- entries() {
41
- return getChoiceEntries(this.options);
23
+ format(value) {
24
+ return this.options[value];
42
25
  }
43
26
  }
44
27
  /** Choose from an allowed set of values. */
@@ -1,4 +1,7 @@
1
1
  import { StringSchema, type StringSchemaOptions } from "./StringSchema.js";
2
+ /** Options for a `ColorSchema` */
3
+ export interface ColorSchemaOptions extends Omit<StringSchemaOptions, "type" | "min" | "max" | "match" | "multiline"> {
4
+ }
2
5
  /**
3
6
  * Define a valid color hex string, e.g `#00CCFF`
4
7
  *
@@ -9,7 +12,7 @@ import { StringSchema, type StringSchemaOptions } from "./StringSchema.js";
9
12
  * Colors are limited to 512 characters (this can be changed with `max`), but generally these won't be data: URIs so this is a reasonable limit.
10
13
  */
11
14
  export declare class ColorSchema extends StringSchema {
12
- constructor({ one, title, value, ...options }: Omit<StringSchemaOptions, "type" | "min" | "max" | "match" | "multiline">);
15
+ constructor({ one, title, value, ...options }: ColorSchemaOptions);
13
16
  sanitize(insaneString: string): string;
14
17
  }
15
18
  /** Valid color hex string, e.g. `#00CCFF` (required because empty string is invalid). */
@@ -14,4 +14,4 @@ export declare class CountrySchema extends ChoiceSchema<Country> {
14
14
  /** Valid country code, e.g. `GB` (required because falsy values are invalid). */
15
15
  export declare const COUNTRY: CountrySchema;
16
16
  /** Valid country code, e.g. `GB`, or `null` */
17
- export declare const NULLABLE_COUNTRY: import("./NullableSchema.js").NullableSchema<"ID" | "AF" | "AX" | "AL" | "DZ" | "AS" | "AD" | "AO" | "AI" | "AQ" | "AG" | "AR" | "AM" | "AW" | "AU" | "AT" | "AZ" | "BS" | "BH" | "BD" | "BB" | "BY" | "BE" | "BZ" | "BJ" | "BM" | "BT" | "BO" | "BA" | "BW" | "BV" | "BR" | "IO" | "BN" | "BG" | "BF" | "BI" | "KH" | "CM" | "CA" | "CV" | "KY" | "CF" | "TD" | "CL" | "CN" | "CX" | "CC" | "CO" | "KM" | "CG" | "CD" | "CK" | "CR" | "CI" | "HR" | "CU" | "CY" | "CZ" | "DK" | "DJ" | "DM" | "DO" | "EC" | "EG" | "SV" | "GQ" | "ER" | "EE" | "ET" | "FK" | "FO" | "FJ" | "FI" | "FR" | "GF" | "PF" | "TF" | "GA" | "GM" | "GE" | "DE" | "GH" | "GI" | "GR" | "GL" | "GD" | "GP" | "GU" | "GT" | "GG" | "GN" | "GW" | "GY" | "HT" | "HM" | "VA" | "HN" | "HK" | "HU" | "IS" | "IN" | "IR" | "IQ" | "IE" | "IM" | "IL" | "IT" | "JM" | "JP" | "JE" | "JO" | "KZ" | "KE" | "KI" | "KR" | "KP" | "KW" | "KG" | "LA" | "LV" | "LB" | "LS" | "LR" | "LY" | "LI" | "LT" | "LU" | "MO" | "MK" | "MG" | "MW" | "MY" | "MV" | "ML" | "MT" | "MH" | "MQ" | "MR" | "MU" | "YT" | "MX" | "FM" | "MD" | "MC" | "MN" | "ME" | "MS" | "MA" | "MZ" | "MM" | "NA" | "NR" | "NP" | "NL" | "AN" | "NC" | "NZ" | "NI" | "NE" | "NG" | "NU" | "NF" | "MP" | "NO" | "OM" | "PK" | "PW" | "PS" | "PA" | "PG" | "PY" | "PE" | "PH" | "PN" | "PL" | "PT" | "PR" | "QA" | "RE" | "RO" | "RU" | "RW" | "BL" | "SH" | "KN" | "LC" | "MF" | "PM" | "VC" | "WS" | "SM" | "ST" | "SA" | "SN" | "RS" | "SC" | "SL" | "SG" | "SK" | "SI" | "SB" | "SO" | "ZA" | "GS" | "ES" | "LK" | "SD" | "SR" | "SJ" | "SZ" | "SE" | "CH" | "SY" | "TW" | "TJ" | "TZ" | "TH" | "TL" | "TG" | "TK" | "TO" | "TT" | "TN" | "TR" | "TM" | "TC" | "TV" | "UG" | "UA" | "AE" | "GB" | "US" | "UM" | "UY" | "UZ" | "VU" | "VE" | "VN" | "VG" | "VI" | "WF" | "EH" | "YE" | "ZM" | "ZW">;
17
+ export declare const NULLABLE_COUNTRY: import("./NullableSchema.js").NullableSchema<"AD" | "AE" | "AF" | "AG" | "AI" | "AL" | "AM" | "AN" | "AO" | "AQ" | "AR" | "AS" | "AT" | "AU" | "AW" | "AX" | "AZ" | "BA" | "BB" | "BD" | "BE" | "BF" | "BG" | "BH" | "BI" | "BJ" | "BL" | "BM" | "BN" | "BO" | "BR" | "BS" | "BT" | "BV" | "BW" | "BY" | "BZ" | "CA" | "CC" | "CD" | "CF" | "CG" | "CH" | "CI" | "CK" | "CL" | "CM" | "CN" | "CO" | "CR" | "CU" | "CV" | "CX" | "CY" | "CZ" | "DE" | "DJ" | "DK" | "DM" | "DO" | "DZ" | "EC" | "EE" | "EG" | "EH" | "ER" | "ES" | "ET" | "FI" | "FJ" | "FK" | "FM" | "FO" | "FR" | "GA" | "GB" | "GD" | "GE" | "GF" | "GG" | "GH" | "GI" | "GL" | "GM" | "GN" | "GP" | "GQ" | "GR" | "GS" | "GT" | "GU" | "GW" | "GY" | "HK" | "HM" | "HN" | "HR" | "HT" | "HU" | "ID" | "IE" | "IL" | "IM" | "IN" | "IO" | "IQ" | "IR" | "IS" | "IT" | "JE" | "JM" | "JO" | "JP" | "KE" | "KG" | "KH" | "KI" | "KM" | "KN" | "KP" | "KR" | "KW" | "KY" | "KZ" | "LA" | "LB" | "LC" | "LI" | "LK" | "LR" | "LS" | "LT" | "LU" | "LV" | "LY" | "MA" | "MC" | "MD" | "ME" | "MF" | "MG" | "MH" | "MK" | "ML" | "MM" | "MN" | "MO" | "MP" | "MQ" | "MR" | "MS" | "MT" | "MU" | "MV" | "MW" | "MX" | "MY" | "MZ" | "NA" | "NC" | "NE" | "NF" | "NG" | "NI" | "NL" | "NO" | "NP" | "NR" | "NU" | "NZ" | "OM" | "PA" | "PE" | "PF" | "PG" | "PH" | "PK" | "PL" | "PM" | "PN" | "PR" | "PS" | "PT" | "PW" | "PY" | "QA" | "RE" | "RO" | "RS" | "RU" | "RW" | "SA" | "SB" | "SC" | "SD" | "SE" | "SG" | "SH" | "SI" | "SJ" | "SK" | "SL" | "SM" | "SN" | "SO" | "SR" | "ST" | "SV" | "SY" | "SZ" | "TC" | "TD" | "TF" | "TG" | "TH" | "TJ" | "TK" | "TL" | "TM" | "TN" | "TO" | "TR" | "TT" | "TV" | "TW" | "TZ" | "UA" | "UG" | "UM" | "US" | "UY" | "UZ" | "VA" | "VC" | "VE" | "VG" | "VI" | "VN" | "VU" | "WF" | "WS" | "YE" | "YT" | "ZA" | "ZM" | "ZW">;
@@ -17,9 +17,11 @@ export interface CurrencyAmountSchemaOptions extends NumberSchemaOptions {
17
17
  * PRICE.format(12.3); // "£12.30"
18
18
  */
19
19
  export declare class CurrencyAmountSchema extends NumberSchema {
20
+ readonly step: number;
20
21
  readonly currency: CurrencyCode;
21
22
  readonly symbol: string;
22
- constructor({ currency, one, title, symbol, step, format, ...options }: CurrencyAmountSchemaOptions);
23
+ constructor({ currency, one, title, symbol, step, ...options }: CurrencyAmountSchemaOptions);
24
+ format(value: number): string;
23
25
  }
24
26
  /** Valid non-negative monetary amount in the a currency. */
25
27
  export declare const CURRENCY_AMOUNT: (currency: CurrencyCode) => CurrencyAmountSchema;
@@ -16,18 +16,21 @@ import { NumberSchema } from "./NumberSchema.js";
16
16
  export class CurrencyAmountSchema extends NumberSchema {
17
17
  currency;
18
18
  symbol;
19
- constructor({ currency, one = "amount", title = "Amount", symbol, step, format = (value, options) => formatCurrency(value, currency, options), ...options }) {
19
+ constructor({ currency, one = "amount", title = "Amount", symbol, step, ...options }) {
20
20
  const validCurrency = requireCurrencyCode(currency, CurrencyAmountSchema);
21
21
  super({
22
22
  one,
23
23
  title,
24
24
  step: step ?? getCurrencyStep(validCurrency, CurrencyAmountSchema),
25
- format,
26
25
  ...options,
27
26
  });
28
27
  this.currency = validCurrency;
29
28
  this.symbol = symbol ?? getCurrencySymbol(validCurrency, CurrencyAmountSchema);
30
29
  }
30
+ format(value) {
31
+ const options = this.step >= 1 ? { maximumFractionDigits: 0 } : {}; // Skip showing decimal places if step is 1 or more.
32
+ return formatCurrency(value, this.currency, options, this.format);
33
+ }
31
34
  }
32
35
  /** Valid non-negative monetary amount in the a currency. */
33
36
  export const CURRENCY_AMOUNT = (currency) => new CurrencyAmountSchema({ currency });
@@ -19,6 +19,7 @@ export declare class DataSchema<T extends Data> extends Schema<unknown> {
19
19
  pick<K extends Key<T>>(...keys: K[]): DataSchema<Pick<T, K>>;
20
20
  /** Make a new `DataSchema` that omits one or more of the current props. */
21
21
  omit<K extends Key<T>>(...keys: K[]): DataSchema<Omit<T, K>>;
22
+ format(value: T): string;
22
23
  }
23
24
  /** Create a `DataSchema` for a set of properties. */
24
25
  export declare const DATA: <T extends Data>(props: Schemas<T>) => DataSchema<T>;
@@ -1,4 +1,5 @@
1
1
  import { isData } from "../util/data.js";
2
+ import { formatObject } from "../util/format.js";
2
3
  import { omitProps, pickProps } from "../util/object.js";
3
4
  import { mapProps } from "../util/transform.js";
4
5
  import { validateData } from "../util/validate.js";
@@ -27,6 +28,9 @@ export class DataSchema extends Schema {
27
28
  omit(...keys) {
28
29
  return new DataSchema({ ...this, props: omitProps(this.props, ...keys) });
29
30
  }
31
+ format(value) {
32
+ return formatObject(value);
33
+ }
30
34
  }
31
35
  function _getSchemaValue([, { value }]) {
32
36
  return value;
@@ -1,5 +1,4 @@
1
1
  import type { PossibleDate } from "../util/date.js";
2
- import { formatDate } from "../util/format.js";
3
2
  import type { Nullish } from "../util/null.js";
4
3
  import type { SchemaOptions } from "./Schema.js";
5
4
  import { Schema } from "./Schema.js";
@@ -11,8 +10,6 @@ export interface DateSchemaOptions extends SchemaOptions {
11
10
  readonly min?: Nullish<PossibleDate>;
12
11
  readonly max?: Nullish<PossibleDate>;
13
12
  readonly input?: DateInputType | undefined;
14
- /** Format the date for display in downstream UIs. */
15
- readonly format?: typeof formatDate | undefined;
16
13
  /**
17
14
  * Rounding step (in milliseconds, because that's the base unit for time).
18
15
  * - E.g. `1000 * 60` will round to the nearest minute.
@@ -26,10 +23,10 @@ export declare class DateSchema extends Schema<string> {
26
23
  readonly max: Date | undefined;
27
24
  readonly input: DateInputType;
28
25
  readonly step: number | undefined;
29
- format: typeof formatDate;
30
- constructor({ one, min, max, value, input, step, format, ...options }: DateSchemaOptions);
26
+ constructor({ one, min, max, value, input, step, ...options }: DateSchemaOptions);
31
27
  validate(value?: unknown): string;
32
28
  stringify(value: Date): string;
29
+ format(value: string): string;
33
30
  }
34
31
  /** Valid date, e.g. `2005-09-12` (required because falsy values are invalid). */
35
32
  export declare const DATE: DateSchema;
@@ -8,14 +8,12 @@ export class DateSchema extends Schema {
8
8
  max;
9
9
  input;
10
10
  step;
11
- format;
12
- constructor({ one = "date", min, max, value, input = "date", step, format = formatDate, ...options }) {
11
+ constructor({ one = "date", min, max, value, input = "date", step, ...options }) {
13
12
  super({ one, title: "Date", value, ...options });
14
13
  this.min = getDate(min);
15
14
  this.max = getDate(max);
16
15
  this.input = input;
17
16
  this.step = step;
18
- this.format = format;
19
17
  }
20
18
  validate(value = this.value) {
21
19
  const date = getDate(value);
@@ -23,14 +21,17 @@ export class DateSchema extends Schema {
23
21
  throw value ? `Invalid ${this.one} format` : "Required";
24
22
  const stepped = typeof this.step === "number" ? new Date(roundStep(date.getTime(), this.step)) : date;
25
23
  if (this.min && stepped < this.min)
26
- throw `Minimum ${this.format(this.min)}`;
24
+ throw `Minimum ${this.format(this.stringify(this.min))}`;
27
25
  if (this.max && stepped > this.max)
28
- throw `Maximum ${this.format(this.max)}`;
26
+ throw `Maximum ${this.format(this.stringify(this.max))}`;
29
27
  return this.stringify(stepped);
30
28
  }
31
29
  stringify(value) {
32
30
  return requireDateString(value);
33
31
  }
32
+ format(value) {
33
+ return formatDate(value, undefined, this.format);
34
+ }
34
35
  }
35
36
  /** Valid date, e.g. `2005-09-12` (required because falsy values are invalid). */
36
37
  export const DATE = new DateSchema({});
@@ -6,8 +6,9 @@ import { DateSchema, type DateSchemaOptions } from "./DateSchema.js";
6
6
  * - If you wish to define an _abstract_ time without a timezone, e.g. a daily alarm, use `TimeSchema` instead.
7
7
  */
8
8
  export declare class DateTimeSchema extends DateSchema {
9
- constructor({ one, title, input, format, ...options }: DateSchemaOptions);
9
+ constructor({ one, title, input, ...options }: DateSchemaOptions);
10
10
  stringify(value: Date): string;
11
+ format(value: string): string;
11
12
  }
12
13
  /** Valid datetime, e.g. `2005-09-12T08:00:00Z` (required because falsy values are invalid). */
13
14
  export declare const DATETIME: DateTimeSchema;
@@ -8,12 +8,15 @@ import { NULLABLE } from "./NullableSchema.js";
8
8
  * - If you wish to define an _abstract_ time without a timezone, e.g. a daily alarm, use `TimeSchema` instead.
9
9
  */
10
10
  export class DateTimeSchema extends DateSchema {
11
- constructor({ one = "time", title = "Time", input = "datetime-local", format = formatDateTime, ...options }) {
12
- super({ one, title, input, format, ...options });
11
+ constructor({ one = "time", title = "Time", input = "datetime-local", ...options }) {
12
+ super({ one, title, input, ...options });
13
13
  }
14
14
  stringify(value) {
15
15
  return value.toISOString();
16
16
  }
17
+ format(value) {
18
+ return formatDateTime(value, undefined, this.format);
19
+ }
17
20
  }
18
21
  /** Valid datetime, e.g. `2005-09-12T08:00:00Z` (required because falsy values are invalid). */
19
22
  export const DATETIME = new DateTimeSchema({});
@@ -16,6 +16,7 @@ export declare class DictionarySchema<T> extends Schema<ImmutableDictionary<T>>
16
16
  readonly max: number;
17
17
  constructor({ items, one, many, placeholder, min, max, title, value, ...options }: DictionarySchemaOptions<T>);
18
18
  validate(unsafeValue?: unknown): ImmutableDictionary<T>;
19
+ format(dict: ImmutableDictionary<T>): string;
19
20
  }
20
21
  /** Valid dictionary object with specifed items. */
21
22
  export declare const DICTIONARY: <T>(items: Schema<T>) => DictionarySchema<T>;
@@ -1,4 +1,5 @@
1
1
  import { isDictionary } from "../util/dictionary.js";
2
+ import { formatArray } from "../util/format.js";
2
3
  import { validateDictionary } from "../util/validate.js";
3
4
  import { Schema } from "./Schema.js";
4
5
  /** Validate a dictionary object (whose props are all the same with string keys). */
@@ -23,6 +24,9 @@ export class DictionarySchema extends Schema {
23
24
  throw `Maximum ${this.max} ${this.many}`;
24
25
  return validDictionary;
25
26
  }
27
+ format(dict) {
28
+ return formatArray(Object.values(dict).map(v => this.items.format(v)), undefined, this.format);
29
+ }
26
30
  }
27
31
  /** Valid dictionary object with specifed items. */
28
32
  export const DICTIONARY = (items) => new DictionarySchema({ items });
@@ -14,4 +14,4 @@ export declare class EntitySchema<T extends string> extends StringSchema {
14
14
  /** Valid file, e.g. `challenge:a1b2c3` */
15
15
  export declare const ENTITY: EntitySchema<string>;
16
16
  /** Valid optional file, e.g. `file.txt`, or `null` */
17
- export declare const NULLABLE_ENTITY: import("./NullableSchema.js").NullableSchema<`${string}:${string}`>;
17
+ export declare const NULLABLE_ENTITY: import("./NullableSchema.js").NullableSchema<string>;
@@ -8,7 +8,7 @@ import { StringSchema, type StringSchemaOptions } from "./StringSchema.js";
8
8
  * - 32 characters is enough for UUIDs, as the 4 `-` hyphens are removed.
9
9
  */
10
10
  export declare class KeySchema extends StringSchema {
11
- constructor({ one, min, max, ...options }: StringSchemaOptions);
11
+ constructor({ one, title, min, max, ...options }: StringSchemaOptions);
12
12
  sanitize(str: string): string;
13
13
  }
14
14
  /** Valid database key. */
@@ -10,8 +10,8 @@ const R_NOT_CHAR = /[^a-zA-Z0-9]/g;
10
10
  * - 32 characters is enough for UUIDs, as the 4 `-` hyphens are removed.
11
11
  */
12
12
  export class KeySchema extends StringSchema {
13
- constructor({ one = "key", min = 1, max = 32, ...options }) {
14
- super({ one, min, max, ...options });
13
+ constructor({ one = "key", title = "Key", min = 1, max = 32, ...options }) {
14
+ super({ one, title, min, max, ...options });
15
15
  }
16
16
  sanitize(str) {
17
17
  return str.replace(R_NOT_CHAR, "");
@@ -10,6 +10,7 @@ export declare class NullableSchema<T> extends ThroughSchema<T | null> {
10
10
  readonly value: T | null;
11
11
  constructor({ value, ...options }: NullableSchemaOptions<T>);
12
12
  validate(unsafeValue?: unknown): T | null;
13
+ format(value: T | null): string;
13
14
  }
14
15
  /** Create a new nullable schema from a source schema. */
15
16
  export declare const NULLABLE: <T>(source: Schema<T>) => NullableSchema<T>;
@@ -9,6 +9,9 @@ export class NullableSchema extends ThroughSchema {
9
9
  return null;
10
10
  return super.validate(unsafeValue);
11
11
  }
12
+ format(value) {
13
+ return value === null ? `No ${this.source.one}` : super.format(value);
14
+ }
12
15
  }
13
16
  /** Create a new nullable schema from a source schema. */
14
17
  export const NULLABLE = (source) => new NullableSchema({ source });
@@ -16,9 +16,9 @@ export declare class NumberSchema extends Schema<number> {
16
16
  readonly min: number;
17
17
  readonly max: number;
18
18
  readonly step: number | undefined;
19
- format: typeof formatNumber;
20
19
  constructor({ one, title, min, max, step, format, value, ...options }: NumberSchemaOptions);
21
20
  validate(value?: unknown): number;
21
+ format(value: number): string;
22
22
  }
23
23
  /** Valid number, e.g. `2048.12345` or `0` zero and a default value of zero. */
24
24
  export declare const NUMBER: NumberSchema;
@@ -7,13 +7,11 @@ export class NumberSchema extends Schema {
7
7
  min;
8
8
  max;
9
9
  step;
10
- format;
11
10
  constructor({ one = "number", title = "Number", min = Number.NEGATIVE_INFINITY, max = Number.POSITIVE_INFINITY, step, format = formatNumber, value, ...options }) {
12
11
  super({ one, title, value, ...options });
13
12
  this.min = min;
14
13
  this.max = max;
15
14
  this.step = step;
16
- this.format = format;
17
15
  }
18
16
  validate(value = this.value) {
19
17
  const number = getNumber(value);
@@ -26,6 +24,9 @@ export class NumberSchema extends Schema {
26
24
  throw `Maximum ${this.format(this.max)}`;
27
25
  return stepped;
28
26
  }
27
+ format(value) {
28
+ return formatNumber(value);
29
+ }
29
30
  }
30
31
  /** Valid number, e.g. `2048.12345` or `0` zero and a default value of zero. */
31
32
  export const NUMBER = new NumberSchema({ title: "Number" });
@@ -14,6 +14,7 @@ export declare class OptionalSchema<T> extends ThroughSchema<T | undefined> {
14
14
  readonly value: undefined;
15
15
  constructor(options: OptionalSchemaOptions<T>);
16
16
  validate(unsafeValue: unknown): T | undefined;
17
+ format(value: T | undefined): string;
17
18
  }
18
19
  /** Make a property of a set of data optional, i.e. it can be the value or `undefined` */
19
20
  export declare const OPTIONAL: <T>(source: Schema<T>) => OptionalSchema<T>;
@@ -13,6 +13,9 @@ export class OptionalSchema extends ThroughSchema {
13
13
  return undefined;
14
14
  return super.validate(unsafeValue);
15
15
  }
16
+ format(value) {
17
+ return value === undefined ? `No ${this.source.one}` : super.format(value);
18
+ }
16
19
  }
17
20
  /** Make a property of a set of data optional, i.e. it can be the value or `undefined` */
18
21
  export const OPTIONAL = (source) => new OptionalSchema({ source });
@@ -0,0 +1,9 @@
1
+ import { StringSchema, type StringSchemaOptions } from "./StringSchema.js";
2
+ export interface PasswordSchemaOptions extends Omit<StringSchemaOptions, "input"> {
3
+ }
4
+ export declare class PasswordSchema extends StringSchema {
5
+ constructor({ one, title, min, ...options }?: PasswordSchemaOptions);
6
+ format(): string;
7
+ }
8
+ /** Password string. */
9
+ export declare const PASSWORD: StringSchema;
@@ -0,0 +1,11 @@
1
+ import { StringSchema } from "./StringSchema.js";
2
+ export class PasswordSchema extends StringSchema {
3
+ constructor({ one = "password", title = "Password", min = 6, ...options } = {}) {
4
+ super({ one, title, min, ...options, input: "password" });
5
+ }
6
+ format() {
7
+ return ""; // Never format a password for display.
8
+ }
9
+ }
10
+ /** Password string. */
11
+ export const PASSWORD = new StringSchema({});