@sanity/validation 2.30.0 → 2.30.1-dev-preview.1013

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 (191) hide show
  1. package/{dist/dts → lib/dts/src}/Rule.d.ts +3 -3
  2. package/lib/dts/src/Rule.d.ts.map +1 -0
  3. package/lib/dts/src/Rule.js +336 -0
  4. package/lib/dts/src/Rule.js.map +1 -0
  5. package/{dist/dts → lib/dts/src}/ValidationError.d.ts +3 -3
  6. package/lib/dts/src/ValidationError.d.ts.map +1 -0
  7. package/lib/dts/src/ValidationError.js +18 -0
  8. package/lib/dts/src/ValidationError.js.map +1 -0
  9. package/{dist/dts → lib/dts/src}/index.d.ts +12 -12
  10. package/lib/dts/src/index.d.ts.map +1 -0
  11. package/lib/dts/src/index.js +7 -0
  12. package/lib/dts/src/index.js.map +1 -0
  13. package/{dist/dts → lib/dts/src}/inferFromSchema.d.ts +3 -3
  14. package/lib/dts/src/inferFromSchema.d.ts.map +1 -0
  15. package/lib/dts/src/inferFromSchema.js +14 -0
  16. package/lib/dts/src/inferFromSchema.js.map +1 -0
  17. package/{dist/dts → lib/dts/src}/inferFromSchemaType.d.ts +4 -4
  18. package/lib/dts/src/inferFromSchemaType.d.ts.map +1 -0
  19. package/lib/dts/src/inferFromSchemaType.js +33 -0
  20. package/lib/dts/src/inferFromSchemaType.js.map +1 -0
  21. package/{dist/dts → lib/dts/src}/util/convertToValidationMarker.d.ts +5 -5
  22. package/lib/dts/src/util/convertToValidationMarker.d.ts.map +1 -0
  23. package/lib/dts/src/util/convertToValidationMarker.js +51 -0
  24. package/lib/dts/src/util/convertToValidationMarker.js.map +1 -0
  25. package/{dist/dts → lib/dts/src}/util/deepEquals.d.ts +5 -5
  26. package/lib/dts/src/util/deepEquals.d.ts.map +1 -0
  27. package/lib/dts/src/util/deepEquals.js +65 -0
  28. package/lib/dts/src/util/deepEquals.js.map +1 -0
  29. package/{dist/dts → lib/dts/src}/util/escapeRegex.d.ts +2 -2
  30. package/lib/dts/src/util/escapeRegex.d.ts.map +1 -0
  31. package/lib/dts/src/util/escapeRegex.js +6 -0
  32. package/lib/dts/src/util/escapeRegex.js.map +1 -0
  33. package/{dist/dts → lib/dts/src}/util/normalizeValidationRules.d.ts +5 -5
  34. package/lib/dts/src/util/normalizeValidationRules.d.ts.map +1 -0
  35. package/lib/dts/src/util/normalizeValidationRules.js +104 -0
  36. package/lib/dts/src/util/normalizeValidationRules.js.map +1 -0
  37. package/{dist/dts → lib/dts/src}/util/normalizeValidationRules.test.d.ts +0 -0
  38. package/lib/dts/src/util/normalizeValidationRules.test.d.ts.map +1 -0
  39. package/lib/dts/src/util/normalizeValidationRules.test.js +150 -0
  40. package/lib/dts/src/util/normalizeValidationRules.test.js.map +1 -0
  41. package/{dist/dts → lib/dts/src}/util/pathToString.d.ts +2 -2
  42. package/lib/dts/src/util/pathToString.d.ts.map +1 -0
  43. package/lib/dts/src/util/pathToString.js +18 -0
  44. package/lib/dts/src/util/pathToString.js.map +1 -0
  45. package/{dist/dts → lib/dts/src}/util/typeString.d.ts +1 -1
  46. package/lib/dts/src/util/typeString.d.ts.map +1 -0
  47. package/lib/dts/src/util/typeString.js +23 -0
  48. package/lib/dts/src/util/typeString.js.map +1 -0
  49. package/{dist/dts → lib/dts/src}/util/typeString.test.d.ts +0 -0
  50. package/lib/dts/src/util/typeString.test.d.ts.map +1 -0
  51. package/lib/dts/src/util/typeString.test.js +24 -0
  52. package/lib/dts/src/util/typeString.test.js.map +1 -0
  53. package/{dist/dts → lib/dts/src}/validateDocument.d.ts +22 -21
  54. package/lib/dts/src/validateDocument.d.ts.map +1 -0
  55. package/lib/dts/src/validateDocument.js +142 -0
  56. package/lib/dts/src/validateDocument.js.map +1 -0
  57. package/{dist/dts → lib/dts/src}/validateDocument.test.d.ts +0 -0
  58. package/lib/dts/src/validateDocument.test.d.ts.map +1 -0
  59. package/lib/dts/src/validateDocument.test.js +703 -0
  60. package/lib/dts/src/validateDocument.test.js.map +1 -0
  61. package/{dist/dts → lib/dts/src}/validators/arrayValidator.d.ts +3 -3
  62. package/lib/dts/src/validators/arrayValidator.d.ts.map +1 -0
  63. package/lib/dts/src/validators/arrayValidator.js +79 -0
  64. package/lib/dts/src/validators/arrayValidator.js.map +1 -0
  65. package/{dist/dts → lib/dts/src}/validators/booleanValidator.d.ts +3 -3
  66. package/lib/dts/src/validators/booleanValidator.d.ts.map +1 -0
  67. package/lib/dts/src/validators/booleanValidator.js +12 -0
  68. package/lib/dts/src/validators/booleanValidator.js.map +1 -0
  69. package/{dist/dts → lib/dts/src}/validators/dateValidator.d.ts +4 -4
  70. package/lib/dts/src/validators/dateValidator.d.ts.map +1 -0
  71. package/lib/dts/src/validators/dateValidator.js +83 -0
  72. package/lib/dts/src/validators/dateValidator.js.map +1 -0
  73. package/{dist/dts → lib/dts/src}/validators/genericValidator.d.ts +3 -3
  74. package/lib/dts/src/validators/genericValidator.d.ts.map +1 -0
  75. package/lib/dts/src/validators/genericValidator.js +93 -0
  76. package/lib/dts/src/validators/genericValidator.js.map +1 -0
  77. package/{dist/dts → lib/dts/src}/validators/numberValidator.d.ts +3 -3
  78. package/lib/dts/src/validators/numberValidator.d.ts.map +1 -0
  79. package/lib/dts/src/validators/numberValidator.js +47 -0
  80. package/lib/dts/src/validators/numberValidator.js.map +1 -0
  81. package/{dist/dts → lib/dts/src}/validators/objectValidator.d.ts +3 -3
  82. package/lib/dts/src/validators/objectValidator.d.ts.map +1 -0
  83. package/lib/dts/src/validators/objectValidator.js +48 -0
  84. package/lib/dts/src/validators/objectValidator.js.map +1 -0
  85. package/{dist/dts → lib/dts/src}/validators/slugValidator.d.ts +8 -8
  86. package/lib/dts/src/validators/slugValidator.d.ts.map +1 -0
  87. package/lib/dts/src/validators/slugValidator.js +83 -0
  88. package/lib/dts/src/validators/slugValidator.js.map +1 -0
  89. package/{dist/dts → lib/dts/src}/validators/stringValidator.d.ts +3 -3
  90. package/lib/dts/src/validators/stringValidator.d.ts.map +1 -0
  91. package/lib/dts/src/validators/stringValidator.js +94 -0
  92. package/lib/dts/src/validators/stringValidator.js.map +1 -0
  93. package/lib/dts/test/array.test.d.ts +2 -0
  94. package/lib/dts/test/array.test.d.ts.map +1 -0
  95. package/lib/dts/test/array.test.js +55 -0
  96. package/lib/dts/test/array.test.js.map +1 -0
  97. package/lib/dts/test/children.test.d.ts +2 -0
  98. package/lib/dts/test/children.test.d.ts.map +1 -0
  99. package/lib/dts/test/children.test.js +70 -0
  100. package/lib/dts/test/children.test.js.map +1 -0
  101. package/lib/dts/test/createSchema.d.ts +6 -0
  102. package/lib/dts/test/createSchema.d.ts.map +1 -0
  103. package/lib/dts/test/createSchema.js +19 -0
  104. package/lib/dts/test/createSchema.js.map +1 -0
  105. package/lib/dts/test/generics.test.d.ts +2 -0
  106. package/lib/dts/test/generics.test.d.ts.map +1 -0
  107. package/lib/dts/test/generics.test.js +60 -0
  108. package/lib/dts/test/generics.test.js.map +1 -0
  109. package/lib/dts/test/infer.test.d.ts +2 -0
  110. package/lib/dts/test/infer.test.d.ts.map +1 -0
  111. package/lib/dts/test/infer.test.js +243 -0
  112. package/lib/dts/test/infer.test.js.map +1 -0
  113. package/lib/dts/test/mocks/mockSanityClient.d.ts +6 -0
  114. package/lib/dts/test/mocks/mockSanityClient.d.ts.map +1 -0
  115. package/lib/dts/test/mocks/mockSanityClient.js +8 -0
  116. package/lib/dts/test/mocks/mockSanityClient.js.map +1 -0
  117. package/lib/dts/test/nullExport.d.ts +3 -0
  118. package/lib/dts/test/nullExport.d.ts.map +1 -0
  119. package/lib/dts/test/nullExport.js +4 -0
  120. package/lib/dts/test/nullExport.js.map +1 -0
  121. package/lib/dts/test/numbers.test.d.ts +2 -0
  122. package/lib/dts/test/numbers.test.d.ts.map +1 -0
  123. package/lib/dts/test/numbers.test.js +57 -0
  124. package/lib/dts/test/numbers.test.js.map +1 -0
  125. package/lib/dts/test/strings.test.d.ts +2 -0
  126. package/lib/dts/test/strings.test.d.ts.map +1 -0
  127. package/lib/dts/test/strings.test.js +100 -0
  128. package/lib/dts/test/strings.test.js.map +1 -0
  129. package/lib/dts/tsconfig.lib.tsbuildinfo +1 -0
  130. package/lib/dts/tsconfig.tsbuildinfo +1 -0
  131. package/lib/index.cjs +1318 -0
  132. package/lib/index.cjs.map +1 -0
  133. package/lib/index.js +1308 -48
  134. package/lib/index.js.map +1 -0
  135. package/package.json +21 -11
  136. package/src/Rule.ts +6 -2
  137. package/src/inferFromSchema.ts +7 -1
  138. package/src/util/convertToValidationMarker.ts +5 -3
  139. package/src/validateDocument.test.ts +22 -23
  140. package/src/validateDocument.ts +3 -1
  141. package/src/validators/dateValidator.ts +4 -4
  142. package/src/validators/slugValidator.ts +3 -3
  143. package/src/validators/stringValidator.ts +2 -1
  144. package/dist/dts/Rule.d.ts.map +0 -1
  145. package/dist/dts/ValidationError.d.ts.map +0 -1
  146. package/dist/dts/getClient.d.ts +0 -3
  147. package/dist/dts/getClient.d.ts.map +0 -1
  148. package/dist/dts/index.d.ts.map +0 -1
  149. package/dist/dts/inferFromSchema.d.ts.map +0 -1
  150. package/dist/dts/inferFromSchemaType.d.ts.map +0 -1
  151. package/dist/dts/util/convertToValidationMarker.d.ts.map +0 -1
  152. package/dist/dts/util/deepEquals.d.ts.map +0 -1
  153. package/dist/dts/util/escapeRegex.d.ts.map +0 -1
  154. package/dist/dts/util/normalizeValidationRules.d.ts.map +0 -1
  155. package/dist/dts/util/normalizeValidationRules.test.d.ts.map +0 -1
  156. package/dist/dts/util/pathToString.d.ts.map +0 -1
  157. package/dist/dts/util/typeString.d.ts.map +0 -1
  158. package/dist/dts/util/typeString.test.d.ts.map +0 -1
  159. package/dist/dts/validateDocument.d.ts.map +0 -1
  160. package/dist/dts/validateDocument.test.d.ts.map +0 -1
  161. package/dist/dts/validators/arrayValidator.d.ts.map +0 -1
  162. package/dist/dts/validators/booleanValidator.d.ts.map +0 -1
  163. package/dist/dts/validators/dateValidator.d.ts.map +0 -1
  164. package/dist/dts/validators/genericValidator.d.ts.map +0 -1
  165. package/dist/dts/validators/numberValidator.d.ts.map +0 -1
  166. package/dist/dts/validators/objectValidator.d.ts.map +0 -1
  167. package/dist/dts/validators/slugValidator.d.ts.map +0 -1
  168. package/dist/dts/validators/stringValidator.d.ts.map +0 -1
  169. package/jest.config.js +0 -5
  170. package/lib/Rule.js +0 -491
  171. package/lib/ValidationError.js +0 -39
  172. package/lib/getClient.js +0 -20
  173. package/lib/inferFromSchema.js +0 -22
  174. package/lib/inferFromSchemaType.js +0 -86
  175. package/lib/util/convertToValidationMarker.js +0 -65
  176. package/lib/util/deepEquals.js +0 -87
  177. package/lib/util/escapeRegex.js +0 -14
  178. package/lib/util/normalizeValidationRules.js +0 -115
  179. package/lib/util/pathToString.js +0 -30
  180. package/lib/util/typeString.js +0 -29
  181. package/lib/validateDocument.js +0 -231
  182. package/lib/validators/arrayValidator.js +0 -123
  183. package/lib/validators/booleanValidator.js +0 -29
  184. package/lib/validators/dateValidator.js +0 -120
  185. package/lib/validators/genericValidator.js +0 -135
  186. package/lib/validators/numberValidator.js +0 -70
  187. package/lib/validators/objectValidator.js +0 -93
  188. package/lib/validators/slugValidator.js +0 -133
  189. package/lib/validators/stringValidator.js +0 -131
  190. package/src/getClient.ts +0 -13
  191. package/tsconfig.json +0 -10
