@graphql-codegen/typescript-nest
Version:
GraphQL Code Generator plugin for generating NestJS compatible types
268 lines (267 loc) • 14 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NestVisitor = void 0;
const tslib_1 = require("tslib");
const auto_bind_1 = tslib_1.__importDefault(require("auto-bind"));
const graphql_1 = require("graphql");
const typescript_1 = require("@graphql-codegen/typescript");
const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common");
const constants_js_1 = require("./constants.js");
const utils_js_1 = require("./utils.js");
class NestVisitor extends typescript_1.TsVisitor {
constructor(schema, pluginConfig, additionalConfig = {}) {
super(schema, pluginConfig, {
avoidOptionals: (0, visitor_plugin_common_1.getConfigValue)(pluginConfig.avoidOptionals, false),
maybeValue: (0, visitor_plugin_common_1.getConfigValue)(pluginConfig.maybeValue, 'T | null'),
constEnums: (0, visitor_plugin_common_1.getConfigValue)(pluginConfig.constEnums, false),
enumsAsTypes: (0, visitor_plugin_common_1.getConfigValue)(pluginConfig.enumsAsTypes, false),
immutableTypes: (0, visitor_plugin_common_1.getConfigValue)(pluginConfig.immutableTypes, false),
declarationKind: {
type: 'class',
interface: 'abstract class',
arguments: 'class',
input: 'class',
scalar: 'type',
},
decoratorName: {
type: 'ObjectType',
interface: 'InterfaceType',
arguments: 'ArgsType',
field: 'Field',
input: 'InputType',
...pluginConfig.decoratorName,
},
decorateTypes: (0, visitor_plugin_common_1.getConfigValue)(pluginConfig.decorateTypes, undefined),
disableDescriptions: (0, visitor_plugin_common_1.getConfigValue)(pluginConfig.disableDescriptions, false),
...additionalConfig,
});
(0, auto_bind_1.default)(this);
this.typescriptVisitor = new typescript_1.TsVisitor(schema, pluginConfig, additionalConfig);
const enumNames = Object.values(schema.getTypeMap())
.map(type => (type instanceof graphql_1.GraphQLEnumType ? type.name : undefined))
.filter(t => t);
this.setArgumentsTransformer(new typescript_1.TypeScriptOperationVariablesToObject(this.scalars, this.convertName, this.config.avoidOptionals, this.config.immutableTypes, null, enumNames, this.config.enumPrefix, this.config.enumValues, undefined, undefined, 'Maybe'));
this.setDeclarationBlockConfig({
enumNameValueSeparator: ' =',
});
}
getBaseDecoratorOptions(node) {
const decoratorOptions = {};
if (node.description) {
// If we have a description, add it to the decorator options
decoratorOptions.description = (0, utils_js_1.escapeString)(typeof node.description === 'string' ? node.description : node.description.value);
}
return decoratorOptions;
}
getWrapperDefinitions() {
return [...super.getWrapperDefinitions(), this.getFixDecoratorDefinition()];
}
getFixDecoratorDefinition() {
return `${this.getExportPrefix()}${constants_js_1.FIX_DECORATOR_SIGNATURE}`;
}
getMaybeWrapper() {
return 'Maybe';
}
buildArgumentsBlock(node) {
const fieldsWithArguments = node.fields.filter(field => field.arguments && field.arguments.length > 0) || [];
return fieldsWithArguments
.map(field => {
const name = node.name.value +
(this.config.addUnderscoreToArgsType ? '_' : '') +
this.convertName(field, {
useTypesPrefix: false,
useTypesSuffix: false,
}) +
'Args';
if (this.shouldBeDecorated(name)) {
return this.getArgumentsObjectTypeDefinition(node, name, field);
}
return this.typescriptVisitor.getArgumentsObjectTypeDefinition(node, name, field);
})
.join('\n\n');
}
ObjectTypeDefinition(node, key, parent) {
var _a;
const nodeName = typeof node.name === 'string' ? node.name : node.name.value;
const isGraphQLType = constants_js_1.GRAPHQL_TYPES.includes(nodeName);
if (!isGraphQLType && !this.shouldBeDecorated(nodeName)) {
return this.typescriptVisitor.ObjectTypeDefinition(node, key, parent);
}
const typeDecorator = this.config.decoratorName.type;
const originalNode = parent[key];
const decoratorOptions = this.getBaseDecoratorOptions(originalNode);
let declarationBlock;
if (isGraphQLType) {
declarationBlock = this.typescriptVisitor.getObjectTypeDeclarationBlock(node, originalNode);
}
else {
declarationBlock = this.getObjectTypeDeclarationBlock(node, originalNode);
// Add decorator
const interfaces = ((_a = originalNode.interfaces) === null || _a === void 0 ? void 0 : _a.map(i => this.convertName(i))) || [];
if (interfaces.length > 1) {
decoratorOptions.implements = `[${interfaces.join(', ')}]`;
}
else if (interfaces.length === 1) {
decoratorOptions.implements = interfaces[0];
}
declarationBlock = declarationBlock.withDecorator(`@${constants_js_1.NEST_PREFIX}.${typeDecorator}(${(0, utils_js_1.formatDecoratorOptions)(decoratorOptions)})`);
}
// Remove comment added by typescript plugin
declarationBlock._comment = undefined;
return [declarationBlock.string, this.buildArgumentsBlock(originalNode)]
.filter(f => f)
.join('\n\n');
}
InputObjectTypeDefinition(node) {
if (!this.shouldBeDecorated(typeof node.name === 'string' ? node.name : node.name.value)) {
return this.typescriptVisitor.InputObjectTypeDefinition(node);
}
const typeDecorator = this.config.decoratorName.input;
const decoratorOptions = this.getBaseDecoratorOptions(node);
const declarationBlock = this.getInputObjectDeclarationBlock(node).withDecorator(`@${constants_js_1.NEST_PREFIX}.${typeDecorator}(${(0, utils_js_1.formatDecoratorOptions)(decoratorOptions)})`);
return declarationBlock.string;
}
getArgumentsObjectDeclarationBlock(node, name, field) {
return new visitor_plugin_common_1.DeclarationBlock(this._declarationBlockConfig)
.export()
.asKind(this._parsedConfig.declarationKind.arguments)
.withName(this.convertName(name))
.withComment(node.description)
.withBlock(field.arguments.map(argument => this.InputValueDefinition(argument)).join('\n'));
}
getArgumentsObjectTypeDefinition(node, name, field) {
const typeDecorator = this.config.decoratorName.arguments;
const declarationBlock = this.getArgumentsObjectDeclarationBlock(node, name, field).withDecorator(`@${constants_js_1.NEST_PREFIX}.${typeDecorator}()`);
return declarationBlock.string;
}
InterfaceTypeDefinition(node, key, parent) {
if (!this.shouldBeDecorated(typeof node.name === 'string' ? node.name : node.name.value)) {
return this.typescriptVisitor.InterfaceTypeDefinition(node, key, parent);
}
const interfaceDecorator = this.config.decoratorName.interface;
const originalNode = parent[key];
const decoratorOptions = this.getBaseDecoratorOptions(originalNode);
const declarationBlock = this.getInterfaceTypeDeclarationBlock(node, originalNode).withDecorator(`@${constants_js_1.NEST_PREFIX}.${interfaceDecorator}(${(0, utils_js_1.formatDecoratorOptions)(decoratorOptions)})`);
return [declarationBlock.string, this.buildArgumentsBlock(originalNode)]
.filter(f => f)
.join('\n\n');
}
shouldBeDecorated(name) {
if (constants_js_1.GRAPHQL_TYPES.includes(name)) {
return false;
}
if (!this.config.decorateTypes) {
return true;
}
return this.config.decorateTypes.includes(name);
}
parseType(type) {
if (typeof type === 'string') {
const isNullable = !!type.match(constants_js_1.MAYBE_REGEX);
const nonNullableType = type.replace(constants_js_1.MAYBE_REGEX, '$1');
const isArray = !!nonNullableType.match(constants_js_1.ARRAY_REGEX);
const singularType = nonNullableType.replace(constants_js_1.ARRAY_REGEX, '$1');
const isSingularTypeNullable = !!singularType.match(constants_js_1.MAYBE_REGEX);
const singularNonNullableType = singularType.replace(constants_js_1.MAYBE_REGEX, '$1');
const isScalar = !!singularNonNullableType.match(constants_js_1.SCALAR_REGEX);
const resolvedType = singularNonNullableType.replace(constants_js_1.SCALAR_REGEX, (_match, type) => {
if (constants_js_1.NEST_SCALARS.includes(type)) {
return `${constants_js_1.NEST_PREFIX}.${type}`;
}
if (global[type]) {
return type;
}
if (this.scalars[type]) {
return this.scalars[type];
}
throw new Error(`Unknown scalar type ${type}`);
});
return {
type: resolvedType,
isNullable,
isArray,
isScalar,
isItemsNullable: isArray && isSingularTypeNullable,
};
}
else {
const typeNode = type;
if (typeNode.kind === 'NamedType') {
return {
type: typeNode.name.value,
isNullable: true,
isArray: false,
isItemsNullable: false,
isScalar: constants_js_1.SCALARS.includes(typeNode.name.value),
};
}
if (typeNode.kind === 'NonNullType') {
return {
...this.parseType(typeNode.type),
isNullable: false,
};
}
if (typeNode.kind === 'ListType') {
return {
...this.parseType(typeNode.type),
isArray: true,
isNullable: true,
};
}
}
throw new Error(`Unknown type ${type}`);
}
FieldDefinition(node, key, parent, _path, ancestors) {
var _a, _b;
const parentName = (_b = (_a = ancestors === null || ancestors === void 0 ? void 0 : ancestors[ancestors.length - 1]) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.value;
if (!this.shouldBeDecorated(parentName)) {
return this.typescriptVisitor.FieldDefinition(node, key, parent);
}
const fieldDecorator = this.config.decoratorName.field;
let typeString = node.type;
const type = this.parseType(typeString);
const decoratorOptions = this.getBaseDecoratorOptions(node);
const nullableValue = (0, utils_js_1.getNestNullableValue)(type);
if (nullableValue) {
decoratorOptions.nullable = nullableValue;
}
const decorator = '\n' +
(0, visitor_plugin_common_1.indent)(`@${constants_js_1.NEST_PREFIX}.${fieldDecorator}(type => ${type.isArray ? `[${type.type}]` : type.type}${(0, utils_js_1.formatDecoratorOptions)(decoratorOptions, false)})`) +
'\n';
typeString = (0, utils_js_1.fixDecorator)(type, typeString);
return (decorator +
(0, visitor_plugin_common_1.indent)(`${this.config.immutableTypes ? 'readonly ' : ''}${node.name}${type.isNullable ? '?' : '!'}: ${typeString};`));
}
InputValueDefinition(node, key, parent, path, ancestors) {
const parentName = ancestors === null || ancestors === void 0 ? void 0 : ancestors[ancestors.length - 1].name.value;
if (parent && !this.shouldBeDecorated(parentName)) {
return this.typescriptVisitor.InputValueDefinition(node, key, parent, path, ancestors);
}
const fieldDecorator = this.config.decoratorName.field;
const rawType = node.type;
const type = this.parseType(rawType);
const nestType = type.isScalar && constants_js_1.NEST_SCALARS.includes(type.type) ? `${constants_js_1.NEST_PREFIX}.${type.type}` : type.type;
const decoratorOptions = this.getBaseDecoratorOptions(node);
const nullableValue = (0, utils_js_1.getNestNullableValue)(type);
if (nullableValue) {
decoratorOptions.nullable = nullableValue;
}
const decorator = '\n' +
(0, visitor_plugin_common_1.indent)(`@${constants_js_1.NEST_PREFIX}.${fieldDecorator}(type => ${type.isArray ? `[${nestType}]` : nestType}${(0, utils_js_1.formatDecoratorOptions)(decoratorOptions, false)})`) +
'\n';
const nameString = node.name.kind ? node.name.value : node.name;
const typeString = rawType.kind
? (0, utils_js_1.buildTypeString)(type)
: (0, utils_js_1.fixDecorator)(type, rawType);
return (decorator +
(0, visitor_plugin_common_1.indent)(`${this.config.immutableTypes ? 'readonly ' : ''}${nameString}${type.isNullable ? '?' : '!'}: ${typeString};`));
}
EnumTypeDefinition(node) {
if (!this.shouldBeDecorated(typeof node.name === 'string' ? node.name : node.name.value)) {
return this.typescriptVisitor.EnumTypeDefinition(node);
}
return (super.EnumTypeDefinition(node) +
`${constants_js_1.NEST_PREFIX}.registerEnumType(${this.convertName(node)}, { name: '${this.convertName(node)}' });\n`);
}
}
exports.NestVisitor = NestVisitor;