UNPKG

@capaj/prisma-typegraphql-types-generator

Version:

Prisma generator for generating TypeGraphQL class types and enums, It works like a copilot where the generated output is very human readable and can be edited

305 lines 16.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const generator_helper_1 = require("@prisma/generator-helper"); const logger_1 = require("./utils/logger"); const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const constants_1 = require("./constants"); const templates_1 = require("./templates"); const decorator_1 = require("./templates/decorator"); const field_1 = require("./templates/field"); const import_1 = require("./templates/import"); const model_1 = require("./templates/model"); const convertType_1 = require("./utils/convertType"); const extractFieldsModifications_1 = require("./utils/extractFieldsModifications"); const hideOrPrivate_1 = require("./utils/hideOrPrivate"); const mkdir_1 = require("./utils/mkdir"); const modulesThatIsUsed_1 = require("./utils/modulesThatIsUsed"); const objectToString_1 = require("./utils/objectToString"); const child_process_1 = require("child_process"); const enum_1 = require("./templates/enum"); const replaceAll_1 = require("./utils/replaceAll"); const restoreClassChanges_1 = require("./utils/restoreClassChanges"); const restoreImportsSection_1 = require("./utils/restoreImportsSection"); const restoreDecoratorObjects_1 = require("./utils/restoreDecoratorObjects"); const format_1 = require("./utils/format"); const toPascalCase_1 = require("./utils/toPascalCase"); const defaultModelsOutput = path_1.default.join(process.cwd(), './src/generated/models'); const defaultEnumsOutput = path_1.default.join(process.cwd(), './src/generated/enums'); const installPackage = (useYarn, pkgName) => { const packageManager = useYarn ? 'yarn add' : 'npm i'; const hasGraphQLScalars = fs_1.default .readFileSync(path_1.default.join(process.cwd(), './package.json'), 'utf-8') .includes(`"${pkgName}"`); if (hasGraphQLScalars) return; logger_1.logger.info(`${constants_1.GENERATOR_NAME}:Installing ${pkgName}`); (0, child_process_1.spawn)(`${packageManager} ${pkgName}`, [], { shell: true, stdio: 'inherit', }); }; const { version } = require('../package.json'); (0, generator_helper_1.generatorHandler)({ onManifest: () => ({ defaultOutput: '../src/generated/models', prettyName: constants_1.GENERATOR_NAME, version, }), onGenerate: async (options) => { const extractedData = (0, extractFieldsModifications_1.ExtractFieldsModifications)(options.datamodel); const splitScalars = !!options.generator.config.splitScalarAndObjectTypeFields; const { config } = options.generator; const exportedNameSuffix = config.exportedNameSuffix || ''; const exportedNamePrefix = config.exportedNamePrefix || ''; const pascalCaseModelNames = !!config.pascalCaseModelNames; const modelsWriteLocation = config.modelsOutput || defaultModelsOutput; const enumWriteLocation = config.enumsOutput || defaultEnumsOutput; options.dmmf.datamodel.models.map(async (model) => { const getModelName = (name) => `${exportedNamePrefix}${pascalCaseModelNames ? (0, toPascalCase_1.toPascalCase)(name) : name}${exportedNameSuffix}`; const modelName = getModelName(model.name); const fileName = modelName + '.ts'; const writeLocation = path_1.default.join(modelsWriteLocation, fileName); const allFields = []; model.fields.map((field) => { const tsScalarType = `${(0, convertType_1.convertType)(field.type)}${field.isRequired ? '' : ' | null'}`; const fieldType = `${tsScalarType ? tsScalarType : getModelName(field.type)}${field.isList ? '[]' : ''}`; allFields.push({ field: field.name, type: fieldType }); }); const decoratorObjects = (0, restoreDecoratorObjects_1.restoreDecoratorObjects)(writeLocation, allFields.map((e) => ({ field: e.field.replace('?', ''), type: e.type, })), modelName); let dynamicImports = ''; const formattedFields = model.fields.map((field) => { const { isHide, isPrivate } = (0, hideOrPrivate_1.HideOrPrivate)(extractedData, field.name, model.name); if (isHide) return { hide: true, type: field.type }; const tsScalarType = (0, convertType_1.convertType)(field.type); const fieldType = `${tsScalarType ? tsScalarType : getModelName(field.type)}${field.isList ? '[]' : ''}${field.isRequired ? '' : ' | null'}`; const decoratorType = () => { const type = (type) => `(${options.generator.config.removeTypeInFieldDecorator ? '' : '_type'}) => ${type}`; const modifiedFieldType = field.kind === 'scalar' ? field.type : getModelName(field.type); const addDynamicImports = (exported) => { if (dynamicImports.split(',').find((e) => e.trim() === exported)) { return; } dynamicImports += `, ${exported}`; }; const getEquivalentType = () => { const convertedType = (0, convertType_1.convertType)(field.type); if (field.isId && field.type === 'String') { addDynamicImports('ID'); return 'ID'; } else if (field.type === 'Int') { addDynamicImports('Int'); return 'Int'; } else if (field.type === 'Float') { addDynamicImports('Float'); return 'Float'; } else if (field.type === 'DateTime') { addDynamicImports('GraphQLISODateTime'); return 'GraphQLISODateTime'; } else if (field.type === 'BigInt') { return 'GraphQLScalars.BigIntResolver'; } else if (convertedType === 'Prisma.JsonValue') { return 'GraphQLScalars.JSONResolver'; } else if (convertedType === 'Buffer') { return 'GraphQLScalars.ByteResolver'; } else if (convertedType === 'Prisma.Decimal') { return 'GraphQLDecimal'; } else { return modifiedFieldType; } }; const typeGraphQLType = getEquivalentType(); if (field.isList) { return type(`[${typeGraphQLType}]`); } else if (field.kind === 'object' && !field.isList) { return type(modifiedFieldType); } if (typeGraphQLType.length === 0 || (field.kind === 'scalar' && field.isRequired && !field.isId && field.type !== 'Json' && field.type !== 'Bytes' && !dynamicImports .split(',') .find((e) => e.trim() === typeGraphQLType))) { return ''; } return type(typeGraphQLType); }; const fieldName = field.name; const decoratorObject = () => { let object = {}; const editedOptions = decoratorObjects === null || decoratorObjects === void 0 ? void 0 : decoratorObjects.find((e) => e.field === field.name.replace('?', '')); if (editedOptions) { Object.keys(editedOptions.decorator).forEach((key) => editedOptions.decorator[key] === undefined && delete editedOptions.decorator[key]); } if (editedOptions && Object.keys((editedOptions === null || editedOptions === void 0 ? void 0 : editedOptions.decorator) || {}).length > 0) { const value = editedOptions.decorator; object = { ...object, ...value }; } if (!field.isRequired || isPrivate) { object.nullable = true; } else { object.nullable = undefined; } Object.keys(object).forEach((key) => object[key] === undefined && delete object[key]); if (Object.keys(object).length === 0) { return undefined; } return (0, objectToString_1.objToString)(object); }; const Decorator = (0, decorator_1.DECORATOR_TEMPLATE)(decoratorType(), decoratorObject()); const Field = (0, field_1.FIELD_TEMPLATE)(Decorator, '\n ' + fieldName, fieldType); return { field: Field, kind: field.kind }; }); const hidden = formattedFields.filter((e) => { if (e === null || e === void 0 ? void 0 : e.hide) return true; else return false; }); const scalarFields = formattedFields .filter((e) => { if (!(e === null || e === void 0 ? void 0 : e.field) || e.kind === 'object') return false; else return true; }) .map((e) => e.field); const objectsFields = formattedFields .filter((e) => { if (!(e === null || e === void 0 ? void 0 : e.field) || e.kind === 'scalar' || e.kind === 'enum') return false; else return true; }) .map((e) => e.field); const mergedFields = formattedFields .filter((e) => { if (!(e === null || e === void 0 ? void 0 : e.field)) return false; else return true; }) .map((e) => e.field); const dependsOn = (0, modulesThatIsUsed_1.modulesThatIsUsed)(options.dmmf.datamodel.models, model.name); let imports = []; imports.push((0, import_1.IMPORT_TEMPLATE)(`{ Field, ObjectType${dynamicImports} }`, `type-graphql`)); imports = [ ...imports, ...dependsOn .map(({ kind, name }) => { if (!hidden.find((e) => e.type === name)) { if (kind === 'object') { const importModelName = getModelName(name); if (importModelName === modelName) { return; } return (0, import_1.IMPORT_TEMPLATE)(`{ ${importModelName} }`, `./${getModelName(name)}`); } else if (kind === 'enum') { const relativePathToEnums = (0, replaceAll_1.replaceAll)(path_1.default.relative(path_1.default.join(process.cwd(), modelsWriteLocation), path_1.default.join(process.cwd(), enumWriteLocation)), '\\', '/'); const enumName = `${exportedNamePrefix}${name}${exportedNameSuffix}`; return (0, import_1.IMPORT_TEMPLATE)(`{ ${enumName} }`, `${relativePathToEnums}/${name}`); } } else { return 'remove'; } }) .filter((e) => e !== 'remove'), ]; const scalarsJoined = scalarFields.join('\n'); if (scalarsJoined.includes('Prisma.')) { imports.push((0, import_1.IMPORT_TEMPLATE)(`{ Prisma }`, options.generator.config.useDotPrismaImport ? `.prisma/client` : `@prisma/client`)); } if (scalarsJoined.includes('GraphQLScalars.')) { installPackage(options.generator.config.useYarn, 'graphql-scalars'); imports.push((0, import_1.IMPORT_TEMPLATE)(`* as GraphQLScalars`, `graphql-scalars`)); } if (scalarsJoined.includes('GraphQLDecimal')) { imports.push((0, import_1.IMPORT_TEMPLATE)(`{ GraphQLDecimal }`, 'prisma-graphql-type-decimal')); } const classChanges = (0, restoreClassChanges_1.restoreClassChanges)(writeLocation); const importsChanges = (0, restoreImportsSection_1.restoreImportsChanges)(writeLocation, modelName); if (!importsChanges) { imports.push(`\n@ObjectType()`); } const actualImportsThatChanged = importsChanges ? (await (0, format_1.format)(importsChanges .split('\n') .filter((e) => { return e.includes('import ') || e.includes('require('); }) .join('\n'))).split('\n') : null; const otherCodeThatChanged = importsChanges ? '\n' + (importsChanges === null || importsChanges === void 0 ? void 0 : importsChanges.split('\n').filter((e) => { return !e.includes('import ') && !e.includes('require('); }).join('\n')) : ''; let mergedImports = !importsChanges ? imports : [ ...new Set([ ...actualImportsThatChanged, ...(await (0, format_1.format)(imports.join('\n'))).split('\n'), ]), ]; const codeSplitted = (mergedImports.join('\n') + otherCodeThatChanged).split('\n'); const ObjectTypeIndex = codeSplitted.findIndex((e) => e.includes('@ObjectType')); if (codeSplitted[ObjectTypeIndex - 1].length !== 0) { if (otherCodeThatChanged.length) { mergedImports.push(''); } } let generatedModel; if (splitScalars) { const scalarsClass = (0, model_1.MODEL_TEMPLATE)(`${modelName}Scalars`, scalarFields.join('\n'), '\n}'); const objectsClass = (0, model_1.MODEL_TEMPLATE)(modelName, objectsFields.join('\n'), classChanges, ` extends ${modelName}Scalars`); generatedModel = (0, templates_1.INDEX_TEMPLATE)([scalarsClass, objectsClass].join('\n\n'), mergedImports.join('\n') + otherCodeThatChanged); } else { const wholeClass = (0, model_1.MODEL_TEMPLATE)(modelName, mergedFields.join('\n'), classChanges); generatedModel = (0, templates_1.INDEX_TEMPLATE)(wholeClass, mergedImports.filter((e) => e !== '').join('\n') + otherCodeThatChanged); } (0, mkdir_1.mkdir)(writeLocation, fileName); fs_1.default.writeFileSync(writeLocation, await (0, format_1.format)(generatedModel)); }); options.dmmf.datamodel.enums.map(async (prismaEnum) => { const fileName = prismaEnum.name + '.ts'; const writeLocation = path_1.default.join(enumWriteLocation, fileName); const enumName = `${exportedNamePrefix}${prismaEnum.name}${exportedNameSuffix}`; const generatedEnum = (0, enum_1.ENUM_TEMPLATE)(enumName, prismaEnum.values.map((e) => ` ${e.name} = '${e.name}'`).join(',\n'), prismaEnum.name); (0, mkdir_1.mkdir)(writeLocation, fileName); fs_1.default.writeFileSync(writeLocation, await (0, format_1.format)(generatedEnum)); }); logger_1.logger.info(`${constants_1.GENERATOR_NAME}:Generated Successfully!`); }, }); logger_1.logger.info(`${constants_1.GENERATOR_NAME}:Registered`); //# sourceMappingURL=generator.js.map