@sanity/validation 2.30.1-purple-unicorn.964 → 3.0.0-dev-preview.0

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 (48) hide show
  1. package/lib/dts/src/Rule.js +317 -312
  2. package/lib/dts/src/ValidationError.js +16 -16
  3. package/lib/dts/src/index.js +7 -7
  4. package/lib/dts/src/inferFromSchema.js +11 -11
  5. package/lib/dts/src/inferFromSchemaType.js +24 -24
  6. package/lib/dts/src/util/convertToValidationMarker.js +44 -53
  7. package/lib/dts/src/util/deepEquals.js +50 -49
  8. package/lib/dts/src/util/escapeRegex.js +4 -4
  9. package/lib/dts/src/util/normalizeValidationRules.js +87 -78
  10. package/lib/dts/src/util/normalizeValidationRules.test.d.ts +2 -2
  11. package/lib/dts/src/util/normalizeValidationRules.test.js +149 -149
  12. package/lib/dts/src/util/pathToString.js +16 -16
  13. package/lib/dts/src/util/typeString.js +17 -14
  14. package/lib/dts/src/util/typeString.test.d.ts +2 -2
  15. package/lib/dts/src/util/typeString.test.js +23 -24
  16. package/lib/dts/src/validateDocument.js +132 -157
  17. package/lib/dts/src/validateDocument.test.d.ts +2 -2
  18. package/lib/dts/src/validateDocument.test.js +664 -678
  19. package/lib/dts/src/validators/arrayValidator.js +75 -75
  20. package/lib/dts/src/validators/booleanValidator.js +11 -11
  21. package/lib/dts/src/validators/dateValidator.js +74 -68
  22. package/lib/dts/src/validators/genericValidator.js +89 -87
  23. package/lib/dts/src/validators/numberValidator.js +46 -48
  24. package/lib/dts/src/validators/objectValidator.js +47 -47
  25. package/lib/dts/src/validators/slugValidator.js +68 -74
  26. package/lib/dts/src/validators/stringValidator.js +93 -93
  27. package/lib/dts/test/array.test.d.ts +2 -2
  28. package/lib/dts/test/array.test.js +54 -78
  29. package/lib/dts/test/children.test.d.ts +2 -2
  30. package/lib/dts/test/children.test.js +69 -87
  31. package/lib/dts/test/createSchema.d.ts +6 -3
  32. package/lib/dts/test/createSchema.js +17 -17
  33. package/lib/dts/test/generics.test.d.ts +2 -2
  34. package/lib/dts/test/generics.test.js +59 -59
  35. package/lib/dts/test/infer.test.d.ts +2 -2
  36. package/lib/dts/test/infer.test.js +236 -285
  37. package/lib/dts/test/mocks/mockSanityClient.d.ts +4 -5
  38. package/lib/dts/test/mocks/mockSanityClient.d.ts.map +1 -1
  39. package/lib/dts/test/mocks/mockSanityClient.js +6 -6
  40. package/lib/dts/test/nullExport.d.ts +3 -3
  41. package/lib/dts/test/nullExport.js +2 -2
  42. package/lib/dts/test/numbers.test.d.ts +2 -2
  43. package/lib/dts/test/numbers.test.js +56 -62
  44. package/lib/dts/test/strings.test.d.ts +2 -2
  45. package/lib/dts/test/strings.test.js +99 -150
  46. package/lib/dts/tsconfig.lib.tsbuildinfo +1 -1
  47. package/lib/dts/tsconfig.tsbuildinfo +1 -1
  48. package/package.json +4 -4
