shelving 1.145.3 → 1.147.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.
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.145.3",
14
+ "version": "1.147.0",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
@@ -0,0 +1,18 @@
1
+ import type { Data } from "../util/data.js";
2
+ import type { DataSchema } from "./DataSchema.js";
3
+ import type { SchemaOptions } from "./Schema.js";
4
+ import { ThroughSchema } from "./ThroughSchema.js";
5
+ /** Allowed options for `PartialSchema` */
6
+ export interface PartialSchemaOptions<T extends Data> extends SchemaOptions {
7
+ readonly source: DataSchema<T>;
8
+ readonly value?: Partial<T> | undefined;
9
+ }
10
+ /** Validate a partial value for a given `DataSchema` source. */
11
+ export declare class PartialSchema<T extends Data> extends ThroughSchema<Partial<T>> {
12
+ readonly source: DataSchema<T>;
13
+ readonly value: Partial<T>;
14
+ constructor({ value, ...options }: PartialSchemaOptions<T>);
15
+ validate(unsafeValue?: unknown): Partial<T>;
16
+ }
17
+ /** Create a new partial schema from a `DataSchema` source. */
18
+ export declare const PARTIAL: <T extends Data>(source: DataSchema<T>) => PartialSchema<T>;
@@ -0,0 +1,17 @@
1
+ import { ValueFeedback } from "../feedback/Feedback.js";
2
+ import { isData } from "../util/data.js";
3
+ import { validateData } from "../util/validate.js";
4
+ import { ThroughSchema } from "./ThroughSchema.js";
5
+ /** Validate a partial value for a given `DataSchema` source. */
6
+ export class PartialSchema extends ThroughSchema {
7
+ constructor({ value = {}, ...options }) {
8
+ super({ value, ...options });
9
+ }
10
+ validate(unsafeValue = this.value) {
11
+ if (!isData(unsafeValue))
12
+ throw new ValueFeedback("Must be object", unsafeValue);
13
+ return validateData(unsafeValue, this.source.props, true);
14
+ }
15
+ }
16
+ /** Create a new partial schema from a `DataSchema` source. */
17
+ export const PARTIAL = (source) => new PartialSchema({ source });
@@ -1,4 +1,4 @@
1
- import { requireSlug } from "../util/string.js";
1
+ import { getSlug } from "../util/string.js";
2
2
  import { OPTIONAL } from "./OptionalSchema.js";
3
3
  import { StringSchema } from "./StringSchema.js";
4
4
  /**
@@ -17,7 +17,7 @@ export class SlugSchema extends StringSchema {
17
17
  });
18
18
  }
19
19
  sanitize(str) {
20
- return requireSlug(str);
20
+ return getSlug(str) || "";
21
21
  }
22
22
  }
23
23
  /** Valid slug, e.g. `this-is-a-slug` */
