UNPKG

gatsby-source-prismic

Version:

Gatsby source plugin for building websites using Prismic as a data source

171 lines (162 loc) 5.14 kB
import * as gqlc from "graphql-compose"; import * as imgixGatsby from "@imgix/gatsby/dist/pluginHelpers"; import * as prismicT from "@prismicio/types"; import * as RTE from "fp-ts/ReaderTaskEither"; import * as O from "fp-ts/Option"; import * as S from "fp-ts/Semigroup"; import * as A from "fp-ts/Array"; import * as R from "fp-ts/Record"; import { constNull, pipe } from "fp-ts/function"; import { sanitizeImageURL } from "../lib/sanitizeImageURL"; import { stripURLQueryParameters } from "../lib/stripURLParameters"; import { Dependencies } from "../types"; /** * Returns the URL of an image from the value of an Image field. * * @param source - Image field data. * * @returns The URL of the image if an image is provided, `null` otherwise. */ const resolveUrl = (source: prismicT.ImageField): string | null => source.url ? sanitizeImageURL(stripURLQueryParameters(source.url)) : source.url ?? null; /** * Returns the width of an image from the value of an Image field. * * @param source - Image field data. * * @returns The width of the image if an image is provided, `undefined` otherwise. */ const resolveWidth = (source: prismicT.ImageField): number | undefined => source.dimensions?.width; /** * Returns the height of an image from the value of an Image field. * * @param source - Image field data. * * @returns The height of the image if an image is provided, `undefined` otherwise. */ const resolveHeight = (source: prismicT.ImageField): number | undefined => source.dimensions?.height; /** * The minimum required GraphQL argument properties for an `@imgix/gatsby` field. */ interface ImgixGatsbyFieldArgsLike { imgixParams: Record<string, string | number | boolean>; } /** * Modifies an `@imgix/gatsby` GraphQL field config to retain existing Imgix * parameters set on the source URL. * * This is needed if the source URL contains parameters like `rect` (crops an * image). Without this config enhancer, the `rect` parameter would be removed. * * @param fieldConfig - GraphQL field config object to be enhanced. * * @returns `fieldConfig` with the ability to retain existing Imgix parameters * on the source URL. */ const withExistingURLImgixParameters = < TContext, TArgs extends ImgixGatsbyFieldArgsLike, >( fieldConfig: gqlc.ObjectTypeComposerFieldConfigAsObjectDefinition< prismicT.ImageField, TContext, TArgs >, ): typeof fieldConfig => ({ ...fieldConfig, resolve: (source, args, ...rest) => pipe( O.Do, O.bind("url", () => O.fromNullable(source.url ? new URL(source.url) : null), ), O.bind("existingImgixParams", (scope) => pipe( [...scope.url.searchParams.entries()], R.fromFoldable(S.last<string>(), A.Foldable), O.of, ), ), O.map((scope) => fieldConfig.resolve?.( source, { ...args, imgixParams: { ...scope.existingImgixParams, ...args.imgixParams, }, }, ...rest, ), ), O.getOrElseW(constNull), ), }); /** * Builds a GraphQL field configuration object to be used as part of another * Image field GraphQL configuration object. For example, this base * configuration object could be added to a config for the thumbnails of an Image field. */ export const buildImageBaseFieldConfigMap: RTE.ReaderTaskEither< Dependencies, never, gqlc.ObjectTypeComposerFieldConfigMapDefinition<prismicT.ImageField, unknown> > = pipe( RTE.ask<Dependencies>(), RTE.bind("imgixTypes", (scope) => RTE.right( imgixGatsby.createImgixGatsbyTypes({ // IMPORTANT: These options need to be kept in sync with the options at // packages/gatsby-source-prismic/src/builders/buildImgixImageTypes.ts cache: scope.cache, resolveUrl, resolveWidth, resolveHeight, defaultParams: scope.pluginOptions.imageImgixParams, namespace: "Imgix", }), ), ), RTE.bind("urlField", (scope) => RTE.right(withExistingURLImgixParameters(scope.imgixTypes.fields.url)), ), RTE.bind("fixedField", (scope) => RTE.right(withExistingURLImgixParameters(scope.imgixTypes.fields.fixed)), ), RTE.bind("fluidField", (scope) => RTE.right(withExistingURLImgixParameters(scope.imgixTypes.fields.fluid)), ), RTE.bind("gatsbyImageDataField", (scope) => pipe( RTE.right( withExistingURLImgixParameters(scope.imgixTypes.fields.gatsbyImageData), ), // This field is 'JSON!' by default (i.e. non-nullable). If an image is // not set in Prismic, however, this field throws a GraphQL error saying a // non-nullable field was returned a null value. This should not happen // since the field is nested in a nullable object type, but it happens // anyway. // // We're making the field nullable manually here. RTE.chainFirst((field) => RTE.fromIO(() => (field.type = "JSON"))), ), ), RTE.map((scope) => ({ alt: "String", copyright: "String", dimensions: scope.globalNodeHelpers.createTypeName("ImageDimensionsType"), url: scope.urlField, fixed: scope.fixedField, fluid: scope.fluidField, gatsbyImageData: scope.gatsbyImageDataField, localFile: { type: "File", extensions: { link: {} }, }, })), );