@prismicio/types-internal
Version:
Prismic types for Custom Types and Prismic Data
131 lines (119 loc) • 3 kB
text/typescript
import { isRight } from "fp-ts/lib/Either"
import * as t from "io-ts"
import { v4 as uuid, validate as validateUuid } from "uuid"
import type {
CompositeSlice,
Group,
NestableWidget,
StaticSlices,
UID,
VariationFields,
} from "../customtypes"
import {
FieldContentType,
FieldType,
SharedSliceItemContent,
SliceItemContent,
WidgetContent,
} from "./fields"
type WithFieldType = WithContentType & { type: FieldType }
export function hasFieldContentType(obj: unknown): obj is WithFieldType {
return (
hasContentType(obj) &&
obj.__TYPE__ === FieldContentType &&
(obj as WithFieldType)?.type !== undefined &&
typeof (obj as WithFieldType).type === "string" &&
isRight(FieldType.decode((obj as WithFieldType).type))
)
}
type WithContentType = { __TYPE__: string }
export function hasContentType(obj: unknown): obj is WithContentType {
return typeof obj === "object" && obj !== null && "__TYPE__" in obj
}
const isUuid = (input: unknown): input is string =>
typeof input === "string" && validateUuid(input)
const uuidWithFallback = new t.Type<string, string, unknown>(
"UUID",
isUuid,
(u, c) => {
if (typeof u === "undefined") return t.success(uuid())
if (isUuid(u)) return t.success(u)
return t.failure(u, c)
},
t.identity,
)
export function withKey<C extends t.Mixed>(codec: C) {
return t.intersection([t.strict({ key: uuidWithFallback }), codec])
}
export type TraverseSliceContentFn = <
S extends SliceItemContent | SharedSliceItemContent,
D extends VariationFields | CompositeSlice | Group | NestableWidget,
>({
path,
key,
apiId,
model,
content,
}: {
path: ContentPath
key: string
apiId: string
model?: D | undefined
content: S
}) => S | SharedSliceItemContent | undefined
export type TraverseWidgetContentFn<
ContentTransformMode extends "preserve" | "widen" = "preserve",
> = <
C extends WidgetContent,
D extends NestableWidget | StaticSlices | Group | UID,
>({
path,
key,
apiId,
model,
content,
}: {
path: ContentPath
key: string
apiId: string
model?: D | undefined
content: C
}) =>
| ([ContentTransformMode] extends ["preserve"] ? C : WidgetContent)
| undefined
export type ContentPathEntry = {
type:
| "CustomType"
| "Widget"
| "SharedSlice"
| "Slice"
| "LegacySlice"
| "GroupItem"
| "primary"
| "items"
| "RepeatableItem"
key: string
}
export type ContentPath = ReadonlyArray<ContentPathEntry>
const PATH_SEPARATOR = "::"
export const ContentPath = {
serialize(path: ContentPath): string {
return path.map((entry) => entry.key).join(PATH_SEPARATOR)
},
current(path: ContentPath): ContentPathEntry | undefined {
return path[path.length - 1]
},
append(path: string, strElement: string): string {
return path + PATH_SEPARATOR + strElement
},
make(
entries: Array<{
key?: ContentPathEntry["key"] | undefined
type: ContentPathEntry["type"]
}>,
): ContentPath {
return entries.reduce<ContentPath>((acc, { key, type }) => {
return key ? acc.concat({ key, type }) : acc
}, [])
},
}