@maroonedog/luq 2.4.1 → 2.4.3
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/dist/builder/compile-declarations.d.ts +7 -1
- package/dist/builder/compile-declarations.js +1 -0
- package/dist/builder/compile-declarations.mjs +1 -0
- package/dist/builder/create-field-builder.js +1 -1
- package/dist/builder/create-field-builder.mjs +1 -1
- package/dist/builder/create-plan-validator.d.ts +2 -1
- package/dist/builder/create-plan-validator.js +2 -2
- package/dist/builder/create-plan-validator.mjs +2 -2
- package/dist/runtime/create-validator.d.ts +12 -4
- package/dist/runtime/create-validator.js +22 -11
- package/dist/runtime/create-validator.mjs +21 -10
- package/dist/runtime/index-stack.d.ts +10 -1
- package/dist/runtime/index-stack.js +19 -3
- package/dist/runtime/index-stack.mjs +19 -3
- package/dist/runtime/index.d.ts +2 -2
- package/dist/runtime/index.js +1 -3
- package/dist/runtime/index.mjs +2 -2
- package/dist/runtime/run-branch.js +8 -3
- package/dist/runtime/run-branch.mjs +9 -4
- package/dist/runtime/run-plan.d.ts +5 -11
- package/dist/runtime/run-plan.js +5 -21
- package/dist/runtime/run-plan.mjs +5 -20
- package/dist/runtime/run-recursion.js +9 -7
- package/dist/runtime/run-recursion.mjs +10 -8
- package/dist/types/global-config.d.ts +12 -0
- package/dist/types/global-config.js +2 -0
- package/dist/types/global-config.mjs +2 -0
- package/package.json +1 -1
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { ValidationPlan } from "../compile/validation-plan.types";
|
|
2
|
-
import type { GlobalConfig } from "../types/global-config";
|
|
2
|
+
import type { GlobalConfig, ResolvedGlobalConfig } from "../types/global-config";
|
|
3
3
|
import type { FieldEntry } from "./field-entry.types";
|
|
4
4
|
import type { FieldDeclaredCalls } from "./field-declared-calls.types";
|
|
5
5
|
/** What build() makes in one pass: the plan to run, and what was declared. */
|
|
6
6
|
export interface CompiledDeclarations {
|
|
7
7
|
readonly plan: ValidationPlan;
|
|
8
8
|
readonly declaredCalls: readonly FieldDeclaredCalls[];
|
|
9
|
+
/**
|
|
10
|
+
* Resolved once here, and carried out because the root short-circuit needs
|
|
11
|
+
* it too. That rejection happens before any rule, so it cannot read the
|
|
12
|
+
* config the way a plugin does — through RuleBuildContext.
|
|
13
|
+
*/
|
|
14
|
+
readonly config: ResolvedGlobalConfig;
|
|
9
15
|
}
|
|
10
16
|
export declare function compileDeclarations(entries: readonly FieldEntry[], configOverride: GlobalConfig | undefined): CompiledDeclarations;
|
|
@@ -27,7 +27,7 @@ const NO_ENTRIES = Object.freeze([]);
|
|
|
27
27
|
*/
|
|
28
28
|
function buildValidator(entries, configOverride) {
|
|
29
29
|
const compiled = (0, compile_declarations_1.compileDeclarations)(entries, configOverride);
|
|
30
|
-
const validator = (0, create_plan_validator_1.createPlanBackedValidator)(compiled.plan);
|
|
30
|
+
const validator = (0, create_plan_validator_1.createPlanBackedValidator)(compiled.plan, compiled.config);
|
|
31
31
|
(0, declared_calls_store_1.rememberDeclaredCalls)(validator, compiled.declaredCalls);
|
|
32
32
|
return validator;
|
|
33
33
|
}
|
|
@@ -24,7 +24,7 @@ const NO_ENTRIES = Object.freeze([]);
|
|
|
24
24
|
*/
|
|
25
25
|
function buildValidator(entries, configOverride) {
|
|
26
26
|
const compiled = compileDeclarations(entries, configOverride);
|
|
27
|
-
const validator = createPlanBackedValidator(compiled.plan);
|
|
27
|
+
const validator = createPlanBackedValidator(compiled.plan, compiled.config);
|
|
28
28
|
rememberDeclaredCalls(validator, compiled.declaredCalls);
|
|
29
29
|
return validator;
|
|
30
30
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { ValidationPlan } from "../compile/validation-plan.types";
|
|
2
|
+
import type { ResolvedGlobalConfig } from "../types/global-config";
|
|
2
3
|
import type { PlanBackedValidator } from "./builder-surface.types";
|
|
3
|
-
export declare function createPlanBackedValidator(plan: ValidationPlan): PlanBackedValidator;
|
|
4
|
+
export declare function createPlanBackedValidator(plan: ValidationPlan, config: ResolvedGlobalConfig): PlanBackedValidator;
|
|
@@ -4,8 +4,8 @@ exports.createPlanBackedValidator = createPlanBackedValidator;
|
|
|
4
4
|
const create_field_validator_1 = require("../runtime/create-field-validator");
|
|
5
5
|
const create_validator_1 = require("../runtime/create-validator");
|
|
6
6
|
const create_subset_validator_1 = require("./create-subset-validator");
|
|
7
|
-
function createPlanBackedValidator(plan) {
|
|
8
|
-
const validator = (0, create_validator_1.createValidator)(plan);
|
|
7
|
+
function createPlanBackedValidator(plan, config) {
|
|
8
|
+
const validator = (0, create_validator_1.createValidator)(plan, config);
|
|
9
9
|
return Object.freeze({
|
|
10
10
|
validate: validator.validate,
|
|
11
11
|
parse: validator.parse,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createFieldValidator } from "../runtime/create-field-validator.mjs";
|
|
2
2
|
import { createValidator } from "../runtime/create-validator.mjs";
|
|
3
3
|
import { createSubsetValidator } from "./create-subset-validator.mjs";
|
|
4
|
-
export function createPlanBackedValidator(plan) {
|
|
5
|
-
const validator = createValidator(plan);
|
|
4
|
+
export function createPlanBackedValidator(plan, config) {
|
|
5
|
+
const validator = createValidator(plan, config);
|
|
6
6
|
return Object.freeze({
|
|
7
7
|
validate: validator.validate,
|
|
8
8
|
parse: validator.parse,
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import type { ValidationIssue } from "../types";
|
|
2
2
|
import type { ValidateOptions, ValidationResult } from "../types/validation-result.types";
|
|
3
3
|
import type { ValidationPlan } from "../compile/validation-plan.types";
|
|
4
|
+
import { type ResolvedGlobalConfig } from "../types/global-config";
|
|
4
5
|
/** The untyped pair. L6 puts the declared type back on top of it. */
|
|
5
6
|
export interface PlanValidator {
|
|
6
7
|
validate(value: unknown, options?: ValidateOptions): ValidationResult<unknown>;
|
|
7
8
|
parse(value: unknown, options?: ValidateOptions): ValidationResult<unknown>;
|
|
8
9
|
}
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* The code an absent SUBJECT reports.
|
|
12
|
+
*
|
|
13
|
+
* The same spelling a missing FIELD reports, deliberately. It was "REQUIRED"
|
|
14
|
+
* — 1.x's SCREAMING_SNAKE, carried over with the wording — which meant a
|
|
15
|
+
* caller switching on issue.code handled `required` for a missing field and
|
|
16
|
+
* missed the root, where the only difference is how much of the value was
|
|
17
|
+
* absent.
|
|
18
|
+
*/
|
|
19
|
+
export declare const ROOT_MISSING_CODE = "required";
|
|
12
20
|
/**
|
|
13
21
|
* Severity decides validity, and nothing else does. An `info` or `warning`
|
|
14
22
|
* issue is still an issue — the sink counted it and abortEarly saw it — but it
|
|
@@ -16,4 +24,4 @@ export declare const ROOT_MISSING_MESSAGE = "Value is required";
|
|
|
16
24
|
* an `issues` list at all.
|
|
17
25
|
*/
|
|
18
26
|
export declare function hasRejectingIssue(issues: readonly ValidationIssue[]): boolean;
|
|
19
|
-
export declare function createValidator(plan: ValidationPlan): PlanValidator;
|
|
27
|
+
export declare function createValidator(plan: ValidationPlan, config?: ResolvedGlobalConfig): PlanValidator;
|
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.ROOT_MISSING_CODE = void 0;
|
|
4
4
|
exports.hasRejectingIssue = hasRejectingIssue;
|
|
5
5
|
exports.createValidator = createValidator;
|
|
6
|
+
const global_config_1 = require("../types/global-config");
|
|
6
7
|
const index_stack_1 = require("./index-stack");
|
|
7
8
|
const issue_sink_1 = require("./issue-sink");
|
|
8
9
|
const output_writer_1 = require("./output-writer");
|
|
9
10
|
const run_recursion_1 = require("./run-recursion");
|
|
10
11
|
const run_plan_1 = require("./run-plan");
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The code an absent SUBJECT reports.
|
|
14
|
+
*
|
|
15
|
+
* The same spelling a missing FIELD reports, deliberately. It was "REQUIRED"
|
|
16
|
+
* — 1.x's SCREAMING_SNAKE, carried over with the wording — which meant a
|
|
17
|
+
* caller switching on issue.code handled `required` for a missing field and
|
|
18
|
+
* missed the root, where the only difference is how much of the value was
|
|
19
|
+
* absent.
|
|
20
|
+
*/
|
|
21
|
+
exports.ROOT_MISSING_CODE = "required";
|
|
14
22
|
/**
|
|
15
23
|
* A null or undefined subject fails before the plan runs. Without it every
|
|
16
24
|
* reader would answer `undefined`, OPEN_PRESENCE would permit every absence,
|
|
17
25
|
* and `validate(null)` would report success for a schema that declares nothing
|
|
18
26
|
* required.
|
|
19
27
|
*/
|
|
20
|
-
function rejectMissingRoot() {
|
|
28
|
+
function rejectMissingRoot(config) {
|
|
21
29
|
return {
|
|
22
30
|
valid: false,
|
|
23
31
|
issues: Object.freeze([
|
|
24
32
|
Object.freeze({
|
|
25
33
|
path: "",
|
|
26
34
|
code: exports.ROOT_MISSING_CODE,
|
|
27
|
-
message:
|
|
35
|
+
message: config.rootMissingMessage,
|
|
36
|
+
// Not config.defaultSeverity. A warning here would let validate(null)
|
|
37
|
+
// report success for a schema that declares nothing required, which is
|
|
38
|
+
// the outcome this rejection exists to prevent.
|
|
28
39
|
severity: "error",
|
|
29
40
|
}),
|
|
30
41
|
]),
|
|
@@ -66,9 +77,9 @@ function nodeCanRecurse(node) {
|
|
|
66
77
|
return (node.elementFields.some((field) => field.recursion !== null) ||
|
|
67
78
|
node.nested.some(nodeCanRecurse));
|
|
68
79
|
}
|
|
69
|
-
function runRoot(plan, value, options, targets, shouldApplyTransforms, canRecurse) {
|
|
80
|
+
function runRoot(plan, config, value, options, targets, shouldApplyTransforms, canRecurse) {
|
|
70
81
|
if (value === null || value === undefined)
|
|
71
|
-
return rejectMissingRoot();
|
|
82
|
+
return rejectMissingRoot(config);
|
|
72
83
|
const sink = new issue_sink_1.IssueSink((0, issue_sink_1.resolveAbortPolicy)(options));
|
|
73
84
|
const output = (0, run_plan_1.runPlan)(plan, value, {
|
|
74
85
|
root: value,
|
|
@@ -89,12 +100,12 @@ function runRoot(plan, value, options, targets, shouldApplyTransforms, canRecurs
|
|
|
89
100
|
return { valid: false, issues };
|
|
90
101
|
return { valid: true, data: output, issues };
|
|
91
102
|
}
|
|
92
|
-
function createValidator(plan) {
|
|
103
|
+
function createValidator(plan, config = global_config_1.DEFAULT_GLOBAL_CONFIG) {
|
|
93
104
|
const parseTargets = (0, output_writer_1.createPlanWriteTargets)(plan);
|
|
94
105
|
const shouldWriteOutput = parseTargets !== null;
|
|
95
106
|
const canRecurse = planCanRecurse(plan);
|
|
96
107
|
return {
|
|
97
|
-
validate: (value, options) => runRoot(plan, value, options, output_writer_1.NO_WRITE_TARGETS, false, canRecurse),
|
|
98
|
-
parse: (value, options) => runRoot(plan, value, options, parseTargets ?? output_writer_1.NO_WRITE_TARGETS, shouldWriteOutput, canRecurse),
|
|
108
|
+
validate: (value, options) => runRoot(plan, config, value, options, output_writer_1.NO_WRITE_TARGETS, false, canRecurse),
|
|
109
|
+
parse: (value, options) => runRoot(plan, config, value, options, parseTargets ?? output_writer_1.NO_WRITE_TARGETS, shouldWriteOutput, canRecurse),
|
|
99
110
|
};
|
|
100
111
|
}
|
|
@@ -1,25 +1,36 @@
|
|
|
1
|
+
import { DEFAULT_GLOBAL_CONFIG, } from "../types/global-config.mjs";
|
|
1
2
|
import { IndexStack } from "./index-stack.mjs";
|
|
2
3
|
import { IssueSink, resolveAbortPolicy } from "./issue-sink.mjs";
|
|
3
4
|
import { NO_WRITE_TARGETS, createPlanWriteTargets } from "./output-writer.mjs";
|
|
4
5
|
import { createRecursionRunner } from "./run-recursion.mjs";
|
|
5
6
|
import { runPlan } from "./run-plan.mjs";
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* The code an absent SUBJECT reports.
|
|
9
|
+
*
|
|
10
|
+
* The same spelling a missing FIELD reports, deliberately. It was "REQUIRED"
|
|
11
|
+
* — 1.x's SCREAMING_SNAKE, carried over with the wording — which meant a
|
|
12
|
+
* caller switching on issue.code handled `required` for a missing field and
|
|
13
|
+
* missed the root, where the only difference is how much of the value was
|
|
14
|
+
* absent.
|
|
15
|
+
*/
|
|
16
|
+
export const ROOT_MISSING_CODE = "required";
|
|
9
17
|
/**
|
|
10
18
|
* A null or undefined subject fails before the plan runs. Without it every
|
|
11
19
|
* reader would answer `undefined`, OPEN_PRESENCE would permit every absence,
|
|
12
20
|
* and `validate(null)` would report success for a schema that declares nothing
|
|
13
21
|
* required.
|
|
14
22
|
*/
|
|
15
|
-
function rejectMissingRoot() {
|
|
23
|
+
function rejectMissingRoot(config) {
|
|
16
24
|
return {
|
|
17
25
|
valid: false,
|
|
18
26
|
issues: Object.freeze([
|
|
19
27
|
Object.freeze({
|
|
20
28
|
path: "",
|
|
21
29
|
code: ROOT_MISSING_CODE,
|
|
22
|
-
message:
|
|
30
|
+
message: config.rootMissingMessage,
|
|
31
|
+
// Not config.defaultSeverity. A warning here would let validate(null)
|
|
32
|
+
// report success for a schema that declares nothing required, which is
|
|
33
|
+
// the outcome this rejection exists to prevent.
|
|
23
34
|
severity: "error",
|
|
24
35
|
}),
|
|
25
36
|
]),
|
|
@@ -61,9 +72,9 @@ function nodeCanRecurse(node) {
|
|
|
61
72
|
return (node.elementFields.some((field) => field.recursion !== null) ||
|
|
62
73
|
node.nested.some(nodeCanRecurse));
|
|
63
74
|
}
|
|
64
|
-
function runRoot(plan, value, options, targets, shouldApplyTransforms, canRecurse) {
|
|
75
|
+
function runRoot(plan, config, value, options, targets, shouldApplyTransforms, canRecurse) {
|
|
65
76
|
if (value === null || value === undefined)
|
|
66
|
-
return rejectMissingRoot();
|
|
77
|
+
return rejectMissingRoot(config);
|
|
67
78
|
const sink = new IssueSink(resolveAbortPolicy(options));
|
|
68
79
|
const output = runPlan(plan, value, {
|
|
69
80
|
root: value,
|
|
@@ -84,12 +95,12 @@ function runRoot(plan, value, options, targets, shouldApplyTransforms, canRecurs
|
|
|
84
95
|
return { valid: false, issues };
|
|
85
96
|
return { valid: true, data: output, issues };
|
|
86
97
|
}
|
|
87
|
-
export function createValidator(plan) {
|
|
98
|
+
export function createValidator(plan, config = DEFAULT_GLOBAL_CONFIG) {
|
|
88
99
|
const parseTargets = createPlanWriteTargets(plan);
|
|
89
100
|
const shouldWriteOutput = parseTargets !== null;
|
|
90
101
|
const canRecurse = planCanRecurse(plan);
|
|
91
102
|
return {
|
|
92
|
-
validate: (value, options) => runRoot(plan, value, options, NO_WRITE_TARGETS, false, canRecurse),
|
|
93
|
-
parse: (value, options) => runRoot(plan, value, options, parseTargets ?? NO_WRITE_TARGETS, shouldWriteOutput, canRecurse),
|
|
103
|
+
validate: (value, options) => runRoot(plan, config, value, options, NO_WRITE_TARGETS, false, canRecurse),
|
|
104
|
+
parse: (value, options) => runRoot(plan, config, value, options, parseTargets ?? NO_WRITE_TARGETS, shouldWriteOutput, canRecurse),
|
|
94
105
|
};
|
|
95
106
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare class IndexStack {
|
|
2
|
+
private readonly basePath;
|
|
2
3
|
private readonly nodePaths;
|
|
3
4
|
private readonly openIndices;
|
|
4
5
|
/**
|
|
@@ -10,6 +11,11 @@ export declare class IndexStack {
|
|
|
10
11
|
* raises no issue never renders its own prefix at all.
|
|
11
12
|
*/
|
|
12
13
|
private currentPrefix;
|
|
14
|
+
/**
|
|
15
|
+
* Where this run sits inside the whole value: `""` for the run the caller
|
|
16
|
+
* started, and the entering rule's path for a branch or a recursive re-entry.
|
|
17
|
+
*/
|
|
18
|
+
constructor(basePath?: string);
|
|
13
19
|
/** How many array levels are currently open. */
|
|
14
20
|
get depth(): number;
|
|
15
21
|
/** The open indices, outermost first: `[0, 2]` inside `grid[0][2]`. */
|
|
@@ -25,7 +31,10 @@ export declare class IndexStack {
|
|
|
25
31
|
* it took 12% of the array shape's self time.
|
|
26
32
|
*/
|
|
27
33
|
private readTop;
|
|
28
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* `""` at the root of the run the caller started, `items[0]` inside the first
|
|
36
|
+
* element of `items`, and the base path when a nested run has no array open.
|
|
37
|
+
*/
|
|
29
38
|
get prefix(): string;
|
|
30
39
|
/**
|
|
31
40
|
* Enters element `index` of an array node. `nodePath` is the node's own path
|
|
@@ -25,12 +25,25 @@
|
|
|
25
25
|
// stack lives for one validate() call, and 10k elements must not allocate 10k
|
|
26
26
|
// index arrays. It is also why FieldRuleContext remembers the path it built —
|
|
27
27
|
// this stack has moved on by the time a retained context could read it.
|
|
28
|
+
//
|
|
29
|
+
// A NESTED run starts from a BASE PATH rather than from the root. A branch plan
|
|
30
|
+
// and a recursive re-entry each declare their fields against their own subject,
|
|
31
|
+
// so a field renders `name` where the consumer must read `user.name`. The base
|
|
32
|
+
// is handed to the stack, so the path is right the first time it is built — and
|
|
33
|
+
// the message, which is rendered from that same path, names the field the issue
|
|
34
|
+
// reports. Rewriting the path afterwards cannot do that: by then the message has
|
|
35
|
+
// already been rendered against the short one.
|
|
28
36
|
// ===========================================================================
|
|
29
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
38
|
exports.IndexStack = void 0;
|
|
31
39
|
exports.joinIssuePath = joinIssuePath;
|
|
32
40
|
class IndexStack {
|
|
33
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Where this run sits inside the whole value: `""` for the run the caller
|
|
43
|
+
* started, and the entering rule's path for a branch or a recursive re-entry.
|
|
44
|
+
*/
|
|
45
|
+
constructor(basePath = "") {
|
|
46
|
+
this.basePath = basePath;
|
|
34
47
|
this.nodePaths = [];
|
|
35
48
|
this.openIndices = [];
|
|
36
49
|
/**
|
|
@@ -65,7 +78,7 @@ class IndexStack {
|
|
|
65
78
|
const already = this.currentPrefix;
|
|
66
79
|
if (already !== null)
|
|
67
80
|
return already;
|
|
68
|
-
let built =
|
|
81
|
+
let built = this.basePath;
|
|
69
82
|
for (let i = 0; i < this.nodePaths.length; i += 1) {
|
|
70
83
|
const nodePath = this.nodePaths[i];
|
|
71
84
|
const index = this.openIndices[i];
|
|
@@ -76,7 +89,10 @@ class IndexStack {
|
|
|
76
89
|
this.currentPrefix = built;
|
|
77
90
|
return built;
|
|
78
91
|
}
|
|
79
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* `""` at the root of the run the caller started, `items[0]` inside the first
|
|
94
|
+
* element of `items`, and the base path when a nested run has no array open.
|
|
95
|
+
*/
|
|
80
96
|
get prefix() {
|
|
81
97
|
return this.readTop();
|
|
82
98
|
}
|
|
@@ -24,9 +24,22 @@
|
|
|
24
24
|
// stack lives for one validate() call, and 10k elements must not allocate 10k
|
|
25
25
|
// index arrays. It is also why FieldRuleContext remembers the path it built —
|
|
26
26
|
// this stack has moved on by the time a retained context could read it.
|
|
27
|
+
//
|
|
28
|
+
// A NESTED run starts from a BASE PATH rather than from the root. A branch plan
|
|
29
|
+
// and a recursive re-entry each declare their fields against their own subject,
|
|
30
|
+
// so a field renders `name` where the consumer must read `user.name`. The base
|
|
31
|
+
// is handed to the stack, so the path is right the first time it is built — and
|
|
32
|
+
// the message, which is rendered from that same path, names the field the issue
|
|
33
|
+
// reports. Rewriting the path afterwards cannot do that: by then the message has
|
|
34
|
+
// already been rendered against the short one.
|
|
27
35
|
// ===========================================================================
|
|
28
36
|
export class IndexStack {
|
|
29
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Where this run sits inside the whole value: `""` for the run the caller
|
|
39
|
+
* started, and the entering rule's path for a branch or a recursive re-entry.
|
|
40
|
+
*/
|
|
41
|
+
constructor(basePath = "") {
|
|
42
|
+
this.basePath = basePath;
|
|
30
43
|
this.nodePaths = [];
|
|
31
44
|
this.openIndices = [];
|
|
32
45
|
/**
|
|
@@ -61,7 +74,7 @@ export class IndexStack {
|
|
|
61
74
|
const already = this.currentPrefix;
|
|
62
75
|
if (already !== null)
|
|
63
76
|
return already;
|
|
64
|
-
let built =
|
|
77
|
+
let built = this.basePath;
|
|
65
78
|
for (let i = 0; i < this.nodePaths.length; i += 1) {
|
|
66
79
|
const nodePath = this.nodePaths[i];
|
|
67
80
|
const index = this.openIndices[i];
|
|
@@ -72,7 +85,10 @@ export class IndexStack {
|
|
|
72
85
|
this.currentPrefix = built;
|
|
73
86
|
return built;
|
|
74
87
|
}
|
|
75
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* `""` at the root of the run the caller started, `items[0]` inside the first
|
|
90
|
+
* element of `items`, and the base path when a nested run has no array open.
|
|
91
|
+
*/
|
|
76
92
|
get prefix() {
|
|
77
93
|
return this.readTop();
|
|
78
94
|
}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -9,11 +9,11 @@ export type { FieldRunContext, FieldRunOutcome, RecursionRunner, } from "./run-f
|
|
|
9
9
|
export { NO_WRITE_TARGETS, createArrayWriteTargets, createPlanWriteTargets, replaceElement, writeFieldValue, } from "./output-writer";
|
|
10
10
|
export type { ArrayWriteTarget } from "./output-writer";
|
|
11
11
|
export { runArrayNodes } from "./run-array-node";
|
|
12
|
-
export {
|
|
12
|
+
export { runPlan } from "./run-plan";
|
|
13
13
|
export { RECURSION_ABORT_POLICY, createRecursionRunner } from "./run-recursion";
|
|
14
14
|
export type { RecursionHost } from "./run-recursion";
|
|
15
15
|
export { BRANCH_ABORT_POLICY, createBranchExecutor } from "./run-branch";
|
|
16
|
-
export { ROOT_MISSING_CODE,
|
|
16
|
+
export { ROOT_MISSING_CODE, createValidator, hasRejectingIssue, } from "./create-validator";
|
|
17
17
|
export type { PlanValidator } from "./create-validator";
|
|
18
18
|
export { createFieldValidator } from "./create-field-validator";
|
|
19
19
|
export type { PlanFieldValidator } from "./create-field-validator";
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createFieldValidator = exports.hasRejectingIssue = exports.createValidator = exports.
|
|
3
|
+
exports.createFieldValidator = exports.hasRejectingIssue = exports.createValidator = exports.ROOT_MISSING_CODE = exports.createBranchExecutor = exports.BRANCH_ABORT_POLICY = exports.createRecursionRunner = exports.RECURSION_ABORT_POLICY = exports.runPlan = exports.runArrayNodes = exports.writeFieldValue = exports.replaceElement = exports.createPlanWriteTargets = exports.createArrayWriteTargets = exports.NO_WRITE_TARGETS = exports.runField = exports.FIELD_VALUE_UNCHANGED = exports.decidePresence = exports.renderFallbackMessage = exports.createIssue = exports.joinIssuePath = exports.IndexStack = exports.resolveAbortPolicy = exports.IssueSink = exports.DEFAULT_ABORT_EARLY_ON_EACH_FIELD = exports.DEFAULT_ABORT_EARLY = exports.ARRAY_ELEMENTS_ABORT_ON_EACH_FIELD = void 0;
|
|
4
4
|
// ===========================================================================
|
|
5
5
|
// L5 src/runtime/index.ts — re-exports only. The engine: one plan in, issues
|
|
6
6
|
// and (for parse) a copy-on-write output out. Nothing is defined in this file.
|
|
@@ -31,7 +31,6 @@ Object.defineProperty(exports, "writeFieldValue", { enumerable: true, get: funct
|
|
|
31
31
|
var run_array_node_1 = require("./run-array-node");
|
|
32
32
|
Object.defineProperty(exports, "runArrayNodes", { enumerable: true, get: function () { return run_array_node_1.runArrayNodes; } });
|
|
33
33
|
var run_plan_1 = require("./run-plan");
|
|
34
|
-
Object.defineProperty(exports, "prefixIssuePaths", { enumerable: true, get: function () { return run_plan_1.prefixIssuePaths; } });
|
|
35
34
|
Object.defineProperty(exports, "runPlan", { enumerable: true, get: function () { return run_plan_1.runPlan; } });
|
|
36
35
|
var run_recursion_1 = require("./run-recursion");
|
|
37
36
|
Object.defineProperty(exports, "RECURSION_ABORT_POLICY", { enumerable: true, get: function () { return run_recursion_1.RECURSION_ABORT_POLICY; } });
|
|
@@ -41,7 +40,6 @@ Object.defineProperty(exports, "BRANCH_ABORT_POLICY", { enumerable: true, get: f
|
|
|
41
40
|
Object.defineProperty(exports, "createBranchExecutor", { enumerable: true, get: function () { return run_branch_1.createBranchExecutor; } });
|
|
42
41
|
var create_validator_1 = require("./create-validator");
|
|
43
42
|
Object.defineProperty(exports, "ROOT_MISSING_CODE", { enumerable: true, get: function () { return create_validator_1.ROOT_MISSING_CODE; } });
|
|
44
|
-
Object.defineProperty(exports, "ROOT_MISSING_MESSAGE", { enumerable: true, get: function () { return create_validator_1.ROOT_MISSING_MESSAGE; } });
|
|
45
43
|
Object.defineProperty(exports, "createValidator", { enumerable: true, get: function () { return create_validator_1.createValidator; } });
|
|
46
44
|
Object.defineProperty(exports, "hasRejectingIssue", { enumerable: true, get: function () { return create_validator_1.hasRejectingIssue; } });
|
|
47
45
|
var create_field_validator_1 = require("./create-field-validator");
|
package/dist/runtime/index.mjs
CHANGED
|
@@ -9,8 +9,8 @@ export { decidePresence } from "./decide-presence.mjs";
|
|
|
9
9
|
export { FIELD_VALUE_UNCHANGED, runField } from "./run-field.mjs";
|
|
10
10
|
export { NO_WRITE_TARGETS, createArrayWriteTargets, createPlanWriteTargets, replaceElement, writeFieldValue, } from "./output-writer.mjs";
|
|
11
11
|
export { runArrayNodes } from "./run-array-node.mjs";
|
|
12
|
-
export {
|
|
12
|
+
export { runPlan } from "./run-plan.mjs";
|
|
13
13
|
export { RECURSION_ABORT_POLICY, createRecursionRunner } from "./run-recursion.mjs";
|
|
14
14
|
export { BRANCH_ABORT_POLICY, createBranchExecutor } from "./run-branch.mjs";
|
|
15
|
-
export { ROOT_MISSING_CODE,
|
|
15
|
+
export { ROOT_MISSING_CODE, createValidator, hasRejectingIssue, } from "./create-validator.mjs";
|
|
16
16
|
export { createFieldValidator } from "./create-field-validator.mjs";
|
|
@@ -48,7 +48,13 @@ function createBranchExecutor() {
|
|
|
48
48
|
(0, run_plan_1.runPlan)(plan, value, {
|
|
49
49
|
root: ruleContext.root,
|
|
50
50
|
sink,
|
|
51
|
-
|
|
51
|
+
// The branch plan's fields are declared against the branch's own
|
|
52
|
+
// subject, so a field of it renders `name` while the consumer must read
|
|
53
|
+
// `user.name`. Starting the stack at the composite's path is what makes
|
|
54
|
+
// the cause's message agree with the cause's path: both come from here,
|
|
55
|
+
// and a message rendered against the short path could not be corrected
|
|
56
|
+
// afterwards.
|
|
57
|
+
indices: new index_stack_1.IndexStack(ruleContext.path),
|
|
52
58
|
shouldApplyTransforms: false,
|
|
53
59
|
runRecursion: (0, run_recursion_1.createRecursionRunner)({
|
|
54
60
|
root: ruleContext.root,
|
|
@@ -60,8 +66,7 @@ function createBranchExecutor() {
|
|
|
60
66
|
});
|
|
61
67
|
if (sink.count === 0)
|
|
62
68
|
return types_1.PASS;
|
|
63
|
-
|
|
64
|
-
return (0, types_1.fail)({ causes: Object.freeze(causes) });
|
|
69
|
+
return (0, types_1.fail)({ causes: Object.freeze(sink.issues) });
|
|
65
70
|
},
|
|
66
71
|
};
|
|
67
72
|
}
|
|
@@ -22,7 +22,7 @@ import { PASS, fail } from "../types/index.mjs";
|
|
|
22
22
|
import { IndexStack } from "./index-stack.mjs";
|
|
23
23
|
import { IssueSink } from "./issue-sink.mjs";
|
|
24
24
|
import { createRecursionRunner } from "./run-recursion.mjs";
|
|
25
|
-
import {
|
|
25
|
+
import { runPlan } from "./run-plan.mjs";
|
|
26
26
|
/**
|
|
27
27
|
* A branch is a decision, not a report: the first failure already answers it,
|
|
28
28
|
* so both aborts stay on. Collecting every issue of every alternative of a
|
|
@@ -44,7 +44,13 @@ export function createBranchExecutor() {
|
|
|
44
44
|
runPlan(plan, value, {
|
|
45
45
|
root: ruleContext.root,
|
|
46
46
|
sink,
|
|
47
|
-
|
|
47
|
+
// The branch plan's fields are declared against the branch's own
|
|
48
|
+
// subject, so a field of it renders `name` while the consumer must read
|
|
49
|
+
// `user.name`. Starting the stack at the composite's path is what makes
|
|
50
|
+
// the cause's message agree with the cause's path: both come from here,
|
|
51
|
+
// and a message rendered against the short path could not be corrected
|
|
52
|
+
// afterwards.
|
|
53
|
+
indices: new IndexStack(ruleContext.path),
|
|
48
54
|
shouldApplyTransforms: false,
|
|
49
55
|
runRecursion: createRecursionRunner({
|
|
50
56
|
root: ruleContext.root,
|
|
@@ -56,8 +62,7 @@ export function createBranchExecutor() {
|
|
|
56
62
|
});
|
|
57
63
|
if (sink.count === 0)
|
|
58
64
|
return PASS;
|
|
59
|
-
|
|
60
|
-
return fail({ causes: Object.freeze(causes) });
|
|
65
|
+
return fail({ causes: Object.freeze(sink.issues) });
|
|
61
66
|
},
|
|
62
67
|
};
|
|
63
68
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ValidationIssue } from "../types";
|
|
2
1
|
import type { ValidationPlan } from "../compile/validation-plan.types";
|
|
3
2
|
import type { FieldRunContext } from "./run-field";
|
|
4
3
|
import type { ArrayWriteTarget } from "./output-writer";
|
|
@@ -15,14 +14,9 @@ import type { ArrayWriteTarget } from "./output-writer";
|
|
|
15
14
|
*/
|
|
16
15
|
export declare function runPlan(plan: ValidationPlan, subject: unknown, context: FieldRunContext, targets?: readonly ArrayWriteTarget[]): unknown;
|
|
17
16
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* It lives here because both callers already depend on this module and neither
|
|
25
|
-
* may depend on the other — run-branch creates a recursion runner, so
|
|
26
|
-
* run-recursion could not own it without a cycle.
|
|
17
|
+
* A nested plan does NOT come back to have its issue paths corrected. A branch
|
|
18
|
+
* and a recursive re-entry each start their IndexStack at the entering rule's
|
|
19
|
+
* path, so every issue is built at its full path and its message is rendered
|
|
20
|
+
* from that same path. Rewriting the path afterwards used to leave the message
|
|
21
|
+
* naming the field's short name, so one issue reported two different fields.
|
|
27
22
|
*/
|
|
28
|
-
export declare function prefixIssuePaths(prefix: string, issues: readonly ValidationIssue[]): readonly ValidationIssue[];
|
package/dist/runtime/run-plan.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.runPlan = runPlan;
|
|
4
|
-
exports.prefixIssuePaths = prefixIssuePaths;
|
|
5
|
-
const index_stack_1 = require("./index-stack");
|
|
6
4
|
const run_array_node_1 = require("./run-array-node");
|
|
7
5
|
const run_field_1 = require("./run-field");
|
|
8
6
|
const output_writer_1 = require("./output-writer");
|
|
@@ -32,23 +30,9 @@ function runPlan(plan, subject, context, targets = output_writer_1.NO_WRITE_TARG
|
|
|
32
30
|
return (0, run_array_node_1.runArrayNodes)(plan.arrays, current, context, targets);
|
|
33
31
|
}
|
|
34
32
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* It lives here because both callers already depend on this module and neither
|
|
42
|
-
* may depend on the other — run-branch creates a recursion runner, so
|
|
43
|
-
* run-recursion could not own it without a cycle.
|
|
33
|
+
* A nested plan does NOT come back to have its issue paths corrected. A branch
|
|
34
|
+
* and a recursive re-entry each start their IndexStack at the entering rule's
|
|
35
|
+
* path, so every issue is built at its full path and its message is rendered
|
|
36
|
+
* from that same path. Rewriting the path afterwards used to leave the message
|
|
37
|
+
* naming the field's short name, so one issue reported two different fields.
|
|
44
38
|
*/
|
|
45
|
-
function prefixIssuePaths(prefix, issues) {
|
|
46
|
-
if (prefix === "")
|
|
47
|
-
return issues;
|
|
48
|
-
return issues.map((issue) => Object.freeze({
|
|
49
|
-
path: (0, index_stack_1.joinIssuePath)(prefix, issue.path),
|
|
50
|
-
code: issue.code,
|
|
51
|
-
message: issue.message,
|
|
52
|
-
severity: issue.severity,
|
|
53
|
-
}));
|
|
54
|
-
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { joinIssuePath } from "./index-stack.mjs";
|
|
2
1
|
import { runArrayNodes } from "./run-array-node.mjs";
|
|
3
2
|
import { runField } from "./run-field.mjs";
|
|
4
3
|
import { NO_WRITE_TARGETS, writeFieldValue } from "./output-writer.mjs";
|
|
@@ -28,23 +27,9 @@ export function runPlan(plan, subject, context, targets = NO_WRITE_TARGETS) {
|
|
|
28
27
|
return runArrayNodes(plan.arrays, current, context, targets);
|
|
29
28
|
}
|
|
30
29
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* It lives here because both callers already depend on this module and neither
|
|
38
|
-
* may depend on the other — run-branch creates a recursion runner, so
|
|
39
|
-
* run-recursion could not own it without a cycle.
|
|
30
|
+
* A nested plan does NOT come back to have its issue paths corrected. A branch
|
|
31
|
+
* and a recursive re-entry each start their IndexStack at the entering rule's
|
|
32
|
+
* path, so every issue is built at its full path and its message is rendered
|
|
33
|
+
* from that same path. Rewriting the path afterwards used to leave the message
|
|
34
|
+
* naming the field's short name, so one issue reported two different fields.
|
|
40
35
|
*/
|
|
41
|
-
export function prefixIssuePaths(prefix, issues) {
|
|
42
|
-
if (prefix === "")
|
|
43
|
-
return issues;
|
|
44
|
-
return issues.map((issue) => Object.freeze({
|
|
45
|
-
path: joinIssuePath(prefix, issue.path),
|
|
46
|
-
code: issue.code,
|
|
47
|
-
message: issue.message,
|
|
48
|
-
severity: issue.severity,
|
|
49
|
-
}));
|
|
50
|
-
}
|
|
@@ -15,11 +15,13 @@ exports.createRecursionRunner = createRecursionRunner;
|
|
|
15
15
|
// Legacy truncated at maxDepth as a SUCCESS, which meant a structure deeper
|
|
16
16
|
// than the limit silently skipped every rule below it.
|
|
17
17
|
//
|
|
18
|
-
// The nested plan runs into its OWN sink and its OWN index stack
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
18
|
+
// The nested plan runs into its OWN sink, and its OWN index stack STARTED AT
|
|
19
|
+
// the entering field's path. That is what makes `node.child.name` come out
|
|
20
|
+
// right: the plan's fields are declared relative to the plan's subject and know
|
|
21
|
+
// nothing about where they were re-entered from, so the stack is what carries
|
|
22
|
+
// the descent. Giving it the path up front rather than rewriting the issues
|
|
23
|
+
// afterwards is also what makes a message agree with the path beside it — a
|
|
24
|
+
// message is rendered once, from that path, at the moment the issue is built.
|
|
23
25
|
//
|
|
24
26
|
// A re-entry never writes. RecursionRunner returns void by contract, so there
|
|
25
27
|
// is nowhere for a transformed subtree to go; recursion is validation, and
|
|
@@ -88,12 +90,12 @@ function bindRecursionRunner(host, progress) {
|
|
|
88
90
|
(0, run_plan_1.runPlan)(policy.plan.resolve(), value, {
|
|
89
91
|
root: host.root,
|
|
90
92
|
sink: nested,
|
|
91
|
-
indices: new index_stack_1.IndexStack(),
|
|
93
|
+
indices: new index_stack_1.IndexStack(path),
|
|
92
94
|
shouldApplyTransforms: false,
|
|
93
95
|
runRecursion: bindRecursionRunner({ ...host, sink: nested }, progress),
|
|
94
96
|
external: host.external,
|
|
95
97
|
});
|
|
96
|
-
for (const issue of
|
|
98
|
+
for (const issue of nested.issues) {
|
|
97
99
|
host.sink.add(issue);
|
|
98
100
|
}
|
|
99
101
|
}
|
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
// Legacy truncated at maxDepth as a SUCCESS, which meant a structure deeper
|
|
12
12
|
// than the limit silently skipped every rule below it.
|
|
13
13
|
//
|
|
14
|
-
// The nested plan runs into its OWN sink and its OWN index stack
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
14
|
+
// The nested plan runs into its OWN sink, and its OWN index stack STARTED AT
|
|
15
|
+
// the entering field's path. That is what makes `node.child.name` come out
|
|
16
|
+
// right: the plan's fields are declared relative to the plan's subject and know
|
|
17
|
+
// nothing about where they were re-entered from, so the stack is what carries
|
|
18
|
+
// the descent. Giving it the path up front rather than rewriting the issues
|
|
19
|
+
// afterwards is also what makes a message agree with the path beside it — a
|
|
20
|
+
// message is rendered once, from that path, at the moment the issue is built.
|
|
19
21
|
//
|
|
20
22
|
// A re-entry never writes. RecursionRunner returns void by contract, so there
|
|
21
23
|
// is nowhere for a transformed subtree to go; recursion is validation, and
|
|
@@ -25,7 +27,7 @@ import { isArray } from "../types/index.mjs";
|
|
|
25
27
|
import { createIssue } from "./create-issue.mjs";
|
|
26
28
|
import { IndexStack } from "./index-stack.mjs";
|
|
27
29
|
import { IssueSink } from "./issue-sink.mjs";
|
|
28
|
-
import {
|
|
30
|
+
import { runPlan } from "./run-plan.mjs";
|
|
29
31
|
/**
|
|
30
32
|
* Legacy contract, kept: fields do not abort each other inside a recursive
|
|
31
33
|
* re-entry. A descent that stopped at its first issue would report one leaf of
|
|
@@ -84,12 +86,12 @@ function bindRecursionRunner(host, progress) {
|
|
|
84
86
|
runPlan(policy.plan.resolve(), value, {
|
|
85
87
|
root: host.root,
|
|
86
88
|
sink: nested,
|
|
87
|
-
indices: new IndexStack(),
|
|
89
|
+
indices: new IndexStack(path),
|
|
88
90
|
shouldApplyTransforms: false,
|
|
89
91
|
runRecursion: bindRecursionRunner({ ...host, sink: nested }, progress),
|
|
90
92
|
external: host.external,
|
|
91
93
|
});
|
|
92
|
-
for (const issue of
|
|
94
|
+
for (const issue of nested.issues) {
|
|
93
95
|
host.sink.add(issue);
|
|
94
96
|
}
|
|
95
97
|
}
|
|
@@ -15,6 +15,17 @@ export interface GlobalConfig {
|
|
|
15
15
|
readonly customTransforms?: Readonly<Record<string, ValueTransform>>;
|
|
16
16
|
/** Severity a rule emits when neither the rule nor the call names one. */
|
|
17
17
|
readonly defaultSeverity?: IssueSeverity;
|
|
18
|
+
/**
|
|
19
|
+
* What `validate(null)` and `validate(undefined)` say.
|
|
20
|
+
*
|
|
21
|
+
* A subject that is absent fails before the plan runs, so there is no rule
|
|
22
|
+
* to carry a messageFactory and no call site to name one. This is where it
|
|
23
|
+
* is said instead. The severity is NOT settable with it: a warning here
|
|
24
|
+
* would let `validate(null)` report success for a schema that declares
|
|
25
|
+
* nothing required, which is the outcome the short-circuit exists to
|
|
26
|
+
* prevent.
|
|
27
|
+
*/
|
|
28
|
+
readonly rootMissingMessage?: string;
|
|
18
29
|
}
|
|
19
30
|
/** Every member present: this is what a plugin reads. */
|
|
20
31
|
export interface ResolvedGlobalConfig {
|
|
@@ -26,6 +37,7 @@ export interface ResolvedGlobalConfig {
|
|
|
26
37
|
readonly caseSensitive: boolean;
|
|
27
38
|
readonly customTransforms: Readonly<Record<string, ValueTransform>>;
|
|
28
39
|
readonly defaultSeverity: IssueSeverity;
|
|
40
|
+
readonly rootMissingMessage: string;
|
|
29
41
|
}
|
|
30
42
|
export declare const DEFAULT_GLOBAL_CONFIG: ResolvedGlobalConfig;
|
|
31
43
|
export declare function resolveGlobalConfig(overrides: GlobalConfig | undefined, base?: ResolvedGlobalConfig): ResolvedGlobalConfig;
|
|
@@ -14,6 +14,7 @@ exports.DEFAULT_GLOBAL_CONFIG = Object.freeze({
|
|
|
14
14
|
caseSensitive: true,
|
|
15
15
|
customTransforms: Object.freeze({}),
|
|
16
16
|
defaultSeverity: "error",
|
|
17
|
+
rootMissingMessage: "Value is required",
|
|
17
18
|
});
|
|
18
19
|
function resolveGlobalConfig(overrides, base = exports.DEFAULT_GLOBAL_CONFIG) {
|
|
19
20
|
if (overrides === undefined)
|
|
@@ -32,5 +33,6 @@ function resolveGlobalConfig(overrides, base = exports.DEFAULT_GLOBAL_CONFIG) {
|
|
|
32
33
|
caseSensitive: overrides.caseSensitive ?? base.caseSensitive,
|
|
33
34
|
customTransforms: overrides.customTransforms ?? base.customTransforms,
|
|
34
35
|
defaultSeverity: overrides.defaultSeverity ?? base.defaultSeverity,
|
|
36
|
+
rootMissingMessage: overrides.rootMissingMessage ?? base.rootMissingMessage,
|
|
35
37
|
});
|
|
36
38
|
}
|
|
@@ -10,6 +10,7 @@ export const DEFAULT_GLOBAL_CONFIG = Object.freeze({
|
|
|
10
10
|
caseSensitive: true,
|
|
11
11
|
customTransforms: Object.freeze({}),
|
|
12
12
|
defaultSeverity: "error",
|
|
13
|
+
rootMissingMessage: "Value is required",
|
|
13
14
|
});
|
|
14
15
|
export function resolveGlobalConfig(overrides, base = DEFAULT_GLOBAL_CONFIG) {
|
|
15
16
|
if (overrides === undefined)
|
|
@@ -28,5 +29,6 @@ export function resolveGlobalConfig(overrides, base = DEFAULT_GLOBAL_CONFIG) {
|
|
|
28
29
|
caseSensitive: overrides.caseSensitive ?? base.caseSensitive,
|
|
29
30
|
customTransforms: overrides.customTransforms ?? base.customTransforms,
|
|
30
31
|
defaultSeverity: overrides.defaultSeverity ?? base.defaultSeverity,
|
|
32
|
+
rootMissingMessage: overrides.rootMissingMessage ?? base.rootMissingMessage,
|
|
31
33
|
});
|
|
32
34
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maroonedog/luq",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.3",
|
|
4
4
|
"description": "Universal Model & API Definition Platform - TypeScript validation library evolving into cross-language code generation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|