Skip to content

Commit

Permalink
feat(schema): add validation to disallow array members with same name…
Browse files Browse the repository at this point in the history
… as bulitin types
  • Loading branch information
bjoerge authored and rexxars committed Aug 15, 2022
1 parent 5ee4151 commit ce862bd
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 22 deletions.
45 changes: 24 additions & 21 deletions packages/@sanity/schema/src/sanity/coreTypes.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
export default [
{name: 'array', jsonType: 'array'},
{name: 'block', jsonType: 'object'},
{name: 'boolean', jsonType: 'boolean'},
{name: 'datetime', jsonType: 'string'},
{name: 'date', jsonType: 'string'},
{name: 'document', jsonType: 'object'},
{name: 'email', jsonType: 'string'},
{name: 'file', jsonType: 'object'},
{name: 'geopoint', jsonType: 'object'},
{name: 'image', jsonType: 'object'},
{name: 'number', jsonType: 'number'},
{name: 'object', jsonType: 'object'},
{name: 'reference', jsonType: 'object'},
{name: 'crossDatasetReference', jsonType: 'object'},
{name: 'slug', jsonType: 'object'},
{name: 'string', jsonType: 'string'},
{name: 'telephone', jsonType: 'string'},
{name: 'text', jsonType: 'string'},
{name: 'url', jsonType: 'string'},
].map((t) => ({...t, type: 'type'}))
const coreTypes = [
{name: 'array', jsonType: 'array', type: 'type'},
{name: 'block', jsonType: 'object', type: 'type'},
{name: 'boolean', jsonType: 'boolean', type: 'type'},
{name: 'datetime', jsonType: 'string', type: 'type'},
{name: 'date', jsonType: 'string', type: 'type'},
{name: 'document', jsonType: 'object', type: 'type'},
{name: 'email', jsonType: 'string', type: 'type'},
{name: 'file', jsonType: 'object', type: 'type'},
{name: 'geopoint', jsonType: 'object', type: 'type'},
{name: 'image', jsonType: 'object', type: 'type'},
{name: 'number', jsonType: 'number', type: 'type'},
{name: 'object', jsonType: 'object', type: 'type'},
{name: 'reference', jsonType: 'object', type: 'type'},
{name: 'crossDatasetReference', jsonType: 'object', type: 'type'},
{name: 'slug', jsonType: 'object', type: 'type'},
{name: 'string', jsonType: 'string', type: 'type'},
{name: 'telephone', jsonType: 'string', type: 'type'},
{name: 'text', jsonType: 'string', type: 'type'},
{name: 'url', jsonType: 'string', type: 'type'},
] as const

export const coreTypeNames = coreTypes.map((t) => t.name)
export default coreTypes
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export const HELP_IDS = {
ARRAY_OF_ARRAY: 'schema-array-of-array',
ARRAY_OF_INVALID: 'schema-array-of-invalid',
ARRAY_OF_NOT_UNIQUE: 'schema-array-of-invalid',
ARRAY_OF_TYPE_GLOBAL_TYPE_CONFLICT: 'schema-array-of-type-global-type-conflict',
ARRAY_OF_TYPE_BUILTIN_TYPE_CONFLICT: 'schema-array-of-type-builtin-type-conflict',
REFERENCE_TO_INVALID: 'schema-reference-to-invalid',
REFERENCE_TO_NOT_UNIQUE: 'schema-reference-to-invalid',
REFERENCE_INVALID_OPTIONS: 'schema-reference-invalid-options',
Expand Down
40 changes: 39 additions & 1 deletion packages/@sanity/schema/src/sanity/validation/types/array.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,51 @@
import {error, HELP_IDS} from '../createValidationResult'
import {error, HELP_IDS, warning} from '../createValidationResult'
import {flatten} from 'lodash'
import {getDupes} from '../utils/getDupes'
import {coreTypeNames} from '../../coreTypes'

export default (typeDef, visitorContext) => {
// name should already have been marked
const ofIsArray = Array.isArray(typeDef.of)

if (ofIsArray) {
const invalid = typeDef.of.reduce((errs, def, idx) => {
if (typeof def.name === 'string') {
// If an array member has been given a "local" type name, we want to trigger an error if the given member type name
// is one of the builtin types
//
// The following examples should be an error (where book is an existing root level type and reference is a built-in type):
// - (…) of: [{type: 'book', name: 'image'}]
// - (…) of: [{type: 'book', name: 'object'}]
// - (…) of: [{type: 'object', name: 'reference'}]
// The following examples are valid (where "address" is not defined as a global object type)
// - (…) of: [{type: 'object', name: 'address'}]
// The following examples are redundant, but should be allowed (at least for now)
// - (…) of: [{type: 'object', name: 'object'}]
// - (…) of: [{type: 'image', name: 'image'}]

if (
// specifying the same name as the type is redundant, but should not be a hard error at this point
// Consider showing a warning for this and deprecate this ability eventually
def.name !== def.type &&
coreTypeNames.includes(def.name)
) {
return errs.concat(
error(
`Found array member declaration with the same type name as a built-in type ("${def.name}"). Array members can not be given the same name as a built-in type.`,
HELP_IDS.ARRAY_OF_TYPE_BUILTIN_TYPE_CONFLICT
)
)
}
}

if (def.type === 'object' && def.name && visitorContext.getType(def.name)) {
return errs.concat(
warning(
`Found array member declaration with the same name as the global schema type "${def.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
)
)
}
if (def.type === 'array') {
return errs.concat(
error(
Expand Down

0 comments on commit ce862bd

Please sign in to comment.