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
131 lines (95 loc) • 3.06 kB
text/typescript
/* eslint-disable no-loop-func */
import {type Path, type SanityDocument, type SchemaType} from '@sanity/types'
import {isArray, isRecord} from 'sanity'
export function getPathTitles(options: {
path: Path
schemaType: SchemaType
value: Partial<SanityDocument> | null
}): Array<{name: string; title?: string}> {
const {path, schemaType, value} = options
const result: Array<{name: string; title?: string}> = []
let s = schemaType
let v: unknown = value
for (const segment of path) {
// field name
if (typeof segment === 'string') {
if (!isRecord(v) && v !== undefined) {
throw new Error(`Parent value is not an object, cannot get path segment: .${segment}`)
}
if (s.jsonType !== 'object') {
throw new Error(
`Parent type is not an object schema type, cannot get path segment: .${segment}`,
)
}
v = v?.[segment]
const field = s.fields.find((f) => f.name === segment)
if (!field) {
result.push({name: segment})
return result
}
s = field.type
result.push(s)
continue
}
// array item index
if (typeof segment === 'number') {
if (!isArray(v) && v !== undefined) {
throw new Error(`Parent value is not an array, cannot get path segment: [${segment}]`)
}
if (s.jsonType !== 'array') {
throw new Error(
`Parent type is not an array schema type, cannot get path segment: [${segment}]`,
)
}
v = v?.[segment]
const itemType = s.of.find((ofType) => {
if (typeof v === 'string') {
return ofType.jsonType === 'string'
}
if (typeof v === 'number') {
return ofType.jsonType === 'number'
}
if (typeof v === 'boolean') {
return ofType.jsonType === 'boolean'
}
if (isRecord(v)) {
return ofType.name === v?._type
}
return false
})
if (!itemType) {
throw new Error(`Item type not found: [${segment}]`)
}
s = itemType
result.push(s)
continue
}
// array item key
if (isRecord(segment) && segment._key) {
if (!isArray(v)) {
throw new Error(
`Parent value is not an array, cannot get path segment: [_key == ${segment}]`,
)
}
if (s.jsonType !== 'array') {
throw new Error(
`Parent type is not an array schema type, cannot get path segment: .${segment}`,
)
}
const values = v ?? []
v = values.find((i) => isRecord(i) && i._key === segment._key)
if (!isRecord(v)) {
throw new Error(`Array item not found: [_key == ${segment._key}]`)
}
const ofType = s.of.find((i) => isRecord(v) && i.name === v?._type)
if (!ofType) {
throw new Error(`Array item type not found: .${v?._type}`)
}
s = ofType
result.push(s)
continue
}
throw new Error(`Invalid path segment: ${JSON.stringify(segment)}`)
}
return result
}