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

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"}
@@ -3,7 +3,7 @@ import { SanityDocument, Schema, SchemaType, ValidationContext, ValidationMarker
3
3
  * @internal
4
4
  */
5
5
  export declare function resolveTypeForArrayItem(item: unknown, candidates: SchemaType[]): SchemaType | undefined;
6
- export default function validateDocument(doc: SanityDocument, schema: Schema, context?: Pick<ValidationContext, 'getDocumentExists'>): Promise<ValidationMarker[]>;
6
+ export default function validateDocument(doc: SanityDocument, schema: Schema): Promise<ValidationMarker[]>;
7
7
  /**
8
8
  * this is used make optional properties required by replacing optionals with
9
9
  * `T[P] | undefined`. this is used to prevent errors in `validateItem` where
@@ -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,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;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;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');
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"));
@@ -74,7 +74,7 @@ function resolveTypeForArrayItem(item, candidates) {
74
74
  }) || candidates.find(candidate => candidate.name === itemType) || candidates.find(candidate => candidate.name === 'object' && primitive === 'object');
75
75
  }
76
76
 
77
- function validateDocument(_x, _x2, _x3) {
77
+ function validateDocument(_x, _x2) {
78
78
  return _validateDocument.apply(this, arguments);
79
79
  }
80
80
  /**
@@ -87,7 +87,7 @@ function validateDocument(_x, _x2, _x3) {
87
87
 
88
88
 
89
89
  function _validateDocument() {
90
- _validateDocument = _asyncToGenerator(function* (doc, schema, context) {
90
+ _validateDocument = _asyncToGenerator(function* (doc, schema) {
91
91
  var documentType = schema.get(doc._type);
92
92
 
93
93
  if (!documentType) {
@@ -101,8 +101,7 @@ function _validateDocument() {
101
101
  value: doc,
102
102
  path: [],
103
103
  document: doc,
104
- type: documentType,
105
- getDocumentExists: context === null || context === void 0 ? void 0 : context.getDocumentExists
104
+ type: documentType
106
105
  });
107
106
  } catch (err) {
108
107
  console.error(err);
@@ -117,7 +116,7 @@ function _validateDocument() {
117
116
  return _validateDocument.apply(this, arguments);
118
117
  }
119
118
 
120
- function validateItem(_x4) {
119
+ function validateItem(_x3) {
121
120
  return _validateItem.apply(this, arguments);
122
121
  }
123
122
 
@@ -141,7 +140,10 @@ function _validateItem() {
141
140
  var nestedChecks = [];
142
141
  var selfIsRequired = rules.some(rule => rule.isRequired());
143
142
  var shouldRunNestedObjectValidation = // run nested validation for objects
144
- (type === null || type === void 0 ? void 0 : type.jsonType) === 'object' && (!!value || (value === null || value === undefined) && selfIsRequired);
143
+ (type === null || type === void 0 ? void 0 : type.jsonType) === 'object' && ( // if the value is truthy
144
+ !!value || // or
145
+ // (the value is null or undefined) and the top-level value is required
146
+ (value === null || value === undefined) && selfIsRequired);
145
147
 
146
148
  if (shouldRunNestedObjectValidation) {
147
149
  var fieldTypes = type.fields.reduce((acc, field) => {
@@ -190,9 +192,32 @@ function _validateItem() {
190
192
  } : value.indexOf(item)),
191
193
  type: resolveTypeForArrayItem(item, type.of)
192
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
+ }))));
193
218
  }
194
219
 
195
- 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
196
221
  // cause repeat markers
197
222
 
198
223
  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
 
@@ -5,16 +5,10 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _types = require("@sanity/types");
9
-
10
8
  var _genericValidator = _interopRequireDefault(require("./genericValidator"));
11
9
 
12
10
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
11
 
14
- 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); } }
15
-
16
- 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); }); }; }
17
-
18
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; }
19
13
 
20
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; }
@@ -37,65 +31,17 @@ var objectValidators = _objectSpread(_objectSpread({}, _genericValidator.default
37
31
 
38
32
  return true;
39
33
  },
40
- reference: function () {
41
- var _reference = _asyncToGenerator(function* (_unused, value, message, context) {
42
- if (!value) {
43
- return true;
44
- }
45
-
46
- if (!(0, _types.isReference)(value)) {
47
- return message || 'Must be a reference to a document';
48
- }
49
-
50
- var type = context.type,
51
- getDocumentExists = context.getDocumentExists;
52
-
53
- if (!type) {
54
- throw new Error("`type` was not provided in validation context");
55
- }
56
-
57
- if ('weak' in type && type.weak) {
58
- return true;
59
- }
60
-
61
- if (!getDocumentExists) {
62
- throw new Error("`getDocumentExists` was not provided in validation context");
63
- }
64
-
65
- var exists = yield getDocumentExists({
66
- id: value._ref
67
- });
68
-
69
- if (!exists) {
70
- return 'This reference must be published';
71
- }
72
-
34
+ reference: (_unused, value, message) => {
35
+ if (!value) {
73
36
  return true;
74
- });
75
-
76
- function reference(_x, _x2, _x3, _x4) {
77
- return _reference.apply(this, arguments);
78
37
  }
79
38
 
80
- return reference;
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);
39
+ if (typeof value._ref !== 'string') {
40
+ return message || 'Must be a reference to a document';
95
41
  }
96
42
 
97
- return block;
98
- }(),
43
+ return true;
44
+ },
99
45
  assetRequired: (flag, value, message) => {
100
46
  if (!value || !value.asset || !value.asset._ref) {
101
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.11-reference-updates.62+f98497b413",
3
+ "version": "2.22.3-next.5+2137cd3924",
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-next.5+2137cd3924",
36
+ "@sanity/schema": "2.22.3-next.5+2137cd3924"
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-next.5+2137cd3924",
48
48
  "date-fns": "^2.16.1",
49
49
  "lodash": "^4.17.15"
50
50
  },
51
- "gitHead": "f98497b413e20f06fcca0923f540b8ae2c8ae564"
51
+ "gitHead": "2137cd39247f34c84661c8a90dd002860f05f9cc"
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({
@@ -165,7 +168,6 @@ describe('validateItem', () => {
165
168
  path: [],
166
169
  parent: undefined,
167
170
  type: schema.get('testObj'),
168
- getDocumentExists: undefined,
169
171
  })
170
172
  ).resolves.toMatchObject([
171
173
  {
@@ -229,6 +231,9 @@ describe('validateItem', () => {
229
231
  ],
230
232
  })
231
233
 
234
+ // ensures there are no schema formatting issues
235
+ expect(schema._validation).toHaveLength(0)
236
+
232
237
  await expect(
233
238
  validateItem({
234
239
  document: undefined,
@@ -236,7 +241,6 @@ describe('validateItem', () => {
236
241
  path: undefined,
237
242
  type: schema.get('testObj'),
238
243
  value: {foo: 5},
239
- getDocumentExists: undefined,
240
244
  })
241
245
  ).resolves.toMatchObject([
242
246
  {
@@ -254,17 +258,231 @@ describe('validateItem', () => {
254
258
  ])
255
259
  })
256
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
+
257
473
  it('resolves an array item type if there is just one type', async () => {
258
474
  const schema = createSchema({
259
475
  types: [
260
476
  {
261
477
  name: 'values',
478
+ title: 'Values',
262
479
  type: 'array',
263
480
  // note that there is only one type available
264
481
  of: [{type: 'arrayItem'}],
265
482
  validation: (rule: Rule) => rule.required(),
266
483
  },
267
484
  {
485
+ title: 'Array Item',
268
486
  name: 'arrayItem',
269
487
  type: 'object',
270
488
  fields: [{name: 'title', type: 'string'}],
@@ -272,6 +490,9 @@ describe('validateItem', () => {
272
490
  ],
273
491
  })
274
492
 
493
+ // ensures there are no schema formatting issues
494
+ expect(schema._validation).toHaveLength(0)
495
+
275
496
  const values = [
276
497
  {
277
498
  // note how this doesn't have a _type
@@ -287,7 +508,6 @@ describe('validateItem', () => {
287
508
  path: [],
288
509
  type: schema.get('values'),
289
510
  value: values,
290
- getDocumentExists: undefined,
291
511
  })
292
512
  ).resolves.toEqual([
293
513
  {
@@ -308,6 +528,7 @@ describe('validateItem', () => {
308
528
  {
309
529
  name: 'root',
310
530
  type: 'object',
531
+ title: 'Root',
311
532
  fields: [
312
533
  {
313
534
  name: 'level1Object',
@@ -344,6 +565,10 @@ describe('validateItem', () => {
344
565
  ],
345
566
  })
346
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
+
347
572
  const value = {
348
573
  level1Object: {level3String: 'a string'},
349
574
  level1Array: [{level2Number: 5}],
@@ -380,7 +605,6 @@ describe('validateItem', () => {
380
605
  document,
381
606
  parent: document,
382
607
  path: undefined,
383
- getDocumentExists: undefined,
384
608
  })
385
609
  ).resolves.toMatchObject([
386
610
  {
@@ -521,7 +745,6 @@ describe('validateItem', () => {
521
745
  parent: undefined,
522
746
  path: undefined,
523
747
  type: schema.get('root'),
524
- getDocumentExists: undefined,
525
748
  })
526
749
 
527
750
  // after `validateItem(...)` has been initiated, all of the custom
@@ -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'
@@ -45,8 +48,7 @@ export function resolveTypeForArrayItem(
45
48
 
46
49
  export default async function validateDocument(
47
50
  doc: SanityDocument,
48
- schema: Schema,
49
- context?: Pick<ValidationContext, 'getDocumentExists'>
51
+ schema: Schema
50
52
  ): Promise<ValidationMarker[]> {
51
53
  const documentType = schema.get(doc._type)
52
54
  if (!documentType) {
@@ -61,7 +63,6 @@ export default async function validateDocument(
61
63
  path: [],
62
64
  document: doc,
63
65
  type: documentType,
64
- getDocumentExists: context?.getDocumentExists,
65
66
  })
66
67
  } catch (err) {
67
68
  console.error(err)
@@ -182,9 +183,39 @@ export async function validateItem({
182
183
  )
183
184
  }
184
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
+
185
216
  const results = (await Promise.all([...selfChecks, ...nestedChecks])).flat()
186
217
 
187
- // run `dedupeValidationMarkers` if `_fieldRules` are present because they can
218
+ // run `uniqBy` if `_fieldRules` are present because they can
188
219
  // cause repeat markers
189
220
  if (rules.some((rule) => rule._fieldRules)) {
190
221
  return uniqBy(results, (rule) => JSON.stringify(rule))
@@ -1,4 +1,4 @@
1
- import {Validators, isReference} from '@sanity/types'
1
+ import {Validators} from '@sanity/types'
2
2
  import genericValidator from './genericValidator'
3
3
 
4
4
  const metaKeys = ['_key', '_type', '_weak']
@@ -20,46 +20,18 @@ const objectValidators: Validators = {
20
20
  return true
21
21
  },
22
22
 
23
- reference: async (_unused, value: unknown, message, context) => {
23
+ reference: (_unused, value, message) => {
24
24
  if (!value) {
25
25
  return true
26
26
  }
27
27
 
28
- if (!isReference(value)) {
28
+ if (typeof value._ref !== 'string') {
29
29
  return message || 'Must be a reference to a document'
30
30
  }
31
31
 
32
- const {type, getDocumentExists} = context
33
-
34
- if (!type) {
35
- throw new Error(`\`type\` was not provided in validation context`)
36
- }
37
-
38
- if ('weak' in type && type.weak) {
39
- return true
40
- }
41
-
42
- if (!getDocumentExists) {
43
- throw new Error(`\`getDocumentExists\` was not provided in validation context`)
44
- }
45
-
46
- const exists = await getDocumentExists({id: value._ref})
47
- if (!exists) {
48
- return 'This reference must be published'
49
- }
50
-
51
32
  return true
52
33
  },
53
34
 
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
35
  assetRequired: (flag, value, message) => {
64
36
  if (!value || !value.asset || !value.asset._ref) {
65
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,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
- }