nest-prisma_doc-gen 1.0.18 → 1.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/dist/entities/dto-generator.js +14 -18
- package/dist/entities/field.js +1 -1
- package/dist/entities/generic.js +3 -2
- package/dist/entities/model.js +23 -6
- package/dist/entities/response-generator.js +3 -20
- package/dist/file.js +1 -0
- package/dist/main.js +60 -9
- package/dist/rules.js +3 -1
- package/dist/schemas/config.schema.json +14 -16
- package/dist/utils/helpers.js +9 -1
- package/dist/utils/loader.js +3 -1
- package/package.json +1 -1
|
@@ -1,30 +1,23 @@
|
|
|
1
|
-
import { DocGenFile } from "../file.js";
|
|
2
1
|
import { Helper } from "../utils/helpers.js";
|
|
3
2
|
import { Static } from "../static.js";
|
|
4
3
|
import { DocGenField } from "./field.js";
|
|
4
|
+
import { config } from "../utils/loader.js";
|
|
5
5
|
export class DocGenDto {
|
|
6
6
|
name;
|
|
7
|
-
file;
|
|
7
|
+
// file: DocGenFile;
|
|
8
8
|
fields = [];
|
|
9
|
-
imports = new Set([
|
|
10
|
-
`${Static.AUTO_GENERATED_COMMENT}`,
|
|
11
|
-
`import { ApiProperty, IntersectionType } from '@nestjs/swagger'`,
|
|
12
|
-
`import { DefaultIdDtoDG } from '../generic.dto'`,
|
|
13
|
-
]);
|
|
9
|
+
imports = new Set([`${Static.AUTO_GENERATED_COMMENT}`, `import { ApiProperty } from '@nestjs/swagger'`]);
|
|
14
10
|
classValidators = new Set();
|
|
15
11
|
enums = new Set();
|
|
16
12
|
constructor(model) {
|
|
17
13
|
this.name = model.name;
|
|
14
|
+
this.classValidators.add("IsString");
|
|
15
|
+
this.classValidators.add("IsNotEmpty");
|
|
18
16
|
for (const field of model.fields) {
|
|
19
17
|
if (field.isUpdatedAt || field.isId || field.name === "createdAt" || field.kind === "object")
|
|
20
18
|
continue;
|
|
21
19
|
this.fields.push(new DocGenField(field, "dto"));
|
|
22
20
|
}
|
|
23
|
-
this.file = new DocGenFile({
|
|
24
|
-
dir: "/dto",
|
|
25
|
-
fileName: `${Helper.toKebab(this.name)}.dto.ts`,
|
|
26
|
-
data: this.build(),
|
|
27
|
-
});
|
|
28
21
|
}
|
|
29
22
|
build() {
|
|
30
23
|
const sanitizedFields = this.fields
|
|
@@ -46,16 +39,19 @@ export class DocGenDto {
|
|
|
46
39
|
this.classValidators.add("IsEnum");
|
|
47
40
|
this.imports.add(`import { ${Array.from(this.enums)} } from '@prisma/client';`);
|
|
48
41
|
}
|
|
49
|
-
this.imports.add(`import { ${Array.from(this.classValidators)} } from '
|
|
42
|
+
this.imports.add(`import { ${Array.from(this.classValidators)} } from '${config.validatorPath}';`);
|
|
50
43
|
return [
|
|
51
44
|
`${Array.from(this.imports).join("\n")}`,
|
|
52
|
-
`
|
|
45
|
+
`class ${this.name}Dto {
|
|
53
46
|
${sanitizedFields}
|
|
54
47
|
}`,
|
|
55
|
-
`
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
`class ${this.name}Id {
|
|
49
|
+
@ApiProperty({ type: 'string', example: 'cmfxu4njg000008l52v7t8qze', required: true })
|
|
50
|
+
@IsString()
|
|
51
|
+
@IsNotEmpty()
|
|
52
|
+
${this.name.toLocaleLowerCase()}Id!: string;
|
|
53
|
+
}
|
|
54
|
+
`,
|
|
59
55
|
].join("\n\n");
|
|
60
56
|
}
|
|
61
57
|
}
|
package/dist/entities/field.js
CHANGED
|
@@ -79,7 +79,7 @@ export class DocGenField {
|
|
|
79
79
|
}
|
|
80
80
|
else if (this.kind === "object") {
|
|
81
81
|
this.isResponse = true;
|
|
82
|
-
this.type = `${this.scalarType}
|
|
82
|
+
this.type = `${this.scalarType}Res`;
|
|
83
83
|
}
|
|
84
84
|
else if (this.kind === "scalar") {
|
|
85
85
|
this.type = Helper.prismaScalarToTs(this.scalarType);
|
package/dist/entities/generic.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { DocGenFile } from "../file.js";
|
|
2
|
+
import { config } from "../utils/loader.js";
|
|
2
3
|
export class DocGenGeneric {
|
|
3
4
|
file;
|
|
4
5
|
constructor() {
|
|
5
6
|
const imports = `
|
|
6
7
|
import { ApiProperty } from '@nestjs/swagger';
|
|
7
|
-
import { IsString, IsNotEmpty } from '
|
|
8
|
+
import { IsString, IsNotEmpty } from '${config.validatorPath}';
|
|
8
9
|
`;
|
|
9
10
|
const validatorProps = `
|
|
10
|
-
export class
|
|
11
|
+
export class DefaultIdDto {
|
|
11
12
|
@ApiProperty({ type: 'string', example: 'cmfxu4njg000008l52v7t8qze', required: true })
|
|
12
13
|
@IsString()
|
|
13
14
|
@IsNotEmpty()
|
package/dist/entities/model.js
CHANGED
|
@@ -1,18 +1,35 @@
|
|
|
1
|
+
import { DocGenFile } from "../file.js";
|
|
2
|
+
import { Helper } from "../utils/helpers.js";
|
|
1
3
|
import { DocGenDto } from "./dto-generator.js";
|
|
2
4
|
import { DocGenResponse } from "./response-generator.js";
|
|
3
5
|
export class DocGenModel {
|
|
4
6
|
name;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
response;
|
|
8
|
+
dto;
|
|
7
9
|
fields;
|
|
10
|
+
exports;
|
|
11
|
+
file;
|
|
8
12
|
constructor(model) {
|
|
9
13
|
this.name = model.name;
|
|
10
14
|
this.fields = model.fields;
|
|
11
|
-
this.
|
|
12
|
-
this.
|
|
15
|
+
this.response = new DocGenResponse(model);
|
|
16
|
+
this.dto = new DocGenDto(model);
|
|
17
|
+
this.exports = [`export * from './types/${Helper.toKebab(this.name)}'`];
|
|
18
|
+
const intaaa = `
|
|
19
|
+
export namespace ${this.name} {
|
|
20
|
+
export type Dto = ${this.name}Dto;
|
|
21
|
+
export type Res = ${this.name}Res;
|
|
22
|
+
export type Id = ${this.name}Id;
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
const data = [this.dto.build(), this.response.build(), intaaa].join("");
|
|
26
|
+
this.file = new DocGenFile({
|
|
27
|
+
dir: "/types",
|
|
28
|
+
fileName: `${Helper.toKebab(this.name)}.ts`,
|
|
29
|
+
data,
|
|
30
|
+
});
|
|
13
31
|
}
|
|
14
32
|
save() {
|
|
15
|
-
this.
|
|
16
|
-
this.dtos.file.save();
|
|
33
|
+
this.file.save();
|
|
17
34
|
}
|
|
18
35
|
}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import { DocGenFile } from "../file.js";
|
|
2
|
-
import { Helper } from "../utils/helpers.js";
|
|
3
|
-
import { Static } from "../static.js";
|
|
4
1
|
import { DocGenField } from "./field.js";
|
|
5
2
|
export class DocGenResponse {
|
|
6
3
|
name;
|
|
7
|
-
file;
|
|
4
|
+
// file: DocGenFile;
|
|
8
5
|
fields = [];
|
|
9
|
-
imports = new Set([`${Static.AUTO_GENERATED_COMMENT}`, `import { ApiProperty } from '@nestjs/swagger'`]);
|
|
10
6
|
enums = new Set();
|
|
11
7
|
constructor(model) {
|
|
12
8
|
this.name = model.name;
|
|
@@ -15,31 +11,18 @@ export class DocGenResponse {
|
|
|
15
11
|
continue;
|
|
16
12
|
this.fields.push(new DocGenField(field, "res"));
|
|
17
13
|
}
|
|
18
|
-
this.file = new DocGenFile({
|
|
19
|
-
dir: "/res",
|
|
20
|
-
fileName: `${Helper.toKebab(this.name)}.res.ts`,
|
|
21
|
-
data: this.build(),
|
|
22
|
-
});
|
|
23
14
|
}
|
|
24
15
|
build() {
|
|
25
16
|
const sanitizedFields = this.fields
|
|
26
17
|
.map((field) => {
|
|
27
|
-
if (field.
|
|
28
|
-
this.imports.add(`import { ${field.type} } from './${Helper.toKebab(field.scalarType)}.res'`);
|
|
29
|
-
this.imports.add(`import { generateExample } from 'src/utils/functions/reflect'`);
|
|
30
|
-
}
|
|
31
|
-
else if (field.isEnum) {
|
|
18
|
+
if (field.isEnum) {
|
|
32
19
|
this.enums.add(field.type);
|
|
33
20
|
}
|
|
34
21
|
return field.build();
|
|
35
22
|
})
|
|
36
23
|
.join("\n\n");
|
|
37
|
-
if (this.enums.size > 0) {
|
|
38
|
-
this.imports.add(`import { ${Array.from(this.enums)} } from '@prisma/client';`);
|
|
39
|
-
}
|
|
40
24
|
return [
|
|
41
|
-
|
|
42
|
-
`export class ${this.name}ResDG {
|
|
25
|
+
`class ${this.name}Res {
|
|
43
26
|
${sanitizedFields}
|
|
44
27
|
}`,
|
|
45
28
|
].join("\n\n");
|
package/dist/file.js
CHANGED
package/dist/main.js
CHANGED
|
@@ -5,6 +5,8 @@ import { DocFields } from "./field.type.js";
|
|
|
5
5
|
import prismaPkg from "@prisma/internals";
|
|
6
6
|
import { PrismaUtils } from "./utils/prisma-utils.js";
|
|
7
7
|
import { DocGenGeneric } from "./entities/generic.js";
|
|
8
|
+
import { DocGenFile } from "./file.js";
|
|
9
|
+
import { Helper } from "./utils/helpers.js";
|
|
8
10
|
const { getDMMF } = prismaPkg;
|
|
9
11
|
const ROOT = process.cwd();
|
|
10
12
|
const PRISMA_DIR = path.join(ROOT, "src");
|
|
@@ -15,18 +17,11 @@ export class DocGen {
|
|
|
15
17
|
fields;
|
|
16
18
|
models;
|
|
17
19
|
generic = new DocGenGeneric();
|
|
20
|
+
indexFile;
|
|
21
|
+
fieldFile;
|
|
18
22
|
async init() {
|
|
19
23
|
const prismaDataModel = await PrismaUtils.readPrismaFolderDatamodel(PRISMA_DIR);
|
|
20
24
|
const { datamodel } = await getDMMF({ datamodel: prismaDataModel });
|
|
21
|
-
// this.enums = new DocEnums(
|
|
22
|
-
// datamodel.enums.map(({ dbName, name, values }) => {
|
|
23
|
-
// return new DocGenEnum({
|
|
24
|
-
// dbName: dbName ?? "",
|
|
25
|
-
// name,
|
|
26
|
-
// values: values as EnumValue[],
|
|
27
|
-
// });
|
|
28
|
-
// })
|
|
29
|
-
// );
|
|
30
25
|
const fieldSet = new Set();
|
|
31
26
|
for (const model of datamodel.models) {
|
|
32
27
|
for (const field of model.fields) {
|
|
@@ -42,9 +37,65 @@ export class DocGen {
|
|
|
42
37
|
build() {
|
|
43
38
|
this.generic.build();
|
|
44
39
|
this.fields.file.save();
|
|
40
|
+
const indexFileData = [`export * from './fields.types'`];
|
|
41
|
+
const fields = [];
|
|
42
|
+
const enumsSet = new Set();
|
|
43
|
+
const classValidatorsSet = new Set();
|
|
45
44
|
for (const model of this.models) {
|
|
45
|
+
indexFileData.push(...model.exports);
|
|
46
|
+
fields.push(...model.dto.fields);
|
|
47
|
+
for (const e of model.dto.enums) {
|
|
48
|
+
enumsSet.add(e);
|
|
49
|
+
}
|
|
50
|
+
for (const classValidator of model.dto.classValidators) {
|
|
51
|
+
classValidatorsSet.add(classValidator);
|
|
52
|
+
}
|
|
46
53
|
model.save();
|
|
47
54
|
}
|
|
55
|
+
indexFileData.push("export * as DG from 'src/types/docgen/index';");
|
|
56
|
+
const fieldMap = new Map();
|
|
57
|
+
for (const field of fields) {
|
|
58
|
+
if (fieldMap.has(field.name))
|
|
59
|
+
continue;
|
|
60
|
+
fieldMap.set(field.name, field);
|
|
61
|
+
}
|
|
62
|
+
const imports = new Set([`import { ApiProperty } from '@nestjs/swagger'`]);
|
|
63
|
+
const validators = `import { ${Array.from(classValidatorsSet)} } from 'src/_nest/validators';`;
|
|
64
|
+
const exportTypes = [];
|
|
65
|
+
const fieldClasses = Array.from(fieldMap)
|
|
66
|
+
.map(([_, field]) => {
|
|
67
|
+
field.isRequired = true;
|
|
68
|
+
const name = Helper.capitalizeFirstSafe(field.name);
|
|
69
|
+
exportTypes.push(`
|
|
70
|
+
export type ${name} = ${name}Dto
|
|
71
|
+
`);
|
|
72
|
+
return `
|
|
73
|
+
class ${name}Dto {
|
|
74
|
+
${field.build()}
|
|
75
|
+
}
|
|
76
|
+
`;
|
|
77
|
+
})
|
|
78
|
+
.join("\n");
|
|
79
|
+
imports.add(`import { ${Array.from(enumsSet)} } from '@prisma/client';`);
|
|
80
|
+
imports.add(validators);
|
|
81
|
+
const teste = `
|
|
82
|
+
export namespace Input {
|
|
83
|
+
${exportTypes.join(";")}
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
const fieldFileContent = [Array.from(imports).join("\n"), fieldClasses, teste];
|
|
87
|
+
this.fieldFile = new DocGenFile({
|
|
88
|
+
fileName: "fields.types.ts",
|
|
89
|
+
dir: "",
|
|
90
|
+
data: fieldFileContent.join("\n"),
|
|
91
|
+
});
|
|
92
|
+
this.indexFile = new DocGenFile({
|
|
93
|
+
fileName: "index.ts",
|
|
94
|
+
dir: "",
|
|
95
|
+
data: indexFileData.join("\n"),
|
|
96
|
+
});
|
|
97
|
+
this.indexFile.save();
|
|
98
|
+
this.fieldFile.save();
|
|
48
99
|
}
|
|
49
100
|
}
|
|
50
101
|
const generator = new DocGen();
|
package/dist/rules.js
CHANGED
|
@@ -2,9 +2,11 @@ export class DocGenRules {
|
|
|
2
2
|
ignore;
|
|
3
3
|
examples;
|
|
4
4
|
validators;
|
|
5
|
+
validatorPath;
|
|
5
6
|
constructor(params) {
|
|
6
|
-
const { examples, ignore, validators } = params;
|
|
7
|
+
const { examples, ignore, validators, validatorPath } = params;
|
|
7
8
|
this.ignore = ignore;
|
|
9
|
+
this.validatorPath = validatorPath;
|
|
8
10
|
if (!validators.length) {
|
|
9
11
|
console.warn("[doc-gen] Nenhum validator encontrado. Verifique seu docgen.config.ts*");
|
|
10
12
|
}
|
|
@@ -13,15 +13,18 @@
|
|
|
13
13
|
},
|
|
14
14
|
"fields": {
|
|
15
15
|
"type": "array",
|
|
16
|
-
"items": {
|
|
17
|
-
"type": "string"
|
|
18
|
-
},
|
|
16
|
+
"items": { "type": "string" },
|
|
19
17
|
"description": "Lista de nomes de campos onde o exemplo será aplicado."
|
|
20
18
|
}
|
|
21
19
|
},
|
|
22
20
|
"required": ["fields", "example"]
|
|
23
21
|
},
|
|
24
22
|
|
|
23
|
+
"ValidatorPath": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "Caminho (path) para o arquivo/pasta de validators usado pelo gerador."
|
|
26
|
+
},
|
|
27
|
+
|
|
25
28
|
"ValidatorBuilder": {
|
|
26
29
|
"additionalProperties": false,
|
|
27
30
|
"type": "object",
|
|
@@ -33,9 +36,7 @@
|
|
|
33
36
|
},
|
|
34
37
|
"fields": {
|
|
35
38
|
"type": "array",
|
|
36
|
-
"items": {
|
|
37
|
-
"type": "string"
|
|
38
|
-
},
|
|
39
|
+
"items": { "type": "string" },
|
|
39
40
|
"description": "Campos que recebem este validador."
|
|
40
41
|
}
|
|
41
42
|
},
|
|
@@ -53,27 +54,24 @@
|
|
|
53
54
|
},
|
|
54
55
|
"ignore": {
|
|
55
56
|
"type": "array",
|
|
56
|
-
"items": {
|
|
57
|
-
"type": "string"
|
|
58
|
-
},
|
|
57
|
+
"items": { "type": "string" },
|
|
59
58
|
"description": "Campos a serem ignorados durante a geração automática de DTOs."
|
|
60
59
|
},
|
|
60
|
+
"validatorPath": {
|
|
61
|
+
"$ref": "#/definitions/ValidatorPath"
|
|
62
|
+
},
|
|
61
63
|
"examples": {
|
|
62
64
|
"type": "array",
|
|
63
|
-
"items": {
|
|
64
|
-
"$ref": "#/definitions/ApiExampleBuilder"
|
|
65
|
-
},
|
|
65
|
+
"items": { "$ref": "#/definitions/ApiExampleBuilder" },
|
|
66
66
|
"description": "Lista de exemplos a serem aplicados a campos específicos."
|
|
67
67
|
},
|
|
68
68
|
"validators": {
|
|
69
69
|
"type": "array",
|
|
70
|
-
"items": {
|
|
71
|
-
"$ref": "#/definitions/ValidatorBuilder"
|
|
72
|
-
},
|
|
70
|
+
"items": { "$ref": "#/definitions/ValidatorBuilder" },
|
|
73
71
|
"description": "Lista de validadores associados a campos específicos."
|
|
74
72
|
}
|
|
75
73
|
},
|
|
76
|
-
"required": ["ignore", "examples", "validators"]
|
|
74
|
+
"required": ["ignore", "validatorPath", "examples", "validators"]
|
|
77
75
|
}
|
|
78
76
|
}
|
|
79
77
|
}
|
package/dist/utils/helpers.js
CHANGED
|
@@ -72,7 +72,7 @@ export class Helper {
|
|
|
72
72
|
return undefined;
|
|
73
73
|
}
|
|
74
74
|
static toKebab(s) {
|
|
75
|
-
return s.
|
|
75
|
+
return s.replaceAll(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
76
76
|
}
|
|
77
77
|
importsForModel(model) {
|
|
78
78
|
const needsEnum = model.fields.some((field) => field.kind === "enum");
|
|
@@ -135,4 +135,12 @@ export class Helper {
|
|
|
135
135
|
isDate(field) {
|
|
136
136
|
return field.kind === "scalar" && field.type === "DateTime";
|
|
137
137
|
}
|
|
138
|
+
// Mais segura (remove espaços do começo e lida melhor com alguns caracteres)
|
|
139
|
+
static capitalizeFirstSafe(str) {
|
|
140
|
+
const s = str.trimStart();
|
|
141
|
+
if (!s)
|
|
142
|
+
return s;
|
|
143
|
+
const [first, ...rest] = Array.from(s); // lida melhor com unicode
|
|
144
|
+
return first.toUpperCase() + rest.join("");
|
|
145
|
+
}
|
|
138
146
|
}
|
package/dist/utils/loader.js
CHANGED
|
@@ -14,11 +14,13 @@ export class DocGenConfig {
|
|
|
14
14
|
ignore;
|
|
15
15
|
examples;
|
|
16
16
|
validators;
|
|
17
|
+
validatorPath;
|
|
17
18
|
constructor(configs) {
|
|
18
|
-
const { examples, ignore, validators } = configs;
|
|
19
|
+
const { examples, ignore, validators, validatorPath } = configs;
|
|
19
20
|
this.ignore = ignore;
|
|
20
21
|
this.examples = examples;
|
|
21
22
|
this.validators = validators;
|
|
23
|
+
this.validatorPath = validatorPath;
|
|
22
24
|
}
|
|
23
25
|
static async readJson(filePath) {
|
|
24
26
|
const content = await fs.readFile(filePath, "utf8");
|