@sanity/schema
Version:
1 lines • 149 kB
Source Map (JSON)
{"version":3,"file":"_internal.mjs","sources":["../src/legacy/actionUtils.ts","../src/sanity/builtinTypes/assetSourceData.ts","../src/sanity/builtinTypes/fileAsset.ts","../src/sanity/builtinTypes/geopoint.ts","../src/sanity/builtinTypes/imageAsset.ts","../src/sanity/builtinTypes/imageCrop.ts","../src/sanity/builtinTypes/imageDimensions.ts","../src/sanity/builtinTypes/imageHotspot.ts","../src/sanity/builtinTypes/imageMetadata.ts","../src/sanity/builtinTypes/imagePalette.ts","../src/sanity/builtinTypes/imagePaletteSwatch.ts","../src/sanity/builtinTypes/slug.ts","../src/sanity/builtinTypes/index.ts","../src/sanity/extractSchema.ts","../src/sanity/validation/createValidationResult.ts","../src/sanity/groupProblems.ts","../src/sanity/validation/utils/getDupes.ts","../src/core/traverseSchema.ts","../src/sanity/coreTypes.ts","../src/sanity/traverseSchema.ts","../src/sanity/validation/types/array.ts","../src/sanity/validation/utils/isJSONTypeOf.ts","../src/sanity/validation/types/block.ts","../src/sanity/validation/utils/validateNonObjectFieldsProp.ts","../src/sanity/validation/utils/validateTypeName.ts","../src/sanity/validation/types/deprecated.ts","../src/sanity/validation/types/common.ts","../src/sanity/validation/types/crossDatasetReference.ts","../src/sanity/validation/utils/isComponent.ts","../src/sanity/validation/utils/validateComponent.ts","../src/sanity/validation/types/object.ts","../src/sanity/validation/types/document.ts","../src/sanity/validation/types/file.ts","../src/sanity/validation/types/globalDocumentReference.ts","../src/sanity/validation/types/image.ts","../src/sanity/validation/types/reference.ts","../src/sanity/validation/types/rootType.ts","../src/sanity/validation/types/slug.ts","../src/sanity/validateSchema.ts","../src/sanity/validateMediaLibraryAssetAspect.ts"],"sourcesContent":["import {generateHelpUrl} from '@sanity/generate-help-url'\nimport {type SchemaType} from '@sanity/types'\nimport {difference} from 'lodash'\n\nconst ACTIONS_FLAG = '__experimental_actions'\n\nconst DEFAULT_ACTIONS = ['create', 'update', 'delete', 'publish']\nconst VALID_ACTIONS = DEFAULT_ACTIONS\n\n// todo: enable this when officially deprecating experimental actions\nconst DEPRECATE_EXPERIMENTAL_ACTIONS = false\n\nconst hasWarned = {}\nconst readActions = (schemaType: SchemaType): string[] => {\n if (DEPRECATE_EXPERIMENTAL_ACTIONS && !(schemaType.name in hasWarned)) {\n console.warn(`Heads up! Experimental actions is now deprecated and replaced by Document Actions. Read more about how to migrate on ${generateHelpUrl(\n 'experimental-actions-replaced-by-document-actions',\n )}\".\n`)\n ;(hasWarned as any)[schemaType.name] = true\n }\n\n return ACTIONS_FLAG in schemaType ? (schemaType[ACTIONS_FLAG] as string[]) : DEFAULT_ACTIONS\n}\n\nconst validateActions = (typeName: string, actions: string[]) => {\n if (!Array.isArray(actions)) {\n throw new Error(\n `The value of <type>.${ACTIONS_FLAG} should be an array with any of the actions ${VALID_ACTIONS.join(\n ', ',\n )}`,\n )\n }\n\n const invalid = difference(actions, VALID_ACTIONS)\n\n if (invalid.length > 0) {\n throw new Error(\n `Invalid action${\n invalid.length > 1 ? 's' : ''\n } configured for schema type \"${typeName}\": ${invalid.join(\n ', ',\n )}. Valid actions are: ${VALID_ACTIONS.join(', ')}`,\n )\n }\n\n return actions\n}\n\nexport const resolveEnabledActions = (schemaType: SchemaType): string[] =>\n validateActions(schemaType.name, readActions(schemaType))\n\nexport const isActionEnabled = (schemaType: SchemaType, action: string): boolean =>\n resolveEnabledActions(schemaType).includes(action)\n","export default {\n name: 'sanity.assetSourceData',\n title: 'Asset Source Data',\n type: 'object',\n fields: [\n {\n name: 'name',\n title: 'Source name',\n description: 'A canonical name for the source this asset is originating from',\n type: 'string',\n },\n {\n name: 'id',\n title: 'Asset Source ID',\n description:\n 'The unique ID for the asset within the originating source so you can programatically find back to it',\n type: 'string',\n },\n {\n name: 'url',\n title: 'Asset information URL',\n description: 'A URL to find more information about this asset in the originating source',\n type: 'string',\n },\n ],\n}\n","export default {\n name: 'sanity.fileAsset',\n title: 'File',\n type: 'document',\n fieldsets: [\n {\n name: 'system',\n title: 'System fields',\n description: 'These fields are managed by the system and not editable',\n },\n ],\n fields: [\n {\n name: 'originalFilename',\n type: 'string',\n title: 'Original file name',\n readOnly: true,\n },\n {\n name: 'label',\n type: 'string',\n title: 'Label',\n },\n {\n name: 'title',\n type: 'string',\n title: 'Title',\n },\n {\n name: 'description',\n type: 'string',\n title: 'Description',\n },\n {\n name: 'altText',\n type: 'string',\n title: 'Alternative text',\n },\n {\n name: 'sha1hash',\n type: 'string',\n title: 'SHA1 hash',\n readOnly: true,\n fieldset: 'system',\n },\n {\n name: 'extension',\n type: 'string',\n title: 'File extension',\n readOnly: true,\n fieldset: 'system',\n },\n {\n name: 'mimeType',\n type: 'string',\n title: 'Mime type',\n readOnly: true,\n fieldset: 'system',\n },\n {\n name: 'size',\n type: 'number',\n title: 'File size in bytes',\n readOnly: true,\n fieldset: 'system',\n },\n {\n name: 'assetId',\n type: 'string',\n title: 'Asset ID',\n readOnly: true,\n fieldset: 'system',\n },\n {\n name: 'uploadId',\n type: 'string',\n readOnly: true,\n hidden: true,\n fieldset: 'system',\n },\n {\n name: 'path',\n type: 'string',\n title: 'Path',\n readOnly: true,\n fieldset: 'system',\n },\n {\n name: 'url',\n type: 'string',\n title: 'Url',\n readOnly: true,\n fieldset: 'system',\n },\n {\n name: 'source',\n type: 'sanity.assetSourceData',\n title: 'Source',\n readOnly: true,\n fieldset: 'system',\n },\n ],\n preview: {\n select: {\n title: 'originalFilename',\n path: 'path',\n mimeType: 'mimeType',\n size: 'size',\n },\n prepare(doc: Record<string, any>) {\n return {\n title: doc.title || doc.path.split('/').slice(-1)[0],\n subtitle: `${doc.mimeType} (${(doc.size / 1024 / 1024).toFixed(2)} MB)`,\n }\n },\n },\n orderings: [\n {\n title: 'File size',\n name: 'fileSizeDesc',\n by: [{field: 'size', direction: 'desc'}],\n },\n ],\n}\n","export default {\n title: 'Geographical Point',\n name: 'geopoint',\n type: 'object',\n fields: [\n {\n name: 'lat',\n type: 'number',\n title: 'Latitude',\n },\n {\n name: 'lng',\n type: 'number',\n title: 'Longitude',\n },\n {\n name: 'alt',\n type: 'number',\n title: 'Altitude',\n },\n ],\n}\n","import {type SanityDocument} from '@sanity/types'\n\nexport default {\n name: 'sanity.imageAsset',\n title: 'Image',\n type: 'document',\n fieldsets: [\n {\n name: 'system',\n title: 'System fields',\n description: 'These fields are managed by the system and not editable',\n },\n ],\n fields: [\n {\n name: 'originalFilename',\n type: 'string',\n title: 'Original file name',\n readOnly: true,\n },\n {\n name: 'label',\n type: 'string',\n title: 'Label',\n },\n {\n name: 'title',\n type: 'string',\n title: 'Title',\n },\n {\n name: 'description',\n type: 'string',\n title: 'Description',\n },\n {\n name: 'altText',\n type: 'string',\n title: 'Alternative text',\n },\n {\n name: 'sha1hash',\n type: 'string',\n title: 'SHA1 hash',\n readOnly: true,\n fieldset: 'system',\n },\n {\n name: 'extension',\n type: 'string',\n readOnly: true,\n title: 'File extension',\n fieldset: 'system',\n },\n {\n name: 'mimeType',\n type: 'string',\n readOnly: true,\n title: 'Mime type',\n fieldset: 'system',\n },\n {\n name: 'size',\n type: 'number',\n title: 'File size in bytes',\n readOnly: true,\n fieldset: 'system',\n },\n {\n name: 'assetId',\n type: 'string',\n title: 'Asset ID',\n readOnly: true,\n fieldset: 'system',\n },\n {\n name: 'uploadId',\n type: 'string',\n readOnly: true,\n hidden: true,\n fieldset: 'system',\n },\n {\n name: 'path',\n type: 'string',\n title: 'Path',\n readOnly: true,\n fieldset: 'system',\n },\n {\n name: 'url',\n type: 'string',\n title: 'Url',\n readOnly: true,\n fieldset: 'system',\n },\n {\n name: 'metadata',\n type: 'sanity.imageMetadata',\n title: 'Metadata',\n },\n {\n name: 'source',\n type: 'sanity.assetSourceData',\n title: 'Source',\n readOnly: true,\n fieldset: 'system',\n },\n ],\n preview: {\n select: {\n id: '_id',\n title: 'originalFilename',\n mimeType: 'mimeType',\n size: 'size',\n },\n prepare(doc: Partial<SanityDocument>) {\n return {\n title: doc.title || (typeof doc.path === 'string' && doc.path.split('/').slice(-1)[0]),\n media: {asset: {_ref: doc.id}},\n subtitle: `${doc.mimeType} (${(Number(doc.size) / 1024 / 1024).toFixed(2)} MB)`,\n }\n },\n },\n orderings: [\n {\n title: 'File size',\n name: 'fileSizeDesc',\n by: [{field: 'size', direction: 'desc'}],\n },\n ],\n}\n","export default {\n name: 'sanity.imageCrop',\n title: 'Image crop',\n type: 'object',\n fields: [\n {\n name: 'top',\n type: 'number',\n },\n {\n name: 'bottom',\n type: 'number',\n },\n {\n name: 'left',\n type: 'number',\n },\n {\n name: 'right',\n type: 'number',\n },\n ],\n}\n","export default {\n name: 'sanity.imageDimensions',\n type: 'object',\n title: 'Image dimensions',\n fields: [\n {name: 'height', type: 'number', title: 'Height', readOnly: true},\n {name: 'width', type: 'number', title: 'Width', readOnly: true},\n {name: 'aspectRatio', type: 'number', title: 'Aspect ratio', readOnly: true},\n ],\n}\n","export default {\n name: 'sanity.imageHotspot',\n title: 'Image hotspot',\n type: 'object',\n fields: [\n {\n name: 'x',\n type: 'number',\n },\n {\n name: 'y',\n type: 'number',\n },\n {\n name: 'height',\n type: 'number',\n },\n {\n name: 'width',\n type: 'number',\n },\n ],\n}\n","export default {\n name: 'sanity.imageMetadata',\n title: 'Image metadata',\n type: 'object',\n fieldsets: [\n {\n name: 'extra',\n title: 'Extra metadata…',\n options: {\n collapsable: true,\n },\n },\n ],\n fields: [\n {\n name: 'location',\n type: 'geopoint',\n },\n {\n name: 'dimensions',\n title: 'Dimensions',\n type: 'sanity.imageDimensions',\n fieldset: 'extra',\n },\n {\n name: 'palette',\n type: 'sanity.imagePalette',\n title: 'Palette',\n fieldset: 'extra',\n },\n {\n name: 'lqip',\n title: 'LQIP (Low-Quality Image Placeholder)',\n type: 'string',\n readOnly: true,\n },\n {\n name: 'blurHash',\n title: 'BlurHash',\n type: 'string',\n readOnly: true,\n },\n {\n name: 'hasAlpha',\n title: 'Has alpha channel',\n type: 'boolean',\n readOnly: true,\n },\n {\n name: 'isOpaque',\n title: 'Is opaque',\n type: 'boolean',\n readOnly: true,\n },\n ],\n}\n","export default {\n name: 'sanity.imagePalette',\n title: 'Image palette',\n type: 'object',\n fields: [\n {name: 'darkMuted', type: 'sanity.imagePaletteSwatch', title: 'Dark Muted'},\n {name: 'lightVibrant', type: 'sanity.imagePaletteSwatch', title: 'Light Vibrant'},\n {name: 'darkVibrant', type: 'sanity.imagePaletteSwatch', title: 'Dark Vibrant'},\n {name: 'vibrant', type: 'sanity.imagePaletteSwatch', title: 'Vibrant'},\n {name: 'dominant', type: 'sanity.imagePaletteSwatch', title: 'Dominant'},\n {name: 'lightMuted', type: 'sanity.imagePaletteSwatch', title: 'Light Muted'},\n {name: 'muted', type: 'sanity.imagePaletteSwatch', title: 'Muted'},\n ],\n}\n","export default {\n name: 'sanity.imagePaletteSwatch',\n title: 'Image palette swatch',\n type: 'object',\n fields: [\n {name: 'background', type: 'string', title: 'Background', readOnly: true},\n {name: 'foreground', type: 'string', title: 'Foreground', readOnly: true},\n {name: 'population', type: 'number', title: 'Population', readOnly: true},\n {name: 'title', type: 'string', title: 'String', readOnly: true},\n ],\n}\n","import {type Rule} from '@sanity/types'\n\nexport default {\n title: 'Slug',\n name: 'slug',\n type: 'object',\n fields: [\n {\n name: 'current',\n title: 'Current slug',\n type: 'string',\n validation: (Rule: Rule): Rule => Rule.required(),\n },\n {\n // The source field is deprecated/unused, but leaving it included and hidden\n // to prevent rendering \"Unknown field\" warnings on legacy data\n name: 'source',\n title: 'Source field',\n type: 'string',\n hidden: true,\n },\n ],\n}\n","import assetSourceData from './assetSourceData'\nimport fileAsset from './fileAsset'\nimport geopoint from './geopoint'\nimport imageAsset from './imageAsset'\nimport imageCrop from './imageCrop'\nimport imageDimensions from './imageDimensions'\nimport imageHotspot from './imageHotspot'\nimport imageMetadata from './imageMetadata'\nimport imagePalette from './imagePalette'\nimport imagePaletteSwatch from './imagePaletteSwatch'\nimport slug from './slug'\n\nexport const builtinTypes = [\n assetSourceData,\n slug,\n geopoint,\n // legacyRichDate,\n imageAsset,\n fileAsset,\n imageCrop,\n imageHotspot,\n imageMetadata,\n imageDimensions,\n imagePalette,\n imagePaletteSwatch,\n]\n","import {\n type ArraySchemaType,\n type NumberSchemaType,\n type ObjectField,\n type ObjectFieldType,\n type ObjectSchemaType,\n type ReferenceSchemaType,\n type Rule,\n type Schema as SchemaDef,\n type SchemaType as SanitySchemaType,\n type StringSchemaType,\n} from '@sanity/types'\nimport {\n type ArrayTypeNode,\n createReferenceTypeNode,\n type DocumentSchemaType,\n type InlineTypeNode,\n type NullTypeNode,\n type NumberTypeNode,\n type ObjectAttribute,\n type ObjectTypeNode,\n type SchemaType,\n type StringTypeNode,\n type TypeDeclarationSchemaType,\n type TypeNode,\n type UnionTypeNode,\n type UnknownTypeNode,\n} from 'groq-js'\n\nconst documentDefaultFields = (typeName: string): Record<string, ObjectAttribute> => ({\n _id: {\n type: 'objectAttribute',\n value: {type: 'string'},\n },\n _type: {\n type: 'objectAttribute',\n value: {type: 'string', value: typeName},\n },\n _createdAt: {\n type: 'objectAttribute',\n value: {type: 'string'},\n },\n _updatedAt: {\n type: 'objectAttribute',\n value: {type: 'string'},\n },\n _rev: {\n type: 'objectAttribute',\n value: {type: 'string'},\n },\n})\nconst typesMap = new Map<string, TypeNode>([\n ['text', {type: 'string'}],\n ['url', {type: 'string'}],\n ['datetime', {type: 'string'}],\n ['date', {type: 'string'}],\n ['boolean', {type: 'boolean'}],\n ['email', {type: 'string'}],\n])\n\nexport interface ExtractSchemaOptions {\n enforceRequiredFields?: boolean\n}\n\nexport function extractSchema(\n schemaDef: SchemaDef,\n extractOptions: ExtractSchemaOptions = {},\n): SchemaType {\n const inlineFields = new Set<SanitySchemaType>()\n const documentTypes = new Map<string, DocumentSchemaType>()\n const schema: SchemaType = []\n\n // get a list of all the types in the schema, sorted by their dependencies. This ensures that when we check for inline/reference types, we have already processed the type\n const sortedSchemaTypeNames = sortByDependencies(schemaDef)\n sortedSchemaTypeNames.forEach((typeName) => {\n const schemaType = schemaDef.get(typeName)\n if (schemaType === undefined) {\n return\n }\n const base = convertBaseType(schemaType)\n if (base === null) {\n return\n }\n if (base.type === 'type') {\n inlineFields.add(schemaType)\n }\n if (base.type === 'document') {\n documentTypes.set(typeName, base)\n }\n\n schema.push(base)\n })\n\n function convertBaseType(\n schemaType: SanitySchemaType,\n ): DocumentSchemaType | TypeDeclarationSchemaType | null {\n let typeName: string | undefined\n if (schemaType.type) {\n typeName = schemaType.type.name\n } else if ('jsonType' in schemaType) {\n typeName = schemaType.jsonType\n }\n\n if (typeName === 'document' && isObjectType(schemaType)) {\n const defaultAttributes = documentDefaultFields(schemaType.name)\n\n const object = createObject(schemaType)\n if (object.type === 'unknown') {\n return null\n }\n\n return {\n name: schemaType.name,\n type: 'document',\n attributes: {\n ...defaultAttributes,\n ...object.attributes,\n },\n }\n }\n\n const value = convertSchemaType(schemaType)\n if (value.type === 'unknown') {\n return null\n }\n if (value.type === 'object') {\n return {\n name: schemaType.name,\n type: 'type',\n value: {\n type: 'object',\n attributes: {\n _type: {\n type: 'objectAttribute',\n value: {\n type: 'string',\n value: schemaType.name,\n },\n },\n ...value.attributes,\n },\n },\n }\n }\n\n return {\n name: schemaType.name,\n type: 'type',\n value,\n }\n }\n\n function convertSchemaType(schemaType: SanitySchemaType): TypeNode {\n // if we have already seen the base type, we can just reference it\n if (inlineFields.has(schemaType.type!)) {\n return {type: 'inline', name: schemaType.type!.name} satisfies InlineTypeNode\n }\n\n // If we have a type that is point to a type, that is pointing to a type, we assume this is a circular reference\n // and we return an inline type referencing it instead\n if (schemaType.type?.type?.name === 'object') {\n return {type: 'inline', name: schemaType.type.name} satisfies InlineTypeNode\n }\n\n if (isStringType(schemaType)) {\n return createStringTypeNodeDefintion(schemaType)\n }\n\n if (isNumberType(schemaType)) {\n return createNumberTypeNodeDefintion(schemaType)\n }\n\n // map some known types\n if (schemaType.type && typesMap.has(schemaType.type.name)) {\n return typesMap.get(schemaType.type.name)!\n }\n\n // Cross dataset references are not supported\n if (isCrossDatasetReferenceType(schemaType)) {\n return {type: 'unknown'} satisfies UnknownTypeNode // we don't support cross-dataset references at the moment\n }\n\n // Global document references are not supported\n if (isGlobalDocumentReferenceType(schemaType)) {\n return {type: 'unknown'} satisfies UnknownTypeNode // we don't support global document references at the moment\n }\n\n if (isReferenceType(schemaType)) {\n return createReferenceTypeNodeDefintion(schemaType)\n }\n\n if (isArrayType(schemaType)) {\n return createArray(schemaType)\n }\n\n if (isObjectType(schemaType)) {\n return createObject(schemaType)\n }\n\n if (lastType(schemaType)?.name === 'document') {\n const doc = documentTypes.get(schemaType.name)\n if (doc === undefined) {\n return {type: 'unknown'} satisfies UnknownTypeNode\n }\n return {type: 'object', attributes: doc?.attributes} satisfies ObjectTypeNode\n }\n\n throw new Error(`Type \"${schemaType.name}\" not found`)\n }\n\n function createObject(\n schemaType: ObjectSchemaType | SanitySchemaType,\n ): ObjectTypeNode | UnknownTypeNode {\n const attributes: Record<string, ObjectAttribute> = {}\n\n const fields = gatherFields(schemaType)\n for (const field of fields) {\n const fieldIsRequired = isFieldRequired(field)\n const value = convertSchemaType(field.type)\n if (value === null) {\n continue\n }\n\n // if the field sets assetRequired() we will mark the asset attribute as required\n // also guard against the case where the field is not an object, though type validation should catch this\n if (hasAssetRequired(field) && value.type === 'object') {\n value.attributes.asset.optional = false\n }\n\n // if we extract with enforceRequiredFields, we will mark the field as optional only if it is not a required field,\n // else we will always mark it as optional\n const optional = extractOptions.enforceRequiredFields ? fieldIsRequired === false : true\n\n attributes[field.name] = {\n type: 'objectAttribute',\n value,\n optional,\n }\n }\n\n // Ignore empty objects\n if (Object.keys(attributes).length === 0) {\n return {type: 'unknown'} satisfies UnknownTypeNode\n }\n\n if (schemaType.type?.name !== 'document' && schemaType.name !== 'object') {\n attributes._type = {\n type: 'objectAttribute',\n value: {\n type: 'string',\n value: schemaType.name,\n },\n }\n }\n\n return {\n type: 'object',\n attributes,\n }\n }\n\n function createArray(arraySchemaType: ArraySchemaType): ArrayTypeNode | NullTypeNode {\n const of: TypeNode[] = []\n for (const item of arraySchemaType.of) {\n const field = convertSchemaType(item)\n if (field.type === 'inline') {\n of.push({\n type: 'object',\n attributes: {\n _key: createKeyField(),\n },\n rest: field,\n } satisfies ObjectTypeNode)\n } else if (field.type === 'object') {\n field.rest = {\n type: 'object',\n attributes: {\n _key: createKeyField(),\n },\n }\n of.push(field)\n } else {\n of.push(field)\n }\n }\n\n if (of.length === 0) {\n return {type: 'null'}\n }\n\n return {\n type: 'array',\n of:\n of.length > 1\n ? {\n type: 'union',\n of,\n }\n : of[0],\n }\n }\n\n return schema\n}\n\nfunction createKeyField(): ObjectAttribute<StringTypeNode> {\n return {\n type: 'objectAttribute',\n value: {\n type: 'string',\n },\n }\n}\n\nfunction isFieldRequired(field: ObjectField): boolean {\n const {validation} = field.type\n if (!validation) {\n return false\n }\n const rules = Array.isArray(validation) ? validation : [validation]\n for (const rule of rules) {\n let required = false\n\n // hack to check if a field is required. We create a proxy that returns itself when a method is called,\n // if the method is \"required\" we set a flag\n const proxy = new Proxy(\n {},\n {\n get: (target, methodName) => () => {\n if (methodName === 'required') {\n required = true\n }\n return proxy\n },\n },\n ) as Rule\n\n if (typeof rule === 'function') {\n rule(proxy)\n if (required) {\n return true\n }\n }\n\n if (typeof rule === 'object' && rule !== null && '_required' in rule) {\n if (rule._required === 'required') {\n return true\n }\n }\n }\n\n return false\n}\n\nfunction hasAssetRequired(field: ObjectField): boolean {\n const {validation} = field.type\n if (!validation) {\n return false\n }\n const rules = Array.isArray(validation) ? validation : [validation]\n for (const rule of rules) {\n let assetRequired = false\n\n // hack to check if a field is required. We create a proxy that returns itself when a method is called,\n // if the method is \"required\" we set a flag\n const proxy = new Proxy(\n {},\n {\n get: (target, methodName) => () => {\n if (methodName === 'assetRequired') {\n assetRequired = true\n }\n return proxy\n },\n },\n ) as Rule\n\n if (typeof rule === 'function') {\n rule(proxy)\n if (assetRequired) {\n return true\n }\n }\n\n if (\n typeof rule === 'object' &&\n rule !== null &&\n '_rules' in rule &&\n Array.isArray(rule._rules)\n ) {\n if (rule._rules.some((r) => r.flag === 'assetRequired')) {\n return true\n }\n }\n }\n\n return false\n}\n\nfunction isObjectType(typeDef: SanitySchemaType): typeDef is ObjectSchemaType {\n return isType(typeDef, 'object') || typeDef.jsonType === 'object' || 'fields' in typeDef\n}\nfunction isArrayType(typeDef: SanitySchemaType): typeDef is ArraySchemaType {\n return isType(typeDef, 'array')\n}\nfunction isReferenceType(typeDef: SanitySchemaType): typeDef is ReferenceSchemaType {\n return isType(typeDef, 'reference')\n}\nfunction isCrossDatasetReferenceType(typeDef: SanitySchemaType) {\n return isType(typeDef, 'crossDatasetReference')\n}\nfunction isGlobalDocumentReferenceType(typeDef: SanitySchemaType) {\n return isType(typeDef, 'globalDocumentReference')\n}\nfunction isStringType(typeDef: SanitySchemaType): typeDef is StringSchemaType {\n return isType(typeDef, 'string')\n}\nfunction isNumberType(typeDef: SanitySchemaType): typeDef is NumberSchemaType {\n return isType(typeDef, 'number')\n}\nfunction createStringTypeNodeDefintion(\n stringSchemaType: StringSchemaType,\n): StringTypeNode | UnionTypeNode<StringTypeNode> {\n const listOptions = stringSchemaType.options?.list\n if (listOptions && Array.isArray(listOptions)) {\n return {\n type: 'union',\n of: listOptions.map((v) => ({\n type: 'string',\n value: typeof v === 'string' ? v : v.value,\n })),\n }\n }\n return {\n type: 'string',\n }\n}\n\nfunction createNumberTypeNodeDefintion(\n numberSchemaType: NumberSchemaType,\n): NumberTypeNode | UnionTypeNode<NumberTypeNode> {\n const listOptions = numberSchemaType.options?.list\n if (listOptions && Array.isArray(listOptions)) {\n return {\n type: 'union',\n of: listOptions.map((v) => ({\n type: 'number',\n value: typeof v === 'number' ? v : v.value,\n })),\n }\n }\n return {\n type: 'number',\n }\n}\n\nfunction createReferenceTypeNodeDefintion(\n reference: ReferenceSchemaType,\n): ObjectTypeNode | UnionTypeNode<ObjectTypeNode> {\n const references = gatherReferenceNames(reference)\n if (references.length === 1) {\n return createReferenceTypeNode(references[0])\n }\n\n return {\n type: 'union',\n of: references.map((name) => createReferenceTypeNode(name)),\n }\n}\n\n// Traverse the reference type tree and gather all the reference names\nfunction gatherReferenceNames(type: ReferenceSchemaType): string[] {\n const allReferences = gatherReferenceTypes(type)\n // Remove duplicates\n return [...new Set([...allReferences.map((ref) => ref.name)])]\n}\n\nfunction gatherReferenceTypes(type: ReferenceSchemaType): ObjectSchemaType[] {\n const refTo = 'to' in type ? type.to : []\n if ('type' in type && isReferenceType(type.type!)) {\n return [...gatherReferenceTypes(type.type), ...refTo]\n }\n\n return refTo\n}\n\n// Traverse the type tree and gather all the fields\nfunction gatherFields(type: SanitySchemaType | ObjectSchemaType): ObjectField[] {\n if ('fields' in type) {\n return type.type ? gatherFields(type.type).concat(type.fields) : type.fields\n }\n\n return []\n}\n\n// Traverse the type tree and check if the type or any of its subtypes are of the given type\nfunction isType(\n typeDef: SanitySchemaType | ObjectField | ObjectFieldType,\n typeName: string,\n): boolean {\n let type: SchemaType | ObjectField | ObjectFieldType | undefined = typeDef\n while (type) {\n if (type.name === typeName || (type.type && type.type.name === typeName)) {\n return true\n }\n\n type = type.type\n }\n return false\n}\n\n// Traverse the type tree and return the \"last\" type, ie deepest type in the tree\nfunction lastType(typeDef: SanitySchemaType): SanitySchemaType | undefined {\n let type: SchemaType | ObjectField | ObjectFieldType | undefined = typeDef\n while (type) {\n if (!type.type) {\n return type\n }\n type = type.type\n }\n\n return undefined\n}\n\n// Sorts the types by their dependencies by using a topological sort depth-first algorithm.\nfunction sortByDependencies(compiledSchema: SchemaDef): string[] {\n const seen = new Set<SanitySchemaType>()\n\n // Walks the dependencies of a schema type and adds them to the dependencies set\n function walkDependencies(\n schemaType: SanitySchemaType,\n dependencies: Set<SanitySchemaType>,\n ): void {\n if (seen.has(schemaType)) {\n return\n }\n seen.add(schemaType)\n\n if ('fields' in schemaType) {\n for (const field of gatherFields(schemaType)) {\n const last = lastType(field.type)\n if (last!.name === 'document') {\n dependencies.add(last!)\n continue\n }\n\n let schemaTypeName: string | undefined\n if (schemaType.type!.type) {\n schemaTypeName = field.type.type!.name\n } else if ('jsonType' in schemaType.type!) {\n schemaTypeName = field.type.jsonType\n }\n\n if (schemaTypeName === 'object' || schemaTypeName === 'block') {\n if (isReferenceType(field.type)) {\n field.type.to.forEach((ref) => dependencies.add(ref.type!))\n } else {\n dependencies.add(field.type)\n }\n }\n walkDependencies(field.type, dependencies)\n }\n } else if ('of' in schemaType) {\n for (const item of schemaType.of) {\n walkDependencies(item, dependencies)\n }\n }\n }\n const dependencyMap = new Map<SanitySchemaType, Set<SanitySchemaType>>()\n compiledSchema.getTypeNames().forEach((typeName) => {\n const schemaType = compiledSchema.get(typeName)\n if (schemaType === undefined || schemaType.type === null) {\n return\n }\n const dependencies = new Set<SanitySchemaType>()\n\n walkDependencies(schemaType, dependencies)\n dependencyMap.set(schemaType, dependencies)\n seen.clear() // Clear the seen set for the next type\n })\n\n // Sorts the types by their dependencies\n const typeNames: string[] = []\n // holds a temporary mark for types that are currently being visited, to detect cyclic dependencies\n const currentlyVisiting = new Set<SanitySchemaType>()\n\n // holds a permanent mark for types that have been already visited\n const visited = new Set<SanitySchemaType>()\n\n // visit implements a depth-first search\n function visit(type: SanitySchemaType) {\n if (visited.has(type)) {\n return\n }\n // If we find a type that is already in the temporary mark, we have a cyclic dependency.\n if (currentlyVisiting.has(type)) {\n return\n }\n // mark this as a temporary mark, meaning it's being visited\n currentlyVisiting.add(type)\n const deps = dependencyMap.get(type)\n if (deps !== undefined) {\n deps.forEach((dep) => visit(dep))\n }\n currentlyVisiting.delete(type)\n visited.add(type)\n\n if (!typeNames.includes(type.name)) {\n typeNames.unshift(type.name)\n }\n }\n // Visit all types in the dependency map\n for (const [type] of dependencyMap) {\n visit(type)\n }\n\n return typeNames\n}\n","import {type SchemaValidationResult} from '../typedefs'\n\n// Temporary solution to ensure we have a central registry over used helpIds\nexport const HELP_IDS = {\n TYPE_INVALID: 'schema-type-invalid',\n TYPE_IS_ESM_MODULE: 'schema-type-is-esm-module',\n TYPE_NAME_RESERVED: 'schema-type-name-reserved',\n TYPE_MISSING_NAME: 'schema-type-missing-name-or-type',\n TYPE_MISSING_TYPE: 'schema-type-missing-name-or-type',\n TYPE_TITLE_RECOMMENDED: 'schema-type-title-is-recommended',\n TYPE_TITLE_INVALID: 'schema-type-title-is-recommended',\n OBJECT_FIELDS_INVALID: 'schema-object-fields-invalid',\n OBJECT_FIELD_NOT_UNIQUE: 'schema-object-fields-invalid',\n OBJECT_FIELD_NAME_INVALID: 'schema-object-fields-invalid',\n OBJECT_FIELD_DEFINITION_INVALID_TYPE: 'schema-object-fields-invalid',\n ARRAY_PREDEFINED_CHOICES_INVALID: 'schema-predefined-choices-invalid',\n ARRAY_OF_ARRAY: 'schema-array-of-array',\n ARRAY_OF_INVALID: 'schema-array-of-invalid',\n ARRAY_OF_NOT_UNIQUE: 'schema-array-of-invalid',\n ARRAY_OF_TYPE_GLOBAL_TYPE_CONFLICT: 'schema-array-of-type-global-type-conflict',\n ARRAY_OF_TYPE_BUILTIN_TYPE_CONFLICT: 'schema-array-of-type-builtin-type-conflict',\n REFERENCE_TO_INVALID: 'schema-reference-to-invalid',\n REFERENCE_TO_NOT_UNIQUE: 'schema-reference-to-invalid',\n REFERENCE_INVALID_OPTIONS: 'schema-reference-invalid-options',\n REFERENCE_INVALID_OPTIONS_LOCATION: 'schema-reference-options-nesting',\n REFERENCE_INVALID_FILTER_PARAMS_COMBINATION: 'schema-reference-filter-params-combination',\n SLUG_SLUGIFY_FN_RENAMED: 'slug-slugifyfn-renamed',\n ASSET_METADATA_FIELD_INVALID: 'asset-metadata-field-invalid',\n CROSS_DATASET_REFERENCE_INVALID: 'cross-dataset-reference-invalid',\n GLOBAL_DOCUMENT_REFERENCE_INVALID: 'global-document-reference-invalid',\n DEPRECATED_BLOCKEDITOR_KEY: 'schema-deprecated-blockeditor-key',\n STANDALONE_BLOCK_TYPE: 'schema-standalone-block-type',\n}\n\nfunction createValidationResult(\n severity: SchemaValidationResult['severity'],\n message: string,\n helpId: string | null,\n): SchemaValidationResult {\n if (helpId && !Object.keys(HELP_IDS).some((id) => (HELP_IDS as any)[id] === helpId)) {\n throw new Error(\n `Used the unknown helpId \"${helpId}\", please add it to the array in createValidationResult.js`,\n )\n }\n return {\n severity,\n message,\n helpId: helpId!,\n }\n}\n\nexport const error = (message: string, helpId?: string | null): SchemaValidationResult =>\n createValidationResult('error', message, helpId!)\n\nexport const warning = (message: string, helpId?: string | null): SchemaValidationResult =>\n createValidationResult('warning', message, helpId!)\n","import {\n type SchemaType,\n type SchemaTypeDefinition,\n type SchemaValidationProblemGroup,\n} from '@sanity/types'\nimport {flatten, get} from 'lodash'\n\nimport {type ProblemPath, type ProblemPathPropertySegment, type TypeWithProblems} from './typedefs'\nimport {error} from './validation/createValidationResult'\n\n/**\n * @internal\n */\nexport function groupProblems(types: SchemaTypeDefinition[]): SchemaValidationProblemGroup[] {\n return flatten<TypeWithProblems>(types.map((type) => getTypeProblems(type))).filter(\n (type) => type.problems.length > 0,\n )\n}\n\nfunction createTypeWithMembersProblemsAccessor(\n memberPropertyName: string,\n getMembers = (type: SchemaType) => get(type, memberPropertyName),\n) {\n return function getProblems(type: any, parentPath: ProblemPath): TypeWithProblems[] {\n const currentPath: ProblemPath = [\n ...parentPath,\n {kind: 'type', type: type.type, name: type.name},\n ]\n\n const members = getMembers(type) || []\n\n const memberProblems: TypeWithProblems[][] = Array.isArray(members)\n ? members.map((memberType) => {\n const propertySegment: ProblemPathPropertySegment = {\n kind: 'property',\n name: memberPropertyName,\n }\n const memberPath: ProblemPath = [...currentPath, propertySegment]\n return getTypeProblems(memberType, memberPath as any)\n })\n : [\n [\n {\n path: currentPath,\n problems: [error(`Member declaration (${memberPropertyName}) is not an array`)],\n },\n ],\n ]\n\n return [\n {\n path: currentPath,\n problems: type._problems || [],\n },\n ...flatten(memberProblems),\n ]\n }\n}\n\nconst arrify = (val: any) =>\n Array.isArray(val) ? val : (typeof val === 'undefined' && []) || [val]\n\nconst getObjectProblems = createTypeWithMembersProblemsAccessor('fields')\nconst getImageProblems = createTypeWithMembersProblemsAccessor('fields')\nconst getFileProblems = createTypeWithMembersProblemsAccessor('fields')\nconst getArrayProblems = createTypeWithMembersProblemsAccessor('of')\nconst getReferenceProblems = createTypeWithMembersProblemsAccessor('to', (type) =>\n 'to' in type ? arrify(type.to) : [],\n)\nconst getBlockAnnotationProblems = createTypeWithMembersProblemsAccessor('marks.annotations')\nconst getBlockMemberProblems = createTypeWithMembersProblemsAccessor('of')\nconst getBlockProblems = (type: any, problems: any) => [\n ...getBlockAnnotationProblems(type, problems),\n ...getBlockMemberProblems(type, problems),\n]\n\nfunction getDefaultProblems(type: any, path = []): TypeWithProblems[] {\n return [\n {\n path: [...path, {kind: 'type', type: type.type, name: type.name}],\n problems: type._problems || [],\n },\n ]\n}\n\nfunction getTypeProblems(type: SchemaTypeDefinition, path = []): TypeWithProblems[] {\n switch (type.type) {\n case 'object': {\n return getObjectProblems(type, path)\n }\n case 'document': {\n return getObjectProblems(type, path)\n }\n case 'array': {\n return getArrayProblems(type, path)\n }\n case 'reference': {\n return getReferenceProblems(type, path)\n }\n case 'block': {\n return getBlockProblems(type, path)\n }\n case 'image': {\n return getImageProblems(type, path)\n }\n case 'file': {\n return getFileProblems(type, path)\n }\n default: {\n return getDefaultProblems(type, path)\n }\n }\n}\n","export function getDupes(array: any, selector = (v: any) => v) {\n const dupes = array.reduce((acc: any, item: any) => {\n const key = selector(item)\n if (!acc[key]) {\n acc[key] = []\n }\n acc[key].push(item)\n return acc\n }, {})\n\n return Object.keys(dupes)\n .map((key) => (dupes[key].length > 1 ? dupes[key] : null))\n .filter(Boolean)\n}\n","import {flatten, uniq} from 'lodash'\n\nimport {getDupes} from '../sanity/validation/utils/getDupes'\n\ntype SchemaType = Record<string, any>\ntype SchemaTypeDef = Record<string, any>\n\ntype VisitContext = {\n isRoot: boolean\n isReserved: (typeName: string) => boolean\n visit: Visitor\n index: number\n isDuplicate: (typeName: string) => boolean\n getType: (typeName: string) => null | SchemaType\n getTypeNames: () => Array<string>\n}\n\nexport type Visitor = (typeDef: SchemaTypeDef, arg1: VisitContext) => SchemaType\n\nconst NOOP_VISITOR: Visitor = (typeDef) => typeDef\n\nexport class UnknownType {\n name: string\n\n constructor(name: string) {\n this.name = name\n }\n}\n\nconst TYPE_TYPE = {name: 'type', type: null}\n\nconst FUTURE_RESERVED = ['any', 'time', 'date']\n\nexport function traverseSchema(\n types: SchemaTypeDef[] = [],\n coreTypes: SchemaTypeDef[] = [],\n visitor: Visitor = NOOP_VISITOR,\n) {\n const coreTypesRegistry = Object.create(null)\n const registry = Object.create(null)\n\n const coreTypeNames = coreTypes.map((typeDef) => typeDef.name)\n\n const reservedTypeNames = FUTURE_RESERVED.concat(coreTypeNames)\n\n const typeNames = types.map((typeDef) => typeDef && typeDef.name).filter(Boolean)\n\n coreTypes.forEach((coreType) => {\n coreTypesRegistry[coreType.name] = coreType\n })\n\n types.forEach((type, i) => {\n // Allocate a placeholder for each type\n registry[(type && type.name) || `__unnamed_${i}`] = {}\n })\n\n function getType(typeName: any) {\n return typeName === 'type'\n ? TYPE_TYPE\n : coreTypesRegistry[typeName] || registry[typeName] || null\n }\n\n const duplicateNames = uniq(flatten(getDupes(typeNames)))\n\n function isDuplicate(typeName: any) {\n return duplicateNames.includes(typeName)\n }\n function getTypeNames() {\n return typeNames.concat(coreTypeNames)\n }\n function isReserved(typeName: any) {\n return typeName === 'type' || reservedTypeNames.includes(typeName)\n }\n\n const visitType = (isRoot: any) => (typeDef: any, index: any) => {\n return visitor(typeDef, {\n visit: visitType(false),\n isRoot,\n getType,\n getTypeNames,\n isReserved,\n isDuplicate,\n index,\n })\n }\n\n coreTypes.forEach((coreTypeDef) => {\n Object.assign(coreTypesRegistry[coreTypeDef.name], visitType(coreTypeDef))\n })\n\n types.forEach((typeDef, i) => {\n Object.assign(\n registry[(typeDef && typeDef.name) || `__unnamed_${i}`],\n visitType(true)(typeDef, i),\n )\n })\n\n return {\n get(typeName: string) {\n const res = registry[typeName] || coreTypesRegistry[typeName]\n if (res) {\n return res\n }\n throw new Error(`No such type: ${typeName}`)\n },\n has(typeName: string): boolean {\n return typeName in registry || typeName in coreTypesRegistry\n },\n getTypeNames(): string[] {\n return Object.keys(registry)\n },\n getTypes() {\n return this.getTypeNames().map(this.get)\n },\n toJSON() {\n return this.getTypes()\n },\n }\n}\n","const coreTypes = [\n {name: 'array', jsonType: 'array', type: 'type'},\n {name: 'block', jsonType: 'object', type: 'type'},\n {name: 'boolean', jsonType: 'boolean', type: 'type'},\n {name: 'datetime', jsonType: 'string', type: 'type'},\n {name: 'date', jsonType: 'string', type: 'type'},\n {name: 'document', jsonType: 'object', type: 'type'},\n {name: 'email', jsonType: 'string', type: 'type'},\n {name: 'file', jsonType: 'object', type: 'type'},\n {name: 'geopoint', jsonType: 'object', type: 'type'},\n {name: 'image', jsonType: 'object', type: 'type'},\n {name: 'number', jsonType: 'number', type: 'type'},\n {name: 'object', jsonType: 'object', type: 'type'},\n {name: 'reference', jsonType: 'object', type: 'type'},\n {name: 'crossDatasetReference', jsonType: 'object', type: 'type'},\n {name: 'globalDocumentReference', jsonType: 'object', type: 'type'},\n {name: 'slug', jsonType: 'object', type: 'type'},\n {name: 'span', jsonType: 'object', type: 'type'},\n {name: 'string', jsonType: 'string', type: 'type'},\n {name: 'telephone', jsonType: 'string', type: 'type'},\n {name: 'text', jsonType: 'string', type: 'type'},\n {name: 'url', jsonType: 'string', type: 'type'},\n] as const\n\nexport const coreTypeNames = coreTypes.map((t) => t.name)\nexport default coreTypes\n","import {traverseSchema, type Visitor} from '../core/traverseSchema'\nimport coreTypes from './coreTypes'\nimport {type _FIXME_} from './typedefs'\n\nexport function traverseSanitySchema(schemaTypes: _FIXME_[], visitor: Visitor) {\n return traverseSchema(schemaTypes, coreTypes as _FIXME_, visitor)\n}\n","import humanizeList from 'humanize-list'\nimport {flatten, partition} from 'lodash'\n\nimport {coreTypeNames} from '../../coreTypes'\nimport {error, HELP_IDS, warning} from '../createValidationResult'\nimport {getDupes} from '../utils/getDupes'\n\nfunction isPrimitiveTypeName(typeName: any) {\n return typeName === 'string' || typeName === 'number' || typeName === 'boolean'\n}\n\nfunction isAssignable(typeName: any, type: any) {\n return (typeof type.name === 'string' ? type.name : type.type) === typeName\n}\n\nfunction quote(n: any) {\n return `\"${n}\"`\n}\n\nfunction pluralize(arr: unknown[], suf = 's') {\n return arr.length === 1 ? '' : suf\n}\n\nfunction format(value: unknown) {\n if (Array.isArray(value)) {\n return `array with ${value.length} entries`\n }\n if (typeof value === 'object' && value !== null) {\n return `object with keys ${humanizeList(Object.keys(value).map(quote))}`\n }\n return quote(value)\n}\n\nexport default (typeDef: any, visitorContext: any) => {\n // name should already have been marked\n const ofIsArray = Array.isArray(typeDef.of)\n\n if (ofIsArray) {\n const invalid = typeDef.of.reduce((errs: any, def: any, idx: any) => {\n if (typeof def.name === 'string') {\n // If an array member has been given a \"local\" type name, we want to trigger an error if the given member type name\n // is one of the builtin types\n //\n // The following examples should be an error (where book is an existing root level type and reference is a built-in type):\n // - (…) of: [{type: 'book', name: 'image'}]\n // - (…) of: [{type: 'book', name: 'object'}]\n // - (…) of: [{type: 'object', name: 'reference'}]\n // The following examples are valid (where \"address\" is not defined as a global object type)\n // - (…) of: [{type: 'object', name: 'address'}]\n // The following examples are redundant, but should be allowed (at least for now)\n // - (…) of: [{type: 'object', name: 'object'}]\n // - (…) of: [{type: 'image', name: 'image'}]\n\n if (\n // specifying the same name as the type is redundant, but should not be a hard error at this point\n // Consider showing a warning for this and deprecate this ability eventually\n def.name !== def.type &&\n coreTypeNames.includes(def.name)\n ) {\n return errs.concat(\n error(\n `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.`,\n HELP_IDS.ARRAY_OF_TYPE_BUILTIN_TYPE_CONFLICT,\n ),\n )\n }\n }\n\n if (def.type === 'object' && def.name && visitorContext.getType(def.name)) {\n return errs.concat(\n warning(\n `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.`,\n HELP_IDS.ARRAY_OF_TYPE_GLOBAL_TYPE_CONFLICT,\n ),\n )\n }\n if (def.type === 'array') {\n return errs.concat(\n error(\n `Found array member declaration of type \"array\" - multidimensional arrays are not currently supported by Sanity`,\n HELP_IDS.ARRAY_OF_ARRAY,\n ),\n )\n }\n\n if (def) {\n return errs\n }\n\n const err = `Found ${def === null ? 'null' : typeof def}, expected member declaration`\n return errs.concat(\n error(\n `Found invalid type member declaration in array at index ${idx}: ${err}`,\n HELP_IDS.ARRAY_OF_INVALID,\n ),\n )\n }, [])\n\n if (invalid.length > 0) {\n return {\n ...typeDef,\n of: [],\n _problems: invalid,\n }\n }\n }\n\n const problems = flatten([\n ofIsArray\n ? getDupes(typeDef.of, (t) => `${t.name};${t.type}`).map((dupes) =>\n error(\n `Found ${dupes.length} members with same type, but not unique names \"${dupes[0].type}\" in array. This makes it impossible to tell their values apart and you should consider naming them`,\n HELP_IDS.ARRAY_OF_NOT_UNIQUE,\n ),\n )\n : error(\n 'The array type is missing or having an invalid value for the required \"of\" property',\n HELP_IDS.ARRAY_OF_INVALID,\n ),\n ])\n const of = ofIsArray ? typeDef.of : []\n\n // Don't allow object types without a name in block arrays\n const hasObjectTypesWithoutName = of.some(\n (type: any) => type.type === 'object' && typeof type.name === 'undefined',\n )\n const hasBlockType = of.some((ofType: any) => ofType.type === 'block')\n if (hasBlockType && hasObjectTypesWithoutName) {\n problems.push(\n error(\n \"The array type's 'of' property can't have an object type without a 'name' property as member, when the 'block' type is also a member of that array.\",\n HELP_IDS.ARRAY_OF_INVALID,\n ),\n )\n }\n\n const [primitiveTypes, objectTypes] = partition(\n of,\n (ofType) =>\n isPrimitiveTypeName(ofType.type) ||\n isPrimitiveTypeName(visitorContext.getType(ofType.type)?.jsonType),\n )\n\n const isMixedArray = primitiveTypes.length > 0 && objectTypes.length > 0\n\n if (isMixedArray) {\n const primitiveTypeNames = primitiveTypes.map((t) => t.type)\n const objectTypeNames = objectTypes.map((t) => t.type)\n problems.push(\n error(\n `The array type's 'of' property can't have both object types and primitive types (found primitive type ${pluralize(\n primitiveTypeNames,\n )} ${humanizeList(primitiveTypeNames.map(quote))} and object type${pluralize(\n objectTypeNames,\n )} ${humanizeList(objectTypeNames.map(quote))})`,\n HELP_IDS.ARRAY_OF_INVALID,\n ),\n )\n }\n\n const list = typeDef?.options?.list\n if (!isMixedArray && Array.isArray(list)) {\n const isArrayOfPrimitives = primitiveTypes.length > 0\n if (isArrayOfPrimitives) {\n list.forEach((option) => {\n const value = option?.value ?? option\n const isDeclared = primitiveT