UNPKG

@cran/lib.gql.core

Version:

GQL Core Functionality

102 lines (80 loc) 2.66 kB
import type { getDirective } from "@graphql-tools/utils"; import { type GraphQLOutputType, type GraphQLSchema, isOutputType, } from "graphql"; import { Plugin } from "./Plugin"; import { type IntrospectionKind, IntrospectionType, type SchemaMapperArgs, createDirective, getExtension, patchField, setExtension, } from "../utilities"; export namespace withMetadata { export type Fallback = ( value: Parameters<typeof getDirective>[1], name: string ) => unknown; export type Fields = Record<IntrospectionKind | "default", Record<string, string>>; export type Names = Partial<Record<IntrospectionKind, string>>; export type Fallbacks = Partial<Record<IntrospectionKind, Fallback>>; export interface Options { fields : Fields; names? : Names; fallbacks?: Fallbacks; } } export function withMetadata ( options: withMetadata.Options ) { const plugins: Array<Plugin> = [ ]; for (const key in options.fields) { if ("default" !== key) { const kind = key as IntrospectionKind; plugins.push(createDirective( options.names?.[kind] ?? `${IntrospectionType[kind].name.slice(2)}Metadata`, { ...options.fields.default, ...options.fields[kind], }, { [kind]: directiveMapper, } )); } } plugins.push({ transformer: { [Plugin.Phase.FINALIZE] ( schema ) { for (const name in options.fields) { if ("default" !== name) { addFields(schema, name as IntrospectionKind, options); } } return schema; }, }, }); return plugins; } function directiveMapper ( [ directive, ]: Array<Record<string, unknown>>, type: SchemaMapperArgs[0] ) { setExtension(type, "metadata", directive); } function addFields ( schema: GraphQLSchema, kind: IntrospectionKind, options: withMetadata.Options ) { const field = options.fields[kind]; for (const key in field) { const type = schema.getType(field[key]!); if (!type || !isOutputType(type)) { throw new TypeError(`MetadataPlugin expects "GraphQLOutputType" received "${type?.name}"`); } addField(kind, key, type, options); } } function addField ( kind: IntrospectionKind, key: string, type: GraphQLOutputType, options: withMetadata.Options ) { const fallback = options.fallbacks?.[kind] || alwaysNull; patchField(IntrospectionType[kind], key, { type, resolve ( source: Parameters<withMetadata.Fallback>[0] ) { const value = getExtension<Record<string, unknown>>(source, "metadata")?.[key]; return value ?? fallback(source, key); }, }); } function alwaysNull ( ): null { return null; }