@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 CHANGED
@@ -5,9 +5,9 @@ Validates complete Sanity documents against a compiled Sanity schema.
5
5
  ```ts
6
6
  import {validateDocument, validationMarkerCodes} from '@sanity/validation'
7
7
 
8
- const markers = await validateDocument({document, schema, client})
8
+ const result = await validateDocument({document, schema, client})
9
9
 
10
- for (const marker of markers) {
10
+ for (const marker of result.markers) {
11
11
  if (marker.code === validationMarkerCodes.stringMinimumLength) {
12
12
  const {actualLength, minimumLength} = marker.details || {}
13
13
  if (typeof actualLength === 'number' && typeof minimumLength === 'number') {
@@ -16,7 +16,7 @@ for (const marker of markers) {
16
16
  }
17
17
  }
18
18
 
19
- const summary = markers
19
+ const summary = result.markers
20
20
  .map((marker) => {
21
21
  const path = marker.path
22
22
  .map((segment) => (typeof segment === 'object' ? segment._key : segment))
@@ -27,26 +27,50 @@ const summary = markers
27
27
  .join('\n')
28
28
  ```
29
29
 
30
- Every returned marker includes a stable machine-readable `code` alongside its localized `message`,
30
+ Every failed marker includes a stable machine-readable `code` alongside its localized `message`,
31
31
  `level`, and `path`. Built-in failures may also include structured `details`. Custom validators can
32
32
  return their own `code` and `details`; custom codes should be namespaced, for example
33
33
  `custom.seo-title`.
34
34
 
35
+ When a check cannot run, `result.status` is `notEvaluated`. Omitting `client` disables custom
36
+ callbacks and skips network checks. Pass `customValidation: false` to disable custom callbacks while
37
+ still providing a client.
38
+
39
+ Pass one `AbortSignal` to cancel validation and its pending network work. Built-in checks and client
40
+ requests made through a custom validator's `context.getClient()` inherit this signal. A custom
41
+ `getDocumentExists` callback receives it as an argument; custom work using another API should pass
42
+ `context.signal` to that API. Cancellation rejects with the signal's reason (an `AbortError` when
43
+ no custom reason was supplied). Work that does not accept an abort signal cannot be stopped, even
44
+ though validation itself rejects immediately.
45
+
46
+ ```ts
47
+ const controller = new AbortController()
48
+ const validation = validateDocument({document, schema, client, signal: controller.signal})
49
+ const reason = new Error('Validation cancelled')
50
+
51
+ controller.abort(reason)
52
+ try {
53
+ await validation
54
+ } catch (error) {
55
+ if (error !== reason) throw error
56
+ }
57
+ ```
58
+
35
59
  The package does not apply mutations or decide whether a document may be edited or published.
36
60
 
37
61
  ## Migrating from `sanity`
38
62
 
39
63
  Add `@sanity/validation` as a direct dependency. The workspace-based API is available as a
40
- compatibility overload, so call sites that only import `validateDocument` can migrate by changing
41
- the import:
64
+ deprecated compatibility helper, so call sites that only import the validation function can
65
+ migrate by changing the imported symbol:
42
66
 
43
67
  ```ts
44
- import {validateDocument} from '@sanity/validation'
68
+ import {validateDocumentWithWorkspace} from '@sanity/validation'
45
69
 
46
- const markers = await validateDocument({document, workspace})
70
+ const markers = await validateDocumentWithWorkspace({document, workspace})
47
71
  ```
48
72
 
49
73
  Call sites that also import `ValidateDocumentOptions` from `sanity` should use
50
74
  `ValidateDocumentWorkspaceOptions` for the workspace-shaped options.
51
75
 
