@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.
- package/dist/dts/Rule.d.ts.map +1 -1
- package/dist/dts/util/normalizeValidationRules.d.ts.map +1 -1
- package/dist/dts/validateDocument.d.ts.map +1 -1
- package/dist/dts/validators/objectValidator.d.ts.map +1 -1
- package/lib/Rule.js +11 -7
- package/lib/index.js +7 -7
- package/lib/util/convertToValidationMarker.js +1 -1
- package/lib/util/normalizeValidationRules.js +0 -3
- package/lib/validateDocument.js +29 -3
- package/lib/validators/dateValidator.js +1 -1
- package/lib/validators/objectValidator.js +0 -17
- package/package.json +5 -5
- package/src/Rule.ts +8 -5
- package/src/util/normalizeValidationRules.ts +0 -2
- package/src/validateDocument.test.ts +231 -2
- package/src/validateDocument.ts +34 -1
- package/src/validators/objectValidator.ts +0 -9
- package/dist/dts/validators/blockValidator.d.ts +0 -3
- package/dist/dts/validators/blockValidator.d.ts.map +0 -1
- package/lib/validators/blockValidator.js +0 -66
- package/src/validators/blockValidator.ts +0 -55
package/dist/dts/Rule.d.ts.map
CHANGED
|
@@ -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,
|
|
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;
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
package/lib/validateDocument.js
CHANGED
|
@@ -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' && (
|
|
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 `
|
|
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)) {
|
|
@@ -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.
|
|
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.
|
|
36
|
-
"@sanity/schema": "2.
|
|
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.
|
|
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": "
|
|
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}],
|
package/src/validateDocument.ts
CHANGED
|
@@ -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 `
|
|
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 +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
|
-
}
|