@@ -0,0 +1,703 @@
1
+ import { createSchema } from '../test/createSchema';
2
+ import { createMockSanityClient } from '../test/mocks/mockSanityClient';
3
+ import validateDocument, { resolveTypeForArrayItem, validateItem } from './validateDocument';
4
+ import { convertToValidationMarker } from './util/convertToValidationMarker';
5
+ jest.mock('./util/convertToValidationMarker', () => {
6
+ return {
7
+ convertToValidationMarker: jest.fn(jest.requireActual('./util/convertToValidationMarker').convertToValidationMarker),
8
+ };
9
+ });
10
+ beforeEach(() => {
11
+ ;
12
+ convertToValidationMarker.mockClear();
13
+ });
14
+ // mock client
15
+ const client = createMockSanityClient();
16
+ describe('resolveTypeForArrayItem', () => {
17
+ const schema = createSchema({
18
+ types: [
19
+ {
20
+ name: 'foo',
21
+ type: 'object',
22
+ fields: [{ name: 'title', type: 'number' }],
23
+ },
24
+ {
25
+ name: 'bar',
26
+ type: 'object',
27
+ fields: [{ name: 'title', type: 'string' }],
28
+ },
29
+ ],
30
+ });
31
+ const fooType = schema.get('foo');
32
+ const barType = schema.get('bar');
33
+ it('finds a matching schema type for an array item value given a list of candidate types', () => {
34
+ const resolved = resolveTypeForArrayItem({
35
+ _type: 'bar',
36
+ _key: 'exampleKey',
37
+ title: 5,
38
+ }, [fooType, barType]);
39
+ expect(resolved).toBe(barType);
40
+ });
41
+ it('assumes the type if there is only one possible candidate', () => {
42
+ const resolved = resolveTypeForArrayItem({
43
+ // notice no _type
44
+ _key: 'exampleKey',
45
+ title: 5,
46
+ }, [fooType]);
47
+ expect(resolved).toBe(fooType);
48
+ });
49
+ });
50
+ describe('validateDocument', () => {
51
+ it('takes in a document + a compiled schema and returns a list of validation markers', async () => {
52
+ const schema = createSchema({
53
+ types: [
54
+ {
55
+ name: 'simpleDoc',
56
+ type: 'document',
57
+ title: 'Simple Document',
58
+ fields: [
59
+ {
60
+ name: 'title',
61
+ type: 'string',
62
+ validation: (rule) => rule.required(),
63
+ },
64
+ ],
65
+ },
66
+ ],
67
+ });
68
+ const document = {
69
+ _id: 'testId',
70
+ _createdAt: '2021-08-27T14:48:51.650Z',
71
+ _rev: 'exampleRev',
72
+ _type: 'simpleDoc',
73
+ _updatedAt: '2021-08-27T14:48:51.650Z',
74
+ title: null,
75
+ };
76
+ const result = await validateDocument(client, document, schema);
77
+ expect(result).toMatchObject([
78
+ {
79
+ level: 'error',
80
+ item: {
81
+ message: 'Expected type "String", got "null"',
82
+ paths: [],
83
+ },
84
+ path: ['title'],
85
+ },
86
+ {
87
+ level: 'error',
88
+ item: {
89
+ message: 'Required',
90
+ paths: [],
91
+ },
92
+ path: ['title'],
93
+ },
94
+ ]);
95
+ });
96
+ });
97
+ describe('validateItem', () => {
98
+ it("runs nested validation on an undefined value for object types if it's required", async () => {
99
+ const validation = (rule) => [
100
+ rule.required().error('This is required!'),
101
+ rule.max(160).warning('Too long!'),
102
+ ];
103
+ const schema = createSchema({
104
+ types: [
105
+ {
106
+ name: 'testObj',
107
+ type: 'object',
108
+ title: 'Test Object',
109
+ fields: [
110
+ { name: 'registeredString', type: 'registeredString' },
111
+ { name: 'inlineString', type: 'string', validation },
112
+ {
113
+ name: 'registeredObject',
114
+ type: 'registeredObjectField',
115
+ validation: (rule) => rule.required(),
116
+ },
117
+ {
118
+ name: 'inlineObject',
119
+ type: 'object',
120
+ fields: [{ name: 'foo', type: 'string', validation }],
121
+ validation: (rule) => rule.required(),
122
+ },
123
+ {
124
+ name: 'notRequiredRegisteredObject',
125
+ type: 'registeredObjectField',
126
+ },
127
+ {
128
+ name: 'notRequiredInlineObject',
129
+ type: 'object',
130
+ fields: [{ name: 'foo', type: 'string', validation }],
131
+ },
132
+ ],
133
+ },
134
+ { name: 'registeredString', title: 'Registered String', type: 'string', validation },
135
+ {
136
+ title: 'Registered Object Field',
137
+ name: 'registeredObjectField',
138
+ type: 'object',
139
+ fields: [{ name: 'foo', type: 'string', validation }],
140
+ },
141
+ ],
142
+ });
143
+ // ensures there are no schema formatting issues
144
+ expect(schema._validation).toHaveLength(0);
145
+ await expect(validateItem({
146
+ client: client,
147
+ value: {},
148
+ document: undefined,
149
+ path: [],
150
+ parent: undefined,
151
+ type: schema.get('testObj'),
152
+ getDocumentExists: undefined,
153
+ })).resolves.toMatchObject([
154
+ {
155
+ level: 'error',
156
+ item: { message: 'This is required!' },
157
+ path: ['registeredString'],
158
+ },
159
+ {
160
+ level: 'error',
161
+ item: { message: 'This is required!' },
162
+ path: ['inlineString'],
163
+ },
164
+ {
165
+ level: 'error',
166
+ item: { message: 'Required' },
167
+ path: ['registeredObject'],
168
+ },
169
+ {
170
+ level: 'error',
171
+ item: { message: 'This is required!' },
172
+ path: ['registeredObject', 'foo'],
173
+ },
174
+ {
175
+ level: 'error',
176
+ item: { message: 'Required' },
177
+ path: ['inlineObject'],
178
+ },
179
+ {
180
+ level: 'error',
181
+ item: { message: 'This is required!' },
182
+ path: ['inlineObject', 'foo'],
183
+ },
184
+ ]);
185
+ });
186
+ it('runs nested validation for object-level rules set via Rule.fields()', async () => {
187
+ const schema = createSchema({
188
+ types: [
189
+ {
190
+ name: 'testObj',
191
+ type: 'object',
192
+ title: 'Test Object',
193
+ fields: [
194
+ { name: 'foo', type: 'string' },
195
+ { name: 'bar', type: 'string' },
196
+ ],
197
+ validation: (rule) => [
198
+ rule.required(),
199
+ rule.fields({
200
+ foo: (r) => r.required(),
201
+ bar: (r) => r.required(),
202
+ }),
203
+ ],
204
+ },
205
+ ],
206
+ });
207
+ // ensures there are no schema formatting issues
208
+ expect(schema._validation).toHaveLength(0);
209
+ await expect(validateItem({
210
+ client: client,
211
+ document: undefined,
212
+ parent: undefined,
213
+ path: undefined,
214
+ type: schema.get('testObj'),
215
+ value: { foo: 5 },
216
+ getDocumentExists: undefined,
217
+ })).resolves.toMatchObject([
218
+ {
219
+ item: { message: 'Expected type "String", got "Number"' },
220
+ level: 'error',
221
+ path: ['foo'],
222
+ },
223
+ {
224
+ item: { message: 'Required' },
225
+ level: 'error',
226
+ path: ['bar'],
227
+ },
228
+ ]);
229
+ });
230
+ it('runs nested validation for markDefs', async () => {
231
+ const linkValidationSpy = jest.fn(() => true);
232
+ const internalLinkSpy = jest.fn(() => 'mock invalid response');
233
+ const schema = createSchema({
234
+ types: [
235
+ {
236
+ name: 'post',
237
+ title: 'Post',
238
+ type: 'document',
239
+ fields: [
240
+ { name: 'title', type: 'string' },
241
+ { name: 'body', type: 'string' },
242
+ ],
243
+ },
244
+ {
245
+ name: 'registeredEditor',
246
+ type: 'object',
247
+ title: 'Registered Editor',
248
+ fields: [
249
+ {
250
+ name: 'editor',
251
+ type: 'array',
252
+ of: [
253
+ {
254
+ type: 'block',
255
+ marks: {
256
+ annotations: [
257
+ {
258
+ name: 'exampleAnnotation',
259
+ type: 'object',
260
+ fields: [{ name: 'value', type: 'string' }],
261
+ },
262
+ ],
263
+ },
264
+ },
265
+ ],
266
+ },
267
+ ],
268
+ },
269
+ {
270
+ name: 'blockTest',
271
+ type: 'document',
272
+ title: 'blockTest',
273
+ fields: [
274
+ {
275
+ name: 'content',
276
+ title: 'Content',
277
+ type: 'array',
278
+ of: [
279
+ {
280
+ type: 'block',
281
+ marks: {
282
+ annotations: [
283
+ {
284
+ name: 'link',
285
+ type: 'object',
286
+ title: 'link',
287
+ fields: [{ name: 'url', type: 'url' }],
288
+ validation: (rule) => rule.custom(linkValidationSpy),
289
+ },
290
+ {
291
+ name: 'internalLink',
292
+ type: 'object',
293
+ title: 'Internal link',
294
+ fields: [{ name: 'reference', type: 'reference', to: [{ type: 'post' }] }],
295
+ validation: (rule) => rule.custom(internalLinkSpy),
296
+ },
297
+ { name: 'nestedEditor', type: 'registeredEditor' },
298
+ ],
299
+ },
300
+ },
301
+ ],
302
+ },
303
+ ],
304
+ },
305
+ ],
306
+ });
307
+ expect(schema._validation).toHaveLength(0);
308
+ const nestedBlock = {
309
+ _type: 'block',
310
+ _key: 'nested-block-key',
311
+ children: [
312
+ {
313
+ _key: 'some-key',
314
+ _type: 'span',
315
+ text: 'hey',
316
+ marks: ['example-annotation-key'],
317
+ },
318
+ ],
319
+ markDefs: [
320
+ {
321
+ _type: 'exampleAnnotation',
322
+ _key: 'example-annotation-key',
323
+ value: 5,
324
+ },
325
+ ],
326
+ style: 'normal',
327
+ };
328
+ const block = {
329
+ _key: 'block-key',
330
+ _type: 'block',
331
+ children: [
332
+ {
333
+ _key: 'child-0',
334
+ _type: 'span',
335
+ marks: ['0', '1', '2'],
336
+ text: 'hey',
337
+ },
338
+ ],
339
+ markDefs: [
340
+ {
341
+ _key: '0',
342
+ _type: 'link',
343
+ url: 'https://example.com',
344
+ },
345
+ {
346
+ _key: '1',
347
+ _type: 'internalLink',
348
+ _ref: 'post-id',
349
+ },
350
+ {
351
+ _key: '2',
352
+ _type: 'nestedEditor',
353
+ editor: [nestedBlock],
354
+ },
355
+ ],
356
+ style: 'normal',
357
+ };
358
+ const document = {
359
+ _id: 'mock-id',
360
+ _type: 'blockTest',
361
+ _createdAt: '2021-11-15T21:06:41.812Z',
362
+ _rev: 'example-ref',
363
+ _updatedAt: '2021-11-15T21:06:41.812Z',
364
+ content: [block],
365
+ };
366
+ const result = await validateItem({
367
+ client: client,
368
+ document: document,
369
+ parent: undefined,
370
+ path: [],
371
+ type: schema.get('blockTest'),
372
+ value: document,
373
+ getDocumentExists: undefined,
374
+ });
375
+ expect(result).toMatchObject([
376
+ {
377
+ item: { message: 'mock invalid response', paths: [] },
378
+ level: 'error',
379
+ path: ['content', { _key: 'block-key' }, 'markDefs', { _key: '1' }],
380
+ },
381
+ // this tests for nested markDef validation
382
+ {
383
+ item: {
384
+ message: 'Expected type "String", got "Number"',
385
+ paths: [],
386
+ },
387
+ level: 'error',
388
+ path: [
389
+ 'content',
390
+ { _key: 'block-key' },
391
+ 'markDefs',
392
+ { _key: '2' },
393
+ 'editor',
394
+ { _key: 'nested-block-key' },
395
+ 'markDefs',
396
+ { _key: 'example-annotation-key' },
397
+ 'value',
398
+ ],
399
+ },
400
+ ]);
401
+ expect(linkValidationSpy.mock.calls).toMatchObject([
402
+ [
403
+ {
404
+ _key: '0',
405
+ _type: 'link',
406
+ url: 'https://example.com',
407
+ },
408
+ {
409
+ document: { _id: 'mock-id' },
410
+ parent: { _key: 'block-key' },
411
+ path: ['content', { _key: 'block-key' }, 'markDefs', { _key: '0' }],
412
+ type: { name: 'link' },
413
+ },
414
+ ],
415
+ ]);
416
+ expect(internalLinkSpy.mock.calls).toMatchObject([
417
+ [
418
+ {
419
+ _key: '1',
420
+ _ref: 'post-id',
421
+ _type: 'internalLink',
422
+ },
423
+ {
424
+ document: { _id: 'mock-id' },
425
+ parent: { _key: 'block-key' },
426
+ path: ['content', { _key: 'block-key' }, 'markDefs', { _key: '1' }],
427
+ type: { name: 'internalLink' },
428
+ },
429
+ ],
430
+ ]);
431
+ });
432
+ it('resolves an array item type if there is just one type', async () => {
433
+ const schema = createSchema({
434
+ types: [
435
+ {
436
+ name: 'values',
437
+ title: 'Values',
438
+ type: 'array',
439
+ // note that there is only one type available
440
+ of: [{ type: 'arrayItem' }],
441
+ validation: (rule) => rule.required(),
442
+ },
443
+ {
444
+ title: 'Array Item',
445
+ name: 'arrayItem',
446
+ type: 'object',
447
+ fields: [{ name: 'title', type: 'string' }],
448
+ },
449
+ ],
450
+ });
451
+ // ensures there are no schema formatting issues
452
+ expect(schema._validation).toHaveLength(0);
453
+ const values = [
454
+ {
455
+ // note how this doesn't have a _type
456
+ title: 5,
457
+ _key: 'exampleKey',
458
+ },
459
+ ];
460
+ await expect(validateItem({
461
+ client: client,
462
+ document: undefined,
463
+ parent: undefined,
464
+ path: [],
465
+ type: schema.get('values'),
466
+ value: values,
467
+ getDocumentExists: undefined,
468
+ })).resolves.toEqual([
469
+ {
470
+ level: 'error',
471
+ item: {
472
+ message: 'Expected type "String", got "Number"',
473
+ paths: [],
474
+ },
475
+ path: [{ _key: 'exampleKey' }, 'title'],
476
+ },
477
+ ]);
478
+ });
479
+ it('properly passes the nested value, type, and path to rule.validate', async () => {
480
+ const schema = createSchema({
481
+ types: [
482
+ {
483
+ name: 'root',
484
+ type: 'object',
485
+ title: 'Root',
486
+ fields: [
487
+ {
488
+ name: 'level1Object',
489
+ type: 'object',
490
+ validation: (rule) => rule.custom(() => 'from level 1 object'),
491
+ fields: [
492
+ {
493
+ name: 'level2String',
494
+ type: 'string',
495
+ validation: (rule) => rule.custom(() => 'from level 2 via object'),
496
+ },
497
+ ],
498
+ },
499
+ {
500
+ name: 'level1Array',
501
+ type: 'array',
502
+ validation: (rule) => rule.custom(() => 'from level 1 array'),
503
+ of: [
504
+ {
505
+ type: 'object',
506
+ fields: [
507
+ {
508
+ name: 'level2Number',
509
+ type: 'number',
510
+ validation: (rule) => rule.custom(() => 'from level 2 via array'),
511
+ },
512
+ ],
513
+ },
514
+ ],
515
+ },
516
+ ],
517
+ validation: (rule) => rule.custom(() => 'from root'),
518
+ },
519
+ ],
520
+ });
521
+ // ensures there are no schema formatting issues
522
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
523
+ expect(schema._validation).toHaveLength(0);
524
+ const value = {
525
+ level1Object: { level3String: 'a string' },
526
+ level1Array: [{ level2Number: 5 }],
527
+ };
528
+ const document = {
529
+ value,
530
+ _type: 'something',
531
+ _createdAt: '2021-09-05T19:28:30.882Z',
532
+ _id: 'something.id',
533
+ _rev: 'exampleRev',
534
+ _updatedAt: '2021-09-05T19:28:30.882Z',
535
+ };
536
+ const getField = ({ in: type, name }) => {
537
+ const result = 'fields' in type && type.fields.find((f) => f.name === name)?.type;
538
+ if (!result)
539
+ throw new Error(`Could not find field \`${name}\` in \`${type.name}\``);
540
+ return result;
541
+ };
542
+ const rootType = schema.get('root');
543
+ const level1ObjectType = getField({ in: rootType, name: 'level1Object' });
544
+ const level2StringType = getField({ in: level1ObjectType, name: 'level2String' });
545
+ const level1ArrayType = getField({ in: rootType, name: 'level1Array' });
546
+ const level2NumberType = getField({
547
+ in: level1ArrayType.of[0],
548
+ name: 'level2Number',
549
+ });
550
+ await expect(validateItem({
551
+ client: client,
552
+ value,
553
+ type: rootType,
554
+ document,
555
+ parent: document,
556
+ path: undefined,
557
+ getDocumentExists: undefined,
558
+ })).resolves.toMatchObject([
559
+ {
560
+ item: { message: 'from root' },
561
+ path: [],
562
+ },
563
+ {
564
+ item: { message: 'from level 1 object' },
565
+ path: ['level1Object'],
566
+ },
567
+ {
568
+ item: { message: 'from level 2 via object' },
569
+ path: ['level1Object', 'level2String'],
570
+ },
571
+ {
572
+ item: { message: 'from level 1 array' },
573
+ path: ['level1Array'],
574
+ },
575
+ {
576
+ item: { message: 'from level 2 via array' },
577
+ path: ['level1Array', 0, 'level2Number'],
578
+ },
579
+ ]);
580
+ const calls = convertToValidationMarker.mock.calls;
581
+ expect(calls.find((call) => call[0] === 'from root')).toMatchObject([
582
+ 'from root',
583
+ 'error',
584
+ {
585
+ parent: document,
586
+ document: document,
587
+ path: [],
588
+ type: rootType,
589
+ },
590
+ ]);
591
+ expect(calls.find((call) => call[0] === 'from level 1 object')).toMatchObject([
592
+ 'from level 1 object',
593
+ 'error',
594
+ {
595
+ parent: value,
596
+ document: document,
597
+ path: ['level1Object'],
598
+ type: level1ObjectType,
599
+ },
600
+ ]);
601
+ expect(calls.find((call) => call[0] === 'from level 2 via object')).toMatchObject([
602
+ 'from level 2 via object',
603
+ 'error',
604
+ {
605
+ parent: value.level1Object,
606
+ document: document,
607
+ path: ['level1Object', 'level2String'],
608
+ type: level2StringType,
609
+ },
610
+ ]);
611
+ expect(calls.find((call) => call[0] === 'from level 1 array')).toMatchObject([
612
+ 'from level 1 array',
613
+ 'error',
614
+ {
615
+ parent: value,
616
+ document: document,
617
+ path: ['level1Array'],
618
+ type: level1ArrayType,
619
+ },
620
+ ]);
621
+ expect(calls.find((call) => call[0] === 'from level 2 via array')).toMatchObject([
622
+ 'from level 2 via array',
623
+ 'error',
624
+ {
625
+ parent: value.level1Array[0],
626
+ document: document,
627
+ path: ['level1Array', 0, 'level2Number'],
628
+ type: level2NumberType,
629
+ },
630
+ ]);
631
+ });
632
+ it('runs all nested validation checks concurrently', async () => {
633
+ const resolvers = new Set();
634
+ const customValidationFn = () => new Promise((resolve) => resolvers.add(resolve));
635
+ const schema = createSchema({
636
+ types: [
637
+ {
638
+ name: 'root',
639
+ type: 'object',
640
+ fields: [
641
+ {
642
+ name: 'level1Object',
643
+ type: 'object',
644
+ validation: (rule) => [
645
+ rule.custom(customValidationFn),
646
+ rule.fields({
647
+ level2String: (r) => r.custom(customValidationFn),
648
+ }),
649
+ ],
650
+ fields: [
651
+ {
652
+ name: 'level2String',
653
+ type: 'string',
654
+ validation: (rule) => rule.custom(customValidationFn),
655
+ },
656
+ ],
657
+ },
658
+ {
659
+ name: 'level1Array',
660
+ type: 'array',
661
+ validation: (rule) => rule.custom(customValidationFn),
662
+ of: [
663
+ {
664
+ type: 'object',
665
+ fields: [
666
+ {
667
+ name: 'level2Number',
668
+ type: 'number',
669
+ validation: (rule) => rule.custom(customValidationFn),
670
+ },
671
+ ],
672
+ },
673
+ ],
674
+ },
675
+ ],
676
+ validation: (rule) => rule.custom(customValidationFn),
677
+ },
678
+ ],
679
+ });
680
+ const value = {
681
+ level1Object: { level3String: 'a string' },
682
+ level1Array: [{ level2Number: 5 }],
683
+ };
684
+ const resultPromise = validateItem({
685
+ client: client,
686
+ value,
687
+ document: undefined,
688
+ parent: undefined,
689
+ path: undefined,
690
+ type: schema.get('root'),
691
+ getDocumentExists: undefined,
692
+ });
693
+ // after `validateItem(...)` has been initiated, all of the custom
694
+ // validation calls should have fired so the resolver size should equal the
695
+ // amount of total fields
696
+ expect(resolvers.size).toBe(6);
697
+ for (const resolver of resolvers) {
698
+ resolver(true);
699
+ }
700
+ await resultPromise;
701
+ });
702
+ });
703
+ //# sourceMappingURL=validateDocument.test.js.map