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