@cran/lib.gql.core
Version:
GQL Core Functionality
93 lines (73 loc) • 2.51 kB
text/typescript
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { GraphQLSchema } from "graphql";
import type { IResolvers, TypeSource } from "@graphql-tools/utils";
import { makeExecutableSchema } from "@graphql-tools/schema";
export namespace Plugin {
export enum Phase {
PREPARE = 0, DEFAULT = 1, FINALIZE = 2,
}
export type Transformer =
( schema: GraphQLSchema ) => GraphQLSchema;
export type Transformers = {
[Key in `${Phase}`]?: Transformer;
};
export function apply<Context = any> (
plugin: Plugin<Context>
) {
let schema = makeExecutableSchema<Context>({
typeDefs : plugin.typeDefs ?? [ ],
resolvers: plugin.resolvers ?? { },
});
for (const phase of [ Phase.PREPARE, Phase.DEFAULT, Phase.FINALIZE, ]) {
schema = getTransformerByPhase(plugin, phase)?.(schema) ?? schema;
}
return schema;
}
export function compose<Context = any> (
plugins: Array<Plugin<Context>>
) {
return {
typeDefs: plugins.map(function mapTypeDefs ( plugin ) {
return plugin.typeDefs;
}),
resolvers: plugins.reduce<IResolvers<any, Context>>(
function reduceResolvers ( acc, plugin ) {
return Object.assign(acc, plugin.resolvers);
}, { }
),
transformer: {
[Phase.PREPARE] : composeTransformerByPhase(plugins, Phase.PREPARE),
[Phase.DEFAULT] : composeTransformerByPhase(plugins, Phase.DEFAULT),
[Phase.FINALIZE]: composeTransformerByPhase(plugins, Phase.FINALIZE),
},
} as const as Plugin<Context>;
}
export function composeTransformerByPhase<Context> (
plugins: Array<Plugin<Context>>, phase: Phase
) {
return function wrappedTransformerPhase ( schema: GraphQLSchema ) {
let current = schema;
for (const plugin of plugins) {
const transformer = getTransformerByPhase(plugin, phase);
if (transformer) { current = transformer(current); }
}
return current;
};
}
export function getTransformerByPhase<Context> (
plugin: Plugin<Context>, phase: Phase
) {
if ("object" === typeof plugin.transformer) {
return plugin.transformer[phase];
}
if (phase === Phase.DEFAULT && "function" === typeof plugin.transformer) {
return plugin.transformer;
}
return undefined;
}
}
export interface Plugin<Context = any> {
typeDefs? : TypeSource;
resolvers? : IResolvers<any, Context>;
transformer?: Plugin.Transformer | Plugin.Transformers;
}