@sanity/validation 3.14.3 → 6.12.0-next.112

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 +52 -0
  3. package/lib/_internal.d.ts +96 -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-6pLTIHIn.d.ts +277 -0
  9. package/lib/validateDocument-Cq33kUmN.js +1127 -0
  10. package/lib/validateDocument-Cq33kUmN.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
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2016 - 2023 Sanity.io
3
+ Copyright (c) 2016 - 2026 Sanity.io
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # @sanity/validation
2
+
3
+ Validates complete Sanity documents against a compiled Sanity schema.
4
+
5
+ ```ts
6
+ import {validateDocument, validationMarkerCodes} from '@sanity/validation'
7
+
8
+ const markers = await validateDocument({document, schema, client})
9
+
10
+ for (const marker of markers) {
11
+ if (marker.code === validationMarkerCodes.stringMinimumLength) {
12
+ const {actualLength, minimumLength} = marker.details || {}
13
+ if (typeof actualLength === 'number' && typeof minimumLength === 'number') {
14
+ console.log(`Expected at least ${minimumLength} characters, got ${actualLength}`)
15
+ }
16
+ }
17
+ }
18
+
19
+ const summary = markers
20
+ .map((marker) => {
21
+ const path = marker.path
22
+ .map((segment) => (typeof segment === 'object' ? segment._key : segment))
23
+ .join('.')
24
+
25
+ return `[${marker.level}] ${path || '<document>'}: ${marker.message} (${marker.code})`
26
+ })
27
+ .join('\n')
28
+ ```
29
+
30
+ Every returned marker includes a stable machine-readable `code` alongside its localized `message`,
31
+ `level`, and `path`. Built-in failures may also include structured `details`. Custom validators can
32
+ return their own `code` and `details`; custom codes should be namespaced, for example
33
+ `custom.seo-title`.
34
+
35
+ The package does not apply mutations or decide whether a document may be edited or published.
36
+
37
+ ## Migrating from `sanity`
38
+
39
+ 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:
42
+
43
+ ```ts
44
+ import {validateDocument} from '@sanity/validation'
45
+
46
+ const markers = await validateDocument({document, workspace})
47
+ ```
48
+
49
+ Call sites that also import `ValidateDocumentOptions` from `sanity` should use
50
+ `ValidateDocumentWorkspaceOptions` for the workspace-shaped options.
51
+
52
+ Prefer the `{document, schema, client}` API for new code.
@@ -0,0 +1,96 @@
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";
2
+ import { Path, Rule as Rule$1, RuleClass, Schema, SchemaType, SchemaValidationValue, ValidationContext as ValidationContext$1, ValidationError, ValidationMarker } from "@sanity/types";
3
+ declare function getFallbackLocaleSource(): LocaleSource;
4
+ declare const validationLocaleStrings: {
5
+ readonly 'array.exact-length': 'Must have exactly {{wantedLength}} items';
6
+ readonly 'array.exact-length_blocks': 'Must have exactly {{wantedLength}} blocks';
7
+ readonly 'array.item-duplicate': "Can't be a duplicate";
8
+ readonly 'array.maximum-length': 'Must have at most {{maxLength}} items';
9
+ readonly 'array.maximum-length_blocks': 'Must have at most {{maxLength}} blocks';
10
+ readonly 'array.minimum-length': 'Must have at least {{minLength}} items';
11
+ readonly 'array.minimum-length_blocks': 'Must have at least {{minLength}} blocks';
12
+ readonly 'date.invalid-format': 'Must be a valid ISO-8601 formatted date string';
13
+ readonly 'date.maximum': 'Must be at or before {{maxDate}}';
14
+ readonly 'date.minimum': 'Must be at or after {{minDate}}';
15
+ readonly 'generic.incorrect-type': 'Expected type "{{expectedType}}", got "{{actualType}}"';
16
+ readonly 'generic.not-allowed': 'Value did not match any allowed values';
17
+ readonly 'generic.not-allowed_hint': 'Value "{{hint}}" did not match any allowed values';
18
+ readonly 'generic.required': 'Required';
19
+ readonly 'number.greater-than': 'Must be greater than {{threshold}}';
20
+ readonly 'number.less-than': 'Must be less than {{threshold}}';
21
+ readonly 'number.maximum': 'Must be lower than or equal to {{maxNumber}}';
22
+ readonly 'number.maximum-precision': 'Max precision is {{limit}}';
23
+ readonly 'number.minimum': 'Must be greater than or equal to {{minNumber}}';
24
+ readonly 'number.non-integer': 'Must be an integer';
25
+ readonly 'object.asset-required': 'Asset is required';
26
+ readonly 'object.asset-required_file': 'File is required';
27
+ readonly 'object.asset-required_image': 'Image is required';
28
+ readonly 'object.media-not-found': 'The asset could not be found in the Media Library';
29
+ readonly 'object.not-media-library-asset': 'Must be a reference to a Media Library asset';
30
+ readonly 'object.not-reference': 'Must be a reference to a document';
31
+ readonly 'object.reference-not-published': 'Referenced document must be published';
32
+ readonly 'slug.missing-current': 'Slug must have a value';
33
+ readonly 'slug.not-object': 'Slug must be an object';
34
+ readonly 'slug.not-unique': 'Slug is already in use';
35
+ readonly 'string.email': 'Must be a valid email address';
36
+ readonly 'string.exact-length': 'Must be exactly {{wantedLength}} characters long';
37
+ readonly 'string.lowercase': 'Must be all lowercase characters';
38
+ readonly 'string.maximum-length': 'Must be at most {{maxLength}} characters long';
39
+ readonly 'string.minimum-length': 'Must be at least {{minLength}} characters long';
40
+ readonly 'string.regex-does-not-match': 'Does not match "{{name}}"-pattern';
41
+ readonly 'string.regex-match': 'Should not match "{{name}}"-pattern';
42
+ readonly 'string.uppercase': 'Must be all uppercase characters';
43
+ readonly 'string.url.disallowed-scheme': 'Does not match allowed protocols/schemes';
44
+ readonly 'string.url.includes-credentials': 'Username/password not allowed';
45
+ readonly 'string.url.invalid': 'Not a valid URL';
46
+ readonly 'string.url.not-absolute': 'Relative URLs are not allowed';
47
+ readonly 'string.url.not-relative': 'Only relative URLs are allowed';
48
+ };
49
+ declare function inferFromSchema(schema: Schema): Schema;
50
+ declare function inferFromSchemaType(typeDef: SchemaType, _schema: Schema, _visited?: Set<SchemaType>): SchemaType;
51
+ declare function inferFromSchemaType(typeDef: SchemaType): SchemaType;
52
+ /**
53
+ * Checks if a validation function uses the context parameter.
54
+ *
55
+ * Functions with 2+ parameters like `(rule, context) => ...` need runtime context
56
+ * (e.g., `context.hidden`, `context.document`) and cannot be pre-evaluated at schema compile time.
57
+ *
58
+ * Functions with 1 parameter like `(rule) => rule.required()` don't need context
59
+ * and can be normalized immediately for better performance.
60
+ *
61
+ * @internal
62
+ */
63
+ declare function hasValidationContext(validation: SchemaValidationValue | undefined): boolean;
64
+ /**
65
+ * Concrete Rule implementation with validation logic.
66
+ * This extends the base Rule class from `@sanity/schema` and adds the validate method.
67
+ *
68
+ * Note: `RuleClass` and `Rule` are split to fit the current `@sanity/types`
69
+ * setup. Classes are a bit weird in the `@sanity/types` package because classes
70
+ * create an actual javascript class while simultaneously creating a type
71
+ * definition.
72
+ *
73
+ * This implicitly creates two types:
74
+ * 1. the instance type — `Rule` and
75
+ * 2. the static/class type - `RuleClass`
76
+ *
77
+ * The `RuleClass` type contains the static methods and the `Rule` instance
78
+ * contains the instance methods.
79
+ *
80
+ * This package exports the RuleClass as a value without implicitly exporting
81
+ * an instance definition. This should help reminder downstream users to import
82
+ * from the `@sanity/types` package.
83
+ *
84
+ * @internal
85
+ */
86
+ declare const Rule: RuleClass;
87
+ declare function convertToValidationMarker(validatorResult: true | true[] | string | string[] | ValidationError | ValidationError[], level: 'error' | 'warning' | 'info' | undefined, context: ValidationContext, fallback?: {
88
+ code: ValidationMarkerCode;
89
+ details?: Record<string, unknown>;
90
+ }): ValidationMarker[];
91
+ declare function getTypeChain(type: SchemaType | undefined, visited?: Set<SchemaType>): SchemaType[];
92
+ declare function normalizeValidationRules(typeDef: SchemaType | undefined, context?: ValidationContext$1): Rule$1[];
93
+ declare function pathToString(path?: Path | undefined): string;
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 };
96
+ //# sourceMappingURL=_internal.d.ts.map
@@ -0,0 +1,39 @@
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";
2
+ function inferFromSchemaType(typeDef) {
3
+ return traverse(typeDef, /* @__PURE__ */ new Set()), typeDef;
4
+ }
5
+ function traverse(typeDef, visited) {
6
+ if (!visited.has(typeDef)) {
7
+ if (visited.add(typeDef), hasValidationContext(typeDef.validation) || (typeDef.validation = normalizeValidationRules(typeDef)), "fields" in typeDef) for (let field of typeDef.fields) traverse(field.type, visited);
8
+ if ("of" in typeDef) for (let candidate of typeDef.of) traverse(candidate, visited);
9
+ if (typeDef.annotations) for (let annotation of typeDef.annotations) traverse(annotation, visited);
10
+ }
11
+ }
12
+ /**
13
+ * Checks if a validation function uses the context parameter.
14
+ *
15
+ * Functions with 2+ parameters like `(rule, context) => ...` need runtime context
16
+ * (e.g., `context.hidden`, `context.document`) and cannot be pre-evaluated at schema compile time.
17
+ *
18
+ * Functions with 1 parameter like `(rule) => rule.required()` don't need context
19
+ * and can be normalized immediately for better performance.
20
+ *
21
+ * @internal
22
+ */
23
+ function hasValidationContext(validation) {
24
+ if (!validation) return !1;
25
+ if (Array.isArray(validation)) return validation.some(hasValidationContext);
26
+ if (typeof validation != "function") return !1;
27
+ if (validation.length >= 2) return !0;
28
+ let signature = Function.prototype.toString.call(validation);
29
+ return /\(\s*\w+\s*,\s*\.\.\./.test(signature);
30
+ }
31
+ function inferFromSchema(schema) {
32
+ return schema.getLocalTypeNames().forEach((typeName) => {
33
+ let schemaType = schema.get(typeName);
34
+ schemaType && inferFromSchemaType(schemaType);
35
+ }), schema;
36
+ }
37
+ export { Rule, convertToValidationMarker, getFallbackLocaleSource, getTypeChain, hasValidationContext, inferFromSchema, inferFromSchemaType, normalizeValidationRules, pathToString, resolveTypeForArrayItem, typeString, validateDocumentInternal, validateDocumentObservable, validateItem, validationLocaleStrings };
38
+
39
+ //# sourceMappingURL=_internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_internal.js","names":[],"sources":["../src/inferFromSchemaType.ts","../src/inferFromSchema.ts"],"sourcesContent":["import {type Schema, type SchemaType, type SchemaValidationValue} from '@sanity/types'\n\nimport {normalizeValidationRules} from './util/normalizeValidationRules'\n\n// NOTE: this overload is for TS API compatibility with a previous implementation\nexport function inferFromSchemaType(\n typeDef: SchemaType,\n // these are intentionally unused\n _schema: Schema,\n _visited?: Set<SchemaType>,\n): SchemaType\n// note: this seemingly redundant overload is required\nexport function inferFromSchemaType(typeDef: SchemaType): SchemaType\nexport function inferFromSchemaType(typeDef: SchemaType): SchemaType {\n traverse(typeDef, new Set())\n return typeDef\n}\n\nfunction traverse(typeDef: SchemaType, visited: Set<SchemaType>) {\n if (visited.has(typeDef)) {\n return\n }\n\n visited.add(typeDef)\n\n const usesValidationContext = hasValidationContext(typeDef.validation)\n\n // Only normalize validation at schema-compile time when it doesn't rely on runtime context.\n // Context-aware validation functions must be evaluated during validation, where context exists.\n if (!usesValidationContext) {\n typeDef.validation = normalizeValidationRules(typeDef)\n }\n\n if ('fields' in typeDef) {\n for (const field of typeDef.fields) {\n traverse(field.type, visited)\n }\n }\n\n if ('of' in typeDef) {\n for (const candidate of typeDef.of) {\n traverse(candidate, visited)\n }\n }\n\n // @ts-expect-error TODO (eventually): `annotations` does not exist on the SchemaType yet\n if (typeDef.annotations) {\n // @ts-expect-error TODO (eventually): `annotations` does not exist on the SchemaType yet\n for (const annotation of typeDef.annotations) {\n traverse(annotation, visited)\n }\n }\n}\n\n/**\n * Checks if a validation function uses the context parameter.\n *\n * Functions with 2+ parameters like `(rule, context) => ...` need runtime context\n * (e.g., `context.hidden`, `context.document`) and cannot be pre-evaluated at schema compile time.\n *\n * Functions with 1 parameter like `(rule) => rule.required()` don't need context\n * and can be normalized immediately for better performance.\n *\n * @internal\n */\nexport function hasValidationContext(validation: SchemaValidationValue | undefined): boolean {\n if (!validation) return false\n if (Array.isArray(validation)) {\n return validation.some(hasValidationContext)\n }\n if (typeof validation !== 'function') return false\n\n // Check declared parameter count first (most common case)\n if (validation.length >= 2) return true\n\n // Function.length doesn't count rest parameters, so check the signature for patterns like\n // `(rule, ...args)` which would have length === 1 but still expects context\n const signature = Function.prototype.toString.call(validation)\n return /\\(\\s*\\w+\\s*,\\s*\\.\\.\\./.test(signature)\n}\n","import {type Schema} from '@sanity/types'\n\nimport {inferFromSchemaType} from './inferFromSchemaType'\n\n// Note: Mutates schema. Refactor when @sanity/schema supports middlewares\nexport function inferFromSchema(schema: Schema): Schema {\n const typeNames = schema.getLocalTypeNames()\n\n typeNames.forEach((typeName) => {\n const schemaType = schema.get(typeName)\n\n if (schemaType) {\n inferFromSchemaType(schemaType)\n }\n })\n\n return schema\n}\n"],"mappings":";AAaA,SAAgB,oBAAoB,SAAiC;CAEnE,OADA,SAAS,yBAAS,IAAI,IAAI,CAAC,GACpB;AACT;AAEA,SAAS,SAAS,SAAqB,SAA0B;CAC3D,aAAQ,IAAI,OAAO,GAcvB;MAVA,QAAQ,IAAI,OAAO,GAEW,qBAAqB,QAAQ,UAIlC,MACvB,QAAQ,aAAa,yBAAyB,OAAO,IAGnD,YAAY,SACd,KAAK,IAAM,SAAS,QAAQ,QAC1B,SAAS,MAAM,MAAM,OAAO;EAIhC,IAAI,QAAQ,SACV,KAAK,IAAM,aAAa,QAAQ,IAC9B,SAAS,WAAW,OAAO;EAK/B,IAAI,QAAQ,aAEV,KAAK,IAAM,cAAc,QAAQ,aAC/B,SAAS,YAAY,OAAO;CAdA;AAiBlC;;;;;;;;;;;;AAaA,SAAgB,qBAAqB,YAAwD;CAC3F,IAAI,CAAC,YAAY,OAAO;CACxB,IAAI,MAAM,QAAQ,UAAU,GAC1B,OAAO,WAAW,KAAK,oBAAoB;CAE7C,IAAI,OAAO,cAAe,YAAY,OAAO;CAG7C,IAAI,WAAW,UAAU,GAAG,OAAO;CAInC,IAAM,YAAY,SAAS,UAAU,SAAS,KAAK,UAAU;CAC7D,OAAO,wBAAwB,KAAK,SAAS;AAC/C;AC1EA,SAAgB,gBAAgB,QAAwB;CAWtD,OARA,OAFyB,kBAEjB,CAAC,CAAC,SAAS,aAAa;EAC9B,IAAM,aAAa,OAAO,IAAI,QAAQ;EAEtC,AAAI,cACF,oBAAoB,UAAU;CAElC,CAAC,GAEM;AACT"}
package/lib/index.d.ts ADDED
@@ -0,0 +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 };