Skip to content

Commit

Permalink
[schema] Validate file, image schema fields
Browse files Browse the repository at this point in the history
  • Loading branch information
rexxars committed Nov 30, 2019
1 parent daae65f commit ea6825e
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 20 deletions.
8 changes: 8 additions & 0 deletions packages/@sanity/schema/src/sanity/groupProblems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ function createTypeWithMembersProblemsAccessor(
const arrify = val => (Array.isArray(val) ? val : (typeof val === 'undefined' && []) || [val])

const getObjectProblems = createTypeWithMembersProblemsAccessor('fields')
const getImageProblems = createTypeWithMembersProblemsAccessor('fields')
const getFileProblems = createTypeWithMembersProblemsAccessor('fields')
const getArrayProblems = createTypeWithMembersProblemsAccessor('of')
const getReferenceProblems = createTypeWithMembersProblemsAccessor('to', type => arrify(type.to))
const getBlockAnnotationProblems = createTypeWithMembersProblemsAccessor('marks.annotations')
Expand Down Expand Up @@ -70,6 +72,12 @@ export function getTypeProblems(type, path = []): TypeWithProblems[] {
case 'block': {
return getBlockProblems(type, path)
}
case 'image': {
return getImageProblems(type, path)
}
case 'file': {
return getFileProblems(type, path)
}
default: {
return getDefaultProblems(type, path)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const HELP_IDS = {
OBJECT_FIELDS_INVALID: 'schema-object-fields-invalid',
OBJECT_FIELD_NOT_UNIQUE: 'schema-object-fields-invalid',
OBJECT_FIELD_NAME_INVALID: 'schema-object-fields-invalid',
OBJECT_FIELD_DEFINITION_INVALID_TYPE: 'schema-object-fields-invalid',
ARRAY_OF_ARRAY: 'schema-array-of-array',
ARRAY_OF_INVALID: 'schema-array-of-invalid',
ARRAY_OF_NOT_UNIQUE: 'schema-array-of-invalid',
Expand Down
15 changes: 15 additions & 0 deletions packages/@sanity/schema/src/sanity/validation/types/file.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import {error, HELP_IDS} from '../createValidationResult'
import {validateFields, validateField} from './object'

export default (typeDef, visitorContext) => {
const problems = []
let fields = typeDef.fields

if (fields) {
problems.push(...validateFields(fields, {allowEmpty: true}))
}

if (
typeDef.options &&
Expand All @@ -18,6 +24,15 @@ export default (typeDef, visitorContext) => {

return {
...typeDef,
fields: (Array.isArray(fields) ? fields : []).map(field => {
const {name, ...fieldTypeDef} = field
const {_problems, ...fieldType} = visitorContext.visit(fieldTypeDef, visitorContext)
return {
name,
...fieldType,
_problems: validateField(field, visitorContext).concat(_problems || [])
}
}),
_problems: problems
}
}
15 changes: 15 additions & 0 deletions packages/@sanity/schema/src/sanity/validation/types/image.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import {error, HELP_IDS} from '../createValidationResult'
import {validateFields, validateField} from './object'

export default (typeDef, visitorContext) => {
const problems = []
let fields = typeDef.fields

if (fields) {
problems.push(...validateFields(fields, {allowEmpty: true}))
}

if (
typeDef.options &&
Expand All @@ -18,6 +24,15 @@ export default (typeDef, visitorContext) => {

return {
...typeDef,
fields: (Array.isArray(fields) ? fields : []).map(field => {
const {name, ...fieldTypeDef} = field
const {_problems, ...fieldType} = visitorContext.visit(fieldTypeDef, visitorContext)
return {
name,
...fieldType,
_problems: validateField(field, visitorContext).concat(_problems || [])
}
}),
_problems: problems
}
}
57 changes: 37 additions & 20 deletions packages/@sanity/schema/src/sanity/validation/types/object.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {isPlainObject} from 'lodash'
import {error, HELP_IDS, warning} from '../createValidationResult'
import inspect from '../../inspect'

Expand Down Expand Up @@ -47,7 +48,16 @@ function validateFieldName(name): Array<any> {
return []
}

function validateField(field, visitorContext) {
export function validateField(field, visitorContext) {
if (!isPlainObject(field)) {
return [
error(
`Incorrect type for field definition - should be an object, saw ${inspect(field)}`,
HELP_IDS.OBJECT_FIELD_DEFINITION_INVALID_TYPE
)
]
}

const {name, fieldset, ...fieldType} = field
return 'name' in field
? validateFieldName(name)
Expand All @@ -67,32 +77,39 @@ function getDuplicateFields(array: Array<Field>): Array<Array<Field>> {
.filter(Boolean)
}

export default (typeDef, visitorContext) => {
export function validateFields(fields: any, options = {allowEmpty: false}) {
const problems = []
const fieldsIsArray = Array.isArray(typeDef.fields)
if (fieldsIsArray) {
const fieldsWithNames = typeDef.fields.filter(field => typeof field.name === 'string')

getDuplicateFields(fieldsWithNames).forEach(dupes => {
problems.push(
error(
`Found ${dupes.length} fields with name "${dupes[0].name}" in object`,
HELP_IDS.OBJECT_FIELD_NOT_UNIQUE
)
const fieldsIsArray = Array.isArray(fields)
if (!fieldsIsArray) {
return [
error(
`The "fields" property must be an array of fields. Instead saw "${typeof fields}"`,
HELP_IDS.OBJECT_FIELDS_INVALID
)
})
if (typeDef.fields.length === 0) {
problems.push(error('Object should have at least one field', HELP_IDS.OBJECT_FIELDS_INVALID))
}
} else {
]
}

const fieldsWithNames = fields.filter(field => typeof field.name === 'string')

getDuplicateFields(fieldsWithNames).forEach(dupes => {
problems.push(
error(
`The "fields" property must be an array of fields. Instead saw "${typeof typeDef.fields}"`,
HELP_IDS.OBJECT_FIELDS_INVALID
`Found ${dupes.length} fields with name "${dupes[0].name}" in object`,
HELP_IDS.OBJECT_FIELD_NOT_UNIQUE
)
)
})

if (fields.length === 0 && !options.allowEmpty) {
problems.push(error('Object should have at least one field', HELP_IDS.OBJECT_FIELDS_INVALID))
}

return problems
}

export default (typeDef, visitorContext) => {
const problems = validateFields(typeDef.fields)

if (typeDef.type !== 'document' && typeof typeDef.initialValue !== 'undefined') {
problems.push(
error(`The "initialValue" property is currently only supported for document types.`)
Expand All @@ -101,7 +118,7 @@ export default (typeDef, visitorContext) => {

return {
...typeDef,
fields: (fieldsIsArray ? typeDef.fields : []).map(field => {
fields: (Array.isArray(typeDef.fields) ? typeDef.fields : []).map(field => {
const {name, ...fieldTypeDef} = field
const {_problems, ...fieldType} = visitorContext.visit(fieldTypeDef, visitorContext)
return {
Expand Down

0 comments on commit ea6825e

Please sign in to comment.