@gadmin2n/prisma-nest-generator 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +177 -0
- package/README.md +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +4 -0
- package/dist/generator/annotations.d.ts +14 -0
- package/dist/generator/annotations.js +28 -0
- package/dist/generator/compute-model-params/compute-connect-dto-params.d.ts +7 -0
- package/dist/generator/compute-model-params/compute-connect-dto-params.js +14 -0
- package/dist/generator/compute-model-params/compute-create-dto-params.d.ts +9 -0
- package/dist/generator/compute-model-params/compute-create-dto-params.js +80 -0
- package/dist/generator/compute-model-params/compute-entity-params.d.ts +9 -0
- package/dist/generator/compute-model-params/compute-entity-params.js +74 -0
- package/dist/generator/compute-model-params/compute-update-dto-params.d.ts +9 -0
- package/dist/generator/compute-model-params/compute-update-dto-params.js +72 -0
- package/dist/generator/compute-model-params/index.d.ts +9 -0
- package/dist/generator/compute-model-params/index.js +22 -0
- package/dist/generator/field-classifiers.d.ts +14 -0
- package/dist/generator/field-classifiers.js +51 -0
- package/dist/generator/generate-connect-dto.d.ts +7 -0
- package/dist/generator/generate-connect-dto.js +14 -0
- package/dist/generator/generate-controller-spec.d.ts +8 -0
- package/dist/generator/generate-controller-spec.js +28 -0
- package/dist/generator/generate-controller.d.ts +8 -0
- package/dist/generator/generate-controller.js +207 -0
- package/dist/generator/generate-create-dto.d.ts +8 -0
- package/dist/generator/generate-create-dto.js +15 -0
- package/dist/generator/generate-entity.d.ts +7 -0
- package/dist/generator/generate-entity.js +16 -0
- package/dist/generator/generate-form-validator-class.d.ts +8 -0
- package/dist/generator/generate-form-validator-class.js +42 -0
- package/dist/generator/generate-module.d.ts +8 -0
- package/dist/generator/generate-module.js +18 -0
- package/dist/generator/generate-modules-index.d.ts +8 -0
- package/dist/generator/generate-modules-index.js +13 -0
- package/dist/generator/generate-service-spec.d.ts +8 -0
- package/dist/generator/generate-service-spec.js +406 -0
- package/dist/generator/generate-service.d.ts +8 -0
- package/dist/generator/generate-service.js +91 -0
- package/dist/generator/generate-types-dto.d.ts +7 -0
- package/dist/generator/generate-types-dto.js +160 -0
- package/dist/generator/generate-update-dto.d.ts +8 -0
- package/dist/generator/generate-update-dto.js +12 -0
- package/dist/generator/helpers.d.ts +32 -0
- package/dist/generator/helpers.js +167 -0
- package/dist/generator/index.d.ts +17 -0
- package/dist/generator/index.js +187 -0
- package/dist/generator/template-helpers.d.ts +56 -0
- package/dist/generator/template-helpers.js +138 -0
- package/dist/generator/types.d.ts +56 -0
- package/dist/generator/types.js +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +77 -0
- package/package.json +71 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { DMMF } from '@prisma/generator-helper';
|
|
2
|
+
import type { TemplateHelpers } from './template-helpers';
|
|
3
|
+
import type { ImportStatementParams, Model, ParsedField } from './types';
|
|
4
|
+
export declare const uniq: <T = any>(input: T[]) => T[];
|
|
5
|
+
export declare const concatIntoArray: <T = any>(source: T[], target: T[]) => void;
|
|
6
|
+
export declare const makeImportsFromPrismaClient: (fields: ParsedField[]) => ImportStatementParams | null;
|
|
7
|
+
export declare const mapDMMFToParsedField: (field: DMMF.Field, overrides?: Partial<DMMF.Field>) => ParsedField;
|
|
8
|
+
export declare const getRelationScalars: (fields: DMMF.Field[]) => Record<string, string[]>;
|
|
9
|
+
interface GetRelationConnectInputFieldsParam {
|
|
10
|
+
field: DMMF.Field;
|
|
11
|
+
allModels: DMMF.Model[];
|
|
12
|
+
}
|
|
13
|
+
export declare const getRelationConnectInputFields: ({ field, allModels, }: GetRelationConnectInputFieldsParam) => Set<DMMF.Field>;
|
|
14
|
+
export declare const getRelativePath: (from: string, to: string) => string;
|
|
15
|
+
interface GenerateRelationInputParam {
|
|
16
|
+
field: DMMF.Field;
|
|
17
|
+
model: Model;
|
|
18
|
+
allModels: Model[];
|
|
19
|
+
templateHelpers: TemplateHelpers;
|
|
20
|
+
preAndSuffixClassName: TemplateHelpers['createDtoName'] | TemplateHelpers['updateDtoName'];
|
|
21
|
+
canCreateAnnotation: RegExp;
|
|
22
|
+
canConnectAnnotation: RegExp;
|
|
23
|
+
}
|
|
24
|
+
export declare const generateRelationInput: ({ field, model, allModels, templateHelpers: t, preAndSuffixClassName, canCreateAnnotation, canConnectAnnotation, }: GenerateRelationInputParam) => {
|
|
25
|
+
type: string;
|
|
26
|
+
imports: ImportStatementParams[];
|
|
27
|
+
generatedClasses: string[];
|
|
28
|
+
apiExtraModels: string[];
|
|
29
|
+
};
|
|
30
|
+
export declare const mergeImportStatements: (first: ImportStatementParams, second: ImportStatementParams) => ImportStatementParams;
|
|
31
|
+
export declare const zipImportStatementParams: (items: ImportStatementParams[]) => ImportStatementParams[];
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.zipImportStatementParams = exports.mergeImportStatements = exports.generateRelationInput = exports.getRelativePath = exports.getRelationConnectInputFields = exports.getRelationScalars = exports.mapDMMFToParsedField = exports.makeImportsFromPrismaClient = exports.concatIntoArray = exports.uniq = void 0;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const slash_1 = __importDefault(require("slash"));
|
|
9
|
+
const field_classifiers_1 = require("./field-classifiers");
|
|
10
|
+
const template_helpers_1 = require("./template-helpers");
|
|
11
|
+
const uniq = (input) => Array.from(new Set(input));
|
|
12
|
+
exports.uniq = uniq;
|
|
13
|
+
const concatIntoArray = (source, target) => source.forEach((item) => target.push(item));
|
|
14
|
+
exports.concatIntoArray = concatIntoArray;
|
|
15
|
+
const makeImportsFromPrismaClient = (fields) => {
|
|
16
|
+
const enumsToImport = (0, exports.uniq)(fields.filter(({ kind }) => kind === 'enum').map(({ type }) => type));
|
|
17
|
+
const importPrisma = fields
|
|
18
|
+
.filter(({ kind }) => kind === 'scalar')
|
|
19
|
+
.some(({ type }) => (0, template_helpers_1.scalarToTS)(type).includes('Prisma'));
|
|
20
|
+
if (!(enumsToImport.length || importPrisma)) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
from: '@prisma/client',
|
|
25
|
+
destruct: importPrisma ? ['Prisma', ...enumsToImport] : enumsToImport,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
exports.makeImportsFromPrismaClient = makeImportsFromPrismaClient;
|
|
29
|
+
const mapDMMFToParsedField = (field, overrides = {}) => ({
|
|
30
|
+
...field,
|
|
31
|
+
...overrides,
|
|
32
|
+
});
|
|
33
|
+
exports.mapDMMFToParsedField = mapDMMFToParsedField;
|
|
34
|
+
const getRelationScalars = (fields) => {
|
|
35
|
+
const scalars = fields.flatMap(({ relationFromFields = [] }) => relationFromFields);
|
|
36
|
+
return scalars.reduce((result, scalar) => ({
|
|
37
|
+
...result,
|
|
38
|
+
[scalar]: fields
|
|
39
|
+
.filter(({ relationFromFields = [] }) => relationFromFields.includes(scalar))
|
|
40
|
+
.map(({ name }) => name),
|
|
41
|
+
}), {});
|
|
42
|
+
};
|
|
43
|
+
exports.getRelationScalars = getRelationScalars;
|
|
44
|
+
const getRelationConnectInputFields = ({ field, allModels, }) => {
|
|
45
|
+
const { name, type, relationToFields = [] } = field;
|
|
46
|
+
if (!(0, field_classifiers_1.isRelation)(field)) {
|
|
47
|
+
throw new Error(`Can not resolve RelationConnectInputFields for field '${name}'. Not a relation field.`);
|
|
48
|
+
}
|
|
49
|
+
const relatedModel = allModels.find(({ name: modelName }) => modelName === type);
|
|
50
|
+
if (!relatedModel) {
|
|
51
|
+
throw new Error(`Can not resolve RelationConnectInputFields for field '${name}'. Related model '${type}' unknown.`);
|
|
52
|
+
}
|
|
53
|
+
if (!relationToFields.length) {
|
|
54
|
+
throw new Error(`Can not resolve RelationConnectInputFields for field '${name}'. Foreign keys are unknown.`);
|
|
55
|
+
}
|
|
56
|
+
const foreignKeyFields = relationToFields.map((relationToFieldName) => {
|
|
57
|
+
const relatedField = relatedModel.fields.find((relatedModelField) => relatedModelField.name === relationToFieldName);
|
|
58
|
+
if (!relatedField)
|
|
59
|
+
throw new Error(`Can not find foreign key field '${relationToFieldName}' on model '${relatedModel.name}'`);
|
|
60
|
+
return relatedField;
|
|
61
|
+
});
|
|
62
|
+
const idFields = relatedModel.fields.filter((relatedModelField) => (0, field_classifiers_1.isId)(relatedModelField));
|
|
63
|
+
const uniqueFields = relatedModel.fields.filter((relatedModelField) => (0, field_classifiers_1.isUnique)(relatedModelField));
|
|
64
|
+
const foreignFields = new Set([
|
|
65
|
+
...foreignKeyFields,
|
|
66
|
+
...idFields,
|
|
67
|
+
...uniqueFields,
|
|
68
|
+
]);
|
|
69
|
+
return foreignFields;
|
|
70
|
+
};
|
|
71
|
+
exports.getRelationConnectInputFields = getRelationConnectInputFields;
|
|
72
|
+
const getRelativePath = (from, to) => {
|
|
73
|
+
const result = (0, slash_1.default)(node_path_1.default.relative(from, to));
|
|
74
|
+
return result || '.';
|
|
75
|
+
};
|
|
76
|
+
exports.getRelativePath = getRelativePath;
|
|
77
|
+
const generateRelationInput = ({ field, model, allModels, templateHelpers: t, preAndSuffixClassName, canCreateAnnotation, canConnectAnnotation, }) => {
|
|
78
|
+
const relationInputClassProps = [];
|
|
79
|
+
const imports = [];
|
|
80
|
+
const apiExtraModels = [];
|
|
81
|
+
const generatedClasses = [];
|
|
82
|
+
if (true || (0, field_classifiers_1.isAnnotatedWith)(field, canCreateAnnotation)) {
|
|
83
|
+
const preAndPostfixedName = t.createDtoName(field.type);
|
|
84
|
+
apiExtraModels.push(preAndPostfixedName);
|
|
85
|
+
const modelToImportFrom = allModels.find(({ name }) => name === field.type);
|
|
86
|
+
if (!modelToImportFrom)
|
|
87
|
+
throw new Error(`related model '${field.type}' for '${model.name}.${field.name}' not found`);
|
|
88
|
+
imports.push({
|
|
89
|
+
from: (0, slash_1.default)(`${(0, exports.getRelativePath)(model.output.dto, modelToImportFrom.output.dto)}${node_path_1.default.sep}${t.createDtoFilename(field.type)}`),
|
|
90
|
+
destruct: [preAndPostfixedName],
|
|
91
|
+
});
|
|
92
|
+
relationInputClassProps.push({
|
|
93
|
+
name: 'create',
|
|
94
|
+
type: preAndPostfixedName,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (true || (0, field_classifiers_1.isAnnotatedWith)(field, canConnectAnnotation)) {
|
|
98
|
+
const preAndPostfixedName = t.connectDtoName(field.type);
|
|
99
|
+
apiExtraModels.push(preAndPostfixedName);
|
|
100
|
+
const modelToImportFrom = allModels.find(({ name }) => name === field.type);
|
|
101
|
+
if (!modelToImportFrom)
|
|
102
|
+
throw new Error(`related model '${field.type}' for '${model.name}.${field.name}' not found`);
|
|
103
|
+
imports.push({
|
|
104
|
+
from: (0, slash_1.default)(`${(0, exports.getRelativePath)(model.output.dto, modelToImportFrom.output.dto)}${node_path_1.default.sep}${t.connectDtoFilename(field.type)}`),
|
|
105
|
+
destruct: [preAndPostfixedName],
|
|
106
|
+
});
|
|
107
|
+
relationInputClassProps.push({
|
|
108
|
+
name: 'connect',
|
|
109
|
+
type: preAndPostfixedName,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (!relationInputClassProps.length) {
|
|
113
|
+
throw new Error(`Can not find relation input props for '${model.name}.${field.name}'`);
|
|
114
|
+
}
|
|
115
|
+
const originalInputClassName = `${t.transformClassNameCase(model.name)}${t.transformClassNameCase(field.name)}RelationInput`;
|
|
116
|
+
const preAndPostfixedInputClassName = preAndSuffixClassName(originalInputClassName);
|
|
117
|
+
generatedClasses.push(`class ${preAndPostfixedInputClassName} {
|
|
118
|
+
${t.fieldsToDtoProps(relationInputClassProps.map((inputField) => ({
|
|
119
|
+
...inputField,
|
|
120
|
+
kind: 'relation-input',
|
|
121
|
+
isRequired: relationInputClassProps.length === 1,
|
|
122
|
+
isList: field.isList,
|
|
123
|
+
})), true)}
|
|
124
|
+
}`);
|
|
125
|
+
apiExtraModels.push(preAndPostfixedInputClassName);
|
|
126
|
+
return {
|
|
127
|
+
type: preAndPostfixedInputClassName,
|
|
128
|
+
imports,
|
|
129
|
+
generatedClasses,
|
|
130
|
+
apiExtraModels,
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
exports.generateRelationInput = generateRelationInput;
|
|
134
|
+
const mergeImportStatements = (first, second) => {
|
|
135
|
+
if (first.from !== second.from) {
|
|
136
|
+
throw new Error(`Can not merge import statements; 'from' parameter is different`);
|
|
137
|
+
}
|
|
138
|
+
if (first.default && second.default) {
|
|
139
|
+
throw new Error(`Can not merge import statements; both statements have set the 'default' preoperty`);
|
|
140
|
+
}
|
|
141
|
+
const firstDestruct = first.destruct || [];
|
|
142
|
+
const secondDestruct = second.destruct || [];
|
|
143
|
+
const destructStrings = (0, exports.uniq)([...firstDestruct, ...secondDestruct].filter((destructItem) => typeof destructItem === 'string'));
|
|
144
|
+
const destructObject = [...firstDestruct, ...secondDestruct].reduce((result, destructItem) => {
|
|
145
|
+
if (typeof destructItem === 'string')
|
|
146
|
+
return result;
|
|
147
|
+
return { ...result, ...destructItem };
|
|
148
|
+
}, {});
|
|
149
|
+
return {
|
|
150
|
+
...first,
|
|
151
|
+
...second,
|
|
152
|
+
destruct: [...destructStrings, destructObject],
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
exports.mergeImportStatements = mergeImportStatements;
|
|
156
|
+
const zipImportStatementParams = (items) => {
|
|
157
|
+
const itemsByFrom = items.reduce((result, item) => {
|
|
158
|
+
const { from } = item;
|
|
159
|
+
const { [from]: existingItem } = result;
|
|
160
|
+
if (!existingItem) {
|
|
161
|
+
return { ...result, [from]: item };
|
|
162
|
+
}
|
|
163
|
+
return { ...result, [from]: (0, exports.mergeImportStatements)(existingItem, item) };
|
|
164
|
+
}, {});
|
|
165
|
+
return Object.values(itemsByFrom);
|
|
166
|
+
};
|
|
167
|
+
exports.zipImportStatementParams = zipImportStatementParams;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DMMF } from '@prisma/generator-helper';
|
|
2
|
+
import { NamingStyle, WriteableFileSpecs } from './types';
|
|
3
|
+
interface RunParam {
|
|
4
|
+
output: string;
|
|
5
|
+
dmmf: DMMF.Document;
|
|
6
|
+
exportRelationModifierClasses: boolean;
|
|
7
|
+
outputToNestJsResourceStructure: boolean;
|
|
8
|
+
connectDtoPrefix: string;
|
|
9
|
+
createDtoPrefix: string;
|
|
10
|
+
updateDtoPrefix: string;
|
|
11
|
+
dtoSuffix: string;
|
|
12
|
+
entityPrefix: string;
|
|
13
|
+
entitySuffix: string;
|
|
14
|
+
fileNamingStyle: NamingStyle;
|
|
15
|
+
}
|
|
16
|
+
export declare const run: ({ output, dmmf, ...options }: RunParam) => WriteableFileSpecs[];
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.run = void 0;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const case_1 = require("case");
|
|
9
|
+
const sdk_1 = require("@prisma/sdk");
|
|
10
|
+
const template_helpers_1 = require("./template-helpers");
|
|
11
|
+
const compute_model_params_1 = require("./compute-model-params");
|
|
12
|
+
const generate_modules_index_1 = require("./generate-modules-index");
|
|
13
|
+
const generate_connect_dto_1 = require("./generate-connect-dto");
|
|
14
|
+
const generate_create_dto_1 = require("./generate-create-dto");
|
|
15
|
+
const generate_update_dto_1 = require("./generate-update-dto");
|
|
16
|
+
const generate_entity_1 = require("./generate-entity");
|
|
17
|
+
const generate_module_1 = require("./generate-module");
|
|
18
|
+
const generate_service_1 = require("./generate-service");
|
|
19
|
+
const generate_service_spec_1 = require("./generate-service-spec");
|
|
20
|
+
const generate_controller_1 = require("./generate-controller");
|
|
21
|
+
const generate_controller_spec_1 = require("./generate-controller-spec");
|
|
22
|
+
const generate_types_dto_1 = require("./generate-types-dto");
|
|
23
|
+
const generate_form_validator_class_1 = require("./generate-form-validator-class");
|
|
24
|
+
const annotations_1 = require("./annotations");
|
|
25
|
+
const field_classifiers_1 = require("./field-classifiers");
|
|
26
|
+
const helpers_1 = require("./helpers");
|
|
27
|
+
const run = ({ output, dmmf, ...options }) => {
|
|
28
|
+
const { exportRelationModifierClasses, outputToNestJsResourceStructure, fileNamingStyle = 'camel', ...preAndSuffixes } = options;
|
|
29
|
+
const transformers = {
|
|
30
|
+
camel: case_1.camel,
|
|
31
|
+
kebab: case_1.kebab,
|
|
32
|
+
pascal: case_1.pascal,
|
|
33
|
+
snake: case_1.snake,
|
|
34
|
+
};
|
|
35
|
+
const transformFileNameCase = transformers[fileNamingStyle];
|
|
36
|
+
const templateHelpers = (0, template_helpers_1.makeHelpers)({
|
|
37
|
+
transformFileNameCase,
|
|
38
|
+
transformClassNameCase: case_1.pascal,
|
|
39
|
+
...preAndSuffixes,
|
|
40
|
+
});
|
|
41
|
+
const allModels = dmmf.datamodel.models;
|
|
42
|
+
const filteredModels = allModels
|
|
43
|
+
.filter((model) => !(0, field_classifiers_1.isAnnotatedWith)(model, annotations_1.DTO_IGNORE_NEST_CODE))
|
|
44
|
+
.map((model) => ({
|
|
45
|
+
...model,
|
|
46
|
+
output: {
|
|
47
|
+
dto: outputToNestJsResourceStructure
|
|
48
|
+
? node_path_1.default.join(output, transformFileNameCase(model.name), 'dto')
|
|
49
|
+
: output,
|
|
50
|
+
entity: outputToNestJsResourceStructure
|
|
51
|
+
? node_path_1.default.join(output, transformFileNameCase(model.name), 'entities')
|
|
52
|
+
: output,
|
|
53
|
+
},
|
|
54
|
+
}));
|
|
55
|
+
const moduleIndexFile = {
|
|
56
|
+
fileName: node_path_1.default.join(output, 'modules.index.ts'),
|
|
57
|
+
content: (0, generate_modules_index_1.generateModulesIndex)({
|
|
58
|
+
allModels: filteredModels,
|
|
59
|
+
templateHelpers,
|
|
60
|
+
}),
|
|
61
|
+
};
|
|
62
|
+
const modelFiles = filteredModels.map((model) => {
|
|
63
|
+
sdk_1.logger.info(`Processing Model ${model.name}`);
|
|
64
|
+
const modelParams = (0, compute_model_params_1.computeModelParams)({
|
|
65
|
+
model,
|
|
66
|
+
allModels: filteredModels,
|
|
67
|
+
templateHelpers,
|
|
68
|
+
});
|
|
69
|
+
const connectDto = {
|
|
70
|
+
fileName: node_path_1.default.join(model.output.dto, templateHelpers.connectDtoFilename(model.name, true)),
|
|
71
|
+
content: (0, generate_connect_dto_1.generateConnectDto)({
|
|
72
|
+
...modelParams.connect,
|
|
73
|
+
templateHelpers,
|
|
74
|
+
}),
|
|
75
|
+
};
|
|
76
|
+
const createDto = {
|
|
77
|
+
fileName: node_path_1.default.join(model.output.dto, templateHelpers.createDtoFilename(model.name, true)),
|
|
78
|
+
content: (0, generate_create_dto_1.generateCreateDto)({
|
|
79
|
+
...modelParams.create,
|
|
80
|
+
exportRelationModifierClasses,
|
|
81
|
+
templateHelpers,
|
|
82
|
+
}),
|
|
83
|
+
};
|
|
84
|
+
const formValidatorClass = {
|
|
85
|
+
fileName: node_path_1.default.join(model.output.dto, `${transformFileNameCase(model.name)}.form.validator.ts`),
|
|
86
|
+
content: (0, generate_form_validator_class_1.generateFormValidatorClass)({
|
|
87
|
+
...modelParams.create,
|
|
88
|
+
exportRelationModifierClasses,
|
|
89
|
+
templateHelpers,
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
92
|
+
modelParams.update.imports.push({
|
|
93
|
+
from: '@nestjs/swagger',
|
|
94
|
+
destruct: ['PartialType'],
|
|
95
|
+
});
|
|
96
|
+
modelParams.update.imports.push({
|
|
97
|
+
from: `./create-${transformFileNameCase(model.name)}.dto`,
|
|
98
|
+
destruct: [templateHelpers.createDtoName(model.name)],
|
|
99
|
+
});
|
|
100
|
+
modelParams.update.imports = (0, helpers_1.zipImportStatementParams)(modelParams.update.imports);
|
|
101
|
+
const updateDto = {
|
|
102
|
+
fileName: node_path_1.default.join(model.output.dto, templateHelpers.updateDtoFilename(model.name, true)),
|
|
103
|
+
content: (0, generate_update_dto_1.generateUpdateDto)({
|
|
104
|
+
...modelParams.update,
|
|
105
|
+
exportRelationModifierClasses,
|
|
106
|
+
templateHelpers,
|
|
107
|
+
}),
|
|
108
|
+
};
|
|
109
|
+
modelParams.entity.imports.push({
|
|
110
|
+
from: '@nestjs/swagger',
|
|
111
|
+
destruct: ['ApiProperty'],
|
|
112
|
+
});
|
|
113
|
+
modelParams.entity.imports.push({
|
|
114
|
+
from: 'class-transformer',
|
|
115
|
+
destruct: ['Transform'],
|
|
116
|
+
});
|
|
117
|
+
modelParams.entity.imports.push({
|
|
118
|
+
from: '@prisma/client',
|
|
119
|
+
destruct: [model.name, 'Prisma'],
|
|
120
|
+
});
|
|
121
|
+
modelParams.entity.imports = (0, helpers_1.zipImportStatementParams)(modelParams.entity.imports);
|
|
122
|
+
const entity = {
|
|
123
|
+
fileName: node_path_1.default.join(model.output.entity, templateHelpers.entityFilename(model.name, true)),
|
|
124
|
+
content: (0, generate_entity_1.generateEntity)({
|
|
125
|
+
...modelParams.entity,
|
|
126
|
+
templateHelpers,
|
|
127
|
+
}),
|
|
128
|
+
};
|
|
129
|
+
const modelTypes = {
|
|
130
|
+
fileName: node_path_1.default.join(model.output.dto, `${transformFileNameCase(model.name)}-types.dto.ts`),
|
|
131
|
+
content: (0, generate_types_dto_1.generateTypesDto)({
|
|
132
|
+
...modelParams.entity,
|
|
133
|
+
templateHelpers,
|
|
134
|
+
}),
|
|
135
|
+
};
|
|
136
|
+
const module = {
|
|
137
|
+
fileName: node_path_1.default.join(model.output.entity, '..', `${transformFileNameCase(model.name)}.module.ts`),
|
|
138
|
+
content: (0, generate_module_1.generateModule)({
|
|
139
|
+
model,
|
|
140
|
+
templateHelpers,
|
|
141
|
+
}),
|
|
142
|
+
};
|
|
143
|
+
const service = {
|
|
144
|
+
fileName: node_path_1.default.join(model.output.entity, '..', `${transformFileNameCase(model.name)}.service.ts`),
|
|
145
|
+
content: (0, generate_service_1.generateService)({
|
|
146
|
+
model,
|
|
147
|
+
templateHelpers,
|
|
148
|
+
}),
|
|
149
|
+
};
|
|
150
|
+
const serviceSpec = {
|
|
151
|
+
fileName: node_path_1.default.join(model.output.entity, '..', `${transformFileNameCase(model.name)}.service.spec.ts`),
|
|
152
|
+
content: (0, generate_service_spec_1.generateServiceSpec)({
|
|
153
|
+
model,
|
|
154
|
+
templateHelpers,
|
|
155
|
+
}),
|
|
156
|
+
};
|
|
157
|
+
const controller = {
|
|
158
|
+
fileName: node_path_1.default.join(model.output.entity, '..', `${transformFileNameCase(model.name)}.controller.ts`),
|
|
159
|
+
content: (0, generate_controller_1.generateController)({
|
|
160
|
+
model,
|
|
161
|
+
templateHelpers,
|
|
162
|
+
}),
|
|
163
|
+
};
|
|
164
|
+
const controllerSpec = {
|
|
165
|
+
fileName: node_path_1.default.join(model.output.entity, '..', `${transformFileNameCase(model.name)}.controller.spec.ts`),
|
|
166
|
+
content: (0, generate_controller_spec_1.generateControllerSpec)({
|
|
167
|
+
model,
|
|
168
|
+
templateHelpers,
|
|
169
|
+
}),
|
|
170
|
+
};
|
|
171
|
+
return [
|
|
172
|
+
connectDto,
|
|
173
|
+
createDto,
|
|
174
|
+
updateDto,
|
|
175
|
+
entity,
|
|
176
|
+
modelTypes,
|
|
177
|
+
module,
|
|
178
|
+
service,
|
|
179
|
+
serviceSpec,
|
|
180
|
+
controller,
|
|
181
|
+
controllerSpec,
|
|
182
|
+
formValidatorClass,
|
|
183
|
+
];
|
|
184
|
+
});
|
|
185
|
+
return [...modelFiles, [moduleIndexFile]].flat();
|
|
186
|
+
};
|
|
187
|
+
exports.run = run;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ImportStatementParams, ParsedField } from './types';
|
|
2
|
+
export declare const scalarToTS: (scalar: string, useInputTypes?: boolean) => string;
|
|
3
|
+
export declare const echo: (input: string) => string;
|
|
4
|
+
export declare const when: (condition: any, thenTemplate: string, elseTemplate?: string) => string;
|
|
5
|
+
export declare const unless: (condition: any, thenTemplate: string, elseTemplate?: string) => string;
|
|
6
|
+
export declare const each: <T = any>(arr: T[], fn: (item: T) => string, joinWith?: string) => string;
|
|
7
|
+
export declare const importStatement: (input: ImportStatementParams) => string;
|
|
8
|
+
export declare const importStatements: (items: ImportStatementParams[]) => string;
|
|
9
|
+
interface MakeHelpersParam {
|
|
10
|
+
connectDtoPrefix: string;
|
|
11
|
+
createDtoPrefix: string;
|
|
12
|
+
updateDtoPrefix: string;
|
|
13
|
+
dtoSuffix: string;
|
|
14
|
+
entityPrefix: string;
|
|
15
|
+
entitySuffix: string;
|
|
16
|
+
transformClassNameCase?: (item: string) => string;
|
|
17
|
+
transformFileNameCase?: (item: string) => string;
|
|
18
|
+
}
|
|
19
|
+
export declare const makeHelpers: ({ connectDtoPrefix, createDtoPrefix, updateDtoPrefix, dtoSuffix, entityPrefix, entitySuffix, transformClassNameCase, transformFileNameCase, }: MakeHelpersParam) => {
|
|
20
|
+
config: {
|
|
21
|
+
connectDtoPrefix: string;
|
|
22
|
+
createDtoPrefix: string;
|
|
23
|
+
updateDtoPrefix: string;
|
|
24
|
+
dtoSuffix: string;
|
|
25
|
+
entityPrefix: string;
|
|
26
|
+
entitySuffix: string;
|
|
27
|
+
};
|
|
28
|
+
apiExtraModels: (names: string[]) => string;
|
|
29
|
+
entityName: (name: string) => string;
|
|
30
|
+
connectDtoName: (name: string) => string;
|
|
31
|
+
createDtoName: (name: string) => string;
|
|
32
|
+
updateDtoName: (name: string) => string;
|
|
33
|
+
connectDtoFilename: (name: string, withExtension?: boolean) => string;
|
|
34
|
+
createDtoFilename: (name: string, withExtension?: boolean) => string;
|
|
35
|
+
updateDtoFilename: (name: string, withExtension?: boolean) => string;
|
|
36
|
+
entityFilename: (name: string, withExtension?: boolean) => string;
|
|
37
|
+
each: <T = any>(arr: T[], fn: (item: T) => string, joinWith?: string) => string;
|
|
38
|
+
echo: (input: string) => string;
|
|
39
|
+
fieldsToDtoProps: (fields: ParsedField[], useInputTypes?: boolean, forceOptional?: boolean) => string;
|
|
40
|
+
fieldToDtoProp: (field: ParsedField, useInputTypes?: boolean, forceOptional?: boolean) => string;
|
|
41
|
+
fieldToEntityProp: (field: ParsedField) => string;
|
|
42
|
+
fieldsToEntityProps: (fields: ParsedField[]) => string;
|
|
43
|
+
fieldToTypesProp: (field: ParsedField) => string;
|
|
44
|
+
fieldsToTypesProps: (fields: ParsedField[]) => string;
|
|
45
|
+
fieldType: (field: ParsedField, toInputType?: boolean, forEntity?: boolean) => string;
|
|
46
|
+
for: <T = any>(arr: T[], fn: (item: T) => string, joinWith?: string) => string;
|
|
47
|
+
if: (condition: any, thenTemplate: string, elseTemplate?: string) => string;
|
|
48
|
+
importStatement: (input: ImportStatementParams) => string;
|
|
49
|
+
importStatements: (items: ImportStatementParams[]) => string;
|
|
50
|
+
transformClassNameCase: (item: string) => string;
|
|
51
|
+
transformFileNameCase: (item: string) => string;
|
|
52
|
+
unless: (condition: any, thenTemplate: string, elseTemplate?: string) => string;
|
|
53
|
+
when: (condition: any, thenTemplate: string, elseTemplate?: string) => string;
|
|
54
|
+
};
|
|
55
|
+
export declare type TemplateHelpers = ReturnType<typeof makeHelpers>;
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeHelpers = exports.importStatements = exports.importStatement = exports.each = exports.unless = exports.when = exports.echo = exports.scalarToTS = void 0;
|
|
4
|
+
const PrismaScalarToTypeScript = {
|
|
5
|
+
String: 'string',
|
|
6
|
+
Boolean: 'boolean',
|
|
7
|
+
Int: 'number',
|
|
8
|
+
BigInt: 'bigint',
|
|
9
|
+
Float: 'number',
|
|
10
|
+
Decimal: 'number',
|
|
11
|
+
DateTime: 'Date',
|
|
12
|
+
Json: 'Prisma.JsonValue',
|
|
13
|
+
Bytes: 'Buffer',
|
|
14
|
+
};
|
|
15
|
+
const TSScalarToValidator = {
|
|
16
|
+
String: '@IsString()',
|
|
17
|
+
Boolean: '@IsBoolean()',
|
|
18
|
+
Int: '@IsNumber()',
|
|
19
|
+
BigInt: '@IsNumber()',
|
|
20
|
+
Float: '@IsNumber()',
|
|
21
|
+
Decimal: '@IsNumber()',
|
|
22
|
+
DateTime: '@IsDate()',
|
|
23
|
+
Json: '@IsJSON()',
|
|
24
|
+
Bytes: '',
|
|
25
|
+
};
|
|
26
|
+
const knownPrismaScalarTypes = Object.keys(PrismaScalarToTypeScript);
|
|
27
|
+
const scalarToTS = (scalar, useInputTypes = false) => {
|
|
28
|
+
if (!knownPrismaScalarTypes.includes(scalar)) {
|
|
29
|
+
throw new Error(`Unrecognized scalar type: ${scalar}`);
|
|
30
|
+
}
|
|
31
|
+
if (useInputTypes && scalar === 'Json') {
|
|
32
|
+
return 'Prisma.InputJsonValue';
|
|
33
|
+
}
|
|
34
|
+
return PrismaScalarToTypeScript[scalar];
|
|
35
|
+
};
|
|
36
|
+
exports.scalarToTS = scalarToTS;
|
|
37
|
+
const echo = (input) => input;
|
|
38
|
+
exports.echo = echo;
|
|
39
|
+
const when = (condition, thenTemplate, elseTemplate = '') => condition ? thenTemplate : elseTemplate;
|
|
40
|
+
exports.when = when;
|
|
41
|
+
const unless = (condition, thenTemplate, elseTemplate = '') => (!condition ? thenTemplate : elseTemplate);
|
|
42
|
+
exports.unless = unless;
|
|
43
|
+
const each = (arr, fn, joinWith = '') => arr.map(fn).join(joinWith);
|
|
44
|
+
exports.each = each;
|
|
45
|
+
const importStatement = (input) => {
|
|
46
|
+
const { from, destruct = [], default: defaultExport } = input;
|
|
47
|
+
const fragments = ['import'];
|
|
48
|
+
if (defaultExport) {
|
|
49
|
+
if (typeof defaultExport === 'string') {
|
|
50
|
+
fragments.push(defaultExport);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
fragments.push(`* as ${defaultExport['*']}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (destruct.length) {
|
|
57
|
+
if (defaultExport) {
|
|
58
|
+
fragments.push(',');
|
|
59
|
+
}
|
|
60
|
+
fragments.push(`{${destruct.flatMap((item) => {
|
|
61
|
+
if (typeof item === 'string')
|
|
62
|
+
return item;
|
|
63
|
+
return Object.entries(item).map(([key, value]) => `${key} as ${value}`);
|
|
64
|
+
})}}`);
|
|
65
|
+
}
|
|
66
|
+
fragments.push(`from '${from}'`);
|
|
67
|
+
return fragments.join(' ');
|
|
68
|
+
};
|
|
69
|
+
exports.importStatement = importStatement;
|
|
70
|
+
const importStatements = (items) => `${(0, exports.each)(items, exports.importStatement, '\n')}`;
|
|
71
|
+
exports.importStatements = importStatements;
|
|
72
|
+
const VALIDATOR_REGEX = /^@Dto\S+\n?/gm;
|
|
73
|
+
const makeHelpers = ({ connectDtoPrefix, createDtoPrefix, updateDtoPrefix, dtoSuffix, entityPrefix, entitySuffix, transformClassNameCase = exports.echo, transformFileNameCase = exports.echo, }) => {
|
|
74
|
+
const className = (name, prefix = '', suffix = '') => `${prefix}${transformClassNameCase(name)}${suffix}`;
|
|
75
|
+
const fileName = (name, prefix = '', suffix = '', withExtension = false) => `${prefix}${transformFileNameCase(name)}${suffix}${(0, exports.when)(withExtension, '.ts')}`;
|
|
76
|
+
const entityName = (name) => className(name, entityPrefix, entitySuffix);
|
|
77
|
+
const connectDtoName = (name) => className(name, connectDtoPrefix, dtoSuffix);
|
|
78
|
+
const createDtoName = (name) => className(name, createDtoPrefix, dtoSuffix);
|
|
79
|
+
const updateDtoName = (name) => className(name, updateDtoPrefix, dtoSuffix);
|
|
80
|
+
const connectDtoFilename = (name, withExtension = false) => fileName(name, 'connect-', '.dto', withExtension);
|
|
81
|
+
const createDtoFilename = (name, withExtension = false) => fileName(name, 'create-', '.dto', withExtension);
|
|
82
|
+
const updateDtoFilename = (name, withExtension = false) => fileName(name, 'update-', '.dto', withExtension);
|
|
83
|
+
const entityFilename = (name, withExtension = false) => fileName(name, undefined, '.entity', withExtension);
|
|
84
|
+
const fieldType = (field, toInputType = false, forEntity = false) => `${field.kind === 'scalar'
|
|
85
|
+
? (0, exports.scalarToTS)(field.type, toInputType)
|
|
86
|
+
: field.kind === 'enum' || field.kind === 'relation-input'
|
|
87
|
+
? field.type
|
|
88
|
+
: forEntity
|
|
89
|
+
? entityName(field.type)
|
|
90
|
+
: field.type}${(0, exports.when)(field.isList, '[]')}`;
|
|
91
|
+
const fieldToDtoProp = (field, useInputTypes = false, forceOptional = false) => {
|
|
92
|
+
var _a, _b;
|
|
93
|
+
return `${(0, exports.when)(field.kind === 'enum', `@ApiProperty({ enum: ${fieldType(field, useInputTypes)}})\n`)}${((_a = field.documentation) === null || _a === void 0 ? void 0 : _a.replace(VALIDATOR_REGEX, '').replace(/^@FormItem[\S ]+\n?/gm, '')) || ''}${(0, exports.when)(!field.isRequired || forceOptional || field.hasDefaultValue, '@IsOptional()\n')}${(0, exports.when)((_b = field.documentation) === null || _b === void 0 ? void 0 : _b.replace(VALIDATOR_REGEX, '').match(/^@FormItem[\S ]*\(JSON/gm), '@IsJSON()\n')}${(0, exports.when)(field.kind === 'scalar', `${TSScalarToValidator[field.type]}\n`)}${(0, exports.when)(field.isList, '@ValidateNested()\n')}${field.name}${(0, exports.when)(!field.isRequired || forceOptional || field.hasDefaultValue, '?')}: ${fieldType(field, useInputTypes)};`;
|
|
94
|
+
};
|
|
95
|
+
const fieldsToDtoProps = (fields, useInputTypes = false, forceOptional = false) => `${(0, exports.each)(fields, (field) => fieldToDtoProp(field, useInputTypes, forceOptional), '\n')}`;
|
|
96
|
+
const fieldToEntityProp = (field) => `${field.name}${(0, exports.unless)(field.isRequired, '?')}: ${fieldType(field, false, true)} ${(0, exports.when)(field.isNullable, ' | null')};`;
|
|
97
|
+
const fieldsToEntityProps = (fields) => `${(0, exports.each)(fields, (field) => fieldToEntityProp(field), '\n')}`;
|
|
98
|
+
const fieldToTypesProp = (field) => `@IsOptional()\n${field.name}?: object;`;
|
|
99
|
+
const fieldsToTypesProps = (fields) => `${(0, exports.each)(fields, (field) => fieldToTypesProp(field), '\n\n')}`;
|
|
100
|
+
const apiExtraModels = (names) => `@ApiExtraModels(${names})`;
|
|
101
|
+
return {
|
|
102
|
+
config: {
|
|
103
|
+
connectDtoPrefix,
|
|
104
|
+
createDtoPrefix,
|
|
105
|
+
updateDtoPrefix,
|
|
106
|
+
dtoSuffix,
|
|
107
|
+
entityPrefix,
|
|
108
|
+
entitySuffix,
|
|
109
|
+
},
|
|
110
|
+
apiExtraModels,
|
|
111
|
+
entityName,
|
|
112
|
+
connectDtoName,
|
|
113
|
+
createDtoName,
|
|
114
|
+
updateDtoName,
|
|
115
|
+
connectDtoFilename,
|
|
116
|
+
createDtoFilename,
|
|
117
|
+
updateDtoFilename,
|
|
118
|
+
entityFilename,
|
|
119
|
+
each: exports.each,
|
|
120
|
+
echo: exports.echo,
|
|
121
|
+
fieldsToDtoProps,
|
|
122
|
+
fieldToDtoProp,
|
|
123
|
+
fieldToEntityProp,
|
|
124
|
+
fieldsToEntityProps,
|
|
125
|
+
fieldToTypesProp,
|
|
126
|
+
fieldsToTypesProps,
|
|
127
|
+
fieldType,
|
|
128
|
+
for: exports.each,
|
|
129
|
+
if: exports.when,
|
|
130
|
+
importStatement: exports.importStatement,
|
|
131
|
+
importStatements: exports.importStatements,
|
|
132
|
+
transformClassNameCase,
|
|
133
|
+
transformFileNameCase,
|
|
134
|
+
unless: exports.unless,
|
|
135
|
+
when: exports.when,
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
exports.makeHelpers = makeHelpers;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { DMMF } from '@prisma/generator-helper';
|
|
2
|
+
export interface Model extends DMMF.Model {
|
|
3
|
+
output: {
|
|
4
|
+
dto: string;
|
|
5
|
+
entity: string;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export interface ParsedField {
|
|
9
|
+
kind: DMMF.FieldKind | 'relation-input';
|
|
10
|
+
name: string;
|
|
11
|
+
type: string;
|
|
12
|
+
documentation?: string;
|
|
13
|
+
isRequired: boolean;
|
|
14
|
+
isList: boolean;
|
|
15
|
+
isNullable?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface ExtraModel {
|
|
18
|
+
originalName: string;
|
|
19
|
+
preAndPostfixedName: string;
|
|
20
|
+
isLocal?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface ImportStatementParams {
|
|
23
|
+
from: string;
|
|
24
|
+
default?: string | {
|
|
25
|
+
'*': string;
|
|
26
|
+
};
|
|
27
|
+
destruct?: (string | Record<string, string>)[];
|
|
28
|
+
}
|
|
29
|
+
export interface DtoParams {
|
|
30
|
+
model: DMMF.Model;
|
|
31
|
+
fields: ParsedField[];
|
|
32
|
+
imports: ImportStatementParams[];
|
|
33
|
+
}
|
|
34
|
+
export declare type ConnectDtoParams = Omit<DtoParams, 'imports'>;
|
|
35
|
+
export interface CreateDtoParams extends DtoParams {
|
|
36
|
+
extraClasses: string[];
|
|
37
|
+
apiExtraModels: string[];
|
|
38
|
+
}
|
|
39
|
+
export interface UpdateDtoParams extends DtoParams {
|
|
40
|
+
extraClasses: string[];
|
|
41
|
+
apiExtraModels: string[];
|
|
42
|
+
}
|
|
43
|
+
export interface EntityParams extends DtoParams {
|
|
44
|
+
apiExtraModels: string[];
|
|
45
|
+
}
|
|
46
|
+
export interface ModelParams {
|
|
47
|
+
connect: ConnectDtoParams;
|
|
48
|
+
create: CreateDtoParams;
|
|
49
|
+
update: UpdateDtoParams;
|
|
50
|
+
entity: EntityParams;
|
|
51
|
+
}
|
|
52
|
+
export declare type WriteableFileSpecs = {
|
|
53
|
+
fileName: string;
|
|
54
|
+
content: string;
|
|
55
|
+
};
|
|
56
|
+
export declare type NamingStyle = 'snake' | 'camel' | 'pascal' | 'kebab';
|
package/dist/index.d.ts
ADDED