@modulify/validator 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +324 -107
- package/dist/assert.cjs +66 -0
- package/dist/assert.d.ts +16 -0
- package/dist/assert.mjs +66 -0
- package/dist/assertions.cjs +190 -92
- package/dist/assertions.d.ts +58 -2
- package/dist/assertions.mjs +191 -93
- package/dist/checkers.d.ts +8 -0
- package/dist/combinators.cjs +341 -0
- package/dist/combinators.d.ts +17 -0
- package/dist/combinators.mjs +341 -0
- package/dist/constraints.d.ts +4 -0
- package/dist/extractors.d.ts +2 -0
- package/dist/index.cjs +172 -61
- package/dist/index.d.ts +10 -4
- package/dist/index.mjs +176 -64
- package/dist/json-schema.cjs +514 -0
- package/dist/json-schema.d.ts +14 -0
- package/dist/json-schema.mjs +514 -0
- package/dist/metadata.cjs +8 -0
- package/dist/metadata.cjs.js +130 -0
- package/dist/metadata.d.ts +8 -0
- package/dist/metadata.es.js +131 -0
- package/dist/metadata.mjs +8 -0
- package/dist/predicates.cjs +40 -5
- package/dist/predicates.d.ts +25 -3
- package/dist/predicates.mjs +40 -5
- package/dist/violations.d.ts +29 -0
- package/docs/en/00-index.md +14 -0
- package/docs/en/01-shape-api.md +348 -0
- package/docs/en/02-metadata-and-introspection.md +276 -0
- package/docs/en/03-violations.md +267 -0
- package/docs/en/04-json-schema-export.md +264 -0
- package/docs/en/05-public-api.md +123 -0
- package/docs/en/06-common-recipes.md +273 -0
- package/docs/en/07-ai-reference.md +215 -0
- package/docs/en/08-violation-code-types.md +241 -0
- package/docs/ru/00-index.md +15 -0
- package/docs/ru/01-shape-api.md +348 -0
- package/docs/ru/02-metadata-and-introspection.md +276 -0
- package/docs/ru/03-violations.md +267 -0
- package/docs/ru/04-json-schema-export.md +264 -0
- package/docs/ru/05-public-api.md +123 -0
- package/docs/ru/06-common-recipes.md +273 -0
- package/docs/ru/07-ai-reference.md +215 -0
- package/docs/ru/08-violation-code-types.md +241 -0
- package/docs/ru/README.md +371 -0
- package/package.json +51 -33
- package/types/index.d.ts +789 -30
- package/types/json-schema.d.ts +75 -0
- package/dist/assertions/Assert.d.ts +0 -2
- package/dist/assertions/HasLength.d.ts +0 -7
- package/dist/assertions/check.d.ts +0 -3
- package/dist/assertions/index.d.ts +0 -16
- package/dist/runners/Each.d.ts +0 -3
- package/dist/runners/HasProperties.d.ts +0 -6
- package/dist/runners/index.d.ts +0 -2
- package/dist/runners.cjs +0 -32
- package/dist/runners.d.ts +0 -2
- package/dist/runners.mjs +0 -32
package/dist/index.cjs
CHANGED
|
@@ -1,51 +1,119 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const assertions = require("./assertions.cjs");
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
return null;
|
|
4
|
+
const combinators = require("./combinators.cjs");
|
|
5
|
+
const metadata = require("./metadata.cjs.js");
|
|
6
|
+
const assert = require("./assert.cjs");
|
|
7
|
+
const ROOT_PATH = Object.freeze([]);
|
|
8
|
+
const normalizePath = (path) => path ?? ROOT_PATH;
|
|
9
|
+
const isSamePath = (left, right = ROOT_PATH) => {
|
|
10
|
+
const normalizedLeft = normalizePath(left);
|
|
11
|
+
if (normalizedLeft.length !== right.length) {
|
|
12
|
+
return false;
|
|
17
13
|
}
|
|
18
|
-
return
|
|
19
|
-
value,
|
|
20
|
-
path,
|
|
21
|
-
violates: assert.fqn,
|
|
22
|
-
..."reason" in assert ? { reason: assert.reason } : {},
|
|
23
|
-
..."meta" in assert ? { meta: assert.meta } : {}
|
|
24
|
-
};
|
|
14
|
+
return normalizedLeft.every((part, index) => Object.is(part, right[index]));
|
|
25
15
|
};
|
|
26
|
-
const
|
|
27
|
-
|
|
16
|
+
const isPathPrefix = (path, prefix) => {
|
|
17
|
+
if (prefix.length > path.length) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return prefix.every((part, index) => Object.is(part, path[index]));
|
|
28
21
|
};
|
|
29
|
-
const
|
|
22
|
+
const createTreeState = (path) => ({
|
|
23
|
+
path: Object.freeze([...path]),
|
|
24
|
+
self: [],
|
|
25
|
+
subtree: [],
|
|
26
|
+
children: /* @__PURE__ */ new Map()
|
|
27
|
+
});
|
|
28
|
+
class TreeNode {
|
|
29
|
+
constructor(state) {
|
|
30
|
+
this.path = state.path;
|
|
31
|
+
this.self = new ViolationCollection(state.self);
|
|
32
|
+
this.subtree = new ViolationCollection(state.subtree);
|
|
33
|
+
this.children = new Map(
|
|
34
|
+
[...state.children.entries()].map(([key, child]) => [key, new TreeNode(child)])
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
at(path) {
|
|
38
|
+
if (!isPathPrefix(path, this.path)) {
|
|
39
|
+
return void 0;
|
|
40
|
+
}
|
|
41
|
+
if (path.length === this.path.length) {
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
const child = this.children.get(path[this.path.length]);
|
|
45
|
+
return child?.at(path);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const buildTree = (violations) => {
|
|
49
|
+
const root = createTreeState(ROOT_PATH);
|
|
50
|
+
violations.forEach((violation) => {
|
|
51
|
+
const path = normalizePath(violation.path);
|
|
52
|
+
root.subtree.push(violation);
|
|
53
|
+
if (path.length === 0) {
|
|
54
|
+
root.self.push(violation);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
let current = root;
|
|
58
|
+
const currentPath = [];
|
|
59
|
+
path.forEach((segment, index) => {
|
|
60
|
+
currentPath.push(segment);
|
|
61
|
+
let child = current.children.get(segment);
|
|
62
|
+
if (!child) {
|
|
63
|
+
child = createTreeState(currentPath);
|
|
64
|
+
current.children.set(segment, child);
|
|
65
|
+
}
|
|
66
|
+
child.subtree.push(violation);
|
|
67
|
+
if (index === path.length - 1) {
|
|
68
|
+
child.self.push(violation);
|
|
69
|
+
}
|
|
70
|
+
current = child;
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
return new TreeNode(root);
|
|
74
|
+
};
|
|
75
|
+
class ViolationCollection {
|
|
76
|
+
constructor(violations) {
|
|
77
|
+
this.violations = [...violations];
|
|
78
|
+
this.size = this.violations.length;
|
|
79
|
+
}
|
|
80
|
+
[Symbol.iterator]() {
|
|
81
|
+
return this.violations[Symbol.iterator]();
|
|
82
|
+
}
|
|
83
|
+
forEach(callback) {
|
|
84
|
+
this.violations.forEach((violation, index) => callback(violation, index, this));
|
|
85
|
+
}
|
|
86
|
+
map(callback) {
|
|
87
|
+
return this.violations.map((violation, index) => callback(violation, index, this));
|
|
88
|
+
}
|
|
89
|
+
at(path) {
|
|
90
|
+
return new ViolationCollection(this.violations.filter((violation) => isSamePath(violation.path, path)));
|
|
91
|
+
}
|
|
92
|
+
tree() {
|
|
93
|
+
return buildTree(this.violations);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const collection = (violations) => new ViolationCollection(violations);
|
|
97
|
+
const collectViolations = async (value, constraints, path = []) => {
|
|
30
98
|
const validations = [];
|
|
31
|
-
for (const c of
|
|
32
|
-
if (
|
|
33
|
-
validations.push(...c.run(
|
|
99
|
+
for (const c of metadata.arrayify(constraints)) {
|
|
100
|
+
if (metadata.isValidator(c)) {
|
|
101
|
+
validations.push(...c.run(collectViolations, value, path).map((v2) => v2 instanceof Promise ? v2 : Promise.resolve(v2)));
|
|
34
102
|
continue;
|
|
35
103
|
}
|
|
36
|
-
const v =
|
|
104
|
+
const v = c(value);
|
|
37
105
|
if (v instanceof Promise) {
|
|
38
106
|
if (c.bail) {
|
|
39
107
|
const awaited = await v;
|
|
40
108
|
if (awaited) {
|
|
41
|
-
validations.push(Promise.resolve([awaited]));
|
|
109
|
+
validations.push(Promise.resolve([Object.assign(awaited, { path: [...path] })]));
|
|
42
110
|
break;
|
|
43
111
|
}
|
|
44
112
|
} else {
|
|
45
|
-
validations.push(v.then((v2) => v2 ? [v2] : []));
|
|
113
|
+
validations.push(v.then((v2) => v2 ? [Object.assign(v2, { path: [...path] })] : []));
|
|
46
114
|
}
|
|
47
115
|
} else if (v) {
|
|
48
|
-
validations.push(Promise.resolve([v]));
|
|
116
|
+
validations.push(Promise.resolve([Object.assign(v, { path: [...path] })]));
|
|
49
117
|
if (c.bail) {
|
|
50
118
|
break;
|
|
51
119
|
}
|
|
@@ -53,30 +121,25 @@ const _validate = async (value, constraints, path = []) => {
|
|
|
53
121
|
}
|
|
54
122
|
return settle(value, path, validations);
|
|
55
123
|
};
|
|
56
|
-
const
|
|
124
|
+
const collectViolationsSync = (value, constraints, path = []) => {
|
|
57
125
|
const violations = [];
|
|
58
|
-
for (const c of
|
|
59
|
-
if (
|
|
60
|
-
violations.push(...c.run(
|
|
126
|
+
for (const c of metadata.arrayify(constraints)) {
|
|
127
|
+
if (metadata.isValidator(c)) {
|
|
128
|
+
violations.push(...c.run(collectViolationsSync, value, path));
|
|
61
129
|
continue;
|
|
62
130
|
}
|
|
63
|
-
const v =
|
|
131
|
+
const v = c(value);
|
|
64
132
|
if (v instanceof Promise) {
|
|
65
|
-
throw new Error("Found asynchronous
|
|
133
|
+
throw new Error("Found asynchronous validator " + String(c.name));
|
|
66
134
|
} else if (v) {
|
|
67
|
-
violations.push(v);
|
|
68
|
-
if (c.bail)
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
135
|
+
violations.push(Object.assign(v, { path: [...path] }));
|
|
136
|
+
if (c.bail) break;
|
|
71
137
|
}
|
|
72
138
|
}
|
|
73
139
|
return flatten(violations);
|
|
74
140
|
};
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
});
|
|
78
|
-
function arraify(value) {
|
|
79
|
-
return Array.isArray(value) ? [...value] : [value];
|
|
141
|
+
function toResult(value, violations) {
|
|
142
|
+
return violations.length === 0 ? [true, value, []] : [false, value, violations];
|
|
80
143
|
}
|
|
81
144
|
function flatten(recursive) {
|
|
82
145
|
const flattened = [];
|
|
@@ -95,25 +158,73 @@ async function settle(value, path, validations) {
|
|
|
95
158
|
violations.push({
|
|
96
159
|
value,
|
|
97
160
|
path,
|
|
98
|
-
violates: "
|
|
99
|
-
reason: "reject",
|
|
100
|
-
meta: result.reason
|
|
161
|
+
violates: { kind: "runtime", name: "validate", code: "runtime.rejection", args: [result.reason] }
|
|
101
162
|
});
|
|
102
163
|
}
|
|
103
164
|
});
|
|
104
165
|
return violations;
|
|
105
166
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
167
|
+
const matches = {
|
|
168
|
+
sync(value, constraints) {
|
|
169
|
+
return collectViolationsSync(value, constraints).length === 0;
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const validate = Object.assign(
|
|
173
|
+
async (value, constraints) => {
|
|
174
|
+
const violations = await collectViolations(value, constraints);
|
|
175
|
+
return toResult(
|
|
176
|
+
value,
|
|
177
|
+
violations
|
|
178
|
+
);
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
sync(value, constraints) {
|
|
182
|
+
const violations = collectViolationsSync(value, constraints);
|
|
183
|
+
return toResult(
|
|
184
|
+
value,
|
|
185
|
+
violations
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
exports.endsWith = assertions.endsWith;
|
|
191
|
+
exports.hasLength = assertions.hasLength;
|
|
192
|
+
exports.hasPattern = assertions.hasPattern;
|
|
193
|
+
exports.hasSize = assertions.hasSize;
|
|
194
|
+
exports.hasValue = assertions.hasValue;
|
|
195
|
+
exports.isBigInt = assertions.isBigInt;
|
|
196
|
+
exports.isBlob = assertions.isBlob;
|
|
197
|
+
exports.isBoolean = assertions.isBoolean;
|
|
198
|
+
exports.isDate = assertions.isDate;
|
|
199
|
+
exports.isDefined = assertions.isDefined;
|
|
200
|
+
exports.isEmail = assertions.isEmail;
|
|
201
|
+
exports.isFile = assertions.isFile;
|
|
202
|
+
exports.isFunction = assertions.isFunction;
|
|
203
|
+
exports.isMap = assertions.isMap;
|
|
204
|
+
exports.isNaN = assertions.isNaN;
|
|
205
|
+
exports.isNull = assertions.isNull;
|
|
206
|
+
exports.isNumber = assertions.isNumber;
|
|
207
|
+
exports.isSet = assertions.isSet;
|
|
208
|
+
exports.isString = assertions.isString;
|
|
209
|
+
exports.isSymbol = assertions.isSymbol;
|
|
210
|
+
exports.multipleOf = assertions.multipleOf;
|
|
211
|
+
exports.oneOf = assertions.oneOf;
|
|
212
|
+
exports.startsWith = assertions.startsWith;
|
|
213
|
+
exports.discriminatedUnion = combinators.discriminatedUnion;
|
|
214
|
+
exports.each = combinators.each;
|
|
215
|
+
exports.exact = combinators.exact;
|
|
216
|
+
exports.nullable = combinators.nullable;
|
|
217
|
+
exports.nullish = combinators.nullish;
|
|
218
|
+
exports.optional = combinators.optional;
|
|
219
|
+
exports.record = combinators.record;
|
|
220
|
+
exports.shape = combinators.shape;
|
|
221
|
+
exports.tuple = combinators.tuple;
|
|
222
|
+
exports.union = combinators.union;
|
|
223
|
+
exports.custom = metadata.custom;
|
|
224
|
+
exports.describe = metadata.describe;
|
|
225
|
+
exports.meta = metadata.meta;
|
|
226
|
+
exports.assert = assert.assert;
|
|
227
|
+
exports.ViolationCollection = ViolationCollection;
|
|
228
|
+
exports.collection = collection;
|
|
229
|
+
exports.matches = matches;
|
|
119
230
|
exports.validate = validate;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import { Constraint, MaybeMany,
|
|
1
|
+
import { Constraint, InferConstraints, InferMaybeManyViolations, MaybeMany, ValidationTuple } from '../types';
|
|
2
2
|
export * from './assertions';
|
|
3
|
-
export * from './
|
|
4
|
-
export
|
|
5
|
-
|
|
3
|
+
export * from './combinators';
|
|
4
|
+
export { collection, ViolationCollection, } from './violations';
|
|
5
|
+
export { custom, describe, meta, } from './metadata';
|
|
6
|
+
export type { AllOfConstraintDescriptor, AssertionDescriptor, AssertionDescriptorConstraint, Constraint, ConstraintDescriptor, ConstraintDescriptorBase, ConstraintMetadata, CustomConstraintDescriptor, DescribeAssertionConstraint, DescribeAssertionConstraintTuple, DescribeConstraint, DescribeConstraintTuple, DescribeMaybeMany, DescribeObjectDescriptor, DescribedValidator, DiscriminatedUnionValidator, EachValidator, FieldsMatchObjectShapeRuleDescriptor, GenericObjectShapeRuleDescriptor, InferConstraint, InferConstraints, InferConstraintViolations, InferMaybeManyViolations, DiscriminatedUnionConstraintDescriptor, EachConstraintDescriptor, NullableValidator, NullishValidator, KnownViolationCode, KnownViolationSubject, ObjectShapeFieldSelector, ObjectShapeRefinement, ObjectShapeRefinementIssue, ObjectShapeRuleDescriptor, ObjectShapeRuleDescriptorBase, OptionalValidator, RecordValidator, RecordConstraintDescriptor, ShapeConstraintDescriptor, TupleValidator, TupleConstraintDescriptor, UnionValidator, ValidationFailure, ValidationSuccess, ViolationArgs, ViolationCode, ViolationCodeEntry, ViolationCodeRegistry, ViolationEntry, ViolationKind, ViolationKindOf, ViolationNameOf, ViolationSubject, ViolationTreeNode, UnionConstraintDescriptor, ValidationTuple, ValidationResult, Validator, ValidatorDescriptor, Violation, WrapperConstraintDescriptor, } from '../types';
|
|
7
|
+
export declare const matches: {
|
|
8
|
+
sync<const C extends MaybeMany<Constraint>>(value: unknown, constraints: C): value is InferConstraints<C>;
|
|
9
|
+
};
|
|
10
|
+
export declare const validate: (<const C extends MaybeMany<Constraint>>(value: unknown, constraints: C) => Promise<ValidationTuple<InferConstraints<C>, InferMaybeManyViolations<C>>>) & {
|
|
11
|
+
sync<const C extends MaybeMany<Constraint>>(value: unknown, constraints: C): ValidationTuple<InferConstraints<C>, InferMaybeManyViolations<C>>;
|
|
6
12
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -1,80 +1,144 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
return null;
|
|
1
|
+
import { endsWith, hasLength, hasPattern, hasSize, hasValue, isBigInt, isBlob, isBoolean, isDate, isDefined, isEmail, isFile, isFunction, isMap, isNaN, isNull, isNumber, isSet, isString, isSymbol, multipleOf, oneOf, startsWith } from "./assertions.mjs";
|
|
2
|
+
import { discriminatedUnion, each, exact, nullable, nullish, optional, record, shape, tuple, union } from "./combinators.mjs";
|
|
3
|
+
import { a as arrayify, i as isValidator } from "./metadata.es.js";
|
|
4
|
+
import { c, b, m } from "./metadata.es.js";
|
|
5
|
+
import { assert } from "./assert.mjs";
|
|
6
|
+
const ROOT_PATH = Object.freeze([]);
|
|
7
|
+
const normalizePath = (path) => path ?? ROOT_PATH;
|
|
8
|
+
const isSamePath = (left, right = ROOT_PATH) => {
|
|
9
|
+
const normalizedLeft = normalizePath(left);
|
|
10
|
+
if (normalizedLeft.length !== right.length) {
|
|
11
|
+
return false;
|
|
15
12
|
}
|
|
16
|
-
return
|
|
17
|
-
value,
|
|
18
|
-
path,
|
|
19
|
-
violates: assert.fqn,
|
|
20
|
-
..."reason" in assert ? { reason: assert.reason } : {},
|
|
21
|
-
..."meta" in assert ? { meta: assert.meta } : {}
|
|
22
|
-
};
|
|
13
|
+
return normalizedLeft.every((part, index) => Object.is(part, right[index]));
|
|
23
14
|
};
|
|
24
|
-
const
|
|
25
|
-
|
|
15
|
+
const isPathPrefix = (path, prefix) => {
|
|
16
|
+
if (prefix.length > path.length) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return prefix.every((part, index) => Object.is(part, path[index]));
|
|
26
20
|
};
|
|
27
|
-
const
|
|
21
|
+
const createTreeState = (path) => ({
|
|
22
|
+
path: Object.freeze([...path]),
|
|
23
|
+
self: [],
|
|
24
|
+
subtree: [],
|
|
25
|
+
children: /* @__PURE__ */ new Map()
|
|
26
|
+
});
|
|
27
|
+
class TreeNode {
|
|
28
|
+
constructor(state) {
|
|
29
|
+
this.path = state.path;
|
|
30
|
+
this.self = new ViolationCollection(state.self);
|
|
31
|
+
this.subtree = new ViolationCollection(state.subtree);
|
|
32
|
+
this.children = new Map(
|
|
33
|
+
[...state.children.entries()].map(([key, child]) => [key, new TreeNode(child)])
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
at(path) {
|
|
37
|
+
if (!isPathPrefix(path, this.path)) {
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
if (path.length === this.path.length) {
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
const child = this.children.get(path[this.path.length]);
|
|
44
|
+
return child?.at(path);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const buildTree = (violations) => {
|
|
48
|
+
const root = createTreeState(ROOT_PATH);
|
|
49
|
+
violations.forEach((violation) => {
|
|
50
|
+
const path = normalizePath(violation.path);
|
|
51
|
+
root.subtree.push(violation);
|
|
52
|
+
if (path.length === 0) {
|
|
53
|
+
root.self.push(violation);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
let current = root;
|
|
57
|
+
const currentPath = [];
|
|
58
|
+
path.forEach((segment, index) => {
|
|
59
|
+
currentPath.push(segment);
|
|
60
|
+
let child = current.children.get(segment);
|
|
61
|
+
if (!child) {
|
|
62
|
+
child = createTreeState(currentPath);
|
|
63
|
+
current.children.set(segment, child);
|
|
64
|
+
}
|
|
65
|
+
child.subtree.push(violation);
|
|
66
|
+
if (index === path.length - 1) {
|
|
67
|
+
child.self.push(violation);
|
|
68
|
+
}
|
|
69
|
+
current = child;
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
return new TreeNode(root);
|
|
73
|
+
};
|
|
74
|
+
class ViolationCollection {
|
|
75
|
+
constructor(violations) {
|
|
76
|
+
this.violations = [...violations];
|
|
77
|
+
this.size = this.violations.length;
|
|
78
|
+
}
|
|
79
|
+
[Symbol.iterator]() {
|
|
80
|
+
return this.violations[Symbol.iterator]();
|
|
81
|
+
}
|
|
82
|
+
forEach(callback) {
|
|
83
|
+
this.violations.forEach((violation, index) => callback(violation, index, this));
|
|
84
|
+
}
|
|
85
|
+
map(callback) {
|
|
86
|
+
return this.violations.map((violation, index) => callback(violation, index, this));
|
|
87
|
+
}
|
|
88
|
+
at(path) {
|
|
89
|
+
return new ViolationCollection(this.violations.filter((violation) => isSamePath(violation.path, path)));
|
|
90
|
+
}
|
|
91
|
+
tree() {
|
|
92
|
+
return buildTree(this.violations);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const collection = (violations) => new ViolationCollection(violations);
|
|
96
|
+
const collectViolations = async (value, constraints, path = []) => {
|
|
28
97
|
const validations = [];
|
|
29
|
-
for (const
|
|
30
|
-
if (
|
|
31
|
-
validations.push(...
|
|
98
|
+
for (const c2 of arrayify(constraints)) {
|
|
99
|
+
if (isValidator(c2)) {
|
|
100
|
+
validations.push(...c2.run(collectViolations, value, path).map((v2) => v2 instanceof Promise ? v2 : Promise.resolve(v2)));
|
|
32
101
|
continue;
|
|
33
102
|
}
|
|
34
|
-
const v =
|
|
103
|
+
const v = c2(value);
|
|
35
104
|
if (v instanceof Promise) {
|
|
36
|
-
if (
|
|
105
|
+
if (c2.bail) {
|
|
37
106
|
const awaited = await v;
|
|
38
107
|
if (awaited) {
|
|
39
|
-
validations.push(Promise.resolve([awaited]));
|
|
108
|
+
validations.push(Promise.resolve([Object.assign(awaited, { path: [...path] })]));
|
|
40
109
|
break;
|
|
41
110
|
}
|
|
42
111
|
} else {
|
|
43
|
-
validations.push(v.then((v2) => v2 ? [v2] : []));
|
|
112
|
+
validations.push(v.then((v2) => v2 ? [Object.assign(v2, { path: [...path] })] : []));
|
|
44
113
|
}
|
|
45
114
|
} else if (v) {
|
|
46
|
-
validations.push(Promise.resolve([v]));
|
|
47
|
-
if (
|
|
115
|
+
validations.push(Promise.resolve([Object.assign(v, { path: [...path] })]));
|
|
116
|
+
if (c2.bail) {
|
|
48
117
|
break;
|
|
49
118
|
}
|
|
50
119
|
}
|
|
51
120
|
}
|
|
52
121
|
return settle(value, path, validations);
|
|
53
122
|
};
|
|
54
|
-
const
|
|
123
|
+
const collectViolationsSync = (value, constraints, path = []) => {
|
|
55
124
|
const violations = [];
|
|
56
|
-
for (const
|
|
57
|
-
if (
|
|
58
|
-
violations.push(...
|
|
125
|
+
for (const c2 of arrayify(constraints)) {
|
|
126
|
+
if (isValidator(c2)) {
|
|
127
|
+
violations.push(...c2.run(collectViolationsSync, value, path));
|
|
59
128
|
continue;
|
|
60
129
|
}
|
|
61
|
-
const v =
|
|
130
|
+
const v = c2(value);
|
|
62
131
|
if (v instanceof Promise) {
|
|
63
|
-
throw new Error("Found asynchronous
|
|
132
|
+
throw new Error("Found asynchronous validator " + String(c2.name));
|
|
64
133
|
} else if (v) {
|
|
65
|
-
violations.push(v);
|
|
66
|
-
if (
|
|
67
|
-
break;
|
|
68
|
-
}
|
|
134
|
+
violations.push(Object.assign(v, { path: [...path] }));
|
|
135
|
+
if (c2.bail) break;
|
|
69
136
|
}
|
|
70
137
|
}
|
|
71
138
|
return flatten(violations);
|
|
72
139
|
};
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
});
|
|
76
|
-
function arraify(value) {
|
|
77
|
-
return Array.isArray(value) ? [...value] : [value];
|
|
140
|
+
function toResult(value, violations) {
|
|
141
|
+
return violations.length === 0 ? [true, value, []] : [false, value, violations];
|
|
78
142
|
}
|
|
79
143
|
function flatten(recursive) {
|
|
80
144
|
const flattened = [];
|
|
@@ -93,27 +157,75 @@ async function settle(value, path, validations) {
|
|
|
93
157
|
violations.push({
|
|
94
158
|
value,
|
|
95
159
|
path,
|
|
96
|
-
violates: "
|
|
97
|
-
reason: "reject",
|
|
98
|
-
meta: result.reason
|
|
160
|
+
violates: { kind: "runtime", name: "validate", code: "runtime.rejection", args: [result.reason] }
|
|
99
161
|
});
|
|
100
162
|
}
|
|
101
163
|
});
|
|
102
164
|
return violations;
|
|
103
165
|
}
|
|
166
|
+
const matches = {
|
|
167
|
+
sync(value, constraints) {
|
|
168
|
+
return collectViolationsSync(value, constraints).length === 0;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
const validate = Object.assign(
|
|
172
|
+
async (value, constraints) => {
|
|
173
|
+
const violations = await collectViolations(value, constraints);
|
|
174
|
+
return toResult(
|
|
175
|
+
value,
|
|
176
|
+
violations
|
|
177
|
+
);
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
sync(value, constraints) {
|
|
181
|
+
const violations = collectViolationsSync(value, constraints);
|
|
182
|
+
return toResult(
|
|
183
|
+
value,
|
|
184
|
+
violations
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
);
|
|
104
189
|
export {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
190
|
+
ViolationCollection,
|
|
191
|
+
assert,
|
|
192
|
+
collection,
|
|
193
|
+
c as custom,
|
|
194
|
+
b as describe,
|
|
195
|
+
discriminatedUnion,
|
|
196
|
+
each,
|
|
197
|
+
endsWith,
|
|
198
|
+
exact,
|
|
199
|
+
hasLength,
|
|
200
|
+
hasPattern,
|
|
201
|
+
hasSize,
|
|
202
|
+
hasValue,
|
|
203
|
+
isBigInt,
|
|
204
|
+
isBlob,
|
|
205
|
+
isBoolean,
|
|
206
|
+
isDate,
|
|
207
|
+
isDefined,
|
|
208
|
+
isEmail,
|
|
209
|
+
isFile,
|
|
210
|
+
isFunction,
|
|
211
|
+
isMap,
|
|
212
|
+
isNaN,
|
|
213
|
+
isNull,
|
|
214
|
+
isNumber,
|
|
215
|
+
isSet,
|
|
216
|
+
isString,
|
|
217
|
+
isSymbol,
|
|
218
|
+
matches,
|
|
219
|
+
m as meta,
|
|
220
|
+
multipleOf,
|
|
221
|
+
nullable,
|
|
222
|
+
nullish,
|
|
223
|
+
oneOf,
|
|
224
|
+
optional,
|
|
225
|
+
record,
|
|
226
|
+
shape,
|
|
227
|
+
startsWith,
|
|
228
|
+
tuple,
|
|
229
|
+
union,
|
|
118
230
|
validate
|
|
119
231
|
};
|