@sanity/validation 3.14.4 → 6.12.0-next.32

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.
Files changed (40) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +12 -0
  3. package/lib/_internal.d.ts +93 -0
  4. package/lib/_internal.js +39 -0
  5. package/lib/_internal.js.map +1 -0
  6. package/lib/index.d.ts +2 -0
  7. package/lib/index.js +2 -1306
  8. package/lib/validateDocument-C6wlQ7gA.d.ts +151 -0
  9. package/lib/validateDocument-il4G-TLy.js +828 -0
  10. package/lib/validateDocument-il4G-TLy.js.map +1 -0
  11. package/package.json +53 -45
  12. package/lib/dts/src/index.d.ts +0 -50
  13. package/lib/index.cjs.mjs +0 -9
  14. package/lib/index.esm.js +0 -1286
  15. package/lib/index.esm.js.map +0 -1
  16. package/lib/index.js.map +0 -1
  17. package/src/Rule.ts +0 -424
  18. package/src/ValidationError.ts +0 -32
  19. package/src/index.ts +0 -9
  20. package/src/inferFromSchema.ts +0 -19
  21. package/src/inferFromSchemaType.ts +0 -50
  22. package/src/util/convertToValidationMarker.ts +0 -84
  23. package/src/util/deepEquals.ts +0 -77
  24. package/src/util/escapeRegex.ts +0 -5
  25. package/src/util/normalizeValidationRules.test.ts +0 -170
  26. package/src/util/normalizeValidationRules.ts +0 -118
  27. package/src/util/pathToString.ts +0 -21
  28. package/src/util/requestIdleCallback.ts +0 -31
  29. package/src/util/typeString.test.ts +0 -27
  30. package/src/util/typeString.ts +0 -23
  31. package/src/validateDocument.test.ts +0 -703
  32. package/src/validateDocument.ts +0 -240
  33. package/src/validators/arrayValidator.ts +0 -100
  34. package/src/validators/booleanValidator.ts +0 -16
  35. package/src/validators/dateValidator.ts +0 -113
  36. package/src/validators/genericValidator.ts +0 -117
  37. package/src/validators/numberValidator.ts +0 -66
  38. package/src/validators/objectValidator.ts +0 -64
  39. package/src/validators/slugValidator.ts +0 -117
  40. package/src/validators/stringValidator.ts +0 -120
