@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
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* 使用実績: required 138 / optional 26 / nullable 12。
|
|
2
|
+
* Present, absent, null. Nearly every declaration uses one of the three.
|
|
4
3
|
*/
|
|
5
4
|
export declare const presence: Readonly<{
|
|
6
5
|
required: import("..").PluginDefinition<"required", "required", readonly import("..").TypeName[], {
|
|
@@ -19,7 +18,7 @@ export declare const presence: Readonly<{
|
|
|
19
18
|
context: import("..").MessageContextExtra;
|
|
20
19
|
}>;
|
|
21
20
|
}>;
|
|
22
|
-
/**
|
|
21
|
+
/** The everyday string checks. */
|
|
23
22
|
export declare const strings: Readonly<{
|
|
24
23
|
stringMin: import("..").PluginDefinition<"stringMin", "min", readonly ["string"], {
|
|
25
24
|
args: readonly [min: number];
|
|
@@ -46,7 +45,7 @@ export declare const strings: Readonly<{
|
|
|
46
45
|
};
|
|
47
46
|
}>;
|
|
48
47
|
}>;
|
|
49
|
-
/**
|
|
48
|
+
/** The everyday number checks. */
|
|
50
49
|
export declare const numbers: Readonly<{
|
|
51
50
|
numberMin: import("..").PluginDefinition<"numberMin", "min", readonly ["number"], {
|
|
52
51
|
args: readonly [min: number, exclusive?: boolean];
|
|
@@ -64,7 +63,7 @@ export declare const numbers: Readonly<{
|
|
|
64
63
|
context: import("..").MessageContextExtra;
|
|
65
64
|
}>;
|
|
66
65
|
}>;
|
|
67
|
-
/**
|
|
66
|
+
/** The everyday array checks. Per-element rules ride on arrayEach. */
|
|
68
67
|
export declare const arrays: Readonly<{
|
|
69
68
|
arrayMinLength: import("..").PluginDefinition<"arrayMinLength", "minLength", readonly ["array", "tuple"], {
|
|
70
69
|
args: readonly [min: number];
|
|
@@ -83,14 +82,14 @@ export declare const arrays: Readonly<{
|
|
|
83
82
|
}>;
|
|
84
83
|
}>;
|
|
85
84
|
/**
|
|
86
|
-
*
|
|
85
|
+
* The four bundles above, together.
|
|
87
86
|
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
87
|
+
* Not called "common", because that name says nothing — and lint bans it. It
|
|
88
|
+
* holds presence plus the everyday string, number and array checks, and the
|
|
89
|
+
* name is the claim that this is the range people write day to day.
|
|
91
90
|
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
91
|
+
* Still not everything. For everything there is the `@maroonedog/luq/plugins`
|
|
92
|
+
* barrel, which costs accordingly.
|
|
94
93
|
*/
|
|
95
94
|
export declare const everydayRules: Readonly<{
|
|
96
95
|
arrayMinLength: import("..").PluginDefinition<"arrayMinLength", "minLength", readonly ["array", "tuple"], {
|
package/dist/presets/presets.js
CHANGED
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.everydayRules = exports.arrays = exports.numbers = exports.strings = exports.presence = void 0;
|
|
4
4
|
// ===========================================================================
|
|
5
|
-
// L7 src/presets/presets.ts —
|
|
5
|
+
// L7 src/presets/presets.ts — predefined plugin bundles.
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
7
|
+
// Why they exist. Importing plugins one at a time is the very mechanism behind
|
|
8
|
+
// "you only ship what you used", but making someone write fifteen use() lines
|
|
9
|
+
// for their first validator is imposing that correctness on them.
|
|
10
10
|
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
11
|
+
// Why several small ones rather than one big one. A single everything-bundle
|
|
12
|
+
// bills the person who needs five plugins for forty. A bundle is just a
|
|
13
|
+
// `PluginBag`, so useAll() takes only the ones wanted, and mixing them is
|
|
14
|
+
// first-wins rather than a collision:
|
|
14
15
|
//
|
|
15
16
|
// Builder().useAll(presence).useAll(strings).for<User>()
|
|
16
17
|
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
// stringEmail 33 / optional 26 という並びで、上位が束の中身になっている。
|
|
18
|
+
// Membership was chosen from how often each plugin is actually used across
|
|
19
|
+
// this repository, most-used first.
|
|
20
20
|
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
21
|
+
// What a bundle costs in bytes is measured by the size budget. A preset trades
|
|
22
|
+
// bytes for convenience, so the price should be measured rather than asserted.
|
|
23
23
|
// ===========================================================================
|
|
24
24
|
const required_1 = require("../plugins/required");
|
|
25
25
|
const optional_1 = require("../plugins/optional");
|
|
@@ -35,42 +35,41 @@ const array_min_length_1 = require("../plugins/array-min-length");
|
|
|
35
35
|
const array_max_length_1 = require("../plugins/array-max-length");
|
|
36
36
|
const array_each_1 = require("../plugins/array-each");
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
39
|
-
* 使用実績: required 138 / optional 26 / nullable 12。
|
|
38
|
+
* Present, absent, null. Nearly every declaration uses one of the three.
|
|
40
39
|
*/
|
|
41
40
|
exports.presence = Object.freeze({
|
|
42
41
|
required: required_1.requiredPlugin,
|
|
43
42
|
optional: optional_1.optionalPlugin,
|
|
44
43
|
nullable: nullable_1.nullablePlugin,
|
|
45
44
|
});
|
|
46
|
-
/**
|
|
45
|
+
/** The everyday string checks. */
|
|
47
46
|
exports.strings = Object.freeze({
|
|
48
47
|
stringMin: string_min_1.stringMinPlugin,
|
|
49
48
|
stringMax: string_max_1.stringMaxPlugin,
|
|
50
49
|
stringPattern: string_pattern_1.stringPatternPlugin,
|
|
51
50
|
stringEmail: string_email_1.stringEmailPlugin,
|
|
52
51
|
});
|
|
53
|
-
/**
|
|
52
|
+
/** The everyday number checks. */
|
|
54
53
|
exports.numbers = Object.freeze({
|
|
55
54
|
numberMin: number_min_1.numberMinPlugin,
|
|
56
55
|
numberMax: number_max_1.numberMaxPlugin,
|
|
57
56
|
numberInteger: number_integer_1.numberIntegerPlugin,
|
|
58
57
|
});
|
|
59
|
-
/**
|
|
58
|
+
/** The everyday array checks. Per-element rules ride on arrayEach. */
|
|
60
59
|
exports.arrays = Object.freeze({
|
|
61
60
|
arrayMinLength: array_min_length_1.arrayMinLengthPlugin,
|
|
62
61
|
arrayMaxLength: array_max_length_1.arrayMaxLengthPlugin,
|
|
63
62
|
arrayEach: array_each_1.arrayEachPlugin,
|
|
64
63
|
});
|
|
65
64
|
/**
|
|
66
|
-
*
|
|
65
|
+
* The four bundles above, together.
|
|
67
66
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
67
|
+
* Not called "common", because that name says nothing — and lint bans it. It
|
|
68
|
+
* holds presence plus the everyday string, number and array checks, and the
|
|
69
|
+
* name is the claim that this is the range people write day to day.
|
|
71
70
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
71
|
+
* Still not everything. For everything there is the `@maroonedog/luq/plugins`
|
|
72
|
+
* barrel, which costs accordingly.
|
|
74
73
|
*/
|
|
75
74
|
exports.everydayRules = Object.freeze({
|
|
76
75
|
...exports.presence,
|
package/dist/presets/presets.mjs
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
// ===========================================================================
|
|
2
|
-
// L7 src/presets/presets.ts —
|
|
2
|
+
// L7 src/presets/presets.ts — predefined plugin bundles.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// Why they exist. Importing plugins one at a time is the very mechanism behind
|
|
5
|
+
// "you only ship what you used", but making someone write fifteen use() lines
|
|
6
|
+
// for their first validator is imposing that correctness on them.
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
8
|
+
// Why several small ones rather than one big one. A single everything-bundle
|
|
9
|
+
// bills the person who needs five plugins for forty. A bundle is just a
|
|
10
|
+
// `PluginBag`, so useAll() takes only the ones wanted, and mixing them is
|
|
11
|
+
// first-wins rather than a collision:
|
|
11
12
|
//
|
|
12
13
|
// Builder().useAll(presence).useAll(strings).for<User>()
|
|
13
14
|
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// stringEmail 33 / optional 26 という並びで、上位が束の中身になっている。
|
|
15
|
+
// Membership was chosen from how often each plugin is actually used across
|
|
16
|
+
// this repository, most-used first.
|
|
17
17
|
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
18
|
+
// What a bundle costs in bytes is measured by the size budget. A preset trades
|
|
19
|
+
// bytes for convenience, so the price should be measured rather than asserted.
|
|
20
20
|
// ===========================================================================
|
|
21
21
|
import { requiredPlugin } from "../plugins/required/index.mjs";
|
|
22
22
|
import { optionalPlugin } from "../plugins/optional/index.mjs";
|
|
@@ -32,42 +32,41 @@ import { arrayMinLengthPlugin } from "../plugins/array-min-length/index.mjs";
|
|
|
32
32
|
import { arrayMaxLengthPlugin } from "../plugins/array-max-length/index.mjs";
|
|
33
33
|
import { arrayEachPlugin } from "../plugins/array-each/index.mjs";
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
36
|
-
* 使用実績: required 138 / optional 26 / nullable 12。
|
|
35
|
+
* Present, absent, null. Nearly every declaration uses one of the three.
|
|
37
36
|
*/
|
|
38
37
|
export const presence = Object.freeze({
|
|
39
38
|
required: requiredPlugin,
|
|
40
39
|
optional: optionalPlugin,
|
|
41
40
|
nullable: nullablePlugin,
|
|
42
41
|
});
|
|
43
|
-
/**
|
|
42
|
+
/** The everyday string checks. */
|
|
44
43
|
export const strings = Object.freeze({
|
|
45
44
|
stringMin: stringMinPlugin,
|
|
46
45
|
stringMax: stringMaxPlugin,
|
|
47
46
|
stringPattern: stringPatternPlugin,
|
|
48
47
|
stringEmail: stringEmailPlugin,
|
|
49
48
|
});
|
|
50
|
-
/**
|
|
49
|
+
/** The everyday number checks. */
|
|
51
50
|
export const numbers = Object.freeze({
|
|
52
51
|
numberMin: numberMinPlugin,
|
|
53
52
|
numberMax: numberMaxPlugin,
|
|
54
53
|
numberInteger: numberIntegerPlugin,
|
|
55
54
|
});
|
|
56
|
-
/**
|
|
55
|
+
/** The everyday array checks. Per-element rules ride on arrayEach. */
|
|
57
56
|
export const arrays = Object.freeze({
|
|
58
57
|
arrayMinLength: arrayMinLengthPlugin,
|
|
59
58
|
arrayMaxLength: arrayMaxLengthPlugin,
|
|
60
59
|
arrayEach: arrayEachPlugin,
|
|
61
60
|
});
|
|
62
61
|
/**
|
|
63
|
-
*
|
|
62
|
+
* The four bundles above, together.
|
|
64
63
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
64
|
+
* Not called "common", because that name says nothing — and lint bans it. It
|
|
65
|
+
* holds presence plus the everyday string, number and array checks, and the
|
|
66
|
+
* name is the claim that this is the range people write day to day.
|
|
68
67
|
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
68
|
+
* Still not everything. For everything there is the `@maroonedog/luq/plugins`
|
|
69
|
+
* barrel, which costs accordingly.
|
|
71
70
|
*/
|
|
72
71
|
export const everydayRules = Object.freeze({
|
|
73
72
|
...presence,
|
|
@@ -60,13 +60,11 @@ function createSubjectComposer(template) {
|
|
|
60
60
|
return (siblings, value) => mergeOntoSiblings(siblings, nest(value));
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
|
-
*
|
|
63
|
+
* Walks the template **once** and folds it into a wrapping function.
|
|
64
64
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* 決めるのはコンパイルが済ませたこと」であり、ここはその例外になっていた。
|
|
69
|
-
* 非ワイルドカードの経路 (createValueWriter) は最初からこの形である。
|
|
65
|
+
* Walking it per validation re-read each segment's kind every time, which is
|
|
66
|
+
* exactly the thing validation time must not do: what something IS was settled
|
|
67
|
+
* at compile time. The non-wildcard route was always shaped this way.
|
|
70
68
|
*/
|
|
71
69
|
function compileNester(template) {
|
|
72
70
|
let nest = (value) => value;
|
|
@@ -57,13 +57,11 @@ function createSubjectComposer(template) {
|
|
|
57
57
|
return (siblings, value) => mergeOntoSiblings(siblings, nest(value));
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
|
-
*
|
|
60
|
+
* Walks the template **once** and folds it into a wrapping function.
|
|
61
61
|
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* 決めるのはコンパイルが済ませたこと」であり、ここはその例外になっていた。
|
|
66
|
-
* 非ワイルドカードの経路 (createValueWriter) は最初からこの形である。
|
|
62
|
+
* Walking it per validation re-read each segment's kind every time, which is
|
|
63
|
+
* exactly the thing validation time must not do: what something IS was settled
|
|
64
|
+
* at compile time. The non-wildcard route was always shaped this way.
|
|
67
65
|
*/
|
|
68
66
|
function compileNester(template) {
|
|
69
67
|
let nest = (value) => value;
|
|
@@ -40,23 +40,23 @@ function hasRejectingIssue(issues) {
|
|
|
40
40
|
return issues.some((issue) => issue.severity === "error");
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
43
|
+
* The shared do-nothing runner for a plan that cannot recurse.
|
|
44
44
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
45
|
+
* Building a real runner allocates a WeakSet and several closures. Doing that
|
|
46
|
+
* on every validate() of a plan with no recursive rule in it was most of the
|
|
47
|
+
* fixed per-call cost. Whether a plan can recurse is known at build time and
|
|
48
|
+
* is not a question to re-ask at validation time.
|
|
49
49
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
50
|
+
* Never actually called: a field only reaches its runner when it declares
|
|
51
|
+
* recursion, and a plan containing one gets the real runner instead.
|
|
52
52
|
*/
|
|
53
53
|
const NO_RECURSION = () => { };
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
55
|
+
* Whether the root needs a real runner.
|
|
56
56
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
57
|
+
* Only the fields directly under the root and the elements of array nodes
|
|
58
|
+
* matter. A composite branch makes its own runner for the nested plan, so it
|
|
59
|
+
* never uses the one passed from here.
|
|
60
60
|
*/
|
|
61
61
|
function planCanRecurse(plan) {
|
|
62
62
|
return (plan.fields.some((field) => field.recursion !== null) ||
|
|
@@ -35,23 +35,23 @@ export function hasRejectingIssue(issues) {
|
|
|
35
35
|
return issues.some((issue) => issue.severity === "error");
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
38
|
+
* The shared do-nothing runner for a plan that cannot recurse.
|
|
39
39
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
40
|
+
* Building a real runner allocates a WeakSet and several closures. Doing that
|
|
41
|
+
* on every validate() of a plan with no recursive rule in it was most of the
|
|
42
|
+
* fixed per-call cost. Whether a plan can recurse is known at build time and
|
|
43
|
+
* is not a question to re-ask at validation time.
|
|
44
44
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
45
|
+
* Never actually called: a field only reaches its runner when it declares
|
|
46
|
+
* recursion, and a plan containing one gets the real runner instead.
|
|
47
47
|
*/
|
|
48
48
|
const NO_RECURSION = () => { };
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
50
|
+
* Whether the root needs a real runner.
|
|
51
51
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
52
|
+
* Only the fields directly under the root and the elements of array nodes
|
|
53
|
+
* matter. A composite branch makes its own runner for the nested plan, so it
|
|
54
|
+
* never uses the one passed from here.
|
|
55
55
|
*/
|
|
56
56
|
function planCanRecurse(plan) {
|
|
57
57
|
return (plan.fields.some((field) => field.recursion !== null) ||
|
|
@@ -24,8 +24,12 @@ function createArrayWriteTargets(nodes) {
|
|
|
24
24
|
* hands back the very object it was given.
|
|
25
25
|
*/
|
|
26
26
|
function createPlanWriteTargets(plan) {
|
|
27
|
-
|
|
27
|
+
// A field declaring only a normalizer is still written back by parse().
|
|
28
|
+
// Leave it out of this condition and no writer is made, so the value read
|
|
29
|
+
// comes back unchanged and in silence.
|
|
30
|
+
if (!plan.hasTransforms && !plan.hasDefaults && !plan.hasNormalizers) {
|
|
28
31
|
return null;
|
|
32
|
+
}
|
|
29
33
|
return createArrayWriteTargets(plan.arrays);
|
|
30
34
|
}
|
|
31
35
|
/**
|
|
@@ -17,8 +17,12 @@ export function createArrayWriteTargets(nodes) {
|
|
|
17
17
|
* hands back the very object it was given.
|
|
18
18
|
*/
|
|
19
19
|
export function createPlanWriteTargets(plan) {
|
|
20
|
-
|
|
20
|
+
// A field declaring only a normalizer is still written back by parse().
|
|
21
|
+
// Leave it out of this condition and no writer is made, so the value read
|
|
22
|
+
// comes back unchanged and in silence.
|
|
23
|
+
if (!plan.hasTransforms && !plan.hasDefaults && !plan.hasNormalizers) {
|
|
21
24
|
return null;
|
|
25
|
+
}
|
|
22
26
|
return createArrayWriteTargets(plan.arrays);
|
|
23
27
|
}
|
|
24
28
|
/**
|
|
@@ -57,12 +57,12 @@ function runElements(node, array, context, target) {
|
|
|
57
57
|
const nodePath = node.renderedPath;
|
|
58
58
|
const elementSink = context.sink.forArrayElements();
|
|
59
59
|
const nested = target === undefined ? output_writer_1.NO_WRITE_TARGETS : target.nested;
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
60
|
+
// One element context per node. `item` is the only member that changes per
|
|
61
|
+
// element; the rest hold still for the whole node, and rebuilding them per
|
|
62
|
+
// element only happened because the fixed parts sat beside the moving one.
|
|
63
|
+
// **It never reaches a plugin** — a plugin sees the RuleContext that running
|
|
64
|
+
// a field assembles, and that reads `item` afresh, so reusing this is not
|
|
65
|
+
// observable from outside.
|
|
66
66
|
const elementContext = {
|
|
67
67
|
root: context.root,
|
|
68
68
|
sink: elementSink,
|
|
@@ -54,12 +54,12 @@ function runElements(node, array, context, target) {
|
|
|
54
54
|
const nodePath = node.renderedPath;
|
|
55
55
|
const elementSink = context.sink.forArrayElements();
|
|
56
56
|
const nested = target === undefined ? NO_WRITE_TARGETS : target.nested;
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
57
|
+
// One element context per node. `item` is the only member that changes per
|
|
58
|
+
// element; the rest hold still for the whole node, and rebuilding them per
|
|
59
|
+
// element only happened because the fixed parts sat beside the moving one.
|
|
60
|
+
// **It never reaches a plugin** — a plugin sees the RuleContext that running
|
|
61
|
+
// a field assembles, and that reads `item` afresh, so reusing this is not
|
|
62
|
+
// observable from outside.
|
|
63
63
|
const elementContext = {
|
|
64
64
|
root: context.root,
|
|
65
65
|
sink: elementSink,
|
|
@@ -12,7 +12,7 @@ exports.FIELD_VALUE_UNCHANGED = Object.freeze({
|
|
|
12
12
|
function runField(field, subject, context) {
|
|
13
13
|
const ruleContext = new field_rule_context_1.FieldRuleContext(context.root, context.indices, field.renderedPath, context.item, context.external);
|
|
14
14
|
const read = field.read(subject);
|
|
15
|
-
const value = applyDefault(field, read, context.root);
|
|
15
|
+
const value = applyNormalize(field, applyDefault(field, read, context.root));
|
|
16
16
|
if (!(0, decide_presence_1.decidePresence)(field, value, ruleContext, context.sink)) {
|
|
17
17
|
return exports.FIELD_VALUE_UNCHANGED;
|
|
18
18
|
}
|
|
@@ -40,15 +40,21 @@ function applyDefault(field, value, root) {
|
|
|
40
40
|
return field.defaultOf(root);
|
|
41
41
|
return value;
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Tidies the value before anything judges it: after default, before presence.
|
|
45
|
+
*
|
|
46
|
+
* Never called for undefined or null. That closes the accident where a
|
|
47
|
+
* caller's `(v) => String(v).trim()` turns a missing field into the string
|
|
48
|
+
* `"undefined"` and walks it past `.required()`. Absence is default's job.
|
|
49
|
+
*/
|
|
50
|
+
function applyNormalize(field, value) {
|
|
51
|
+
if (field.normalize === null || value === undefined || value === null) {
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
return field.normalize(value);
|
|
55
|
+
}
|
|
43
56
|
/** A closed gate ends the field successfully: no check, no transform. */
|
|
44
57
|
function openGates(field, value, ruleContext) {
|
|
45
|
-
// 添字ループである。for-of ではない。ここが回るのはコンパイル済みの
|
|
46
|
-
// 凍結配列で、凍結配列は V8 では PACKED_FROZEN_ELEMENTS になり、配列
|
|
47
|
-
// イテレータの高速化パスから外れる — イテレータと IteratorResult が
|
|
48
|
-
// 消去されず、要素×フィールドの回数だけ確保される。配列シェイプでは
|
|
49
|
-
// それだけで全ゴミの 45〜54% を占めていた (独立に5通りの改変で -45%
|
|
50
|
-
// 〜 -54%)。凍結は落とさない: コンパイル層の不変条件であり、凍結を
|
|
51
|
-
// 外しても添字ループより速くはならない。
|
|
52
58
|
const gates = field.gates;
|
|
53
59
|
for (let i = 0; i < gates.length; i += 1) {
|
|
54
60
|
const gate = gates[i];
|
|
@@ -60,17 +66,10 @@ function openGates(field, value, ruleContext) {
|
|
|
60
66
|
return true;
|
|
61
67
|
}
|
|
62
68
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* --trace-turbo-inlining に名指しされていた。その 302 バイトの大半が、
|
|
68
|
-
* 受理された値では一度も走らない issue の組み立てである。ここへ出すと
|
|
69
|
-
* 残るループ本体が縮み、受理パスで 6.4% 速くなった。
|
|
70
|
-
*
|
|
71
|
-
* 中断の判定はここに含めない。issue を足したあとに shouldStopField を
|
|
72
|
-
* 見るという順序が abortEarlyOnEachField の意味そのものなので、呼び出し側に
|
|
73
|
-
* 並べて置いておく。
|
|
69
|
+
* The side taken only on failure. Lifted out of the loop body because most of
|
|
70
|
+
* that body was issue construction an accepted value never runs, and its size
|
|
71
|
+
* was what pushed the check loop past the inlining budget. Stopping is not
|
|
72
|
+
* decided here: add the issue, then ask — that order is what abortEarly means.
|
|
74
73
|
*/
|
|
75
74
|
function reportCheckFailure(check, detail, value, ruleContext, context) {
|
|
76
75
|
context.sink.add((0, create_issue_1.createIssue)({
|
|
@@ -8,7 +8,7 @@ export const FIELD_VALUE_UNCHANGED = Object.freeze({
|
|
|
8
8
|
export function runField(field, subject, context) {
|
|
9
9
|
const ruleContext = new FieldRuleContext(context.root, context.indices, field.renderedPath, context.item, context.external);
|
|
10
10
|
const read = field.read(subject);
|
|
11
|
-
const value = applyDefault(field, read, context.root);
|
|
11
|
+
const value = applyNormalize(field, applyDefault(field, read, context.root));
|
|
12
12
|
if (!decidePresence(field, value, ruleContext, context.sink)) {
|
|
13
13
|
return FIELD_VALUE_UNCHANGED;
|
|
14
14
|
}
|
|
@@ -36,15 +36,21 @@ function applyDefault(field, value, root) {
|
|
|
36
36
|
return field.defaultOf(root);
|
|
37
37
|
return value;
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Tidies the value before anything judges it: after default, before presence.
|
|
41
|
+
*
|
|
42
|
+
* Never called for undefined or null. That closes the accident where a
|
|
43
|
+
* caller's `(v) => String(v).trim()` turns a missing field into the string
|
|
44
|
+
* `"undefined"` and walks it past `.required()`. Absence is default's job.
|
|
45
|
+
*/
|
|
46
|
+
function applyNormalize(field, value) {
|
|
47
|
+
if (field.normalize === null || value === undefined || value === null) {
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
return field.normalize(value);
|
|
51
|
+
}
|
|
39
52
|
/** A closed gate ends the field successfully: no check, no transform. */
|
|
40
53
|
function openGates(field, value, ruleContext) {
|
|
41
|
-
// 添字ループである。for-of ではない。ここが回るのはコンパイル済みの
|
|
42
|
-
// 凍結配列で、凍結配列は V8 では PACKED_FROZEN_ELEMENTS になり、配列
|
|
43
|
-
// イテレータの高速化パスから外れる — イテレータと IteratorResult が
|
|
44
|
-
// 消去されず、要素×フィールドの回数だけ確保される。配列シェイプでは
|
|
45
|
-
// それだけで全ゴミの 45〜54% を占めていた (独立に5通りの改変で -45%
|
|
46
|
-
// 〜 -54%)。凍結は落とさない: コンパイル層の不変条件であり、凍結を
|
|
47
|
-
// 外しても添字ループより速くはならない。
|
|
48
54
|
const gates = field.gates;
|
|
49
55
|
for (let i = 0; i < gates.length; i += 1) {
|
|
50
56
|
const gate = gates[i];
|
|
@@ -56,17 +62,10 @@ function openGates(field, value, ruleContext) {
|
|
|
56
62
|
return true;
|
|
57
63
|
}
|
|
58
64
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* --trace-turbo-inlining に名指しされていた。その 302 バイトの大半が、
|
|
64
|
-
* 受理された値では一度も走らない issue の組み立てである。ここへ出すと
|
|
65
|
-
* 残るループ本体が縮み、受理パスで 6.4% 速くなった。
|
|
66
|
-
*
|
|
67
|
-
* 中断の判定はここに含めない。issue を足したあとに shouldStopField を
|
|
68
|
-
* 見るという順序が abortEarlyOnEachField の意味そのものなので、呼び出し側に
|
|
69
|
-
* 並べて置いておく。
|
|
65
|
+
* The side taken only on failure. Lifted out of the loop body because most of
|
|
66
|
+
* that body was issue construction an accepted value never runs, and its size
|
|
67
|
+
* was what pushed the check loop past the inlining budget. Stopping is not
|
|
68
|
+
* decided here: add the issue, then ask — that order is what abortEarly means.
|
|
70
69
|
*/
|
|
71
70
|
function reportCheckFailure(check, detail, value, ruleContext, context) {
|
|
72
71
|
context.sink.add(createIssue({
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FieldDeclaredCalls } from "../builder/field-declared-calls.types";
|
|
2
|
+
import type { UnrepresentablePolicy } from "./unrepresentable-rule-error";
|
|
3
|
+
/** Assembles the root schema from the list of declarations. */
|
|
4
|
+
export declare function assembleJsonSchema(fields: readonly FieldDeclaredCalls[], policy: UnrepresentablePolicy): Record<string, unknown>;
|