@comet/api-generator 9.0.0-beta.2 → 9.0.0-beta.3
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/lib/commands/generate/generate-command.js +4 -13
- package/lib/commands/generate/generateCrud/build-options.d.ts +1 -1
- package/lib/commands/generate/generateCrud/build-options.js +3 -3
- package/lib/commands/generate/generateCrud/generate-crud.d.ts +1 -1
- package/lib/commands/generate/generateCrud/generate-crud.js +109 -104
- package/lib/commands/generate/generateCrud/generate-enum-filter-dto.d.ts +1 -1
- package/lib/commands/generate/generateCrud/generate-payload-object-types.d.ts +2 -2
- package/lib/commands/generate/generateCrud/generate-payload-object-types.js +2 -3
- package/lib/commands/generate/generateCrud/generate-service-hook-call.d.ts +2 -2
- package/lib/commands/generate/generateCrud/generate-service-hook-call.js +8 -7
- package/lib/commands/generate/generateCrudInput/generate-crud-input.d.ts +2 -2
- package/lib/commands/generate/generateCrudInput/generate-crud-input.js +381 -388
- package/lib/commands/generate/generateCrudSingle/generate-crud-single.d.ts +2 -2
- package/lib/commands/generate/generateCrudSingle/generate-crud-single.js +29 -41
- package/lib/commands/generate/generateFiles.js +17 -26
- package/lib/commands/generate/utils/build-name-variants.d.ts +1 -1
- package/lib/commands/generate/utils/find-hooks-service.d.ts +3 -3
- package/lib/commands/generate/utils/find-hooks-service.js +3 -6
- package/lib/commands/generate/utils/ts-morph-helper.d.ts +1 -1
- package/lib/commands/generate/utils/ts-morph-helper.js +23 -19
- package/lib/commands/generate/utils/write-generated-file.js +12 -23
- package/lib/commands/generate/utils/write-generated-files.js +4 -16
- package/lib/commands/generate/watchMode/handleChildProcess.d.ts +1 -1
- package/lib/commands/generate/watchMode/watchMode.js +6 -15
- package/package.json +8 -8
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.generateCrudInput = generateCrudInput;
|
|
13
4
|
const cms_api_1 = require("@comet/cms-api");
|
|
@@ -20,14 +11,16 @@ const generate_imports_code_1 = require("../utils/generate-imports-code");
|
|
|
20
11
|
const ts_morph_helper_1 = require("../utils/ts-morph-helper");
|
|
21
12
|
function tsCodeRecordToString(object) {
|
|
22
13
|
const filteredEntries = Object.entries(object).filter(([key, value]) => value !== undefined);
|
|
23
|
-
if (filteredEntries.length == 0)
|
|
14
|
+
if (filteredEntries.length == 0) {
|
|
24
15
|
return "";
|
|
16
|
+
}
|
|
25
17
|
return `{${filteredEntries.map(([key, value]) => `${key}: ${value},`).join("\n")}}`;
|
|
26
18
|
}
|
|
27
19
|
function findReferenceTargetType(targetMeta, referencedColumnName) {
|
|
28
|
-
const referencedColumnProp = targetMeta
|
|
29
|
-
if (!referencedColumnProp)
|
|
20
|
+
const referencedColumnProp = targetMeta?.props.find((p) => p.name == referencedColumnName);
|
|
21
|
+
if (!referencedColumnProp) {
|
|
30
22
|
throw new Error("referencedColumnProp not found");
|
|
23
|
+
}
|
|
31
24
|
if (referencedColumnProp.type == "uuid") {
|
|
32
25
|
return "uuid";
|
|
33
26
|
}
|
|
@@ -44,258 +37,230 @@ function findReferenceTargetType(targetMeta, referencedColumnName) {
|
|
|
44
37
|
return null;
|
|
45
38
|
}
|
|
46
39
|
}
|
|
47
|
-
function generateCrudInput(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
40
|
+
async function generateCrudInput(generatorOptions,
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
metadata, options = {
|
|
43
|
+
nested: false,
|
|
44
|
+
excludeFields: [],
|
|
45
|
+
generateUpdateInput: true,
|
|
46
|
+
}) {
|
|
47
|
+
const generatedFiles = [];
|
|
48
|
+
const { dedicatedResolverArgProps, targetDirectory } = (0, build_options_1.buildOptions)(metadata, generatorOptions);
|
|
49
|
+
const props = metadata.props
|
|
50
|
+
.filter((prop) => {
|
|
51
|
+
return !prop.embedded;
|
|
52
|
+
})
|
|
53
|
+
.filter((prop) => {
|
|
54
|
+
return (0, cms_api_1.hasCrudFieldFeature)(metadata.class, prop.name, "input");
|
|
55
|
+
})
|
|
56
|
+
.filter((prop) => {
|
|
57
|
+
//filter out props that are dedicatedResolverArgProps
|
|
58
|
+
return !dedicatedResolverArgProps.some((dedicatedResolverArgProp) => dedicatedResolverArgProp.name === prop.name);
|
|
59
|
+
})
|
|
60
|
+
.filter((prop) => !options.excludeFields.includes(prop.name));
|
|
61
|
+
let fieldsOut = "";
|
|
62
|
+
const imports = [
|
|
63
|
+
{ name: "IsSlug", importPath: "@comet/cms-api" },
|
|
64
|
+
{ name: "RootBlockInputScalar", importPath: "@comet/cms-api" },
|
|
65
|
+
{ name: "IsNullable", importPath: "@comet/cms-api" },
|
|
66
|
+
{ name: "PartialType", importPath: "@comet/cms-api" },
|
|
67
|
+
{ name: "BlockInputInterface", importPath: "@comet/cms-api" },
|
|
68
|
+
{ name: "isBlockInputInterface", importPath: "@comet/cms-api" },
|
|
69
|
+
{ name: "IsString", importPath: "class-validator" },
|
|
70
|
+
{ name: "IsNotEmpty", importPath: "class-validator" },
|
|
71
|
+
{ name: "ValidateNested", importPath: "class-validator" },
|
|
72
|
+
{ name: "IsNumber", importPath: "class-validator" },
|
|
73
|
+
{ name: "IsBoolean", importPath: "class-validator" },
|
|
74
|
+
{ name: "IsDate", importPath: "class-validator" },
|
|
75
|
+
{ name: "IsDateString", importPath: "class-validator" },
|
|
76
|
+
{ name: "IsOptional", importPath: "class-validator" },
|
|
77
|
+
{ name: "IsEnum", importPath: "class-validator" },
|
|
78
|
+
{ name: "IsUUID", importPath: "class-validator" },
|
|
79
|
+
{ name: "IsArray", importPath: "class-validator" },
|
|
80
|
+
{ name: "IsInt", importPath: "class-validator" },
|
|
81
|
+
];
|
|
82
|
+
for (const prop of props) {
|
|
83
|
+
let type = prop.type;
|
|
84
|
+
const fieldName = prop.name;
|
|
85
|
+
const definedDecorators = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getDecorators();
|
|
86
|
+
const decorators = [];
|
|
87
|
+
let isOptional = prop.nullable;
|
|
88
|
+
if (prop.name != "position") {
|
|
89
|
+
if (!prop.nullable) {
|
|
90
|
+
decorators.push("@IsNotEmpty()");
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
decorators.push("@IsNullable()");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (["id", "createdAt", "updatedAt", "scope"].includes(prop.name)) {
|
|
97
|
+
//skip those (TODO find a non-magic solution?)
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
else if (prop.name == "position") {
|
|
101
|
+
const initializer = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()?.getText();
|
|
102
|
+
const defaultValue = initializer == "undefined" || initializer == "null" ? "null" : initializer;
|
|
103
|
+
const fieldOptions = tsCodeRecordToString({ nullable: "true", defaultValue });
|
|
104
|
+
isOptional = true;
|
|
105
|
+
decorators.push(`@IsOptional()`);
|
|
106
|
+
imports.push({ name: "Min", importPath: "class-validator" });
|
|
107
|
+
decorators.push(`@Min(1)`);
|
|
108
|
+
decorators.push("@IsInt()");
|
|
109
|
+
decorators.push(`@Field(() => Int, ${fieldOptions})`);
|
|
110
|
+
type = "number";
|
|
111
|
+
}
|
|
112
|
+
else if (prop.enum) {
|
|
113
|
+
const initializer = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()?.getText();
|
|
114
|
+
const defaultValue = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined) ? "null" : initializer;
|
|
115
|
+
const fieldOptions = tsCodeRecordToString({ nullable: prop.nullable ? "true" : undefined, defaultValue });
|
|
116
|
+
const enumName = (0, ts_morph_helper_1.findEnumName)(prop.name, metadata);
|
|
117
|
+
const importPath = (0, ts_morph_helper_1.findEnumImportPath)(enumName, `${targetDirectory}/dto`, metadata);
|
|
118
|
+
imports.push({ name: enumName, importPath });
|
|
119
|
+
decorators.push(`@IsEnum(${enumName})`);
|
|
120
|
+
decorators.push(`@Field(() => ${enumName}, ${fieldOptions})`);
|
|
121
|
+
type = enumName;
|
|
122
|
+
}
|
|
123
|
+
else if (prop.type === "EnumArrayType") {
|
|
124
|
+
if (prop.nullable) {
|
|
125
|
+
console.warn(`${prop.name}: Nullable enum arrays are not supported`);
|
|
104
126
|
}
|
|
105
|
-
|
|
106
|
-
|
|
127
|
+
decorators.length = 0; //remove @IsNotEmpty
|
|
128
|
+
const initializer = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()?.getText();
|
|
129
|
+
const fieldOptions = tsCodeRecordToString({ defaultValue: initializer });
|
|
130
|
+
const enumName = (0, ts_morph_helper_1.findEnumName)(prop.name, metadata);
|
|
131
|
+
const importPath = (0, ts_morph_helper_1.findEnumImportPath)(enumName, `${targetDirectory}/dto`, metadata);
|
|
132
|
+
imports.push({ name: enumName, importPath });
|
|
133
|
+
decorators.push(`@IsEnum(${enumName}, { each: true })`);
|
|
134
|
+
decorators.push(`@Field(() => [${enumName}], ${fieldOptions})`);
|
|
135
|
+
type = `${enumName}[]`;
|
|
136
|
+
}
|
|
137
|
+
else if (prop.type === "string" || prop.type === "text") {
|
|
138
|
+
const initializer = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()?.getText();
|
|
139
|
+
const defaultValue = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined) ? "null" : initializer;
|
|
140
|
+
const fieldOptions = tsCodeRecordToString({ nullable: prop.nullable ? "true" : undefined, defaultValue });
|
|
141
|
+
decorators.push("@IsString()");
|
|
142
|
+
if (prop.name.startsWith("scope_")) {
|
|
107
143
|
continue;
|
|
108
144
|
}
|
|
109
|
-
else if (prop.name
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
145
|
+
else if (prop.name === "slug") {
|
|
146
|
+
//TODO find a non-magic solution
|
|
147
|
+
decorators.push("@IsSlug()");
|
|
148
|
+
}
|
|
149
|
+
decorators.push(`@Field(${fieldOptions})`);
|
|
150
|
+
type = "string";
|
|
151
|
+
}
|
|
152
|
+
else if (constants_1.numberTypes.includes(prop.type)) {
|
|
153
|
+
const initializer = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()?.getText();
|
|
154
|
+
const defaultValue = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined) ? "null" : initializer;
|
|
155
|
+
const fieldOptions = tsCodeRecordToString({ nullable: prop.nullable ? "true" : undefined, defaultValue });
|
|
156
|
+
if (constants_1.integerTypes.includes(prop.columnTypes[0])) {
|
|
117
157
|
decorators.push("@IsInt()");
|
|
118
158
|
decorators.push(`@Field(() => Int, ${fieldOptions})`);
|
|
119
|
-
type = "number";
|
|
120
|
-
}
|
|
121
|
-
else if (prop.enum) {
|
|
122
|
-
const initializer = (_b = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()) === null || _b === void 0 ? void 0 : _b.getText();
|
|
123
|
-
const defaultValue = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined) ? "null" : initializer;
|
|
124
|
-
const fieldOptions = tsCodeRecordToString({ nullable: prop.nullable ? "true" : undefined, defaultValue });
|
|
125
|
-
const enumName = (0, ts_morph_helper_1.findEnumName)(prop.name, metadata);
|
|
126
|
-
const importPath = (0, ts_morph_helper_1.findEnumImportPath)(enumName, `${targetDirectory}/dto`, metadata);
|
|
127
|
-
imports.push({ name: enumName, importPath });
|
|
128
|
-
decorators.push(`@IsEnum(${enumName})`);
|
|
129
|
-
decorators.push(`@Field(() => ${enumName}, ${fieldOptions})`);
|
|
130
|
-
type = enumName;
|
|
131
|
-
}
|
|
132
|
-
else if (prop.type === "EnumArrayType") {
|
|
133
|
-
if (prop.nullable) {
|
|
134
|
-
console.warn(`${prop.name}: Nullable enum arrays are not supported`);
|
|
135
|
-
}
|
|
136
|
-
decorators.length = 0; //remove @IsNotEmpty
|
|
137
|
-
const initializer = (_c = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()) === null || _c === void 0 ? void 0 : _c.getText();
|
|
138
|
-
const fieldOptions = tsCodeRecordToString({ defaultValue: initializer });
|
|
139
|
-
const enumName = (0, ts_morph_helper_1.findEnumName)(prop.name, metadata);
|
|
140
|
-
const importPath = (0, ts_morph_helper_1.findEnumImportPath)(enumName, `${targetDirectory}/dto`, metadata);
|
|
141
|
-
imports.push({ name: enumName, importPath });
|
|
142
|
-
decorators.push(`@IsEnum(${enumName}, { each: true })`);
|
|
143
|
-
decorators.push(`@Field(() => [${enumName}], ${fieldOptions})`);
|
|
144
|
-
type = `${enumName}[]`;
|
|
145
159
|
}
|
|
146
|
-
else
|
|
147
|
-
|
|
148
|
-
const defaultValue = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined) ? "null" : initializer;
|
|
149
|
-
const fieldOptions = tsCodeRecordToString({ nullable: prop.nullable ? "true" : undefined, defaultValue });
|
|
150
|
-
decorators.push("@IsString()");
|
|
151
|
-
if (prop.name.startsWith("scope_")) {
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
else if (prop.name === "slug") {
|
|
155
|
-
//TODO find a non-magic solution
|
|
156
|
-
decorators.push("@IsSlug()");
|
|
157
|
-
}
|
|
160
|
+
else {
|
|
161
|
+
decorators.push("@IsNumber()");
|
|
158
162
|
decorators.push(`@Field(${fieldOptions})`);
|
|
159
|
-
type = "string";
|
|
160
163
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
164
|
+
type = "number";
|
|
165
|
+
}
|
|
166
|
+
else if (prop.type === "DateType") {
|
|
167
|
+
// ISO Date without time
|
|
168
|
+
const initializer = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()?.getText();
|
|
169
|
+
const defaultValue = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined) ? "null" : initializer;
|
|
170
|
+
const fieldOptions = tsCodeRecordToString({ nullable: prop.nullable ? "true" : undefined, defaultValue });
|
|
171
|
+
decorators.push("@IsDateString()");
|
|
172
|
+
decorators.push(`@Field(() => GraphQLLocalDate, ${fieldOptions})`);
|
|
173
|
+
type = "string";
|
|
174
|
+
}
|
|
175
|
+
else if (prop.type === "Date") {
|
|
176
|
+
// DateTime
|
|
177
|
+
const initializer = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()?.getText();
|
|
178
|
+
const defaultValue = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined) ? "null" : initializer;
|
|
179
|
+
const fieldOptions = tsCodeRecordToString({ nullable: prop.nullable ? "true" : undefined, defaultValue });
|
|
180
|
+
decorators.push("@IsDate()");
|
|
181
|
+
decorators.push(`@Field(${fieldOptions})`);
|
|
182
|
+
type = "Date";
|
|
183
|
+
}
|
|
184
|
+
else if (prop.type === "BooleanType" || prop.type === "boolean") {
|
|
185
|
+
const initializer = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()?.getText();
|
|
186
|
+
const defaultValue = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined) ? "null" : initializer;
|
|
187
|
+
const fieldOptions = tsCodeRecordToString({ nullable: prop.nullable ? "true" : undefined, defaultValue });
|
|
188
|
+
decorators.push("@IsBoolean()");
|
|
189
|
+
decorators.push(`@Field(${fieldOptions})`);
|
|
190
|
+
type = "boolean";
|
|
191
|
+
}
|
|
192
|
+
else if (prop.type === "RootBlockType") {
|
|
193
|
+
const blockName = (0, ts_morph_helper_1.findBlockName)(prop.name, metadata);
|
|
194
|
+
const importPath = (0, ts_morph_helper_1.findBlockImportPath)(blockName, `${targetDirectory}/dto`, metadata);
|
|
195
|
+
imports.push({ name: blockName, importPath });
|
|
196
|
+
decorators.push(`@Field(() => RootBlockInputScalar(${blockName})${prop.nullable ? ", { nullable: true }" : ""})`);
|
|
197
|
+
decorators.push(`@Transform(({ value }) => (isBlockInputInterface(value) ? value : ${blockName}.blockInputFactory(value)), { toClassOnly: true })`);
|
|
198
|
+
decorators.push("@ValidateNested()");
|
|
199
|
+
type = "BlockInputInterface";
|
|
200
|
+
}
|
|
201
|
+
else if (prop.kind == "m:1") {
|
|
202
|
+
const initializer = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()?.getText();
|
|
203
|
+
const defaultValueNull = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined);
|
|
204
|
+
const fieldOptions = tsCodeRecordToString({
|
|
205
|
+
nullable: prop.nullable ? "true" : undefined,
|
|
206
|
+
defaultValue: defaultValueNull ? "null" : undefined,
|
|
207
|
+
});
|
|
208
|
+
decorators.push(`@Field(() => ID, ${fieldOptions})`);
|
|
209
|
+
if (prop.referencedColumnNames.length > 1) {
|
|
210
|
+
console.warn(`${prop.name}: Composite keys are not supported`);
|
|
211
|
+
continue;
|
|
174
212
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const initializer = (_f = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()) === null || _f === void 0 ? void 0 : _f.getText();
|
|
178
|
-
const defaultValue = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined) ? "null" : initializer;
|
|
179
|
-
const fieldOptions = tsCodeRecordToString({ nullable: prop.nullable ? "true" : undefined, defaultValue });
|
|
180
|
-
decorators.push("@IsDateString()");
|
|
181
|
-
decorators.push(`@Field(() => GraphQLLocalDate, ${fieldOptions})`);
|
|
213
|
+
const refType = findReferenceTargetType(prop.targetMeta, prop.referencedColumnNames[0]);
|
|
214
|
+
if (refType == "uuid") {
|
|
182
215
|
type = "string";
|
|
216
|
+
decorators.push("@IsUUID()");
|
|
183
217
|
}
|
|
184
|
-
else if (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const defaultValue = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined) ? "null" : initializer;
|
|
188
|
-
const fieldOptions = tsCodeRecordToString({ nullable: prop.nullable ? "true" : undefined, defaultValue });
|
|
189
|
-
decorators.push("@IsDate()");
|
|
190
|
-
decorators.push(`@Field(${fieldOptions})`);
|
|
191
|
-
type = "Date";
|
|
192
|
-
}
|
|
193
|
-
else if (prop.type === "BooleanType" || prop.type === "boolean") {
|
|
194
|
-
const initializer = (_h = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()) === null || _h === void 0 ? void 0 : _h.getText();
|
|
195
|
-
const defaultValue = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined) ? "null" : initializer;
|
|
196
|
-
const fieldOptions = tsCodeRecordToString({ nullable: prop.nullable ? "true" : undefined, defaultValue });
|
|
197
|
-
decorators.push("@IsBoolean()");
|
|
198
|
-
decorators.push(`@Field(${fieldOptions})`);
|
|
199
|
-
type = "boolean";
|
|
218
|
+
else if (refType == "string") {
|
|
219
|
+
type = "string";
|
|
220
|
+
decorators.push("@IsString()");
|
|
200
221
|
}
|
|
201
|
-
else if (
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
decorators.push(`@Field(() => RootBlockInputScalar(${blockName})${prop.nullable ? ", { nullable: true }" : ""})`);
|
|
206
|
-
decorators.push(`@Transform(({ value }) => (isBlockInputInterface(value) ? value : ${blockName}.blockInputFactory(value)), { toClassOnly: true })`);
|
|
207
|
-
decorators.push("@ValidateNested()");
|
|
208
|
-
type = "BlockInputInterface";
|
|
222
|
+
else if (refType == "integer") {
|
|
223
|
+
type = "number";
|
|
224
|
+
decorators.push("@Transform(({ value }) => (value ? parseInt(value) : null))");
|
|
225
|
+
decorators.push("@IsInt()");
|
|
209
226
|
}
|
|
210
|
-
else
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const fieldOptions = tsCodeRecordToString({
|
|
214
|
-
nullable: prop.nullable ? "true" : undefined,
|
|
215
|
-
defaultValue: defaultValueNull ? "null" : undefined,
|
|
216
|
-
});
|
|
217
|
-
decorators.push(`@Field(() => ID, ${fieldOptions})`);
|
|
218
|
-
if (prop.referencedColumnNames.length > 1) {
|
|
219
|
-
console.warn(`${prop.name}: Composite keys are not supported`);
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
const refType = findReferenceTargetType(prop.targetMeta, prop.referencedColumnNames[0]);
|
|
223
|
-
if (refType == "uuid") {
|
|
224
|
-
type = "string";
|
|
225
|
-
decorators.push("@IsUUID()");
|
|
226
|
-
}
|
|
227
|
-
else if (refType == "string") {
|
|
228
|
-
type = "string";
|
|
229
|
-
decorators.push("@IsString()");
|
|
230
|
-
}
|
|
231
|
-
else if (refType == "integer") {
|
|
232
|
-
type = "number";
|
|
233
|
-
decorators.push("@Transform(({ value }) => (value ? parseInt(value) : null))");
|
|
234
|
-
decorators.push("@IsInt()");
|
|
235
|
-
}
|
|
236
|
-
else {
|
|
237
|
-
console.warn(`${prop.name}: Unsupported referenced type`);
|
|
238
|
-
continue;
|
|
239
|
-
}
|
|
227
|
+
else {
|
|
228
|
+
console.warn(`${prop.name}: Unsupported referenced type`);
|
|
229
|
+
continue;
|
|
240
230
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
{
|
|
249
|
-
const excludeFields = prop.targetMeta.props.filter((p) => p.kind == "m:1" && p.targetMeta == metadata).map((p) => p.name);
|
|
250
|
-
const { fileNameSingular } = (0, build_name_variants_1.buildNameVariants)(metadata);
|
|
251
|
-
const { fileNameSingular: targetFileNameSingular } = (0, build_name_variants_1.buildNameVariants)(prop.targetMeta);
|
|
252
|
-
const fileName = `dto/${fileNameSingular}-nested-${targetFileNameSingular}.input.ts`;
|
|
253
|
-
const nestedInputFiles = yield generateCrudInput(generatorOptions, prop.targetMeta, {
|
|
254
|
-
nested: true,
|
|
255
|
-
fileName,
|
|
256
|
-
className: inputNameClassName,
|
|
257
|
-
excludeFields,
|
|
258
|
-
});
|
|
259
|
-
generatedFiles.push(...nestedInputFiles);
|
|
260
|
-
imports.push({
|
|
261
|
-
name: inputNameClassName,
|
|
262
|
-
importPath: nestedInputFiles[nestedInputFiles.length - 1].name.replace(/^dto/, ".").replace(/\.ts$/, ""),
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
decorators.push(`@Field(() => [${inputNameClassName}], {${prop.nullable ? "nullable: true" : "defaultValue: []"}})`);
|
|
266
|
-
decorators.push(`@IsArray()`);
|
|
267
|
-
decorators.push(`@Type(() => ${inputNameClassName})`);
|
|
268
|
-
type = `${inputNameClassName}[]`;
|
|
231
|
+
}
|
|
232
|
+
else if (prop.kind == "1:m") {
|
|
233
|
+
if (prop.orphanRemoval) {
|
|
234
|
+
//if orphanRemoval is enabled, we need to generate a nested input type
|
|
235
|
+
decorators.length = 0;
|
|
236
|
+
if (!prop.targetMeta) {
|
|
237
|
+
throw new Error("No targetMeta");
|
|
269
238
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
else if (refType == "integer") {
|
|
289
|
-
type = "number[]";
|
|
290
|
-
decorators.push("@Transform(({ value }) => value.map((id: string) => parseInt(id)))");
|
|
291
|
-
decorators.push("@IsInt({ each: true })");
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
console.warn(`${prop.name}: Unsupported referenced type`);
|
|
295
|
-
}
|
|
239
|
+
const inputNameClassName = `${metadata.className}Nested${prop.targetMeta.className}Input`;
|
|
240
|
+
{
|
|
241
|
+
const excludeFields = prop.targetMeta.props.filter((p) => p.kind == "m:1" && p.targetMeta == metadata).map((p) => p.name);
|
|
242
|
+
const { fileNameSingular } = (0, build_name_variants_1.buildNameVariants)(metadata);
|
|
243
|
+
const { fileNameSingular: targetFileNameSingular } = (0, build_name_variants_1.buildNameVariants)(prop.targetMeta);
|
|
244
|
+
const fileName = `dto/${fileNameSingular}-nested-${targetFileNameSingular}.input.ts`;
|
|
245
|
+
const nestedInputFiles = await generateCrudInput(generatorOptions, prop.targetMeta, {
|
|
246
|
+
nested: true,
|
|
247
|
+
fileName,
|
|
248
|
+
className: inputNameClassName,
|
|
249
|
+
excludeFields,
|
|
250
|
+
});
|
|
251
|
+
generatedFiles.push(...nestedInputFiles);
|
|
252
|
+
imports.push({
|
|
253
|
+
name: inputNameClassName,
|
|
254
|
+
importPath: nestedInputFiles[nestedInputFiles.length - 1].name.replace(/^dto/, ".").replace(/\.ts$/, ""),
|
|
255
|
+
});
|
|
296
256
|
}
|
|
257
|
+
decorators.push(`@Field(() => [${inputNameClassName}], {${prop.nullable ? "nullable: true" : "defaultValue: []"}})`);
|
|
258
|
+
decorators.push(`@IsArray()`);
|
|
259
|
+
decorators.push(`@Type(() => ${inputNameClassName})`);
|
|
260
|
+
type = `${inputNameClassName}[]`;
|
|
297
261
|
}
|
|
298
|
-
else
|
|
262
|
+
else {
|
|
263
|
+
//if orphanRemoval is disabled, we reference the id in input
|
|
299
264
|
decorators.length = 0;
|
|
300
265
|
decorators.push(`@Field(() => [ID], {${prop.nullable ? "nullable: true" : "defaultValue: []"}})`);
|
|
301
266
|
decorators.push(`@IsArray()`);
|
|
@@ -315,169 +280,198 @@ function generateCrudInput(generatorOptions_1, metadata_1) {
|
|
|
315
280
|
else if (refType == "integer") {
|
|
316
281
|
type = "number[]";
|
|
317
282
|
decorators.push("@Transform(({ value }) => value.map((id: string) => parseInt(id)))");
|
|
283
|
+
decorators.push("@IsInt({ each: true })");
|
|
318
284
|
}
|
|
319
285
|
else {
|
|
320
286
|
console.warn(`${prop.name}: Unsupported referenced type`);
|
|
321
287
|
}
|
|
322
288
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
289
|
+
}
|
|
290
|
+
else if (prop.kind == "m:n") {
|
|
291
|
+
decorators.length = 0;
|
|
292
|
+
decorators.push(`@Field(() => [ID], {${prop.nullable ? "nullable: true" : "defaultValue: []"}})`);
|
|
293
|
+
decorators.push(`@IsArray()`);
|
|
294
|
+
if (prop.referencedColumnNames.length > 1) {
|
|
295
|
+
console.warn(`${prop.name}: Composite keys are not supported`);
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
const refType = findReferenceTargetType(prop.targetMeta, prop.referencedColumnNames[0]);
|
|
299
|
+
if (refType == "uuid") {
|
|
300
|
+
type = "string[]";
|
|
301
|
+
decorators.push("@IsUUID(undefined, { each: true })");
|
|
302
|
+
}
|
|
303
|
+
else if (refType == "string") {
|
|
304
|
+
type = "string[]";
|
|
305
|
+
decorators.push("@IsString({ each: true })");
|
|
306
|
+
}
|
|
307
|
+
else if (refType == "integer") {
|
|
308
|
+
type = "number[]";
|
|
309
|
+
decorators.push("@Transform(({ value }) => value.map((id: string) => parseInt(id)))");
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
console.warn(`${prop.name}: Unsupported referenced type`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
else if (prop.kind == "1:1") {
|
|
316
|
+
if (!prop.targetMeta) {
|
|
317
|
+
throw new Error("No targetMeta");
|
|
318
|
+
}
|
|
319
|
+
const inputNameClassName = `${metadata.className}Nested${prop.targetMeta.className}Input`;
|
|
320
|
+
{
|
|
321
|
+
const excludeFields = prop.targetMeta.props.filter((p) => p.kind == "1:1" && p.targetMeta == metadata).map((p) => p.name);
|
|
322
|
+
const { fileNameSingular } = (0, build_name_variants_1.buildNameVariants)(metadata);
|
|
323
|
+
const { fileNameSingular: targetFileNameSingular } = (0, build_name_variants_1.buildNameVariants)(prop.targetMeta);
|
|
324
|
+
const fileName = `dto/${fileNameSingular}-nested-${targetFileNameSingular}.input.ts`;
|
|
325
|
+
const nestedInputFiles = await generateCrudInput(generatorOptions, prop.targetMeta, {
|
|
326
|
+
nested: true,
|
|
327
|
+
fileName,
|
|
328
|
+
className: inputNameClassName,
|
|
329
|
+
excludeFields,
|
|
330
|
+
});
|
|
331
|
+
generatedFiles.push(...nestedInputFiles);
|
|
332
|
+
imports.push({
|
|
333
|
+
name: inputNameClassName,
|
|
334
|
+
importPath: nestedInputFiles[nestedInputFiles.length - 1].name.replace(/^dto/, ".").replace(/\.ts$/, ""),
|
|
335
|
+
});
|
|
348
336
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
337
|
+
decorators.push(`@Field(() => ${inputNameClassName}${prop.nullable ? ", { nullable: true }" : ""})`);
|
|
338
|
+
decorators.push(`@Type(() => ${inputNameClassName})`);
|
|
339
|
+
decorators.push("@ValidateNested()");
|
|
340
|
+
type = `${inputNameClassName}`;
|
|
341
|
+
}
|
|
342
|
+
else if (prop.type == "JsonType" || prop.embeddable || prop.type == "ArrayType") {
|
|
343
|
+
const tsProp = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata);
|
|
344
|
+
let tsType = tsProp.getType();
|
|
345
|
+
if (tsType.isUnion() && tsType.getUnionTypes().length == 2 && tsType.getUnionTypes()[0].getText() == "undefined") {
|
|
346
|
+
// undefinded | type (or prop?: type) -> type
|
|
347
|
+
tsType = tsType.getUnionTypes()[1];
|
|
348
|
+
}
|
|
349
|
+
type = tsType.getText(tsProp);
|
|
350
|
+
if (tsType.isArray()) {
|
|
351
|
+
const initializer = tsProp.getInitializer()?.getText();
|
|
352
|
+
const defaultValue = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined)
|
|
353
|
+
? "null"
|
|
354
|
+
: initializer == "[]"
|
|
355
|
+
? "[]"
|
|
356
|
+
: undefined;
|
|
357
|
+
const fieldOptions = tsCodeRecordToString({
|
|
358
|
+
nullable: prop.nullable ? "true" : undefined,
|
|
359
|
+
defaultValue: defaultValue,
|
|
360
|
+
});
|
|
361
|
+
decorators.push(`@IsArray()`);
|
|
362
|
+
if (type == "string[]") {
|
|
363
|
+
decorators.push(`@Field(() => [String], ${fieldOptions})`);
|
|
364
|
+
decorators.push("@IsString({ each: true })");
|
|
355
365
|
}
|
|
356
|
-
type
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
: undefined;
|
|
364
|
-
const fieldOptions = tsCodeRecordToString({
|
|
365
|
-
nullable: prop.nullable ? "true" : undefined,
|
|
366
|
-
defaultValue: defaultValue,
|
|
367
|
-
});
|
|
368
|
-
decorators.push(`@IsArray()`);
|
|
369
|
-
if (type == "string[]") {
|
|
370
|
-
decorators.push(`@Field(() => [String], ${fieldOptions})`);
|
|
371
|
-
decorators.push("@IsString({ each: true })");
|
|
372
|
-
}
|
|
373
|
-
else if (type == "number[]") {
|
|
374
|
-
decorators.push(`@Field(() => [Number], ${fieldOptions})`);
|
|
375
|
-
decorators.push("@IsNumber({ each: true })");
|
|
376
|
-
}
|
|
377
|
-
else if (type == "boolean[]") {
|
|
378
|
-
decorators.push(`@Field(() => [Boolean], ${fieldOptions})`);
|
|
379
|
-
decorators.push("@IsBoolean({ each: true })");
|
|
380
|
-
}
|
|
381
|
-
else if (tsType.getArrayElementTypeOrThrow().isClass()) {
|
|
382
|
-
const nestedClassName = tsType.getArrayElementTypeOrThrow().getText(tsProp);
|
|
383
|
-
const importPath = (0, ts_morph_helper_1.findInputClassImportPath)(nestedClassName, `${targetDirectory}/dto`, metadata);
|
|
384
|
-
imports.push({ name: nestedClassName, importPath });
|
|
385
|
-
decorators.push(`@ValidateNested()`);
|
|
386
|
-
decorators.push(`@Type(() => ${nestedClassName})`);
|
|
387
|
-
decorators.push(`@Field(() => [${nestedClassName}], ${fieldOptions})`);
|
|
388
|
-
}
|
|
389
|
-
else {
|
|
390
|
-
const typeNode = tsProp.getTypeNodeOrThrow().asKindOrThrow(ts_morph_1.SyntaxKind.ArrayType);
|
|
391
|
-
const elementTypeNode = typeNode.getElementTypeNode();
|
|
392
|
-
if (elementTypeNode.isKind(ts_morph_1.SyntaxKind.TypeReference)) {
|
|
393
|
-
// if the element type is a type reference, we need to find the import path
|
|
394
|
-
const { importPath } = (0, ts_morph_helper_1.findImportPath)(elementTypeNode.getText(), `${targetDirectory}/dto`, metadata);
|
|
395
|
-
if (importPath) {
|
|
396
|
-
imports.push({ name: elementTypeNode.getText(), importPath });
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
decorators.push(`@Field(() => [GraphQLJSONObject], ${fieldOptions}) // Warning: this input is not validated properly`);
|
|
400
|
-
}
|
|
366
|
+
else if (type == "number[]") {
|
|
367
|
+
decorators.push(`@Field(() => [Number], ${fieldOptions})`);
|
|
368
|
+
decorators.push("@IsNumber({ each: true })");
|
|
369
|
+
}
|
|
370
|
+
else if (type == "boolean[]") {
|
|
371
|
+
decorators.push(`@Field(() => [Boolean], ${fieldOptions})`);
|
|
372
|
+
decorators.push("@IsBoolean({ each: true })");
|
|
401
373
|
}
|
|
402
|
-
else if (tsType.isClass()) {
|
|
403
|
-
const nestedClassName = tsType.getText(tsProp);
|
|
374
|
+
else if (tsType.getArrayElementTypeOrThrow().isClass()) {
|
|
375
|
+
const nestedClassName = tsType.getArrayElementTypeOrThrow().getText(tsProp);
|
|
404
376
|
const importPath = (0, ts_morph_helper_1.findInputClassImportPath)(nestedClassName, `${targetDirectory}/dto`, metadata);
|
|
405
377
|
imports.push({ name: nestedClassName, importPath });
|
|
406
378
|
decorators.push(`@ValidateNested()`);
|
|
407
379
|
decorators.push(`@Type(() => ${nestedClassName})`);
|
|
408
|
-
decorators.push(`@Field(() => ${nestedClassName}
|
|
380
|
+
decorators.push(`@Field(() => [${nestedClassName}], ${fieldOptions})`);
|
|
409
381
|
}
|
|
410
382
|
else {
|
|
411
|
-
const typeNode = tsProp.getTypeNodeOrThrow();
|
|
412
|
-
|
|
383
|
+
const typeNode = tsProp.getTypeNodeOrThrow().asKindOrThrow(ts_morph_1.SyntaxKind.ArrayType);
|
|
384
|
+
const elementTypeNode = typeNode.getElementTypeNode();
|
|
385
|
+
if (elementTypeNode.isKind(ts_morph_1.SyntaxKind.TypeReference)) {
|
|
413
386
|
// if the element type is a type reference, we need to find the import path
|
|
414
|
-
const { importPath } = (0, ts_morph_helper_1.findImportPath)(
|
|
387
|
+
const { importPath } = (0, ts_morph_helper_1.findImportPath)(elementTypeNode.getText(), `${targetDirectory}/dto`, metadata);
|
|
415
388
|
if (importPath) {
|
|
416
|
-
imports.push({ name:
|
|
389
|
+
imports.push({ name: elementTypeNode.getText(), importPath });
|
|
417
390
|
}
|
|
418
391
|
}
|
|
419
|
-
decorators.push(`@Field(() => GraphQLJSONObject
|
|
392
|
+
decorators.push(`@Field(() => [GraphQLJSONObject], ${fieldOptions}) // Warning: this input is not validated properly`);
|
|
420
393
|
}
|
|
421
394
|
}
|
|
422
|
-
else if (
|
|
423
|
-
const
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
nullable: prop.nullable ? "true" : undefined,
|
|
427
|
-
defaultValue: defaultValueNull ? "null" : undefined,
|
|
428
|
-
});
|
|
429
|
-
decorators.push(`@Field(() => ID, ${fieldOptions})`);
|
|
430
|
-
decorators.push("@IsUUID()");
|
|
431
|
-
type = "string";
|
|
432
|
-
}
|
|
433
|
-
else if ((0, ts_morph_helper_1.getFieldDecoratorClassName)(prop.name, metadata)) {
|
|
434
|
-
//for custom mikro-orm type
|
|
435
|
-
const className = (0, ts_morph_helper_1.getFieldDecoratorClassName)(prop.name, metadata);
|
|
436
|
-
const importPath = (0, ts_morph_helper_1.findInputClassImportPath)(className, `${targetDirectory}/dto`, metadata);
|
|
437
|
-
imports.push({ name: className, importPath });
|
|
395
|
+
else if (tsType.isClass()) {
|
|
396
|
+
const nestedClassName = tsType.getText(tsProp);
|
|
397
|
+
const importPath = (0, ts_morph_helper_1.findInputClassImportPath)(nestedClassName, `${targetDirectory}/dto`, metadata);
|
|
398
|
+
imports.push({ name: nestedClassName, importPath });
|
|
438
399
|
decorators.push(`@ValidateNested()`);
|
|
439
|
-
decorators.push(`@Type(() => ${
|
|
440
|
-
decorators.push(`@Field(() => ${
|
|
441
|
-
type = className;
|
|
400
|
+
decorators.push(`@Type(() => ${nestedClassName})`);
|
|
401
|
+
decorators.push(`@Field(() => ${nestedClassName}${prop.nullable ? ", { nullable: true }" : ""})`);
|
|
442
402
|
}
|
|
443
403
|
else {
|
|
444
|
-
|
|
404
|
+
const typeNode = tsProp.getTypeNodeOrThrow();
|
|
405
|
+
if (typeNode.isKind(ts_morph_1.SyntaxKind.TypeReference)) {
|
|
406
|
+
// if the element type is a type reference, we need to find the import path
|
|
407
|
+
const { importPath } = (0, ts_morph_helper_1.findImportPath)(typeNode.getText(), `${targetDirectory}/dto`, metadata);
|
|
408
|
+
if (importPath) {
|
|
409
|
+
imports.push({ name: typeNode.getText(), importPath });
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
decorators.push(`@Field(() => GraphQLJSONObject${prop.nullable ? ", { nullable: true }" : ""}) // Warning: this input is not validated properly`);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
else if (prop.type == "uuid") {
|
|
416
|
+
const initializer = (0, ts_morph_helper_1.morphTsProperty)(prop.name, metadata).getInitializer()?.getText();
|
|
417
|
+
const defaultValueNull = prop.nullable && (initializer == "undefined" || initializer == "null" || initializer === undefined);
|
|
418
|
+
const fieldOptions = tsCodeRecordToString({
|
|
419
|
+
nullable: prop.nullable ? "true" : undefined,
|
|
420
|
+
defaultValue: defaultValueNull ? "null" : undefined,
|
|
421
|
+
});
|
|
422
|
+
decorators.push(`@Field(() => ID, ${fieldOptions})`);
|
|
423
|
+
decorators.push("@IsUUID()");
|
|
424
|
+
type = "string";
|
|
425
|
+
}
|
|
426
|
+
else if ((0, ts_morph_helper_1.getFieldDecoratorClassName)(prop.name, metadata)) {
|
|
427
|
+
//for custom mikro-orm type
|
|
428
|
+
const className = (0, ts_morph_helper_1.getFieldDecoratorClassName)(prop.name, metadata);
|
|
429
|
+
const importPath = (0, ts_morph_helper_1.findInputClassImportPath)(className, `${targetDirectory}/dto`, metadata);
|
|
430
|
+
imports.push({ name: className, importPath });
|
|
431
|
+
decorators.push(`@ValidateNested()`);
|
|
432
|
+
decorators.push(`@Type(() => ${className})`);
|
|
433
|
+
decorators.push(`@Field(() => ${className}${prop.nullable ? ", { nullable: true }" : ""})`);
|
|
434
|
+
type = className;
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
console.warn(`${prop.name}: unsupported type ${type}`);
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
const classValidatorValidators = (0, class_validator_1.getMetadataStorage)().getTargetValidationMetadatas(metadata.class, prop.name, false, false, undefined);
|
|
441
|
+
for (const validator of classValidatorValidators) {
|
|
442
|
+
if (validator.propertyName !== prop.name) {
|
|
445
443
|
continue;
|
|
446
444
|
}
|
|
447
|
-
const
|
|
448
|
-
for (const
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
if (importPath) {
|
|
463
|
-
imports.push({ name: decorator.getName(), importPath });
|
|
464
|
-
if (!decorators.includes(decorator.getText())) {
|
|
465
|
-
decorators.unshift(decorator.getText());
|
|
466
|
-
}
|
|
445
|
+
const constraints = (0, class_validator_1.getMetadataStorage)().getTargetValidatorConstraints(validator.constraintCls);
|
|
446
|
+
for (const constraint of constraints) {
|
|
447
|
+
const decorator = definedDecorators.find((decorator) => {
|
|
448
|
+
return (
|
|
449
|
+
// ignore casing since class validator is inconsistent with casing
|
|
450
|
+
decorator.getName().toUpperCase() === constraint.name.toUpperCase() ||
|
|
451
|
+
// some class validator decorators have a prefix "Is" but not in the constraint name
|
|
452
|
+
`Is${decorator.getName()}`.toUpperCase() === constraint.name.toUpperCase());
|
|
453
|
+
});
|
|
454
|
+
if (decorator) {
|
|
455
|
+
const importPath = (0, ts_morph_helper_1.findValidatorImportPath)(decorator.getName(), targetDirectory, metadata);
|
|
456
|
+
if (importPath) {
|
|
457
|
+
imports.push({ name: decorator.getName(), importPath });
|
|
458
|
+
if (!decorators.includes(decorator.getText())) {
|
|
459
|
+
decorators.unshift(decorator.getText());
|
|
467
460
|
}
|
|
468
461
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
}
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
console.warn(`Decorator import for constraint ${constraint.name} not found`);
|
|
472
465
|
}
|
|
473
466
|
}
|
|
474
|
-
|
|
467
|
+
}
|
|
468
|
+
fieldsOut += `${decorators.join("\n")}
|
|
475
469
|
${fieldName}${isOptional ? "?" : ""}: ${type};
|
|
476
470
|
|
|
477
471
|
`;
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
472
|
+
}
|
|
473
|
+
const className = options.className ?? `${metadata.className}Input`;
|
|
474
|
+
const inputOut = `import { Field, InputType, ID, Int } from "@nestjs/graphql";
|
|
481
475
|
import { Transform, Type } from "class-transformer";
|
|
482
476
|
import { GraphQLJSONObject, GraphQLLocalDate } from "graphql-scalars";
|
|
483
477
|
${(0, generate_imports_code_1.generateImportsCode)(imports)}
|
|
@@ -488,19 +482,18 @@ export class ${className} {
|
|
|
488
482
|
}
|
|
489
483
|
|
|
490
484
|
${options.generateUpdateInput && !options.nested
|
|
491
|
-
|
|
485
|
+
? `
|
|
492
486
|
@InputType()
|
|
493
487
|
export class ${className.replace(/Input$/, "")}UpdateInput extends PartialType(${className}) {}
|
|
494
488
|
`
|
|
495
|
-
|
|
489
|
+
: ""}
|
|
496
490
|
`;
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
});
|
|
504
|
-
return generatedFiles;
|
|
491
|
+
const { fileNameSingular } = (0, build_name_variants_1.buildNameVariants)(metadata);
|
|
492
|
+
const fileName = options.fileName ?? `dto/${fileNameSingular}.input.ts`;
|
|
493
|
+
generatedFiles.push({
|
|
494
|
+
name: fileName,
|
|
495
|
+
content: inputOut,
|
|
496
|
+
type: "input",
|
|
505
497
|
});
|
|
498
|
+
return generatedFiles;
|
|
506
499
|
}
|