@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
JavaScript
;
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