@sanity/validation 2.21.12-shopify.7 → 2.22.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.
@@ -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,GACb,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA0B7B;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,GACb,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA0B7B;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;AAKxC,QAAA,MAAM,gBAAgB,EAAE,UA8CvB,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;AAKxC,QAAA,MAAM,gBAAgB,EAAE,UAqCvB,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');
@@ -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
 
@@ -192,9 +192,32 @@ function _validateItem() {
192
192
  } : value.indexOf(item)),
193
193
  type: resolveTypeForArrayItem(item, type.of)
194
194
  }))));
195
+ } // markDefs also do no run nested validation if the parent object is undefined
196
+ // for a similar reason to arrays
197
+
198
+
199
+ var shouldRunNestedValidationForMarkDefs = (0, _types.isBlock)(value) && value.markDefs.length && (0, _types.isBlockSchemaType)(type);
200
+
201
+ if (shouldRunNestedValidationForMarkDefs) {
202
+ var _type$fields = _slicedToArray(type.fields, 1),
203
+ spanChildrenField = _type$fields[0];
204
+
205
+ var spanType = spanChildrenField.type.of.find(_types.isSpanSchemaType);
206
+ var annotations = ((spanType === null || spanType === void 0 ? void 0 : spanType.annotations) || []).reduce((map, annotationType) => {
207
+ map.set(annotationType.name, annotationType);
208
+ return map;
209
+ }, new Map());
210
+ nestedChecks = nestedChecks.concat(value.markDefs.map(markDef => validateItem(_objectSpread(_objectSpread({}, restOfContext), {}, {
211
+ parent: value,
212
+ value: markDef,
213
+ path: path.concat(['markDefs', {
214
+ _key: markDef._key
215
+ }]),
216
+ type: annotations.get(markDef._type)
217
+ }))));
195
218
  }
196
219
 
197
- var results = (yield Promise.all([...selfChecks, ...nestedChecks])).flat(); // run `dedupeValidationMarkers` if `_fieldRules` are present because they can
220
+ var results = (yield Promise.all([...selfChecks, ...nestedChecks])).flat(); // run `uniqBy` if `_fieldRules` are present because they can
198
221
  // cause repeat markers
199
222
 
200
223
  if (rules.some(rule => rule._fieldRules)) {
@@ -9,10 +9,6 @@ var _genericValidator = _interopRequireDefault(require("./genericValidator"));
9
9
 
10
10
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
11
 
12
- 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); } }
13
-
14
- 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); }); }; }
15
-
16
12
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
17
13
 
