From 60aa9c4316d338d91df33c7db62726b69330a89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rge=20N=C3=A6ss?= Date: Tue, 22 Jun 2021 12:17:26 +0200 Subject: [PATCH] fix(validation): fix issue where object field validation were written on individual fields, causing unintended validation rule leakage --- .../validation/src/inferFromSchemaType.js | 9 ----- .../validation/src/validateDocument.js | 34 +++++++++++++++++-- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/packages/@sanity/validation/src/inferFromSchemaType.js b/packages/@sanity/validation/src/inferFromSchemaType.js index 3a4d4d8217b0..fc7cbf550e00 100644 --- a/packages/@sanity/validation/src/inferFromSchemaType.js +++ b/packages/@sanity/validation/src/inferFromSchemaType.js @@ -79,16 +79,7 @@ function inferForFields(typeDef, schema, visited) { return } - const fieldRules = typeDef.validation - .map((rule) => rule._fieldRules) - .filter(Boolean) - .reduce((acc, current) => ({fields: {...acc.fields, ...current}, hasRules: true}), { - fields: {}, - hasRules: false, - }) - typeDef.fields.forEach((field) => { - field.type.validation = fieldRules.fields[field.name] || field.type.validation inferFromSchemaType(field.type, schema, visited) }) } diff --git a/packages/@sanity/validation/src/validateDocument.js b/packages/@sanity/validation/src/validateDocument.js index cc3898d7a584..37b1837ba643 100644 --- a/packages/@sanity/validation/src/validateDocument.js +++ b/packages/@sanity/validation/src/validateDocument.js @@ -1,6 +1,7 @@ const Type = require('type-of-is') const {flatten} = require('lodash') const ValidationError = require('./ValidationError') +const Rule = require('./Rule') /* eslint-disable no-console */ module.exports = async (doc, schema) => { @@ -54,14 +55,41 @@ function validateObject(obj, type, path, options) { // Validate fields within object const fields = type.fields || [] + + const fieldRules = type.validation + .map((rule) => rule._fieldRules) + .filter(Boolean) + .reduce(Object.assign, {}) + const fieldChecks = fields.map((field) => { - const validation = field.type && field.type.validation - if (!validation) { + // field validation from the enclosing object type + + const fieldValidation = fieldRules[field.name] + if (!fieldValidation) { return [] } + const fieldPath = appendPath(path, field.name) + const fieldValue = obj[field.name] + + return fieldValidation(new Rule()) + .validate(fieldValue, { + parent: obj, + document: options.document, + path: fieldPath, + type: field.type, + }) + .then((result) => applyPath(result, fieldPath)) + }) + + const fieldTypeChecks = fields.map((field) => { + // field validation from field type const fieldPath = appendPath(path, field.name) const fieldValue = obj[field.name] + const validation = field.type && field.type.validation + if (!validation) { + return [] + } return validateItem(fieldValue, field.type, fieldPath, { parent: obj, document: options.document, @@ -70,7 +98,7 @@ function validateObject(obj, type, path, options) { }) }) - return Promise.all([...objChecks, ...fieldChecks]).then(flatten) + return Promise.all([...objChecks, ...fieldChecks, ...fieldTypeChecks]).then(flatten) } function validateArray(items, type, path, options) {