@@ -1,167 +1,142 @@
1
- import {
2
- isKeyedObject,
3
- isTypedObject,
4
- isBlock,
5
- isBlockSchemaType,
6
- isSpanSchemaType,
7
- } from '@sanity/types'
8
- import {uniqBy} from 'lodash'
9
- import typeString from './util/typeString'
10
- import ValidationErrorClass from './ValidationError'
11
- import normalizeValidationRules from './util/normalizeValidationRules'
12
- const isRecord = (maybeRecord) =>
13
- typeof maybeRecord === 'object' && maybeRecord !== null && !Array.isArray(maybeRecord)
14
- const isNonNullable = (value) => value !== null && value !== undefined
1
+ import { isKeyedObject, isTypedObject, isBlock, isBlockSchemaType, isSpanSchemaType, } from '@sanity/types';
2
+ import { uniqBy } from 'lodash';
3
+ import typeString from './util/typeString';
4
+ import ValidationErrorClass from './ValidationError';
5
+ import normalizeValidationRules from './util/normalizeValidationRules';
6
+ const isRecord = (maybeRecord) => typeof maybeRecord === 'object' && maybeRecord !== null && !Array.isArray(maybeRecord);
7
+ const isNonNullable = (value) => value !== null && value !== undefined;
15
8
  /**
16
9
  * @internal
17
10
  */
18
11
  export function resolveTypeForArrayItem(item, candidates) {
19
- // if there is only one type available, assume that it's the correct one
20
- if (candidates.length === 1) return candidates[0]
21
- const itemType = isTypedObject(item) && item._type
22
- const primitive =
23
- item === undefined || item === null || (!itemType && typeString(item).toLowerCase())
24
- if (primitive && primitive !== 'object') {
25
- return candidates.find((candidate) => candidate.jsonType === primitive)
26
- }
27
- return (
28
- candidates.find((candidate) => candidate.type?.name === itemType) ||
29
- candidates.find((candidate) => candidate.name === itemType) ||
30
- candidates.find((candidate) => candidate.name === 'object' && primitive === 'object')
31
- )
12
+ // if there is only one type available, assume that it's the correct one
13
+ if (candidates.length === 1)
14
+ return candidates[0];
15
+ const itemType = isTypedObject(item) && item._type;
16
+ const primitive = item === undefined || item === null || (!itemType && typeString(item).toLowerCase());
17
+ if (primitive && primitive !== 'object') {
18
+ return candidates.find((candidate) => candidate.jsonType === primitive);
19
+ }
20
+ return (candidates.find((candidate) => candidate.type?.name === itemType) ||
21
+ candidates.find((candidate) => candidate.name === itemType) ||
22
+ candidates.find((candidate) => candidate.name === 'object' && primitive === 'object'));
32
23
  }
33
24
  export default async function validateDocument(client, doc, schema, context) {
34
- const documentType = schema.get(doc._type)
35
- if (!documentType) {
36
- console.warn('Schema type for object type "%s" not found, skipping validation', doc._type)
37
- return []
38
- }
39
- try {
40
- return await validateItem({
41
- client,
42
- parent: undefined,
43
- value: doc,
44
- path: [],
45
- document: doc,
46
- type: documentType,
47
- getDocumentExists: context?.getDocumentExists,
48
- })
49
- } catch (err) {
50
- console.error(err)
51
- return [
52
- {
53
- level: 'error',
54
- path: [],
55
- item: new ValidationErrorClass(err?.message),
56
- },
57
- ]
58
- }
25
+ const documentType = schema.get(doc._type);
26
+ if (!documentType) {
27
+ console.warn('Schema type for object type "%s" not found, skipping validation', doc._type);
28
+ return [];
29
+ }
30
+ try {
31
+ return await validateItem({
32
+ client,
33
+ parent: undefined,
34
+ value: doc,
35
+ path: [],
36
+ document: doc,
37
+ type: documentType,
38
+ getDocumentExists: context?.getDocumentExists,
39
+ });
40
+ }
41
+ catch (err) {
42
+ console.error(err);
43
+ return [
44
+ {
45
+ level: 'error',
46
+ path: [],
47
+ item: new ValidationErrorClass(err?.message),
48
+ },
49
+ ];
50
+ }
59
51
  }