18
14
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
@@ -46,23 +42,6 @@ var objectValidators = _objectSpread(_objectSpread({}, _genericValidator.default
46
42
 
47
43
  return true;
48
44
  },
49
- block: function () {
50
- var _block = _asyncToGenerator(function* (validateBlock, value, message, context) {
51
- var result = yield validateBlock(value, context);
52
-
53
- if (typeof result === 'string') {
54
- return message || result;
55
- }
56
-
57
- return result;
58
- });
59
-
60
- function block(_x, _x2, _x3, _x4) {
61
- return _block.apply(this, arguments);
62
- }
63
-
64
- return block;
65
- }(),
66
45
  assetRequired: (flag, value, message) => {
67
46
  if (!value || !value.asset || !value.asset._ref) {
68
47
  var assetType = flag.assetType || 'Asset';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/validation",
3
- "version": "2.21.12-shopify.7+43c0621a9",
3
+ "version": "2.22.0",
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.12-shopify.7+43c0621a9",
36
- "@sanity/schema": "2.21.12-shopify.7+43c0621a9"
35
+ "@sanity/client": "2.21.10",
36
+ "@sanity/schema": "2.22.0"
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.12-shopify.7+43c0621a9",
47
+ "@sanity/types": "2.22.0",
48
48
  "date-fns": "^2.16.1",
49
49
  "lodash": "^4.17.15"
50
50
  },
51
- "gitHead": "43c0621a981601c64af5fec68da8cda9d4d6d4e7"
51
+ "gitHead": "f41f6620cf21f38352e1587ea7a1c350b33d2c33"
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({
@@ -228,6 +231,9 @@ describe('validateItem', () => {
228
231
  ],
229
232
  })
230
233
 
234
+ // ensures there are no schema formatting issues
235
+ expect(schema._validation).toHaveLength(0)
236
+
231
237
  await expect(
232
238
  validateItem({
233
239
  document: undefined,
@@ -252,17 +258,231 @@ describe('validateItem', () => {
252
258
  ])
253
259
  })
254
260
 
261
+ it('runs nested validation for markDefs', async () => {
262
+ const linkValidationSpy = jest.fn(() => true as const)
263
+ const internalLinkSpy = jest.fn(() => 'mock invalid response')
264
+
265
+ const schema = createSchema({
266
+ types: [
267
+ {
268
+ name: 'post',
269
+ title: 'Post',
270
+ type: 'document',
271
+ fields: [
272
+ {name: 'title', type: 'string'},
273
+ {name: 'body', type: 'string'},
274
+ ],
275
+ },
276
+ {
277
+ name: 'registeredEditor',
278
+ type: 'object',
279
+ title: 'Registered Editor',
280
+ fields: [
281
+ {
282
+ name: 'editor',
283
+ type: 'array',
284
+ of: [
285
+ {
286
+ type: 'block',
287
+ marks: {
288
+ annotations: [
289
+ {
290
+ name: 'exampleAnnotation',
291
+ type: 'object',
292
+ fields: [{name: 'value', type: 'string'}],
293
+ },
294
+ ],
295
+ },
296
+ },
297
+ ],
298
+ },
299
+ ],
300
+ },
301
+ {
302
+ name: 'blockTest',
303
+ type: 'document',
304
+ title: 'blockTest',
305
+ fields: [
306
+ {
307
+ name: 'content',
308
+ title: 'Content',
309
+ type: 'array',
310
+ of: [
311
+ {
312
+ type: 'block',
313
+ marks: {
314
+ annotations: [
315
+ {
316
+ name: 'link',
317
+ type: 'object',
318
+ title: 'link',
319
+ fields: [{name: 'url', type: 'url'}],
320
+ validation: (rule: Rule) => rule.custom(linkValidationSpy),
321
+ },
322
+ {
323
+ name: 'internalLink',
324
+ type: 'object',
325
+ title: 'Internal link',
326
+ fields: [{name: 'reference', type: 'reference', to: [{type: 'post'}]}],
327
+ validation: (rule: Rule) => rule.custom(internalLinkSpy),
328
+ },
329
+ {name: 'nestedEditor', type: 'registeredEditor'},
330
+ ],
331
+ },
332
+ },
333
+ ],
334
+ },
335
+ ],
336
+ },
337
+ ],
338
+ })
339
+
340
+ expect(schema._validation).toHaveLength(0)
341
+
342
+ const nestedBlock: Block = {
343
+ _type: 'block',
344
+ _key: 'nested-block-key',
345
+ children: [
346
+ {
347
+ _key: 'some-key',
348
+ _type: 'span',
349
+ text: 'hey',
350
+ marks: ['example-annotation-key'],
351
+ },
352
+ ],
353
+ markDefs: [
354
+ {
355
+ _type: 'exampleAnnotation',
356
+ _key: 'example-annotation-key',
357
+ value: 5,
358
+ },
359
+ ],
360
+ style: 'normal',
361
+ }
362
+
363
+ const block: Block = {
364
+ _key: 'block-key',
365
+ _type: 'block',
366
+ children: [
367
+ {
368
+ _key: 'child-0',
369
+ _type: 'span',
370
+ marks: ['0', '1', '2'],
371
+ text: 'hey',
372
+ },
373
+ ],
374
+ markDefs: [
375
+ {
376
+ _key: '0',
377
+ _type: 'link',
378
+ url: 'https://example.com',
379
+ },
380
+ {
381
+ _key: '1',
382
+ _type: 'internalLink',
383
+ _ref: 'post-id',
384
+ },
385
+ {
386
+ _key: '2',
387
+ _type: 'nestedEditor',
388
+ editor: [nestedBlock],
389
+ },
390
+ ],
391
+ style: 'normal',
392
+ }
393
+
394
+ const document: SanityDocument = {
395
+ _id: 'mock-id',
396
+ _type: 'blockTest',
397
+ _createdAt: '2021-11-15T21:06:41.812Z',
398
+ _rev: 'example-ref',
399
+ _updatedAt: '2021-11-15T21:06:41.812Z',
400
+ content: [block],
401
+ }
402
+
403
+ const result = await validateItem({
404
+ document: document,
405
+ parent: undefined,
406
+ path: [],
407
+ type: schema.get('blockTest'),
408
+ value: document,
409
+ })
410
+
411
+ expect(result).toMatchObject([
412
+ {
413
+ item: {message: 'mock invalid response', paths: []},
414
+ level: 'error',
415
+ path: ['content', {_key: 'block-key'}, 'markDefs', {_key: '1'}],
416
+ type: 'validation',
417
+ },
418
+ // this tests for nested markDef validation
419
+ {
420
+ item: {
421
+ message: 'Expected type "String", got "Number"',
422
+ paths: [],
423
+ },
424
+ level: 'error',
425
+ path: [
426
+ 'content',
427
+ {_key: 'block-key'},
428
+ 'markDefs',
429
+ {_key: '2'},
430
+ 'editor',
431
+ {_key: 'nested-block-key'},
432
+ 'markDefs',
433
+ {_key: 'example-annotation-key'},
434
+ 'value',
435
+ ],
436
+ type: 'validation',
437
+ },
438
+ ])
439
+
440
+ expect(linkValidationSpy.mock.calls).toMatchObject([
441
+ [
442
+ {
443
+ _key: '0',
444
+ _type: 'link',
445
+ url: 'https://example.com',
446
+ },
447
+ {
448
+ document: {_id: 'mock-id'},
449
+ parent: {_key: 'block-key'},
450
+ path: ['content', {_key: 'block-key'}, 'markDefs', {_key: '0'}],
451
+ type: {name: 'link'},
452
+ },
453
+ ],
454
+ ])
455
+
456
+ expect(internalLinkSpy.mock.calls).toMatchObject([
457
+ [
458
+ {
459
+ _key: '1',
460
+ _ref: 'post-id',
461
+ _type: 'internalLink',
462
+ },
463
+ {
464
+ document: {_id: 'mock-id'},
465
+ parent: {_key: 'block-key'},
466
+ path: ['content', {_key: 'block-key'}, 'markDefs', {_key: '1'}],
467
+ type: {name: 'internalLink'},
468
+ },
469
+ ],
470
+ ])
471
+ })
472
+
255
473
  it('resolves an array item type if there is just one type', async () => {
256
474
  const schema = createSchema({
257
475
  types: [
258
476
  {
259
477
  name: 'values',
478
+ title: 'Values',
260
479
  type: 'array',
261
480
  // note that there is only one type available
262
481
  of: [{type: 'arrayItem'}],
263
482
  validation: (rule: Rule) => rule.required(),
264
483
  },
265
484
  {
485
+ title: 'Array Item',
266
486
  name: 'arrayItem',
267
487
  type: 'object',
268
488
  fields: [{name: 'title', type: 'string'}],
@@ -270,6 +490,9 @@ describe('validateItem', () => {
270
490
  ],
271
491
  })
272
492
 
493
+ // ensures there are no schema formatting issues
494
+ expect(schema._validation).toHaveLength(0)
495
+
273
496
  const values = [
274
497
  {
275
498
  // note how this doesn't have a _type
@@ -305,6 +528,7 @@ describe('validateItem', () => {
305
528
  {
306
529
  name: 'root',
307
530
  type: 'object',
531
+ title: 'Root',
308
532
  fields: [
309
533
  {
310
534
  name: 'level1Object',
@@ -341,6 +565,10 @@ describe('validateItem', () => {
341
565
  ],
342
566
  })
343
567
 
568
+ // ensures there are no schema formatting issues
569
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
570
+ expect((schema as any)._validation).toHaveLength(0)
571
+
344
572
  const value = {
345
573
  level1Object: {level3String: 'a string'},
346
574
  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'
@@ -180,9 +183,39 @@ export async function validateItem({
180
183
  )
181
184
  }
182
185
 
186
+ // markDefs also do no run nested validation if the parent object is undefined
187
+ // for a similar reason to arrays
188
+ const shouldRunNestedValidationForMarkDefs =
189
+ isBlock(value) && value.markDefs.length && isBlockSchemaType(type)
190
+
191
+ if (shouldRunNestedValidationForMarkDefs) {
192
+ const [spanChildrenField] = type.fields
193
+ const spanType = spanChildrenField.type.of.find(isSpanSchemaType)
194
+
195
+ const annotations = (spanType?.annotations || []).reduce<Map<string, SchemaType>>(
196
+ (map, annotationType) => {
197
+ map.set(annotationType.name, annotationType)
198
+ return map
199
+ },
200
+ new Map()
201
+ )
202
+
203
+ nestedChecks = nestedChecks.concat(
204
+ value.markDefs.map((markDef) =>
205
+ validateItem({
206
+ ...restOfContext,
207
+ parent: value,
208
+ value: markDef,
209
+ path: path.concat(['markDefs', {_key: markDef._key}]),
210
+ type: annotations.get(markDef._type),
211
+ })
212
+ )
213
+ )
214
+ }
215
+
183
216
  const results = (await Promise.all([...selfChecks, ...nestedChecks])).flat()
184
217
 
185
- // run `dedupeValidationMarkers` if `_fieldRules` are present because they can
218
+ // run `uniqBy` if `_fieldRules` are present because they can
186
219
  // cause repeat markers
187
220
  if (rules.some((rule) => rule._fieldRules)) {
188
221
  return uniqBy(results, (rule) => JSON.stringify(rule))
@@ -32,15 +32,6 @@ const objectValidators: Validators = {
32
32
  return true
33
33
  },
34
34
 
35
- block: async (validateBlock, value, message, context) => {
36
- const result = await validateBlock(value, context)
37
- if (typeof result === 'string') {
38
- return message || result
39
- }
40
-
41
- return result
42
- },
43
-
44
35
  assetRequired: (flag, value, message) => {
45
36
  if (!value || !value.asset || !value.asset._ref) {
46
37
  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,cAkD5B,CAAA"}
@@ -1,65 +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
- });
49
- annotationValidations.push(validations);
50
- });
51
- var results = yield Promise.all(annotationValidations);
52
- var flattened = results.flat();
53
- if (!flattened.length) return [];
54
- return flattened.map(res => {
55
- res.item.paths = [res.path];
56
- return res.item;
57
- });
58
- });
59
-
60
- return function blockValidator(_x, _x2) {
61
- return _ref.apply(this, arguments);
62
- };
63
- }();
64
-
65
- exports.blockValidator = blockValidator;
@@ -1,54 +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
- })
42
- annotationValidations.push(validations)
43
- })
44
-
45
- const results = await Promise.all(annotationValidations)
46
- const flattened = results.flat()
47
-
48
- if (!flattened.length) return []
49
-
50
- return flattened.map((res) => {
51
- res.item.paths = [res.path]
52
- return res.item
53
- })
54
- }