Skip to content

Commit

Permalink
feature(schema): validate block children for supported object types
Browse files Browse the repository at this point in the history
Block members can not be given a type that is not a object-like type.

A type like 'string' for instance doesn't make sense inside a block child,
as they always have to be wrapped in a object.

I have identified the following supported core types:

['file', 'image', 'object', 'reference']

It is still possible to use shorthands for hoisted object-like types.
If 'author' is defined as a object elsewhere, {type: 'author'} will
still be allowed.

Everything else in the block types 'of' property
will throw a schema validation error with a listing of supported types.
  • Loading branch information
skogsmaskin committed Sep 6, 2023
1 parent 4e02847 commit 9c8bb83
Showing 1 changed file with 38 additions and 0 deletions.
38 changes: 38 additions & 0 deletions packages/@sanity/schema/src/sanity/validation/types/block.ts
Expand Up @@ -2,6 +2,7 @@ import {omit, isPlainObject} from 'lodash'
import humanizeList from 'humanize-list'
import {error, HELP_IDS, warning} from '../createValidationResult'
import {isJSONTypeOf} from '../utils/isJSONTypeOf'
import {coreTypeNames} from '../../coreTypes'

const getTypeOf = (thing) => (Array.isArray(thing) ? 'array' : typeof thing)
const quote = (str) => `"${str}"`
Expand All @@ -21,6 +22,7 @@ const allowedMarkKeys = ['decorators', 'annotations']
const allowedStyleKeys = ['blockEditor', 'title', 'value', 'component']
const allowedDecoratorKeys = ['blockEditor', 'title', 'value', 'icon', 'component']
const allowedListKeys = ['title', 'value', 'icon', 'component']
const supportedBuiltInObjectTypes = ['file', 'image', 'object', 'reference']

export default function validateBlockType(typeDef, visitorContext) {
const problems = []
Expand Down Expand Up @@ -307,6 +309,42 @@ function validateMembers(members, visitorContext, problems) {

return members.map((member) => {
const {_problems} = visitorContext.visit(member, visitorContext)
if (member.type === 'object' && member.name && visitorContext.getType(member.name)) {
return {
...member,
_problems: [
warning(
`Found array member declaration with the same name as the global schema type "${member.name}". It's recommended to use a unique name to avoid possibly incompatible data types that shares the same name.`,
HELP_IDS.ARRAY_OF_TYPE_GLOBAL_TYPE_CONFLICT,
),
],
}
}

// Test that each member is of a support object-like type
let type = member
while (type && !type.jsonType) {
type = visitorContext.getType(type.type)
}
const nonObjectCoreTypes = coreTypeNames.filter((n) => !supportedBuiltInObjectTypes.includes(n))
if (
// Must be object-like type (to validate hoisted types)
(type && type.jsonType !== 'object') ||
// Can't be a core type, or core object type that isn't supported (like 'span')
nonObjectCoreTypes.some((coreName) => coreName === member.type)
) {
return {
...member,
_problems: [
error(
`Block member types must be a supported object-like type. The following built-in types are supported: '${supportedBuiltInObjectTypes.join(
"', '",
)}'. You can also use shorthands for previously defined object types like {type: 'myObjectType'}`,
HELP_IDS.ARRAY_OF_TYPE_BUILTIN_TYPE_CONFLICT,
),
],
}
}
return {...member, _problems}
})
}

0 comments on commit 9c8bb83

Please sign in to comment.