@sanity/validation 6.12.0-next.63 → 6.12.0-next.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -3
- package/lib/_internal.d.ts +5 -2
- package/lib/_internal.js +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -2
- package/lib/{validateDocument-CBOsd748.d.ts → validateDocument-6pLTIHIn.d.ts} +87 -9
- package/lib/{validateDocument-C77_Oewa.js → validateDocument-Cq33kUmN.js} +370 -86
- package/lib/validateDocument-Cq33kUmN.js.map +1 -0
- package/package.json +4 -4
- package/lib/validateDocument-C77_Oewa.js.map +0 -1
|
@@ -2,18 +2,64 @@ import { isArrayOfBlocksSchemaType, isKeyedObject, isReference, isSlug, isTypedO
|
|
|
2
2
|
import { createClientConcurrencyLimiter } from "@sanity/util/client";
|
|
3
3
|
import { ConcurrencyLimiter } from "@sanity/util/concurrency-limiter";
|
|
4
4
|
import flatten from "lodash-es/flatten.js";
|
|
5
|
-
import
|
|
5
|
+
import isEqual from "lodash-es/isEqual.js";
|
|
6
6
|
import { Observable, Subject, bufferTime, concat, defer, filter, finalize, firstValueFrom, from, lastValueFrom, map, merge, mergeMap, of, share, switchMap } from "rxjs";
|
|
7
7
|
import { catchError, map as map$1, mergeAll, mergeMap as mergeMap$1, switchMap as switchMap$1, toArray } from "rxjs/operators";
|
|
8
8
|
import { createInstance } from "i18next";
|
|
9
|
-
import isEqual from "lodash-es/isEqual.js";
|
|
10
9
|
import { Rule as Rule$1 } from "@sanity/schema";
|
|
11
10
|
import get from "lodash-es/get.js";
|
|
12
11
|
import isPlainObject from "lodash-es/isPlainObject.js";
|
|
13
12
|
import * as legacyDateFormat from "@sanity/util/legacyDateFormat";
|
|
14
13
|
import { getPublishedId } from "@sanity/id-utils";
|
|
15
14
|
import memoize from "lodash-es/memoize.js";
|
|
16
|
-
|
|
15
|
+
/** Machine-readable codes emitted by built-in document validation. @beta */
|
|
16
|
+
const validationMarkerCodes = {
|
|
17
|
+
arrayDuplicateItem: "array.duplicate-item",
|
|
18
|
+
arrayExactLength: "array.exact-length",
|
|
19
|
+
arrayMaximumLength: "array.maximum-length",
|
|
20
|
+
arrayMinimumLength: "array.minimum-length",
|
|
21
|
+
assetRequired: "asset.required",
|
|
22
|
+
custom: "custom",
|
|
23
|
+
dateInvalidFormat: "date.invalid-format",
|
|
24
|
+
dateMaximum: "date.maximum",
|
|
25
|
+
dateMinimum: "date.minimum",
|
|
26
|
+
documentUnknownType: "document.unknown-type",
|
|
27
|
+
mediaCustom: "media.custom",
|
|
28
|
+
mediaInvalidReference: "media.invalid-reference",
|
|
29
|
+
mediaNotFound: "media.not-found",
|
|
30
|
+
numberGreaterThan: "number.greater-than",
|
|
31
|
+
numberInteger: "number.integer",
|
|
32
|
+
numberLessThan: "number.less-than",
|
|
33
|
+
numberMaximum: "number.maximum",
|
|
34
|
+
numberMinimum: "number.minimum",
|
|
35
|
+
numberPrecision: "number.precision",
|
|
36
|
+
objectUnknownField: "object.unknown-field",
|
|
37
|
+
referenceInvalid: "reference.invalid",
|
|
38
|
+
referenceNotPublished: "reference.not-published",
|
|
39
|
+
ruleAllFailed: "rule.all-failed",
|
|
40
|
+
ruleEitherFailed: "rule.either-failed",
|
|
41
|
+
slugInvalidType: "slug.invalid-type",
|
|
42
|
+
slugMissingCurrent: "slug.missing-current",
|
|
43
|
+
slugNotUnique: "slug.not-unique",
|
|
44
|
+
stringEmail: "string.email",
|
|
45
|
+
stringExactLength: "string.exact-length",
|
|
46
|
+
stringLowercase: "string.lowercase",
|
|
47
|
+
stringMaximumLength: "string.maximum-length",
|
|
48
|
+
stringMinimumLength: "string.minimum-length",
|
|
49
|
+
stringRegexMatch: "string.regex-match",
|
|
50
|
+
stringRegexMismatch: "string.regex-mismatch",
|
|
51
|
+
stringUppercase: "string.uppercase",
|
|
52
|
+
stringUrlCredentialsNotAllowed: "string.url.credentials-not-allowed",
|
|
53
|
+
stringUrlInvalid: "string.url.invalid",
|
|
54
|
+
stringUrlNotAbsolute: "string.url.not-absolute",
|
|
55
|
+
stringUrlNotRelative: "string.url.not-relative",
|
|
56
|
+
stringUrlSchemeNotAllowed: "string.url.scheme-not-allowed",
|
|
57
|
+
validationException: "validation.exception",
|
|
58
|
+
validationFailed: "validation.failed",
|
|
59
|
+
valueNotAllowed: "value.not-allowed",
|
|
60
|
+
valueRequired: "value.required",
|
|
61
|
+
valueTypeMismatch: "value.type-mismatch"
|
|
62
|
+
}, validationLocaleStrings = {
|
|
17
63
|
"array.exact-length": "Must have exactly {{wantedLength}} items",
|
|
18
64
|
"array.exact-length_blocks": "Must have exactly {{wantedLength}} blocks",
|
|
19
65
|
"array.item-duplicate": "Can't be a duplicate",
|
|
@@ -121,25 +167,26 @@ function pathToString(path = []) {
|
|
|
121
167
|
throw Error(`Unsupported path segment "${segment}"`);
|
|
122
168
|
}, "");
|
|
123
169
|
}
|
|
124
|
-
function
|
|
125
|
-
return t !== null || t !== void 0;
|
|
126
|
-
}
|
|
127
|
-
function convertToValidationMarker(validatorResult, level, context) {
|
|
170
|
+
function convertToValidationMarker(validatorResult, level, context, fallback = { code: validationMarkerCodes.validationFailed }) {
|
|
128
171
|
if (!context) throw Error("missing context");
|
|
129
172
|
if (validatorResult === !0) return [];
|
|
130
|
-
if (Array.isArray(validatorResult)) return validatorResult.flatMap((child) => convertToValidationMarker(child, level, context))
|
|
131
|
-
if (typeof validatorResult == "string") return convertToValidationMarker({ message: validatorResult }, level, context);
|
|
173
|
+
if (Array.isArray(validatorResult)) return validatorResult.flatMap((child) => convertToValidationMarker(child, level, context, fallback));
|
|
174
|
+
if (typeof validatorResult == "string") return convertToValidationMarker({ message: validatorResult }, level, context, fallback);
|
|
132
175
|
if (typeof validatorResult.message != "string") throw Error(`${pathToString(context.path)}: Validator must return 'true' if valid or an error message as a string on errors`);
|
|
133
|
-
let { message, __internal_metadata } = validatorResult, normalizedPaths = [];
|
|
176
|
+
let { message, __internal_metadata } = validatorResult, code = validatorResult.code || fallback.code, details = validatorResult.details || fallback.details, normalizedPaths = [];
|
|
134
177
|
validatorResult.path && normalizedPaths.push(validatorResult.path);
|
|
135
178
|
for (let path of validatorResult.paths || []) normalizedPaths.push(path);
|
|
136
179
|
return normalizedPaths.length ? normalizedPaths.map((path) => ({
|
|
180
|
+
code,
|
|
181
|
+
...details && { details },
|
|
137
182
|
path: (context.path || []).concat(path),
|
|
138
183
|
level: level || "error",
|
|
139
184
|
item: { message },
|
|
140
185
|
message,
|
|
141
186
|
__internal_metadata
|
|
142
187
|
})) : [{
|
|
188
|
+
code,
|
|
189
|
+
...details && { details },
|
|
143
190
|
level: level || "error",
|
|
144
191
|
item: { message },
|
|
145
192
|
message,
|
|
@@ -223,21 +270,43 @@ function typeString(obj) {
|
|
|
223
270
|
let constructorType = obj.constructor;
|
|
224
271
|
return constructorType && !isBuiltIn(constructorType) ? constructorType.name : stringType;
|
|
225
272
|
}
|
|
226
|
-
const SLOW_VALIDATOR_TIMEOUT = 5e3, formatValidationErrors = (options) =>
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
273
|
+
const SLOW_VALIDATOR_TIMEOUT = 5e3, formatValidationErrors = (options) => {
|
|
274
|
+
let message = options.message || (options.results.length === 1 ? options.results[0]?.message : options.i18n.t("{{messages, list}}", {
|
|
275
|
+
messages: options.results.map((err) => err.message || err.item?.message),
|
|
276
|
+
formatParams: { messages: {
|
|
277
|
+
style: "long",
|
|
278
|
+
type: options.operation
|
|
279
|
+
} }
|
|
280
|
+
}));
|
|
281
|
+
return {
|
|
282
|
+
code: options.operation === "conjunction" ? validationMarkerCodes.ruleAllFailed : validationMarkerCodes.ruleEitherFailed,
|
|
283
|
+
details: { causes: options.results.map(({ code, details, item, message: causeMessage, path }) => ({
|
|
284
|
+
code: code || validationMarkerCodes.validationFailed,
|
|
285
|
+
details,
|
|
286
|
+
message: causeMessage || item?.message,
|
|
287
|
+
path
|
|
288
|
+
})) },
|
|
289
|
+
message: message || "Validation failed"
|
|
290
|
+
};
|
|
291
|
+
}, genericValidators = {
|
|
233
292
|
type: (expectedType, value, message, { i18n }) => {
|
|
234
293
|
let actualType = typeString(value);
|
|
235
|
-
return actualType !== expectedType && actualType !== "undefined" ?
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
294
|
+
return actualType !== expectedType && actualType !== "undefined" ? {
|
|
295
|
+
code: validationMarkerCodes.valueTypeMismatch,
|
|
296
|
+
details: {
|
|
297
|
+
actualType,
|
|
298
|
+
expectedType
|
|
299
|
+
},
|
|
300
|
+
message: message || i18n.t("validation:generic.incorrect-type", {
|
|
301
|
+
actualType,
|
|
302
|
+
expectedType
|
|
303
|
+
})
|
|
304
|
+
} : !0;
|
|
239
305
|
},
|
|
240
|
-
presence: (expected, value, message, { i18n }) => value === void 0 && expected === "required" ?
|
|
306
|
+
presence: (expected, value, message, { i18n }) => value === void 0 && expected === "required" ? {
|
|
307
|
+
code: validationMarkerCodes.valueRequired,
|
|
308
|
+
message: message || i18n.t("validation:generic.required")
|
|
309
|
+
} : !0,
|
|
241
310
|
all: async (children, value, message, context) => {
|
|
242
311
|
let results = (await Promise.all(children.map((child) => child.validate(value, context)))).flat();
|
|
243
312
|
return results.length === 0 || formatValidationErrors({
|
|
@@ -260,10 +329,14 @@ const SLOW_VALIDATOR_TIMEOUT = 5e3, formatValidationErrors = (options) => option
|
|
|
260
329
|
let valueType = typeof actual;
|
|
261
330
|
if (valueType === "undefined") return !0;
|
|
262
331
|
let value = (valueType === "number" || valueType === "string") && `${actual}`, strValue = value && value.length > 30 ? `${value.slice(0, 30)}…` : value;
|
|
263
|
-
return allowedValues.some((expected) => deepEqualsIgnoreKey(expected, actual)) ? !0 :
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
332
|
+
return allowedValues.some((expected) => deepEqualsIgnoreKey(expected, actual)) ? !0 : {
|
|
333
|
+
code: validationMarkerCodes.valueNotAllowed,
|
|
334
|
+
details: { allowedValuesCount: allowedValues.length },
|
|
335
|
+
message: message || i18n.t("validation:generic.not-allowed", value ? {
|
|
336
|
+
context: "hint",
|
|
337
|
+
replace: { hint: strValue }
|
|
338
|
+
} : {})
|
|
339
|
+
};
|
|
267
340
|
},
|
|
268
341
|
custom: async (fn, value, message, context) => {
|
|
269
342
|
let slowTimer = setTimeout(() => {
|
|
@@ -281,28 +354,52 @@ const SLOW_VALIDATOR_TIMEOUT = 5e3, formatValidationErrors = (options) => option
|
|
|
281
354
|
min: (minLength, value, message, { i18n, type }) => {
|
|
282
355
|
if (!value || value.length >= minLength) return !0;
|
|
283
356
|
let context = isArrayOfBlocksSchemaType(type) ? "blocks" : void 0;
|
|
284
|
-
return
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
357
|
+
return {
|
|
358
|
+
code: validationMarkerCodes.arrayMinimumLength,
|
|
359
|
+
details: {
|
|
360
|
+
actualLength: value.length,
|
|
361
|
+
minimumLength: minLength
|
|
362
|
+
},
|
|
363
|
+
message: message || i18n.t("validation:array.minimum-length", {
|
|
364
|
+
minLength,
|
|
365
|
+
context
|
|
366
|
+
})
|
|
367
|
+
};
|
|
288
368
|
},
|
|
289
369
|
max: (maxLength, value, message, { i18n, type }) => {
|
|
290
370
|
if (!value || value.length <= maxLength) return !0;
|
|
291
371
|
let context = isArrayOfBlocksSchemaType(type) ? "blocks" : void 0;
|
|
292
|
-
return
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
372
|
+
return {
|
|
373
|
+
code: validationMarkerCodes.arrayMaximumLength,
|
|
374
|
+
details: {
|
|
375
|
+
actualLength: value.length,
|
|
376
|
+
maximumLength: maxLength
|
|
377
|
+
},
|
|
378
|
+
message: message || i18n.t("validation:array.maximum-length", {
|
|
379
|
+
maxLength,
|
|
380
|
+
context
|
|
381
|
+
})
|
|
382
|
+
};
|
|
296
383
|
},
|
|
297
384
|
length: (wantedLength, value, message, { i18n, type }) => {
|
|
298
385
|
if (!value || value.length === wantedLength) return !0;
|
|
299
386
|
let context = isArrayOfBlocksSchemaType(type) ? "blocks" : void 0;
|
|
300
|
-
return
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
387
|
+
return {
|
|
388
|
+
code: validationMarkerCodes.arrayExactLength,
|
|
389
|
+
details: {
|
|
390
|
+
actualLength: value.length,
|
|
391
|
+
expectedLength: wantedLength
|
|
392
|
+
},
|
|
393
|
+
message: message || i18n.t("validation:array.exact-length", {
|
|
394
|
+
wantedLength,
|
|
395
|
+
context
|
|
396
|
+
})
|
|
397
|
+
};
|
|
304
398
|
},
|
|
305
|
-
presence: (flag, value, message, { i18n }) => flag === "required" && !value ?
|
|
399
|
+
presence: (flag, value, message, { i18n }) => flag === "required" && !value ? {
|
|
400
|
+
code: validationMarkerCodes.valueRequired,
|
|
401
|
+
message: message || i18n.t("validation:generic.required", { context: "array" })
|
|
402
|
+
} : !0,
|
|
306
403
|
valid: (allowedValues, values, message, { i18n }) => {
|
|
307
404
|
if (values === void 0) return !0;
|
|
308
405
|
let paths = [];
|
|
@@ -314,6 +411,8 @@ const SLOW_VALIDATOR_TIMEOUT = 5e3, formatValidationErrors = (options) => option
|
|
|
314
411
|
}
|
|
315
412
|
let sharedMessage = message || i18n.t("validation:generic.not-allowed");
|
|
316
413
|
return paths.map((path) => ({
|
|
414
|
+
code: validationMarkerCodes.valueNotAllowed,
|
|
415
|
+
details: { allowedValuesCount: allowedValues.length },
|
|
317
416
|
message: sharedMessage,
|
|
318
417
|
path
|
|
319
418
|
}));
|
|
@@ -330,13 +429,17 @@ const SLOW_VALIDATOR_TIMEOUT = 5e3, formatValidationErrors = (options) => option
|
|
|
330
429
|
return [item && item._key ? { _key: item._key } : idx];
|
|
331
430
|
}), sharedMessage = message || i18n.t("validation:array.item-duplicate");
|
|
332
431
|
return paths.map((path) => ({
|
|
432
|
+
code: validationMarkerCodes.arrayDuplicateItem,
|
|
333
433
|
message: sharedMessage,
|
|
334
434
|
path
|
|
335
435
|
}));
|
|
336
436
|
}
|
|
337
437
|
}, booleanValidators = {
|
|
338
438
|
...genericValidators,
|
|
339
|
-
presence: (flag, value, message, { i18n }) => flag === "required" && typeof value != "boolean" ?
|
|
439
|
+
presence: (flag, value, message, { i18n }) => flag === "required" && typeof value != "boolean" ? {
|
|
440
|
+
code: validationMarkerCodes.valueRequired,
|
|
441
|
+
message: message || i18n.t("validation:generic.required", { context: "boolean" })
|
|
442
|
+
} : !0
|
|
340
443
|
};
|
|
341
444
|
function isRecord$1(obj) {
|
|
342
445
|
return typeof obj == "object" && !!obj && !Array.isArray(obj);
|
|
@@ -354,39 +457,96 @@ function parseDate(date, throwOnError = !1) {
|
|
|
354
457
|
}
|
|
355
458
|
const dateValidators = {
|
|
356
459
|
...genericValidators,
|
|
357
|
-
type: (_unused, value, message, { i18n }) => value === void 0 || isoDate.test(`${value}`) ? !0 :
|
|
460
|
+
type: (_unused, value, message, { i18n }) => value === void 0 || isoDate.test(`${value}`) ? !0 : {
|
|
461
|
+
code: validationMarkerCodes.dateInvalidFormat,
|
|
462
|
+
details: { actualValue: value },
|
|
463
|
+
message: message || i18n.t("validation:date.invalid-format")
|
|
464
|
+
},
|
|
358
465
|
min: (minDate, value, message, { type, i18n }) => {
|
|
359
466
|
let dateVal = parseDate(value), minDateVal = parseDate(minDate, !0);
|
|
360
467
|
if (!dateVal || !value || dateVal >= minDateVal) return !0;
|
|
361
468
|
if (!type) throw Error("`type` was not provided in validation context.");
|
|
362
469
|
let dateTimeOptions = isRecord$1(type.options) ? type.options : {};
|
|
363
|
-
return
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
470
|
+
return {
|
|
471
|
+
code: validationMarkerCodes.dateMinimum,
|
|
472
|
+
details: {
|
|
473
|
+
actualValue: value,
|
|
474
|
+
minimum: minDate
|
|
475
|
+
},
|
|
476
|
+
message: message || i18n.t("validation:date.minimum", {
|
|
477
|
+
minDate: getFormattedDate(type.name, minDateVal, dateTimeOptions),
|
|
478
|
+
providedMinDate: minDate
|
|
479
|
+
})
|
|
480
|
+
};
|
|
367
481
|
},
|
|
368
482
|
max: (maxDate, value, message, { type, i18n }) => {
|
|
369
483
|
let dateVal = parseDate(value), maxDateVal = parseDate(maxDate, !0);
|
|
370
484
|
if (!dateVal || !value || dateVal <= maxDateVal) return !0;
|
|
371
485
|
if (!type) throw Error("`type` was not provided in validation context.");
|
|
372
486
|
let dateTimeOptions = isRecord$1(type.options) ? type.options : {};
|
|
373
|
-
return
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
487
|
+
return {
|
|
488
|
+
code: validationMarkerCodes.dateMaximum,
|
|
489
|
+
details: {
|
|
490
|
+
actualValue: value,
|
|
491
|
+
maximum: maxDate
|
|
492
|
+
},
|
|
493
|
+
message: message || i18n.t("validation:date.maximum", {
|
|
494
|
+
maxDate: getFormattedDate(type.name, maxDateVal, dateTimeOptions),
|
|
495
|
+
providedMaxDate: maxDate
|
|
496
|
+
})
|
|
497
|
+
};
|
|
377
498
|
}
|
|
378
499
|
}, precisionRx = /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/, numberValidators = {
|
|
379
500
|
...genericValidators,
|
|
380
|
-
integer: (_unused, value, message, { i18n }) => Number.isInteger(value) ? !0 :
|
|
501
|
+
integer: (_unused, value, message, { i18n }) => Number.isInteger(value) ? !0 : {
|
|
502
|
+
code: validationMarkerCodes.numberInteger,
|
|
503
|
+
details: { actualValue: value },
|
|
504
|
+
message: message || i18n.t("validation:number.non-integer")
|
|
505
|
+
},
|
|
381
506
|
precision: (limit, value, message, { i18n }) => {
|
|
382
507
|
if (value === void 0) return !0;
|
|
383
|
-
let places = value.toString().match(precisionRx);
|
|
384
|
-
return
|
|
508
|
+
let places = value.toString().match(precisionRx), decimals = Math.max((places[1] ? places[1].length : 0) - (places[2] ? parseInt(places[2], 10) : 0), 0);
|
|
509
|
+
return decimals > limit ? {
|
|
510
|
+
code: validationMarkerCodes.numberPrecision,
|
|
511
|
+
details: {
|
|
512
|
+
actualPrecision: decimals,
|
|
513
|
+
maximumPrecision: limit
|
|
514
|
+
},
|
|
515
|
+
message: message || i18n.t("validation:number.maximum-precision", { limit })
|
|
516
|
+
} : !0;
|
|
385
517
|
},
|
|
386
|
-
min: (minNumber, value, message, { i18n }) => value >= minNumber ||
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
518
|
+
min: (minNumber, value, message, { i18n }) => value >= minNumber || {
|
|
519
|
+
code: validationMarkerCodes.numberMinimum,
|
|
520
|
+
details: {
|
|
521
|
+
actualValue: value,
|
|
522
|
+
minimum: minNumber
|
|
523
|
+
},
|
|
524
|
+
message: message || i18n.t("validation:number.minimum", { minNumber })
|
|
525
|
+
},
|
|
526
|
+
max: (maxNumber, value, message, { i18n }) => value <= maxNumber || {
|
|
527
|
+
code: validationMarkerCodes.numberMaximum,
|
|
528
|
+
details: {
|
|
529
|
+
actualValue: value,
|
|
530
|
+
maximum: maxNumber
|
|
531
|
+
},
|
|
532
|
+
message: message || i18n.t("validation:number.maximum", { maxNumber })
|
|
533
|
+
},
|
|
534
|
+
greaterThan: (threshold, value, message, { i18n }) => value > threshold || {
|
|
535
|
+
code: validationMarkerCodes.numberGreaterThan,
|
|
536
|
+
details: {
|
|
537
|
+
actualValue: value,
|
|
538
|
+
threshold
|
|
539
|
+
},
|
|
540
|
+
message: message || i18n.t("validation:number.greater-than", { threshold })
|
|
541
|
+
},
|
|
542
|
+
lessThan: (threshold, value, message, { i18n }) => value < threshold || {
|
|
543
|
+
code: validationMarkerCodes.numberLessThan,
|
|
544
|
+
details: {
|
|
545
|
+
actualValue: value,
|
|
546
|
+
threshold
|
|
547
|
+
},
|
|
548
|
+
message: message || i18n.t("validation:number.less-than", { threshold })
|
|
549
|
+
}
|
|
390
550
|
}, metaKeys = [
|
|
391
551
|
"_key",
|
|
392
552
|
"_type",
|
|
@@ -396,20 +556,33 @@ const dateValidators = {
|
|
|
396
556
|
presence: (expected, value, message, { i18n }) => {
|
|
397
557
|
if (expected !== "required") return !0;
|
|
398
558
|
let keys = value && Object.keys(value).filter((key) => !metaKeys.includes(key));
|
|
399
|
-
return value === void 0 || keys && keys.length === 0 ?
|
|
559
|
+
return value === void 0 || keys && keys.length === 0 ? {
|
|
560
|
+
code: validationMarkerCodes.valueRequired,
|
|
561
|
+
message: message || i18n.t("validation:generic.required", { context: "object" })
|
|
562
|
+
} : !0;
|
|
400
563
|
},
|
|
401
564
|
reference: async (_unused, value, message, context) => {
|
|
402
565
|
if (!value) return !0;
|
|
403
566
|
let { type, document, getDocumentExists, i18n } = context;
|
|
404
|
-
if (!isReference(value)) return
|
|
567
|
+
if (!isReference(value)) return {
|
|
568
|
+
code: validationMarkerCodes.referenceInvalid,
|
|
569
|
+
details: { actualType: typeString(value) },
|
|
570
|
+
message: message || i18n.t("validation:object.not-reference")
|
|
571
|
+
};
|
|
405
572
|
if (!type) throw Error("`type` was not provided in validation context");
|
|
406
573
|
if ("weak" in type && type.weak) return !0;
|
|
407
574
|
if (!getDocumentExists) throw Error("`getDocumentExists` was not provided in validation context");
|
|
408
575
|
let documentId = document?._id;
|
|
409
|
-
return documentId && value._ref == getPublishedId(documentId) || await getDocumentExists({ id: value._ref }) ? !0 :
|
|
576
|
+
return documentId && value._ref == getPublishedId(documentId) || await getDocumentExists({ id: value._ref }) ? !0 : {
|
|
577
|
+
code: validationMarkerCodes.referenceNotPublished,
|
|
578
|
+
details: { referenceId: value._ref },
|
|
579
|
+
message: i18n.t("validation:object.reference-not-published", { documentId: value._ref })
|
|
580
|
+
};
|
|
410
581
|
},
|
|
411
582
|
assetRequired: (flag, value, message, { i18n }) => !value || !value.asset || !value.asset._ref ? {
|
|
412
583
|
__internal_metadata: { name: "assetRequired" },
|
|
584
|
+
code: validationMarkerCodes.assetRequired,
|
|
585
|
+
details: { assetType: flag.assetType },
|
|
413
586
|
message: message || i18n.t("validation:object.asset-required", { context: flag.assetType || "" })
|
|
414
587
|
} : !0,
|
|
415
588
|
media: async (fn, value, message, context) => {
|
|
@@ -417,14 +590,21 @@ const dateValidators = {
|
|
|
417
590
|
context.environment === "studio" && console.warn(`Media validator at ${pathToString(context.path)} has taken more than ${SLOW_VALIDATOR_TIMEOUT}ms to respond`);
|
|
418
591
|
}, SLOW_VALIDATOR_TIMEOUT);
|
|
419
592
|
if (!value) return !0;
|
|
420
|
-
if (!value || !value.media || !value.media._ref) return
|
|
593
|
+
if (!value || !value.media || !value.media._ref) return {
|
|
594
|
+
code: validationMarkerCodes.mediaInvalidReference,
|
|
595
|
+
message: context.i18n.t("validation:object.not-media-library-asset")
|
|
596
|
+
};
|
|
421
597
|
let result = !0;
|
|
422
598
|
try {
|
|
423
599
|
let [type, libraryId, documentId] = value.media._ref.split(":", 3), resourceConfig = { resource: {
|
|
424
600
|
type,
|
|
425
601
|
id: libraryId
|
|
426
602
|
} }, asset = await context.getClient({ apiVersion: "2025-02-19" }).withConfig(resourceConfig).fetch("*[_id == $id] { ..., 'currentVersion': @.currentVersion-> { ... } }[0]", { id: documentId });
|
|
427
|
-
if (!asset) return console.warn(`${context.i18n.t("validation:object.media-not-found")}\nAsset ID: ${value.media._ref}`),
|
|
603
|
+
if (!asset) return console.warn(`${context.i18n.t("validation:object.media-not-found")}\nAsset ID: ${value.media._ref}`), {
|
|
604
|
+
code: validationMarkerCodes.mediaNotFound,
|
|
605
|
+
details: { referenceId: value.media._ref },
|
|
606
|
+
message: context.i18n.t("validation:object.media-not-found")
|
|
607
|
+
};
|
|
428
608
|
result = await fn({
|
|
429
609
|
media: { asset },
|
|
430
610
|
value
|
|
@@ -452,9 +632,33 @@ const dateValidators = {
|
|
|
452
632
|
Number: numberValidators,
|
|
453
633
|
String: {
|
|
454
634
|
...genericValidators,
|
|
455
|
-
min: (minLength, value, message, { i18n }) => !value || value.length >= minLength ||
|
|
456
|
-
|
|
457
|
-
|
|
635
|
+
min: (minLength, value, message, { i18n }) => !value || value.length >= minLength || {
|
|
636
|
+
code: validationMarkerCodes.stringMinimumLength,
|
|
637
|
+
details: {
|
|
638
|
+
actualLength: value.length,
|
|
639
|
+
minimumLength: minLength
|
|
640
|
+
},
|
|
641
|
+
message: message || i18n.t("validation:string.minimum-length", { minLength })
|
|
642
|
+
},
|
|
643
|
+
max: (maxLength, value, message, { i18n }) => !value || value.length <= maxLength || {
|
|
644
|
+
code: validationMarkerCodes.stringMaximumLength,
|
|
645
|
+
details: {
|
|
646
|
+
actualLength: value.length,
|
|
647
|
+
maximumLength: maxLength
|
|
648
|
+
},
|
|
649
|
+
message: message || i18n.t("validation:string.maximum-length", { maxLength })
|
|
650
|
+
},
|
|
651
|
+
length: (wantedLength, value, message, { i18n }) => {
|
|
652
|
+
let strValue = value || "";
|
|
653
|
+
return strValue.length === wantedLength || {
|
|
654
|
+
code: validationMarkerCodes.stringExactLength,
|
|
655
|
+
details: {
|
|
656
|
+
actualLength: strValue.length,
|
|
657
|
+
expectedLength: wantedLength
|
|
658
|
+
},
|
|
659
|
+
message: message || i18n.t("validation:string.exact-length", { wantedLength })
|
|
660
|
+
};
|
|
661
|
+
},
|
|
458
662
|
uri: (constraints, value, message, { i18n }) => {
|
|
459
663
|
let strValue = value || "";
|
|
460
664
|
if (!strValue) return !0;
|
|
@@ -462,34 +666,70 @@ const dateValidators = {
|
|
|
462
666
|
try {
|
|
463
667
|
url = allowRelative ? new URL(strValue, DUMMY_ORIGIN) : new URL(strValue);
|
|
464
668
|
} catch {
|
|
465
|
-
return
|
|
669
|
+
return {
|
|
670
|
+
code: validationMarkerCodes.stringUrlInvalid,
|
|
671
|
+
message: message || i18n.t("validation:string.url.invalid")
|
|
672
|
+
};
|
|
466
673
|
}
|
|
467
|
-
if (relativeOnly && url.origin !== DUMMY_ORIGIN) return
|
|
468
|
-
|
|
469
|
-
|
|
674
|
+
if (relativeOnly && url.origin !== DUMMY_ORIGIN) return {
|
|
675
|
+
code: validationMarkerCodes.stringUrlNotRelative,
|
|
676
|
+
message: message || i18n.t("validation:string.url.not-relative")
|
|
677
|
+
};
|
|
678
|
+
if (!allowRelative && url.origin === DUMMY_ORIGIN && isRelativeUrl(strValue)) return {
|
|
679
|
+
code: validationMarkerCodes.stringUrlNotAbsolute,
|
|
680
|
+
message: message || i18n.t("validation:string.url.not-absolute")
|
|
681
|
+
};
|
|
682
|
+
if (!allowCredentials && (url.username || url.password)) return {
|
|
683
|
+
code: validationMarkerCodes.stringUrlCredentialsNotAllowed,
|
|
684
|
+
message: message || i18n.t("validation:string.url.includes-credentials")
|
|
685
|
+
};
|
|
470
686
|
let urlScheme = url.protocol.replace(/:$/, "");
|
|
471
|
-
return isRelativeUrl(strValue) || options.scheme.some((scheme) => scheme.test(urlScheme)) ? !0 :
|
|
687
|
+
return isRelativeUrl(strValue) || options.scheme.some((scheme) => scheme.test(urlScheme)) ? !0 : {
|
|
688
|
+
code: validationMarkerCodes.stringUrlSchemeNotAllowed,
|
|
689
|
+
details: { scheme: urlScheme },
|
|
690
|
+
message: message || i18n.t("validation:string.url.disallowed-scheme", { scheme: urlScheme })
|
|
691
|
+
};
|
|
472
692
|
},
|
|
473
693
|
stringCasing: (casing, value, message, { i18n }) => {
|
|
474
694
|
let strValue = value || "";
|
|
475
|
-
return casing === "uppercase" && strValue !== strValue.toLocaleUpperCase() ?
|
|
695
|
+
return casing === "uppercase" && strValue !== strValue.toLocaleUpperCase() ? {
|
|
696
|
+
code: validationMarkerCodes.stringUppercase,
|
|
697
|
+
message: message || i18n.t("validation:string.uppercase")
|
|
698
|
+
} : casing === "lowercase" && strValue !== strValue.toLocaleLowerCase() ? {
|
|
699
|
+
code: validationMarkerCodes.stringLowercase,
|
|
700
|
+
message: message || i18n.t("validation:string.lowercase")
|
|
701
|
+
} : !0;
|
|
476
702
|
},
|
|
477
|
-
presence: (flag, value, message, { i18n }) => flag === "required" && !value ?
|
|
703
|
+
presence: (flag, value, message, { i18n }) => flag === "required" && !value ? {
|
|
704
|
+
code: validationMarkerCodes.valueRequired,
|
|
705
|
+
message: message || i18n.t("validation:generic.required", { context: "string" })
|
|
706
|
+
} : !0,
|
|
478
707
|
regex: (options, value, message, { i18n }) => {
|
|
479
708
|
let { pattern, name, invert } = options, regName = name || `${pattern.toString()}`, strValue = value || "";
|
|
480
709
|
pattern.lastIndex = 0;
|
|
481
710
|
let matches = pattern.test(strValue);
|
|
482
|
-
return !invert && !matches || invert && matches ?
|
|
711
|
+
return !invert && !matches || invert && matches ? {
|
|
712
|
+
code: invert ? validationMarkerCodes.stringRegexMatch : validationMarkerCodes.stringRegexMismatch,
|
|
713
|
+
details: {
|
|
714
|
+
invert,
|
|
715
|
+
name: regName,
|
|
716
|
+
pattern: pattern.source
|
|
717
|
+
},
|
|
718
|
+
message: message || (invert ? i18n.t("validation:string.regex-match", { name: regName }) : i18n.t("validation:string.regex-does-not-match", { name: regName }))
|
|
719
|
+
} : !0;
|
|
483
720
|
},
|
|
484
721
|
email: (_unused, value, message, { i18n }) => {
|
|
485
722
|
let strValue = `${value || ""}`.trim();
|
|
486
|
-
return !strValue || emailRegex.test(strValue) ? !0 :
|
|
723
|
+
return !strValue || emailRegex.test(strValue) ? !0 : {
|
|
724
|
+
code: validationMarkerCodes.stringEmail,
|
|
725
|
+
message: message || i18n.t("validation:string.email")
|
|
726
|
+
};
|
|
487
727
|
}
|
|
488
728
|
},
|
|
489
729
|
Array: arrayValidators,
|
|
490
730
|
Object: objectValidators,
|
|
491
731
|
Date: dateValidators
|
|
492
|
-
}, isFieldRef = (constraint) => typeof constraint != "object" || !constraint ? !1 : constraint.type === Rule$2.FIELD_REF, EMPTY_ARRAY = [], Rule$2 = class Rule extends Rule$1 {
|
|
732
|
+
}, isFieldRef = (constraint) => typeof constraint != "object" || !constraint ? !1 : constraint.type === Rule$2.FIELD_REF, EMPTY_ARRAY = [], fallbackCodeForRule = (flag) => flag === "custom" ? validationMarkerCodes.custom : flag === "media" ? validationMarkerCodes.mediaCustom : flag === "all" ? validationMarkerCodes.ruleAllFailed : flag === "either" ? validationMarkerCodes.ruleEitherFailed : validationMarkerCodes.validationFailed, Rule$2 = class Rule extends Rule$1 {
|
|
493
733
|
static array = (def) => new Rule(def).type("Array");
|
|
494
734
|
static object = (def) => new Rule(def).type("Object");
|
|
495
735
|
static string = (def) => new Rule(def).type("String");
|
|
@@ -525,9 +765,13 @@ const dateValidators = {
|
|
|
525
765
|
}
|
|
526
766
|
let message = isLocalizedMessages(this._message) ? localizeMessage(this._message, context.i18n) : this._message;
|
|
527
767
|
try {
|
|
528
|
-
return convertToValidationMarker(await validator(specConstraint, value, message, context), this._level, context);
|
|
768
|
+
return convertToValidationMarker(await validator(specConstraint, value, message, context), this._level, context, { code: fallbackCodeForRule(curr.flag) });
|
|
529
769
|
} catch (err) {
|
|
530
|
-
|
|
770
|
+
let errorMessage = `${pathToString(context.path)}: Exception occurred while validating value: ${err.message}`;
|
|
771
|
+
return convertToValidationMarker({
|
|
772
|
+
code: validationMarkerCodes.validationException,
|
|
773
|
+
message: errorMessage
|
|
774
|
+
}, "error", context);
|
|
531
775
|
}
|
|
532
776
|
}))).flat();
|
|
533
777
|
}
|
|
@@ -571,15 +815,26 @@ function warnOnArraySlug(serializedPath) {
|
|
|
571
815
|
const slugValidator = async (value, context) => {
|
|
572
816
|
if (!value) return !0;
|
|
573
817
|
let { i18n } = context;
|
|
574
|
-
if (typeof value != "object" || Array.isArray(value)) return
|
|
575
|
-
|
|
818
|
+
if (typeof value != "object" || Array.isArray(value)) return {
|
|
819
|
+
code: validationMarkerCodes.slugInvalidType,
|
|
820
|
+
details: { actualType: typeString(value) },
|
|
821
|
+
message: i18n.t("validation:slug.not-object")
|
|
822
|
+
};
|
|
823
|
+
if (!isSlug(value) || value.current.trim().length === 0) return {
|
|
824
|
+
code: validationMarkerCodes.slugMissingCurrent,
|
|
825
|
+
message: i18n.t("validation:slug.missing-current")
|
|
826
|
+
};
|
|
576
827
|
let isUnique = context?.type?.options?.isUnique || defaultIsUnique, slugContext = {
|
|
577
828
|
...context,
|
|
578
829
|
parent: context.parent,
|
|
579
830
|
type: context.type,
|
|
580
831
|
defaultIsUnique
|
|
581
832
|
};
|
|
582
|
-
return await isUnique(value.current, slugContext) ? !0 :
|
|
833
|
+
return await isUnique(value.current, slugContext) ? !0 : {
|
|
834
|
+
code: validationMarkerCodes.slugNotUnique,
|
|
835
|
+
details: { slug: value.current },
|
|
836
|
+
message: i18n.t("validation:slug.not-unique", { slug: value.current })
|
|
837
|
+
};
|
|
583
838
|
}, ruleConstraintTypes = {
|
|
584
839
|
array: !0,
|
|
585
840
|
boolean: !0,
|
|
@@ -648,6 +903,11 @@ const requestIdleCallbackShim = function requestIdleCallbackShim(callback, _opti
|
|
|
648
903
|
if (typeof value != "object" || !value) return !0;
|
|
649
904
|
let fieldNames = new Set(type.fields?.map((field) => field.name));
|
|
650
905
|
return Object.keys(value).filter((key) => !key.startsWith("_")).filter((key) => !fieldNames.has(key)).map((unknownField) => ({
|
|
906
|
+
code: validationMarkerCodes.objectUnknownField,
|
|
907
|
+
details: {
|
|
908
|
+
fieldName: unknownField,
|
|
909
|
+
typeName: type.name
|
|
910
|
+
},
|
|
651
911
|
message: `Field '${unknownField}' does not exist on type '${type.name}'`,
|
|
652
912
|
path: [unknownField]
|
|
653
913
|
}));
|
|
@@ -727,6 +987,8 @@ function validateDocumentObservable({ document, getClient, i18n = getFallbackLoc
|
|
|
727
987
|
if (typeof document?._type != "string") throw Error("Tried to validate a value without a '_type'");
|
|
728
988
|
let documentType = schema.get(document._type);
|
|
729
989
|
if (!documentType) return environment === "studio" ? (console.warn("Schema type for object type \"%s\" not found, skipping validation", document._type), of([])) : of([{
|
|
990
|
+
code: validationMarkerCodes.documentUnknownType,
|
|
991
|
+
details: { documentType: document._type },
|
|
730
992
|
level: "warning",
|
|
731
993
|
message: `Could not find schema type for type '${document._type}', skipping validation`,
|
|
732
994
|
path: []
|
|
@@ -747,15 +1009,16 @@ function validateDocumentObservable({ document, getClient, i18n = getFallbackLoc
|
|
|
747
1009
|
customValidationConcurrencyLimiter,
|
|
748
1010
|
currentUser
|
|
749
1011
|
};
|
|
750
|
-
return from(i18n.loadNamespaces(["validation"])).pipe(switchMap$1(() => validateItemObservable(validationOptions)), catchError((err) => {
|
|
1012
|
+
return from(i18n.loadNamespaces(["validation"])).pipe(switchMap$1(() => validateItemObservable(validationOptions)), map$1((markers) => markers.map(toDocumentValidationMarker)), catchError((err) => {
|
|
751
1013
|
console.error(err);
|
|
752
|
-
let message = err?.message || "Unknown error"
|
|
753
|
-
|
|
1014
|
+
let message = err?.message || "Unknown error", errorMarker = {
|
|
1015
|
+
code: validationMarkerCodes.validationException,
|
|
754
1016
|
level: "error",
|
|
755
1017
|
message,
|
|
756
1018
|
item: { message },
|
|
757
1019
|
path: []
|
|
758
|
-
}
|
|
1020
|
+
};
|
|
1021
|
+
return of([errorMarker]);
|
|
759
1022
|
}));
|
|
760
1023
|
}
|
|
761
1024
|
function validateItem(opts) {
|
|
@@ -828,7 +1091,28 @@ function validateItemObservable({ value, type, path = [], parent, customValidati
|
|
|
828
1091
|
type: resolveTypeForArrayItem(item, type.of),
|
|
829
1092
|
environment,
|
|
830
1093
|
customValidationConcurrencyLimiter
|
|
831
|
-
})))), defer(() => merge([...selfChecks, ...nestedChecks])).pipe(mergeMap$1((validateNode) => concat(idle(), validateNode), 40), mergeAll(), toArray(), map$1(flatten), map$1((results) => rules.some((rule) => extractFieldRulesFromRule(rule).length > 0) ?
|
|
1094
|
+
})))), defer(() => merge([...selfChecks, ...nestedChecks])).pipe(mergeMap$1((validateNode) => concat(idle(), validateNode), 40), mergeAll(), toArray(), map$1(flatten), map$1((results) => rules.some((rule) => extractFieldRulesFromRule(rule).length > 0) ? deduplicateMarkers(results) : results));
|
|
1095
|
+
}
|
|
1096
|
+
function deduplicateMarkers(markers) {
|
|
1097
|
+
let buckets = /* @__PURE__ */ new Map();
|
|
1098
|
+
return markers.filter((marker) => {
|
|
1099
|
+
let key = JSON.stringify([
|
|
1100
|
+
marker.level,
|
|
1101
|
+
marker.code,
|
|
1102
|
+
marker.message,
|
|
1103
|
+
marker.path
|
|
1104
|
+
]), bucket = buckets.get(key);
|
|
1105
|
+
return bucket ? !bucket.some((existing) => isEqual(existing, marker)) && (bucket.push(marker), !0) : (buckets.set(key, [marker]), !0);
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
function hasValidationMarkerCode(marker) {
|
|
1109
|
+
return typeof marker.code == "string";
|
|
1110
|
+
}
|
|
1111
|
+
function toDocumentValidationMarker(marker) {
|
|
1112
|
+
return hasValidationMarkerCode(marker) ? marker : {
|
|
1113
|
+
...marker,
|
|
1114
|
+
code: validationMarkerCodes.validationFailed
|
|
1115
|
+
};
|
|
832
1116
|
}
|
|
833
1117
|
function idle(timeout) {
|
|
834
1118
|
return new Observable((observer) => {
|
|
@@ -838,6 +1122,6 @@ function idle(timeout) {
|
|
|
838
1122
|
return () => cancelIdleCallback(handle);
|
|
839
1123
|
});
|
|
840
1124
|
}
|
|
841
|
-
export { validateDocumentWithWorkspace as a, normalizeValidationRules as c, convertToValidationMarker as d, pathToString as f, validateDocumentObservable as i, Rule$2 as l, validationLocaleStrings as m, validateDocument as n, validateItem as o, getFallbackLocaleSource as p, validateDocumentInternal as r, getTypeChain as s, resolveTypeForArrayItem as t, typeString as u };
|
|
1125
|
+
export { validateDocumentWithWorkspace as a, normalizeValidationRules as c, convertToValidationMarker as d, pathToString as f, validationMarkerCodes as h, validateDocumentObservable as i, Rule$2 as l, validationLocaleStrings as m, validateDocument as n, validateItem as o, getFallbackLocaleSource as p, validateDocumentInternal as r, getTypeChain as s, resolveTypeForArrayItem as t, typeString as u };
|
|
842
1126
|
|
|
843
|
-
//# sourceMappingURL=validateDocument-
|
|
1127
|
+
//# sourceMappingURL=validateDocument-Cq33kUmN.js.map
|