UNPKG

sanity

Version:

Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches

366 lines (306 loc) • 11.6 kB
import {type AssetSource, type SchemaTypeDefinition} from '@sanity/types' import {type ReactNode} from 'react' import {type LocaleConfigContext, type LocaleDefinition, type LocaleResourceBundle} from '../i18n' import {type Template, type TemplateItem} from '../templates' import {getPrintableType} from '../util/getPrintableType' import { type DocumentActionComponent, type DocumentBadgeComponent, type DocumentInspector, } from './document' import {flattenConfig} from './flattenConfig' import { type AsyncConfigPropertyReducer, type ConfigContext, type ConfigPropertyReducer, type DocumentActionsContext, type DocumentBadgesContext, type DocumentCommentsEnabledContext, type DocumentInspectorContext, type DocumentLanguageFilterComponent, type DocumentLanguageFilterContext, type NewDocumentOptionsContext, type PluginOptions, type ResolveProductionUrlContext, type Tool, } from './types' export const initialDocumentBadges: DocumentBadgeComponent[] = [] export const initialDocumentActions: DocumentActionComponent[] = [] export const initialLanguageFilter: DocumentLanguageFilterComponent[] = [] export const schemaTypesReducer: ConfigPropertyReducer< SchemaTypeDefinition[], Omit<ConfigContext, 'schema' | 'currentUser' | 'client' | 'getClient' | 'i18n'> > = (prev, {schema}, context) => { const schemaTypes = schema?.types if (!schemaTypes) return prev if (typeof schemaTypes === 'function') return schemaTypes(prev, context) if (Array.isArray(schemaTypes)) return [...prev, ...schemaTypes] throw new Error( `Expected \`schema.types\` to be an array or a function, but received ${getPrintableType( schemaTypes, )}`, ) } export const resolveProductionUrlReducer: AsyncConfigPropertyReducer< string | undefined, ResolveProductionUrlContext > = async (prev, {document}, context) => { const resolveProductionUrl = document?.productionUrl // the redundant await is useful for error logging because the error is caught // in this stack vs somewhere down stream // eslint-disable-next-line no-return-await if (resolveProductionUrl) return await resolveProductionUrl(prev, context) return prev } export const toolsReducer: ConfigPropertyReducer<Tool[], ConfigContext> = ( prev, {tools}, context, ) => { if (!tools) return prev if (typeof tools === 'function') return tools(prev, context) if (Array.isArray(tools)) return [...prev, ...tools] throw new Error( `Expected \`tools\` to be an array or a function, but received ${getPrintableType(tools)}`, ) } // we will need this when we ressurect user config for search /*export const searchFilterReducer: ConfigPropertyReducer< SearchFilterDefinition<string>[], ConfigContext > = (prev, {search}, context) => { const filters = search?.filters if (!filters) return prev if (typeof filters === 'function') return filters(prev, context) if (Array.isArray(filters)) return [...prev, ...filters] throw new Error( `Expected \`search.filters\` to be an array or a function, but received ${typeof filters}` ) } export const searchOperatorsReducer: ConfigPropertyReducer< SearchOperatorDefinition[], ConfigContext > = (prev, {search}, context) => { const operators = search?.operators if (!operators) return prev if (typeof operators === 'function') return operators(prev, context) if (Array.isArray(operators)) return [...prev, ...operators] throw new Error( `Expected \`operators\` to be be an array or a function, but received ${getPrintableType(operators)}` ) }*/ export const schemaTemplatesReducer: ConfigPropertyReducer<Template[], ConfigContext> = ( prev, {schema}, context, ) => { const schemaTemplates = schema?.templates if (!schemaTemplates) return prev if (typeof schemaTemplates === 'function') return schemaTemplates(prev, context) if (Array.isArray(schemaTemplates)) return [...prev, ...schemaTemplates] throw new Error( `Expected \`schema.templates\` to be an array or a function, but received ${getPrintableType( schemaTemplates, )}`, ) } export const localeDefReducer: ConfigPropertyReducer<LocaleDefinition[], LocaleConfigContext> = ( prev, {i18n}, context, ) => { const locales = i18n?.locales if (!locales) return prev if (typeof locales === 'function') return locales(prev, context) if (Array.isArray(locales)) return [...prev, ...locales] throw new Error( `Expected \`i18n.locales\` to be an array or a function, but received ${getPrintableType( locales, )}`, ) } export const localeBundlesReducer: ConfigPropertyReducer< LocaleResourceBundle[], LocaleConfigContext > = (prev, {i18n}, context) => { const bundles = i18n?.bundles if (!bundles) return prev if (Array.isArray(bundles)) return [...prev, ...bundles] if (typeof bundles === 'function') return bundles(prev, context) throw new Error( `Expected \`i18n.bundles\` to be an array or a function, but received ${typeof bundles}`, ) } export const documentBadgesReducer: ConfigPropertyReducer< DocumentBadgeComponent[], DocumentBadgesContext > = (prev, {document}, context) => { const documentBadges = document?.badges if (!documentBadges) return prev if (typeof documentBadges === 'function') return documentBadges(prev, context) if (Array.isArray(documentBadges)) return [...prev, ...documentBadges] throw new Error( `Expected \`document.badges\` to be an array or a function, but received ${getPrintableType( documentBadges, )}`, ) } export const documentActionsReducer: ConfigPropertyReducer< DocumentActionComponent[], DocumentActionsContext > = (prev, {document}, context) => { const documentActions = document?.actions if (!documentActions) return prev if (typeof documentActions === 'function') return documentActions(prev, context) if (Array.isArray(documentActions)) return [...prev, ...documentActions] throw new Error( `Expected \`document.actions\` to be an array or a function, but received ${getPrintableType( documentActions, )}`, ) } export const newDocumentOptionsResolver: ConfigPropertyReducer< TemplateItem[], NewDocumentOptionsContext > = (prev, {document}, context) => { const resolveNewDocumentOptions = document?.newDocumentOptions if (!resolveNewDocumentOptions) return prev if (typeof resolveNewDocumentOptions !== 'function') { throw new Error( `Expected \`document.resolveNewDocumentOptions\` to be a function, but received ${getPrintableType( resolveNewDocumentOptions, )}`, ) } return resolveNewDocumentOptions(prev, context) } export const fileAssetSourceResolver: ConfigPropertyReducer<AssetSource[], ConfigContext> = ( prev, {form}, context, ) => { const assetSources = form?.file?.assetSources if (!assetSources) return prev if (typeof assetSources === 'function') return assetSources(prev, context) if (Array.isArray(assetSources)) return [...prev, ...assetSources] throw new Error( `Expected \`form.file.assetSources\` to be an array or a function, but received ${getPrintableType( assetSources, )}`, ) } export const imageAssetSourceResolver: ConfigPropertyReducer<AssetSource[], ConfigContext> = ( prev, {form}, context, ) => { const assetSources = form?.image?.assetSources if (!assetSources) return prev if (typeof assetSources === 'function') return assetSources(prev, context) if (Array.isArray(assetSources)) return [...prev, ...assetSources] throw new Error( `Expected \`form.image.assetSources\` to be an array or a function, but received ${getPrintableType( assetSources, )}`, ) } /** * @internal */ export const documentLanguageFilterReducer: ConfigPropertyReducer< DocumentLanguageFilterComponent[], DocumentLanguageFilterContext > = (prev, {document}, context) => { const resolveDocumentLanguageFilter = document?.unstable_languageFilter if (!resolveDocumentLanguageFilter) return prev if (typeof resolveDocumentLanguageFilter === 'function') return resolveDocumentLanguageFilter(prev, context) if (Array.isArray(resolveDocumentLanguageFilter)) return [...prev, ...resolveDocumentLanguageFilter] throw new Error( `Expected \`document.unstable_languageFilter\` to be an array or a function, but received ${getPrintableType( resolveDocumentLanguageFilter, )}`, ) } export const documentInspectorsReducer: ConfigPropertyReducer< DocumentInspector[], DocumentInspectorContext > = (prev, {document}, context) => { const resolveInspectorsFilter = document?.inspectors if (!resolveInspectorsFilter) return prev if (typeof resolveInspectorsFilter === 'function') return resolveInspectorsFilter(prev, context) if (Array.isArray(resolveInspectorsFilter)) return [...prev, ...resolveInspectorsFilter] throw new Error( `Expected \`document.inspectors\` to be an array or a function, but received ${getPrintableType( resolveInspectorsFilter, )}`, ) } export const documentCommentsEnabledReducer = (opts: { config: PluginOptions context: DocumentCommentsEnabledContext initialValue: boolean }): boolean => { const {config, context, initialValue} = opts const flattenedConfig = flattenConfig(config, []) // There is no concept of 'previous value' in this API. We only care about the final value. // That is, if a plugin returns true, but the next plugin returns false, the result will be false. // The last plugin 'wins'. const result = flattenedConfig.reduce((acc, {config: innerConfig}) => { const resolver = innerConfig.document?.unstable_comments?.enabled if (!resolver && typeof resolver !== 'boolean') return acc if (typeof resolver === 'function') return resolver(context) if (typeof resolver === 'boolean') return resolver throw new Error( `Expected \`document.unstable_comments.enabled\` to be a boolean or a function, but received ${getPrintableType( resolver, )}`, ) }, initialValue) return result } export const internalTasksReducer = (opts: { config: PluginOptions }): {footerAction: ReactNode} | undefined => { const {config} = opts const flattenedConfig = flattenConfig(config, []) const result = flattenedConfig.reduce( (acc: {footerAction: ReactNode} | undefined, {config: innerConfig}) => { const resolver = innerConfig.__internal_tasks if (!resolver) return acc if (typeof resolver === 'object' && resolver.footerAction) return resolver throw new Error( `Expected \`__internal__tasks\` to be an object with footerAction, but received ${getPrintableType( resolver, )}`, ) }, undefined, ) return result } export const partialIndexingEnabledReducer = (opts: { config: PluginOptions initialValue: boolean }): boolean => { const {config, initialValue} = opts const flattenedConfig = flattenConfig(config, []) const result = flattenedConfig.reduce((acc, {config: innerConfig}) => { const resolver = innerConfig.search?.unstable_partialIndexing?.enabled if (!resolver && typeof resolver !== 'boolean') return acc if (typeof resolver === 'boolean') return resolver throw new Error( `Expected \`search.unstable_partialIndexing.enabled\` to be a boolean, but received ${getPrintableType( resolver, )}`, ) }, initialValue) return result } export const newSearchEnabledReducer: ConfigPropertyReducer<boolean, ConfigContext> = ( prev, {search}, ): boolean => { return prev || search?.unstable_enableNewSearch || false }