60
- export async function validateItem({value, type, path = [], parent, ...restOfContext}) {
61
- const rules = normalizeValidationRules(type)
62
- // run validation for the current value
63
- const selfChecks = rules.map((rule) =>
64
- rule.validate(value, {
65
- ...restOfContext,
66
- parent,
67
- path,
68
- type,
69
- })
70
- )
71
- // run validation for nested values (conditionally)
72
- let nestedChecks = []
73
- const selfIsRequired = rules.some((rule) => rule.isRequired())
74
- const shouldRunNestedObjectValidation =
52
+ export async function validateItem({ value, type, path = [], parent, ...restOfContext }) {
53
+ const rules = normalizeValidationRules(type);
54
+ // run validation for the current value
55
+ const selfChecks = rules.map((rule) => rule.validate(value, {
56
+ ...restOfContext,
57
+ parent,
58
+ path,
59
+ type,
60
+ }));
61
+ // run validation for nested values (conditionally)
62
+ let nestedChecks = [];
63
+ const selfIsRequired = rules.some((rule) => rule.isRequired());
64
+ const shouldRunNestedObjectValidation =
75
65
  // run nested validation for objects
76
66
  type?.jsonType === 'object' &&
77
- // if the value is truthy
78
- (!!value || // or
79
- // (the value is null or undefined) and the top-level value is required
80
- ((value === null || value === undefined) && selfIsRequired))
81
- if (shouldRunNestedObjectValidation) {
82
- const fieldTypes = type.fields.reduce((acc, field) => {
83
- acc[field.name] = field.type
84
- return acc
85
- }, {})
86
- // Validation for rules set at the object level with `Rule.fields({/* ... */})`
87
- nestedChecks = nestedChecks.concat(
88
- rules
89
- .map((rule) => rule._fieldRules)
90
- .filter(isNonNullable)
91
- .flatMap((fieldResults) => Object.entries(fieldResults))
92
- .flatMap(([name, validation]) => {
93
- const fieldType = fieldTypes[name]
94
- return normalizeValidationRules({...fieldType, validation}).map((subRule) => {
95
- const nestedValue = isRecord(value) ? value[name] : undefined
96
- return subRule.validate(nestedValue, {
97
- ...restOfContext,
98
- parent: value,
99
- path: path.concat(name),
100
- type: fieldType,
101
- })
102
- })
103
- })
104
- )
105
- // Validation from each field's schema `validation: Rule => {/* ... */}` function
106
- nestedChecks = nestedChecks.concat(
107
- type.fields.map((field) =>
108
- validateItem({
109
- ...restOfContext,
110
- parent: value,
111
- value: isRecord(value) ? value[field.name] : undefined,
112
- path: path.concat(field.name),
113
- type: field.type,
114
- })
115
- )
116
- )
117
- }
118
- // note: unlike objects, arrays should not run nested validation for undefined
119
- // values because we won't have a valid path to put a marker (i.e. missing the
120
- // key or index in the path) and the downstream form builder won't have a
121
- // valid target component
122
- const shouldRunNestedValidationForArrays = type?.jsonType === 'array' && Array.isArray(value)
123
- if (shouldRunNestedValidationForArrays) {
124
- nestedChecks = nestedChecks.concat(
125
- value.map((item) =>
126
- validateItem({
127
- ...restOfContext,
128
- parent: value,
129
- value: item,
130
- path: path.concat(isKeyedObject(item) ? {_key: item._key} : value.indexOf(item)),
131
- type: resolveTypeForArrayItem(item, type.of),
132
- })
133
- )
134
- )
135
- }
136
- // markDefs also do no run nested validation if the parent object is undefined
137
- // for a similar reason to arrays
138
- const shouldRunNestedValidationForMarkDefs =
139
- isBlock(value) && value.markDefs.length && isBlockSchemaType(type)
140
- if (shouldRunNestedValidationForMarkDefs) {
141
- const [spanChildrenField] = type.fields
142
- const spanType = spanChildrenField.type.of.find(isSpanSchemaType)
143
- const annotations = (spanType?.annotations || []).reduce((map, annotationType) => {
144
- map.set(annotationType.name, annotationType)
145
- return map
146
- }, new Map())
147
- nestedChecks = nestedChecks.concat(
148
- value.markDefs.map((markDef) =>
149
- validateItem({
150
- ...restOfContext,
151
- parent: value,
152
- value: markDef,
153
- path: path.concat(['markDefs', {_key: markDef._key}]),
154
- type: annotations.get(markDef._type),
155
- })
156
- )
157
- )
158
- }
159
- const results = (await Promise.all([...selfChecks, ...nestedChecks])).flat()
160
- // run `uniqBy` if `_fieldRules` are present because they can
161
- // cause repeat markers
162
- if (rules.some((rule) => rule._fieldRules)) {
163
- return uniqBy(results, (rule) => JSON.stringify(rule))
164
- }
165
- return results
67
+ // if the value is truthy
68
+ (!!value || // or
69
+ // (the value is null or undefined) and the top-level value is required
70
+ ((value === null || value === undefined) && selfIsRequired));
71
+ if (shouldRunNestedObjectValidation) {
72
+ const fieldTypes = type.fields.reduce((acc, field) => {
73
+ acc[field.name] = field.type;
74
+ return acc;
75
+ }, {});
76
+ // Validation for rules set at the object level with `Rule.fields({/* ... */})`
77
+ nestedChecks = nestedChecks.concat(rules
78
+ .map((rule) => rule._fieldRules)
79
+ .filter(isNonNullable)
80
+ .flatMap((fieldResults) => Object.entries(fieldResults))
81
+ .flatMap(([name, validation]) => {
82
+ const fieldType = fieldTypes[name];
83
+ return normalizeValidationRules({ ...fieldType, validation }).map((subRule) => {
84
+ const nestedValue = isRecord(value) ? value[name] : undefined;
85
+ return subRule.validate(nestedValue, {
86
+ ...restOfContext,
87
+ parent: value,
88
+ path: path.concat(name),
89
+ type: fieldType,
90
+ });
91
+ });
92
+ }));
93
+ // Validation from each field's schema `validation: Rule => {/* ... */}` function
94
+ nestedChecks = nestedChecks.concat(type.fields.map((field) => validateItem({
95
+ ...restOfContext,
96
+ parent: value,
97
+ value: isRecord(value) ? value[field.name] : undefined,
98
+ path: path.concat(field.name),
99
+ type: field.type,
100
+ })));
101
+ }
102
+ // note: unlike objects, arrays should not run nested validation for undefined
103
+ // values because we won't have a valid path to put a marker (i.e. missing the
104
+ // key or index in the path) and the downstream form builder won't have a
105
+ // valid target component
106
+ const shouldRunNestedValidationForArrays = type?.jsonType === 'array' && Array.isArray(value);
107
+ if (shouldRunNestedValidationForArrays) {
108
+ nestedChecks = nestedChecks.concat(value.map((item) => validateItem({
109
+ ...restOfContext,
110
+ parent: value,
111
+ value: item,
112
+ path: path.concat(isKeyedObject(item) ? { _key: item._key } : value.indexOf(item)),
113
+ type: resolveTypeForArrayItem(item, type.of),
114
+ })));
115
+ }
116
+ // markDefs also do no run nested validation if the parent object is undefined
117
+ // for a similar reason to arrays
118
+ const shouldRunNestedValidationForMarkDefs = isBlock(value) && value.markDefs.length && isBlockSchemaType(type);
119
+ if (shouldRunNestedValidationForMarkDefs) {
120
+ const [spanChildrenField] = type.fields;
121
+ const spanType = spanChildrenField.type.of.find(isSpanSchemaType);
122
+ const annotations = (spanType?.annotations || []).reduce((map, annotationType) => {
123
+ map.set(annotationType.name, annotationType);
124
+ return map;
125
+ }, new Map());
126
+ nestedChecks = nestedChecks.concat(value.markDefs.map((markDef) => validateItem({
127
+ ...restOfContext,
128
+ parent: value,
129
+ value: markDef,
130
+ path: path.concat(['markDefs', { _key: markDef._key }]),
131
+ type: annotations.get(markDef._type),
132
+ })));
133
+ }
134
+ const results = (await Promise.all([...selfChecks, ...nestedChecks])).flat();
135
+ // run `uniqBy` if `_fieldRules` are present because they can
136
+ // cause repeat markers
137
+ if (rules.some((rule) => rule._fieldRules)) {
138
+ return uniqBy(results, (rule) => JSON.stringify(rule));
139
+ }
140
+ return results;
166
141
  }
167
- //# sourceMappingURL=validateDocument.js.map
142
+ //# sourceMappingURL=validateDocument.js.map
@@ -1,2 +1,2 @@
1
- export {}
2
- //# sourceMappingURL=validateDocument.test.d.ts.map
1
+ export {};
2
+ //# sourceMappingURL=validateDocument.test.d.ts.map