52
- Prefer the `{document, schema, client}` API for new code.
76
+ Prefer `validateDocument({document, schema, client})` for new code.
@@ -1,4 +1,4 @@
1
- import { c as resolveTypeForArrayItem, d as validateDocumentObservable, g as ValidationMarkerCode, n as ValidateDocumentObservableOptions, p as validateItem, t as ValidateDocumentInternalOptions, u as validateDocumentInternal, v as ValidationContext, y as LocaleSource } from "./validateDocument-6pLTIHIn.js";
1
+ import { C as LocaleSource, S as ValidationContext, _ as validateItem, b as ValidationMarkerCode, d as evaluateDocumentObservable, f as resolveTypeForArrayItem, h as validateDocumentObservable, m as validateDocumentInternal, n as ValidateDocumentInternalOptions, o as ValidateItemOptions, r as ValidateDocumentObservableOptions, u as evaluateDocumentInternal } from "./validateDocument-CdvFjlAk.js";
2
2
  import { Path, Rule as Rule$1, RuleClass, Schema, SchemaType, SchemaValidationValue, ValidationContext as ValidationContext$1, ValidationError, ValidationMarker } from "@sanity/types";
3
3
  declare function getFallbackLocaleSource(): LocaleSource;
4
4
  declare const validationLocaleStrings: {
@@ -92,5 +92,5 @@ declare function getTypeChain(type: SchemaType | undefined, visited?: Set<Schema
92
92
  declare function normalizeValidationRules(typeDef: SchemaType | undefined, context?: ValidationContext$1): Rule$1[];
93
93
  declare function pathToString(path?: Path | undefined): string;
94
94
  declare function typeString(obj: unknown): string;
95
- export { type LocaleSource, Rule, type ValidateDocumentInternalOptions, type ValidateDocumentObservableOptions, type ValidationContext, convertToValidationMarker, getFallbackLocaleSource, getTypeChain, hasValidationContext, inferFromSchema, inferFromSchemaType, normalizeValidationRules, pathToString, resolveTypeForArrayItem, typeString, validateDocumentInternal, validateDocumentObservable, validateItem, validationLocaleStrings };
95
+ export { type LocaleSource, Rule, type ValidateDocumentInternalOptions, type ValidateDocumentObservableOptions, type ValidateItemOptions, type ValidationContext, convertToValidationMarker, evaluateDocumentInternal, evaluateDocumentObservable, getFallbackLocaleSource, getTypeChain, hasValidationContext, inferFromSchema, inferFromSchemaType, normalizeValidationRules, pathToString, resolveTypeForArrayItem, typeString, validateDocumentInternal, validateDocumentObservable, validateItem, validationLocaleStrings };
96
96
  //# sourceMappingURL=_internal.d.ts.map
package/lib/_internal.js CHANGED
@@ -1,4 +1,4 @@
1
- import { c as normalizeValidationRules, d as convertToValidationMarker, f as pathToString, i as validateDocumentObservable, l as Rule, m as validationLocaleStrings, o as validateItem, p as getFallbackLocaleSource, r as validateDocumentInternal, s as getTypeChain, t as resolveTypeForArrayItem, u as typeString } from "./validateDocument-Cq33kUmN.js";
1
+ import { a as validateDocumentInternal, c as validateItem, d as Rule, f as typeString, g as validationLocaleStrings, h as getFallbackLocaleSource, l as getTypeChain, m as pathToString, n as evaluateDocumentObservable, o as validateDocumentObservable, p as convertToValidationMarker, r as resolveTypeForArrayItem, t as evaluateDocumentInternal, u as normalizeValidationRules } from "./validateDocument-DtBbNOGc.js";
2
2
  function inferFromSchemaType(typeDef) {
3
3
  return traverse(typeDef, /* @__PURE__ */ new Set()), typeDef;
4
4
  }
@@ -34,6 +34,6 @@ function inferFromSchema(schema) {
34
34
  schemaType && inferFromSchemaType(schemaType);
35
35
  }), schema;
36
36
  }
