@sanity/validation 3.0.0-v3-pte.69 → 3.0.0-v3-esm.52
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/lib/dts/src/index.d.ts +28 -13
- package/lib/index.cjs +1168 -1265
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +1167 -1265
- package/lib/index.js.map +1 -1
- package/package.json +20 -16
- package/src/index.ts +1 -1
- package/src/validateDocument.ts +1 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/lib/dts/src/Rule.d.ts +0 -4
- package/lib/dts/src/Rule.d.ts.map +0 -1
- package/lib/dts/src/Rule.js +0 -336
- package/lib/dts/src/Rule.js.map +0 -1
- package/lib/dts/src/ValidationError.d.ts +0 -4
- package/lib/dts/src/ValidationError.d.ts.map +0 -1
- package/lib/dts/src/ValidationError.js +0 -18
- package/lib/dts/src/ValidationError.js.map +0 -1
- package/lib/dts/src/index.d.ts.map +0 -1
- package/lib/dts/src/index.js +0 -7
- package/lib/dts/src/index.js.map +0 -1
- package/lib/dts/src/inferFromSchema.d.ts +0 -4
- package/lib/dts/src/inferFromSchema.d.ts.map +0 -1
- package/lib/dts/src/inferFromSchema.js +0 -14
- package/lib/dts/src/inferFromSchema.js.map +0 -1
- package/lib/dts/src/inferFromSchemaType.d.ts +0 -5
- package/lib/dts/src/inferFromSchemaType.d.ts.map +0 -1
- package/lib/dts/src/inferFromSchemaType.js +0 -33
- package/lib/dts/src/inferFromSchemaType.js.map +0 -1
- package/lib/dts/src/util/convertToValidationMarker.d.ts +0 -6
- package/lib/dts/src/util/convertToValidationMarker.d.ts.map +0 -1
- package/lib/dts/src/util/convertToValidationMarker.js +0 -51
- package/lib/dts/src/util/convertToValidationMarker.js.map +0 -1
- package/lib/dts/src/util/deepEquals.d.ts +0 -6
- package/lib/dts/src/util/deepEquals.d.ts.map +0 -1
- package/lib/dts/src/util/deepEquals.js +0 -65
- package/lib/dts/src/util/deepEquals.js.map +0 -1
- package/lib/dts/src/util/escapeRegex.d.ts +0 -3
- package/lib/dts/src/util/escapeRegex.d.ts.map +0 -1
- package/lib/dts/src/util/escapeRegex.js +0 -6
- package/lib/dts/src/util/escapeRegex.js.map +0 -1
- package/lib/dts/src/util/normalizeValidationRules.d.ts +0 -6
- package/lib/dts/src/util/normalizeValidationRules.d.ts.map +0 -1
- package/lib/dts/src/util/normalizeValidationRules.js +0 -104
- package/lib/dts/src/util/normalizeValidationRules.js.map +0 -1
- package/lib/dts/src/util/normalizeValidationRules.test.d.ts +0 -2
- package/lib/dts/src/util/normalizeValidationRules.test.d.ts.map +0 -1
- package/lib/dts/src/util/normalizeValidationRules.test.js +0 -150
- package/lib/dts/src/util/normalizeValidationRules.test.js.map +0 -1
- package/lib/dts/src/util/pathToString.d.ts +0 -3
- package/lib/dts/src/util/pathToString.d.ts.map +0 -1
- package/lib/dts/src/util/pathToString.js +0 -18
- package/lib/dts/src/util/pathToString.js.map +0 -1
- package/lib/dts/src/util/typeString.d.ts +0 -2
- package/lib/dts/src/util/typeString.d.ts.map +0 -1
- package/lib/dts/src/util/typeString.js +0 -23
- package/lib/dts/src/util/typeString.js.map +0 -1
- package/lib/dts/src/util/typeString.test.d.ts +0 -2
- package/lib/dts/src/util/typeString.test.d.ts.map +0 -1
- package/lib/dts/src/util/typeString.test.js +0 -24
- package/lib/dts/src/util/typeString.test.js.map +0 -1
- package/lib/dts/src/validateDocument.d.ts +0 -23
- package/lib/dts/src/validateDocument.d.ts.map +0 -1
- package/lib/dts/src/validateDocument.js +0 -142
- package/lib/dts/src/validateDocument.js.map +0 -1
- package/lib/dts/src/validateDocument.test.d.ts +0 -2
- package/lib/dts/src/validateDocument.test.d.ts.map +0 -1
- package/lib/dts/src/validateDocument.test.js +0 -704
- package/lib/dts/src/validateDocument.test.js.map +0 -1
- package/lib/dts/src/validators/arrayValidator.d.ts +0 -4
- package/lib/dts/src/validators/arrayValidator.d.ts.map +0 -1
- package/lib/dts/src/validators/arrayValidator.js +0 -79
- package/lib/dts/src/validators/arrayValidator.js.map +0 -1
- package/lib/dts/src/validators/booleanValidator.d.ts +0 -4
- package/lib/dts/src/validators/booleanValidator.d.ts.map +0 -1
- package/lib/dts/src/validators/booleanValidator.js +0 -12
- package/lib/dts/src/validators/booleanValidator.js.map +0 -1
- package/lib/dts/src/validators/dateValidator.d.ts +0 -5
- package/lib/dts/src/validators/dateValidator.d.ts.map +0 -1
- package/lib/dts/src/validators/dateValidator.js +0 -83
- package/lib/dts/src/validators/dateValidator.js.map +0 -1
- package/lib/dts/src/validators/genericValidator.d.ts +0 -4
- package/lib/dts/src/validators/genericValidator.d.ts.map +0 -1
- package/lib/dts/src/validators/genericValidator.js +0 -93
- package/lib/dts/src/validators/genericValidator.js.map +0 -1
- package/lib/dts/src/validators/numberValidator.d.ts +0 -4
- package/lib/dts/src/validators/numberValidator.d.ts.map +0 -1
- package/lib/dts/src/validators/numberValidator.js +0 -47
- package/lib/dts/src/validators/numberValidator.js.map +0 -1
- package/lib/dts/src/validators/objectValidator.d.ts +0 -4
- package/lib/dts/src/validators/objectValidator.d.ts.map +0 -1
- package/lib/dts/src/validators/objectValidator.js +0 -48
- package/lib/dts/src/validators/objectValidator.js.map +0 -1
- package/lib/dts/src/validators/slugValidator.d.ts +0 -9
- package/lib/dts/src/validators/slugValidator.d.ts.map +0 -1
- package/lib/dts/src/validators/slugValidator.js +0 -83
- package/lib/dts/src/validators/slugValidator.js.map +0 -1
- package/lib/dts/src/validators/stringValidator.d.ts +0 -4
- package/lib/dts/src/validators/stringValidator.d.ts.map +0 -1
- package/lib/dts/src/validators/stringValidator.js +0 -94
- package/lib/dts/src/validators/stringValidator.js.map +0 -1
- package/lib/dts/test/array.test.d.ts +0 -2
- package/lib/dts/test/array.test.d.ts.map +0 -1
- package/lib/dts/test/array.test.js +0 -55
- package/lib/dts/test/array.test.js.map +0 -1
- package/lib/dts/test/children.test.d.ts +0 -2
- package/lib/dts/test/children.test.d.ts.map +0 -1
- package/lib/dts/test/children.test.js +0 -70
- package/lib/dts/test/children.test.js.map +0 -1
- package/lib/dts/test/createSchema.d.ts +0 -6
- package/lib/dts/test/createSchema.d.ts.map +0 -1
- package/lib/dts/test/createSchema.js +0 -19
- package/lib/dts/test/createSchema.js.map +0 -1
- package/lib/dts/test/generics.test.d.ts +0 -2
- package/lib/dts/test/generics.test.d.ts.map +0 -1
- package/lib/dts/test/generics.test.js +0 -60
- package/lib/dts/test/generics.test.js.map +0 -1
- package/lib/dts/test/infer.test.d.ts +0 -2
- package/lib/dts/test/infer.test.d.ts.map +0 -1
- package/lib/dts/test/infer.test.js +0 -243
- package/lib/dts/test/infer.test.js.map +0 -1
- package/lib/dts/test/mocks/mockSanityClient.d.ts +0 -6
- package/lib/dts/test/mocks/mockSanityClient.d.ts.map +0 -1
- package/lib/dts/test/mocks/mockSanityClient.js +0 -8
- package/lib/dts/test/mocks/mockSanityClient.js.map +0 -1
- package/lib/dts/test/nullExport.d.ts +0 -3
- package/lib/dts/test/nullExport.d.ts.map +0 -1
- package/lib/dts/test/nullExport.js +0 -4
- package/lib/dts/test/nullExport.js.map +0 -1
- package/lib/dts/test/numbers.test.d.ts +0 -2
- package/lib/dts/test/numbers.test.d.ts.map +0 -1
- package/lib/dts/test/numbers.test.js +0 -57
- package/lib/dts/test/numbers.test.js.map +0 -1
- package/lib/dts/test/strings.test.d.ts +0 -2
- package/lib/dts/test/strings.test.d.ts.map +0 -1
- package/lib/dts/test/strings.test.js +0 -100
- package/lib/dts/test/strings.test.js.map +0 -1
- package/lib/dts/tsconfig.lib.tsbuildinfo +0 -1
- package/lib/dts/tsconfig.tsbuildinfo +0 -1
- package/tsconfig.tsbuildinfo +0 -1
package/lib/index.cjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
3
5
|
var lodash = require('lodash');
|
|
4
6
|
var types = require('@sanity/types');
|
|
5
7
|
var formatDate = require('date-fns/format');
|
|
@@ -8,1310 +10,1211 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
8
10
|
|
|
9
11
|
var formatDate__default = /*#__PURE__*/_interopDefaultLegacy(formatDate);
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
message;
|
|
14
|
-
paths;
|
|
15
|
-
children;
|
|
16
|
-
operation;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
paths: this.paths,
|
|
26
|
-
children: this.children,
|
|
27
|
-
operation: this.operation,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
13
|
+
const ValidationError = class ValidationError2 {
|
|
14
|
+
constructor(message, options = {}) {
|
|
15
|
+
this.message = message;
|
|
16
|
+
this.paths = options.paths || [];
|
|
17
|
+
this.children = options.children;
|
|
18
|
+
this.operation = options.operation;
|
|
19
|
+
}
|
|
20
|
+
cloneWithMessage(msg) {
|
|
21
|
+
return new ValidationError2(msg, {
|
|
22
|
+
paths: this.paths,
|
|
23
|
+
children: this.children,
|
|
24
|
+
operation: this.operation
|
|
25
|
+
});
|
|
26
|
+
}
|
|
30
27
|
};
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// Escape ^$.*+-?=!:|\/()[]{},
|
|
35
|
-
return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
|
|
29
|
+
var escapeRegex = (string) => {
|
|
30
|
+
return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, "\\$&");
|
|
36
31
|
};
|
|
37
32
|
|
|
38
|
-
function pathToString(path = []) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
33
|
+
function pathToString(path = []) {
|
|
34
|
+
return path.reduce((target, segment, i) => {
|
|
35
|
+
const segmentType = typeof segment;
|
|
36
|
+
if (segmentType === "number") {
|
|
37
|
+
return `${target}[${segment}]`;
|
|
38
|
+
}
|
|
39
|
+
if (segmentType === "string") {
|
|
40
|
+
const separator = i === 0 ? "" : ".";
|
|
41
|
+
return `${target}${separator}${segment}`;
|
|
42
|
+
}
|
|
43
|
+
if (types.isKeyedObject(segment)) {
|
|
44
|
+
return `${target}[_key=="${segment._key}"]`;
|
|
45
|
+
}
|
|
46
|
+
throw new Error(`Unsupported path segment "${segment}"`);
|
|
47
|
+
}, "");
|
|
53
48
|
}
|
|
54
49
|
|
|
55
|
-
function isNonNullable$1(t) {
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
function convertToValidationMarker(validatorResult, level, context) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
50
|
+
function isNonNullable$1(t) {
|
|
51
|
+
return t !== null || t !== void 0;
|
|
52
|
+
}
|
|
53
|
+
function convertToValidationMarker(validatorResult, level, context) {
|
|
54
|
+
var _a;
|
|
55
|
+
if (!context) {
|
|
56
|
+
throw new Error("missing context");
|
|
57
|
+
}
|
|
58
|
+
if (validatorResult === true)
|
|
59
|
+
return [];
|
|
60
|
+
if (Array.isArray(validatorResult)) {
|
|
61
|
+
return validatorResult.flatMap((child) => convertToValidationMarker(child, level, context)).filter(isNonNullable$1);
|
|
62
|
+
}
|
|
63
|
+
if (typeof validatorResult === "string") {
|
|
64
|
+
return convertToValidationMarker(new ValidationError(validatorResult), level, context);
|
|
65
|
+
}
|
|
66
|
+
if (!(validatorResult instanceof ValidationError)) {
|
|
67
|
+
if (typeof (validatorResult == null ? void 0 : validatorResult.message) !== "string") {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`${pathToString(
|
|
70
|
+
context.path
|
|
71
|
+
)}: Validator must return 'true' if valid or an error message as a string on errors`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
return convertToValidationMarker(
|
|
75
|
+
new ValidationError(validatorResult.message, validatorResult),
|
|
76
|
+
level,
|
|
77
|
+
context
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
const results = [];
|
|
81
|
+
if (!((_a = validatorResult.paths) == null ? void 0 : _a.length)) {
|
|
82
|
+
return [
|
|
83
|
+
{
|
|
84
|
+
level: level || "error",
|
|
85
|
+
item: validatorResult,
|
|
86
|
+
path: context.path || []
|
|
87
|
+
}
|
|
88
|
+
];
|
|
89
|
+
}
|
|
90
|
+
return results.concat(
|
|
91
|
+
validatorResult.paths.map((path) => ({
|
|
92
|
+
path: (context.path || []).concat(path),
|
|
93
|
+
level: level || "error",
|
|
94
|
+
item: validatorResult
|
|
95
|
+
}))
|
|
96
|
+
);
|
|
102
97
|
}
|
|
103
98
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const constructorType = obj.constructor;
|
|
122
|
-
if (constructorType && !isBuiltIn(constructorType))
|
|
123
|
-
return constructorType.name;
|
|
124
|
-
return stringType;
|
|
99
|
+
const _toString = {}.toString;
|
|
100
|
+
const builtIns = [Object, Function, Array, String, Boolean, Number, Date, RegExp, Error];
|
|
101
|
+
function isBuiltIn(_constructor) {
|
|
102
|
+
for (let i = 0; i < builtIns.length; i++) {
|
|
103
|
+
if (builtIns[i] === _constructor)
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
function typeString(obj) {
|
|
109
|
+
const stringType = _toString.call(obj).slice(8, -1);
|
|
110
|
+
if (obj === null || obj === void 0)
|
|
111
|
+
return stringType.toLowerCase();
|
|
112
|
+
const constructorType = obj.constructor;
|
|
113
|
+
if (constructorType && !isBuiltIn(constructorType))
|
|
114
|
+
return constructorType.name;
|
|
115
|
+
return stringType;
|
|
125
116
|
}
|
|
126
117
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
if (!deepEquals(a[key], b[key])) {
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
return true;
|
|
188
|
-
}
|
|
189
|
-
return false;
|
|
118
|
+
function deepEquals(a, b) {
|
|
119
|
+
if (a === b) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
123
|
+
if (a.length != b.length)
|
|
124
|
+
return false;
|
|
125
|
+
for (let i = 0; i < a.length; i++) {
|
|
126
|
+
if (!deepEquals(a[i], b[i])) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
if (Array.isArray(a) != Array.isArray(b)) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
if (a && b && typeof a === "object" && typeof b === "object") {
|
|
136
|
+
const keys = Object.keys(a);
|
|
137
|
+
if (keys.length !== Object.keys(b).length) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
if (a instanceof Date && b instanceof Date) {
|
|
141
|
+
return a.getTime() === b.getTime();
|
|
142
|
+
}
|
|
143
|
+
if (a instanceof Date != b instanceof Date) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
if (a instanceof RegExp && b instanceof RegExp) {
|
|
147
|
+
return a.toString() == b.toString();
|
|
148
|
+
}
|
|
149
|
+
if (a instanceof RegExp != b instanceof RegExp) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
for (let i = 0; i < keys.length; i++) {
|
|
153
|
+
if (keys[i] === "_key") {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
for (let i = 0; i < keys.length; i++) {
|
|
161
|
+
const key = keys[i];
|
|
162
|
+
if (key === "_key") {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (!deepEquals(a[key], b[key])) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
return false;
|
|
190
172
|
}
|
|
191
173
|
|
|
192
|
-
const SLOW_VALIDATOR_TIMEOUT =
|
|
193
|
-
const formatValidationErrors = (options) => {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
children: options.results.length > 1 ? options.results : undefined,
|
|
208
|
-
operation: options.operation,
|
|
209
|
-
});
|
|
210
|
-
};
|
|
211
|
-
const genericValidators = {
|
|
212
|
-
type: (expected, value, message) => {
|
|
213
|
-
const actualType = typeString(value);
|
|
214
|
-
if (actualType !== expected && actualType !== 'undefined') {
|
|
215
|
-
return message || `Expected type "${expected}", got "${actualType}"`;
|
|
216
|
-
}
|
|
217
|
-
return true;
|
|
218
|
-
},
|
|
219
|
-
presence: (expected, value, message) => {
|
|
220
|
-
if (value === undefined && expected === 'required') {
|
|
221
|
-
return message || 'Value is required';
|
|
222
|
-
}
|
|
223
|
-
return true;
|
|
224
|
-
},
|
|
225
|
-
all: async (children, value, message, context) => {
|
|
226
|
-
const resolved = await Promise.all(children.map((child) => child.validate(value, context)));
|
|
227
|
-
const results = resolved.flat();
|
|
228
|
-
if (!results.length)
|
|
229
|
-
return true;
|
|
230
|
-
return formatValidationErrors({
|
|
231
|
-
message,
|
|
232
|
-
results,
|
|
233
|
-
operation: 'AND',
|
|
234
|
-
});
|
|
235
|
-
},
|
|
236
|
-
either: async (children, value, message, context) => {
|
|
237
|
-
const resolved = await Promise.all(children.map((child) => child.validate(value, context)));
|
|
238
|
-
const results = resolved.flat();
|
|
239
|
-
// Read: There is at least one rule that matched
|
|
240
|
-
if (results.length < children.length)
|
|
241
|
-
return true;
|
|
242
|
-
return formatValidationErrors({
|
|
243
|
-
message,
|
|
244
|
-
results,
|
|
245
|
-
operation: 'OR',
|
|
246
|
-
});
|
|
247
|
-
},
|
|
248
|
-
valid: (allowedValues, actual, message) => {
|
|
249
|
-
const valueType = typeof actual;
|
|
250
|
-
if (valueType === 'undefined') {
|
|
251
|
-
return true;
|
|
252
|
-
}
|
|
253
|
-
const value = (valueType === 'number' || valueType === 'string') && `${actual}`;
|
|
254
|
-
const strValue = value && value.length > 30 ? `${value.slice(0, 30)}…` : value;
|
|
255
|
-
const defaultMessage = value
|
|
256
|
-
? `Value "${strValue}" did not match any allowed values`
|
|
257
|
-
: 'Value did not match any allowed values';
|
|
258
|
-
return allowedValues.some((expected) => deepEquals(expected, actual))
|
|
259
|
-
? true
|
|
260
|
-
: message || defaultMessage;
|
|
261
|
-
},
|
|
262
|
-
custom: async (fn, value, message, context) => {
|
|
263
|
-
const slowTimer = setTimeout(() => {
|
|
264
|
-
// eslint-disable-next-line no-console
|
|
265
|
-
console.warn(`Custom validator at ${pathToString(context.path)} has taken more than ${SLOW_VALIDATOR_TIMEOUT}ms to respond`);
|
|
266
|
-
}, SLOW_VALIDATOR_TIMEOUT);
|
|
267
|
-
let result;
|
|
268
|
-
try {
|
|
269
|
-
result = await fn(value, context);
|
|
270
|
-
}
|
|
271
|
-
finally {
|
|
272
|
-
clearTimeout(slowTimer);
|
|
273
|
-
}
|
|
274
|
-
if (typeof result === 'string')
|
|
275
|
-
return message || result;
|
|
276
|
-
return result;
|
|
277
|
-
},
|
|
174
|
+
const SLOW_VALIDATOR_TIMEOUT = 5e3;
|
|
175
|
+
const formatValidationErrors = (options) => {
|
|
176
|
+
var _a;
|
|
177
|
+
let message;
|
|
178
|
+
if (options.message) {
|
|
179
|
+
message = options.message;
|
|
180
|
+
} else if (options.results.length === 1) {
|
|
181
|
+
message = (_a = options.results[0]) == null ? void 0 : _a.item.message;
|
|
182
|
+
} else {
|
|
183
|
+
message = `[${options.results.map((err) => err.item.message).join(` - ${options.operation} - `)}]`;
|
|
184
|
+
}
|
|
185
|
+
return new ValidationError(message, {
|
|
186
|
+
children: options.results.length > 1 ? options.results : void 0,
|
|
187
|
+
operation: options.operation
|
|
188
|
+
});
|
|
278
189
|
};
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
190
|
+
const genericValidators = {
|
|
191
|
+
type: (expected, value, message) => {
|
|
192
|
+
const actualType = typeString(value);
|
|
193
|
+
if (actualType !== expected && actualType !== "undefined") {
|
|
194
|
+
return message || `Expected type "${expected}", got "${actualType}"`;
|
|
195
|
+
}
|
|
196
|
+
return true;
|
|
197
|
+
},
|
|
198
|
+
presence: (expected, value, message) => {
|
|
199
|
+
if (value === void 0 && expected === "required") {
|
|
200
|
+
return message || "Value is required";
|
|
201
|
+
}
|
|
202
|
+
return true;
|
|
203
|
+
},
|
|
204
|
+
all: async (children, value, message, context) => {
|
|
205
|
+
const resolved = await Promise.all(children.map((child) => child.validate(value, context)));
|
|
206
|
+
const results = resolved.flat();
|
|
207
|
+
if (!results.length)
|
|
208
|
+
return true;
|
|
209
|
+
return formatValidationErrors({
|
|
210
|
+
message,
|
|
211
|
+
results,
|
|
212
|
+
operation: "AND"
|
|
213
|
+
});
|
|
214
|
+
},
|
|
215
|
+
either: async (children, value, message, context) => {
|
|
216
|
+
const resolved = await Promise.all(children.map((child) => child.validate(value, context)));
|
|
217
|
+
const results = resolved.flat();
|
|
218
|
+
if (results.length < children.length)
|
|
219
|
+
return true;
|
|
220
|
+
return formatValidationErrors({
|
|
221
|
+
message,
|
|
222
|
+
results,
|
|
223
|
+
operation: "OR"
|
|
224
|
+
});
|
|
225
|
+
},
|
|
226
|
+
valid: (allowedValues, actual, message) => {
|
|
227
|
+
const valueType = typeof actual;
|
|
228
|
+
if (valueType === "undefined") {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
const value = (valueType === "number" || valueType === "string") && `${actual}`;
|
|
232
|
+
const strValue = value && value.length > 30 ? `${value.slice(0, 30)}\u2026` : value;
|
|
233
|
+
const defaultMessage = value ? `Value "${strValue}" did not match any allowed values` : "Value did not match any allowed values";
|
|
234
|
+
return allowedValues.some((expected) => deepEquals(expected, actual)) ? true : message || defaultMessage;
|
|
235
|
+
},
|
|
236
|
+
custom: async (fn, value, message, context) => {
|
|
237
|
+
const slowTimer = setTimeout(() => {
|
|
238
|
+
console.warn(
|
|
239
|
+
`Custom validator at ${pathToString(
|
|
240
|
+
context.path
|
|
241
|
+
)} has taken more than ${SLOW_VALIDATOR_TIMEOUT}ms to respond`
|
|
242
|
+
);
|
|
243
|
+
}, SLOW_VALIDATOR_TIMEOUT);
|
|
244
|
+
let result;
|
|
245
|
+
try {
|
|
246
|
+
result = await fn(value, context);
|
|
247
|
+
} finally {
|
|
248
|
+
clearTimeout(slowTimer);
|
|
249
|
+
}
|
|
250
|
+
if (typeof result === "string")
|
|
251
|
+
return message || result;
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
288
254
|
};
|
|
289
255
|
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
},
|
|
299
|
-
precision: (limit, value, message) => {
|
|
300
|
-
if (value === undefined)
|
|
301
|
-
return true;
|
|
302
|
-
const places = value.toString().match(precisionRx);
|
|
303
|
-
const decimals = Math.max((places[1] ? places[1].length : 0) - (places[2] ? parseInt(places[2], 10) : 0), 0);
|
|
304
|
-
if (decimals > limit) {
|
|
305
|
-
return message || `Max precision is ${limit}`;
|
|
306
|
-
}
|
|
307
|
-
return true;
|
|
308
|
-
},
|
|
309
|
-
min: (minNum, value, message) => {
|
|
310
|
-
if (value >= minNum) {
|
|
311
|
-
return true;
|
|
312
|
-
}
|
|
313
|
-
return message || `Must be greater than or equal ${minNum}`;
|
|
314
|
-
},
|
|
315
|
-
max: (maxNum, value, message) => {
|
|
316
|
-
if (value <= maxNum) {
|
|
317
|
-
return true;
|
|
318
|
-
}
|
|
319
|
-
return message || `Must be less than or equal ${maxNum}`;
|
|
320
|
-
},
|
|
321
|
-
greaterThan: (num, value, message) => {
|
|
322
|
-
if (value > num) {
|
|
323
|
-
return true;
|
|
324
|
-
}
|
|
325
|
-
return message || `Must be greater than ${num}`;
|
|
326
|
-
},
|
|
327
|
-
lessThan: (maxNum, value, message) => {
|
|
328
|
-
if (value < maxNum) {
|
|
329
|
-
return true;
|
|
330
|
-
}
|
|
331
|
-
return message || `Must be less than ${maxNum}`;
|
|
332
|
-
},
|
|
256
|
+
const booleanValidators = {
|
|
257
|
+
...genericValidators,
|
|
258
|
+
presence: (flag, value, message) => {
|
|
259
|
+
if (flag === "required" && typeof value !== "boolean") {
|
|
260
|
+
return message || "Required";
|
|
261
|
+
}
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
333
264
|
};
|
|
334
265
|
|
|
335
|
-
const
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
}
|
|
382
|
-
const urlScheme = url.protocol.replace(/:$/, '');
|
|
383
|
-
const matchesAllowedScheme = options.scheme.some((scheme) => scheme.test(urlScheme));
|
|
384
|
-
if (!matchesAllowedScheme) {
|
|
385
|
-
return message || 'Does not match allowed protocols/schemes';
|
|
386
|
-
}
|
|
387
|
-
return true;
|
|
388
|
-
},
|
|
389
|
-
stringCasing: (casing, value, message) => {
|
|
390
|
-
const strValue = value || '';
|
|
391
|
-
if (casing === 'uppercase' && strValue !== strValue.toLocaleUpperCase()) {
|
|
392
|
-
return message || `Must be all uppercase letters`;
|
|
393
|
-
}
|
|
394
|
-
if (casing === 'lowercase' && strValue !== strValue.toLocaleLowerCase()) {
|
|
395
|
-
return message || `Must be all lowercase letters`;
|
|
396
|
-
}
|
|
397
|
-
return true;
|
|
398
|
-
},
|
|
399
|
-
presence: (flag, value, message) => {
|
|
400
|
-
if (flag === 'required' && !value) {
|
|
401
|
-
return message || 'Required';
|
|
402
|
-
}
|
|
403
|
-
return true;
|
|
404
|
-
},
|
|
405
|
-
regex: (options, value, message) => {
|
|
406
|
-
const { pattern, name, invert } = options;
|
|
407
|
-
const regName = name || `"${pattern.toString()}"`;
|
|
408
|
-
const strValue = value || '';
|
|
409
|
-
const matches = pattern.test(strValue);
|
|
410
|
-
if ((!invert && !matches) || (invert && matches)) {
|
|
411
|
-
const defaultMessage = invert
|
|
412
|
-
? `Should not match ${regName}-pattern`
|
|
413
|
-
: `Does not match ${regName}-pattern`;
|
|
414
|
-
return message || defaultMessage;
|
|
415
|
-
}
|
|
416
|
-
return true;
|
|
417
|
-
},
|
|
418
|
-
email: (_unused, value, message) => {
|
|
419
|
-
const strValue = `${value || ''}`.trim();
|
|
420
|
-
if (!strValue || emailRegex.test(strValue)) {
|
|
421
|
-
return true;
|
|
422
|
-
}
|
|
423
|
-
return message || 'Must be a valid email address';
|
|
424
|
-
},
|
|
266
|
+
const precisionRx = /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
|
|
267
|
+
const numberValidators = {
|
|
268
|
+
...genericValidators,
|
|
269
|
+
integer: (_unused, value, message) => {
|
|
270
|
+
if (!Number.isInteger(value)) {
|
|
271
|
+
return message || "Must be an integer";
|
|
272
|
+
}
|
|
273
|
+
return true;
|
|
274
|
+
},
|
|
275
|
+
precision: (limit, value, message) => {
|
|
276
|
+
if (value === void 0)
|
|
277
|
+
return true;
|
|
278
|
+
const places = value.toString().match(precisionRx);
|
|
279
|
+
const decimals = Math.max(
|
|
280
|
+
(places[1] ? places[1].length : 0) - (places[2] ? parseInt(places[2], 10) : 0),
|
|
281
|
+
0
|
|
282
|
+
);
|
|
283
|
+
if (decimals > limit) {
|
|
284
|
+
return message || `Max precision is ${limit}`;
|
|
285
|
+
}
|
|
286
|
+
return true;
|
|
287
|
+
},
|
|
288
|
+
min: (minNum, value, message) => {
|
|
289
|
+
if (value >= minNum) {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
return message || `Must be greater than or equal ${minNum}`;
|
|
293
|
+
},
|
|
294
|
+
max: (maxNum, value, message) => {
|
|
295
|
+
if (value <= maxNum) {
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
return message || `Must be less than or equal ${maxNum}`;
|
|
299
|
+
},
|
|
300
|
+
greaterThan: (num, value, message) => {
|
|
301
|
+
if (value > num) {
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
return message || `Must be greater than ${num}`;
|
|
305
|
+
},
|
|
306
|
+
lessThan: (maxNum, value, message) => {
|
|
307
|
+
if (value < maxNum) {
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
return message || `Must be less than ${maxNum}`;
|
|
311
|
+
}
|
|
425
312
|
};
|
|
426
313
|
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
314
|
+
const DUMMY_ORIGIN = "http://sanity";
|
|
315
|
+
const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
316
|
+
const isRelativeUrl = (url) => /^\.*\//.test(url);
|
|
317
|
+
const stringValidators = {
|
|
318
|
+
...genericValidators,
|
|
319
|
+
min: (minLength, value, message) => {
|
|
320
|
+
if (!value || value.length >= minLength) {
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
return message || `Must be at least ${minLength} characters long`;
|
|
324
|
+
},
|
|
325
|
+
max: (maxLength, value, message) => {
|
|
326
|
+
if (!value || value.length <= maxLength) {
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
return message || `Must be at most ${maxLength} characters long`;
|
|
330
|
+
},
|
|
331
|
+
length: (wantedLength, value, message) => {
|
|
332
|
+
const strValue = value || "";
|
|
333
|
+
if (strValue.length === wantedLength) {
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
return message || `Must be exactly ${wantedLength} characters long`;
|
|
337
|
+
},
|
|
338
|
+
uri: (constraints, value, message) => {
|
|
339
|
+
const strValue = value || "";
|
|
340
|
+
const { options } = constraints;
|
|
341
|
+
const { allowCredentials, relativeOnly } = options;
|
|
342
|
+
const allowRelative = options.allowRelative || relativeOnly;
|
|
343
|
+
let url;
|
|
344
|
+
try {
|
|
345
|
+
url = allowRelative ? new URL(strValue, DUMMY_ORIGIN) : new URL(strValue);
|
|
346
|
+
} catch (err) {
|
|
347
|
+
return message || "Not a valid URL";
|
|
348
|
+
}
|
|
349
|
+
if (relativeOnly && url.origin !== DUMMY_ORIGIN) {
|
|
350
|
+
return message || "Only relative URLs are allowed";
|
|
351
|
+
}
|
|
352
|
+
if (!allowRelative && url.origin === DUMMY_ORIGIN && isRelativeUrl(strValue)) {
|
|
353
|
+
return message || "Relative URLs are not allowed";
|
|
354
|
+
}
|
|
355
|
+
if (!allowCredentials && (url.username || url.password)) {
|
|
356
|
+
return message || `Username/password not allowed`;
|
|
357
|
+
}
|
|
358
|
+
const urlScheme = url.protocol.replace(/:$/, "");
|
|
359
|
+
const matchesAllowedScheme = options.scheme.some((scheme) => scheme.test(urlScheme));
|
|
360
|
+
if (!matchesAllowedScheme) {
|
|
361
|
+
return message || "Does not match allowed protocols/schemes";
|
|
362
|
+
}
|
|
363
|
+
return true;
|
|
364
|
+
},
|
|
365
|
+
stringCasing: (casing, value, message) => {
|
|
366
|
+
const strValue = value || "";
|
|
367
|
+
if (casing === "uppercase" && strValue !== strValue.toLocaleUpperCase()) {
|
|
368
|
+
return message || `Must be all uppercase letters`;
|
|
369
|
+
}
|
|
370
|
+
if (casing === "lowercase" && strValue !== strValue.toLocaleLowerCase()) {
|
|
371
|
+
return message || `Must be all lowercase letters`;
|
|
372
|
+
}
|
|
373
|
+
return true;
|
|
374
|
+
},
|
|
375
|
+
presence: (flag, value, message) => {
|
|
376
|
+
if (flag === "required" && !value) {
|
|
377
|
+
return message || "Required";
|
|
378
|
+
}
|
|
379
|
+
return true;
|
|
380
|
+
},
|
|
381
|
+
regex: (options, value, message) => {
|
|
382
|
+
const { pattern, name, invert } = options;
|
|
383
|
+
const regName = name || `"${pattern.toString()}"`;
|
|
384
|
+
const strValue = value || "";
|
|
385
|
+
const matches = pattern.test(strValue);
|
|
386
|
+
if (!invert && !matches || invert && matches) {
|
|
387
|
+
const defaultMessage = invert ? `Should not match ${regName}-pattern` : `Does not match ${regName}-pattern`;
|
|
388
|
+
return message || defaultMessage;
|
|
389
|
+
}
|
|
390
|
+
return true;
|
|
391
|
+
},
|
|
392
|
+
email: (_unused, value, message) => {
|
|
393
|
+
const strValue = `${value || ""}`.trim();
|
|
394
|
+
if (!strValue || emailRegex.test(strValue)) {
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
return message || "Must be a valid email address";
|
|
398
|
+
}
|
|
500
399
|
};
|
|
501
400
|
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
401
|
+
const arrayValidators = {
|
|
402
|
+
...genericValidators,
|
|
403
|
+
min: (minLength, value, message) => {
|
|
404
|
+
if (!value || value.length >= minLength) {
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
return message || `Must have at least ${minLength} items`;
|
|
408
|
+
},
|
|
409
|
+
max: (maxLength, value, message) => {
|
|
410
|
+
if (!value || value.length <= maxLength) {
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
return message || `Must have at most ${maxLength} items`;
|
|
414
|
+
},
|
|
415
|
+
length: (wantedLength, value, message) => {
|
|
416
|
+
if (!value || value.length === wantedLength) {
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
419
|
+
return message || `Must have exactly ${wantedLength} items`;
|
|
420
|
+
},
|
|
421
|
+
presence: (flag, value, message) => {
|
|
422
|
+
if (flag === "required" && !value) {
|
|
423
|
+
return message || "Required";
|
|
424
|
+
}
|
|
425
|
+
return true;
|
|
426
|
+
},
|
|
427
|
+
valid: (allowedValues, values, message) => {
|
|
428
|
+
const valueType = typeof values;
|
|
429
|
+
if (valueType === "undefined") {
|
|
430
|
+
return true;
|
|
431
|
+
}
|
|
432
|
+
const paths = [];
|
|
433
|
+
for (let i = 0; i < values.length; i++) {
|
|
434
|
+
const value = values[i];
|
|
435
|
+
if (allowedValues.some((expected) => deepEquals(expected, value))) {
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
const pathSegment = value && value._key ? { _key: value._key } : i;
|
|
439
|
+
paths.push([pathSegment]);
|
|
440
|
+
}
|
|
441
|
+
return paths.length === 0 ? true : new ValidationError(message || "Value did not match any allowed values", { paths });
|
|
442
|
+
},
|
|
443
|
+
unique: (_unused, value, message) => {
|
|
444
|
+
const dupeIndices = [];
|
|
445
|
+
if (!value) {
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
for (let x = 0; x < value.length; x++) {
|
|
449
|
+
for (let y = x + 1; y < value.length; y++) {
|
|
450
|
+
const itemA = value[x];
|
|
451
|
+
const itemB = value[y];
|
|
452
|
+
if (!deepEquals(itemA, itemB)) {
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
if (dupeIndices.indexOf(x) === -1) {
|
|
456
|
+
dupeIndices.push(x);
|
|
457
|
+
}
|
|
458
|
+
if (dupeIndices.indexOf(y) === -1) {
|
|
459
|
+
dupeIndices.push(y);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
const paths = dupeIndices.map((idx) => {
|
|
464
|
+
const item = value[idx];
|
|
465
|
+
const pathSegment = item && item._key ? { _key: item._key } : idx;
|
|
466
|
+
return [pathSegment];
|
|
467
|
+
});
|
|
468
|
+
return dupeIndices.length > 0 ? new ValidationError(message || `Can't be a duplicate`, { paths }) : true;
|
|
469
|
+
}
|
|
545
470
|
};
|
|
546
471
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
if (
|
|
562
|
-
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
},
|
|
591
|
-
min: (minDate, value, message, context) => {
|
|
592
|
-
const dateVal = parseDate(value);
|
|
593
|
-
if (!dateVal) {
|
|
594
|
-
return true; // `type()` should catch parse errors
|
|
595
|
-
}
|
|
596
|
-
if (!value || dateVal >= parseDate(minDate, true)) {
|
|
597
|
-
return true;
|
|
598
|
-
}
|
|
599
|
-
if (!context.type) {
|
|
600
|
-
throw new Error(`\`type\` was not provided in validation context.`);
|
|
601
|
-
}
|
|
602
|
-
const dateTimeOptions = isRecord$1(context.type.options)
|
|
603
|
-
? context.type.options
|
|
604
|
-
: {};
|
|
605
|
-
const date = getFormattedDate(context.type.name, minDate, dateTimeOptions);
|
|
606
|
-
return message || `Must be at or after ${date}`;
|
|
607
|
-
},
|
|
608
|
-
max: (maxDate, value, message, context) => {
|
|
609
|
-
const dateVal = parseDate(value);
|
|
610
|
-
if (!dateVal) {
|
|
611
|
-
return true; // `type()` should catch parse errors
|
|
612
|
-
}
|
|
613
|
-
if (!value || dateVal <= parseDate(maxDate, true)) {
|
|
614
|
-
return true;
|
|
615
|
-
}
|
|
616
|
-
if (!context.type) {
|
|
617
|
-
throw new Error(`\`type\` was not provided in validation context.`);
|
|
618
|
-
}
|
|
619
|
-
const dateTimeOptions = isRecord$1(context.type.options)
|
|
620
|
-
? context.type.options
|
|
621
|
-
: {};
|
|
622
|
-
const date = getFormattedDate(context.type.name, maxDate, dateTimeOptions);
|
|
623
|
-
return message || `Must be at or before ${date}`;
|
|
624
|
-
},
|
|
472
|
+
const metaKeys = ["_key", "_type", "_weak"];
|
|
473
|
+
const objectValidators = {
|
|
474
|
+
...genericValidators,
|
|
475
|
+
presence: (expected, value, message) => {
|
|
476
|
+
if (expected !== "required") {
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
479
|
+
const keys = value && Object.keys(value).filter((key) => !metaKeys.includes(key));
|
|
480
|
+
if (value === void 0 || keys && keys.length === 0) {
|
|
481
|
+
return message || "Required";
|
|
482
|
+
}
|
|
483
|
+
return true;
|
|
484
|
+
},
|
|
485
|
+
reference: async (_unused, value, message, context) => {
|
|
486
|
+
if (!value) {
|
|
487
|
+
return true;
|
|
488
|
+
}
|
|
489
|
+
if (!types.isReference(value)) {
|
|
490
|
+
return message || true;
|
|
491
|
+
}
|
|
492
|
+
const { type, getDocumentExists } = context;
|
|
493
|
+
if (!type) {
|
|
494
|
+
throw new Error(`\`type\` was not provided in validation context`);
|
|
495
|
+
}
|
|
496
|
+
if ("weak" in type && type.weak) {
|
|
497
|
+
return true;
|
|
498
|
+
}
|
|
499
|
+
if (!getDocumentExists) {
|
|
500
|
+
throw new Error(`\`getDocumentExists\` was not provided in validation context`);
|
|
501
|
+
}
|
|
502
|
+
const exists = await getDocumentExists({ id: value._ref });
|
|
503
|
+
if (!exists) {
|
|
504
|
+
return "This reference must be published";
|
|
505
|
+
}
|
|
506
|
+
return true;
|
|
507
|
+
},
|
|
508
|
+
assetRequired: (flag, value, message) => {
|
|
509
|
+
if (!value || !value.asset || !value.asset._ref) {
|
|
510
|
+
const assetType = flag.assetType || "Asset";
|
|
511
|
+
return message || `${assetType} required`;
|
|
512
|
+
}
|
|
513
|
+
return true;
|
|
514
|
+
}
|
|
625
515
|
};
|
|
626
516
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
const
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
}
|
|
698
|
-
// Alias to static method, since we often have access to an _instance_ of a rule but not the actual Rule class
|
|
699
|
-
valueOfField = Rule.valueOfField.bind(Rule);
|
|
700
|
-
error(message) {
|
|
701
|
-
const rule = this.clone();
|
|
702
|
-
rule._level = 'error';
|
|
703
|
-
rule._message = message || undefined;
|
|
704
|
-
return rule;
|
|
705
|
-
}
|
|
706
|
-
warning(message) {
|
|
707
|
-
const rule = this.clone();
|
|
708
|
-
rule._level = 'warning';
|
|
709
|
-
rule._message = message || undefined;
|
|
710
|
-
return rule;
|
|
711
|
-
}
|
|
712
|
-
info(message) {
|
|
713
|
-
const rule = this.clone();
|
|
714
|
-
rule._level = 'info';
|
|
715
|
-
rule._message = message || undefined;
|
|
716
|
-
return rule;
|
|
717
|
-
}
|
|
718
|
-
reset() {
|
|
719
|
-
this._type = this._type || undefined;
|
|
720
|
-
this._rules = (this._rules || []).filter((rule) => rule.flag === 'type');
|
|
721
|
-
this._message = undefined;
|
|
722
|
-
this._required = undefined;
|
|
723
|
-
this._level = 'error';
|
|
724
|
-
this._fieldRules = undefined;
|
|
725
|
-
return this;
|
|
726
|
-
}
|
|
727
|
-
isRequired() {
|
|
728
|
-
return this._required === 'required';
|
|
729
|
-
}
|
|
730
|
-
clone() {
|
|
731
|
-
const rule = new Rule();
|
|
732
|
-
rule._type = this._type;
|
|
733
|
-
rule._message = this._message;
|
|
734
|
-
rule._required = this._required;
|
|
735
|
-
rule._rules = lodash.cloneDeep(this._rules);
|
|
736
|
-
rule._level = this._level;
|
|
737
|
-
rule._fieldRules = this._fieldRules;
|
|
738
|
-
rule._typeDef = this._typeDef;
|
|
739
|
-
return rule;
|
|
740
|
-
}
|
|
741
|
-
cloneWithRules(rules) {
|
|
742
|
-
const rule = this.clone();
|
|
743
|
-
const newRules = new Set();
|
|
744
|
-
rules.forEach((curr) => {
|
|
745
|
-
if (curr.flag === 'type') {
|
|
746
|
-
rule._type = curr.constraint;
|
|
747
|
-
}
|
|
748
|
-
newRules.add(curr.flag);
|
|
749
|
-
});
|
|
750
|
-
rule._rules = rule._rules
|
|
751
|
-
.filter((curr) => {
|
|
752
|
-
const disallowDuplicate = ['type', 'uri', 'email'].includes(curr.flag);
|
|
753
|
-
const isDuplicate = newRules.has(curr.flag);
|
|
754
|
-
return !(disallowDuplicate && isDuplicate);
|
|
755
|
-
})
|
|
756
|
-
.concat(rules);
|
|
757
|
-
return rule;
|
|
758
|
-
}
|
|
759
|
-
merge(rule) {
|
|
760
|
-
if (this._type && rule._type && this._type !== rule._type) {
|
|
761
|
-
throw new Error('merge() failed: conflicting types');
|
|
762
|
-
}
|
|
763
|
-
const newRule = this.cloneWithRules(rule._rules);
|
|
764
|
-
newRule._type = this._type || rule._type;
|
|
765
|
-
newRule._message = this._message || rule._message;
|
|
766
|
-
newRule._required = this._mergeRequired(rule);
|
|
767
|
-
newRule._level = this._level === 'error' ? rule._level : this._level;
|
|
768
|
-
return newRule;
|
|
769
|
-
}
|
|
770
|
-
// Validation flag setters
|
|
771
|
-
type(targetType) {
|
|
772
|
-
const type = `${targetType.slice(0, 1).toUpperCase()}${targetType.slice(1)}`;
|
|
773
|
-
if (!ruleConstraintTypes$1.includes(type)) {
|
|
774
|
-
throw new Error(`Unknown type "${targetType}"`);
|
|
775
|
-
}
|
|
776
|
-
const rule = this.cloneWithRules([{ flag: 'type', constraint: type }]);
|
|
777
|
-
rule._type = type;
|
|
778
|
-
return rule;
|
|
779
|
-
}
|
|
780
|
-
all(children) {
|
|
781
|
-
return this.cloneWithRules([{ flag: 'all', constraint: children }]);
|
|
782
|
-
}
|
|
783
|
-
either(children) {
|
|
784
|
-
return this.cloneWithRules([{ flag: 'either', constraint: children }]);
|
|
785
|
-
}
|
|
786
|
-
// Shared rules
|
|
787
|
-
optional() {
|
|
788
|
-
const rule = this.cloneWithRules([{ flag: 'presence', constraint: 'optional' }]);
|
|
789
|
-
rule._required = 'optional';
|
|
790
|
-
return rule;
|
|
791
|
-
}
|
|
792
|
-
required() {
|
|
793
|
-
const rule = this.cloneWithRules([{ flag: 'presence', constraint: 'required' }]);
|
|
794
|
-
rule._required = 'required';
|
|
795
|
-
return rule;
|
|
796
|
-
}
|
|
797
|
-
custom(fn) {
|
|
798
|
-
return this.cloneWithRules([{ flag: 'custom', constraint: fn }]);
|
|
799
|
-
}
|
|
800
|
-
/**
|
|
801
|
-
* @deprecated use `Rule.custom` instead
|
|
802
|
-
*/
|
|
803
|
-
block(fn) {
|
|
804
|
-
return this.cloneWithRules([{ flag: 'custom', constraint: fn }]);
|
|
805
|
-
}
|
|
806
|
-
min(len) {
|
|
807
|
-
return this.cloneWithRules([{ flag: 'min', constraint: len }]);
|
|
808
|
-
}
|
|
809
|
-
max(len) {
|
|
810
|
-
return this.cloneWithRules([{ flag: 'max', constraint: len }]);
|
|
811
|
-
}
|
|
812
|
-
length(len) {
|
|
813
|
-
return this.cloneWithRules([{ flag: 'length', constraint: len }]);
|
|
814
|
-
}
|
|
815
|
-
valid(value) {
|
|
816
|
-
const values = Array.isArray(value) ? value : [value];
|
|
817
|
-
return this.cloneWithRules([{ flag: 'valid', constraint: values }]);
|
|
818
|
-
}
|
|
819
|
-
// Numbers only
|
|
820
|
-
integer() {
|
|
821
|
-
return this.cloneWithRules([{ flag: 'integer' }]);
|
|
822
|
-
}
|
|
823
|
-
precision(limit) {
|
|
824
|
-
return this.cloneWithRules([{ flag: 'precision', constraint: limit }]);
|
|
825
|
-
}
|
|
826
|
-
positive() {
|
|
827
|
-
return this.cloneWithRules([{ flag: 'min', constraint: 0 }]);
|
|
828
|
-
}
|
|
829
|
-
negative() {
|
|
830
|
-
return this.cloneWithRules([{ flag: 'lessThan', constraint: 0 }]);
|
|
831
|
-
}
|
|
832
|
-
greaterThan(num) {
|
|
833
|
-
return this.cloneWithRules([{ flag: 'greaterThan', constraint: num }]);
|
|
834
|
-
}
|
|
835
|
-
lessThan(num) {
|
|
836
|
-
return this.cloneWithRules([{ flag: 'lessThan', constraint: num }]);
|
|
837
|
-
}
|
|
838
|
-
// String only
|
|
839
|
-
uppercase() {
|
|
840
|
-
return this.cloneWithRules([{ flag: 'stringCasing', constraint: 'uppercase' }]);
|
|
841
|
-
}
|
|
842
|
-
lowercase() {
|
|
843
|
-
return this.cloneWithRules([{ flag: 'stringCasing', constraint: 'lowercase' }]);
|
|
844
|
-
}
|
|
845
|
-
regex(pattern, a, b) {
|
|
846
|
-
const name = typeof a === 'string' ? a : a?.name ?? b?.name;
|
|
847
|
-
const invert = typeof a === 'string' ? false : a?.invert ?? b?.invert;
|
|
848
|
-
const constraint = {
|
|
849
|
-
pattern,
|
|
850
|
-
name,
|
|
851
|
-
invert: invert || false,
|
|
852
|
-
};
|
|
853
|
-
return this.cloneWithRules([{ flag: 'regex', constraint }]);
|
|
854
|
-
}
|
|
855
|
-
email() {
|
|
856
|
-
return this.cloneWithRules([{ flag: 'email' }]);
|
|
857
|
-
}
|
|
858
|
-
uri(opts) {
|
|
859
|
-
const optsScheme = opts?.scheme || ['http', 'https'];
|
|
860
|
-
const schemes = Array.isArray(optsScheme) ? optsScheme : [optsScheme];
|
|
861
|
-
if (!schemes.length) {
|
|
862
|
-
throw new Error('scheme must have at least 1 scheme specified');
|
|
863
|
-
}
|
|
864
|
-
const constraint = {
|
|
865
|
-
options: {
|
|
866
|
-
scheme: schemes.map((scheme) => {
|
|
867
|
-
if (!(scheme instanceof RegExp) && typeof scheme !== 'string') {
|
|
868
|
-
throw new Error('scheme must be a RegExp or a String');
|
|
869
|
-
}
|
|
870
|
-
return typeof scheme === 'string' ? new RegExp(`^${escapeRegex(scheme)}$`) : scheme;
|
|
871
|
-
}),
|
|
872
|
-
allowRelative: opts?.allowRelative || false,
|
|
873
|
-
relativeOnly: opts?.relativeOnly || false,
|
|
874
|
-
allowCredentials: opts?.allowCredentials || false,
|
|
875
|
-
},
|
|
876
|
-
};
|
|
877
|
-
return this.cloneWithRules([{ flag: 'uri', constraint }]);
|
|
878
|
-
}
|
|
879
|
-
// Array only
|
|
880
|
-
unique() {
|
|
881
|
-
return this.cloneWithRules([{ flag: 'unique' }]);
|
|
882
|
-
}
|
|
883
|
-
// Objects only
|
|
884
|
-
reference() {
|
|
885
|
-
return this.cloneWithRules([{ flag: 'reference' }]);
|
|
886
|
-
}
|
|
887
|
-
fields(rules) {
|
|
888
|
-
if (this._type !== 'Object') {
|
|
889
|
-
throw new Error('fields() can only be called on an object type');
|
|
890
|
-
}
|
|
891
|
-
const rule = this.cloneWithRules([]);
|
|
892
|
-
rule._fieldRules = rules;
|
|
893
|
-
return rule;
|
|
894
|
-
}
|
|
895
|
-
assetRequired() {
|
|
896
|
-
const base = getBaseType(this._typeDef);
|
|
897
|
-
let assetType;
|
|
898
|
-
if (base && ['image', 'file'].includes(base.name)) {
|
|
899
|
-
assetType = base.name === 'image' ? 'Image' : 'File';
|
|
900
|
-
}
|
|
901
|
-
else {
|
|
902
|
-
assetType = 'Asset';
|
|
903
|
-
}
|
|
904
|
-
return this.cloneWithRules([{ flag: 'assetRequired', constraint: { assetType } }]);
|
|
905
|
-
}
|
|
906
|
-
async validate(value, context) {
|
|
907
|
-
if (!context) {
|
|
908
|
-
throw new Error('missing context');
|
|
909
|
-
}
|
|
910
|
-
const valueIsEmpty = value === null || value === undefined;
|
|
911
|
-
// Short-circuit on optional, empty fields
|
|
912
|
-
if (valueIsEmpty && this._required === 'optional') {
|
|
913
|
-
return EMPTY_ARRAY;
|
|
914
|
-
}
|
|
915
|
-
const rules =
|
|
916
|
-
// Run only the _custom_ functions if the rule is not set to required or optional
|
|
917
|
-
this._required === undefined && valueIsEmpty
|
|
918
|
-
? this._rules.filter((curr) => curr.flag === 'custom')
|
|
919
|
-
: this._rules;
|
|
920
|
-
const validators = (this._type && typeValidators[this._type]) || genericValidators;
|
|
921
|
-
const results = await Promise.all(rules.map(async (curr) => {
|
|
922
|
-
if (curr.flag === undefined) {
|
|
923
|
-
throw new Error('Invalid rule, did not contain "flag"-property');
|
|
924
|
-
}
|
|
925
|
-
const validator = validators[curr.flag];
|
|
926
|
-
if (!validator) {
|
|
927
|
-
const forType = this._type ? `type "${this._type}"` : 'rule without declared type';
|
|
928
|
-
throw new Error(`Validator for flag "${curr.flag}" not found for ${forType}`);
|
|
929
|
-
}
|
|
930
|
-
let specConstraint = 'constraint' in curr ? curr.constraint : null;
|
|
931
|
-
if (isFieldRef(specConstraint)) {
|
|
932
|
-
specConstraint = lodash.get(context.parent, specConstraint.path);
|
|
933
|
-
}
|
|
934
|
-
let result;
|
|
935
|
-
try {
|
|
936
|
-
result = await validator(specConstraint, value, this._message, context);
|
|
937
|
-
}
|
|
938
|
-
catch (err) {
|
|
939
|
-
const errorFromException = new ValidationError(`${pathToString(context.path)}: Exception occurred while validating value: ${err.message}`);
|
|
940
|
-
return convertToValidationMarker(errorFromException, 'error', context);
|
|
941
|
-
}
|
|
942
|
-
return convertToValidationMarker(result, this._level, context);
|
|
943
|
-
}));
|
|
944
|
-
return results.flat();
|
|
945
|
-
}
|
|
517
|
+
function isRecord$1(obj) {
|
|
518
|
+
return typeof obj === "object" && obj !== null && !Array.isArray(obj);
|
|
519
|
+
}
|
|
520
|
+
const isoDate = /^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/;
|
|
521
|
+
const getFormattedDate = (type = "", value, options) => {
|
|
522
|
+
let format = "yyyy-MM-dd";
|
|
523
|
+
if (options && options.dateFormat) {
|
|
524
|
+
format = options.dateFormat;
|
|
525
|
+
}
|
|
526
|
+
if (type === "date") {
|
|
527
|
+
return formatDate__default["default"](new Date(value), format);
|
|
528
|
+
}
|
|
529
|
+
if (options && options.timeFormat) {
|
|
530
|
+
format += ` ${options.timeFormat}`;
|
|
531
|
+
} else {
|
|
532
|
+
format += " HH:mm";
|
|
533
|
+
}
|
|
534
|
+
return formatDate__default["default"](new Date(value), format);
|
|
535
|
+
};
|
|
536
|
+
function parseDate(date, throwOnError = false) {
|
|
537
|
+
if (!date)
|
|
538
|
+
return null;
|
|
539
|
+
if (date === "now")
|
|
540
|
+
return new Date();
|
|
541
|
+
const parsed = new Date(date);
|
|
542
|
+
const isInvalid = isNaN(parsed.getTime());
|
|
543
|
+
if (isInvalid && throwOnError) {
|
|
544
|
+
throw new Error(`Unable to parse "${date}" to a date`);
|
|
545
|
+
}
|
|
546
|
+
return isInvalid ? null : parsed;
|
|
547
|
+
}
|
|
548
|
+
const dateValidators = {
|
|
549
|
+
...genericValidators,
|
|
550
|
+
type: (_unused, value, message) => {
|
|
551
|
+
const strVal = `${value}`;
|
|
552
|
+
if (!strVal || isoDate.test(value)) {
|
|
553
|
+
return true;
|
|
554
|
+
}
|
|
555
|
+
return message || "Must be a valid ISO-8601 formatted date string";
|
|
556
|
+
},
|
|
557
|
+
min: (minDate, value, message, context) => {
|
|
558
|
+
const dateVal = parseDate(value);
|
|
559
|
+
if (!dateVal) {
|
|
560
|
+
return true;
|
|
561
|
+
}
|
|
562
|
+
if (!value || dateVal >= parseDate(minDate, true)) {
|
|
563
|
+
return true;
|
|
564
|
+
}
|
|
565
|
+
if (!context.type) {
|
|
566
|
+
throw new Error(`\`type\` was not provided in validation context.`);
|
|
567
|
+
}
|
|
568
|
+
const dateTimeOptions = isRecord$1(context.type.options) ? context.type.options : {};
|
|
569
|
+
const date = getFormattedDate(context.type.name, minDate, dateTimeOptions);
|
|
570
|
+
return message || `Must be at or after ${date}`;
|
|
571
|
+
},
|
|
572
|
+
max: (maxDate, value, message, context) => {
|
|
573
|
+
const dateVal = parseDate(value);
|
|
574
|
+
if (!dateVal) {
|
|
575
|
+
return true;
|
|
576
|
+
}
|
|
577
|
+
if (!value || dateVal <= parseDate(maxDate, true)) {
|
|
578
|
+
return true;
|
|
579
|
+
}
|
|
580
|
+
if (!context.type) {
|
|
581
|
+
throw new Error(`\`type\` was not provided in validation context.`);
|
|
582
|
+
}
|
|
583
|
+
const dateTimeOptions = isRecord$1(context.type.options) ? context.type.options : {};
|
|
584
|
+
const date = getFormattedDate(context.type.name, maxDate, dateTimeOptions);
|
|
585
|
+
return message || `Must be at or before ${date}`;
|
|
586
|
+
}
|
|
946
587
|
};
|
|
947
588
|
|
|
948
|
-
|
|
949
|
-
const
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
}, '');
|
|
965
|
-
}
|
|
966
|
-
const defaultIsUnique = (slug, context) => {
|
|
967
|
-
const { client, document, path, type } = context;
|
|
968
|
-
const schemaOptions = type?.options;
|
|
969
|
-
if (!document) {
|
|
970
|
-
throw new Error(`\`document\` was not provided in validation context.`);
|
|
971
|
-
}
|
|
972
|
-
if (!path) {
|
|
973
|
-
throw new Error(`\`path\` was not provided in validation context.`);
|
|
974
|
-
}
|
|
975
|
-
const disableArrayWarning = schemaOptions?.disableArrayWarning || false;
|
|
976
|
-
const { published, draft } = getDocumentIds(document._id);
|
|
977
|
-
const docType = document._type;
|
|
978
|
-
const atPath = serializePath(path.concat('current'));
|
|
979
|
-
if (!disableArrayWarning && atPath.includes('[]')) {
|
|
980
|
-
memoizedWarnOnArraySlug(serializePath(path));
|
|
981
|
-
}
|
|
982
|
-
const constraints = [
|
|
983
|
-
'_type == $docType',
|
|
984
|
-
`!(_id in [$draft, $published])`,
|
|
985
|
-
`${atPath} == $slug`,
|
|
986
|
-
].join(' && ');
|
|
987
|
-
return client.fetch(`!defined(*[${constraints}][0]._id)`, {
|
|
988
|
-
docType,
|
|
989
|
-
draft,
|
|
990
|
-
published,
|
|
991
|
-
slug,
|
|
992
|
-
}, { tag: 'validation.slug-is-unique' });
|
|
993
|
-
};
|
|
994
|
-
function warnOnArraySlug(serializedPath) {
|
|
995
|
-
/* eslint-disable no-console */
|
|
996
|
-
console.warn([
|
|
997
|
-
`Slug field at path ${serializedPath} is within an array and cannot be automatically checked for uniqueness`,
|
|
998
|
-
`If you need to check for uniqueness, provide your own "isUnique" method`,
|
|
999
|
-
`To disable this message, set \`disableArrayWarning: true\` on the slug \`options\` field`,
|
|
1000
|
-
].join('\n'));
|
|
1001
|
-
/* eslint-enable no-console */
|
|
1002
|
-
}
|
|
1003
|
-
/**
|
|
1004
|
-
* Validates slugs values by querying for uniqueness from the client.
|
|
1005
|
-
*
|
|
1006
|
-
* This is a custom rule implementation (e.g. `Rule.custom(slugValidator)`)
|
|
1007
|
-
* that's populated in `inferFromSchemaType` when the type name is `slug`
|
|
1008
|
-
*/
|
|
1009
|
-
const slugValidator = async (value, context) => {
|
|
1010
|
-
if (!value) {
|
|
1011
|
-
return true;
|
|
1012
|
-
}
|
|
1013
|
-
if (typeof value !== 'object') {
|
|
1014
|
-
return 'Slug must be an object';
|
|
1015
|
-
}
|
|
1016
|
-
const slugValue = value.current;
|
|
1017
|
-
if (!slugValue) {
|
|
1018
|
-
return 'Slug must have a value';
|
|
1019
|
-
}
|
|
1020
|
-
const options = context?.type?.options;
|
|
1021
|
-
const isUnique = options?.isUnique || defaultIsUnique;
|
|
1022
|
-
const wasUnique = await isUnique(slugValue, { ...context, defaultIsUnique });
|
|
1023
|
-
if (wasUnique) {
|
|
1024
|
-
return true;
|
|
1025
|
-
}
|
|
1026
|
-
return 'Slug is already in use';
|
|
589
|
+
var _a;
|
|
590
|
+
const typeValidators = {
|
|
591
|
+
Boolean: booleanValidators,
|
|
592
|
+
Number: numberValidators,
|
|
593
|
+
String: stringValidators,
|
|
594
|
+
Array: arrayValidators,
|
|
595
|
+
Object: objectValidators,
|
|
596
|
+
Date: dateValidators
|
|
597
|
+
};
|
|
598
|
+
const getBaseType = (type) => {
|
|
599
|
+
return type && type.type ? getBaseType(type.type) : type;
|
|
600
|
+
};
|
|
601
|
+
const isFieldRef = (constraint) => {
|
|
602
|
+
if (typeof constraint !== "object" || !constraint)
|
|
603
|
+
return false;
|
|
604
|
+
return constraint.type === Rule.FIELD_REF;
|
|
1027
605
|
};
|
|
606
|
+
const EMPTY_ARRAY = [];
|
|
607
|
+
const FIELD_REF = Symbol("FIELD_REF");
|
|
608
|
+
const ruleConstraintTypes$1 = [
|
|
609
|
+
"Array",
|
|
610
|
+
"Boolean",
|
|
611
|
+
"Date",
|
|
612
|
+
"Number",
|
|
613
|
+
"Object",
|
|
614
|
+
"String"
|
|
615
|
+
];
|
|
616
|
+
const Rule = (_a = class {
|
|
617
|
+
constructor(typeDef) {
|
|
618
|
+
this._type = void 0;
|
|
619
|
+
this._level = void 0;
|
|
620
|
+
this._required = void 0;
|
|
621
|
+
this._typeDef = void 0;
|
|
622
|
+
this._message = void 0;
|
|
623
|
+
this._rules = [];
|
|
624
|
+
this._fieldRules = void 0;
|
|
625
|
+
this.valueOfField = _a.valueOfField.bind(_a);
|
|
626
|
+
this._typeDef = typeDef;
|
|
627
|
+
this.reset();
|
|
628
|
+
}
|
|
629
|
+
_mergeRequired(next) {
|
|
630
|
+
if (this._required === "required" || next._required === "required")
|
|
631
|
+
return "required";
|
|
632
|
+
if (this._required === "optional" || next._required === "optional")
|
|
633
|
+
return "optional";
|
|
634
|
+
return void 0;
|
|
635
|
+
}
|
|
636
|
+
error(message) {
|
|
637
|
+
const rule = this.clone();
|
|
638
|
+
rule._level = "error";
|
|
639
|
+
rule._message = message || void 0;
|
|
640
|
+
return rule;
|
|
641
|
+
}
|
|
642
|
+
warning(message) {
|
|
643
|
+
const rule = this.clone();
|
|
644
|
+
rule._level = "warning";
|
|
645
|
+
rule._message = message || void 0;
|
|
646
|
+
return rule;
|
|
647
|
+
}
|
|
648
|
+
info(message) {
|
|
649
|
+
const rule = this.clone();
|
|
650
|
+
rule._level = "info";
|
|
651
|
+
rule._message = message || void 0;
|
|
652
|
+
return rule;
|
|
653
|
+
}
|
|
654
|
+
reset() {
|
|
655
|
+
this._type = this._type || void 0;
|
|
656
|
+
this._rules = (this._rules || []).filter((rule) => rule.flag === "type");
|
|
657
|
+
this._message = void 0;
|
|
658
|
+
this._required = void 0;
|
|
659
|
+
this._level = "error";
|
|
660
|
+
this._fieldRules = void 0;
|
|
661
|
+
return this;
|
|
662
|
+
}
|
|
663
|
+
isRequired() {
|
|
664
|
+
return this._required === "required";
|
|
665
|
+
}
|
|
666
|
+
clone() {
|
|
667
|
+
const rule = new _a();
|
|
668
|
+
rule._type = this._type;
|
|
669
|
+
rule._message = this._message;
|
|
670
|
+
rule._required = this._required;
|
|
671
|
+
rule._rules = lodash.cloneDeep(this._rules);
|
|
672
|
+
rule._level = this._level;
|
|
673
|
+
rule._fieldRules = this._fieldRules;
|
|
674
|
+
rule._typeDef = this._typeDef;
|
|
675
|
+
return rule;
|
|
676
|
+
}
|
|
677
|
+
cloneWithRules(rules) {
|
|
678
|
+
const rule = this.clone();
|
|
679
|
+
const newRules = /* @__PURE__ */ new Set();
|
|
680
|
+
rules.forEach((curr) => {
|
|
681
|
+
if (curr.flag === "type") {
|
|
682
|
+
rule._type = curr.constraint;
|
|
683
|
+
}
|
|
684
|
+
newRules.add(curr.flag);
|
|
685
|
+
});
|
|
686
|
+
rule._rules = rule._rules.filter((curr) => {
|
|
687
|
+
const disallowDuplicate = ["type", "uri", "email"].includes(curr.flag);
|
|
688
|
+
const isDuplicate = newRules.has(curr.flag);
|
|
689
|
+
return !(disallowDuplicate && isDuplicate);
|
|
690
|
+
}).concat(rules);
|
|
691
|
+
return rule;
|
|
692
|
+
}
|
|
693
|
+
merge(rule) {
|
|
694
|
+
if (this._type && rule._type && this._type !== rule._type) {
|
|
695
|
+
throw new Error("merge() failed: conflicting types");
|
|
696
|
+
}
|
|
697
|
+
const newRule = this.cloneWithRules(rule._rules);
|
|
698
|
+
newRule._type = this._type || rule._type;
|
|
699
|
+
newRule._message = this._message || rule._message;
|
|
700
|
+
newRule._required = this._mergeRequired(rule);
|
|
701
|
+
newRule._level = this._level === "error" ? rule._level : this._level;
|
|
702
|
+
return newRule;
|
|
703
|
+
}
|
|
704
|
+
type(targetType) {
|
|
705
|
+
const type = `${targetType.slice(0, 1).toUpperCase()}${targetType.slice(1)}`;
|
|
706
|
+
if (!ruleConstraintTypes$1.includes(type)) {
|
|
707
|
+
throw new Error(`Unknown type "${targetType}"`);
|
|
708
|
+
}
|
|
709
|
+
const rule = this.cloneWithRules([{ flag: "type", constraint: type }]);
|
|
710
|
+
rule._type = type;
|
|
711
|
+
return rule;
|
|
712
|
+
}
|
|
713
|
+
all(children) {
|
|
714
|
+
return this.cloneWithRules([{ flag: "all", constraint: children }]);
|
|
715
|
+
}
|
|
716
|
+
either(children) {
|
|
717
|
+
return this.cloneWithRules([{ flag: "either", constraint: children }]);
|
|
718
|
+
}
|
|
719
|
+
optional() {
|
|
720
|
+
const rule = this.cloneWithRules([{ flag: "presence", constraint: "optional" }]);
|
|
721
|
+
rule._required = "optional";
|
|
722
|
+
return rule;
|
|
723
|
+
}
|
|
724
|
+
required() {
|
|
725
|
+
const rule = this.cloneWithRules([{ flag: "presence", constraint: "required" }]);
|
|
726
|
+
rule._required = "required";
|
|
727
|
+
return rule;
|
|
728
|
+
}
|
|
729
|
+
custom(fn) {
|
|
730
|
+
return this.cloneWithRules([{ flag: "custom", constraint: fn }]);
|
|
731
|
+
}
|
|
732
|
+
block(fn) {
|
|
733
|
+
return this.cloneWithRules([{ flag: "custom", constraint: fn }]);
|
|
734
|
+
}
|
|
735
|
+
min(len) {
|
|
736
|
+
return this.cloneWithRules([{ flag: "min", constraint: len }]);
|
|
737
|
+
}
|
|
738
|
+
max(len) {
|
|
739
|
+
return this.cloneWithRules([{ flag: "max", constraint: len }]);
|
|
740
|
+
}
|
|
741
|
+
length(len) {
|
|
742
|
+
return this.cloneWithRules([{ flag: "length", constraint: len }]);
|
|
743
|
+
}
|
|
744
|
+
valid(value) {
|
|
745
|
+
const values = Array.isArray(value) ? value : [value];
|
|
746
|
+
return this.cloneWithRules([{ flag: "valid", constraint: values }]);
|
|
747
|
+
}
|
|
748
|
+
integer() {
|
|
749
|
+
return this.cloneWithRules([{ flag: "integer" }]);
|
|
750
|
+
}
|
|
751
|
+
precision(limit) {
|
|
752
|
+
return this.cloneWithRules([{ flag: "precision", constraint: limit }]);
|
|
753
|
+
}
|
|
754
|
+
positive() {
|
|
755
|
+
return this.cloneWithRules([{ flag: "min", constraint: 0 }]);
|
|
756
|
+
}
|
|
757
|
+
negative() {
|
|
758
|
+
return this.cloneWithRules([{ flag: "lessThan", constraint: 0 }]);
|
|
759
|
+
}
|
|
760
|
+
greaterThan(num) {
|
|
761
|
+
return this.cloneWithRules([{ flag: "greaterThan", constraint: num }]);
|
|
762
|
+
}
|
|
763
|
+
lessThan(num) {
|
|
764
|
+
return this.cloneWithRules([{ flag: "lessThan", constraint: num }]);
|
|
765
|
+
}
|
|
766
|
+
uppercase() {
|
|
767
|
+
return this.cloneWithRules([{ flag: "stringCasing", constraint: "uppercase" }]);
|
|
768
|
+
}
|
|
769
|
+
lowercase() {
|
|
770
|
+
return this.cloneWithRules([{ flag: "stringCasing", constraint: "lowercase" }]);
|
|
771
|
+
}
|
|
772
|
+
regex(pattern, a, b) {
|
|
773
|
+
var _a2, _b;
|
|
774
|
+
const name = typeof a === "string" ? a : (_a2 = a == null ? void 0 : a.name) != null ? _a2 : b == null ? void 0 : b.name;
|
|
775
|
+
const invert = typeof a === "string" ? false : (_b = a == null ? void 0 : a.invert) != null ? _b : b == null ? void 0 : b.invert;
|
|
776
|
+
const constraint = {
|
|
777
|
+
pattern,
|
|
778
|
+
name,
|
|
779
|
+
invert: invert || false
|
|
780
|
+
};
|
|
781
|
+
return this.cloneWithRules([{ flag: "regex", constraint }]);
|
|
782
|
+
}
|
|
783
|
+
email() {
|
|
784
|
+
return this.cloneWithRules([{ flag: "email" }]);
|
|
785
|
+
}
|
|
786
|
+
uri(opts) {
|
|
787
|
+
const optsScheme = (opts == null ? void 0 : opts.scheme) || ["http", "https"];
|
|
788
|
+
const schemes = Array.isArray(optsScheme) ? optsScheme : [optsScheme];
|
|
789
|
+
if (!schemes.length) {
|
|
790
|
+
throw new Error("scheme must have at least 1 scheme specified");
|
|
791
|
+
}
|
|
792
|
+
const constraint = {
|
|
793
|
+
options: {
|
|
794
|
+
scheme: schemes.map((scheme) => {
|
|
795
|
+
if (!(scheme instanceof RegExp) && typeof scheme !== "string") {
|
|
796
|
+
throw new Error("scheme must be a RegExp or a String");
|
|
797
|
+
}
|
|
798
|
+
return typeof scheme === "string" ? new RegExp(`^${escapeRegex(scheme)}$`) : scheme;
|
|
799
|
+
}),
|
|
800
|
+
allowRelative: (opts == null ? void 0 : opts.allowRelative) || false,
|
|
801
|
+
relativeOnly: (opts == null ? void 0 : opts.relativeOnly) || false,
|
|
802
|
+
allowCredentials: (opts == null ? void 0 : opts.allowCredentials) || false
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
return this.cloneWithRules([{ flag: "uri", constraint }]);
|
|
806
|
+
}
|
|
807
|
+
unique() {
|
|
808
|
+
return this.cloneWithRules([{ flag: "unique" }]);
|
|
809
|
+
}
|
|
810
|
+
reference() {
|
|
811
|
+
return this.cloneWithRules([{ flag: "reference" }]);
|
|
812
|
+
}
|
|
813
|
+
fields(rules) {
|
|
814
|
+
if (this._type !== "Object") {
|
|
815
|
+
throw new Error("fields() can only be called on an object type");
|
|
816
|
+
}
|
|
817
|
+
const rule = this.cloneWithRules([]);
|
|
818
|
+
rule._fieldRules = rules;
|
|
819
|
+
return rule;
|
|
820
|
+
}
|
|
821
|
+
assetRequired() {
|
|
822
|
+
const base = getBaseType(this._typeDef);
|
|
823
|
+
let assetType;
|
|
824
|
+
if (base && ["image", "file"].includes(base.name)) {
|
|
825
|
+
assetType = base.name === "image" ? "Image" : "File";
|
|
826
|
+
} else {
|
|
827
|
+
assetType = "Asset";
|
|
828
|
+
}
|
|
829
|
+
return this.cloneWithRules([{ flag: "assetRequired", constraint: { assetType } }]);
|
|
830
|
+
}
|
|
831
|
+
async validate(value, context) {
|
|
832
|
+
if (!context) {
|
|
833
|
+
throw new Error("missing context");
|
|
834
|
+
}
|
|
835
|
+
const valueIsEmpty = value === null || value === void 0;
|
|
836
|
+
if (valueIsEmpty && this._required === "optional") {
|
|
837
|
+
return EMPTY_ARRAY;
|
|
838
|
+
}
|
|
839
|
+
const rules = this._required === void 0 && valueIsEmpty ? this._rules.filter((curr) => curr.flag === "custom") : this._rules;
|
|
840
|
+
const validators = this._type && typeValidators[this._type] || genericValidators;
|
|
841
|
+
const results = await Promise.all(
|
|
842
|
+
rules.map(async (curr) => {
|
|
843
|
+
if (curr.flag === void 0) {
|
|
844
|
+
throw new Error('Invalid rule, did not contain "flag"-property');
|
|
845
|
+
}
|
|
846
|
+
const validator = validators[curr.flag];
|
|
847
|
+
if (!validator) {
|
|
848
|
+
const forType = this._type ? `type "${this._type}"` : "rule without declared type";
|
|
849
|
+
throw new Error(`Validator for flag "${curr.flag}" not found for ${forType}`);
|
|
850
|
+
}
|
|
851
|
+
let specConstraint = "constraint" in curr ? curr.constraint : null;
|
|
852
|
+
if (isFieldRef(specConstraint)) {
|
|
853
|
+
specConstraint = lodash.get(context.parent, specConstraint.path);
|
|
854
|
+
}
|
|
855
|
+
let result;
|
|
856
|
+
try {
|
|
857
|
+
result = await validator(specConstraint, value, this._message, context);
|
|
858
|
+
} catch (err) {
|
|
859
|
+
const errorFromException = new ValidationError(
|
|
860
|
+
`${pathToString(context.path)}: Exception occurred while validating value: ${err.message}`
|
|
861
|
+
);
|
|
862
|
+
return convertToValidationMarker(errorFromException, "error", context);
|
|
863
|
+
}
|
|
864
|
+
return convertToValidationMarker(result, this._level, context);
|
|
865
|
+
})
|
|
866
|
+
);
|
|
867
|
+
return results.flat();
|
|
868
|
+
}
|
|
869
|
+
}, _a.FIELD_REF = FIELD_REF, _a.array = (def) => new _a(def).type("Array"), _a.object = (def) => new _a(def).type("Object"), _a.string = (def) => new _a(def).type("String"), _a.number = (def) => new _a(def).type("Number"), _a.boolean = (def) => new _a(def).type("Boolean"), _a.dateTime = (def) => new _a(def).type("Date"), _a.valueOfField = (path) => ({
|
|
870
|
+
type: FIELD_REF,
|
|
871
|
+
path
|
|
872
|
+
}), _a);
|
|
1028
873
|
|
|
1029
|
-
const
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
}
|
|
1078
|
-
function
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
return false;
|
|
1087
|
-
return typeDef.fields.some((field) => field.name === 'value');
|
|
1088
|
-
}
|
|
1089
|
-
function extractValueFromListOption(option, typeDef) {
|
|
1090
|
-
// If you define a `list` option with object items, where the item has a `value` field,
|
|
1091
|
-
// we don't want to treat that as the value but rather the surrounding object
|
|
1092
|
-
// This differs from the case where you have a title/value pair setup for a string/number, for instance
|
|
1093
|
-
if (typeDef.jsonType === 'object' && hasValueField(typeDef))
|
|
1094
|
-
return option;
|
|
1095
|
-
return option.value === undefined
|
|
1096
|
-
? option
|
|
1097
|
-
: option.value;
|
|
1098
|
-
}
|
|
1099
|
-
/**
|
|
1100
|
-
* Takes in `SchemaValidationValue` and returns an array of `Rule` instances.
|
|
1101
|
-
*/
|
|
1102
|
-
function normalizeValidationRules(typeDef) {
|
|
1103
|
-
if (!typeDef) {
|
|
1104
|
-
return [];
|
|
1105
|
-
}
|
|
1106
|
-
const validation = typeDef.validation;
|
|
1107
|
-
if (Array.isArray(validation)) {
|
|
1108
|
-
return validation.flatMap((i) => normalizeValidationRules({
|
|
1109
|
-
...typeDef,
|
|
1110
|
-
validation: i,
|
|
1111
|
-
}));
|
|
1112
|
-
}
|
|
1113
|
-
if (validation instanceof Rule) {
|
|
1114
|
-
return [validation];
|
|
1115
|
-
}
|
|
1116
|
-
const baseRule =
|
|
1117
|
-
// using an object + Object.values to de-dupe the type chain by type name
|
|
1118
|
-
Object.values(getTypeChain(typeDef, new Set()).reduce((acc, type) => {
|
|
1119
|
-
acc[type.name] = type;
|
|
1120
|
-
return acc;
|
|
1121
|
-
}, {})).reduce(baseRuleReducer, new Rule(typeDef));
|
|
1122
|
-
if (!validation) {
|
|
1123
|
-
return [baseRule];
|
|
1124
|
-
}
|
|
1125
|
-
return normalizeValidationRules({
|
|
1126
|
-
...typeDef,
|
|
1127
|
-
validation: validation(baseRule),
|
|
1128
|
-
});
|
|
874
|
+
const memoizedWarnOnArraySlug = lodash.memoize(warnOnArraySlug);
|
|
875
|
+
function getDocumentIds(id) {
|
|
876
|
+
const isDraft = id.indexOf("drafts.") === 0;
|
|
877
|
+
return {
|
|
878
|
+
published: isDraft ? id.slice("drafts.".length) : id,
|
|
879
|
+
draft: isDraft ? id : `drafts.${id}`
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
function serializePath(path) {
|
|
883
|
+
return path.reduce((target, part, i) => {
|
|
884
|
+
const isIndex = typeof part === "number";
|
|
885
|
+
const isKey = types.isKeyedObject(part);
|
|
886
|
+
const separator = i === 0 ? "" : ".";
|
|
887
|
+
const add = isIndex || isKey ? "[]" : `${separator}${part}`;
|
|
888
|
+
return `${target}${add}`;
|
|
889
|
+
}, "");
|
|
890
|
+
}
|
|
891
|
+
const defaultIsUnique = (slug, context) => {
|
|
892
|
+
const { client, document, path, type } = context;
|
|
893
|
+
const schemaOptions = type == null ? void 0 : type.options;
|
|
894
|
+
if (!document) {
|
|
895
|
+
throw new Error(`\`document\` was not provided in validation context.`);
|
|
896
|
+
}
|
|
897
|
+
if (!path) {
|
|
898
|
+
throw new Error(`\`path\` was not provided in validation context.`);
|
|
899
|
+
}
|
|
900
|
+
const disableArrayWarning = (schemaOptions == null ? void 0 : schemaOptions.disableArrayWarning) || false;
|
|
901
|
+
const { published, draft } = getDocumentIds(document._id);
|
|
902
|
+
const docType = document._type;
|
|
903
|
+
const atPath = serializePath(path.concat("current"));
|
|
904
|
+
if (!disableArrayWarning && atPath.includes("[]")) {
|
|
905
|
+
memoizedWarnOnArraySlug(serializePath(path));
|
|
906
|
+
}
|
|
907
|
+
const constraints = [
|
|
908
|
+
"_type == $docType",
|
|
909
|
+
`!(_id in [$draft, $published])`,
|
|
910
|
+
`${atPath} == $slug`
|
|
911
|
+
].join(" && ");
|
|
912
|
+
return client.fetch(
|
|
913
|
+
`!defined(*[${constraints}][0]._id)`,
|
|
914
|
+
{
|
|
915
|
+
docType,
|
|
916
|
+
draft,
|
|
917
|
+
published,
|
|
918
|
+
slug
|
|
919
|
+
},
|
|
920
|
+
{ tag: "validation.slug-is-unique" }
|
|
921
|
+
);
|
|
922
|
+
};
|
|
923
|
+
function warnOnArraySlug(serializedPath) {
|
|
924
|
+
console.warn(
|
|
925
|
+
[
|
|
926
|
+
`Slug field at path ${serializedPath} is within an array and cannot be automatically checked for uniqueness`,
|
|
927
|
+
`If you need to check for uniqueness, provide your own "isUnique" method`,
|
|
928
|
+
`To disable this message, set \`disableArrayWarning: true\` on the slug \`options\` field`
|
|
929
|
+
].join("\n")
|
|
930
|
+
);
|
|
1129
931
|
}
|
|
932
|
+
const slugValidator = async (value, context) => {
|
|
933
|
+
var _a;
|
|
934
|
+
if (!value) {
|
|
935
|
+
return true;
|
|
936
|
+
}
|
|
937
|
+
if (typeof value !== "object") {
|
|
938
|
+
return "Slug must be an object";
|
|
939
|
+
}
|
|
940
|
+
const slugValue = value.current;
|
|
941
|
+
if (!slugValue) {
|
|
942
|
+
return "Slug must have a value";
|
|
943
|
+
}
|
|
944
|
+
const options = (_a = context == null ? void 0 : context.type) == null ? void 0 : _a.options;
|
|
945
|
+
const isUnique = (options == null ? void 0 : options.isUnique) || defaultIsUnique;
|
|
946
|
+
const wasUnique = await isUnique(slugValue, { ...context, defaultIsUnique });
|
|
947
|
+
if (wasUnique) {
|
|
948
|
+
return true;
|
|
949
|
+
}
|
|
950
|
+
return "Slug is already in use";
|
|
951
|
+
};
|
|
1130
952
|
|
|
1131
|
-
const
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
nestedChecks = nestedChecks.concat(type.fields.map((field) => validateItem({
|
|
1220
|
-
...restOfContext,
|
|
1221
|
-
parent: value,
|
|
1222
|
-
value: isRecord(value) ? value[field.name] : undefined,
|
|
1223
|
-
path: path.concat(field.name),
|
|
1224
|
-
type: field.type,
|
|
1225
|
-
})));
|
|
1226
|
-
}
|
|
1227
|
-
// note: unlike objects, arrays should not run nested validation for undefined
|
|
1228
|
-
// values because we won't have a valid path to put a marker (i.e. missing the
|
|
1229
|
-
// key or index in the path) and the downstream form builder won't have a
|
|
1230
|
-
// valid target component
|
|
1231
|
-
const shouldRunNestedValidationForArrays = type?.jsonType === 'array' && Array.isArray(value);
|
|
1232
|
-
if (shouldRunNestedValidationForArrays) {
|
|
1233
|
-
nestedChecks = nestedChecks.concat(value.map((item) => validateItem({
|
|
1234
|
-
...restOfContext,
|
|
1235
|
-
parent: value,
|
|
1236
|
-
value: item,
|
|
1237
|
-
path: path.concat(types.isKeyedObject(item) ? { _key: item._key } : value.indexOf(item)),
|
|
1238
|
-
type: resolveTypeForArrayItem(item, type.of),
|
|
1239
|
-
})));
|
|
1240
|
-
}
|
|
1241
|
-
// markDefs also do no run nested validation if the parent object is undefined
|
|
1242
|
-
// for a similar reason to arrays
|
|
1243
|
-
const shouldRunNestedValidationForMarkDefs = types.isBlock(value) && value.markDefs.length && types.isBlockSchemaType(type);
|
|
1244
|
-
if (shouldRunNestedValidationForMarkDefs) {
|
|
1245
|
-
const [spanChildrenField] = type.fields;
|
|
1246
|
-
const spanType = spanChildrenField.type.of.find(types.isSpanSchemaType);
|
|
1247
|
-
const annotations = (spanType?.annotations || []).reduce((map, annotationType) => {
|
|
1248
|
-
map.set(annotationType.name, annotationType);
|
|
1249
|
-
return map;
|
|
1250
|
-
}, new Map());
|
|
1251
|
-
nestedChecks = nestedChecks.concat(value.markDefs.map((markDef) => validateItem({
|
|
1252
|
-
...restOfContext,
|
|
1253
|
-
parent: value,
|
|
1254
|
-
value: markDef,
|
|
1255
|
-
path: path.concat(['markDefs', { _key: markDef._key }]),
|
|
1256
|
-
type: annotations.get(markDef._type),
|
|
1257
|
-
})));
|
|
1258
|
-
}
|
|
1259
|
-
const results = (await Promise.all([...selfChecks, ...nestedChecks])).flat();
|
|
1260
|
-
// run `uniqBy` if `_fieldRules` are present because they can
|
|
1261
|
-
// cause repeat markers
|
|
1262
|
-
if (rules.some((rule) => rule._fieldRules)) {
|
|
1263
|
-
return lodash.uniqBy(results, (rule) => JSON.stringify(rule));
|
|
1264
|
-
}
|
|
1265
|
-
return results;
|
|
953
|
+
const ruleConstraintTypes = {
|
|
954
|
+
array: true,
|
|
955
|
+
boolean: true,
|
|
956
|
+
date: true,
|
|
957
|
+
number: true,
|
|
958
|
+
object: true,
|
|
959
|
+
string: true
|
|
960
|
+
};
|
|
961
|
+
const isRuleConstraint = (typeString) => typeString in ruleConstraintTypes;
|
|
962
|
+
function getTypeChain(type, visited) {
|
|
963
|
+
if (!type)
|
|
964
|
+
return [];
|
|
965
|
+
if (visited.has(type))
|
|
966
|
+
return [];
|
|
967
|
+
visited.add(type);
|
|
968
|
+
const next = type.type ? getTypeChain(type.type, visited) : [];
|
|
969
|
+
return [...next, type];
|
|
970
|
+
}
|
|
971
|
+
function baseRuleReducer(inputRule, type) {
|
|
972
|
+
let baseRule = inputRule;
|
|
973
|
+
if (isRuleConstraint(type.jsonType)) {
|
|
974
|
+
baseRule = baseRule.type(type.jsonType);
|
|
975
|
+
}
|
|
976
|
+
const typeOptionsList = (type == null ? void 0 : type.options) && typeof type.options === "object" && "list" in type.options && type.options.list;
|
|
977
|
+
if (Array.isArray(typeOptionsList)) {
|
|
978
|
+
baseRule = baseRule.valid(
|
|
979
|
+
typeOptionsList.map((option) => extractValueFromListOption(option, type))
|
|
980
|
+
);
|
|
981
|
+
}
|
|
982
|
+
if (type.name === "datetime")
|
|
983
|
+
return baseRule.type("Date");
|
|
984
|
+
if (type.name === "date")
|
|
985
|
+
return baseRule.type("Date");
|
|
986
|
+
if (type.name === "url")
|
|
987
|
+
return baseRule.uri();
|
|
988
|
+
if (type.name === "slug")
|
|
989
|
+
return baseRule.custom(slugValidator);
|
|
990
|
+
if (type.name === "reference")
|
|
991
|
+
return baseRule.reference();
|
|
992
|
+
if (type.name === "email")
|
|
993
|
+
return baseRule.email();
|
|
994
|
+
return baseRule;
|
|
995
|
+
}
|
|
996
|
+
function hasValueField(typeDef) {
|
|
997
|
+
if (!typeDef)
|
|
998
|
+
return false;
|
|
999
|
+
if (!("fields" in typeDef) && typeDef.type)
|
|
1000
|
+
return hasValueField(typeDef.type);
|
|
1001
|
+
if (!("fields" in typeDef))
|
|
1002
|
+
return false;
|
|
1003
|
+
if (!Array.isArray(typeDef.fields))
|
|
1004
|
+
return false;
|
|
1005
|
+
return typeDef.fields.some((field) => field.name === "value");
|
|
1006
|
+
}
|
|
1007
|
+
function extractValueFromListOption(option, typeDef) {
|
|
1008
|
+
if (typeDef.jsonType === "object" && hasValueField(typeDef))
|
|
1009
|
+
return option;
|
|
1010
|
+
return option.value === void 0 ? option : option.value;
|
|
1011
|
+
}
|
|
1012
|
+
function normalizeValidationRules(typeDef) {
|
|
1013
|
+
if (!typeDef) {
|
|
1014
|
+
return [];
|
|
1015
|
+
}
|
|
1016
|
+
const validation = typeDef.validation;
|
|
1017
|
+
if (Array.isArray(validation)) {
|
|
1018
|
+
return validation.flatMap(
|
|
1019
|
+
(i) => normalizeValidationRules({
|
|
1020
|
+
...typeDef,
|
|
1021
|
+
validation: i
|
|
1022
|
+
})
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
if (validation instanceof Rule) {
|
|
1026
|
+
return [validation];
|
|
1027
|
+
}
|
|
1028
|
+
const baseRule = Object.values(
|
|
1029
|
+
getTypeChain(typeDef, /* @__PURE__ */ new Set()).reduce((acc, type) => {
|
|
1030
|
+
acc[type.name] = type;
|
|
1031
|
+
return acc;
|
|
1032
|
+
}, {})
|
|
1033
|
+
).reduce(baseRuleReducer, new Rule(typeDef));
|
|
1034
|
+
if (!validation) {
|
|
1035
|
+
return [baseRule];
|
|
1036
|
+
}
|
|
1037
|
+
return normalizeValidationRules({
|
|
1038
|
+
...typeDef,
|
|
1039
|
+
validation: validation(baseRule)
|
|
1040
|
+
});
|
|
1266
1041
|
}
|
|
1267
1042
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1043
|
+
const isRecord = (maybeRecord) => typeof maybeRecord === "object" && maybeRecord !== null && !Array.isArray(maybeRecord);
|
|
1044
|
+
const isNonNullable = (value) => value !== null && value !== void 0;
|
|
1045
|
+
function resolveTypeForArrayItem(item, candidates) {
|
|
1046
|
+
if (candidates.length === 1)
|
|
1047
|
+
return candidates[0];
|
|
1048
|
+
const itemType = types.isTypedObject(item) && item._type;
|
|
1049
|
+
const primitive = item === void 0 || item === null || !itemType && typeString(item).toLowerCase();
|
|
1050
|
+
if (primitive && primitive !== "object") {
|
|
1051
|
+
return candidates.find((candidate) => candidate.jsonType === primitive);
|
|
1052
|
+
}
|
|
1053
|
+
return candidates.find((candidate) => {
|
|
1054
|
+
var _a;
|
|
1055
|
+
return ((_a = candidate.type) == null ? void 0 : _a.name) === itemType;
|
|
1056
|
+
}) || candidates.find((candidate) => candidate.name === itemType) || candidates.find((candidate) => candidate.name === "object" && primitive === "object");
|
|
1057
|
+
}
|
|
1058
|
+
async function validateDocument(client, doc, schema, context) {
|
|
1059
|
+
const documentType = schema.get(doc._type);
|
|
1060
|
+
if (!documentType) {
|
|
1061
|
+
console.warn('Schema type for object type "%s" not found, skipping validation', doc._type);
|
|
1062
|
+
return [];
|
|
1063
|
+
}
|
|
1064
|
+
try {
|
|
1065
|
+
return await validateItem({
|
|
1066
|
+
client,
|
|
1067
|
+
parent: void 0,
|
|
1068
|
+
value: doc,
|
|
1069
|
+
path: [],
|
|
1070
|
+
document: doc,
|
|
1071
|
+
type: documentType,
|
|
1072
|
+
getDocumentExists: context == null ? void 0 : context.getDocumentExists
|
|
1073
|
+
});
|
|
1074
|
+
} catch (err) {
|
|
1075
|
+
console.error(err);
|
|
1076
|
+
return [
|
|
1077
|
+
{
|
|
1078
|
+
level: "error",
|
|
1079
|
+
path: [],
|
|
1080
|
+
item: new ValidationError(err == null ? void 0 : err.message)
|
|
1081
|
+
}
|
|
1082
|
+
];
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
async function validateItem({
|
|
1086
|
+
value,
|
|
1087
|
+
type,
|
|
1088
|
+
path = [],
|
|
1089
|
+
parent,
|
|
1090
|
+
...restOfContext
|
|
1091
|
+
}) {
|
|
1092
|
+
const rules = normalizeValidationRules(type);
|
|
1093
|
+
const selfChecks = rules.map(
|
|
1094
|
+
(rule) => rule.validate(value, {
|
|
1095
|
+
...restOfContext,
|
|
1096
|
+
parent,
|
|
1097
|
+
path,
|
|
1098
|
+
type
|
|
1099
|
+
})
|
|
1100
|
+
);
|
|
1101
|
+
let nestedChecks = [];
|
|
1102
|
+
const selfIsRequired = rules.some((rule) => rule.isRequired());
|
|
1103
|
+
const shouldRunNestedObjectValidation = (type == null ? void 0 : type.jsonType) === "object" && (!!value || (value === null || value === void 0) && selfIsRequired);
|
|
1104
|
+
if (shouldRunNestedObjectValidation) {
|
|
1105
|
+
const fieldTypes = type.fields.reduce((acc, field) => {
|
|
1106
|
+
acc[field.name] = field.type;
|
|
1107
|
+
return acc;
|
|
1108
|
+
}, {});
|
|
1109
|
+
nestedChecks = nestedChecks.concat(
|
|
1110
|
+
rules.map((rule) => rule._fieldRules).filter(isNonNullable).flatMap((fieldResults) => Object.entries(fieldResults)).flatMap(([name, validation]) => {
|
|
1111
|
+
const fieldType = fieldTypes[name];
|
|
1112
|
+
return normalizeValidationRules({ ...fieldType, validation }).map((subRule) => {
|
|
1113
|
+
const nestedValue = isRecord(value) ? value[name] : void 0;
|
|
1114
|
+
return subRule.validate(nestedValue, {
|
|
1115
|
+
...restOfContext,
|
|
1116
|
+
parent: value,
|
|
1117
|
+
path: path.concat(name),
|
|
1118
|
+
type: fieldType
|
|
1119
|
+
});
|
|
1120
|
+
});
|
|
1121
|
+
})
|
|
1122
|
+
);
|
|
1123
|
+
nestedChecks = nestedChecks.concat(
|
|
1124
|
+
type.fields.map(
|
|
1125
|
+
(field) => validateItem({
|
|
1126
|
+
...restOfContext,
|
|
1127
|
+
parent: value,
|
|
1128
|
+
value: isRecord(value) ? value[field.name] : void 0,
|
|
1129
|
+
path: path.concat(field.name),
|
|
1130
|
+
type: field.type
|
|
1131
|
+
})
|
|
1132
|
+
)
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
const shouldRunNestedValidationForArrays = (type == null ? void 0 : type.jsonType) === "array" && Array.isArray(value);
|
|
1136
|
+
if (shouldRunNestedValidationForArrays) {
|
|
1137
|
+
nestedChecks = nestedChecks.concat(
|
|
1138
|
+
value.map(
|
|
1139
|
+
(item) => validateItem({
|
|
1140
|
+
...restOfContext,
|
|
1141
|
+
parent: value,
|
|
1142
|
+
value: item,
|
|
1143
|
+
path: path.concat(types.isKeyedObject(item) ? { _key: item._key } : value.indexOf(item)),
|
|
1144
|
+
type: resolveTypeForArrayItem(item, type.of)
|
|
1145
|
+
})
|
|
1146
|
+
)
|
|
1147
|
+
);
|
|
1148
|
+
}
|
|
1149
|
+
const shouldRunNestedValidationForMarkDefs = types.isBlock(value) && value.markDefs.length && types.isBlockSchemaType(type);
|
|
1150
|
+
if (shouldRunNestedValidationForMarkDefs) {
|
|
1151
|
+
const [spanChildrenField] = type.fields;
|
|
1152
|
+
const spanType = spanChildrenField.type.of.find(types.isSpanSchemaType);
|
|
1153
|
+
const annotations = ((spanType == null ? void 0 : spanType.annotations) || []).reduce(
|
|
1154
|
+
(map, annotationType) => {
|
|
1155
|
+
map.set(annotationType.name, annotationType);
|
|
1156
|
+
return map;
|
|
1157
|
+
},
|
|
1158
|
+
/* @__PURE__ */ new Map()
|
|
1159
|
+
);
|
|
1160
|
+
nestedChecks = nestedChecks.concat(
|
|
1161
|
+
value.markDefs.map(
|
|
1162
|
+
(markDef) => validateItem({
|
|
1163
|
+
...restOfContext,
|
|
1164
|
+
parent: value,
|
|
1165
|
+
value: markDef,
|
|
1166
|
+
path: path.concat(["markDefs", { _key: markDef._key }]),
|
|
1167
|
+
type: annotations.get(markDef._type)
|
|
1168
|
+
})
|
|
1169
|
+
)
|
|
1170
|
+
);
|
|
1171
|
+
}
|
|
1172
|
+
const results = (await Promise.all([...selfChecks, ...nestedChecks])).flat();
|
|
1173
|
+
if (rules.some((rule) => rule._fieldRules)) {
|
|
1174
|
+
return lodash.uniqBy(results, (rule) => JSON.stringify(rule));
|
|
1175
|
+
}
|
|
1176
|
+
return results;
|
|
1297
1177
|
}
|
|
1298
1178
|
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1179
|
+
function traverse(typeDef, visited) {
|
|
1180
|
+
if (visited.has(typeDef)) {
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
visited.add(typeDef);
|
|
1184
|
+
typeDef.validation = normalizeValidationRules(typeDef);
|
|
1185
|
+
if ("fields" in typeDef) {
|
|
1186
|
+
for (const field of typeDef.fields) {
|
|
1187
|
+
traverse(field.type, visited);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
if ("of" in typeDef) {
|
|
1191
|
+
for (const candidate of typeDef.of) {
|
|
1192
|
+
traverse(candidate, visited);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
if (typeDef.annotations) {
|
|
1196
|
+
for (const annotation of typeDef.annotations) {
|
|
1197
|
+
traverse(annotation, visited);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
function inferFromSchemaType(typeDef) {
|
|
1202
|
+
traverse(typeDef, /* @__PURE__ */ new Set());
|
|
1203
|
+
return typeDef;
|
|
1309
1204
|
}
|
|
1310
1205
|
|
|
1311
|
-
|
|
1206
|
+
function inferFromSchema(schema) {
|
|
1207
|
+
const typeNames = schema.getTypeNames();
|
|
1208
|
+
typeNames.forEach((typeName) => {
|
|
1209
|
+
const schemaType = schema.get(typeName);
|
|
1210
|
+
if (schemaType) {
|
|
1211
|
+
inferFromSchemaType(schemaType);
|
|
1212
|
+
}
|
|
1213
|
+
});
|
|
1214
|
+
return schema;
|
|
1215
|
+
}
|
|
1312
1216
|
|
|
1313
1217
|
exports.Rule = Rule;
|
|
1314
|
-
exports["default"] = index;
|
|
1315
1218
|
exports.inferFromSchema = inferFromSchema;
|
|
1316
1219
|
exports.inferFromSchemaType = inferFromSchemaType;
|
|
1317
1220
|
exports.validateDocument = validateDocument;
|