@@ -29,7 +29,7 @@ export class StringSchema extends Schema {
29
29
  throw new ValueFeedback("Must be string", unsafeValue);
30
30
  const saneString = this.sanitize(possibleString);
31
31
  if (saneString.length < this.min)
32
- throw new ValueFeedback(saneString ? `Minimum ${this.min} characters` : "Required", saneString);
32
+ throw new ValueFeedback(saneString.length ? `Minimum ${this.min} characters` : "Required", saneString);
33
33
  if (saneString.length > this.max)
34
34
  throw new ValueFeedback(`Maximum ${this.max} characters`, saneString);
35
35
  return saneString;
@@ -0,0 +1,14 @@
1
+ import { StringSchema, type StringSchemaOptions } from "./StringSchema.js";
2
+ /**
3
+ * Type of `StringSchema` that defines a valid UUID (versions 1-5). Defaults to any-version validation.
4
+ * - Input is trimmed and lowercased.
5
+ * - Falsy values are converted to empty string.
6
+ */
7
+ export declare class UUIDSchema extends StringSchema {
8
+ constructor(options?: StringSchemaOptions);
9
+ sanitize(str: string): string;
10
+ }
11
+ /** Any valid UUID (versions 1-5) */
12
+ export declare const UUID: UUIDSchema;
13
+ /** Any valid UUID (versions 1-5) or null */
14
+ export declare const OPTIONAL_UUID: import("./OptionalSchema.js").OptionalSchema<string>;
@@ -0,0 +1,26 @@
1
+ import { getUUID } from "../util/uuid.js";
2
+ import { OPTIONAL } from "./OptionalSchema.js";
3
+ import { StringSchema } from "./StringSchema.js";
4
+ /**
5
+ * Type of `StringSchema` that defines a valid UUID (versions 1-5). Defaults to any-version validation.
6
+ * - Input is trimmed and lowercased.
7
+ * - Falsy values are converted to empty string.
8
+ */
9
+ export class UUIDSchema extends StringSchema {
10
+ constructor(options = {}) {
11
+ const { title = "UUID", ...rest } = options;
12
+ super({
13
+ title,
14
+ ...rest,
15
+ min: 36,
16
+ max: 36, // 36 chars including hyphens
17
+ });
18
+ }
19
+ sanitize(str) {
20
+ return getUUID(str) || "";
21
+ }
22
+ }
23
+ /** Any valid UUID (versions 1-5) */
24
+ export const UUID = new UUIDSchema({ title: "ID" });
25
+ /** Any valid UUID (versions 1-5) or null */
26
+ export const OPTIONAL_UUID = OPTIONAL(UUID);
package/schema/index.d.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  export * from "./Schema.js";
2
+ export * from "./ThroughSchema.js";
3
+ export * from "./OptionalSchema.js";
4
+ export * from "./RequiredSchema.js";
5
+ export * from "./PartialSchema.js";
2
6
  export * from "./AllowSchema.js";
3
7
  export * from "./ArraySchema.js";
4
8
  export * from "./BooleanSchema.js";
@@ -18,6 +22,4 @@ export * from "./SlugSchema.js";
18
22
  export * from "./StringSchema.js";
19
23
  export * from "./TextSchema.js";
20
24
  export * from "./TimeSchema.js";
21
- export * from "./ThroughSchema.js";
22
- export * from "./OptionalSchema.js";
23
- export * from "./RequiredSchema.js";
25
+ export * from "./UUIDSchema.js";
package/schema/index.js CHANGED
@@ -1,4 +1,10 @@
1
1
  export * from "./Schema.js";
2
+ // Utility schemas.
3
+ export * from "./ThroughSchema.js";
4
+ export * from "./OptionalSchema.js";
5
+ export * from "./RequiredSchema.js";
6
+ export * from "./PartialSchema.js";
7
+ // Field schemas.
2
8
  export * from "./AllowSchema.js";
3
9
  export * from "./ArraySchema.js";
4
10
  export * from "./BooleanSchema.js";
@@ -18,6 +24,4 @@ export * from "./SlugSchema.js";
18
24
  export * from "./StringSchema.js";
19
25
  export * from "./TextSchema.js";
20
26
  export * from "./TimeSchema.js";
21
- export * from "./ThroughSchema.js";
22
- export * from "./OptionalSchema.js";
23
- export * from "./RequiredSchema.js";
27
+ export * from "./UUIDSchema.js";
package/util/index.d.ts CHANGED
@@ -58,4 +58,5 @@ export * from "./undefined.js";
58
58
  export * from "./units.js";
59
59
  export * from "./update.js";
60
60
  export * from "./url.js";
61
+ export * from "./uuid.js";
61
62
  export * from "./validate.js";
package/util/index.js CHANGED
@@ -58,4 +58,5 @@ export * from "./undefined.js";
58
58
  export * from "./units.js";
59
59
  export * from "./update.js";
60
60
  export * from "./url.js";
61
+ export * from "./uuid.js";
61
62
  export * from "./validate.js";
package/util/uuid.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /** Return a random UUID (v4) */
2
+ export declare function randomUUID(): string;
3
+ /** Convert/validate a unknown value as as UUID. */
4
+ export declare function getUUID(value: string): string | undefined;
5
+ /** Require a valid UUID. */
6
+ export declare function requireUUID(value: string): string;
package/util/uuid.js ADDED
@@ -0,0 +1,22 @@
1
+ import { RequiredError } from "../error/RequiredError.js";
2
+ /** Return a random UUID (v4) */
3
+ export function randomUUID() {
4
+ return crypto.randomUUID();
5
+ }
6
+ /** Convert/validate a unknown value as as UUID. */
7
+ export function getUUID(value) {
8
+ if (typeof value !== "string" || !value)
9
+ return;
10
+ // Strip any non-hex characters (including existing dashes), then normalize to lowercase.
11
+ const cleaned = value.replace(/[^0-9A-Fa-f]/g, "").toLowerCase();
12
+ if (cleaned.length !== 32)
13
+ return;
14
+ return `${cleaned.slice(0, 8)}-${cleaned.slice(8, 12)}-${cleaned.slice(12, 16)}-${cleaned.slice(16, 20)}-${cleaned.slice(20)}`;
15
+ }
16
+ /** Require a valid UUID. */
17
+ export function requireUUID(value) {
18
+ const uuid = getUUID(value);
19
+ if (!uuid)
20
+ throw new RequiredError("Invalid UUID");
21
+ return uuid;
22
+ }