@sanity/validation 6.12.0 → 6.13.0-next.17
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 +33 -9
- package/lib/_internal.d.ts +2 -2
- package/lib/_internal.js +2 -2
- package/lib/index.d.ts +2 -2
- package/lib/index.js +1 -1
- package/lib/{validateDocument-6pLTIHIn.d.ts → validateDocument-CdvFjlAk.d.ts} +65 -26
- package/lib/{validateDocument-Cq33kUmN.js → validateDocument-DtBbNOGc.js} +195 -98
- package/lib/validateDocument-DtBbNOGc.js.map +1 -0
- package/package.json +5 -4
- package/lib/validateDocument-Cq33kUmN.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { isArrayOfBlocksSchemaType, isKeyedObject, isReference, isSlug, isTypedObject } from "@sanity/types";
|
|
2
2
|
import { createClientConcurrencyLimiter } from "@sanity/util/client";
|
|
3
3
|
import { ConcurrencyLimiter } from "@sanity/util/concurrency-limiter";
|
|
4
|
+
import { dequal } from "dequal/lite";
|
|
4
5
|
import flatten from "lodash-es/flatten.js";
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import { catchError, map as map$1, mergeAll, mergeMap as mergeMap$1, switchMap as switchMap$1, toArray } from "rxjs/operators";
|
|
6
|
+
import { Observable, Subject, bufferTime, concat, defer, filter, firstValueFrom, from, lastValueFrom, map, merge, mergeMap, of, share, takeUntil, throwError } from "rxjs";
|
|
7
|
+
import { catchError, map as map$1, mergeAll, mergeMap as mergeMap$1, switchMap, toArray } from "rxjs/operators";
|
|
8
8
|
import { createInstance } from "i18next";
|
|
9
9
|
import { Rule as Rule$1 } from "@sanity/schema";
|
|
10
10
|
import get from "lodash-es/get.js";
|
|
@@ -59,7 +59,27 @@ const validationMarkerCodes = {
|
|
|
59
59
|
valueNotAllowed: "value.not-allowed",
|
|
60
60
|
valueRequired: "value.required",
|
|
61
61
|
valueTypeMismatch: "value.type-mismatch"
|
|
62
|
-
}
|
|
62
|
+
};
|
|
63
|
+
function abortSignalAsObservable(signal) {
|
|
64
|
+
return new Observable((subscriber) => {
|
|
65
|
+
let onAbort = () => subscriber.error(signal.reason);
|
|
66
|
+
if (signal.aborted) {
|
|
67
|
+
onAbort();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
return signal.addEventListener("abort", onAbort, { once: !0 }), () => signal.removeEventListener("abort", onAbort);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function cancelWith(signal) {
|
|
74
|
+
return (source) => signal ? source.pipe(takeUntil(abortSignalAsObservable(signal))) : source;
|
|
75
|
+
}
|
|
76
|
+
var ClientUnavailableError = class extends Error {
|
|
77
|
+
name = "ClientUnavailableError";
|
|
78
|
+
constructor() {
|
|
79
|
+
super("A Sanity client is required to run this validation check");
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const validationLocaleStrings = {
|
|
63
83
|
"array.exact-length": "Must have exactly {{wantedLength}} items",
|
|
64
84
|
"array.exact-length_blocks": "Must have exactly {{wantedLength}} blocks",
|
|
65
85
|
"array.item-duplicate": "Can't be a duplicate",
|
|
@@ -123,6 +143,13 @@ function getFallbackLocaleSource() {
|
|
|
123
143
|
t: i18n.t
|
|
124
144
|
}, fallbackLocaleSource;
|
|
125
145
|
}
|
|
146
|
+
const internalValidators = /* @__PURE__ */ new WeakSet();
|
|
147
|
+
function markInternalValidator(validator) {
|
|
148
|
+
return internalValidators.add(validator), validator;
|
|
149
|
+
}
|
|
150
|
+
function isInternalValidator(validator) {
|
|
151
|
+
return typeof validator == "function" && internalValidators.has(validator);
|
|
152
|
+
}
|
|
126
153
|
function resolveConditionalProperty(property, context) {
|
|
127
154
|
let { currentUser, document, parent, value, path } = context;
|
|
128
155
|
return typeof property == "boolean" || property === void 0 ? !!property : property({
|
|
@@ -133,29 +160,27 @@ function resolveConditionalProperty(property, context) {
|
|
|
133
160
|
path
|
|
134
161
|
}) === !0;
|
|
135
162
|
}
|
|
136
|
-
function createBatchedGetDocumentExists(client) {
|
|
137
|
-
let id$ = new Subject(),
|
|
163
|
+
function createBatchedGetDocumentExists(client, defaultSignal) {
|
|
164
|
+
let id$ = new Subject(), existence$ = id$.pipe(bufferTime(250, null, 100), map((ids) => Array.from(new Set(ids))), filter((ids) => ids.length > 0), mergeMap((ids) => client.observable.request({
|
|
138
165
|
url: client.getDataUrl("doc", ids.join(",")),
|
|
139
166
|
query: { excludeContent: "true" },
|
|
167
|
+
signal: defaultSignal,
|
|
140
168
|
tag: "documents-availability"
|
|
141
169
|
}).pipe(map((availability) => ({
|
|
142
170
|
availability,
|
|
143
171
|
ids
|
|
144
|
-
})))
|
|
145
|
-
let
|
|
146
|
-
return
|
|
147
|
-
id,
|
|
148
|
-
exists: !1
|
|
149
|
-
} : {
|
|
172
|
+
}))), 1), mergeMap(({ availability, ids }) => {
|
|
173
|
+
let missingIds = new Set(availability.omitted.filter(({ reason }) => reason === "existence").map(({ id }) => id));
|
|
174
|
+
return ids.map((id) => ({
|
|
150
175
|
id,
|
|
151
|
-
exists: !
|
|
152
|
-
};
|
|
153
|
-
})
|
|
176
|
+
exists: !missingIds.has(id)
|
|
177
|
+
}));
|
|
178
|
+
}), share());
|
|
154
179
|
return async function getDocumentExists(options) {
|
|
155
|
-
let
|
|
156
|
-
|
|
157
|
-
let { exists }
|
|
158
|
-
return
|
|
180
|
+
let signal = options.signal || defaultSignal;
|
|
181
|
+
signal?.throwIfAborted();
|
|
182
|
+
let result = firstValueFrom(existence$.pipe(filter(({ id }) => id === options.id), map(({ exists }) => exists), cancelWith(signal)));
|
|
183
|
+
return id$.next(options.id), result;
|
|
159
184
|
};
|
|
160
185
|
}
|
|
161
186
|
function pathToString(path = []) {
|
|
@@ -573,7 +598,10 @@ const dateValidators = {
|
|
|
573
598
|
if ("weak" in type && type.weak) return !0;
|
|
574
599
|
if (!getDocumentExists) throw Error("`getDocumentExists` was not provided in validation context");
|
|
575
600
|
let documentId = document?._id;
|
|
576
|
-
return documentId && value._ref == getPublishedId(documentId) || await getDocumentExists({
|
|
601
|
+
return documentId && value._ref == getPublishedId(documentId) || await getDocumentExists({
|
|
602
|
+
id: value._ref,
|
|
603
|
+
signal: context.signal
|
|
604
|
+
}) ? !0 : {
|
|
577
605
|
code: validationMarkerCodes.referenceNotPublished,
|
|
578
606
|
details: { referenceId: value._ref },
|
|
579
607
|
message: i18n.t("validation:object.reference-not-published", { documentId: value._ref })
|
|
@@ -599,7 +627,7 @@ const dateValidators = {
|
|
|
599
627
|
let [type, libraryId, documentId] = value.media._ref.split(":", 3), resourceConfig = { resource: {
|
|
600
628
|
type,
|
|
601
629
|
id: libraryId
|
|
602
|
-
} }, asset = await context.getClient({ apiVersion: "2025-02-19" }).withConfig(resourceConfig).fetch("*[_id == $id] { ..., 'currentVersion': @.currentVersion-> { ... } }[0]", { id: documentId });
|
|
630
|
+
} }, asset = await context.getClient({ apiVersion: "2025-02-19" }).withConfig(resourceConfig).fetch("*[_id == $id] { ..., 'currentVersion': @.currentVersion-> { ... } }[0]", { id: documentId }, { signal: context.signal });
|
|
603
631
|
if (!asset) return console.warn(`${context.i18n.t("validation:object.media-not-found")}\nAsset ID: ${value.media._ref}`), {
|
|
604
632
|
code: validationMarkerCodes.mediaNotFound,
|
|
605
633
|
details: { referenceId: value.media._ref },
|
|
@@ -740,8 +768,8 @@ const dateValidators = {
|
|
|
740
768
|
let rule = new Rule();
|
|
741
769
|
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;
|
|
742
770
|
}
|
|
743
|
-
async validate(value,
|
|
744
|
-
let { customValidationConcurrencyLimiter } = __internal, valueIsEmpty = value == null;
|
|
771
|
+
async validate(value, options) {
|
|
772
|
+
let { __internal = {}, ...context } = options, { customValidation = !0, customValidationConcurrencyLimiter, markIncomplete } = __internal, valueIsEmpty = value == null;
|
|
745
773
|
if (valueIsEmpty && this._required === "optional") return EMPTY_ARRAY;
|
|
746
774
|
let rules = this._required === void 0 && valueIsEmpty ? this._rules.filter((curr) => curr.flag === "custom") : this._rules, validators = this._type && typeValidators[this._type] || genericValidators;
|
|
747
775
|
return (await Promise.all(rules.map(async (curr) => {
|
|
@@ -752,21 +780,16 @@ const dateValidators = {
|
|
|
752
780
|
throw Error(`Validator for flag "${curr.flag}" not found for ${forType}`);
|
|
753
781
|
}
|
|
754
782
|
let specConstraint = "constraint" in curr ? curr.constraint : null;
|
|
755
|
-
if (isFieldRef(specConstraint) && (specConstraint = get(context.parent, specConstraint.path)), curr.flag === "custom" &&
|
|
783
|
+
if (isFieldRef(specConstraint) && (specConstraint = get(context.parent, specConstraint.path)), (curr.flag === "custom" || curr.flag === "media") && !isInternalValidator(specConstraint) && !customValidation) return markIncomplete?.(), [];
|
|
784
|
+
if (curr.flag === "custom" && customValidationConcurrencyLimiter && !specConstraint?.bypassConcurrencyLimit) {
|
|
756
785
|
let customValidator = specConstraint;
|
|
757
|
-
specConstraint =
|
|
758
|
-
await customValidationConcurrencyLimiter.ready();
|
|
759
|
-
try {
|
|
760
|
-
return await customValidator(...args);
|
|
761
|
-
} finally {
|
|
762
|
-
customValidationConcurrencyLimiter.release();
|
|
763
|
-
}
|
|
764
|
-
};
|
|
786
|
+
specConstraint = (...args) => customValidationConcurrencyLimiter.run(() => customValidator(...args), context.signal);
|
|
765
787
|
}
|
|
766
788
|
let message = isLocalizedMessages(this._message) ? localizeMessage(this._message, context.i18n) : this._message;
|
|
767
789
|
try {
|
|
768
790
|
return convertToValidationMarker(await validator(specConstraint, value, message, context), this._level, context, { code: fallbackCodeForRule(curr.flag) });
|
|
769
791
|
} catch (err) {
|
|
792
|
+
if (context.signal?.throwIfAborted(), err instanceof ClientUnavailableError) return markIncomplete?.(), [];
|
|
770
793
|
let errorMessage = `${pathToString(context.path)}: Exception occurred while validating value: ${err.message}`;
|
|
771
794
|
return convertToValidationMarker({
|
|
772
795
|
code: validationMarkerCodes.validationException,
|
|
@@ -776,6 +799,9 @@ const dateValidators = {
|
|
|
776
799
|
}))).flat();
|
|
777
800
|
}
|
|
778
801
|
}, memoizedWarnOnArraySlug = memoize(warnOnArraySlug);
|
|
802
|
+
function hasCustomSlugUniqueness(options) {
|
|
803
|
+
return typeof options == "object" && !!options && "isUnique" in options && typeof options.isUnique == "function";
|
|
804
|
+
}
|
|
779
805
|
function serializePath(path) {
|
|
780
806
|
return path.reduce((target, part, i) => {
|
|
781
807
|
let isIndex = typeof part == "number", isKey = isKeyedObject(part);
|
|
@@ -797,7 +823,10 @@ const defaultIsUnique = (slug, context) => {
|
|
|
797
823
|
docType,
|
|
798
824
|
published: getPublishedId(document._id),
|
|
799
825
|
slug
|
|
800
|
-
}, {
|
|
826
|
+
}, {
|
|
827
|
+
signal: context.signal,
|
|
828
|
+
tag: "validation.slug-is-unique"
|
|
829
|
+
});
|
|
801
830
|
};
|
|
802
831
|
function warnOnArraySlug(serializedPath) {
|
|
803
832
|
console.warn([
|
|
@@ -806,25 +835,21 @@ function warnOnArraySlug(serializedPath) {
|
|
|
806
835
|
"To disable this message, set `disableArrayWarning: true` on the slug `options` field"
|
|
807
836
|
].join("\n"));
|
|
808
837
|
}
|
|
809
|
-
|
|
810
|
-
* Validates slugs values by querying for uniqueness from the client.
|
|
811
|
-
*
|
|
812
|
-
* This is a custom rule implementation (e.g. `Rule.custom(slugValidator)`)
|
|
813
|
-
* that's populated in `inferFromSchemaType` when the type name is `slug`
|
|
814
|
-
*/
|
|
815
|
-
const slugValidator = async (value, context) => {
|
|
838
|
+
const slugStructureValidator = (value, context) => {
|
|
816
839
|
if (!value) return !0;
|
|
817
840
|
let { i18n } = context;
|
|
818
|
-
|
|
841
|
+
return typeof value != "object" || Array.isArray(value) ? {
|
|
819
842
|
code: validationMarkerCodes.slugInvalidType,
|
|
820
843
|
details: { actualType: typeString(value) },
|
|
821
844
|
message: i18n.t("validation:slug.not-object")
|
|
822
|
-
}
|
|
823
|
-
if (!isSlug(value) || value.current.trim().length === 0) return {
|
|
845
|
+
} : !isSlug(value) || value.current.trim().length === 0 ? {
|
|
824
846
|
code: validationMarkerCodes.slugMissingCurrent,
|
|
825
847
|
message: i18n.t("validation:slug.missing-current")
|
|
826
|
-
};
|
|
827
|
-
|
|
848
|
+
} : !0;
|
|
849
|
+
};
|
|
850
|
+
async function validateSlugUniqueness(value, context, isUnique) {
|
|
851
|
+
if (!isSlug(value) || value.current.trim().length === 0) return !0;
|
|
852
|
+
let { i18n } = context, slugContext = {
|
|
828
853
|
...context,
|
|
829
854
|
parent: context.parent,
|
|
830
855
|
type: context.type,
|
|
@@ -835,6 +860,10 @@ const slugValidator = async (value, context) => {
|
|
|
835
860
|
details: { slug: value.current },
|
|
836
861
|
message: i18n.t("validation:slug.not-unique", { slug: value.current })
|
|
837
862
|
};
|
|
863
|
+
}
|
|
864
|
+
const defaultSlugUniquenessValidator = (value, context) => validateSlugUniqueness(value, context, defaultIsUnique), customSlugUniquenessValidator = (value, context) => {
|
|
865
|
+
let options = context.type?.options;
|
|
866
|
+
return !hasCustomSlugUniqueness(options) || validateSlugUniqueness(value, context, options.isUnique);
|
|
838
867
|
}, ruleConstraintTypes = {
|
|
839
868
|
array: !0,
|
|
840
869
|
boolean: !0,
|
|
@@ -850,7 +879,13 @@ function baseRuleReducer(inputRule, type) {
|
|
|
850
879
|
let baseRule = inputRule;
|
|
851
880
|
isRuleConstraint(type.jsonType) && (baseRule = baseRule.type(type.jsonType));
|
|
852
881
|
let typeOptionsList = type?.options && typeof type.options == "object" && "list" in type.options && type.options.list;
|
|
853
|
-
|
|
882
|
+
if (Array.isArray(typeOptionsList) && (baseRule = baseRule.valid(typeOptionsList.map((option) => extractValueFromListOption(option, type)))), type.name === "datetime" || type.name === "date") return baseRule.type("Date");
|
|
883
|
+
if (type.name === "url") return baseRule.uri();
|
|
884
|
+
if (type.name === "slug") {
|
|
885
|
+
let uniquenessValidator = hasCustomSlugUniqueness(type.options) ? customSlugUniquenessValidator : markInternalValidator(defaultSlugUniquenessValidator);
|
|
886
|
+
return baseRule.custom(markInternalValidator(slugStructureValidator), { bypassConcurrencyLimit: !0 }).custom(uniquenessValidator, { bypassConcurrencyLimit: !0 });
|
|
887
|
+
}
|
|
888
|
+
return type.name === "reference" ? baseRule.reference() : type.name === "email" ? baseRule.email() : baseRule;
|
|
854
889
|
}
|
|
855
890
|
function hasValueField(typeDef) {
|
|
856
891
|
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;
|
|
@@ -861,7 +896,7 @@ function extractValueFromListOption(option, typeDef) {
|
|
|
861
896
|
const isUriSpec = (spec) => spec.flag === "uri";
|
|
862
897
|
function omitLeakedDefaultUri(rules, typeDef) {
|
|
863
898
|
if (!getTypeChain(typeDef).some((type) => type.name === "url")) return rules;
|
|
864
|
-
let defaultUri = new Rule$2(typeDef).uri()._rules.find(isUriSpec)?.constraint, isDefaultUri = (spec) => isUriSpec(spec) &&
|
|
899
|
+
let defaultUri = new Rule$2(typeDef).uri()._rules.find(isUriSpec)?.constraint, isDefaultUri = (spec) => isUriSpec(spec) && dequal(spec.constraint, defaultUri), isCustomUri = (spec) => isUriSpec(spec) && !dequal(spec.constraint, defaultUri);
|
|
865
900
|
return rules.some((rule) => rule._rules.some(isCustomUri)) ? rules.map((rule) => {
|
|
866
901
|
if (!rule._rules.some(isDefaultUri)) return rule;
|
|
867
902
|
let cleaned = rule.clone();
|
|
@@ -912,6 +947,9 @@ const requestIdleCallbackShim = function requestIdleCallbackShim(callback, _opti
|
|
|
912
947
|
path: [unknownField]
|
|
913
948
|
}));
|
|
914
949
|
}, DEFAULT_VALIDATION_CLIENT_OPTIONS = { apiVersion: "2025-02-19" }, isRecord = (maybeRecord) => typeof maybeRecord == "object" && !!maybeRecord && !Array.isArray(maybeRecord);
|
|
950
|
+
function throwClientUnavailable() {
|
|
951
|
+
throw new ClientUnavailableError();
|
|
952
|
+
}
|
|
915
953
|
/**
|
|
916
954
|
* Recursively extracts all `_fieldRules` from a rule and its nested constraints.
|
|
917
955
|
* This handles cases where `Rule.fields()` is used inside `Rule.all()` or `Rule.either()`.
|
|
@@ -939,9 +977,10 @@ function resolveTypeForArrayItem(item, candidates) {
|
|
|
939
977
|
* @beta
|
|
940
978
|
* @deprecated Prefer {@link validateDocument} with `{document, schema, client}` for new code.
|
|
941
979
|
*/
|
|
942
|
-
function validateDocumentWithWorkspace({ document, workspace, getClient = workspace.getClient, getDocumentExists, environment = "studio", maxCustomValidationConcurrency, maxFetchConcurrency, currentUser }) {
|
|
980
|
+
function validateDocumentWithWorkspace({ document, workspace, getClient = workspace.getClient, getDocumentExists, environment = "studio", maxCustomValidationConcurrency, maxFetchConcurrency, currentUser, customValidation, signal }) {
|
|
943
981
|
return validateDocumentInternal({
|
|
944
982
|
currentUser,
|
|
983
|
+
customValidation,
|
|
945
984
|
document,
|
|
946
985
|
environment,
|
|
947
986
|
getClient,
|
|
@@ -949,33 +988,58 @@ function validateDocumentWithWorkspace({ document, workspace, getClient = worksp
|
|
|
949
988
|
i18n: workspace.i18n,
|
|
950
989
|
maxCustomValidationConcurrency,
|
|
951
990
|
maxFetchConcurrency,
|
|
952
|
-
schema: workspace.schema
|
|
991
|
+
schema: workspace.schema,
|
|
992
|
+
signal
|
|
953
993
|
});
|
|
954
994
|
}
|
|
995
|
+
/**
|
|
996
|
+
* Validates a document against a compiled schema. Returns failures and whether
|
|
997
|
+
* validation completed
|
|
998
|
+
* without deciding whether the document may be edited or published.
|
|
999
|
+
*
|
|
1000
|
+
* @beta
|
|
1001
|
+
*/
|
|
955
1002
|
function validateDocument(options) {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
return validateDocumentInternal({
|
|
1003
|
+
let { client, customValidation = !!options.client, document, getDocumentExists, schema, ...internalOptions } = options;
|
|
1004
|
+
return evaluateDocumentInternal({
|
|
959
1005
|
...internalOptions,
|
|
1006
|
+
customValidation,
|
|
960
1007
|
document,
|
|
961
1008
|
environment: "cli",
|
|
962
|
-
getClient: ({ apiVersion }) => client.withConfig({ apiVersion }),
|
|
1009
|
+
getClient: client ? ({ apiVersion }) => client.withConfig({ apiVersion }) : throwClientUnavailable,
|
|
1010
|
+
getDocumentExists: getDocumentExists || (client ? void 0 : throwClientUnavailable),
|
|
963
1011
|
i18n: getFallbackLocaleSource(),
|
|
964
1012
|
schema
|
|
965
1013
|
});
|
|
966
1014
|
}
|
|
1015
|
+
function createDocumentValidationResult(markers, complete) {
|
|
1016
|
+
return {
|
|
1017
|
+
status: getDocumentValidationStatus(markers, complete),
|
|
1018
|
+
markers: markers.map(toDocumentValidationMarker)
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
function getDocumentValidationStatus(markers, complete) {
|
|
1022
|
+
return markers.length > 0 ? "failed" : complete ? "passed" : "notEvaluated";
|
|
1023
|
+
}
|
|
1024
|
+
/** @internal */
|
|
1025
|
+
function validateDocumentInternal(options) {
|
|
1026
|
+
return evaluateDocumentInternal(options).then(({ markers }) => markers);
|
|
1027
|
+
}
|
|
967
1028
|
/** @internal */
|
|
968
|
-
function
|
|
969
|
-
|
|
970
|
-
|
|
1029
|
+
function evaluateDocumentInternal({ document, schema, getClient, getDocumentExists, i18n = getFallbackLocaleSource(), environment, maxCustomValidationConcurrency, maxFetchConcurrency, currentUser, customValidation = !0, signal }) {
|
|
1030
|
+
if (signal?.aborted) return Promise.reject(signal.reason);
|
|
1031
|
+
let limitConcurrency = createClientConcurrencyLimiter(maxFetchConcurrency ?? 25, signal), getConcurrencyLimitedClient = (clientOptions) => limitConcurrency(getClient(clientOptions));
|
|
1032
|
+
return lastValueFrom(evaluateDocumentObservable({
|
|
971
1033
|
document,
|
|
972
1034
|
getClient: getConcurrencyLimitedClient,
|
|
973
1035
|
i18n,
|
|
974
1036
|
schema,
|
|
975
|
-
getDocumentExists: getDocumentExists || createBatchedGetDocumentExists(getClient(DEFAULT_VALIDATION_CLIENT_OPTIONS)),
|
|
1037
|
+
getDocumentExists: getDocumentExists || createBatchedGetDocumentExists(getClient(DEFAULT_VALIDATION_CLIENT_OPTIONS), signal),
|
|
976
1038
|
environment,
|
|
977
1039
|
maxCustomValidationConcurrency,
|
|
978
|
-
currentUser
|
|
1040
|
+
currentUser,
|
|
1041
|
+
customValidation,
|
|
1042
|
+
signal
|
|
979
1043
|
}));
|
|
980
1044
|
}
|
|
981
1045
|
const customValidationConcurrencyLimiters = /* @__PURE__ */ new WeakMap();
|
|
@@ -983,48 +1047,69 @@ const customValidationConcurrencyLimiters = /* @__PURE__ */ new WeakMap();
|
|
|
983
1047
|
* Validates a document against the given schema, returning an Observable
|
|
984
1048
|
* @internal
|
|
985
1049
|
*/
|
|
986
|
-
function validateDocumentObservable(
|
|
1050
|
+
function validateDocumentObservable(options) {
|
|
1051
|
+
return evaluateDocumentObservable(options).pipe(map$1(({ markers }) => markers));
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Validates a document against the given schema, including completion status.
|
|
1055
|
+
* @internal
|
|
1056
|
+
*/
|
|
1057
|
+
function evaluateDocumentObservable(options) {
|
|
1058
|
+
let { signal } = options;
|
|
1059
|
+
return defer(() => (signal?.throwIfAborted(), evaluateDocumentObservableWithoutCancellation(options))).pipe(cancelWith(signal));
|
|
1060
|
+
}
|
|
1061
|
+
function evaluateDocumentObservableWithoutCancellation({ document, getClient, i18n = getFallbackLocaleSource(), schema, getDocumentExists, environment, maxCustomValidationConcurrency, currentUser, customValidation = !0, signal }) {
|
|
987
1062
|
if (typeof document?._type != "string") throw Error("Tried to validate a value without a '_type'");
|
|
988
1063
|
let documentType = schema.get(document._type);
|
|
989
|
-
if (!documentType) return environment === "studio" ? (console.warn("Schema type for object type \"%s\" not found, skipping validation", document._type), of([])) : of([{
|
|
1064
|
+
if (!documentType) return environment === "studio" ? (console.warn("Schema type for object type \"%s\" not found, skipping validation", document._type), of(createDocumentValidationResult([], !0))) : of(createDocumentValidationResult([{
|
|
990
1065
|
code: validationMarkerCodes.documentUnknownType,
|
|
991
1066
|
details: { documentType: document._type },
|
|
992
1067
|
level: "warning",
|
|
993
1068
|
message: `Could not find schema type for type '${document._type}', skipping validation`,
|
|
994
1069
|
path: []
|
|
995
|
-
}]);
|
|
1070
|
+
}], !0));
|
|
996
1071
|
let customValidationConcurrencyLimiter = customValidationConcurrencyLimiters.get(schema);
|
|
997
|
-
customValidationConcurrencyLimiter || (customValidationConcurrencyLimiter = new ConcurrencyLimiter(maxCustomValidationConcurrency ?? 5), customValidationConcurrencyLimiters.set(schema, customValidationConcurrencyLimiter))
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
level: "error",
|
|
1017
|
-
message,
|
|
1018
|
-
item: { message },
|
|
1019
|
-
path: []
|
|
1072
|
+
return customValidationConcurrencyLimiter || (customValidationConcurrencyLimiter = new ConcurrencyLimiter(maxCustomValidationConcurrency ?? 5), customValidationConcurrencyLimiters.set(schema, customValidationConcurrencyLimiter)), defer(() => {
|
|
1073
|
+
let complete = !0, validationOptions = {
|
|
1074
|
+
getClient,
|
|
1075
|
+
schema,
|
|
1076
|
+
parent: void 0,
|
|
1077
|
+
value: document,
|
|
1078
|
+
path: [],
|
|
1079
|
+
document,
|
|
1080
|
+
type: documentType,
|
|
1081
|
+
i18n,
|
|
1082
|
+
getDocumentExists,
|
|
1083
|
+
environment,
|
|
1084
|
+
customValidationConcurrencyLimiter,
|
|
1085
|
+
currentUser,
|
|
1086
|
+
customValidation,
|
|
1087
|
+
signal,
|
|
1088
|
+
__internal: { markIncomplete: () => {
|
|
1089
|
+
complete = !1;
|
|
1090
|
+
} }
|
|
1020
1091
|
};
|
|
1021
|
-
return
|
|
1022
|
-
|
|
1092
|
+
return from(i18n.loadNamespaces(["validation"])).pipe(switchMap(() => validateItemObservable(validationOptions)), map$1((markers) => createDocumentValidationResult(markers, complete)), catchError((err) => {
|
|
1093
|
+
if (signal?.aborted) return throwError(() => signal.reason);
|
|
1094
|
+
console.error(err);
|
|
1095
|
+
let message = err?.message || "Unknown error", errorMarker = {
|
|
1096
|
+
code: validationMarkerCodes.validationException,
|
|
1097
|
+
level: "error",
|
|
1098
|
+
message,
|
|
1099
|
+
item: { message },
|
|
1100
|
+
path: []
|
|
1101
|
+
};
|
|
1102
|
+
return of(createDocumentValidationResult([errorMarker], complete));
|
|
1103
|
+
}));
|
|
1104
|
+
});
|
|
1023
1105
|
}
|
|
1024
1106
|
function validateItem(opts) {
|
|
1025
|
-
return lastValueFrom(validateItemObservable(opts));
|
|
1107
|
+
return lastValueFrom(defer(() => (opts.signal?.throwIfAborted(), validateItemObservable(opts))).pipe(cancelWith(opts.signal)));
|
|
1108
|
+
}
|
|
1109
|
+
function validateRule(rule, value, context) {
|
|
1110
|
+
return rule.validate(value, context);
|
|
1026
1111
|
}
|
|
1027
|
-
function validateItemObservable({ value, type, path = [], parent, customValidationConcurrencyLimiter, environment, ...restOfContext }) {
|
|
1112
|
+
function validateItemObservable({ value, type, path = [], parent, customValidationConcurrencyLimiter, environment, customValidation = !0, __internal, ...restOfContext }) {
|
|
1028
1113
|
let ancestorHidden = restOfContext.hidden === !0, resolveHiddenForType = (schemaType, schemaValue, schemaParent, schemaPath, ancestorHiddenValue) => schemaType ? ancestorHiddenValue || resolveConditionalProperty(schemaType.hidden, {
|
|
1029
1114
|
...restOfContext,
|
|
1030
1115
|
parent: schemaParent,
|
|
@@ -1036,21 +1121,25 @@ function validateItemObservable({ value, type, path = [], parent, customValidati
|
|
|
1036
1121
|
"document",
|
|
1037
1122
|
"file",
|
|
1038
1123
|
"image"
|
|
1039
|
-
].includes(t.name)) && environment !== "studio" ? rule.custom(unknownFieldsValidator(type), { bypassConcurrencyLimit: !0 }).warning() : rule, rules = normalizeValidationRules(type, {
|
|
1124
|
+
].includes(t.name)) && environment !== "studio" ? rule.custom(markInternalValidator(unknownFieldsValidator(type)), { bypassConcurrencyLimit: !0 }).warning() : rule, rules = normalizeValidationRules(type, {
|
|
1040
1125
|
...restOfContext,
|
|
1041
1126
|
hidden,
|
|
1042
1127
|
environment,
|
|
1043
1128
|
parent,
|
|
1044
1129
|
path,
|
|
1045
1130
|
type
|
|
1046
|
-
}), selfChecks = rules.map(addUnknownFieldsValidator).map((rule) => defer(() => rule
|
|
1131
|
+
}), selfChecks = rules.map(addUnknownFieldsValidator).map((rule) => defer(() => validateRule(rule, value, {
|
|
1047
1132
|
...restOfContext,
|
|
1048
1133
|
environment,
|
|
1049
1134
|
hidden,
|
|
1050
1135
|
parent,
|
|
1051
1136
|
path,
|
|
1052
1137
|
type,
|
|
1053
|
-
__internal: {
|
|
1138
|
+
__internal: {
|
|
1139
|
+
...__internal,
|
|
1140
|
+
customValidation,
|
|
1141
|
+
customValidationConcurrencyLimiter
|
|
1142
|
+
}
|
|
1054
1143
|
}))), nestedChecks = [], selfIsRequired = rules.some((rule) => rule.isRequired());
|
|
1055
1144
|
if (type?.jsonType === "object" && (value || value == null && selfIsRequired)) {
|
|
1056
1145
|
let fieldTypes = type.fields.reduce((acc, field) => (acc[field.name] = field.type, acc), {});
|
|
@@ -1061,14 +1150,18 @@ function validateItemObservable({ value, type, path = [], parent, customValidati
|
|
|
1061
1150
|
validation
|
|
1062
1151
|
}).map(addUnknownFieldsValidator).map((subRule) => {
|
|
1063
1152
|
let nestedValue = isRecord(value) ? value[name] : void 0, nestedHidden = resolveHiddenForType(fieldType, nestedValue, value, path.concat(name), hidden);
|
|
1064
|
-
return defer(() => subRule
|
|
1153
|
+
return defer(() => validateRule(subRule, nestedValue, {
|
|
1065
1154
|
...restOfContext,
|
|
1066
1155
|
parent: value,
|
|
1067
1156
|
path: path.concat(name),
|
|
1068
1157
|
type: fieldType,
|
|
1069
1158
|
environment,
|
|
1070
1159
|
hidden: nestedHidden,
|
|
1071
|
-
__internal: {
|
|
1160
|
+
__internal: {
|
|
1161
|
+
...__internal,
|
|
1162
|
+
customValidation,
|
|
1163
|
+
customValidationConcurrencyLimiter
|
|
1164
|
+
}
|
|
1072
1165
|
}));
|
|
1073
1166
|
});
|
|
1074
1167
|
})), nestedChecks = nestedChecks.concat(type.fields.map((field) => validateItemObservable({
|
|
@@ -1079,7 +1172,9 @@ function validateItemObservable({ value, type, path = [], parent, customValidati
|
|
|
1079
1172
|
path: path.concat(field.name),
|
|
1080
1173
|
type: field.type,
|
|
1081
1174
|
environment,
|
|
1082
|
-
customValidationConcurrencyLimiter
|
|
1175
|
+
customValidationConcurrencyLimiter,
|
|
1176
|
+
customValidation,
|
|
1177
|
+
__internal
|
|
1083
1178
|
})));
|
|
1084
1179
|
}
|
|
1085
1180
|
return type?.jsonType === "array" && Array.isArray(value) && (nestedChecks = nestedChecks.concat(value.map((item, index) => validateItemObservable({
|
|
@@ -1090,7 +1185,9 @@ function validateItemObservable({ value, type, path = [], parent, customValidati
|
|
|
1090
1185
|
path: path.concat(isKeyedObject(item) ? { _key: item._key } : index),
|
|
1091
1186
|
type: resolveTypeForArrayItem(item, type.of),
|
|
1092
1187
|
environment,
|
|
1093
|
-
customValidationConcurrencyLimiter
|
|
1188
|
+
customValidationConcurrencyLimiter,
|
|
1189
|
+
customValidation,
|
|
1190
|
+
__internal
|
|
1094
1191
|
})))), 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
1192
|
}
|
|
1096
1193
|
function deduplicateMarkers(markers) {
|
|
@@ -1102,7 +1199,7 @@ function deduplicateMarkers(markers) {
|
|
|
1102
1199
|
marker.message,
|
|
1103
1200
|
marker.path
|
|
1104
1201
|
]), bucket = buckets.get(key);
|
|
1105
|
-
return bucket ? !bucket.some((existing) =>
|
|
1202
|
+
return bucket ? !bucket.some((existing) => dequal(existing, marker)) && (bucket.push(marker), !0) : (buckets.set(key, [marker]), !0);
|
|
1106
1203
|
});
|
|
1107
1204
|
}
|
|
1108
1205
|
function hasValidationMarkerCode(marker) {
|
|
@@ -1122,6 +1219,6 @@ function idle(timeout) {
|
|
|
1122
1219
|
return () => cancelIdleCallback(handle);
|
|
1123
1220
|
});
|
|
1124
1221
|
}
|
|
1125
|
-
export {
|
|
1222
|
+
export { validationMarkerCodes as _, validateDocumentInternal as a, validateItem as c, Rule$2 as d, typeString as f, validationLocaleStrings as g, getFallbackLocaleSource as h, validateDocument as i, getTypeChain as l, pathToString as m, evaluateDocumentObservable as n, validateDocumentObservable as o, convertToValidationMarker as p, resolveTypeForArrayItem as r, validateDocumentWithWorkspace as s, evaluateDocumentInternal as t, normalizeValidationRules as u };
|
|
1126
1223
|
|
|
1127
|
-
//# sourceMappingURL=validateDocument-
|
|
1224
|
+
//# sourceMappingURL=validateDocument-DtBbNOGc.js.map
|