@sanity/validation 2.21.11-reference-updates.62 → 2.22.3-reference-updates.54

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.
@@ -1 +1 @@
1
- {"version":3,"file":"Rule.d.ts","sourceRoot":"","sources":["../../src/Rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,SAAS,EAUV,MAAM,eAAe,CAAA;AA0DtB,QAAA,MAAM,IAAI,EAAE,SAwVX,CAAA;AAED,eAAe,IAAI,CAAA"}
1
+ {"version":3,"file":"Rule.d.ts","sourceRoot":"","sources":["../../src/Rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,SAAS,EAUV,MAAM,eAAe,CAAA;AA0DtB,QAAA,MAAM,IAAI,EAAE,SA2VX,CAAA;AAED,eAAe,IAAI,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"normalizeValidationRules.d.ts","sourceRoot":"","sources":["../../../src/util/normalizeValidationRules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,IAAI,EAAqB,MAAM,eAAe,CAAA;AA+ElE;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,wBAAwB,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,GAAG,IAAI,EAAE,CAqCxF"}
1
+ {"version":3,"file":"normalizeValidationRules.d.ts","sourceRoot":"","sources":["../../../src/util/normalizeValidationRules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,IAAI,EAAqB,MAAM,eAAe,CAAA;AA6ElE;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,wBAAwB,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,GAAG,IAAI,EAAE,CAqCxF"}
@@ -1 +1 @@
1
- {"version":3,"file":"validateDocument.d.ts","sourceRoot":"","sources":["../../src/validateDocument.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,MAAM,EACN,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAGjB,MAAM,eAAe,CAAA;AAYtB;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,UAAU,EAAE,GACvB,UAAU,GAAG,SAAS,CAiBxB;AAED,wBAA8B,gBAAgB,CAC5C,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,GACrD,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA2B7B;AAED;;;;;;GAMG;AACH,aAAK,iBAAiB,CAAC,CAAC,IAAI;KACzB,CAAC,IAAI,MAAM,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS;CAC5F,CAAA;AAED,aAAK,mBAAmB,GAAG;IACzB,KAAK,EAAE,OAAO,CAAA;CACf,GAAG,iBAAiB,CAAC,iBAAiB,CAAC,CAAA;AAExC,wBAAsB,YAAY,CAAC,EACjC,KAAK,EACL,IAAI,EACJ,IAAS,EACT,MAAM,EACN,GAAG,aAAa,EACjB,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA8FnD"}
1
+ {"version":3,"file":"validateDocument.d.ts","sourceRoot":"","sources":["../../src/validateDocument.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,MAAM,EACN,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAMjB,MAAM,eAAe,CAAA;AAYtB;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,UAAU,EAAE,GACvB,UAAU,GAAG,SAAS,CAiBxB;AAED,wBAA8B,gBAAgB,CAC5C,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,GACrD,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA2B7B;AAED;;;;;;GAMG;AACH,aAAK,iBAAiB,CAAC,CAAC,IAAI;KACzB,CAAC,IAAI,MAAM,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS;CAC5F,CAAA;AAED,aAAK,mBAAmB,GAAG;IACzB,KAAK,EAAE,OAAO,CAAA;CACf,GAAG,iBAAiB,CAAC,iBAAiB,CAAC,CAAA;AAExC,wBAAsB,YAAY,CAAC,EACjC,KAAK,EACL,IAAI,EACJ,IAAS,EACT,MAAM,EACN,GAAG,aAAa,EACjB,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA4HnD"}
@@ -1 +1 @@
1
- {"version":3,"file":"objectValidator.d.ts","sourceRoot":"","sources":["../../../src/validators/objectValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAc,MAAM,eAAe,CAAA;AAKrD,QAAA,MAAM,gBAAgB,EAAE,UAiEvB,CAAA;AAED,eAAe,gBAAgB,CAAA"}
1
+ {"version":3,"file":"objectValidator.d.ts","sourceRoot":"","sources":["../../../src/validators/objectValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAc,MAAM,eAAe,CAAA;AAKrD,QAAA,MAAM,gBAAgB,EAAE,UAwDvB,CAAA;AAED,eAAe,gBAAgB,CAAA"}
package/lib/Rule.js CHANGED
@@ -232,6 +232,17 @@ var Rule = (_temp = _class = class Rule {
232
232
  constraint: fn
233
233
  }]);
234
234
  }
235
+ /**
236
+ * @deprecated use `Rule.custom` instead
237
+ */
238
+
239
+
240
+ block(fn) {
241
+ return this.cloneWithRules([{
242
+ flag: 'custom',
243
+ constraint: fn
244
+ }]);
245
+ }
235
246
 
236
247
  min(len) {
237
248
  return this.cloneWithRules([{
@@ -383,13 +394,6 @@ var Rule = (_temp = _class = class Rule {
383
394
  }]);
384
395
  }
385
396
 
386
- block(blockValidator) {
387
- return this.cloneWithRules([{
388
- flag: 'block',
389
- constraint: blockValidator
390
- }]);
391
- }
392
-
393
397
  fields(rules) {
394
398
  if (this._type !== 'Object') {
395
399
  throw new Error('fields() can only be called on an object type');
package/lib/index.js CHANGED
@@ -9,12 +9,7 @@ Object.defineProperty(exports, "Rule", {
9
9
  return _Rule.default;
10
10
  }
11
11
  });
12
- Object.defineProperty(exports, "validateDocument", {
13
- enumerable: true,
14
- get: function get() {
15
- return _validateDocument.default;
16
- }
17
- });
12
+ exports.default = void 0;
18
13
  Object.defineProperty(exports, "inferFromSchema", {
19
14
  enumerable: true,
20
15
  get: function get() {
@@ -27,7 +22,12 @@ Object.defineProperty(exports, "inferFromSchemaType", {
27
22
  return _inferFromSchemaType.default;
28
23
  }
29
24
  });
30
- exports.default = void 0;
25
+ Object.defineProperty(exports, "validateDocument", {
26
+ enumerable: true,
27
+ get: function get() {
28
+ return _validateDocument.default;
29
+ }
30
+ });
31
31
 
32
32
  var _Rule = _interopRequireDefault(require("./Rule"));
33
33
 
@@ -3,8 +3,8 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isNonNullable = isNonNullable;
7
6
  exports.default = convertToValidationMarker;
7
+ exports.isNonNullable = isNonNullable;
8
8
 
9
9
  var _ValidationError = _interopRequireDefault(require("../ValidationError"));
10
10
 
@@ -7,8 +7,6 @@ exports.default = normalizeValidationRules;
7
7
 
8
8
  var _Rule = _interopRequireDefault(require("../Rule"));
9
9
 
10
- var _blockValidator = require("../validators/blockValidator");
11
-
12
10
  var _slugValidator = require("../validators/slugValidator");
13
11
 
14
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -61,7 +59,6 @@ function baseRuleReducer(inputRule, type) {
61
59
  if (type.name === 'slug') return baseRule.custom(_slugValidator.slugValidator);
62
60
  if (type.name === 'reference') return baseRule.reference();
63
61
  if (type.name === 'email') return baseRule.email();
64
- if (type.name === 'block') return baseRule.block(_blockValidator.blockValidator);
65
62
  return baseRule;
66
63
  }
67
64
 
@@ -3,8 +3,8 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.resolveTypeForArrayItem = resolveTypeForArrayItem;
7
6
  exports.default = validateDocument;
7
+ exports.resolveTypeForArrayItem = resolveTypeForArrayItem;
8
8
  exports.validateItem = validateItem;
9
9
 
10
10
  var _uniqBy2 = _interopRequireDefault(require("lodash/uniqBy"));
@@ -141,7 +141,10 @@ function _validateItem() {
141
141
  var nestedChecks = [];
142
142
  var selfIsRequired = rules.some(rule => rule.isRequired());
143
143
  var shouldRunNestedObjectValidation = // run nested validation for objects
144
- (type === null || type === void 0 ? void 0 : type.jsonType) === 'object' && (!!value || (value === null || value === undefined) && selfIsRequired);
144
+ (type === null || type === void 0 ? void 0 : type.jsonType) === 'object' && ( // if the value is truthy
145
+ !!value || // or
146
+ // (the value is null or undefined) and the top-level value is required
147
+ (value === null || value === undefined) && selfIsRequired);
145
148
 
146
149
  if (shouldRunNestedObjectValidation) {
147
150
  var fieldTypes = type.fields.reduce((acc, field) => {
@@ -190,9 +193,32 @@ function _validateItem() {
190
193
  } : value.indexOf(item)),
191
194
  type: resolveTypeForArrayItem(item, type.of)
192
195
  }))));
196
+ } // markDefs also do no run nested validation if the parent object is undefined
197
+ // for a similar reason to arrays
198
+
199
+
200
+ var shouldRunNestedValidationForMarkDefs = (0, _types.isBlock)(value) && value.markDefs.length && (0, _types.isBlockSchemaType)(type);
201
+
202
+ if (shouldRunNestedValidationForMarkDefs) {
203
+ var _type$fields = _slicedToArray(type.fields, 1),
204
+ spanChildrenField = _type$fields[0];
205
+
206
+ var spanType = spanChildrenField.type.of.find(_types.isSpanSchemaType);
207
+ var annotations = ((spanType === null || spanType === void 0 ? void 0 : spanType.annotations) || []).reduce((map, annotationType) => {
208
+ map.set(annotationType.name, annotationType);
209
+ return map;
210
+ }, new Map());
211
+ nestedChecks = nestedChecks.concat(value.markDefs.map(markDef => validateItem(_objectSpread(_objectSpread({}, restOfContext), {}, {
212
+ parent: value,
213
+ value: markDef,
214
+ path: path.concat(['markDefs', {
215
+ _key: markDef._key
216
+ }]),
217
+ type: annotations.get(markDef._type)
218
+ }))));
193
219
  }
194
220
 
195
- var results = (yield Promise.all([...selfChecks, ...nestedChecks])).flat(); // run `dedupeValidationMarkers` if `_fieldRules` are present because they can
221
+ var results = (yield Promise.all([...selfChecks, ...nestedChecks])).flat(); // run `uniqBy` if `_fieldRules` are present because they can
196
222
  // cause repeat markers
197
223
 
198
224
  if (rules.some(rule => rule._fieldRules)) {
@@ -3,8 +3,8 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isRecord = isRecord;
7
6
  exports.default = void 0;
7
+ exports.isRecord = isRecord;
8
8
 
9
9
  var _format = _interopRequireDefault(require("date-fns/format"));
10
10
 
@@ -79,23 +79,6 @@ var objectValidators = _objectSpread(_objectSpread({}, _genericValidator.default
79
79
 
80
80
  return reference;
81
81
  }(),
82
- block: function () {
83
- var _block = _asyncToGenerator(function* (validateBlock, value, message, context) {
84
- var result = yield validateBlock(value, context);
85
-
86
- if (typeof result === 'string') {
87
- return message || result;
88
- }
89
-
90
- return result;
91
- });
92
-
93
- function block(_x5, _x6, _x7, _x8) {
94
- return _block.apply(this, arguments);
95
- }
96
-
97
- return block;
98
- }(),
99
82
  assetRequired: (flag, value, message) => {
100
83
  if (!value || !value.asset || !value.asset._ref) {
101
84
  var assetType = flag.assetType || 'Asset';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/validation",
3
- "version": "2.21.11-reference-updates.62+f98497b413",
3
+ "version": "2.22.3-reference-updates.54+c8d2373956",
4
4
  "description": "Validation and warning infrastructure for Sanity projects",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./dist/dts",
@@ -32,8 +32,8 @@
32
32
  "directory": "packages/@sanity/validation"
33
33
  },
34
34
  "devDependencies": {
35
- "@sanity/client": "2.21.11-reference-updates.62+f98497b413",
36
- "@sanity/schema": "2.21.11-reference-updates.62+f98497b413"
35
+ "@sanity/client": "2.22.3-reference-updates.54+c8d2373956",
36
+ "@sanity/schema": "2.22.3-reference-updates.54+c8d2373956"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@sanity/client": "^2.0.0"
@@ -44,9 +44,9 @@
44
44
  }
45
45
  },
46
46
  "dependencies": {
47
- "@sanity/types": "2.21.11-reference-updates.62+f98497b413",
47
+ "@sanity/types": "2.22.3-reference-updates.54+c8d2373956",
48
48
  "date-fns": "^2.16.1",
49
49
  "lodash": "^4.17.15"
50
50
  },
51
- "gitHead": "f98497b413e20f06fcca0923f540b8ae2c8ae564"
51
+ "gitHead": "c8d237395618194918d18736ccbce8a937200b6a"
52
52
  }
package/src/Rule.ts CHANGED
@@ -4,13 +4,13 @@ import {
4
4
  RuleClass,
5
5
  CustomValidator,
6
6
  RuleSpecConstraint,
7
- BlockValidator,
8
7
  FieldRules,
9
8
  ValidationContext,
10
9
  RuleSpec,
11
10
  ValidationMarker,
12
11
  RuleTypeConstraint,
13
12
  Validator,
13
+ Block,
14
14
  } from '@sanity/types'
15
15
  import {cloneDeep, get} from 'lodash'
16
16
  import ValidationErrorClass from './ValidationError'
@@ -219,6 +219,13 @@ const Rule: RuleClass = class Rule implements IRule {
219
219
  return this.cloneWithRules([{flag: 'custom', constraint: fn as CustomValidator}])
220
220
  }
221
221
 
222
+ /**
223
+ * @deprecated use `Rule.custom` instead
224
+ */
225
+ block(fn: CustomValidator<Block>): Rule {
226
+ return this.cloneWithRules([{flag: 'custom', constraint: fn as CustomValidator}])
227
+ }
228
+
222
229
  min(len: number): Rule {
223
230
  return this.cloneWithRules([{flag: 'min', constraint: len}])
224
231
  }
@@ -336,10 +343,6 @@ const Rule: RuleClass = class Rule implements IRule {
336
343
  return this.cloneWithRules([{flag: 'reference'}])
337
344
  }
338
345
 
339
- block(blockValidator: BlockValidator): Rule {
340
- return this.cloneWithRules([{flag: 'block', constraint: blockValidator}])
341
- }
342
-
343
346
  fields(rules: FieldRules): Rule {
344
347
  if (this._type !== 'Object') {
345
348
  throw new Error('fields() can only be called on an object type')
@@ -1,6 +1,5 @@
1
1
  import {SchemaType, Rule, RuleTypeConstraint} from '@sanity/types'
2
2
  import RuleClass from '../Rule'
3
- import {blockValidator} from '../validators/blockValidator'
4
3
  import {slugValidator} from '../validators/slugValidator'
5
4
 
6
5
  const ruleConstraintTypes: {[P in Lowercase<RuleTypeConstraint>]: true} = {
@@ -54,7 +53,6 @@ function baseRuleReducer(inputRule: Rule, type: SchemaType) {
54
53
  if (type.name === 'slug') return baseRule.custom(slugValidator)
55
54
  if (type.name === 'reference') return baseRule.reference()
56
55
  if (type.name === 'email') return baseRule.email()
57
- if (type.name === 'block') return baseRule.block(blockValidator)
58
56
  return baseRule
59
57
  }
60
58
 
@@ -1,6 +1,6 @@
1
1
  /// <reference types="@sanity/types/parts" />
2
2
 
3
- import {Rule, SchemaType, SanityDocument, Schema, ArraySchemaType} from '@sanity/types'
3
+ import {Rule, SchemaType, SanityDocument, Schema, ArraySchemaType, Block} from '@sanity/types'
4
4
  import createSchema from 'part:@sanity/base/schema-creator'
5
5
  import validateDocument, {resolveTypeForArrayItem, validateItem} from './validateDocument'
6
6
  import convertToValidationMarker from './util/convertToValidationMarker'
@@ -149,14 +149,17 @@ describe('validateItem', () => {
149
149
  },
150
150
  ],
151
151
  },
152
- {name: 'registeredString', type: 'string', validation},
152
+ {name: 'registeredString', title: 'Registered String', type: 'string', validation},
153
153
  {
154
+ title: 'Registered Object Field',
154
155
  name: 'registeredObjectField',
155
156
  type: 'object',
156
157
  fields: [{name: 'foo', type: 'string', validation}],
157
158
  },
158
159
  ],
159
160
  })
161
+ // ensures there are no schema formatting issues
162
+ expect(schema._validation).toHaveLength(0)
160
163
 
161
164
  await expect(
162
165
  validateItem({
@@ -229,6 +232,9 @@ describe('validateItem', () => {
229
232
  ],
230
233
  })
231
234
 
235
+ // ensures there are no schema formatting issues
236
+ expect(schema._validation).toHaveLength(0)
237
+
232
238
  await expect(
233
239
  validateItem({
234
240
  document: undefined,
@@ -254,17 +260,232 @@ describe('validateItem', () => {
254
260
  ])
255
261
  })
256
262
 
263
+ it('runs nested validation for markDefs', async () => {
264
+ const linkValidationSpy = jest.fn(() => true as const)
265
+ const internalLinkSpy = jest.fn(() => 'mock invalid response')
266
+
267
+ const schema = createSchema({
268
+ types: [
269
+ {
270
+ name: 'post',
271
+ title: 'Post',
272
+ type: 'document',
273
+ fields: [
274
+ {name: 'title', type: 'string'},
275
+ {name: 'body', type: 'string'},
276
+ ],
277
+ },
278
+ {
279
+ name: 'registeredEditor',
280
+ type: 'object',
281
+ title: 'Registered Editor',
282
+ fields: [
283
+ {
284
+ name: 'editor',
285
+ type: 'array',
286
+ of: [
287
+ {
288
+ type: 'block',
289
+ marks: {
290
+ annotations: [
291
+ {
292
+ name: 'exampleAnnotation',
293
+ type: 'object',
294
+ fields: [{name: 'value', type: 'string'}],
295
+ },
296
+ ],
297
+ },
298
+ },
299
+ ],
300
+ },
301
+ ],
302
+ },
303
+ {
304
+ name: 'blockTest',
305
+ type: 'document',
306
+ title: 'blockTest',
307
+ fields: [
308
+ {
309
+ name: 'content',
310
+ title: 'Content',
311
+ type: 'array',
312
+ of: [
313
+ {
314
+ type: 'block',
315
+ marks: {
316
+ annotations: [
317
+ {
318
+ name: 'link',
319
+ type: 'object',
320
+ title: 'link',
321
+ fields: [{name: 'url', type: 'url'}],
322
+ validation: (rule: Rule) => rule.custom(linkValidationSpy),
323
+ },
324
+ {
325
+ name: 'internalLink',
326
+ type: 'object',
327
+ title: 'Internal link',
328
+ fields: [{name: 'reference', type: 'reference', to: [{type: 'post'}]}],
329
+ validation: (rule: Rule) => rule.custom(internalLinkSpy),
330
+ },
331
+ {name: 'nestedEditor', type: 'registeredEditor'},
332
+ ],
333
+ },
334
+ },
335
+ ],
336
+ },
337
+ ],
338
+ },
339
+ ],
340
+ })
341
+
342
+ expect(schema._validation).toHaveLength(0)
343
+
344
+ const nestedBlock: Block = {
345
+ _type: 'block',
346
+ _key: 'nested-block-key',
347
+ children: [
348
+ {
349
+ _key: 'some-key',
350
+ _type: 'span',
351
+ text: 'hey',
352
+ marks: ['example-annotation-key'],
353
+ },
354
+ ],
355
+ markDefs: [
356
+ {
357
+ _type: 'exampleAnnotation',
358
+ _key: 'example-annotation-key',
359
+ value: 5,
360
+ },
361
+ ],
362
+ style: 'normal',
363
+ }
364
+
365
+ const block: Block = {
366
+ _key: 'block-key',
367
+ _type: 'block',
368
+ children: [
369
+ {
370
+ _key: 'child-0',
371
+ _type: 'span',
372
+ marks: ['0', '1', '2'],
373
+ text: 'hey',
374
+ },
375
+ ],
376
+ markDefs: [
377
+ {
378
+ _key: '0',
379
+ _type: 'link',
380
+ url: 'https://example.com',
381
+ },
382
+ {
383
+ _key: '1',
384
+ _type: 'internalLink',
385
+ _ref: 'post-id',
386
+ },
387
+ {
388
+ _key: '2',
389
+ _type: 'nestedEditor',
390
+ editor: [nestedBlock],
391
+ },
392
+ ],
393
+ style: 'normal',
394
+ }
395
+
396
+ const document: SanityDocument = {
397
+ _id: 'mock-id',
398
+ _type: 'blockTest',
399
+ _createdAt: '2021-11-15T21:06:41.812Z',
400
+ _rev: 'example-ref',
401
+ _updatedAt: '2021-11-15T21:06:41.812Z',
402
+ content: [block],
403
+ }
404
+
405
+ const result = await validateItem({
406
+ document: document,
407
+ parent: undefined,
408
+ path: [],
409
+ type: schema.get('blockTest'),
410
+ value: document,
411
+ getDocumentExists: undefined,
412
+ })
413
+
414
+ expect(result).toMatchObject([
415
+ {
416
+ item: {message: 'mock invalid response', paths: []},
417
+ level: 'error',
418
+ path: ['content', {_key: 'block-key'}, 'markDefs', {_key: '1'}],
419
+ type: 'validation',
420
+ },
421
+ // this tests for nested markDef validation
422
+ {
423
+ item: {
424
+ message: 'Expected type "String", got "Number"',
425
+ paths: [],
426
+ },
427
+ level: 'error',
428
+ path: [
429
+ 'content',
430
+ {_key: 'block-key'},
431
+ 'markDefs',
432
+ {_key: '2'},
433
+ 'editor',
434
+ {_key: 'nested-block-key'},
435
+ 'markDefs',
436
+ {_key: 'example-annotation-key'},
437
+ 'value',
438
+ ],
439
+ type: 'validation',
440
+ },
441
+ ])
442
+
443
+ expect(linkValidationSpy.mock.calls).toMatchObject([
444
+ [
445
+ {
446
+ _key: '0',
447
+ _type: 'link',
448
+ url: 'https://example.com',
449
+ },
450
+ {
451
+ document: {_id: 'mock-id'},
452
+ parent: {_key: 'block-key'},
453
+ path: ['content', {_key: 'block-key'}, 'markDefs', {_key: '0'}],
454
+ type: {name: 'link'},
455
+ },
456
+ ],
457
+ ])
458
+
459
+ expect(internalLinkSpy.mock.calls).toMatchObject([
460
+ [
461
+ {
462
+ _key: '1',
463
+ _ref: 'post-id',
464
+ _type: 'internalLink',
465
+ },
466
+ {
467
+ document: {_id: 'mock-id'},
468
+ parent: {_key: 'block-key'},
469
+ path: ['content', {_key: 'block-key'}, 'markDefs', {_key: '1'}],
470
+ type: {name: 'internalLink'},
471
+ },
472
+ ],
473
+ ])
474
+ })
475
+
257
476
  it('resolves an array item type if there is just one type', async () => {
258
477
  const schema = createSchema({
259
478
  types: [
260
479
  {
261
480
  name: 'values',
481
+ title: 'Values',
262
482
  type: 'array',
263
483
  // note that there is only one type available
264
484
  of: [{type: 'arrayItem'}],
265
485
  validation: (rule: Rule) => rule.required(),
266
486
  },
267
487
  {
488
+ title: 'Array Item',
268
489
  name: 'arrayItem',
269
490
  type: 'object',
270
491
  fields: [{name: 'title', type: 'string'}],
@@ -272,6 +493,9 @@ describe('validateItem', () => {
272
493
  ],
273
494
  })
274
495
 
496
+ // ensures there are no schema formatting issues
497
+ expect(schema._validation).toHaveLength(0)
498
+
275
499
  const values = [
276
500
  {
277
501
  // note how this doesn't have a _type
@@ -308,6 +532,7 @@ describe('validateItem', () => {
308
532
  {
309
533
  name: 'root',
310
534
  type: 'object',
535
+ title: 'Root',
311
536
  fields: [
312
537
  {
313
538
  name: 'level1Object',
@@ -344,6 +569,10 @@ describe('validateItem', () => {
344
569
  ],
345
570
  })
346
571
 
572
+ // ensures there are no schema formatting issues
573
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
574
+ expect((schema as any)._validation).toHaveLength(0)
575
+
347
576
  const value = {
348
577
  level1Object: {level3String: 'a string'},
349
578
  level1Array: [{level2Number: 5}],
@@ -6,6 +6,9 @@ import {
6
6
  ValidationMarker,
7
7
  isKeyedObject,
8
8
  isTypedObject,
9
+ isBlock,
10
+ isBlockSchemaType,
11
+ isSpanSchemaType,
9
12
  } from '@sanity/types'
10
13
  import {uniqBy} from 'lodash'
11
14
  import typeString from './util/typeString'
@@ -182,9 +185,39 @@ export async function validateItem({
182
185
  )
183
186
  }
184
187
 
188
+ // markDefs also do no run nested validation if the parent object is undefined
189
+ // for a similar reason to arrays
190
+ const shouldRunNestedValidationForMarkDefs =
191
+ isBlock(value) && value.markDefs.length && isBlockSchemaType(type)
192
+
193
+ if (shouldRunNestedValidationForMarkDefs) {
194
+ const [spanChildrenField] = type.fields
195
+ const spanType = spanChildrenField.type.of.find(isSpanSchemaType)
196
+
197
+ const annotations = (spanType?.annotations || []).reduce<Map<string, SchemaType>>(
198
+ (map, annotationType) => {
199
+ map.set(annotationType.name, annotationType)
200
+ return map
201
+ },
202
+ new Map()
203
+ )
204
+
205
+ nestedChecks = nestedChecks.concat(
206
+ value.markDefs.map((markDef) =>
207
+ validateItem({
208
+ ...restOfContext,
209
+ parent: value,
210
+ value: markDef,
211
+ path: path.concat(['markDefs', {_key: markDef._key}]),
212
+ type: annotations.get(markDef._type),
213
+ })
214
+ )
215
+ )
216
+ }
217
+
185
218
  const results = (await Promise.all([...selfChecks, ...nestedChecks])).flat()
186
219
 
187
- // run `dedupeValidationMarkers` if `_fieldRules` are present because they can
220
+ // run `uniqBy` if `_fieldRules` are present because they can
188
221
  // cause repeat markers
189
222
  if (rules.some((rule) => rule._fieldRules)) {
190
223
  return uniqBy(results, (rule) => JSON.stringify(rule))
@@ -51,15 +51,6 @@ const objectValidators: Validators = {
51
51
  return true
52
52
  },
53
53
 
54
- block: async (validateBlock, value, message, context) => {
55
- const result = await validateBlock(value, context)
56
- if (typeof result === 'string') {
57
- return message || result
58
- }
59
-
60
- return result
61
- },
62
-
63
54
  assetRequired: (flag, value, message) => {
64
55
  if (!value || !value.asset || !value.asset._ref) {
65
56
  const assetType = flag.assetType || 'Asset'
@@ -1,3 +0,0 @@
1
- import { BlockValidator } from '@sanity/types';
2
- export declare const blockValidator: BlockValidator;
3
- //# sourceMappingURL=blockValidator.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"blockValidator.d.ts","sourceRoot":"","sources":["../../../src/validators/blockValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,cAAc,EAAC,MAAM,eAAe,CAAA;AAG9D,eAAO,MAAM,cAAc,EAAE,cAmD5B,CAAA"}
@@ -1,66 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.blockValidator = void 0;
7
-
8
- var _validateDocument = require("../validateDocument");
9
-
10
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
11
-
12
- function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
13
-
14
- var blockValidator = /*#__PURE__*/function () {
15
- var _ref = _asyncToGenerator(function* (value, context) {
16
- var _type$fields, _type$fields$find;
17
-
18
- if (value.markDefs.length === 0) return [];
19
- var type = context.type;
20
-
21
- if (!type) {
22
- throw new Error("Schema `type` was not provided in validation context");
23
- }
24
-
25
- if (type.jsonType !== 'object') {
26
- throw new Error("Expected schema type with jsonType `object` but found `".concat(type.jsonType, "` instead."));
27
- }
28
-
29
- var childrenType = (_type$fields = type.fields) === null || _type$fields === void 0 ? void 0 : (_type$fields$find = _type$fields.find(field => field.name === 'children')) === null || _type$fields$find === void 0 ? void 0 : _type$fields$find.type;
30
- var spanType = (childrenType === null || childrenType === void 0 ? void 0 : childrenType.jsonType) === 'array' ? childrenType === null || childrenType === void 0 ? void 0 : childrenType.of.find(ofType => ofType.name === 'span') : null; // Validate every markDef (annotation) value
31
- // eslint-disable-next-line no-warning-comments
32
- // @ts-expect-error TODO (eventually): fix these types
33
-
34
- var activeAnnotationTypes = spanType === null || spanType === void 0 ? void 0 : spanType.annotations.filter(annotation => // eslint-disable-next-line no-warning-comments
35
- // @ts-expect-error TODO (eventually): fix these types
36
- value.markDefs.map(def => def._type).includes(annotation.name));
37
- var annotationValidations = [];
38
- value.markDefs.forEach(markDef => {
39
- var annotationType = activeAnnotationTypes.find(aType => aType.name === markDef._type);
40
- var validations = (0, _validateDocument.validateItem)({
41
- document: context.document,
42
- value: markDef,
43
- type: annotationType,
44
- path: (context.path || []).concat(['markDefs', {
45
- _key: markDef._key
46
- }]),
47
- parent: value,
48
- getDocumentExists: context.getDocumentExists
49
- });
50
- annotationValidations.push(validations);
51
- });
52
- var results = yield Promise.all(annotationValidations);
53
- var flattened = results.flat();
54
- if (!flattened.length) return [];
55
- return flattened.map(res => {
56
- res.item.paths = [res.path];
57
- return res.item;
58
- });
59
- });
60
-
61
- return function blockValidator(_x, _x2) {
62
- return _ref.apply(this, arguments);
63
- };
64
- }();
65
-
66
- exports.blockValidator = blockValidator;
@@ -1,55 +0,0 @@
1
- import {ValidationMarker, BlockValidator} from '@sanity/types'
2
- import {validateItem} from '../validateDocument'
3
-
4
- export const blockValidator: BlockValidator = async (value, context) => {
5
- if (value.markDefs.length === 0) return []
6
-
7
- const {type} = context
8
-
9
- if (!type) {
10
- throw new Error(`Schema \`type\` was not provided in validation context`)
11
- }
12
- if (type.jsonType !== 'object') {
13
- throw new Error(
14
- `Expected schema type with jsonType \`object\` but found \`${type.jsonType}\` instead.`
15
- )
16
- }
17
-
18
- const childrenType = type.fields?.find((field) => field.name === 'children')?.type
19
- const spanType =
20
- childrenType?.jsonType === 'array'
21
- ? childrenType?.of.find((ofType) => ofType.name === 'span')
22
- : null
23
-
24
- // Validate every markDef (annotation) value
25
- // eslint-disable-next-line no-warning-comments
26
- // @ts-expect-error TODO (eventually): fix these types
27
- const activeAnnotationTypes: any[] = spanType?.annotations.filter((annotation) =>
28
- // eslint-disable-next-line no-warning-comments
29
- // @ts-expect-error TODO (eventually): fix these types
30
- value.markDefs.map((def) => def._type).includes(annotation.name)
31
- )
32
- const annotationValidations: Promise<ValidationMarker[]>[] = []
33
- value.markDefs.forEach((markDef: any) => {
34
- const annotationType = activeAnnotationTypes.find((aType) => aType.name === markDef._type)
35
- const validations = validateItem({
36
- document: context.document,
37
- value: markDef,
38
- type: annotationType,
39
- path: (context.path || []).concat(['markDefs', {_key: markDef._key}]),
40
- parent: value,
41
- getDocumentExists: context.getDocumentExists,
42
- })
43
- annotationValidations.push(validations)
44
- })
45
-
46
- const results = await Promise.all(annotationValidations)
47
- const flattened = results.flat()
48
-
49
- if (!flattened.length) return []
50
-
51
- return flattened.map((res) => {
52
- res.item.paths = [res.path]
53
- return res.item
54
- })
55
- }