@@ -0,0 +1,828 @@
1
+ import { isArrayOfBlocksSchemaType, isKeyedObject, isReference, isSlug, isTypedObject } from "@sanity/types";
2
+ import { createClientConcurrencyLimiter } from "@sanity/util/client";
3
+ import { ConcurrencyLimiter } from "@sanity/util/concurrency-limiter";
4
+ import flatten from "lodash-es/flatten.js";
5
+ import uniqBy from "lodash-es/uniqBy.js";
6
+ import { Observable, Subject, bufferTime, concat, defer, filter, finalize, firstValueFrom, from, lastValueFrom, map, merge, mergeMap, of, share, switchMap } from "rxjs";
7
+ import { catchError, map as map$1, mergeAll, mergeMap as mergeMap$1, switchMap as switchMap$1, toArray } from "rxjs/operators";
8
+ import { createInstance } from "i18next";
9
+ import isEqual from "lodash-es/isEqual.js";
10
+ import { Rule as Rule$1 } from "@sanity/schema";
11
+ import get from "lodash-es/get.js";
12
+ import isPlainObject from "lodash-es/isPlainObject.js";
13
+ import * as legacyDateFormat from "@sanity/util/legacyDateFormat";
14
+ import { getPublishedId } from "@sanity/id-utils";
15
+ import memoize from "lodash-es/memoize.js";
16
+ const validationLocaleStrings = {
17
+ "array.exact-length": "Must have exactly {{wantedLength}} items",
18
+ "array.exact-length_blocks": "Must have exactly {{wantedLength}} blocks",
19
+ "array.item-duplicate": "Can't be a duplicate",
20
+ "array.maximum-length": "Must have at most {{maxLength}} items",
21
+ "array.maximum-length_blocks": "Must have at most {{maxLength}} blocks",
22
+ "array.minimum-length": "Must have at least {{minLength}} items",
23
+ "array.minimum-length_blocks": "Must have at least {{minLength}} blocks",
24
+ "date.invalid-format": "Must be a valid ISO-8601 formatted date string",
25
+ "date.maximum": "Must be at or before {{maxDate}}",
26
+ "date.minimum": "Must be at or after {{minDate}}",
27
+ "generic.incorrect-type": "Expected type \"{{expectedType}}\", got \"{{actualType}}\"",
28
+ "generic.not-allowed": "Value did not match any allowed values",
29
+ "generic.not-allowed_hint": "Value \"{{hint}}\" did not match any allowed values",
30
+ "generic.required": "Required",
31
+ "number.greater-than": "Must be greater than {{threshold}}",
32
+ "number.less-than": "Must be less than {{threshold}}",
33
+ "number.maximum": "Must be lower than or equal to {{maxNumber}}",
34
+ "number.maximum-precision": "Max precision is {{limit}}",
35
+ "number.minimum": "Must be greater than or equal to {{minNumber}}",
36
+ "number.non-integer": "Must be an integer",
37
+ "object.asset-required": "Asset is required",
38
+ "object.asset-required_file": "File is required",
39
+ "object.asset-required_image": "Image is required",
40
+ "object.media-not-found": "The asset could not be found in the Media Library",
41
+ "object.not-media-library-asset": "Must be a reference to a Media Library asset",
42
+ "object.not-reference": "Must be a reference to a document",
43
+ "object.reference-not-published": "Referenced document must be published",
44
+ "slug.missing-current": "Slug must have a value",
45
+ "slug.not-object": "Slug must be an object",
46
+ "slug.not-unique": "Slug is already in use",
47
+ "string.email": "Must be a valid email address",
48
+ "string.exact-length": "Must be exactly {{wantedLength}} characters long",
49
+ "string.lowercase": "Must be all lowercase characters",
50
+ "string.maximum-length": "Must be at most {{maxLength}} characters long",
51
+ "string.minimum-length": "Must be at least {{minLength}} characters long",
52
+ "string.regex-does-not-match": "Does not match \"{{name}}\"-pattern",
53
+ "string.regex-match": "Should not match \"{{name}}\"-pattern",
54
+ "string.uppercase": "Must be all uppercase characters",
55
+ "string.url.disallowed-scheme": "Does not match allowed protocols/schemes",
56
+ "string.url.includes-credentials": "Username/password not allowed",
57
+ "string.url.invalid": "Not a valid URL",
58
+ "string.url.not-absolute": "Relative URLs are not allowed",
59
+ "string.url.not-relative": "Only relative URLs are allowed"
60
+ };
61
+ let fallbackLocaleSource;
62
+ function getFallbackLocaleSource() {
63
+ if (fallbackLocaleSource) return fallbackLocaleSource;
64
+ let i18n = createInstance({
65
+ defaultNS: "validation",
66
+ fallbackLng: "en-US",
67
+ initAsync: !1,
68
+ interpolation: { escapeValue: !1 },
69
+ lng: "en-US",
70
+ ns: ["validation"],
71
+ resources: { "en-US": { validation: validationLocaleStrings } },
72
+ supportedLngs: ["en-US"]
73
+ });
74
+ return i18n.init(), fallbackLocaleSource = {
75
+ currentLocale: { id: "en-US" },
76
+ loadNamespaces: (namespaces) => i18n.loadNamespaces(namespaces),
77
+ t: i18n.t
78
+ }, fallbackLocaleSource;
79
+ }
80
+ function resolveConditionalProperty(property, context) {
81
+ let { currentUser, document, parent, value, path } = context;
82
+ return typeof property == "boolean" || property === void 0 ? !!property : property({
83
+ document,
84
+ parent,
85
+ value,
86
+ currentUser,
87
+ path
88
+ }) === !0;
89
+ }
90
+ function createBatchedGetDocumentExists(client) {
91
+ let id$ = new Subject(), limiter = new ConcurrencyLimiter(1), existence$ = id$.pipe(bufferTime(250, null, 100), map((ids) => Array.from(new Set(ids))), mergeMap((ids) => from(limiter.ready()).pipe(switchMap(() => client.observable.request({
92
+ url: client.getDataUrl("doc", ids.join(",")),
93
+ query: { excludeContent: "true" },
94
+ tag: "documents-availability"
95
+ }).pipe(map((availability) => ({
96
+ availability,
97
+ ids
98
+ })))), finalize(limiter.release))), mergeMap(({ availability, ids }) => ids.map((id) => {
99
+ let omittedIds = availability.omitted.reduce((acc, next) => (acc[next.id] = next.reason, acc), {});
100
+ return omittedIds[id] && omittedIds[id] === "existence" ? {
101
+ id,
102
+ exists: !1
103
+ } : {
104
+ id,
105
+ exists: !0
106
+ };
107
+ })), share());
108
+ return async function getDocumentExists(options) {
109
+ let result = firstValueFrom(existence$.pipe(filter(({ id }) => id === options.id)));
110
+ id$.next(options.id);
111
+ let { exists } = await result;
112
+ return exists;
113
+ };
114
+ }
115
+ function pathToString(path = []) {
116
+ return path.reduce((target, segment, i) => {
117
+ let segmentType = typeof segment;
118
+ if (segmentType === "number") return `${target}[${segment}]`;
119
+ if (segmentType === "string") return `${target}${i === 0 ? "" : "."}${segment}`;
120
+ if (isKeyedObject(segment)) return `${target}[_key=="${segment._key}"]`;
121
+ throw Error(`Unsupported path segment "${segment}"`);
122
+ }, "");
123
+ }
124
+ function isNonNullable(t) {
125
+ return t !== null || t !== void 0;
126
+ }
127
+ function convertToValidationMarker(validatorResult, level, context) {
128
+ if (!context) throw Error("missing context");
129
+ if (validatorResult === !0) return [];
130
+ if (Array.isArray(validatorResult)) return validatorResult.flatMap((child) => convertToValidationMarker(child, level, context)).filter(isNonNullable);
131
+ if (typeof validatorResult == "string") return convertToValidationMarker({ message: validatorResult }, level, context);
132
+ 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 = [];
134
+ validatorResult.path && normalizedPaths.push(validatorResult.path);
135
+ for (let path of validatorResult.paths || []) normalizedPaths.push(path);
136
+ return normalizedPaths.length ? normalizedPaths.map((path) => ({
137
+ path: (context.path || []).concat(path),
138
+ level: level || "error",
139
+ item: { message },
140
+ message,
141
+ __internal_metadata
142
+ })) : [{
143
+ level: level || "error",
144
+ item: { message },
145
+ message,
146
+ path: context.path || [],
147
+ __internal_metadata
148
+ }];
149
+ }
150
+ /**
151
+ * Extracts the correct localized validation message based on given locale source
152
+ *
153
+ * @param message - Localized messages to extract string from
154
+ * @param i18n - Locale source, holding the current locale
155
+ * @returns The localized string, or a fallback "Unknown error" if not found
156
+ * @internal
157
+ */
158
+ function localizeMessage(message, i18n) {
159
+ let { currentLocale } = i18n, locale = currentLocale.id;
160
+ if (message[locale]) return message[locale];
161
+ if (locale.includes("-")) {
162
+ let language = locale.split("-", 1)[0];
163
+ if (message[language]) return message[language];
164
+ }
165
+ return message["en-US"] || message["en-GB"] || message.en || "Unknown validation error (not localized)";
166
+ }
167
+ /**
168
+ * Check if passed message/result is a localized message object
169
+ *
170
+ * @param message - Message to check
171
+ * @returns True if message is a localized message object, false otherwise
172
+ * @internal
173
+ */
174
+ function isLocalizedMessages(message) {
175
+ return message !== !0 && message !== void 0 && typeof message != "string" && isPlainObject(message) && !("message" in message);
176
+ }
177
+ /**
178
+ * Modified version of fast-deep-equal (https://github.com/epoberezkin/fast-deep-equal)
179
+ * MIT-licensed, copyright (c) 2017 Evgeny Poberezkin
180
+ **/
181
+ function deepEqualsIgnoreKey(a, b) {
182
+ if (a === b) return !0;
183
+ if (Array.isArray(a) && Array.isArray(b)) {
184
+ if (a.length != b.length) return !1;
185
+ for (let i = 0; i < a.length; i++) if (!deepEqualsIgnoreKey(a[i], b[i])) return !1;
186
+ return !0;
187
+ }
188
+ if (Array.isArray(a) != Array.isArray(b)) return !1;
189
+ if (a && b && typeof a == "object" && typeof b == "object") {
190
+ let keys = Object.keys(a);
191
+ if (keys.length !== Object.keys(b).length) return !1;
192
+ if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
193
+ if (a instanceof Date != b instanceof Date) return !1;
194
+ if (a instanceof RegExp && b instanceof RegExp) return a.toString() == b.toString();
195
+ if (a instanceof RegExp != b instanceof RegExp) return !1;
196
+ for (let i = 0; i < keys.length; i++) if (keys[i] !== "_key" && !Object.prototype.hasOwnProperty.call(b, keys[i])) return !1;
197
+ for (let i = 0; i < keys.length; i++) {
198
+ let key = keys[i];
199
+ if (key !== "_key" && !deepEqualsIgnoreKey(a[key], b[key])) return !1;
200
+ }
201
+ return !0;
202
+ }
203
+ return !1;
204
+ }
205
+ const _toString = {}.toString, builtIns = [
206
+ Object,
207
+ Function,
208
+ Array,
209
+ String,
210
+ Boolean,
211
+ Number,
212
+ Date,
213
+ RegExp,
214
+ Error
215
+ ];
216
+ function isBuiltIn(_constructor) {
217
+ for (let i = 0; i < builtIns.length; i++) if (builtIns[i] === _constructor) return !0;
218
+ return !1;
219
+ }
220
+ function typeString(obj) {
221
+ let stringType = _toString.call(obj).slice(8, -1);
222
+ if (obj == null) return stringType.toLowerCase();
223
+ let constructorType = obj.constructor;
224
+ return constructorType && !isBuiltIn(constructorType) ? constructorType.name : stringType;
225
+ }
226
+ const SLOW_VALIDATOR_TIMEOUT = 5e3, formatValidationErrors = (options) => options.message ? options.message : options.results.length === 1 ? options.results[0]?.message : options.i18n.t("{{messages, list}}", {
227
+ messages: options.results.map((err) => err.message || err.item?.message),
228
+ formatParams: { messages: {
229
+ style: "long",
230
+ type: options.operation
231
+ } }
232
+ }), genericValidators = {
233
+ type: (expectedType, value, message, { i18n }) => {
234
+ let actualType = typeString(value);
235
+ return actualType !== expectedType && actualType !== "undefined" ? message || i18n.t("validation:generic.incorrect-type", {
236
+ actualType,
237
+ expectedType
238
+ }) : !0;
239
+ },
240
+ presence: (expected, value, message, { i18n }) => value === void 0 && expected === "required" ? message || i18n.t("validation:generic.required") : !0,
241
+ all: async (children, value, message, context) => {
242
+ let results = (await Promise.all(children.map((child) => child.validate(value, context)))).flat();
243
+ return results.length === 0 || formatValidationErrors({
244
+ message,
245
+ results,
246
+ operation: "conjunction",
247
+ i18n: context.i18n
248
+ });
249
+ },
250
+ either: async (children, value, message, context) => {
251
+ let resolved = await Promise.all(children.map((child) => child.validate(value, context))), results = resolved.flat();
252
+ return resolved.find((result) => !result.length) ? !0 : formatValidationErrors({
253
+ message,
254
+ results,
255
+ operation: "disjunction",
256
+ i18n: context.i18n
257
+ });
258
+ },
259
+ valid: (allowedValues, actual, message, { i18n }) => {
260
+ let valueType = typeof actual;
261
+ if (valueType === "undefined") return !0;
262
+ 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 : message || i18n.t("validation:generic.not-allowed", value ? {
264
+ context: "hint",
265
+ replace: { hint: strValue }
266
+ } : {});
267
+ },
268
+ custom: async (fn, value, message, context) => {
269
+ let slowTimer = setTimeout(() => {
270
+ context.environment === "studio" && console.warn(`Custom validator at ${pathToString(context.path)} has taken more than ${SLOW_VALIDATOR_TIMEOUT}ms to respond`);
271
+ }, SLOW_VALIDATOR_TIMEOUT), result;
272
+ try {
273
+ result = await fn(value, context);
274
+ } finally {
275
+ clearTimeout(slowTimer);
276
+ }
277
+ return isLocalizedMessages(result) ? localizeMessage(result, context.i18n) : typeof result == "string" && message || result;
278
+ }
279
+ }, arrayValidators = {
280
+ ...genericValidators,
281
+ min: (minLength, value, message, { i18n, type }) => {
282
+ if (!value || value.length >= minLength) return !0;
283
+ let context = isArrayOfBlocksSchemaType(type) ? "blocks" : void 0;
284
+ return message || i18n.t("validation:array.minimum-length", {
285
+ minLength,
286
+ context
287
+ });
288
+ },
289
+ max: (maxLength, value, message, { i18n, type }) => {
290
+ if (!value || value.length <= maxLength) return !0;
291
+ let context = isArrayOfBlocksSchemaType(type) ? "blocks" : void 0;
292
+ return message || i18n.t("validation:array.maximum-length", {
293
+ maxLength,
294
+ context
295
+ });
296
+ },
297
+ length: (wantedLength, value, message, { i18n, type }) => {
298
+ if (!value || value.length === wantedLength) return !0;
299
+ let context = isArrayOfBlocksSchemaType(type) ? "blocks" : void 0;
300
+ return message || i18n.t("validation:array.exact-length", {
301
+ wantedLength,
302
+ context
303
+ });
304
+ },
305
+ presence: (flag, value, message, { i18n }) => flag === "required" && !value ? message || i18n.t("validation:generic.required", { context: "array" }) : !0,
306
+ valid: (allowedValues, values, message, { i18n }) => {
307
+ if (values === void 0) return !0;
308
+ let paths = [];
309
+ for (let i = 0; i < values.length; i++) {
310
+ let value = values[i];
311
+ if (allowedValues.some((expected) => deepEqualsIgnoreKey(expected, value))) continue;
312
+ let pathSegment = value && value._key ? { _key: value._key } : i;
313
+ paths.push([pathSegment]);
314
+ }
315
+ let sharedMessage = message || i18n.t("validation:generic.not-allowed");
316
+ return paths.map((path) => ({
317
+ message: sharedMessage,
318
+ path
319
+ }));
320
+ },
321
+ unique: (_unused, value, message, { i18n }) => {
322
+ let dupeIndices = [];
323
+ if (!value) return !0;
324
+ for (let x = 0; x < value.length; x++) for (let y = x + 1; y < value.length; y++) {
325
+ let itemA = value[x], itemB = value[y];
326
+ deepEqualsIgnoreKey(itemA, itemB) && (dupeIndices.indexOf(x) === -1 && dupeIndices.push(x), dupeIndices.indexOf(y) === -1 && dupeIndices.push(y));
327
+ }
328
+ let paths = dupeIndices.map((idx) => {
329
+ let item = value[idx];
330
+ return [item && item._key ? { _key: item._key } : idx];
331
+ }), sharedMessage = message || i18n.t("validation:array.item-duplicate");
332
+ return paths.map((path) => ({
333
+ message: sharedMessage,
334
+ path
335
+ }));
336
+ }
337
+ }, booleanValidators = {
338
+ ...genericValidators,
339
+ presence: (flag, value, message, { i18n }) => flag === "required" && typeof value != "boolean" ? message || i18n.t("validation:generic.required", { context: "boolean" }) : !0
340
+ };
341
+ function isRecord$1(obj) {
342
+ return typeof obj == "object" && !!obj && !Array.isArray(obj);
343
+ }
344
+ 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)?)?)?)?$/, getFormattedDate = (type = "", value, options) => {
345
+ let dateFormat = options?.dateFormat || legacyDateFormat.DEFAULT_DATE_FORMAT, timeFormat = options?.timeFormat || legacyDateFormat.DEFAULT_TIME_FORMAT;
346
+ return legacyDateFormat.format(value, type === "date" ? dateFormat : `${dateFormat} ${timeFormat}`, { useUTC: type === "date" });
347
+ };
348
+ function parseDate(date, throwOnError = !1) {
349
+ if (!date) return null;
350
+ if (date === "now") return /* @__PURE__ */ new Date();
351
+ let parsed = new Date(date), isInvalid = isNaN(parsed.getTime());
352
+ if (isInvalid && throwOnError) throw Error(`Unable to parse "${date}" to a date`);
353
+ return isInvalid ? null : parsed;
354
+ }
355
+ const dateValidators = {
356
+ ...genericValidators,
357
+ type: (_unused, value, message, { i18n }) => value === void 0 || isoDate.test(`${value}`) ? !0 : message || i18n.t("validation:date.invalid-format"),
358
+ min: (minDate, value, message, { type, i18n }) => {
359
+ let dateVal = parseDate(value), minDateVal = parseDate(minDate, !0);
360
+ if (!dateVal || !value || dateVal >= minDateVal) return !0;
361
+ if (!type) throw Error("`type` was not provided in validation context.");
362
+ let dateTimeOptions = isRecord$1(type.options) ? type.options : {};
363
+ return message || i18n.t("validation:date.minimum", {
364
+ minDate: getFormattedDate(type.name, minDateVal, dateTimeOptions),
365
+ providedMinDate: minDate
366
+ });
367
+ },
368
+ max: (maxDate, value, message, { type, i18n }) => {
369
+ let dateVal = parseDate(value), maxDateVal = parseDate(maxDate, !0);
370
+ if (!dateVal || !value || dateVal <= maxDateVal) return !0;
371
+ if (!type) throw Error("`type` was not provided in validation context.");
372
+ let dateTimeOptions = isRecord$1(type.options) ? type.options : {};
373
+ return message || i18n.t("validation:date.maximum", {
374
+ maxDate: getFormattedDate(type.name, maxDateVal, dateTimeOptions),
375
+ providedMaxDate: maxDate
376
+ });
377
+ }
378
+ }, precisionRx = /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/, numberValidators = {
379
+ ...genericValidators,
380
+ integer: (_unused, value, message, { i18n }) => Number.isInteger(value) ? !0 : message || i18n.t("validation:number.non-integer"),
381
+ precision: (limit, value, message, { i18n }) => {
382
+ if (value === void 0) return !0;
383
+ let places = value.toString().match(precisionRx);
384
+ return Math.max((places[1] ? places[1].length : 0) - (places[2] ? parseInt(places[2], 10) : 0), 0) > limit ? message || i18n.t("validation:number.maximum-precision", { limit }) : !0;
385
+ },
386
+ min: (minNumber, value, message, { i18n }) => value >= minNumber || message || i18n.t("validation:number.minimum", { minNumber }),
387
+ max: (maxNumber, value, message, { i18n }) => value <= maxNumber || message || i18n.t("validation:number.maximum", { maxNumber }),
388
+ greaterThan: (threshold, value, message, { i18n }) => value > threshold || message || i18n.t("validation:number.greater-than", { threshold }),
389
+ lessThan: (threshold, value, message, { i18n }) => value < threshold || message || i18n.t("validation:number.less-than", { threshold })
390
+ }, metaKeys = [
391
+ "_key",
392
+ "_type",
393
+ "_weak"
394
+ ], objectValidators = {
395
+ ...genericValidators,
396
+ presence: (expected, value, message, { i18n }) => {
397
+ if (expected !== "required") return !0;
398
+ let keys = value && Object.keys(value).filter((key) => !metaKeys.includes(key));
399
+ return value === void 0 || keys && keys.length === 0 ? message || i18n.t("validation:generic.required", { context: "object" }) : !0;
400
+ },
401
+ reference: async (_unused, value, message, context) => {
402
+ if (!value) return !0;
403
+ let { type, document, getDocumentExists, i18n } = context;
404
+ if (!isReference(value)) return message || i18n.t("validation:object.not-reference");
405
+ if (!type) throw Error("`type` was not provided in validation context");
406
+ if ("weak" in type && type.weak) return !0;
407
+ if (!getDocumentExists) throw Error("`getDocumentExists` was not provided in validation context");
408
+ let documentId = document?._id;
409
+ return documentId && value._ref == getPublishedId(documentId) || await getDocumentExists({ id: value._ref }) ? !0 : i18n.t("validation:object.reference-not-published", { documentId: value._ref });
410
+ },
411
+ assetRequired: (flag, value, message, { i18n }) => !value || !value.asset || !value.asset._ref ? {
412
+ __internal_metadata: { name: "assetRequired" },
413
+ message: message || i18n.t("validation:object.asset-required", { context: flag.assetType || "" })
414
+ } : !0,
415
+ media: async (fn, value, message, context) => {
416
+ let slowTimer = setTimeout(() => {
417
+ context.environment === "studio" && console.warn(`Media validator at ${pathToString(context.path)} has taken more than ${SLOW_VALIDATOR_TIMEOUT}ms to respond`);
418
+ }, SLOW_VALIDATOR_TIMEOUT);
419
+ if (!value) return !0;
420
+ if (!value || !value.media || !value.media._ref) return context.i18n.t("validation:object.not-media-library-asset");
421
+ let result = !0;
422
+ try {
423
+ let [type, libraryId, documentId] = value.media._ref.split(":", 3), resourceConfig = { resource: {
424
+ type,
425
+ id: libraryId
426
+ } }, 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}`), context.i18n.t("validation:object.media-not-found");
428
+ result = await fn({
429
+ media: { asset },
430
+ value
431
+ }, context);
432
+ } catch (err) {
433
+ throw Error(`Media validator at ${pathToString(context.path)} failed with an error: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
434
+ } finally {
435
+ clearTimeout(slowTimer);
436
+ }
437
+ let validationErrorMetadata = { __internal_metadata: { name: "media" } };
438
+ return result === !0 || Array.isArray(result) ? result : [result].map((res) => typeof res == "string" ? {
439
+ ...validationErrorMetadata,
440
+ message: message || res
441
+ } : isLocalizedMessages(res) ? {
442
+ ...validationErrorMetadata,
443
+ message: message || localizeMessage(res, context.i18n)
444
+ } : {
445
+ ...validationErrorMetadata,
446
+ ...res,
447
+ message: message || res.message
448
+ });
449
+ }
450
+ }, DUMMY_ORIGIN = "http://sanity", isRelativeUrl = (url) => /^\.*\//.test(url), 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,}))$/, typeValidators = {
451
+ Boolean: booleanValidators,
452
+ Number: numberValidators,
453
+ String: {
454
+ ...genericValidators,
455
+ min: (minLength, value, message, { i18n }) => !value || value.length >= minLength || message || i18n.t("validation:string.minimum-length", { minLength }),
456
+ max: (maxLength, value, message, { i18n }) => !value || value.length <= maxLength || message || i18n.t("validation:string.maximum-length", { maxLength }),
457
+ length: (wantedLength, value, message, { i18n }) => (value || "").length === wantedLength || message || i18n.t("validation:string.exact-length", { wantedLength }),
458
+ uri: (constraints, value, message, { i18n }) => {
459
+ let strValue = value || "";
460
+ if (!strValue) return !0;
461
+ let { options } = constraints, { allowCredentials, relativeOnly } = options, allowRelative = options.allowRelative || relativeOnly, url;
462
+ try {
463
+ url = allowRelative ? new URL(strValue, DUMMY_ORIGIN) : new URL(strValue);
464
+ } catch {
465
+ return message || i18n.t("validation:string.url.invalid");
466
+ }
467
+ if (relativeOnly && url.origin !== DUMMY_ORIGIN) return message || i18n.t("validation:string.url.not-relative");
468
+ if (!allowRelative && url.origin === DUMMY_ORIGIN && isRelativeUrl(strValue)) return message || i18n.t("validation:string.url.not-absolute");
469
+ if (!allowCredentials && (url.username || url.password)) return message || i18n.t("validation:string.url.includes-credentials");
470
+ let urlScheme = url.protocol.replace(/:$/, "");
471
+ return isRelativeUrl(strValue) || options.scheme.some((scheme) => scheme.test(urlScheme)) ? !0 : message || i18n.t("validation:string.url.disallowed-scheme", { scheme: urlScheme });
472
+ },
473
+ stringCasing: (casing, value, message, { i18n }) => {
474
+ let strValue = value || "";
475
+ return casing === "uppercase" && strValue !== strValue.toLocaleUpperCase() ? message || i18n.t("validation:string.uppercase") : casing === "lowercase" && strValue !== strValue.toLocaleLowerCase() ? message || i18n.t("validation:string.lowercase") : !0;
476
+ },
477
+ presence: (flag, value, message, { i18n }) => flag === "required" && !value ? message || i18n.t("validation:generic.required", { context: "string" }) : !0,
478
+ regex: (options, value, message, { i18n }) => {
479
+ let { pattern, name, invert } = options, regName = name || `${pattern.toString()}`, strValue = value || "";
480
+ pattern.lastIndex = 0;
481
+ let matches = pattern.test(strValue);
482
+ return !invert && !matches || invert && matches ? message || (invert ? i18n.t("validation:string.regex-match", { name: regName }) : i18n.t("validation:string.regex-does-not-match", { name: regName })) : !0;
483
+ },
484
+ email: (_unused, value, message, { i18n }) => {
485
+ let strValue = `${value || ""}`.trim();
486
+ return !strValue || emailRegex.test(strValue) ? !0 : message || i18n.t("validation:string.email");
487
+ }
488
+ },
489
+ Array: arrayValidators,
490
+ Object: objectValidators,
491
+ 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 {
493
+ static array = (def) => new Rule(def).type("Array");
494
+ static object = (def) => new Rule(def).type("Object");
495
+ static string = (def) => new Rule(def).type("String");
496
+ static number = (def) => new Rule(def).type("Number");
497
+ static boolean = (def) => new Rule(def).type("Boolean");
498
+ static dateTime = (def) => new Rule(def).type("Date");
499
+ clone() {
500
+ let rule = new Rule();
501
+ return rule._type = this._type, rule._message = this._message, rule._required = this._required, rule._rules = [...this._rules], rule._level = this._level, rule._fieldRules = this._fieldRules, rule._typeDef = this._typeDef, rule;
502
+ }
503
+ async validate(value, { __internal = {}, ...context }) {
504
+ let { customValidationConcurrencyLimiter } = __internal, valueIsEmpty = value == null;
505
+ if (valueIsEmpty && this._required === "optional") return EMPTY_ARRAY;
506
+ let rules = this._required === void 0 && valueIsEmpty ? this._rules.filter((curr) => curr.flag === "custom") : this._rules, validators = this._type && typeValidators[this._type] || genericValidators;
507
+ return (await Promise.all(rules.map(async (curr) => {
508
+ if (curr.flag === void 0) throw Error("Invalid rule, did not contain \"flag\"-property");
509
+ let validator = validators[curr.flag];
510
+ if (!validator) {
511
+ let forType = this._type ? `type "${this._type}"` : "rule without declared type";
512
+ throw Error(`Validator for flag "${curr.flag}" not found for ${forType}`);
513
+ }
514
+ let specConstraint = "constraint" in curr ? curr.constraint : null;
515
+ if (isFieldRef(specConstraint) && (specConstraint = get(context.parent, specConstraint.path)), curr.flag === "custom" && customValidationConcurrencyLimiter && !specConstraint?.bypassConcurrencyLimit) {
516
+ let customValidator = specConstraint;
517
+ specConstraint = async (...args) => {
518
+ await customValidationConcurrencyLimiter.ready();
519
+ try {
520
+ return await customValidator(...args);
521
+ } finally {
522
+ customValidationConcurrencyLimiter.release();
523
+ }
524
+ };
525
+ }
526
+ let message = isLocalizedMessages(this._message) ? localizeMessage(this._message, context.i18n) : this._message;
527
+ try {
528
+ return convertToValidationMarker(await validator(specConstraint, value, message, context), this._level, context);
529
+ } catch (err) {
530
+ return convertToValidationMarker({ message: `${pathToString(context.path)}: Exception occurred while validating value: ${err.message}` }, "error", context);
531
+ }
532
+ }))).flat();
533
+ }
534
+ }, memoizedWarnOnArraySlug = memoize(warnOnArraySlug);
535
+ function serializePath(path) {
536
+ return path.reduce((target, part, i) => {
537
+ let isIndex = typeof part == "number", isKey = isKeyedObject(part);
538
+ return `${target}${isIndex || isKey ? "[]" : `${i === 0 ? "" : "."}${part}`}`;
539
+ }, "");
540
+ }
541
+ const defaultIsUnique = (slug, context) => {
542
+ let { getClient, document, path, type } = context, schemaOptions = type?.options;
543
+ if (!document) throw Error("`document` was not provided in validation context.");
544
+ if (!path) throw Error("`path` was not provided in validation context.");
545
+ let disableArrayWarning = schemaOptions?.disableArrayWarning || !1, docType = document._type, atPath = serializePath(path.concat("current"));
546
+ !disableArrayWarning && atPath.includes("[]") && context.environment === "studio" && memoizedWarnOnArraySlug(serializePath(path));
547
+ let constraints = [
548
+ "_type == $docType",
549
+ "!sanity::versionOf($published)",
550
+ `${atPath} == $slug`
551
+ ].join(" && ");
552
+ return getClient({ apiVersion: "2025-02-19" }).withConfig({ perspective: "raw" }).fetch(`!defined(*[${constraints}][0]._id)`, {
553
+ docType,
554
+ published: getPublishedId(document._id),
555
+ slug
556
+ }, { tag: "validation.slug-is-unique" });
557
+ };
558
+ function warnOnArraySlug(serializedPath) {
559
+ console.warn([
560
+ `Slug field at path ${serializedPath} is within an array and cannot be automatically checked for uniqueness`,
561
+ "If you need to check for uniqueness, provide your own \"isUnique\" method",
562
+ "To disable this message, set `disableArrayWarning: true` on the slug `options` field"
563
+ ].join("\n"));
564
+ }
565
+ /**
566
+ * Validates slugs values by querying for uniqueness from the client.
567
+ *
568
+ * This is a custom rule implementation (e.g. `Rule.custom(slugValidator)`)
569
+ * that's populated in `inferFromSchemaType` when the type name is `slug`
570
+ */
571
+ const slugValidator = async (value, context) => {
572
+ if (!value) return !0;
573
+ let { i18n } = context;
574
+ if (typeof value != "object" || Array.isArray(value)) return i18n.t("validation:slug.not-object");
575
+ if (!isSlug(value) || value.current.trim().length === 0) return i18n.t("validation:slug.missing-current");
576
+ let isUnique = context?.type?.options?.isUnique || defaultIsUnique, slugContext = {
577
+ ...context,
578
+ parent: context.parent,
579
+ type: context.type,
580
+ defaultIsUnique
581
+ };
582
+ return await isUnique(value.current, slugContext) ? !0 : i18n.t("validation:slug.not-unique", { slug: value.current });
583
+ }, ruleConstraintTypes = {
584
+ array: !0,
585
+ boolean: !0,
586
+ date: !0,
587
+ number: !0,
588
+ object: !0,
589
+ string: !0
590
+ }, isRuleConstraint = (typeString) => typeString in ruleConstraintTypes;
591
+ function getTypeChain(type, visited = /* @__PURE__ */ new Set()) {
592
+ return !type || visited.has(type) ? [] : (visited.add(type), [...type.type ? getTypeChain(type.type, visited) : [], type]);
593
+ }
594
+ function baseRuleReducer(inputRule, type) {
595
+ let baseRule = inputRule;
596
+ isRuleConstraint(type.jsonType) && (baseRule = baseRule.type(type.jsonType));
597
+ let typeOptionsList = type?.options && typeof type.options == "object" && "list" in type.options && type.options.list;
598
+ return Array.isArray(typeOptionsList) && (baseRule = baseRule.valid(typeOptionsList.map((option) => extractValueFromListOption(option, type)))), type.name === "datetime" || type.name === "date" ? baseRule.type("Date") : type.name === "url" ? baseRule.uri() : type.name === "slug" ? baseRule.custom(slugValidator, { bypassConcurrencyLimit: !0 }) : type.name === "reference" ? baseRule.reference() : type.name === "email" ? baseRule.email() : baseRule;
599
+ }
600
+ function hasValueField(typeDef) {
601
+ return typeDef ? !("fields" in typeDef) && typeDef.type ? hasValueField(typeDef.type) : !("fields" in typeDef) || !Array.isArray(typeDef.fields) ? !1 : typeDef.fields.some((field) => field.name === "value") : !1;
602
+ }
603
+ function extractValueFromListOption(option, typeDef) {
604
+ return typeDef.jsonType === "object" && hasValueField(typeDef) || option.value === void 0 ? option : option.value;
605
+ }
606
+ const isUriSpec = (spec) => spec.flag === "uri";
607
+ function omitLeakedDefaultUri(rules, typeDef) {
608
+ if (!getTypeChain(typeDef).some((type) => type.name === "url")) return rules;
609
+ let defaultUri = new Rule$2(typeDef).uri()._rules.find(isUriSpec)?.constraint, isDefaultUri = (spec) => isUriSpec(spec) && isEqual(spec.constraint, defaultUri), isCustomUri = (spec) => isUriSpec(spec) && !isEqual(spec.constraint, defaultUri);
610
+ return rules.some((rule) => rule._rules.some(isCustomUri)) ? rules.map((rule) => {
611
+ if (!rule._rules.some(isDefaultUri)) return rule;
612
+ let cleaned = rule.clone();
613
+ return cleaned._rules = rule._rules.filter((spec) => !isDefaultUri(spec)), cleaned;
614
+ }) : rules;
615
+ }
616
+ function normalizeValidationRules(typeDef, context) {
617
+ if (!typeDef) return [];
618
+ let validation = typeDef.validation;
619
+ if (Array.isArray(validation)) return omitLeakedDefaultUri(validation.flatMap((i) => normalizeValidationRules({
620
+ ...typeDef,
621
+ validation: i
622
+ }, context)), typeDef);
623
+ let baseRule = Object.values(getTypeChain(typeDef).reduce((acc, type) => (acc[type.name] = type, acc), {})).reduce(baseRuleReducer, new Rule$2(typeDef));
624
+ return validation && typeof validation == "object" ? [validation] : validation && typeof validation == "function" ? normalizeValidationRules({
625
+ ...typeDef,
626
+ validation: validation(baseRule, context)
627
+ }, context) : [baseRule];
628
+ }
629
+ /**
630
+ * Simple requestIdleCallback polyfill
631
+ * Can be removed when all browsers support requestIdleCallback: https://caniuse.com/requestidlecallback
632
+ * @param callback -
633
+ * @param options -
634
+ */
635
+ const requestIdleCallbackShim = function requestIdleCallbackShim(callback, _options) {
636
+ let start = Date.now();
637
+ return globalThis.setTimeout(() => {
638
+ callback({
639
+ didTimeout: !1,
640
+ timeRemaining() {
641
+ return Math.max(0, Date.now() - start);
642
+ }
643
+ });
644
+ }, 0);
645
+ }, cancelIdleCallbackShim = function cancelIdleCallbackShim(handle) {
646
+ return globalThis.clearTimeout(handle);
647
+ }, win = typeof window > "u" ? void 0 : window, requestIdleCallback = win?.requestIdleCallback || requestIdleCallbackShim, cancelIdleCallback = win?.cancelIdleCallback || cancelIdleCallbackShim, unknownFieldsValidator = (type) => (value) => {
648
+ if (typeof value != "object" || !value) return !0;
649
+ let fieldNames = new Set(type.fields?.map((field) => field.name));
650
+ return Object.keys(value).filter((key) => !key.startsWith("_")).filter((key) => !fieldNames.has(key)).map((unknownField) => ({
651
+ message: `Field '${unknownField}' does not exist on type '${type.name}'`,
652
+ path: [unknownField]
653
+ }));
654
+ }, DEFAULT_VALIDATION_CLIENT_OPTIONS = { apiVersion: "2025-02-19" }, isRecord = (maybeRecord) => typeof maybeRecord == "object" && !!maybeRecord && !Array.isArray(maybeRecord);
655
+ /**
656
+ * Recursively extracts all `_fieldRules` from a rule and its nested constraints.
657
+ * This handles cases where `Rule.fields()` is used inside `Rule.all()` or `Rule.either()`.
658
+ */
659
+ function extractFieldRulesFromRule(rule) {
660
+ let results = [];
661
+ rule._fieldRules && results.push(rule._fieldRules);
662
+ for (let ruleSpec of rule._rules) if (ruleSpec.flag === "all" || ruleSpec.flag === "either") {
663
+ let childRules = ruleSpec.constraint;
664
+ if (Array.isArray(childRules)) for (let childRule of childRules) results.push(...extractFieldRulesFromRule(childRule));
665
+ }
666
+ return results;
667
+ }
668
+ /**
669
+ * @internal
670
+ */
671
+ function resolveTypeForArrayItem(item, candidates) {
672
+ if (candidates.length === 1) return candidates[0];
673
+ let itemType = isTypedObject(item) && item._type, primitive = item == null || !itemType && typeString(item).toLowerCase();
674
+ return primitive && primitive !== "object" ? candidates.find((candidate) => candidate.jsonType === primitive) : candidates.find((candidate) => candidate.type?.name === itemType) || candidates.find((candidate) => candidate.name === itemType) || candidates.find((candidate) => candidate.name === "object" && primitive === "object");
675
+ }
676
+ /**
677
+ * Validates a document against a compiled schema. Returns validation markers
678
+ * without deciding whether the document may be edited or published.
679
+ *
680
+ * @beta
681
+ */
682
+ function validateDocument({ client, document, schema, ...options }) {
683
+ return validateDocumentInternal({
684
+ ...options,
685
+ document,
686
+ environment: "cli",
687
+ getClient: ({ apiVersion }) => client.withConfig({ apiVersion }),
688
+ i18n: getFallbackLocaleSource(),
689
+ schema
690
+ });
691
+ }
692
+ /** @internal */
693
+ function validateDocumentInternal({ document, schema, getClient, getDocumentExists, i18n = getFallbackLocaleSource(), environment, maxCustomValidationConcurrency, maxFetchConcurrency, currentUser }) {
694
+ let limitConcurrency = createClientConcurrencyLimiter(maxFetchConcurrency ?? 25), getConcurrencyLimitedClient = (clientOptions) => limitConcurrency(getClient(clientOptions));
695
+ return lastValueFrom(validateDocumentObservable({
696
+ document,
697
+ getClient: getConcurrencyLimitedClient,
698
+ i18n,
699
+ schema,
700
+ getDocumentExists: getDocumentExists || createBatchedGetDocumentExists(getClient(DEFAULT_VALIDATION_CLIENT_OPTIONS)),
701
+ environment,
702
+ maxCustomValidationConcurrency,
703
+ currentUser
704
+ }));
705
+ }
706
+ const customValidationConcurrencyLimiters = /* @__PURE__ */ new WeakMap();
707
+ /**
708
+ * Validates a document against the given schema, returning an Observable
709
+ * @internal
710
+ */
711
+ function validateDocumentObservable({ document, getClient, i18n = getFallbackLocaleSource(), schema, getDocumentExists, environment, maxCustomValidationConcurrency, currentUser }) {
712
+ if (typeof document?._type != "string") throw Error("Tried to validate a value without a '_type'");
713
+ let documentType = schema.get(document._type);
714
+ if (!documentType) return environment === "studio" ? (console.warn("Schema type for object type \"%s\" not found, skipping validation", document._type), of([])) : of([{
715
+ level: "warning",
716
+ message: `Could not find schema type for type '${document._type}', skipping validation`,
717
+ path: []
718
+ }]);
719
+ let customValidationConcurrencyLimiter = customValidationConcurrencyLimiters.get(schema);
720
+ customValidationConcurrencyLimiter || (customValidationConcurrencyLimiter = new ConcurrencyLimiter(maxCustomValidationConcurrency ?? 5), customValidationConcurrencyLimiters.set(schema, customValidationConcurrencyLimiter));
721
+ let validationOptions = {
722
+ getClient,
723
+ schema,
724
+ parent: void 0,
725
+ value: document,
726
+ path: [],
727
+ document,
728
+ type: documentType,
729
+ i18n,
730
+ getDocumentExists,
731
+ environment,
732
+ customValidationConcurrencyLimiter,
733
+ currentUser
734
+ };
735
+ return from(i18n.loadNamespaces(["validation"])).pipe(switchMap$1(() => validateItemObservable(validationOptions)), catchError((err) => {
736
+ console.error(err);
737
+ let message = err?.message || "Unknown error";
738
+ return of([{
739
+ level: "error",
740
+ message,
741
+ item: { message },
742
+ path: []
743
+ }]);
744
+ }));
745
+ }
746
+ function validateItem(opts) {
747
+ return lastValueFrom(validateItemObservable(opts));
748
+ }
749
+ function validateItemObservable({ value, type, path = [], parent, customValidationConcurrencyLimiter, environment, ...restOfContext }) {
750
+ let ancestorHidden = restOfContext.hidden === !0, resolveHiddenForType = (schemaType, schemaValue, schemaParent, schemaPath, ancestorHiddenValue) => schemaType ? ancestorHiddenValue || resolveConditionalProperty(schemaType.hidden, {
751
+ ...restOfContext,
752
+ parent: schemaParent,
753
+ value: schemaValue,
754
+ path: schemaPath || [],
755
+ currentUser: restOfContext.currentUser ?? null
756
+ }) : ancestorHiddenValue, hidden = resolveHiddenForType(type, value, parent, path, ancestorHidden), addUnknownFieldsValidator = (rule) => type?.jsonType === "object" && getTypeChain(type).find((t) => [
757
+ "object",
758
+ "document",
759
+ "file",
760
+ "image"
761
+ ].includes(t.name)) && environment !== "studio" ? rule.custom(unknownFieldsValidator(type), { bypassConcurrencyLimit: !0 }).warning() : rule, rules = normalizeValidationRules(type, {
762
+ ...restOfContext,
763
+ hidden,
764
+ environment,
765
+ parent,
766
+ path,
767
+ type
768
+ }), selfChecks = rules.map(addUnknownFieldsValidator).map((rule) => defer(() => rule.validate(value, {
769
+ ...restOfContext,
770
+ environment,
771
+ hidden,
772
+ parent,
773
+ path,
774
+ type,
775
+ __internal: { customValidationConcurrencyLimiter }
776
+ }))), nestedChecks = [], selfIsRequired = rules.some((rule) => rule.isRequired());
777
+ if (type?.jsonType === "object" && (value || value == null && selfIsRequired)) {
778
+ let fieldTypes = type.fields.reduce((acc, field) => (acc[field.name] = field.type, acc), {});
779
+ nestedChecks = nestedChecks.concat(rules.flatMap((rule) => extractFieldRulesFromRule(rule)).flatMap((fieldResults) => Object.entries(fieldResults)).flatMap(([name, validation]) => {
780
+ let fieldType = fieldTypes[name];
781
+ return normalizeValidationRules({
782
+ ...fieldType,
783
+ validation
784
+ }).map(addUnknownFieldsValidator).map((subRule) => {
785
+ let nestedValue = isRecord(value) ? value[name] : void 0, nestedHidden = resolveHiddenForType(fieldType, nestedValue, value, path.concat(name), hidden);
786
+ return defer(() => subRule.validate(nestedValue, {
787
+ ...restOfContext,
788
+ parent: value,
789
+ path: path.concat(name),
790
+ type: fieldType,
791
+ environment,
792
+ hidden: nestedHidden,
793
+ __internal: { customValidationConcurrencyLimiter }
794
+ }));
795
+ });
796
+ })), nestedChecks = nestedChecks.concat(type.fields.map((field) => validateItemObservable({
797
+ ...restOfContext,
798
+ hidden,
799
+ parent: value,
800
+ value: isRecord(value) ? value[field.name] : void 0,
801
+ path: path.concat(field.name),
802
+ type: field.type,
803
+ environment,
804
+ customValidationConcurrencyLimiter
805
+ })));
806
+ }
807
+ return type?.jsonType === "array" && Array.isArray(value) && (nestedChecks = nestedChecks.concat(value.map((item, index) => validateItemObservable({
808
+ ...restOfContext,
809
+ hidden,
810
+ parent: value,
811
+ value: item,
812
+ path: path.concat(isKeyedObject(item) ? { _key: item._key } : index),
813
+ type: resolveTypeForArrayItem(item, type.of),
814
+ environment,
815
+ customValidationConcurrencyLimiter
816
+ })))), 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) ? uniqBy(results, (rule) => JSON.stringify(rule)) : results));
817
+ }
818
+ function idle(timeout) {
819
+ return new Observable((observer) => {
820
+ let handle = requestIdleCallback(() => {
821
+ observer.complete();
822
+ }, timeout ? { timeout } : void 0);
823
+ return () => cancelIdleCallback(handle);
824
+ });
825
+ }
826
+ export { validateItem as a, Rule$2 as c, pathToString as d, getFallbackLocaleSource as f, validateDocumentObservable as i, typeString as l, validateDocument as n, getTypeChain as o, validationLocaleStrings as p, validateDocumentInternal as r, normalizeValidationRules as s, resolveTypeForArrayItem as t, convertToValidationMarker as u };
827
+
828
+ //# sourceMappingURL=validateDocument-il4G-TLy.js.map