37
- export { Rule, convertToValidationMarker, getFallbackLocaleSource, getTypeChain, hasValidationContext, inferFromSchema, inferFromSchemaType, normalizeValidationRules, pathToString, resolveTypeForArrayItem, typeString, validateDocumentInternal, validateDocumentObservable, validateItem, validationLocaleStrings };
37
+ export { Rule, convertToValidationMarker, evaluateDocumentInternal, evaluateDocumentObservable, getFallbackLocaleSource, getTypeChain, hasValidationContext, inferFromSchema, inferFromSchemaType, normalizeValidationRules, pathToString, resolveTypeForArrayItem, typeString, validateDocumentInternal, validateDocumentObservable, validateItem, validationLocaleStrings };
38
38
 
39
39
  //# sourceMappingURL=_internal.js.map
package/lib/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as validationMarkerCodes, a as ValidationClient, f as validateDocumentWithWorkspace, g as ValidationMarkerCode, h as DocumentValidationMarker, i as ValidateDocumentWorkspaceOptions, l as validateDocument, m as BuiltInValidationMarkerCode, o as ValidationSchema, r as ValidateDocumentOptions, s as ValidationSource } from "./validateDocument-6pLTIHIn.js";
2
- export { type BuiltInValidationMarkerCode, type DocumentValidationMarker, type ValidateDocumentOptions, type ValidateDocumentWorkspaceOptions, type ValidationClient, type ValidationMarkerCode, type ValidationSchema, type ValidationSource, validateDocument, validateDocumentWithWorkspace, validationMarkerCodes };
1
+ import { a as ValidateDocumentWorkspaceOptions, b as ValidationMarkerCode, c as ValidationSchema, g as validateDocumentWithWorkspace, i as ValidateDocumentOptions, l as ValidationSource, p as validateDocument, s as ValidationClient, t as DocumentValidationResult, v as BuiltInValidationMarkerCode, x as validationMarkerCodes, y as DocumentValidationMarker } from "./validateDocument-CdvFjlAk.js";
2
+ export { type BuiltInValidationMarkerCode, type DocumentValidationMarker, type DocumentValidationResult, type ValidateDocumentOptions, type ValidateDocumentWorkspaceOptions, type ValidationClient, type ValidationMarkerCode, type ValidationSchema, type ValidationSource, validateDocument, validateDocumentWithWorkspace, validationMarkerCodes };
package/lib/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as validateDocumentWithWorkspace, h as validationMarkerCodes, n as validateDocument } from "./validateDocument-Cq33kUmN.js";
1
+ import { _ as validationMarkerCodes, i as validateDocument, s as validateDocumentWithWorkspace } from "./validateDocument-DtBbNOGc.js";
2
2
  export { validateDocument, validateDocumentWithWorkspace, validationMarkerCodes };
@@ -1,4 +1,4 @@
1
- import { CurrentUser, SanityDocument, Schema, SchemaType, ValidationContext as ValidationContext$1, ValidationMarker } from "@sanity/types";
1
+ import { CurrentUser, SanityDocument, Schema, SchemaType, ValidationContext, ValidationContext as ValidationContext$1, ValidationMarker } from "@sanity/types";
2
2
  import { ConcurrencyLimiter } from "@sanity/util/concurrency-limiter";
3
3
  import { Observable } from "rxjs";
4
4
  import { TFunction } from "i18next";
@@ -34,6 +34,17 @@ declare module '@sanity/types' {
34
34
  i18n: LocaleSource;
35
35
  }
36
36
  }
37
+ interface InternalValidationContext extends ValidationContext {
38
+ __internal?: {
39
+ customValidation?: boolean;
40
+ customValidationConcurrencyLimiter?: {
41
+ ready: (signal?: AbortSignal) => Promise<void>;
42
+ release: () => void;
43
+ run: <T>(work: () => PromiseLike<T> | T, signal?: AbortSignal) => Promise<T>;
44
+ };
45
+ markIncomplete?: () => void;
46
+ };
47
+ }
37
48
  /** Machine-readable codes emitted by built-in document validation. @beta */
