@0kmpo/openapi-clean-arch-generator 1.3.13 → 1.3.15
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/README.md +12 -0
- package/dist/main.js +24 -2
- package/dist/package.json +78 -0
- package/dist/src/generators/clean-arch.generator.js +200 -136
- package/dist/src/generators/dto.generator.js +42 -22
- package/dist/src/generators/report.generator.js +6 -0
- package/dist/src/utils/example-validator.js +86 -0
- package/dist/src/utils/mock-value-resolver.js +19 -7
- package/dist/src/utils/name-formatter.js +99 -2
- package/dist/templates/api.repository.contract.mustache +1 -1
- package/dist/templates/api.repository.impl.mock.mustache +2 -2
- package/dist/templates/api.repository.impl.mustache +5 -5
- package/dist/templates/api.repository.impl.spec.mustache +2 -2
- package/dist/templates/api.use-cases.contract.mustache +1 -1
- package/dist/templates/api.use-cases.impl.mustache +2 -2
- package/dist/templates/api.use-cases.impl.spec.mustache +2 -2
- package/dist/templates/api.use-cases.mock.mustache +2 -2
- package/dist/templates/dto.mock.mustache +1 -1
- package/dist/templates/mapper.mustache +2 -2
- package/dist/templates/mapper.spec.mustache +2 -2
- package/dist/templates/model-entity.mustache +1 -1
- package/dist/templates/model-entity.spec.mustache +4 -0
- package/dist/templates/model.mock.mustache +2 -2
- package/dist/templates/repository.provider.mock.mustache +2 -2
- package/dist/templates/repository.provider.mustache +2 -2
- package/dist/templates/use-cases.provider.mock.mustache +2 -2
- package/dist/templates/use-cases.provider.mustache +2 -2
- package/package.json +2 -1
|
@@ -10,6 +10,7 @@ const child_process_1 = require("child_process");
|
|
|
10
10
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
12
|
const logger_1 = require("../utils/logger");
|
|
13
|
+
const name_formatter_1 = require("../utils/name-formatter");
|
|
13
14
|
/** Invokes `openapi-generator-cli` to generate DTOs into a temporary directory. */
|
|
14
15
|
function generateCode(swaggerFile, templatesDir) {
|
|
15
16
|
(0, logger_1.logStep)('Generating code from OpenAPI spec...');
|
|
@@ -37,8 +38,8 @@ function generateCode(swaggerFile, templatesDir) {
|
|
|
37
38
|
process.exit(1);
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
|
-
/** Copies the generated DTOs from the temporary directory to the output directory. */
|
|
41
|
-
function organizeFiles(tempDir, outputDir) {
|
|
41
|
+
/** Copies the generated DTOs from the temporary directory to the output directory, organised by tag subfolder. */
|
|
42
|
+
function organizeFiles(tempDir, outputDir, schemaTagMap = {}) {
|
|
42
43
|
(0, logger_1.logStep)('Organising generated DTO files...');
|
|
43
44
|
const sourceDir = path_1.default.join(tempDir, 'model');
|
|
44
45
|
const destDir = path_1.default.join(outputDir, 'data/dtos');
|
|
@@ -47,8 +48,13 @@ function organizeFiles(tempDir, outputDir) {
|
|
|
47
48
|
fs_extra_1.default.ensureDirSync(destDir);
|
|
48
49
|
const files = fs_extra_1.default.readdirSync(sourceDir).filter((file) => file.endsWith('.dto.ts'));
|
|
49
50
|
files.forEach((file) => {
|
|
51
|
+
// file is like "userResponse.dto.ts" → derive PascalCase schema name to look up tag
|
|
52
|
+
const camelName = file.replace('.dto.ts', '');
|
|
53
|
+
const pascalName = (0, name_formatter_1.toPascalCase)(camelName);
|
|
54
|
+
const tagFolder = schemaTagMap[pascalName] || 'shared';
|
|
50
55
|
const sourcePath = path_1.default.join(sourceDir, file);
|
|
51
|
-
const destPath = path_1.default.join(destDir, file);
|
|
56
|
+
const destPath = path_1.default.join(destDir, tagFolder, file);
|
|
57
|
+
fs_extra_1.default.ensureDirSync(path_1.default.dirname(destPath));
|
|
52
58
|
fs_extra_1.default.copySync(sourcePath, destPath);
|
|
53
59
|
filesMoved++;
|
|
54
60
|
(0, logger_1.logDetail)('dto', `${file} → ${path_1.default.relative(process.cwd(), destPath)}`);
|
|
@@ -62,46 +68,60 @@ function addDtoImports(outputDir) {
|
|
|
62
68
|
const dtosDir = path_1.default.join(outputDir, 'data/dtos');
|
|
63
69
|
if (!fs_extra_1.default.existsSync(dtosDir))
|
|
64
70
|
return;
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
// Collect all .dto.ts files from all subfolders (1 level deep)
|
|
72
|
+
const allFiles = [];
|
|
73
|
+
const entries = fs_extra_1.default.readdirSync(dtosDir);
|
|
74
|
+
entries.forEach((entry) => {
|
|
75
|
+
const entryPath = path_1.default.join(dtosDir, entry);
|
|
76
|
+
if (fs_extra_1.default.statSync(entryPath).isDirectory()) {
|
|
77
|
+
fs_extra_1.default.readdirSync(entryPath)
|
|
78
|
+
.filter((f) => f.endsWith('.dto.ts'))
|
|
79
|
+
.forEach((file) => allFiles.push({ subfolder: entry, file, fullPath: path_1.default.join(entryPath, file) }));
|
|
80
|
+
}
|
|
81
|
+
else if (entry.endsWith('.dto.ts')) {
|
|
82
|
+
allFiles.push({ subfolder: '', file: entry, fullPath: entryPath });
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
// Build map: ClassName → { subfolder, fileBase }
|
|
67
86
|
const dtoMap = {};
|
|
68
|
-
|
|
69
|
-
const content = fs_extra_1.default.readFileSync(
|
|
87
|
+
allFiles.forEach(({ subfolder, file, fullPath }) => {
|
|
88
|
+
const content = fs_extra_1.default.readFileSync(fullPath, 'utf8');
|
|
70
89
|
const match = content.match(/export interface (\w+)/);
|
|
71
|
-
if (match)
|
|
72
|
-
dtoMap[match[1]] = file.replace('.ts', '');
|
|
73
|
-
}
|
|
90
|
+
if (match)
|
|
91
|
+
dtoMap[match[1]] = { subfolder, fileBase: file.replace('.ts', '') };
|
|
74
92
|
});
|
|
75
93
|
let filesProcessed = 0;
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
const originalContent = fs_extra_1.default.readFileSync(filePath, 'utf8');
|
|
94
|
+
allFiles.forEach(({ subfolder, file, fullPath }) => {
|
|
95
|
+
const originalContent = fs_extra_1.default.readFileSync(fullPath, 'utf8');
|
|
79
96
|
let content = originalContent;
|
|
80
97
|
const selfMatch = content.match(/export interface (\w+)/);
|
|
81
98
|
const selfName = selfMatch ? selfMatch[1] : '';
|
|
82
|
-
// Normalize Array<T> → T[] (openapi-generator-cli always outputs Array<T>)
|
|
83
99
|
content = content.replace(/Array<(\w+)>/g, '$1[]');
|
|
84
|
-
// Find all Dto type references in the file body (excluding the interface name itself)
|
|
85
100
|
const references = new Set();
|
|
86
101
|
const typeRegex = /\b(\w+Dto)\b/g;
|
|
87
102
|
let match;
|
|
88
103
|
while ((match = typeRegex.exec(content)) !== null) {
|
|
89
|
-
if (match[1] !== selfName)
|
|
104
|
+
if (match[1] !== selfName)
|
|
90
105
|
references.add(match[1]);
|
|
91
|
-
}
|
|
92
106
|
}
|
|
93
|
-
// Build import lines for each referenced type that exists in the dtoMap
|
|
94
107
|
const imports = [];
|
|
95
108
|
references.forEach((ref) => {
|
|
96
109
|
if (dtoMap[ref]) {
|
|
97
|
-
|
|
110
|
+
const { subfolder: refSubfolder, fileBase: refFileBase } = dtoMap[ref];
|
|
111
|
+
const fromDir = subfolder ? path_1.default.join(dtosDir, subfolder) : dtosDir;
|
|
112
|
+
const toFile = refSubfolder
|
|
113
|
+
? path_1.default.join(dtosDir, refSubfolder, refFileBase)
|
|
114
|
+
: path_1.default.join(dtosDir, refFileBase);
|
|
115
|
+
let relPath = path_1.default.relative(fromDir, toFile).replace(/\\/g, '/');
|
|
116
|
+
if (!relPath.startsWith('.'))
|
|
117
|
+
relPath = './' + relPath;
|
|
118
|
+
imports.push(`import { ${ref} } from '${relPath}';`);
|
|
98
119
|
}
|
|
99
120
|
});
|
|
100
|
-
if (imports.length > 0)
|
|
121
|
+
if (imports.length > 0)
|
|
101
122
|
content = imports.join('\n') + '\n' + content;
|
|
102
|
-
}
|
|
103
123
|
if (content !== originalContent) {
|
|
104
|
-
fs_extra_1.default.writeFileSync(
|
|
124
|
+
fs_extra_1.default.writeFileSync(fullPath, content);
|
|
105
125
|
filesProcessed++;
|
|
106
126
|
(0, logger_1.logDetail)('dto', `Post-processed ${file} (added ${imports.length} import(s))`);
|
|
107
127
|
}
|
|
@@ -7,6 +7,7 @@ exports.generateReport = generateReport;
|
|
|
7
7
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const logger_1 = require("../utils/logger");
|
|
10
|
+
const example_validator_1 = require("../utils/example-validator");
|
|
10
11
|
/** Counts files ending with `.mock.ts` in a directory (returns 0 if directory does not exist). */
|
|
11
12
|
function countMockFiles(dir) {
|
|
12
13
|
try {
|
|
@@ -37,6 +38,7 @@ function generateReport(outputDir, analysis, lintResult) {
|
|
|
37
38
|
})).length;
|
|
38
39
|
return { name: t.name, description: t.description || '', endpoints: endpointCount };
|
|
39
40
|
});
|
|
41
|
+
const exampleMismatches = (0, example_validator_1.getExampleMismatches)();
|
|
40
42
|
const report = {
|
|
41
43
|
timestamp: new Date().toISOString(),
|
|
42
44
|
tags: analysis.tags.length,
|
|
@@ -44,6 +46,10 @@ function generateReport(outputDir, analysis, lintResult) {
|
|
|
44
46
|
tagDetails,
|
|
45
47
|
outputDirectory: outputDir,
|
|
46
48
|
linting: lintResult,
|
|
49
|
+
warnings: {
|
|
50
|
+
exampleMismatches: exampleMismatches.map((m) => ({ ...m })),
|
|
51
|
+
total: exampleMismatches.length
|
|
52
|
+
},
|
|
47
53
|
structure: {
|
|
48
54
|
dtos: fs_extra_1.default.readdirSync(path_1.default.join(outputDir, 'data/dtos')).length,
|
|
49
55
|
repositories: fs_extra_1.default.readdirSync(path_1.default.join(outputDir, 'data/repositories')).length,
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Validates that OpenAPI `example` values match their declared `type`.
|
|
4
|
+
*
|
|
5
|
+
* YAML parses unquoted values by native type (e.g. `example: 68131` becomes a JS number
|
|
6
|
+
* even when the schema declares `type: string`). This module detects such mismatches,
|
|
7
|
+
* coerces them when possible, and accumulates warnings for the generation report.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.validateExample = validateExample;
|
|
11
|
+
exports.registerMismatch = registerMismatch;
|
|
12
|
+
exports.getExampleMismatches = getExampleMismatches;
|
|
13
|
+
exports.clearExampleMismatches = clearExampleMismatches;
|
|
14
|
+
// Module-level accumulator — reset between runs via `clearExampleMismatches()`.
|
|
15
|
+
let mismatches = [];
|
|
16
|
+
/**
|
|
17
|
+
* Validates an `example` value against a declared OpenAPI `type`.
|
|
18
|
+
*
|
|
19
|
+
* @returns `{ valid: true }` when types already match, or
|
|
20
|
+
* `{ valid: false, coerced: <value> }` when the value was coerced, or
|
|
21
|
+
* `{ valid: false }` when coercion is not possible (caller should ignore the example).
|
|
22
|
+
*/
|
|
23
|
+
function validateExample(declaredType, example) {
|
|
24
|
+
if (declaredType === undefined)
|
|
25
|
+
return { valid: true };
|
|
26
|
+
const jsType = typeof example;
|
|
27
|
+
// ── string declared ──────────────────────────────────────────────────────
|
|
28
|
+
if (declaredType === 'string') {
|
|
29
|
+
if (jsType === 'string')
|
|
30
|
+
return { valid: true };
|
|
31
|
+
// number or boolean → coerce to string
|
|
32
|
+
if (jsType === 'number' || jsType === 'boolean') {
|
|
33
|
+
return { valid: false, coerced: String(example) };
|
|
34
|
+
}
|
|
35
|
+
return { valid: false };
|
|
36
|
+
}
|
|
37
|
+
// ── integer / number declared ────────────────────────────────────────────
|
|
38
|
+
if (declaredType === 'integer' || declaredType === 'number') {
|
|
39
|
+
if (jsType === 'number')
|
|
40
|
+
return { valid: true };
|
|
41
|
+
if (jsType === 'string') {
|
|
42
|
+
const parsed = Number(example);
|
|
43
|
+
if (!Number.isNaN(parsed))
|
|
44
|
+
return { valid: false, coerced: parsed };
|
|
45
|
+
return { valid: false }; // unparseable → ignore
|
|
46
|
+
}
|
|
47
|
+
return { valid: false };
|
|
48
|
+
}
|
|
49
|
+
// ── boolean declared ─────────────────────────────────────────────────────
|
|
50
|
+
if (declaredType === 'boolean') {
|
|
51
|
+
if (jsType === 'boolean')
|
|
52
|
+
return { valid: true };
|
|
53
|
+
if (jsType === 'string') {
|
|
54
|
+
const lower = example.toLowerCase();
|
|
55
|
+
if (lower === 'true')
|
|
56
|
+
return { valid: false, coerced: true };
|
|
57
|
+
if (lower === 'false')
|
|
58
|
+
return { valid: false, coerced: false };
|
|
59
|
+
}
|
|
60
|
+
return { valid: false }; // cannot coerce
|
|
61
|
+
}
|
|
62
|
+
// Other types (object, array, etc.) — no validation
|
|
63
|
+
return { valid: true };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Records a mismatch so it can be retrieved later for console warnings and the report.
|
|
67
|
+
*/
|
|
68
|
+
function registerMismatch(schemaName, propertyName, declaredType, exampleValue, action, coercedValue) {
|
|
69
|
+
mismatches.push({
|
|
70
|
+
schemaName,
|
|
71
|
+
propertyName,
|
|
72
|
+
declaredType,
|
|
73
|
+
exampleValue,
|
|
74
|
+
exampleJsType: typeof exampleValue,
|
|
75
|
+
action,
|
|
76
|
+
coercedValue
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/** Returns all recorded mismatches. */
|
|
80
|
+
function getExampleMismatches() {
|
|
81
|
+
return mismatches;
|
|
82
|
+
}
|
|
83
|
+
/** Clears all recorded mismatches (call before each generation run). */
|
|
84
|
+
function clearExampleMismatches() {
|
|
85
|
+
mismatches = [];
|
|
86
|
+
}
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolveMockValue = resolveMockValue;
|
|
4
|
+
const example_validator_1 = require("./example-validator");
|
|
4
5
|
/**
|
|
5
6
|
* Resolves a TypeScript literal string to use as a mock value for a single schema property.
|
|
6
7
|
*
|
|
7
8
|
* Priority chain:
|
|
8
9
|
* $ref mock call → array $ref mock call → enum[0] → example → format fallback → type default
|
|
9
10
|
*
|
|
10
|
-
* @param propName
|
|
11
|
-
* @param prop
|
|
12
|
-
* @param context
|
|
11
|
+
* @param propName Property name (used for format heuristics such as "email").
|
|
12
|
+
* @param prop Raw OpenAPI property definition.
|
|
13
|
+
* @param context 'dto' generates `mockFooDto()`, 'model' generates `mockFooModel()`.
|
|
14
|
+
* @param schemaName Parent schema name (used for mismatch reporting).
|
|
13
15
|
*/
|
|
14
|
-
function resolveMockValue(propName, prop, context = 'dto') {
|
|
16
|
+
function resolveMockValue(propName, prop, context = 'dto', schemaName = 'unknown') {
|
|
15
17
|
const suffix = context === 'dto' ? 'Dto' : 'Model';
|
|
16
18
|
// 1. Direct $ref → call the referenced mock factory
|
|
17
19
|
if (prop.$ref) {
|
|
@@ -31,9 +33,19 @@ function resolveMockValue(propName, prop, context = 'dto') {
|
|
|
31
33
|
const first = prop.enum[0];
|
|
32
34
|
return typeof first === 'string' ? `'${first}'` : String(first);
|
|
33
35
|
}
|
|
34
|
-
// 5. Example value
|
|
35
|
-
if (prop.example !== undefined)
|
|
36
|
-
|
|
36
|
+
// 5. Example value — validated and coerced if needed
|
|
37
|
+
if (prop.example !== undefined) {
|
|
38
|
+
const result = (0, example_validator_1.validateExample)(prop.type, prop.example);
|
|
39
|
+
if (result.valid) {
|
|
40
|
+
return formatLiteral(prop.example);
|
|
41
|
+
}
|
|
42
|
+
if (result.coerced !== undefined) {
|
|
43
|
+
(0, example_validator_1.registerMismatch)(schemaName, propName, prop.type, prop.example, 'coerced', result.coerced);
|
|
44
|
+
return formatLiteral(result.coerced);
|
|
45
|
+
}
|
|
46
|
+
// Cannot coerce — register and fall through to defaults
|
|
47
|
+
(0, example_validator_1.registerMismatch)(schemaName, propName, prop.type, prop.example, 'ignored');
|
|
48
|
+
}
|
|
37
49
|
// 6. Format-aware fallbacks (when no example is provided)
|
|
38
50
|
if (prop.format === 'date-time')
|
|
39
51
|
return `'2024-01-01T00:00:00.000Z'`;
|
|
@@ -1,16 +1,113 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toPascalCase = toPascalCase;
|
|
3
4
|
exports.toCamelCase = toCamelCase;
|
|
5
|
+
exports.isReservedWord = isReservedWord;
|
|
6
|
+
exports.safePropertyName = safePropertyName;
|
|
4
7
|
/**
|
|
5
|
-
* Converts a
|
|
8
|
+
* Converts a string to PascalCase, handling spaces, hyphens and underscores.
|
|
9
|
+
* Used to derive class names from schema/tag names.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* toPascalCase('Product Format') // 'ProductFormat'
|
|
13
|
+
* toPascalCase('user-response') // 'UserResponse'
|
|
14
|
+
* toPascalCase('UserSchema') // 'UserSchema'
|
|
15
|
+
*/
|
|
16
|
+
function toPascalCase(name) {
|
|
17
|
+
if (!name)
|
|
18
|
+
return name;
|
|
19
|
+
return name
|
|
20
|
+
.split(/[\s\-_]+/)
|
|
21
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
22
|
+
.join('');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Converts a string to camelCase, handling spaces, hyphens and underscores.
|
|
6
26
|
* Used to derive class filenames and variable names from schema/tag names.
|
|
7
27
|
*
|
|
8
28
|
* @example
|
|
29
|
+
* toCamelCase('Product Format') // 'productFormat'
|
|
9
30
|
* toCamelCase('ProductResponse') // 'productResponse'
|
|
10
31
|
* toCamelCase('UserSchema') // 'userSchema'
|
|
11
32
|
*/
|
|
12
33
|
function toCamelCase(name) {
|
|
13
34
|
if (!name)
|
|
14
35
|
return name;
|
|
15
|
-
|
|
36
|
+
const pascal = toPascalCase(name);
|
|
37
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
38
|
+
}
|
|
39
|
+
const JS_RESERVED_WORDS = new Set([
|
|
40
|
+
'abstract',
|
|
41
|
+
'arguments',
|
|
42
|
+
'await',
|
|
43
|
+
'boolean',
|
|
44
|
+
'break',
|
|
45
|
+
'byte',
|
|
46
|
+
'case',
|
|
47
|
+
'catch',
|
|
48
|
+
'char',
|
|
49
|
+
'class',
|
|
50
|
+
'const',
|
|
51
|
+
'continue',
|
|
52
|
+
'debugger',
|
|
53
|
+
'default',
|
|
54
|
+
'delete',
|
|
55
|
+
'do',
|
|
56
|
+
'double',
|
|
57
|
+
'else',
|
|
58
|
+
'enum',
|
|
59
|
+
'eval',
|
|
60
|
+
'export',
|
|
61
|
+
'extends',
|
|
62
|
+
'false',
|
|
63
|
+
'final',
|
|
64
|
+
'finally',
|
|
65
|
+
'float',
|
|
66
|
+
'for',
|
|
67
|
+
'function',
|
|
68
|
+
'goto',
|
|
69
|
+
'if',
|
|
70
|
+
'implements',
|
|
71
|
+
'import',
|
|
72
|
+
'in',
|
|
73
|
+
'instanceof',
|
|
74
|
+
'int',
|
|
75
|
+
'interface',
|
|
76
|
+
'let',
|
|
77
|
+
'long',
|
|
78
|
+
'native',
|
|
79
|
+
'new',
|
|
80
|
+
'null',
|
|
81
|
+
'package',
|
|
82
|
+
'private',
|
|
83
|
+
'protected',
|
|
84
|
+
'public',
|
|
85
|
+
'return',
|
|
86
|
+
'short',
|
|
87
|
+
'static',
|
|
88
|
+
'super',
|
|
89
|
+
'switch',
|
|
90
|
+
'synchronized',
|
|
91
|
+
'this',
|
|
92
|
+
'throw',
|
|
93
|
+
'throws',
|
|
94
|
+
'transient',
|
|
95
|
+
'true',
|
|
96
|
+
'try',
|
|
97
|
+
'typeof',
|
|
98
|
+
'undefined',
|
|
99
|
+
'var',
|
|
100
|
+
'void',
|
|
101
|
+
'volatile',
|
|
102
|
+
'while',
|
|
103
|
+
'with',
|
|
104
|
+
'yield'
|
|
105
|
+
]);
|
|
106
|
+
/** Returns true if the given name is a JS/TS reserved word. */
|
|
107
|
+
function isReservedWord(name) {
|
|
108
|
+
return JS_RESERVED_WORDS.has(name);
|
|
109
|
+
}
|
|
110
|
+
/** Prefixes reserved words with `_` to produce a safe identifier. */
|
|
111
|
+
function safePropertyName(name) {
|
|
112
|
+
return isReservedWord(name) ? `_${name}` : name;
|
|
16
113
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { InjectionToken } from '@angular/core';
|
|
5
5
|
import { Observable } from 'rxjs';
|
|
6
6
|
{{#imports}}
|
|
7
|
-
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
|
7
|
+
import { {{classname}} } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model';
|
|
8
8
|
{{/imports}}
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
import { MockService } from 'ng-mocks';
|
|
5
5
|
import { of } from 'rxjs';
|
|
6
6
|
|
|
7
|
-
import { {{classname}}RepositoryImpl } from '@/data/repositories/{{classFilename}}.repository.impl';
|
|
7
|
+
import { {{classname}}RepositoryImpl } from '@/data/repositories/{{classFilename}}/{{classFilename}}.repository.impl';
|
|
8
8
|
{{#returnImports}}
|
|
9
|
-
import { mock{{classname}}Model } from '@/entities/models/{{classFilename}}.model.mock';
|
|
9
|
+
import { mock{{classname}}Model } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model.mock';
|
|
10
10
|
{{/returnImports}}
|
|
11
11
|
|
|
12
12
|
export const mock{{classname}}RepositoryImpl = () =>
|
|
@@ -9,14 +9,14 @@ import { environment } from '@environment';
|
|
|
9
9
|
|
|
10
10
|
import { MRepository } from '@mercadona/core/utils/repository';
|
|
11
11
|
|
|
12
|
-
import { {{classname}}Repository } from '@/domain/repositories/{{classFilename}}.repository.contract';
|
|
12
|
+
import { {{classname}}Repository } from '@/domain/repositories/{{classFilename}}/{{classFilename}}.repository.contract';
|
|
13
13
|
{{#returnImports}}
|
|
14
|
-
import { {{classname}}Dto } from '@/dtos/{{classFilename}}.dto';
|
|
15
|
-
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
|
16
|
-
import { {{classVarName}}Mapper } from '@/mappers/{{classFilename}}.mapper';
|
|
14
|
+
import { {{classname}}Dto } from '@/dtos/{{tagFilename}}/{{classFilename}}.dto';
|
|
15
|
+
import { {{classname}} } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model';
|
|
16
|
+
import { {{classVarName}}Mapper } from '@/mappers/{{tagFilename}}/{{classFilename}}.mapper';
|
|
17
17
|
{{/returnImports}}
|
|
18
18
|
{{#paramImports}}
|
|
19
|
-
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
|
19
|
+
import { {{classname}} } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model';
|
|
20
20
|
{{/paramImports}}
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -6,8 +6,8 @@ import { TestBed } from '@angular/core/testing';
|
|
|
6
6
|
|
|
7
7
|
import { {{classname}}RepositoryImpl } from './{{classFilename}}.repository.impl';
|
|
8
8
|
{{#returnImports}}
|
|
9
|
-
import { mock{{classname}}Dto } from '@/dtos/{{classFilename}}.dto.mock';
|
|
10
|
-
import { mock{{classname}}Model } from '@/entities/models/{{classFilename}}.model.mock';
|
|
9
|
+
import { mock{{classname}}Dto } from '@/dtos/{{tagFilename}}/{{classFilename}}.dto.mock';
|
|
10
|
+
import { mock{{classname}}Model } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model.mock';
|
|
11
11
|
{{/returnImports}}
|
|
12
12
|
|
|
13
13
|
describe('{{classname}}RepositoryImpl', () => {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { InjectionToken } from '@angular/core';
|
|
5
5
|
import { Observable } from 'rxjs';
|
|
6
6
|
{{#imports}}
|
|
7
|
-
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
|
7
|
+
import { {{classname}} } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model';
|
|
8
8
|
{{/imports}}
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -6,9 +6,9 @@ import { Observable } from 'rxjs';
|
|
|
6
6
|
|
|
7
7
|
import { {{classname}}UseCases } from './{{classFilename}}.use-cases.contract';
|
|
8
8
|
|
|
9
|
-
import { {{constantName}}_REPOSITORY, {{classname}}Repository } from '@/domain/repositories/{{classFilename}}.repository.contract';
|
|
9
|
+
import { {{constantName}}_REPOSITORY, {{classname}}Repository } from '@/domain/repositories/{{classFilename}}/{{classFilename}}.repository.contract';
|
|
10
10
|
{{#imports}}
|
|
11
|
-
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
|
11
|
+
import { {{classname}} } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model';
|
|
12
12
|
{{/imports}}
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -6,9 +6,9 @@ import { of } from 'rxjs';
|
|
|
6
6
|
|
|
7
7
|
import { {{classname}}UseCasesImpl } from './{{classFilename}}.use-cases.impl';
|
|
8
8
|
|
|
9
|
-
import { {{constantName}}_REPOSITORY, {{classname}}Repository } from '@/domain/repositories/{{classFilename}}.repository.contract';
|
|
9
|
+
import { {{constantName}}_REPOSITORY, {{classname}}Repository } from '@/domain/repositories/{{classFilename}}/{{classFilename}}.repository.contract';
|
|
10
10
|
{{#returnImports}}
|
|
11
|
-
import { mock{{classname}}Model } from '@/entities/models/{{classFilename}}.model.mock';
|
|
11
|
+
import { mock{{classname}}Model } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model.mock';
|
|
12
12
|
{{/returnImports}}
|
|
13
13
|
|
|
14
14
|
describe('{{classname}}UseCasesImpl', () => {
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
import { MockService } from 'ng-mocks';
|
|
5
5
|
import { of } from 'rxjs';
|
|
6
6
|
|
|
7
|
-
import { {{classname}}UseCasesImpl } from '@/domain/use-cases/{{classFilename}}.use-cases.impl';
|
|
7
|
+
import { {{classname}}UseCasesImpl } from '@/domain/use-cases/{{classFilename}}/{{classFilename}}.use-cases.impl';
|
|
8
8
|
{{#returnImports}}
|
|
9
|
-
import { mock{{classname}}Model } from '@/entities/models/{{classFilename}}.model.mock';
|
|
9
|
+
import { mock{{classname}}Model } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model.mock';
|
|
10
10
|
{{/returnImports}}
|
|
11
11
|
|
|
12
12
|
export const mock{{classname}}UseCasesImpl = () =>
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
import { MapFromFn } from '@mercadona/common/public';
|
|
5
5
|
import { Builder } from '@mercadona/common/utils';
|
|
6
6
|
|
|
7
|
-
import { {{classname}}Dto } from '@/dtos/{{classFilename}}.dto';
|
|
8
|
-
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
|
7
|
+
import { {{classname}}Dto } from '@/dtos/{{tagFilename}}/{{classFilename}}.dto';
|
|
8
|
+
import { {{classname}} } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* {{classname}} Mapper
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
{{#model}}
|
|
3
3
|
import { {{classVarName}}Mapper } from './{{classFilename}}.mapper';
|
|
4
4
|
|
|
5
|
-
import { mock{{classname}}Dto } from '@/dtos/{{classFilename}}.dto.mock';
|
|
6
|
-
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
|
5
|
+
import { mock{{classname}}Dto } from '@/dtos/{{tagFilename}}/{{classFilename}}.dto.mock';
|
|
6
|
+
import { {{classname}} } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model';
|
|
7
7
|
|
|
8
8
|
describe('{{classVarName}}Mapper', () => {
|
|
9
9
|
{{#vars}}
|
|
@@ -11,6 +11,7 @@ describe('{{classname}}', () => {
|
|
|
11
11
|
});
|
|
12
12
|
|
|
13
13
|
{{#vars}}
|
|
14
|
+
{{#hasMockValue}}
|
|
14
15
|
it('should allow setting {{name}}', () => {
|
|
15
16
|
const model = new {{classname}}();
|
|
16
17
|
const expected = mock{{classname}}Model();
|
|
@@ -19,13 +20,16 @@ describe('{{classname}}', () => {
|
|
|
19
20
|
expect(model.{{name}}).toBe(expected.{{name}});
|
|
20
21
|
});
|
|
21
22
|
|
|
23
|
+
{{/hasMockValue}}
|
|
22
24
|
{{/vars}}
|
|
23
25
|
it('should build a valid model from mock', () => {
|
|
24
26
|
const model = mock{{classname}}Model();
|
|
25
27
|
|
|
26
28
|
expect(model).toBeInstanceOf({{classname}});
|
|
27
29
|
{{#vars}}
|
|
30
|
+
{{#hasMockValue}}
|
|
28
31
|
expect(model.{{name}}).toBeDefined();
|
|
32
|
+
{{/hasMockValue}}
|
|
29
33
|
{{/vars}}
|
|
30
34
|
});
|
|
31
35
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{{#models}}
|
|
2
2
|
{{#model}}
|
|
3
3
|
import { {{classname}} } from './{{classFilename}}.model';
|
|
4
|
-
import { {{classVarName}}Mapper } from '@/mappers/{{classFilename}}.mapper';
|
|
5
|
-
import { mock{{classname}}Dto } from '@/dtos/{{classFilename}}.dto.mock';
|
|
4
|
+
import { {{classVarName}}Mapper } from '@/mappers/{{tagFilename}}/{{classFilename}}.mapper';
|
|
5
|
+
import { mock{{classname}}Dto } from '@/dtos/{{tagFilename}}/{{classFilename}}.dto.mock';
|
|
6
6
|
|
|
7
7
|
export const mock{{classname}}Model = (overrides: Partial<{{classname}}> = {}): {{classname}} =>
|
|
8
8
|
Object.assign(new {{classname}}(), {
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
{{#operations}}
|
|
4
4
|
import { Provider } from '@angular/core';
|
|
5
5
|
|
|
6
|
-
import { {{constantName}}_REPOSITORY } from '@/domain/repositories/{{classFilename}}.repository.contract';
|
|
7
|
-
import { mock{{classname}}RepositoryImpl } from '@/data/repositories/{{classFilename}}.repository.impl.mock';
|
|
6
|
+
import { {{constantName}}_REPOSITORY } from '@/domain/repositories/{{classFilename}}/{{classFilename}}.repository.contract';
|
|
7
|
+
import { mock{{classname}}RepositoryImpl } from '@/data/repositories/{{classFilename}}/{{classFilename}}.repository.impl.mock';
|
|
8
8
|
|
|
9
9
|
export function mock{{classname}}Repository(): Provider[] {
|
|
10
10
|
return [
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
{{#operations}}
|
|
4
4
|
import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';
|
|
5
5
|
|
|
6
|
-
import { {{constantName}}_REPOSITORY } from '@/domain/repositories/{{classFilename}}.repository.contract';
|
|
7
|
-
import { {{classname}}RepositoryImpl } from '@/data/repositories/{{classFilename}}.repository.impl';
|
|
6
|
+
import { {{constantName}}_REPOSITORY } from '@/domain/repositories/{{classFilename}}/{{classFilename}}.repository.contract';
|
|
7
|
+
import { {{classname}}RepositoryImpl } from '@/data/repositories/{{classFilename}}/{{classFilename}}.repository.impl';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* {{classname}} Repository Provider
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
{{#operations}}
|
|
4
4
|
import { Provider } from '@angular/core';
|
|
5
5
|
|
|
6
|
-
import { {{constantName}}_USE_CASES } from '@/domain/use-cases/{{classFilename}}.use-cases.contract';
|
|
7
|
-
import { mock{{classname}}UseCasesImpl } from '@/domain/use-cases/{{classFilename}}.use-cases.mock';
|
|
6
|
+
import { {{constantName}}_USE_CASES } from '@/domain/use-cases/{{classFilename}}/{{classFilename}}.use-cases.contract';
|
|
7
|
+
import { mock{{classname}}UseCasesImpl } from '@/domain/use-cases/{{classFilename}}/{{classFilename}}.use-cases.mock';
|
|
8
8
|
|
|
9
9
|
export function mock{{classname}}UseCases(): Provider[] {
|
|
10
10
|
return [
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
{{#operations}}
|
|
4
4
|
import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';
|
|
5
5
|
|
|
6
|
-
import { {{constantName}}_USE_CASES } from '@/domain/use-cases/{{classFilename}}.use-cases.contract';
|
|
7
|
-
import { {{classname}}UseCasesImpl } from '@/domain/use-cases/{{classFilename}}.use-cases.impl';
|
|
6
|
+
import { {{constantName}}_USE_CASES } from '@/domain/use-cases/{{classFilename}}/{{classFilename}}.use-cases.contract';
|
|
7
|
+
import { {{classname}}UseCasesImpl } from '@/domain/use-cases/{{classFilename}}/{{classFilename}}.use-cases.impl';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* {{classname}} Use Cases Provider
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0kmpo/openapi-clean-arch-generator",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.15",
|
|
4
4
|
"description": "Angular Clean Architecture generator from OpenAPI/Swagger",
|
|
5
5
|
"main": "dist/main.js",
|
|
6
6
|
"bin": {
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"license": "MIT",
|
|
42
42
|
"files": [
|
|
43
43
|
"dist/main.js",
|
|
44
|
+
"dist/package.json",
|
|
44
45
|
"dist/src/",
|
|
45
46
|
"dist/templates/",
|
|
46
47
|
"README.md",
|