@sanity/validation 3.14.4 → 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.
- package/LICENSE +1 -1
- package/README.md +52 -0
- package/lib/_internal.d.ts +96 -0
- package/lib/_internal.js +39 -0
- package/lib/_internal.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -1306
- package/lib/validateDocument-6pLTIHIn.d.ts +277 -0
- package/lib/validateDocument-Cq33kUmN.js +1127 -0
- package/lib/validateDocument-Cq33kUmN.js.map +1 -0
- package/package.json +53 -45
- package/lib/dts/src/index.d.ts +0 -50
- package/lib/index.cjs.mjs +0 -9
- package/lib/index.esm.js +0 -1286
- package/lib/index.esm.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/src/Rule.ts +0 -424
- package/src/ValidationError.ts +0 -32
- package/src/index.ts +0 -9
- package/src/inferFromSchema.ts +0 -19
- package/src/inferFromSchemaType.ts +0 -50
- package/src/util/convertToValidationMarker.ts +0 -84
- package/src/util/deepEquals.ts +0 -77
- package/src/util/escapeRegex.ts +0 -5
- package/src/util/normalizeValidationRules.test.ts +0 -170
- package/src/util/normalizeValidationRules.ts +0 -118
- package/src/util/pathToString.ts +0 -21
- package/src/util/requestIdleCallback.ts +0 -31
- package/src/util/typeString.test.ts +0 -27
- package/src/util/typeString.ts +0 -23
- package/src/validateDocument.test.ts +0 -703
- package/src/validateDocument.ts +0 -240
- package/src/validators/arrayValidator.ts +0 -100
- package/src/validators/booleanValidator.ts +0 -16
- package/src/validators/dateValidator.ts +0 -113
- package/src/validators/genericValidator.ts +0 -117
- package/src/validators/numberValidator.ts +0 -66
- package/src/validators/objectValidator.ts +0 -64
- package/src/validators/slugValidator.ts +0 -117
- package/src/validators/stringValidator.ts +0 -120
package/LICENSE
CHANGED
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
|
package/lib/_internal.js
ADDED
|
@@ -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 };
|