38
49
  declare const validationMarkerCodes: {
39
50
  readonly arrayDuplicateItem: 'array.duplicate-item';
@@ -98,18 +109,15 @@ type DocumentValidationMarker = Omit<ValidationMarker, 'code'> & {
98
109
  * @internal
99
110
  */
100
111
  declare function resolveTypeForArrayItem(item: unknown, candidates: SchemaType[]): SchemaType | undefined;
101
- /**
102
- * @beta
103
- */
104
- interface ValidateDocumentOptions {
112
+ interface ValidateDocumentBaseOptions {
105
113
  /**
106
114
  * The document to be validated
107
115
  */
108
116
  document: SanityDocument;
109
117
  /** The compiled schema to validate against. */
110
118
  schema: ValidationSchema;
111
- /** A configured client used for reference checks and custom validators. */
112
- client: ValidationClient;
119
+ /** Signal used to cancel validation and any work it starts. */
120
+ signal?: AbortSignal;
113
121
  /**
114
122
  * Function used to check if referenced documents exists (and is published).
115
123
  *
@@ -121,6 +129,7 @@ interface ValidateDocumentOptions {
121
129
  */
122
130
  getDocumentExists?: (options: {
123
131
  id: string;
132
+ signal?: AbortSignal;
124
133
  }) => Promise<boolean>;
125
134
  /**
126
135
  * The maximum amount of custom validation functions to be running
@@ -149,6 +158,21 @@ interface ValidateDocumentOptions {
149
158
  */
150
159
  currentUser?: Omit<CurrentUser, 'role'> | null;
151
160
  }
161
+ /**
162
+ * Options for validating a document. Custom validation is disabled when no client is provided.
163
+ *
164
+ * @beta
165
+ */
166
+ type ValidateDocumentOptions = ValidateDocumentBaseOptions & ({
167
+ /** A configured client used for reference checks and custom validators. */
168
+ client: ValidationClient;
169
+ /** Whether to run custom validation callbacks. Defaults to `true`. */
170
+ customValidation?: boolean;
171
+ } | {
172
+ /** Omit the client to perform local validation without custom callbacks. */
173
+ client?: undefined;
174
+ customValidation?: false;
175
+ });
152
176
  /** A compiled schema accepted across compatible `@sanity/types` versions. @beta */
153
177
  interface ValidationSchema {
154
178
  get(name: string): unknown;
@@ -167,6 +191,13 @@ interface ValidationClient {
167
191
  observable: Pick<SanityClient['observable'], 'fetch' | 'request'>;
168
192
  withConfig(config: Parameters<SanityClient['withConfig']>[0]): ValidationClient;
169
193
  }
194
+ /** The result of validating a complete document. @beta */
195
+ interface DocumentValidationResult {
196
+ /** Whether validation passed, failed, or could not be fully evaluated. */
197
+ status: 'passed' | 'failed' | 'notEvaluated';
198
+ /** Validation rules that failed. */
199
+ markers: DocumentValidationMarker[];
200
+ }
170
201
  /**
171
202
  * The validation capabilities required from a resolved Studio source or workspace.
172
203
  *
@@ -187,7 +218,7 @@ interface ValidationSource {
187
218
  *
188
219
  * @beta
189
220
  */
190
- interface ValidateDocumentWorkspaceOptions extends Omit<ValidateDocumentOptions, 'client' | 'schema'> {
221
+ interface ValidateDocumentWorkspaceOptions extends Omit<ValidateDocumentBaseOptions, 'schema'> {
191
222
  /** The resolved Studio workspace or source used for validation. */
192
223
  workspace: ValidationSource;
193
224
  /**
@@ -198,6 +229,8 @@ interface ValidateDocumentWorkspaceOptions extends Omit<ValidateDocumentOptions,
198
229
  getClient?: ValidationSource['getClient'];
199
230
  /** Validation environment exposed to custom validators. */
200
231
  environment?: 'cli' | 'studio';
232
+ /** Whether to run custom validation callbacks. Defaults to `true`. */
233
+ customValidation?: boolean;
201
234
  }
202
235
  /**
203
236
  * Validates a document against the schema in a resolved Studio workspace or source.
@@ -205,23 +238,15 @@ interface ValidateDocumentWorkspaceOptions extends Omit<ValidateDocumentOptions,
205
238
  * @beta
206
239
  * @deprecated Prefer {@link validateDocument} with `{document, schema, client}` for new code.
207
240
  */
208
- declare function validateDocumentWithWorkspace({ document, workspace, getClient, getDocumentExists, environment, maxCustomValidationConcurrency, maxFetchConcurrency, currentUser }: ValidateDocumentWorkspaceOptions): Promise<DocumentValidationMarker[]>;
209
- /**
210
- * Validates a document against the schema in a resolved Studio workspace or source.
211
- *
212
- * This compatibility overload preserves the existing `sanity` API. Prefer the
213
- * `{document, schema, client}` overload for new code.
214
- *
215
- * @beta
216
- */
217
- declare function validateDocument(options: ValidateDocumentWorkspaceOptions): Promise<DocumentValidationMarker[]>;
241
+ declare function validateDocumentWithWorkspace({ document, workspace, getClient, getDocumentExists, environment, maxCustomValidationConcurrency, maxFetchConcurrency, currentUser, customValidation, signal }: ValidateDocumentWorkspaceOptions): Promise<DocumentValidationMarker[]>;
218
242
  /**
219
- * Validates a document against a compiled schema. Returns validation markers
243
+ * Validates a document against a compiled schema. Returns failures and whether
244
+ * validation completed
220
245
  * without deciding whether the document may be edited or published.
221
246
  *
222
247
  * @beta
223
248
  */
224
- declare function validateDocument(options: ValidateDocumentOptions): Promise<DocumentValidationMarker[]>;
249
+ declare function validateDocument(options: ValidateDocumentOptions): Promise<DocumentValidationResult>;
225
250
  /** @internal */
226
251
  interface ValidateDocumentInternalOptions {
227
252
  document: SanityDocument;
@@ -231,19 +256,24 @@ interface ValidateDocumentInternalOptions {
231
256
  }) => SanityClient;
232
257
  getDocumentExists?: (options: {
233
258
  id: string;
259
+ signal?: AbortSignal;
234
260
  }) => Promise<boolean>;
235
261
  i18n?: LocaleSource;
236
262
  environment: 'cli' | 'studio';
237
263
  maxCustomValidationConcurrency?: number;
238
264
  maxFetchConcurrency?: number;
239
265
  currentUser?: Omit<CurrentUser, 'role'> | null;
266
+ customValidation?: boolean;
267
+ signal?: AbortSignal;
240
268
  }
241
269
  /** @internal */
242
- declare function validateDocumentInternal({ document, schema, getClient, getDocumentExists, i18n, environment, maxCustomValidationConcurrency, maxFetchConcurrency, currentUser }: ValidateDocumentInternalOptions): Promise<DocumentValidationMarker[]>;
270
+ declare function validateDocumentInternal(options: ValidateDocumentInternalOptions): Promise<DocumentValidationMarker[]>;
271
+ /** @internal */
272
+ declare function evaluateDocumentInternal({ document, schema, getClient, getDocumentExists, i18n, environment, maxCustomValidationConcurrency, maxFetchConcurrency, currentUser, customValidation, signal }: ValidateDocumentInternalOptions): Promise<DocumentValidationResult>;
243
273
  /**
244
274
  * @internal
245
275
  */
246
- interface ValidateDocumentObservableOptions extends Pick<ValidationContext$1, 'getDocumentExists' | 'i18n'> {
276
+ interface ValidateDocumentObservableOptions extends Pick<ValidationContext$1, 'getDocumentExists' | 'i18n' | 'signal'> {
247
277
  getClient: (options: {
248
278
  apiVersion: string;
249
279
  }) => SanityClient;
@@ -252,12 +282,18 @@ interface ValidateDocumentObservableOptions extends Pick<ValidationContext$1, 'g
252
282
  environment: 'cli' | 'studio';
253
283
  maxCustomValidationConcurrency?: number;
254
284
  currentUser?: Omit<CurrentUser, 'role'> | null;
285
+ customValidation?: boolean;
255
286
  }
256
287
  /**
257
288
  * Validates a document against the given schema, returning an Observable
258
289
  * @internal
259
290
  */
260
- declare function validateDocumentObservable({ document, getClient, i18n, schema, getDocumentExists, environment, maxCustomValidationConcurrency, currentUser }: ValidateDocumentObservableOptions): Observable<DocumentValidationMarker[]>;
291
+ declare function validateDocumentObservable(options: ValidateDocumentObservableOptions): Observable<DocumentValidationMarker[]>;
292
+ /**
293
+ * Validates a document against the given schema, including completion status.
294
+ * @internal
295
+ */
296
+ declare function evaluateDocumentObservable(options: ValidateDocumentObservableOptions): Observable<DocumentValidationResult>;
261
297
  /**
262
298
  * this is used make optional properties required by replacing optionals with
263
299
  * `T[P] | undefined`. this is used to prevent errors in `validateItem` where
@@ -271,7 +307,10 @@ type ValidateItemOptions = {
271
307
  customValidationConcurrencyLimiter?: ConcurrencyLimiter;
272
308
  hidden?: boolean;
273
309
  currentUser?: Omit<CurrentUser, 'role'> | null;
274
- } & ExplicitUndefined<Omit<ValidationContext$1, 'hidden'>>;
310
+ customValidation?: boolean;
311
+ signal?: AbortSignal;
312
+ __internal?: InternalValidationContext['__internal'];
313
+ } & ExplicitUndefined<Omit<ValidationContext$1, 'hidden' | 'signal'>>;
275
314
  declare function validateItem(opts: ValidateItemOptions): Promise<ValidationMarker[]>;
276
- export { validationMarkerCodes as _, ValidationClient as a, resolveTypeForArrayItem as c, validateDocumentObservable as d, validateDocumentWithWorkspace as f, ValidationMarkerCode as g, DocumentValidationMarker as h, ValidateDocumentWorkspaceOptions as i, validateDocument as l, BuiltInValidationMarkerCode as m, ValidateDocumentObservableOptions as n, ValidationSchema as o, validateItem as p, ValidateDocumentOptions as r, ValidationSource as s, ValidateDocumentInternalOptions as t, validateDocumentInternal as u, ValidationContext$1 as v, LocaleSource as y };
277
- //# sourceMappingURL=validateDocument-6pLTIHIn.d.ts.map
315
+ export { LocaleSource as C, ValidationContext$1 as S, validateItem as _, ValidateDocumentWorkspaceOptions as a, ValidationMarkerCode as b, ValidationSchema as c, evaluateDocumentObservable as d, resolveTypeForArrayItem as f, validateDocumentWithWorkspace as g, validateDocumentObservable as h, ValidateDocumentOptions as i, ValidationSource as l, validateDocumentInternal as m, ValidateDocumentInternalOptions as n, ValidateItemOptions as o, validateDocument as p, ValidateDocumentObservableOptions as r, ValidationClient as s, DocumentValidationResult as t, evaluateDocumentInternal as u, BuiltInValidationMarkerCode as v, validationMarkerCodes as x, DocumentValidationMarker as y };
316
+ //# sourceMappingURL=validateDocument-CdvFjlAk.d.ts.map