@maroonedog/luq 2.2.0 → 2.3.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/README.md +47 -602
- package/dist/builder/compile-declarations.d.ts +7 -1
- package/dist/builder/compile-declarations.js +18 -8
- package/dist/builder/compile-declarations.mjs +18 -8
- package/dist/builder/create-builder.js +2 -3
- package/dist/builder/create-builder.mjs +2 -3
- package/dist/builder/create-field-builder.js +13 -1
- package/dist/builder/create-field-builder.mjs +13 -1
- package/dist/builder/declared-calls-store.d.ts +9 -0
- package/dist/builder/declared-calls-store.js +19 -0
- package/dist/builder/declared-calls-store.mjs +15 -0
- package/dist/builder/field-declared-calls.types.d.ts +6 -0
- package/dist/builder/field-declared-calls.types.js +2 -0
- package/dist/builder/field-declared-calls.types.mjs +1 -0
- package/dist/builder/field-entry.types.d.ts +9 -3
- package/dist/builder/field-options.types.d.ts +26 -0
- package/dist/chain/bundle-paths.types.d.ts +9 -12
- package/dist/chain/chain-node-store.d.ts +5 -0
- package/dist/chain/chain-node-store.js +15 -0
- package/dist/chain/chain-node-store.mjs +11 -0
- package/dist/chain/collect-field-rules.d.ts +13 -2
- package/dist/chain/collect-field-rules.js +10 -3
- package/dist/chain/collect-field-rules.mjs +10 -3
- package/dist/chain/create-chain-node.js +19 -9
- package/dist/chain/create-chain-node.mjs +19 -9
- package/dist/chain/declaration-recorder.port.d.ts +31 -0
- package/dist/chain/declaration-recorder.port.js +17 -0
- package/dist/chain/declaration-recorder.port.mjs +13 -0
- package/dist/chain/declared-call.types.d.ts +15 -0
- package/dist/chain/declared-call.types.js +2 -0
- package/dist/chain/declared-call.types.mjs +1 -0
- package/dist/chain/index.d.ts +3 -1
- package/dist/compile/compile-array-node.js +1 -0
- package/dist/compile/compile-array-node.mjs +1 -0
- package/dist/compile/compile-field.d.ts +1 -0
- package/dist/compile/compile-field.js +8 -6
- package/dist/compile/compile-field.mjs +8 -6
- package/dist/compile/compile-schema.js +4 -0
- package/dist/compile/compile-schema.mjs +4 -0
- package/dist/compile/group-array-fields.d.ts +1 -0
- package/dist/compile/split-rules-by-kind.js +10 -14
- package/dist/compile/split-rules-by-kind.mjs +10 -14
- package/dist/compile/validation-plan.types.d.ts +19 -6
- package/dist/core/type-erasure.d.ts +36 -30
- package/dist/core/type-erasure.js +36 -30
- package/dist/core/type-erasure.mjs +36 -30
- package/dist/json-schema/build-from-schema.js +8 -1
- package/dist/json-schema/build-from-schema.mjs +8 -1
- package/dist/json-schema/declare-additional-properties.d.ts +7 -7
- package/dist/json-schema/declare-additional-properties.js +7 -7
- package/dist/json-schema/declare-additional-properties.mjs +7 -7
- package/dist/json-schema/declare-object-keywords.js +4 -4
- package/dist/json-schema/declare-object-keywords.mjs +4 -4
- package/dist/json-schema/follow-json-pointer.d.ts +7 -6
- package/dist/json-schema/follow-json-pointer.js +24 -24
- package/dist/json-schema/follow-json-pointer.mjs +24 -24
- package/dist/json-schema/ref-resolution-error.js +3 -3
- package/dist/json-schema/ref-resolution-error.mjs +3 -3
- package/dist/json-schema/schema-registry.js +12 -11
- package/dist/json-schema/schema-registry.mjs +12 -11
- package/dist/json-schema/uri-reference.js +12 -12
- package/dist/json-schema/uri-reference.mjs +12 -12
- package/dist/path/create-value-writer.js +12 -12
- package/dist/path/create-value-writer.mjs +12 -12
- package/dist/path/reserved-segment.d.ts +16 -16
- package/dist/path/reserved-segment.js +17 -21
- package/dist/path/reserved-segment.mjs +17 -21
- package/dist/plugins/index.generated.js +2 -2
- package/dist/plugins/index.generated.mjs +2 -2
- package/dist/plugins/manifest.generated.js +2 -2
- package/dist/plugins/manifest.generated.mjs +2 -2
- package/dist/plugins/object-additional-properties/select-additional-keys.d.ts +8 -8
- package/dist/plugins/object-additional-properties/select-additional-keys.js +16 -16
- package/dist/plugins/object-additional-properties/select-additional-keys.mjs +16 -16
- package/dist/plugins/stitch/stitch.d.ts +10 -14
- package/dist/plugins/stitch-with/stitch-with.d.ts +1 -1
- package/dist/plugins/stitch-with/stitch-with.js +22 -24
- package/dist/plugins/stitch-with/stitch-with.mjs +22 -24
- package/dist/plugins/string-min/string-min.js +6 -8
- package/dist/plugins/string-min/string-min.mjs +6 -8
- package/dist/presets/presets.d.ts +10 -11
- package/dist/presets/presets.js +22 -23
- package/dist/presets/presets.mjs +22 -23
- package/dist/runtime/create-field-validator.js +4 -6
- package/dist/runtime/create-field-validator.mjs +4 -6
- package/dist/runtime/create-validator.js +11 -11
- package/dist/runtime/create-validator.mjs +11 -11
- package/dist/runtime/output-writer.js +5 -1
- package/dist/runtime/output-writer.mjs +5 -1
- package/dist/runtime/run-array-node.js +6 -6
- package/dist/runtime/run-array-node.mjs +6 -6
- package/dist/runtime/run-field.js +18 -19
- package/dist/runtime/run-field.mjs +18 -19
- package/dist/standard-schema/assemble-json-schema.d.ts +4 -0
- package/dist/standard-schema/assemble-json-schema.js +95 -0
- package/dist/standard-schema/assemble-json-schema.mjs +92 -0
- package/dist/standard-schema/declaration-recorder.d.ts +6 -0
- package/dist/standard-schema/declaration-recorder.js +30 -0
- package/dist/standard-schema/declaration-recorder.mjs +27 -0
- package/dist/standard-schema/declarations-unavailable-error.d.ts +4 -0
- package/dist/standard-schema/declarations-unavailable-error.js +32 -0
- package/dist/standard-schema/declarations-unavailable-error.mjs +28 -0
- package/dist/standard-schema/emit-field-schema.d.ts +9 -0
- package/dist/standard-schema/emit-field-schema.js +68 -0
- package/dist/standard-schema/emit-field-schema.mjs +65 -0
- package/dist/standard-schema/index.d.ts +5 -0
- package/dist/standard-schema/index.js +9 -1
- package/dist/standard-schema/index.mjs +4 -0
- package/dist/standard-schema/json-schema-target.d.ts +6 -0
- package/dist/standard-schema/json-schema-target.js +44 -0
- package/dist/standard-schema/json-schema-target.mjs +39 -0
- package/dist/standard-schema/plugin-keyword-map.d.ts +3 -0
- package/dist/standard-schema/plugin-keyword-map.js +93 -0
- package/dist/standard-schema/plugin-keyword-map.mjs +90 -0
- package/dist/standard-schema/split-issue-path.d.ts +6 -4
- package/dist/standard-schema/split-issue-path.js +15 -13
- package/dist/standard-schema/split-issue-path.mjs +15 -13
- package/dist/standard-schema/standard-schema.types.d.ts +8 -7
- package/dist/standard-schema/standard-schema.types.js +6 -6
- package/dist/standard-schema/standard-schema.types.mjs +6 -6
- package/dist/standard-schema/to-standard-json-schema.d.ts +19 -0
- package/dist/standard-schema/to-standard-json-schema.js +36 -0
- package/dist/standard-schema/to-standard-json-schema.mjs +33 -0
- package/dist/standard-schema/to-standard-schema.d.ts +16 -15
- package/dist/standard-schema/to-standard-schema.js +15 -22
- package/dist/standard-schema/to-standard-schema.mjs +15 -22
- package/dist/standard-schema/unrepresentable-rule-error.d.ts +15 -0
- package/dist/standard-schema/unrepresentable-rule-error.js +43 -0
- package/dist/standard-schema/unrepresentable-rule-error.mjs +38 -0
- package/dist/types/index.d.ts +12 -12
- package/dist/types/index.js +7 -7
- package/dist/types/index.mjs +7 -7
- package/package.json +1 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ===========================================================================
|
|
3
|
+
// L10 src/standard-schema/plugin-keyword-map.ts
|
|
4
|
+
//
|
|
5
|
+
// "This plugin, called with these arguments, means this JSON Schema keyword."
|
|
6
|
+
// The reading direction of keyword-map-*.ts, reusing the correspondence those
|
|
7
|
+
// files already settled rather than inventing a second one.
|
|
8
|
+
//
|
|
9
|
+
// Plugin names are written as STRINGS. Importing the plugins themselves would
|
|
10
|
+
// drag every one of them into the bundle of anyone who emits a schema, which
|
|
11
|
+
// does not fit "you only ship what you used". A test cross-checks each string
|
|
12
|
+
// against the real `plugin.name`, so the names cannot drift without the cost.
|
|
13
|
+
//
|
|
14
|
+
// A plugin that is not listed here cannot be written out. A plugin the user
|
|
15
|
+
// wrote themselves is never listed, so it never can. That is a consequence of
|
|
16
|
+
// the design rather than an oversight, and it surfaces as
|
|
17
|
+
// UnrepresentableRuleError instead of being hidden.
|
|
18
|
+
// ===========================================================================
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.PLUGIN_KEYWORDS = void 0;
|
|
21
|
+
const numberAt = (args, index) => typeof args[index] === "number" ? args[index] : Number.NaN;
|
|
22
|
+
/**
|
|
23
|
+
* A second argument makes `.min(n)` exclusive. The same boundary the
|
|
24
|
+
* reading direction draws when it maps `exclusiveMinimum`.
|
|
25
|
+
*/
|
|
26
|
+
const boundOf = (inclusive, exclusive) => (args) => ({
|
|
27
|
+
[args[1] === true ? exclusive : inclusive]: numberAt(args, 0),
|
|
28
|
+
});
|
|
29
|
+
/** A format with no arguments: the name is the `format` value verbatim. */
|
|
30
|
+
const format = (name) => () => ({ format: name });
|
|
31
|
+
exports.PLUGIN_KEYWORDS = Object.freeze({
|
|
32
|
+
// --- strings ----------------------------------------------------------
|
|
33
|
+
stringMin: (args) => ({ minLength: numberAt(args, 0) }),
|
|
34
|
+
stringMax: (args) => ({ maxLength: numberAt(args, 0) }),
|
|
35
|
+
stringExactLength: (args) => ({
|
|
36
|
+
minLength: numberAt(args, 0),
|
|
37
|
+
maxLength: numberAt(args, 0),
|
|
38
|
+
}),
|
|
39
|
+
// Draft-07's `pattern` is an ECMA-262 SOURCE string. Flags cannot be
|
|
40
|
+
// spelled there, and dropping them changes the meaning, so a flagged
|
|
41
|
+
// RegExp counts as unwritable rather than being silently narrowed.
|
|
42
|
+
stringPattern: (args) => args[0] instanceof RegExp ? { pattern: args[0].source } : null,
|
|
43
|
+
stringContentEncoding: (args) => ({ contentEncoding: args[0] }),
|
|
44
|
+
stringContentMediaType: (args) => ({ contentMediaType: args[0] }),
|
|
45
|
+
// --- formats (names taken verbatim from the format map) ---------------
|
|
46
|
+
stringDatetime: format("date-time"),
|
|
47
|
+
stringDate: format("date"),
|
|
48
|
+
stringTime: format("time"),
|
|
49
|
+
stringDuration: format("duration"),
|
|
50
|
+
stringEmail: format("email"),
|
|
51
|
+
stringIdnEmail: format("idn-email"),
|
|
52
|
+
stringHostname: format("hostname"),
|
|
53
|
+
stringIdnHostname: format("idn-hostname"),
|
|
54
|
+
stringIpv4: format("ipv4"),
|
|
55
|
+
stringIpv6: format("ipv6"),
|
|
56
|
+
// `url` is not a registered JSON Schema format name. Both spellings map
|
|
57
|
+
// to this plugin on the reading side, but a writer has to pick one, so it
|
|
58
|
+
// picks the registered `uri`.
|
|
59
|
+
stringUrl: format("uri"),
|
|
60
|
+
stringUriReference: format("uri-reference"),
|
|
61
|
+
stringIri: format("iri"),
|
|
62
|
+
stringIriReference: format("iri-reference"),
|
|
63
|
+
stringUriTemplate: format("uri-template"),
|
|
64
|
+
stringJsonPointer: format("json-pointer"),
|
|
65
|
+
stringRelativeJsonPointer: format("relative-json-pointer"),
|
|
66
|
+
stringRegex: format("regex"),
|
|
67
|
+
uuid: format("uuid"),
|
|
68
|
+
// --- numbers ----------------------------------------------------------
|
|
69
|
+
numberMin: boundOf("minimum", "exclusiveMinimum"),
|
|
70
|
+
numberMax: boundOf("maximum", "exclusiveMaximum"),
|
|
71
|
+
numberMultipleOf: (args) => ({ multipleOf: numberAt(args, 0) }),
|
|
72
|
+
numberRange: (args) => ({
|
|
73
|
+
minimum: numberAt(args, 0),
|
|
74
|
+
maximum: numberAt(args, 1),
|
|
75
|
+
}),
|
|
76
|
+
numberPositive: () => ({ exclusiveMinimum: 0 }),
|
|
77
|
+
numberNegative: () => ({ exclusiveMaximum: 0 }),
|
|
78
|
+
// --- arrays -----------------------------------------------------------
|
|
79
|
+
arrayMinLength: (args) => ({ minItems: numberAt(args, 0) }),
|
|
80
|
+
arrayMaxLength: (args) => ({ maxItems: numberAt(args, 0) }),
|
|
81
|
+
arrayUnique: () => ({ uniqueItems: true }),
|
|
82
|
+
// --- values -----------------------------------------------------------
|
|
83
|
+
literal: (args) => ({ const: args[0] }),
|
|
84
|
+
oneOf: (args) => (Array.isArray(args[0]) ? { enum: args[0] } : null),
|
|
85
|
+
// --- handled by type or presence, adding no keyword -------------------
|
|
86
|
+
// numberInteger becomes `type: "integer"`, so it feeds the type decision.
|
|
87
|
+
numberInteger: () => null,
|
|
88
|
+
required: () => null,
|
|
89
|
+
optional: () => null,
|
|
90
|
+
nullable: () => null,
|
|
91
|
+
// Changes the order things run in, not the set of accepted values.
|
|
92
|
+
skip: () => null,
|
|
93
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// ===========================================================================
|
|
2
|
+
// L10 src/standard-schema/plugin-keyword-map.ts
|
|
3
|
+
//
|
|
4
|
+
// "This plugin, called with these arguments, means this JSON Schema keyword."
|
|
5
|
+
// The reading direction of keyword-map-*.ts, reusing the correspondence those
|
|
6
|
+
// files already settled rather than inventing a second one.
|
|
7
|
+
//
|
|
8
|
+
// Plugin names are written as STRINGS. Importing the plugins themselves would
|
|
9
|
+
// drag every one of them into the bundle of anyone who emits a schema, which
|
|
10
|
+
// does not fit "you only ship what you used". A test cross-checks each string
|
|
11
|
+
// against the real `plugin.name`, so the names cannot drift without the cost.
|
|
12
|
+
//
|
|
13
|
+
// A plugin that is not listed here cannot be written out. A plugin the user
|
|
14
|
+
// wrote themselves is never listed, so it never can. That is a consequence of
|
|
15
|
+
// the design rather than an oversight, and it surfaces as
|
|
16
|
+
// UnrepresentableRuleError instead of being hidden.
|
|
17
|
+
// ===========================================================================
|
|
18
|
+
const numberAt = (args, index) => typeof args[index] === "number" ? args[index] : Number.NaN;
|
|
19
|
+
/**
|
|
20
|
+
* A second argument makes `.min(n)` exclusive. The same boundary the
|
|
21
|
+
* reading direction draws when it maps `exclusiveMinimum`.
|
|
22
|
+
*/
|
|
23
|
+
const boundOf = (inclusive, exclusive) => (args) => ({
|
|
24
|
+
[args[1] === true ? exclusive : inclusive]: numberAt(args, 0),
|
|
25
|
+
});
|
|
26
|
+
/** A format with no arguments: the name is the `format` value verbatim. */
|
|
27
|
+
const format = (name) => () => ({ format: name });
|
|
28
|
+
export const PLUGIN_KEYWORDS = Object.freeze({
|
|
29
|
+
// --- strings ----------------------------------------------------------
|
|
30
|
+
stringMin: (args) => ({ minLength: numberAt(args, 0) }),
|
|
31
|
+
stringMax: (args) => ({ maxLength: numberAt(args, 0) }),
|
|
32
|
+
stringExactLength: (args) => ({
|
|
33
|
+
minLength: numberAt(args, 0),
|
|
34
|
+
maxLength: numberAt(args, 0),
|
|
35
|
+
}),
|
|
36
|
+
// Draft-07's `pattern` is an ECMA-262 SOURCE string. Flags cannot be
|
|
37
|
+
// spelled there, and dropping them changes the meaning, so a flagged
|
|
38
|
+
// RegExp counts as unwritable rather than being silently narrowed.
|
|
39
|
+
stringPattern: (args) => args[0] instanceof RegExp ? { pattern: args[0].source } : null,
|
|
40
|
+
stringContentEncoding: (args) => ({ contentEncoding: args[0] }),
|
|
41
|
+
stringContentMediaType: (args) => ({ contentMediaType: args[0] }),
|
|
42
|
+
// --- formats (names taken verbatim from the format map) ---------------
|
|
43
|
+
stringDatetime: format("date-time"),
|
|
44
|
+
stringDate: format("date"),
|
|
45
|
+
stringTime: format("time"),
|
|
46
|
+
stringDuration: format("duration"),
|
|
47
|
+
stringEmail: format("email"),
|
|
48
|
+
stringIdnEmail: format("idn-email"),
|
|
49
|
+
stringHostname: format("hostname"),
|
|
50
|
+
stringIdnHostname: format("idn-hostname"),
|
|
51
|
+
stringIpv4: format("ipv4"),
|
|
52
|
+
stringIpv6: format("ipv6"),
|
|
53
|
+
// `url` is not a registered JSON Schema format name. Both spellings map
|
|
54
|
+
// to this plugin on the reading side, but a writer has to pick one, so it
|
|
55
|
+
// picks the registered `uri`.
|
|
56
|
+
stringUrl: format("uri"),
|
|
57
|
+
stringUriReference: format("uri-reference"),
|
|
58
|
+
stringIri: format("iri"),
|
|
59
|
+
stringIriReference: format("iri-reference"),
|
|
60
|
+
stringUriTemplate: format("uri-template"),
|
|
61
|
+
stringJsonPointer: format("json-pointer"),
|
|
62
|
+
stringRelativeJsonPointer: format("relative-json-pointer"),
|
|
63
|
+
stringRegex: format("regex"),
|
|
64
|
+
uuid: format("uuid"),
|
|
65
|
+
// --- numbers ----------------------------------------------------------
|
|
66
|
+
numberMin: boundOf("minimum", "exclusiveMinimum"),
|
|
67
|
+
numberMax: boundOf("maximum", "exclusiveMaximum"),
|
|
68
|
+
numberMultipleOf: (args) => ({ multipleOf: numberAt(args, 0) }),
|
|
69
|
+
numberRange: (args) => ({
|
|
70
|
+
minimum: numberAt(args, 0),
|
|
71
|
+
maximum: numberAt(args, 1),
|
|
72
|
+
}),
|
|
73
|
+
numberPositive: () => ({ exclusiveMinimum: 0 }),
|
|
74
|
+
numberNegative: () => ({ exclusiveMaximum: 0 }),
|
|
75
|
+
// --- arrays -----------------------------------------------------------
|
|
76
|
+
arrayMinLength: (args) => ({ minItems: numberAt(args, 0) }),
|
|
77
|
+
arrayMaxLength: (args) => ({ maxItems: numberAt(args, 0) }),
|
|
78
|
+
arrayUnique: () => ({ uniqueItems: true }),
|
|
79
|
+
// --- values -----------------------------------------------------------
|
|
80
|
+
literal: (args) => ({ const: args[0] }),
|
|
81
|
+
oneOf: (args) => (Array.isArray(args[0]) ? { enum: args[0] } : null),
|
|
82
|
+
// --- handled by type or presence, adding no keyword -------------------
|
|
83
|
+
// numberInteger becomes `type: "integer"`, so it feeds the type decision.
|
|
84
|
+
numberInteger: () => null,
|
|
85
|
+
required: () => null,
|
|
86
|
+
optional: () => null,
|
|
87
|
+
nullable: () => null,
|
|
88
|
+
// Changes the order things run in, not the set of accepted values.
|
|
89
|
+
skip: () => null,
|
|
90
|
+
});
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** The opened path: object keys as strings, array indices as numbers. */
|
|
2
2
|
export type IssuePathSegments = readonly (string | number)[];
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* The root ("") is the empty list, which the spec reads as an issue on the
|
|
5
|
+
* root itself.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* A shape that cannot be interpreted comes back as the whole path in one
|
|
8
|
+
* string segment rather than being swallowed. Handing over something visibly
|
|
9
|
+
* unopened beats dropping the issue.
|
|
8
10
|
*/
|
|
9
11
|
export declare function splitIssuePath(path: string): IssuePathSegments;
|
|
@@ -2,26 +2,28 @@
|
|
|
2
2
|
// ===========================================================================
|
|
3
3
|
// L10 src/standard-schema/split-issue-path.ts
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
// (["items", 1, "productId"])
|
|
5
|
+
// Opens an issue path ("items[1].productId") into the spec's segment list
|
|
6
|
+
// (["items", 1, "productId"]).
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
8
|
+
// Mind the direction: this reverses issue-path FORMATTING, and is not a parser
|
|
9
|
+
// for declared paths. An issue path never contains [*] — it carries the real
|
|
10
|
+
// index instead. Handling both grammars in one function is how [*] quietly
|
|
11
|
+
// starts being read as 0, so they are kept apart.
|
|
12
12
|
//
|
|
13
|
-
//
|
|
14
|
-
// string | number | symbol
|
|
15
|
-
//
|
|
13
|
+
// Array indices come out as numbers. The spec's PropertyKey allows
|
|
14
|
+
// string | number | symbol, and the consumers — form libraries — are written
|
|
15
|
+
// expecting a number.
|
|
16
16
|
// ===========================================================================
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.splitIssuePath = splitIssuePath;
|
|
19
19
|
const INDEX_PATTERN = /^\[(\d+)\]/;
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* The root ("") is the empty list, which the spec reads as an issue on the
|
|
22
|
+
* root itself.
|
|
22
23
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
24
|
+
* A shape that cannot be interpreted comes back as the whole path in one
|
|
25
|
+
* string segment rather than being swallowed. Handing over something visibly
|
|
26
|
+
* unopened beats dropping the issue.
|
|
25
27
|
*/
|
|
26
28
|
function splitIssuePath(path) {
|
|
27
29
|
if (path === "")
|
|
@@ -54,7 +56,7 @@ function splitIssuePath(path) {
|
|
|
54
56
|
}
|
|
55
57
|
return expectKey ? [path] : segments;
|
|
56
58
|
}
|
|
57
|
-
/**
|
|
59
|
+
/** A key runs to the next "." or "[", or to the end when there is neither. */
|
|
58
60
|
function findKeyEnd(rest) {
|
|
59
61
|
const dot = rest.indexOf(".");
|
|
60
62
|
const bracket = rest.indexOf("[");
|
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
// ===========================================================================
|
|
2
2
|
// L10 src/standard-schema/split-issue-path.ts
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
// (["items", 1, "productId"])
|
|
4
|
+
// Opens an issue path ("items[1].productId") into the spec's segment list
|
|
5
|
+
// (["items", 1, "productId"]).
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
7
|
+
// Mind the direction: this reverses issue-path FORMATTING, and is not a parser
|
|
8
|
+
// for declared paths. An issue path never contains [*] — it carries the real
|
|
9
|
+
// index instead. Handling both grammars in one function is how [*] quietly
|
|
10
|
+
// starts being read as 0, so they are kept apart.
|
|
11
11
|
//
|
|
12
|
-
//
|
|
13
|
-
// string | number | symbol
|
|
14
|
-
//
|
|
12
|
+
// Array indices come out as numbers. The spec's PropertyKey allows
|
|
13
|
+
// string | number | symbol, and the consumers — form libraries — are written
|
|
14
|
+
// expecting a number.
|
|
15
15
|
// ===========================================================================
|
|
16
16
|
const INDEX_PATTERN = /^\[(\d+)\]/;
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* The root ("") is the empty list, which the spec reads as an issue on the
|
|
19
|
+
* root itself.
|
|
19
20
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
21
|
+
* A shape that cannot be interpreted comes back as the whole path in one
|
|
22
|
+
* string segment rather than being swallowed. Handing over something visibly
|
|
23
|
+
* unopened beats dropping the issue.
|
|
22
24
|
*/
|
|
23
25
|
export function splitIssuePath(path) {
|
|
24
26
|
if (path === "")
|
|
@@ -51,7 +53,7 @@ export function splitIssuePath(path) {
|
|
|
51
53
|
}
|
|
52
54
|
return expectKey ? [path] : segments;
|
|
53
55
|
}
|
|
54
|
-
/**
|
|
56
|
+
/** A key runs to the next "." or "[", or to the end when there is neither. */
|
|
55
57
|
function findKeyEnd(rest) {
|
|
56
58
|
const dot = rest.indexOf(".");
|
|
57
59
|
const bracket = rest.indexOf("[");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** The spec's StandardSchemaV1, carrying Input and Output as types. */
|
|
2
2
|
export interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
3
3
|
readonly "~standard": StandardSchemaProps<Input, Output>;
|
|
4
4
|
}
|
|
@@ -7,8 +7,8 @@ export interface StandardSchemaProps<Input = unknown, Output = Input> {
|
|
|
7
7
|
readonly vendor: string;
|
|
8
8
|
readonly validate: (value: unknown, options?: StandardSchemaOptions | undefined) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
* InferInput / InferOutput
|
|
10
|
+
* Absent at run time. The spec defines it as a type-only member, and it is
|
|
11
|
+
* what InferInput / InferOutput read.
|
|
12
12
|
*/
|
|
13
13
|
readonly types?: StandardSchemaTypes<Input, Output> | undefined;
|
|
14
14
|
}
|
|
@@ -25,8 +25,9 @@ export interface StandardSchemaFailure {
|
|
|
25
25
|
readonly issues: readonly StandardSchemaIssue[];
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* path
|
|
29
|
-
*
|
|
28
|
+
* The spec makes path optional; it is always present here, with an issue on
|
|
29
|
+
* the root carrying the empty list. That keeps "omitted" distinguishable from
|
|
30
|
+
* "points at the root" on the consuming side.
|
|
30
31
|
*/
|
|
31
32
|
export interface StandardSchemaIssue {
|
|
32
33
|
readonly message: string;
|
|
@@ -38,8 +39,8 @@ export interface StandardSchemaPathSegment {
|
|
|
38
39
|
export type InferStandardInput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
39
40
|
export type InferStandardOutput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
40
41
|
/**
|
|
41
|
-
* validate
|
|
42
|
-
* libraryOptions
|
|
42
|
+
* validate's second parameter, declared because the spec defines it.
|
|
43
|
+
* libraryOptions is the per-vendor extension point, and none is defined yet.
|
|
43
44
|
*/
|
|
44
45
|
export interface StandardSchemaOptions {
|
|
45
46
|
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
// ===========================================================================
|
|
3
3
|
// L10 src/standard-schema/standard-schema.types.ts
|
|
4
4
|
//
|
|
5
|
-
// Standard Schema v1
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
5
|
+
// Declares the Standard Schema v1 types here rather than depending on the
|
|
6
|
+
// spec package. The spec explicitly permits inlining, being types only, and a
|
|
7
|
+
// dependency would add an entry to every user's node_modules for nothing.
|
|
8
|
+
// Type tests pin the shape against the spec so it cannot drift.
|
|
9
9
|
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
10
|
+
// This is the outermost layer because it is a view laid over the validator and
|
|
11
|
+
// nothing in the core imports it. The import direction runs inwards only.
|
|
12
12
|
// ===========================================================================
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// ===========================================================================
|
|
2
2
|
// L10 src/standard-schema/standard-schema.types.ts
|
|
3
3
|
//
|
|
4
|
-
// Standard Schema v1
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
4
|
+
// Declares the Standard Schema v1 types here rather than depending on the
|
|
5
|
+
// spec package. The spec explicitly permits inlining, being types only, and a
|
|
6
|
+
// dependency would add an entry to every user's node_modules for nothing.
|
|
7
|
+
// Type tests pin the shape against the spec so it cannot drift.
|
|
8
8
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
9
|
+
// This is the outermost layer because it is a view laid over the validator and
|
|
10
|
+
// nothing in the core imports it. The import direction runs inwards only.
|
|
11
11
|
// ===========================================================================
|
|
12
12
|
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Validator } from "../builder/validator.types";
|
|
2
|
+
import { type StandardLuqSchema } from "./to-standard-schema";
|
|
3
|
+
/** The spec's Options: target is required, libraryOptions is vendor-defined. */
|
|
4
|
+
export interface JsonSchemaOptions {
|
|
5
|
+
readonly target: string;
|
|
6
|
+
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
7
|
+
}
|
|
8
|
+
interface JsonSchemaConverter {
|
|
9
|
+
readonly input: (options: JsonSchemaOptions) => Record<string, unknown>;
|
|
10
|
+
readonly output: (options: JsonSchemaOptions) => Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
/** A `~standard` carrying both validate and jsonSchema. */
|
|
13
|
+
export type StandardJsonSchemaLuqSchema<T extends object, TParsed = T> = StandardLuqSchema<T, TParsed> & {
|
|
14
|
+
readonly "~standard": StandardLuqSchema<T, TParsed>["~standard"] & {
|
|
15
|
+
readonly jsonSchema: JsonSchemaConverter;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export declare function toStandardJsonSchema<T extends object, TParsed = T>(validator: Validator<T, TParsed>): StandardJsonSchemaLuqSchema<T, TParsed>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toStandardJsonSchema = toStandardJsonSchema;
|
|
4
|
+
const declared_calls_store_1 = require("../builder/declared-calls-store");
|
|
5
|
+
const assemble_json_schema_1 = require("./assemble-json-schema");
|
|
6
|
+
const json_schema_target_1 = require("./json-schema-target");
|
|
7
|
+
const declarations_unavailable_error_1 = require("./declarations-unavailable-error");
|
|
8
|
+
const unrepresentable_rule_error_1 = require("./unrepresentable-rule-error");
|
|
9
|
+
const to_standard_schema_1 = require("./to-standard-schema");
|
|
10
|
+
const declaration_recorder_1 = require("./declaration-recorder");
|
|
11
|
+
// At module scope, not inside the export: this has to be in place before any
|
|
12
|
+
// build() runs, and a chain that already ran cannot be asked again.
|
|
13
|
+
(0, declaration_recorder_1.installJsonSchemaDeclarationRecorder)();
|
|
14
|
+
function toStandardJsonSchema(validator) {
|
|
15
|
+
const declared = (0, declared_calls_store_1.readDeclaredCalls)(validator);
|
|
16
|
+
const emit = (options) => {
|
|
17
|
+
// Refuse an unsupported target before writing anything. Same order even
|
|
18
|
+
// when there is nothing to write, or a wrong target passes as an empty
|
|
19
|
+
// schema instead of an error.
|
|
20
|
+
const schemaUri = (0, json_schema_target_1.resolveJsonSchemaTarget)(options.target);
|
|
21
|
+
if (declared === undefined)
|
|
22
|
+
throw new declarations_unavailable_error_1.DeclarationsUnavailableError();
|
|
23
|
+
return {
|
|
24
|
+
$schema: schemaUri,
|
|
25
|
+
...(0, assemble_json_schema_1.assembleJsonSchema)(declared, (0, unrepresentable_rule_error_1.readUnrepresentablePolicy)(options.libraryOptions)),
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
const standard = (0, to_standard_schema_1.toStandardSchema)(validator);
|
|
29
|
+
return {
|
|
30
|
+
...standard,
|
|
31
|
+
"~standard": {
|
|
32
|
+
...standard["~standard"],
|
|
33
|
+
jsonSchema: { input: emit, output: emit },
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readDeclaredCalls } from "../builder/declared-calls-store.mjs";
|
|
2
|
+
import { assembleJsonSchema } from "./assemble-json-schema.mjs";
|
|
3
|
+
import { resolveJsonSchemaTarget } from "./json-schema-target.mjs";
|
|
4
|
+
import { DeclarationsUnavailableError } from "./declarations-unavailable-error.mjs";
|
|
5
|
+
import { readUnrepresentablePolicy } from "./unrepresentable-rule-error.mjs";
|
|
6
|
+
import { toStandardSchema } from "./to-standard-schema.mjs";
|
|
7
|
+
import { installJsonSchemaDeclarationRecorder } from "./declaration-recorder.mjs";
|
|
8
|
+
// At module scope, not inside the export: this has to be in place before any
|
|
9
|
+
// build() runs, and a chain that already ran cannot be asked again.
|
|
10
|
+
installJsonSchemaDeclarationRecorder();
|
|
11
|
+
export function toStandardJsonSchema(validator) {
|
|
12
|
+
const declared = readDeclaredCalls(validator);
|
|
13
|
+
const emit = (options) => {
|
|
14
|
+
// Refuse an unsupported target before writing anything. Same order even
|
|
15
|
+
// when there is nothing to write, or a wrong target passes as an empty
|
|
16
|
+
// schema instead of an error.
|
|
17
|
+
const schemaUri = resolveJsonSchemaTarget(options.target);
|
|
18
|
+
if (declared === undefined)
|
|
19
|
+
throw new DeclarationsUnavailableError();
|
|
20
|
+
return {
|
|
21
|
+
$schema: schemaUri,
|
|
22
|
+
...assembleJsonSchema(declared, readUnrepresentablePolicy(options.libraryOptions)),
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
const standard = toStandardSchema(validator);
|
|
26
|
+
return {
|
|
27
|
+
...standard,
|
|
28
|
+
"~standard": {
|
|
29
|
+
...standard["~standard"],
|
|
30
|
+
jsonSchema: { input: emit, output: emit },
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import type { Validator } from "../builder/validator.types";
|
|
2
2
|
import type { StandardSchemaOptions, StandardSchemaResult } from "./standard-schema.types";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* The spec allows validate to return a Promise; this one never does. Pinning
|
|
5
|
+
* it to synchronous here spares consumers both the `await` and the narrowing.
|
|
6
|
+
* A narrower type is still assignable to the wider one, so compatibility with
|
|
7
|
+
* StandardSchemaV1 holds — and a type test pins that.
|
|
8
8
|
*/
|
|
9
9
|
interface SynchronousStandardProps<T extends object, TParsed> {
|
|
10
10
|
readonly version: 1;
|
|
11
11
|
readonly vendor: string;
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* The second parameter is in the spec and is deliberately declared even
|
|
14
|
+
* though nothing reads it yet. **Declaring it is the point**: a function
|
|
15
|
+
* with fewer parameters is assignable to one with more, so leaving it out
|
|
16
|
+
* would let the type claim conformance while a consumer's options were
|
|
17
|
+
* silently discarded. Written this way, ignoring them is visible.
|
|
17
18
|
*
|
|
18
|
-
* libraryOptions
|
|
19
|
-
* 何も定義していない。定義したらここで読む。
|
|
19
|
+
* What goes in libraryOptions is per-vendor, and none is defined yet.
|
|
20
20
|
*/
|
|
21
21
|
readonly validate: (value: unknown, options?: StandardSchemaOptions | undefined) => StandardSchemaResult<TParsed>;
|
|
22
22
|
readonly types?: {
|
|
@@ -25,17 +25,18 @@ interface SynchronousStandardProps<T extends object, TParsed> {
|
|
|
25
25
|
} | undefined;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* A Luq validator seen as a Standard Schema.
|
|
29
29
|
*
|
|
30
|
-
* Input
|
|
31
|
-
*
|
|
30
|
+
* Input is the type given to `.for<T>()`; Output is that type after
|
|
31
|
+
* transforms. Both come from the declaration rather than from inference, so
|
|
32
|
+
* InferInput names the very type the caller wrote.
|
|
32
33
|
*/
|
|
33
34
|
export type StandardLuqSchema<T extends object, TParsed = T> = Validator<T, TParsed> & {
|
|
34
35
|
readonly "~standard": SynchronousStandardProps<T, TParsed>;
|
|
35
36
|
};
|
|
36
37
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
38
|
+
* The original validator's members stay. What comes back is still a
|
|
39
|
+
* Validator, so neither face has to be given up for the other.
|
|
39
40
|
*/
|
|
40
41
|
export declare function toStandardSchema<T extends object, TParsed = T>(validator: Validator<T, TParsed>): StandardLuqSchema<T, TParsed>;
|
|
41
42
|
export {};
|
|
@@ -2,21 +2,20 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.toStandardSchema = toStandardSchema;
|
|
4
4
|
const split_issue_path_1 = require("./split-issue-path");
|
|
5
|
-
/** package.
|
|
5
|
+
/** Matches the package name. Consumers show it in error output. */
|
|
6
6
|
const VENDOR = "luq";
|
|
7
7
|
const COLLECT_EVERY_ISSUE = {
|
|
8
8
|
abortEarly: false,
|
|
9
9
|
abortEarlyOnEachField: false,
|
|
10
10
|
};
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* The original validator's members stay. What comes back is still a
|
|
13
|
+
* Validator, so neither face has to be given up for the other.
|
|
14
14
|
*/
|
|
15
15
|
function toStandardSchema(validator) {
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
// ここがコンパイルエラーになる — 黙って落ちるより良い。
|
|
16
|
+
// Assembled without a type assertion; this is not a file allowed to write
|
|
17
|
+
// one. Copying each member by name means a new member on Validator breaks
|
|
18
|
+
// the build here, which beats being dropped in silence.
|
|
20
19
|
const props = {
|
|
21
20
|
version: 1,
|
|
22
21
|
vendor: VENDOR,
|
|
@@ -36,25 +35,19 @@ function toStandardSchema(validator) {
|
|
|
36
35
|
};
|
|
37
36
|
}
|
|
38
37
|
/**
|
|
39
|
-
* code
|
|
40
|
-
*
|
|
38
|
+
* code and severity have nowhere to go in the spec, so they are dropped. The
|
|
39
|
+
* message is passed through as already composed.
|
|
41
40
|
*/
|
|
42
41
|
function toStandardIssue(issue) {
|
|
43
42
|
return { message: issue.message, path: (0, split_issue_path_1.splitIssuePath)(issue.path) };
|
|
44
43
|
}
|
|
45
44
|
// ---------------------------------------------------------------------------
|
|
46
|
-
//
|
|
45
|
+
// Why build() does not simply put ~standard on every validator.
|
|
47
46
|
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
// 7,420 B なので 4.2% にあたり、「使った分しか入らない」という約束と噛み合わない。
|
|
55
|
-
// サブパスにしておけば import しない限り 0 B で、tRPC などに渡したい人だけが払う。
|
|
56
|
-
//
|
|
57
|
-
// 代償は、利用者が toStandardSchema() で1回包む必要があること。build() が
|
|
58
|
-
// 直接 ~standard を持つほうが体験は良いが、その体験のために全員に課金する形に
|
|
59
|
-
// なるので取らなかった。将来コアに入れるなら、この 312 B が判断材料になる。
|
|
47
|
+
// It would be the nicer experience — no wrapping call — but it bills everyone
|
|
48
|
+
// for it, including the majority who never hand a validator to a spec
|
|
49
|
+
// consumer. Measured against the core bundle the surcharge was a few percent,
|
|
50
|
+
// which does not fit "you only ship what you used". As a subpath it costs
|
|
51
|
+
// nothing until imported. Re-measure before revisiting the decision; the
|
|
52
|
+
// figures live with the size budget, not here.
|
|
60
53
|
// ---------------------------------------------------------------------------
|