@prismicio/client
Version:
The official JavaScript + TypeScript client library for Prismic
1 lines • 9.26 kB
Source Map (JSON)
{"version":3,"file":"mapSliceZone.cjs","sources":["../../../src/helpers/mapSliceZone.ts"],"sourcesContent":["import type { Slice } from \"../types/value/slice\"\n\n/**\n * Convert a value to a lazyily loaded module. This is useful when using\n * functions like `() => import(\"...\")`.\n */\ntype LazyModule<T> = () => Promise<T | { default: T }>\n\n/**\n * Mark a type as potentially lazy-loaded via a module.\n */\ntype MaybeLazyModule<T> = T | LazyModule<T>\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyFunction = (...args: any[]) => any\n\n/**\n * Returns the type of a `SliceLike` type.\n *\n * @typeParam Slice - The Slice from which the type will be extracted.\n */\ntype ExtractSliceType<TSlice extends SliceLike> = TSlice extends SliceLikeRestV2\n\t? TSlice[\"slice_type\"]\n\t: TSlice extends SliceLikeGraphQL\n\t\t? TSlice[\"type\"]\n\t\t: never\n\n/**\n * The minimum required properties to represent a Prismic Slice from the Prismic\n * Rest API V2 for the `mapSliceZone()` helper.\n *\n * @typeParam SliceType - Type name of the Slice.\n */\ntype SliceLikeRestV2<TSliceType extends string = string> = Pick<\n\tSlice<TSliceType>,\n\t\"id\" | \"slice_type\"\n>\n\n/**\n * The minimum required properties to represent a Prismic Slice from the Prismic\n * GraphQL API for the `mapSliceZone()` helper.\n *\n * @typeParam SliceType - Type name of the Slice.\n */\ntype SliceLikeGraphQL<TSliceType extends string = string> = {\n\ttype: Slice<TSliceType>[\"slice_type\"]\n}\n\n/**\n * The minimum required properties to represent a Prismic Slice for the\n * `mapSliceZone()` helper.\n *\n * If using Prismic's Rest API V2, use the `Slice` export from\n * `@prismicio/client` for a full interface.\n *\n * @typeParam SliceType - Type name of the Slice.\n */\ntype SliceLike<TSliceType extends string = string> =\n\t| SliceLikeRestV2<TSliceType>\n\t| SliceLikeGraphQL<TSliceType>\n\n/**\n * A looser version of the `SliceZone` type from `@prismicio/client` using\n * `SliceLike`.\n *\n * If using Prismic's Rest API V2, use the `SliceZone` export from\n * `@prismicio/client` for the full type.\n *\n * @typeParam TSlice - The type(s) of a Slice in the Slice Zone.\n */\ntype SliceZoneLike<TSlice extends SliceLike = SliceLike> = readonly TSlice[]\n\n/**\n * A set of properties that identify a Slice as having been mapped. Consumers of\n * the mapped Slice Zone can use these properties to detect and specially handle\n * mapped Slices.\n */\ntype MappedSliceLike = {\n\t/**\n\t * If `true`, this Slice has been modified from its original value using a\n\t * mapper.\n\t *\n\t * @internal\n\t */\n\t__mapped: true\n}\n\n/**\n * Arguments for a function mapping content from a Prismic Slice using the\n * `mapSliceZone()` helper.\n *\n * @typeParam TSlice - The Slice passed as a prop.\n * @typeParam TContext - Arbitrary data passed to `mapSliceZone()` and made\n * available to all Slice mappers.\n */\ntype SliceMapperArgs<\n\tTSlice extends SliceLike = SliceLike,\n\tTContext = unknown,\n> = {\n\t/**\n\t * Slice data.\n\t */\n\tslice: TSlice\n\n\t/**\n\t * The index of the Slice in the Slice Zone.\n\t */\n\tindex: number\n\n\t/**\n\t * All Slices from the Slice Zone to which the Slice belongs.\n\t */\n\t// TODO: We have to keep this list of Slices general due to circular\n\t// reference limtiations. If we had another generic to determine the full\n\t// union of Slice types, it would include TSlice. This causes TypeScript to\n\t// throw a compilation error.\n\tslices: SliceZoneLike<\n\t\tTSlice extends SliceLikeGraphQL ? SliceLikeGraphQL : SliceLikeRestV2\n\t>\n\n\t/**\n\t * Arbitrary data passed to `mapSliceZone()` and made available to all Slice\n\t * mappers.\n\t */\n\tcontext: TContext\n}\n\n/**\n * A record of mappers.\n */\ntype SliceMappers<TSlice extends SliceLike = SliceLike, TContext = unknown> = {\n\t[P in ExtractSliceType<TSlice>]?: MaybeLazyModule<\n\t\tSliceMapper<\n\t\t\tExtract<TSlice, SliceLike<P>>,\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\tany,\n\t\t\tTContext\n\t\t>\n\t>\n}\n\n/**\n * A function that maps a Slice and its metadata to a modified version. The\n * return value will replace the Slice in the Slice Zone.\n */\nexport type SliceMapper<\n\tTSlice extends SliceLike = SliceLike,\n\tTMappedSlice extends Record<string, unknown> | undefined | void =\n\t\t| Record<string, unknown>\n\t\t| undefined\n\t\t| void,\n\tTContext = unknown,\n> = (\n\targs: SliceMapperArgs<TSlice, TContext>,\n) => TMappedSlice | Promise<TMappedSlice>\n\n/**\n * Unwraps a lazily loaded mapper module.\n */\ntype ResolveLazySliceMapperModule<\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tTSliceMapper extends SliceMapper<any, any> | LazyModule<SliceMapper>,\n> =\n\tTSliceMapper extends LazyModule<SliceMapper>\n\t\t? Awaited<ReturnType<TSliceMapper>> extends {\n\t\t\t\tdefault: unknown\n\t\t\t}\n\t\t\t? Awaited<ReturnType<TSliceMapper>>[\"default\"]\n\t\t\t: Awaited<ReturnType<TSliceMapper>>\n\t\t: TSliceMapper\n\n/**\n * Transforms a Slice into its mapped version.\n */\ntype MapSliceLike<\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tTSliceLike extends SliceLike<any>,\n\tTSliceMappers extends SliceMappers<\n\t\tTSliceLike,\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\tany\n\t>,\n> = TSliceLike extends Slice\n\t? TSliceLike[\"slice_type\"] extends keyof TSliceMappers\n\t\t? TSliceMappers[TSliceLike[\"slice_type\"]] extends AnyFunction\n\t\t\t? SliceLikeRestV2<TSliceLike[\"slice_type\"]> &\n\t\t\t\t\tMappedSliceLike &\n\t\t\t\t\tAwaited<\n\t\t\t\t\t\tReturnType<\n\t\t\t\t\t\t\tResolveLazySliceMapperModule<\n\t\t\t\t\t\t\t\tTSliceMappers[TSliceLike[\"slice_type\"]]\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t>\n\t\t\t\t\t>\n\t\t\t: TSliceLike\n\t\t: TSliceLike\n\t: TSliceLike extends SliceLikeGraphQL\n\t\t? TSliceLike[\"type\"] extends keyof TSliceMappers\n\t\t\t? TSliceMappers[TSliceLike[\"type\"]] extends AnyFunction\n\t\t\t\t? SliceLikeGraphQL<TSliceLike[\"type\"]> &\n\t\t\t\t\t\tMappedSliceLike &\n\t\t\t\t\t\tAwaited<\n\t\t\t\t\t\t\tReturnType<\n\t\t\t\t\t\t\t\tResolveLazySliceMapperModule<TSliceMappers[TSliceLike[\"type\"]]>\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t>\n\t\t\t\t: TSliceLike\n\t\t\t: TSliceLike\n\t\t: never\n\n/**\n * Transforms a Slice Zone using a set of mapping functions, one for each type\n * of Slice. Mapping functions can be async.\n *\n * Whenever possible, use this function on the server to minimize client-side\n * processing.\n *\n * @example\n *\n * ```typescript\n * const mappedSliceZone = await mapSliceZone(page.data.slices, {\n * \tcode_block: ({ slice }) => ({\n * \t\tcodeHTML: await highlight(slice.primary.code),\n * \t}),\n * });\n * ```\n */\nexport function mapSliceZone<\n\tTSliceLike extends SliceLike,\n\tTSliceMappers extends SliceMappers<TSliceLike, TContext>,\n\tTContext = unknown,\n>(\n\tsliceZone: SliceZoneLike<TSliceLike>,\n\tmappers: TSliceMappers,\n\tcontext?: TContext,\n): Promise<MapSliceLike<TSliceLike, TSliceMappers>[]> {\n\treturn Promise.all(\n\t\tsliceZone.map(async (slice, index, slices) => {\n\t\t\tconst isRestSliceType = \"slice_type\" in slice\n\t\t\tconst sliceType = isRestSliceType ? slice.slice_type : slice.type\n\n\t\t\tconst mapper = mappers[sliceType as keyof typeof mappers]\n\n\t\t\tif (!mapper) {\n\t\t\t\treturn slice\n\t\t\t}\n\n\t\t\tconst mapperArgs = { slice, slices, index, context }\n\n\t\t\t// `result` may be a mapper function OR a module\n\t\t\t// containing a mapper function.\n\t\t\tlet result = await mapper(\n\t\t\t\t// @ts-expect-error - I don't know how to fix this type\n\t\t\t\tmapperArgs,\n\t\t\t)\n\n\t\t\t// `result` is a module containing a mapper function,\n\t\t\t// we need to dig out the mapper function. `result`\n\t\t\t// will be reassigned with the mapper function's value.\n\t\t\tif (\n\t\t\t\t// `mapper.length < 1` ensures the given\n\t\t\t\t// function is something of the form:\n\t\t\t\t// `() => import(...)`\n\t\t\t\tmapper.length < 1 &&\n\t\t\t\t(typeof result === \"function\" ||\n\t\t\t\t\t(typeof result === \"object\" && \"default\" in result))\n\t\t\t) {\n\t\t\t\tresult = \"default\" in result ? result.default : result\n\t\t\t\tresult = await result(mapperArgs)\n\t\t\t}\n\n\t\t\tif (isRestSliceType) {\n\t\t\t\treturn {\n\t\t\t\t\t__mapped: true,\n\t\t\t\t\tid: slice.id,\n\t\t\t\t\tslice_type: sliceType,\n\t\t\t\t\t...result,\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn {\n\t\t\t\t\t__mapped: true,\n\t\t\t\t\ttype: sliceType,\n\t\t\t\t\t...result,\n\t\t\t\t}\n\t\t\t}\n\t\t}),\n\t)\n}\n"],"names":[],"mappings":";;AAmOgB,SAAA,aAKf,WACA,SACA,SAAkB;AAElB,SAAO,QAAQ,IACd,UAAU,IAAI,OAAO,OAAO,OAAO,WAAU;AAC5C,UAAM,kBAAkB,gBAAgB;AACxC,UAAM,YAAY,kBAAkB,MAAM,aAAa,MAAM;AAEvD,UAAA,SAAS,QAAQ,SAAiC;AAExD,QAAI,CAAC,QAAQ;AACL,aAAA;AAAA,IAAA;AAGR,UAAM,aAAa,EAAE,OAAO,QAAQ,OAAO,QAAO;AAIlD,QAAI,SAAS,MAAM;AAAA;AAAA,MAElB;AAAA,IAAU;AAMX;AAAA;AAAA;AAAA;AAAA,MAIC,OAAO,SAAS,MACf,OAAO,WAAW,cACjB,OAAO,WAAW,YAAY,aAAa;AAAA,MAC5C;AACQ,eAAA,aAAa,SAAS,OAAO,UAAU;AACvC,eAAA,MAAM,OAAO,UAAU;AAAA,IAAA;AAGjC,QAAI,iBAAiB;AACb,aAAA;AAAA,QACN,UAAU;AAAA,QACV,IAAI,MAAM;AAAA,QACV,YAAY;AAAA,QACZ,GAAG;AAAA;WAEE;AACC,aAAA;AAAA,QACN,UAAU;AAAA,QACV,MAAM;AAAA,QACN,GAAG;AAAA;;EAEL,CACA,CAAC;AAEJ;;"}