@pothos/plugin-directives
Version:
Directive plugin for Pothos, enables using graphql-tools based directives with Pothos
171 lines (145 loc) • 4.64 kB
text/typescript
import './global-types';
import SchemaBuilder, {
BasePlugin,
type PothosEnumValueConfig,
type PothosInputFieldConfig,
type PothosOutputFieldConfig,
type PothosTypeConfig,
type SchemaTypes,
} from '@pothos/core';
import type { GraphQLSchema } from 'graphql';
import mockAst from './mock-ast';
import type { DirectiveList } from './types';
export * from './types';
const pluginName = 'directives';
export default pluginName;
export class PothosDirectivesPlugin<Types extends SchemaTypes> extends BasePlugin<Types> {
override onOutputFieldConfig(fieldConfig: PothosOutputFieldConfig<Types>) {
const options = fieldConfig.pothosOptions;
if (!options.directives && !fieldConfig.extensions?.directives) {
return fieldConfig;
}
return {
...fieldConfig,
extensions: {
...fieldConfig.extensions,
directives: this.normalizeDirectives(
this.mergeDirectives(
fieldConfig.extensions?.directives as Record<string, object>,
options.directives as unknown as Record<string, object>,
),
),
},
};
}
override onInputFieldConfig(fieldConfig: PothosInputFieldConfig<Types>) {
const options = fieldConfig.pothosOptions;
if (!options.directives && !fieldConfig.extensions?.directives) {
return fieldConfig;
}
return {
...fieldConfig,
extensions: {
...fieldConfig.extensions,
directives: this.normalizeDirectives(
this.mergeDirectives(
fieldConfig.extensions?.directives as Record<string, object>,
options.directives as unknown as Record<string, object>,
),
),
},
};
}
override onEnumValueConfig(valueConfig: PothosEnumValueConfig<Types>) {
const options = valueConfig.pothosOptions;
if (!options.directives && !valueConfig.extensions?.directives) {
return valueConfig;
}
return {
...valueConfig,
extensions: {
...valueConfig.extensions,
directives: this.normalizeDirectives(
this.mergeDirectives(
valueConfig.extensions?.directives as Record<string, object>,
options.directives as unknown as Record<string, object>,
),
),
},
};
}
override onTypeConfig(typeConfig: PothosTypeConfig) {
const options = typeConfig.pothosOptions;
if (!options.directives && !typeConfig.extensions?.directives) {
return typeConfig;
}
return {
...typeConfig,
extensions: {
...typeConfig.extensions,
directives: this.normalizeDirectives(
this.mergeDirectives(
typeConfig.extensions?.directives as Record<string, object>,
options.directives as unknown as Record<string, object>,
),
),
},
};
}
override afterBuild(schema: GraphQLSchema) {
schema.extensions = {
...schema.extensions,
directives: this.normalizeDirectives(
this.mergeDirectives(
(schema.extensions?.directives as Record<string, object>) ?? {},
this.options.schemaDirectives as unknown as Record<string, object>,
),
),
};
mockAst(schema);
return schema;
}
mergeDirectives(
left: DirectiveList | Record<string, object>,
right: DirectiveList | Record<string, object>,
) {
if (!(left && right)) {
return left || right;
}
return [
...(Array.isArray(left)
? left
: Object.keys(left).map((name) => ({ name, args: left[name] }))),
...(Array.isArray(right)
? right
: Object.keys(right).map((name) => ({ name, args: right[name] }))),
];
}
normalizeDirectives(directives: DirectiveList | Record<string, object>) {
if (this.builder.options.directives?.useGraphQLToolsUnorderedDirectives) {
if (!Array.isArray(directives)) {
return directives;
}
return directives.reduce<Record<string, {}[]>>((obj, directive) => {
if (obj[directive.name]) {
obj[directive.name].push(directive.args ?? {});
} else {
obj[directive.name] = [directive.args ?? {}];
}
return obj;
}, {});
}
if (Array.isArray(directives)) {
return directives;
}
return Object.keys(directives).map((name) => ({ name, args: directives[name] }));
}
}
SchemaBuilder.registerPlugin(pluginName, PothosDirectivesPlugin, {
v3: (options) => ({
useGraphQLToolsUnorderedDirectives: undefined,
directives: {
useGraphQLToolsUnorderedDirectives: options.useGraphQLToolsUnorderedDirectives,
},
}),
});