UNPKG

@sanity/schema

Version:
226 lines (189 loc) • 6.37 kB
import { type FieldGroup, type FieldGroupDefinition, type Fieldset, type FieldsetDefinition, type ObjectDefinition, type ObjectField, } from '@sanity/types' import {castArray, flatMap, pick, startCase} from 'lodash' import guessOrderingConfig from '../ordering/guessOrderingConfig' import createPreviewGetter from '../preview/createPreviewGetter' import {normalizeSearchConfigs} from '../searchConfig/normalize' import {resolveSearchConfig} from '../searchConfig/resolve' import {DEFAULT_OVERRIDEABLE_FIELDS, OWN_PROPS_NAME} from './constants' import {hiddenGetter, lazyGetter} from './utils' const OVERRIDABLE_FIELDS = [ ...DEFAULT_OVERRIDEABLE_FIELDS, 'orderings', '__experimental_search', 'blockEditor', 'icon', ] export const ObjectType = { get() { return { name: 'object', title: 'Object', type: null, jsonType: 'object', } }, extend(rawSubTypeDef: any, createMemberType: any) { const subTypeDef = {fields: [], ...rawSubTypeDef} const options = {...(subTypeDef.options || {})} const ownProps = { ...subTypeDef, title: subTypeDef.title || (subTypeDef.name ? startCase(subTypeDef.name) : 'Object'), options: options, orderings: subTypeDef.orderings || guessOrderingConfig(subTypeDef), fields: subTypeDef.fields.map((fieldDef: any) => { const {name, fieldset, group, ...rest} = fieldDef const compiledField = { name, group, fieldset, } return lazyGetter(compiledField, 'type', () => { return createMemberType({ ...rest, title: fieldDef.title || startCase(name), }) }) }), } const parsed = Object.assign(pick(this.get(), OVERRIDABLE_FIELDS), ownProps, { type: this.get(), }) lazyGetter(parsed, 'fieldsets', () => { return createFieldsets(subTypeDef, parsed.fields) }) lazyGetter(parsed, 'groups', () => { return createFieldsGroups(subTypeDef, parsed.fields) }) lazyGetter(parsed, 'preview', createPreviewGetter(subTypeDef)) lazyGetter( parsed, OWN_PROPS_NAME, () => ({ ...ownProps, fieldsets: parsed.fieldsets, groups: parsed.groups, preview: parsed.preview, }), {enumerable: false, writable: false}, ) lazyGetter( parsed, '__experimental_search', () => { const userProvidedSearchConfig = subTypeDef.__experimental_search ? normalizeSearchConfigs(subTypeDef.__experimental_search) : null if (userProvidedSearchConfig) { return userProvidedSearchConfig.map((entry) => entry === 'defaults' ? normalizeSearchConfigs(subTypeDef) : entry, ) } return resolveSearchConfig(parsed) }, { enumerable: false, }, ) return subtype(parsed) function subtype(parent: any) { return { get() { return parent }, extend: (extensionDef: any) => { if (extensionDef.fields) { throw new Error('Cannot override `fields` of subtypes of "object"') } const subOwnProps = pick(extensionDef, OVERRIDABLE_FIELDS) subOwnProps.title = extensionDef.title || subTypeDef.title || (subTypeDef.name ? startCase(subTypeDef.name) : 'Object') const current = Object.assign({}, parent, pick(extensionDef, OVERRIDABLE_FIELDS), { type: parent, }) lazyGetter(current, '__experimental_search', () => parent.__experimental_search) hiddenGetter(current, OWN_PROPS_NAME, subOwnProps) return subtype(current) }, } } }, } export function createFieldsets(typeDef: ObjectDefinition, fields: ObjectField[]): Fieldset[] { const fieldsetsByName: Record<string, FieldsetDefinition & {fields: ObjectField[]}> = {} for (const fieldset of typeDef.fieldsets || []) { if (fieldsetsByName[fieldset.name]) { throw new Error( `Duplicate fieldset name "${fieldset.name}" found for type '${ typeDef.title ? typeDef.title : startCase(typeDef.name) }'`, ) } fieldsetsByName[fieldset.name] = {title: startCase(fieldset.name), ...fieldset, fields: []} } const fieldsets = new Set<Fieldset>() for (const field of fields) { if (!field.fieldset) { fieldsets.add({single: true, field}) continue } const fieldset = fieldsetsByName[field.fieldset] if (!fieldset) { throw new Error( `Fieldset '${field.fieldset}' is not defined in schema for type '${typeDef.name}'`, ) } fieldset.fields.push(field) // The Set will prevent duplicates fieldsets.add(fieldset) } return Array.from(fieldsets) } function createFieldsGroups(typeDef: ObjectDefinition, fields: ObjectField[]): FieldGroup[] { const groupsByName: Record<string, FieldGroupDefinition & {fields: ObjectField[]}> = {} let numDefaultGroups = 0 for (const group of typeDef.groups || []) { if (groupsByName[group.name]) { throw new Error( `Duplicate group name "${group.name}" found for type '${ typeDef.title ? typeDef.title : startCase(typeDef.name) }'`, ) } groupsByName[group.name] = {title: startCase(group.name), ...group, fields: []} if (group.default && ++numDefaultGroups > 1) { // Throw if you have multiple default field groups defined throw new Error( `More than one field group defined as default for type '${ typeDef.title ? typeDef.title : startCase(typeDef.name) }' - only 1 is supported`, ) } } fields.forEach((field) => { const fieldGroupNames = castArray(field.group || []) if (fieldGroupNames.length === 0) { return } fieldGroupNames.forEach((fieldGroupName) => { const currentGroup = groupsByName[fieldGroupName] if (!currentGroup) { throw new Error( `Field group '${fieldGroupName}' is not defined in schema for type '${ typeDef.title ? typeDef.name : startCase(typeDef.name) }'`, ) } currentGroup.fields.push(field) }) }) return flatMap(groupsByName).filter((group) => group.fields.length > 0) }