@0kmpo/openapi-clean-arch-generator 1.3.15 → 1.4.0

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 CHANGED
@@ -75,6 +75,7 @@ Options:
75
75
  -i, --input <file> OpenAPI/Swagger file (yaml or json) [default: swagger.yaml]
76
76
  -o, --output <dir> Output directory [default: ./src/app]
77
77
  -t, --templates <dir> Custom templates directory [default: ./templates]
78
+ -k, --base-name <name> Base name for generated folders (defaults to swagger filename)
78
79
  -s, --select-endpoints Interactively select tags and endpoints to generate
79
80
  -c, --config <file> Use a JSON configuration file (skips interactive prompts)
80
81
  --init-config [file] Generate a JSON configuration file instead of generating code
@@ -84,12 +85,31 @@ Options:
84
85
  -h, --help Show help
85
86
  ```
86
87
 
88
+ ### Base name (`-k`)
89
+
90
+ The generator organises output into subfolders based on a **base name** derived from your OpenAPI file. By default it extracts the token immediately before `-swagger` in the filename:
91
+
92
+ | Filename | Derived base name |
93
+ |---|---|
94
+ | `my-app-swagger.yaml` | `app` |
95
+ | `ecommerce-swagger.yaml` | `ecommerce` |
96
+ | `backoffice.yaml` | `backoffice` (+ warning) |
97
+
98
+ Use `-k` to override this value:
99
+
100
+ ```bash
101
+ generate-clean-arch -i api.yaml -k example1 # all files go under example1/
102
+ ```
103
+
87
104
  ### Examples
88
105
 
89
106
  ```bash
90
107
  # Generate from swagger.yaml into src/app
91
108
  generate-clean-arch -i swagger.yaml -o ./src/app
92
109
 
110
+ # Override base name (folder organisation)
111
+ generate-clean-arch -i ecommerce-api-swagger.yaml -o src/app -k ecommerce
112
+
93
113
  # Interactively select tags/endpoints
94
114
  generate-clean-arch -i api.yaml -s
95
115
 
@@ -109,68 +129,62 @@ generate-clean-arch --init-config generation-config.json
109
129
  generate-clean-arch -c generation-config.json
110
130
 
111
131
  # Full example with all options
112
- generate-clean-arch -i ./docs/api.yaml -o ./frontend/src/app -t ./custom-templates
132
+ generate-clean-arch -i ./docs/api.yaml -o ./frontend/src/app -t ./custom-templates -k myapp
113
133
  ```
114
134
 
115
135
  ## 📁 Generated Structure
116
136
 
117
- The generator creates the following structure following Clean Architecture:
137
+ The generator creates the following structure following Clean Architecture. All artefacts are organised under a **base name** folder (derived from the OpenAPI filename or set with `-k`), and within each layer further grouped by **tag subfolders** (one per API tag, or `shared` for types used across multiple tags):
118
138
 
119
139
  ```
120
140
  src/app/
121
- ├── data/ # Data layer
122
- │ ├── dtos/ # Data Transfer Objects
123
- │ │ ├── node/
124
- │ │ │ ├── node.dto.ts
125
- │ │ │ └── node.dto.mock.ts
126
- │ │ ├── order-type/
127
- │ │ ├── order-type.dto.ts
128
- │ │ │ └── order-type.dto.mock.ts
129
- │ │ └── supply-mode/
130
- │ │ ├── supply-mode.dto.ts
131
- │ │ └── supply-mode.dto.mock.ts
132
- │ ├── repositories/ # Repository implementations
133
- │ │ ├── node.repository.impl.ts
134
- │ │ ├── node.repository.impl.mock.ts
135
- │ │ ├── node.repository.impl.spec.ts
136
- │ │ ├── order-type.repository.impl.ts
137
- │ │ ├── order-type.repository.impl.mock.ts
138
- │ │ ├── order-type.repository.impl.spec.ts
139
- │ │ └── ...
140
- │ └── mappers/ # DTO → Entity transformers
141
- ├── node.mapper.ts
142
- ├── node.mapper.spec.ts
143
- ├── order-type.mapper.ts
144
- ├── order-type.mapper.spec.ts
145
- └── ...
146
- ├── domain/ # Domain layer
147
- │ ├── repositories/ # Repository contracts
148
- │ │ ├── node.repository.contract.ts
149
- └── ...
150
- │ └── use-cases/ # Use cases
151
- │ ├── node/
152
- │ │ ├── node.use-cases.contract.ts
153
- │ │ ├── node.use-cases.impl.ts
154
- │ │ ├── node.use-cases.mock.ts
155
- │ │ └── node.use-cases.impl.spec.ts
141
+ ├── <baseName>/ # Base name folder (e.g. "ecommerce")
142
+ │ ├── <tag1>/ # Tag subfolder (camelCase, e.g. "user")
143
+ │ │ ├── data/dtos/ # Data Transfer Objects
144
+ │ │ │ ├── user.dto.ts
145
+ │ │ │ ├── user.dto.mock.ts
146
+ │ │ │ └── ...
147
+ │ │ ├── data/repositories/ # Repository implementations
148
+ │ │ │ ├── user.repository.impl.ts
149
+ │ │ │ ├── user.repository.impl.mock.ts
150
+ │ │ │ └── user.repository.impl.spec.ts
151
+ │ │ ├── data/mappers/ # DTO → Entity transformers
152
+ │ │ ├── user.mapper.ts
153
+ │ │ │ └── user.mapper.spec.ts
154
+ │ │ ├── domain/repositories/ # Repository contracts
155
+ │ │ │ └── user.repository.contract.ts
156
+ │ │ ├── domain/use-cases/ # Use cases
157
+ │ │ ├── user.use-cases.contract.ts
158
+ │ │ ├── user.use-cases.impl.ts
159
+ │ │ │ ├── user.use-cases.mock.ts
160
+ │ │ └── user.use-cases.impl.spec.ts
161
+ ├── di/repositories/ # Repository DI providers
162
+ │ │ ├── user.repository.provider.ts
163
+ │ │ └── user.repository.provider.mock.ts
164
+ │ └── di/use-cases/ # Use case DI providers
165
+ ├── user.use-cases.provider.ts
166
+ │ │ └── user.use-cases.provider.mock.ts
167
+ │ ├── <tag2>/ # Another tag (e.g. "productFormat")
168
+ │ │ └── ... # Same internal structure
169
+ │ └── shared/ # Shared types (used by 0 or multiple tags)
156
170
  │ └── ...
157
- ├── di/ # Dependency injection
158
- │ ├── repositories/ # Repository providers
159
- │ │ ├── node.repository.provider.ts
160
- │ │ ├── node.repository.provider.mock.ts
161
- │ │ └── ...
162
- │ └── use-cases/ # Use case providers
163
- │ ├── node.use-cases.provider.ts
164
- │ ├── node.use-cases.provider.mock.ts
165
- │ └── ...
166
- └── entities/ # Domain entities
171
+ └── entities/ # Domain entities (outside baseName)
167
172
  └── models/
168
- ├── node.model.ts
169
- ├── node.model.mock.ts
170
- ├── node.model.spec.ts
171
- └── ...
173
+ ├── <tag1>/
174
+ ├── user.model.ts
175
+ ├── user.model.mock.ts
176
+ └── user.model.spec.ts
177
+ └── shared/
178
+ └── ...
172
179
  ```
173
180
 
181
+ ### How the folder organisation works
182
+
183
+ 1. **Base name** — derived from the OpenAPI filename (token before `-swagger`) or overridden with `-k`
184
+ 2. **Tag subfolders** — each API tag gets its own camelCase folder (e.g. `User` → `user`, `Product Format` → `productFormat`)
185
+ 3. **Shared types** — schemas used by zero or multiple tags land in `shared/`
186
+ 4. **Layer grouping** — each tag subfolder mirrors the full Clean Architecture layers (`data/`, `domain/`, `di/`, `entities/`)
187
+
174
188
  ## 🔧 Template Customization
175
189
 
176
190
  Templates live in `templates/` and use [Mustache](https://mustache.github.io/) syntax. Override them by passing your own directory with `-t`.
@@ -231,6 +245,20 @@ After each run a `generation-report.json` file is created:
231
245
  "prettier": { "ran": true, "filesFormatted": 42 },
232
246
  "eslint": { "ran": true, "filesFixed": 42 }
233
247
  },
248
+ "warnings": {
249
+ "total": 2,
250
+ "exampleMismatches": [
251
+ {
252
+ "schemaName": "UserDto",
253
+ "propertyName": "age",
254
+ "declaredType": "string",
255
+ "exampleValue": 25,
256
+ "exampleJsType": "number",
257
+ "action": "coerced",
258
+ "coercedValue": "25"
259
+ }
260
+ ]
261
+ },
234
262
  "structure": {
235
263
  "dtos": 15,
236
264
  "repositories": 9,
@@ -243,27 +271,35 @@ After each run a `generation-report.json` file is created:
243
271
  }
244
272
  ```
245
273
 
274
+ The report includes **example/type mismatch warnings** — when your OpenAPI schema declares a type (e.g. `string`) but the `example` value has a different JS type (e.g. a number). The generator either coerces the value or falls back to a type default and logs it here.
275
+
246
276
  ## 🎯 Angular Integration Example
247
277
 
248
278
  ### 1. Generate code
249
279
 
250
280
  ```bash
251
- generate-clean-arch -i ./docs/api.yaml -o ./src/app
281
+ generate-clean-arch -i ./docs/api.yaml -o ./src/app -k myapp
252
282
  ```
253
283
 
284
+ ### Automatic environment API key detection
285
+
286
+ During generation the tool automatically searches for an `environment.ts` file (up to 8 levels deep, skipping `node_modules`, `.git`, `dist`, etc.). It extracts keys containing "api" and offers them for selection per tag. If no file or no matching keys are found, you'll be prompted to enter them manually.
287
+
288
+ Each tag's repositories use the selected environment key to configure the base URL for HTTP calls (e.g. `environment.apiUrl`).
289
+
254
290
  ### 2. Register providers
255
291
 
256
292
  In your `app.config.ts` (Angular 17+ standalone):
257
293
 
258
294
  ```typescript
259
295
  import { ApplicationConfig } from '@angular/core';
260
- import { NodeRepositoryProvider } from './di/repositories/node.repository.provider';
261
- import { NodeUseCasesProvider } from './di/use-cases/node.use-cases.provider';
296
+ import { UserRepositoryProvider } from './myapp/user/di/repositories/user.repository.provider';
297
+ import { UserUseCasesProvider } from './myapp/user/di/use-cases/user.use-cases.provider';
262
298
 
263
299
  export const appConfig: ApplicationConfig = {
264
300
  providers: [
265
- NodeRepositoryProvider,
266
- NodeUseCasesProvider,
301
+ UserRepositoryProvider,
302
+ UserUseCasesProvider,
267
303
  // ... rest of generated providers
268
304
  ]
269
305
  };
@@ -273,18 +309,18 @@ export const appConfig: ApplicationConfig = {
273
309
 
274
310
  ```typescript
275
311
  import { Component, inject } from '@angular/core';
276
- import { NODE_USE_CASES } from './domain/use-cases/node/node.use-cases.contract';
312
+ import { USER_USE_CASES } from './domain/use-cases/myapp/user/user.use-cases.contract';
277
313
 
278
314
  @Component({
279
- selector: 'app-nodes',
315
+ selector: 'app-users',
280
316
  template: `...`
281
317
  })
282
- export class NodesComponent {
283
- readonly #nodeUseCases = inject(NODE_USE_CASES);
318
+ export class UsersComponent {
319
+ readonly #userUseCases = inject(USER_USE_CASES);
284
320
 
285
- loadNodes(): void {
286
- this.#nodeUseCases.getNodes().subscribe((nodes) => {
287
- console.log(nodes);
321
+ loadUsers(): void {
322
+ this.#userUseCases.getUsers().subscribe((users) => {
323
+ console.log(users);
288
324
  });
289
325
  }
290
326
  }
@@ -308,6 +344,18 @@ Specify the correct path with `-i`:
308
344
  generate-clean-arch -i ./path/to/your/api.yaml
309
345
  ```
310
346
 
347
+ ### Base name warning
348
+
349
+ If your OpenAPI file doesn't contain `-swagger` in the filename (e.g. `backoffice.yaml`), the generator uses the last token and emits a warning. Use `-k` to set it explicitly, or define it in your config file:
350
+
351
+ ```bash
352
+ # Via CLI
353
+ generate-clean-arch -i backoffice.yaml -k backoffice
354
+
355
+ # Via config file (-c)
356
+ generate-clean-arch -c generation-config.json # with "baseName": "backoffice" in the JSON
357
+ ```
358
+
311
359
  ### Path aliases `@/` not resolving
312
360
 
313
361
  Configure the aliases in your Angular project's `tsconfig.json`:
@@ -328,12 +376,21 @@ Configure the aliases in your Angular project's `tsconfig.json`:
328
376
  2. Check the Mustache syntax
329
377
  3. Use `--dry-run` to simulate without writing files
330
378
 
379
+ ### Example/type mismatch warnings
380
+
381
+ When your OpenAPI schema declares a type (e.g. `type: string`) but the `example` value is a different JS type (e.g. `example: 25` — a number), the generator either coerces it or uses a type default. Check `generation-report.json` under `warnings.exampleMismatches` for details.
382
+
331
383
  ## 📝 Notes
332
384
 
333
385
  - The generator produces ready-to-use `.ts` files, it does not compile them
334
386
  - Providers must be registered manually in your Angular module or config
335
387
  - Requires Angular 17+ (uses the `inject()` function)
336
388
  - Compatible with both standalone and module-based projects
389
+ - **Base name**: derived from the OpenAPI filename (token before `-swagger`), overridden with `-k`, or set in the config file (`-c`) as `"baseName"`
390
+ - **Tag organisation**: each API tag gets its own subfolder; shared types go in `shared/`
391
+ - **Environment detection**: automatically finds `environment.ts` and offers API keys per tag
392
+ - **Example validation**: type mismatches between declared types and example values are detected, coerced when possible, and reported in `generation-report.json`
393
+ - **Config workflow**: use `--init-config` to generate a `generation-config.json`, edit it to customise tags/endpoints/baseUrls/baseName, then reuse with `-c`
337
394
 
338
395
  ## 🤝 Contributing
339
396
 
package/dist/main.js CHANGED
@@ -20,6 +20,7 @@ const environment_finder_1 = require("./src/utils/environment-finder");
20
20
  const example_validator_1 = require("./src/utils/example-validator");
21
21
  const prompt_1 = require("./src/utils/prompt");
22
22
  const config_1 = require("./src/utils/config");
23
+ const name_formatter_1 = require("./src/utils/name-formatter");
23
24
  const package_json_1 = __importDefault(require("./package.json"));
24
25
  // Disable HTML escaping so that < and > produce valid TypeScript generic types.
25
26
  mustache_1.default.escape = function (text) {
@@ -37,6 +38,7 @@ commander_1.program
37
38
  .option('--dry-run', 'Simulate without generating files')
38
39
  .option('--skip-lint', 'Skip post-generation linting and formatting')
39
40
  .option('-s, --select-endpoints', 'Interactively select which tags and endpoints to generate')
41
+ .option('-k, --base-name <name>', 'Base name for generated folders (defaults to swagger filename)')
40
42
  .option('-c, --config <file>', 'Use a JSON configuration file (skips interactive prompts)')
41
43
  .option('--init-config [file]', 'Generate a JSON configuration file instead of generating code')
42
44
  .parse(process.argv);
@@ -63,6 +65,8 @@ async function main() {
63
65
  options.skipInstall = generationConfig.skipInstall;
64
66
  if (generationConfig.skipLint !== undefined)
65
67
  options.skipLint = generationConfig.skipLint;
68
+ if (generationConfig.baseName)
69
+ options.baseName = generationConfig.baseName;
66
70
  (0, logger_1.logDetail)('config', `Using configuration file: ${configFile}`);
67
71
  }
68
72
  (0, logger_1.logDetail)('config', `Input: ${options.input}`);
@@ -72,6 +76,8 @@ async function main() {
72
76
  (0, logger_1.logError)(`File not found: ${options.input}`);
73
77
  process.exit(1);
74
78
  }
79
+ const baseName = options.baseName ?? (0, name_formatter_1.deriveBaseName)(options.input);
80
+ (0, logger_1.logDetail)('config', `Base name: ${baseName}`);
75
81
  if (options.dryRun) {
76
82
  (0, logger_1.logWarning)('DRY RUN mode — no files will be generated');
77
83
  }
@@ -156,9 +162,9 @@ async function main() {
156
162
  const tagsMapForSchema = (0, clean_arch_generator_1.buildTagsMapFromAnalysis)(analysis, selectionFilter);
157
163
  const schemaTagMap = (0, clean_arch_generator_1.buildSchemaTagMap)(analysis.swagger.components
158
164
  ?.schemas || {}, tagsMapForSchema);
159
- (0, dto_generator_1.organizeFiles)(tempDir, options.output, schemaTagMap);
160
- (0, dto_generator_1.addDtoImports)(options.output);
161
- (0, clean_arch_generator_1.generateCleanArchitecture)(analysis, options.output, options.templates, tagApiKeyMap, selectionFilter, schemaTagMap);
165
+ (0, dto_generator_1.organizeFiles)(tempDir, options.output, schemaTagMap, baseName);
166
+ (0, dto_generator_1.addDtoImports)(options.output, baseName);
167
+ (0, clean_arch_generator_1.generateCleanArchitecture)(analysis, options.output, options.templates, tagApiKeyMap, selectionFilter, schemaTagMap, baseName);
162
168
  (0, filesystem_1.cleanup)(tempDir);
163
169
  // ── EXAMPLE/TYPE MISMATCH WARNINGS ─────────────────────────────────────────
164
170
  const mismatches = (0, example_validator_1.getExampleMismatches)();
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0kmpo/openapi-clean-arch-generator",
3
- "version": "1.3.15",
3
+ "version": "1.4.0",
4
4
  "description": "Angular Clean Architecture generator from OpenAPI/Swagger",
5
5
  "main": "dist/main.js",
6
6
  "bin": {
@@ -191,7 +191,7 @@ function buildSchemaTagMap(schemas, tagsMap) {
191
191
  return result;
192
192
  }
193
193
  /** Generates all Clean Architecture artefacts (models, mappers, repos, use cases, providers) using Mustache. */
194
- function generateCleanArchitecture(analysis, outputDir, templatesDir, tagApiKeyMap = {}, selectionFilter = {}, precomputedSchemaTagMap = {}) {
194
+ function generateCleanArchitecture(analysis, outputDir, templatesDir, tagApiKeyMap = {}, selectionFilter = {}, precomputedSchemaTagMap = {}, baseName = '') {
195
195
  (0, logger_1.logStep)('Generating Clean Architecture artefacts using Mustache...');
196
196
  const generatedCount = {
197
197
  models: 0,
@@ -212,8 +212,9 @@ function generateCleanArchitecture(analysis, outputDir, templatesDir, tagApiKeyM
212
212
  : buildSchemaTagMap(schemas, tagsMap);
213
213
  // 1. Generate Models, Entities and Mappers from Schemas
214
214
  Object.keys(schemas).forEach((schemaName) => {
215
- const baseName = schemaName.replace(/Dto$/, '');
216
- const tagFilename = schemaTagMap[baseName] || 'shared';
215
+ const schemaBaseName = schemaName.replace(/Dto$/, '');
216
+ const tagFilename = schemaTagMap[schemaBaseName] || 'shared';
217
+ const tagFolderPath = baseName ? `${baseName}/${tagFilename}` : tagFilename;
217
218
  const schemaObj = schemas[schemaName];
218
219
  const rawProperties = schemaObj.properties || {};
219
220
  const requiredProps = schemaObj.required || [];
@@ -248,16 +249,20 @@ function generateCleanArchitecture(analysis, outputDir, templatesDir, tagApiKeyM
248
249
  const modelImports = [...referencedTypes].filter(Boolean).map((name) => ({
249
250
  classname: name,
250
251
  classFilename: (0, name_formatter_1.toCamelCase)(name),
251
- tagFilename: schemaTagMap[name] || 'shared'
252
+ tagFilename: schemaTagMap[name] || 'shared',
253
+ tagFolderPath: baseName
254
+ ? `${baseName}/${schemaTagMap[name] || 'shared'}`
255
+ : schemaTagMap[name] || 'shared'
252
256
  }));
253
257
  const modelViewData = {
254
258
  tagFilename,
259
+ tagFolderPath,
255
260
  models: [
256
261
  {
257
262
  model: {
258
- classname: baseName,
259
- classFilename: (0, name_formatter_1.toCamelCase)(baseName),
260
- classVarName: (0, name_formatter_1.toCamelCase)(baseName),
263
+ classname: schemaBaseName,
264
+ classFilename: (0, name_formatter_1.toCamelCase)(schemaBaseName),
265
+ classVarName: (0, name_formatter_1.toCamelCase)(schemaBaseName),
261
266
  description: schemaObj.description || '',
262
267
  imports: modelImports,
263
268
  vars: varsMap
@@ -272,10 +277,11 @@ function generateCleanArchitecture(analysis, outputDir, templatesDir, tagApiKeyM
272
277
  apis: [
273
278
  {
274
279
  operations: {
275
- classname: baseName,
276
- classFilename: (0, name_formatter_1.toCamelCase)(baseName),
277
- classVarName: (0, name_formatter_1.toCamelCase)(baseName),
278
- tagFilename
280
+ classname: schemaBaseName,
281
+ classFilename: (0, name_formatter_1.toCamelCase)(schemaBaseName),
282
+ classVarName: (0, name_formatter_1.toCamelCase)(schemaBaseName),
283
+ tagFilename,
284
+ tagFolderPath
279
285
  }
280
286
  }
281
287
  ]
@@ -286,7 +292,7 @@ function generateCleanArchitecture(analysis, outputDir, templatesDir, tagApiKeyM
286
292
  if (fs_extra_1.default.existsSync(modelTemplatePath)) {
287
293
  const template = fs_extra_1.default.readFileSync(modelTemplatePath, 'utf8');
288
294
  const output = mustache_1.default.render(template, modelViewData);
289
- const destPath = path_1.default.join(outputDir, 'entities/models', tagFilename, `${(0, name_formatter_1.toCamelCase)(baseName)}.model.ts`);
295
+ const destPath = path_1.default.join(outputDir, 'entities/models', tagFolderPath, `${(0, name_formatter_1.toCamelCase)(schemaBaseName)}.model.ts`);
290
296
  fs_extra_1.default.ensureDirSync(path_1.default.dirname(destPath));
291
297
  fs_extra_1.default.writeFileSync(destPath, output);
292
298
  generatedCount.models++;
@@ -297,7 +303,7 @@ function generateCleanArchitecture(analysis, outputDir, templatesDir, tagApiKeyM
297
303
  if (fs_extra_1.default.existsSync(mapperTemplatePath)) {
298
304
  const template = fs_extra_1.default.readFileSync(mapperTemplatePath, 'utf8');
299
305
  const output = mustache_1.default.render(template, mapperViewData);
300
- const destPath = path_1.default.join(outputDir, 'data/mappers', tagFilename, `${(0, name_formatter_1.toCamelCase)(baseName)}.mapper.ts`);
306
+ const destPath = path_1.default.join(outputDir, 'data/mappers', tagFolderPath, `${(0, name_formatter_1.toCamelCase)(schemaBaseName)}.mapper.ts`);
301
307
  fs_extra_1.default.ensureDirSync(path_1.default.dirname(destPath));
302
308
  fs_extra_1.default.writeFileSync(destPath, output);
303
309
  generatedCount.mappers++;
@@ -315,45 +321,50 @@ function generateCleanArchitecture(analysis, outputDir, templatesDir, tagApiKeyM
315
321
  classname: name,
316
322
  classFilename: (0, name_formatter_1.toCamelCase)(name),
317
323
  tagFilename: targetTag,
324
+ tagFolderPath: baseName ? `${baseName}/${targetTag}` : targetTag,
318
325
  importPath
319
326
  };
320
327
  });
321
328
  const dtoMockViewData = {
322
329
  tagFilename,
330
+ tagFolderPath,
323
331
  models: [
324
332
  {
325
333
  model: {
326
- classname: baseName,
327
- classFilename: (0, name_formatter_1.toCamelCase)(baseName),
328
- classVarName: (0, name_formatter_1.toCamelCase)(baseName),
334
+ classname: schemaBaseName,
335
+ classFilename: (0, name_formatter_1.toCamelCase)(schemaBaseName),
336
+ classVarName: (0, name_formatter_1.toCamelCase)(schemaBaseName),
329
337
  mockImports: dtoMockImports,
330
338
  vars: dtoMockVarsMap
331
339
  }
332
340
  }
333
341
  ]
334
342
  };
335
- renderTemplate(templatesDir, 'dto.mock.mustache', dtoMockViewData, path_1.default.join(outputDir, 'data/dtos', tagFilename, `${(0, name_formatter_1.toCamelCase)(baseName)}.dto.mock.ts`), generatedCount, 'mocks');
343
+ renderTemplate(templatesDir, 'dto.mock.mustache', dtoMockViewData, path_1.default.join(outputDir, 'data/dtos', tagFolderPath, `${(0, name_formatter_1.toCamelCase)(schemaBaseName)}.dto.mock.ts`), generatedCount, 'mocks');
336
344
  // Model mock — delegates to mapper + DTO mock (no property values needed)
337
- renderTemplate(templatesDir, 'model.mock.mustache', modelViewData, path_1.default.join(outputDir, 'entities/models', tagFilename, `${(0, name_formatter_1.toCamelCase)(baseName)}.model.mock.ts`), generatedCount, 'mocks');
345
+ renderTemplate(templatesDir, 'model.mock.mustache', modelViewData, path_1.default.join(outputDir, 'entities/models', tagFolderPath, `${(0, name_formatter_1.toCamelCase)(schemaBaseName)}.model.mock.ts`), generatedCount, 'mocks');
338
346
  // Model spec
339
- renderTemplate(templatesDir, 'model-entity.spec.mustache', modelViewData, path_1.default.join(outputDir, 'entities/models', tagFilename, `${(0, name_formatter_1.toCamelCase)(baseName)}.model.spec.ts`), generatedCount, 'specs');
347
+ renderTemplate(templatesDir, 'model-entity.spec.mustache', modelViewData, path_1.default.join(outputDir, 'entities/models', tagFolderPath, `${(0, name_formatter_1.toCamelCase)(schemaBaseName)}.model.spec.ts`), generatedCount, 'specs');
340
348
  // Mapper spec
341
- renderTemplate(templatesDir, 'mapper.spec.mustache', mapperViewData, path_1.default.join(outputDir, 'data/mappers', tagFilename, `${(0, name_formatter_1.toCamelCase)(baseName)}.mapper.spec.ts`), generatedCount, 'specs');
349
+ renderTemplate(templatesDir, 'mapper.spec.mustache', mapperViewData, path_1.default.join(outputDir, 'data/mappers', tagFolderPath, `${(0, name_formatter_1.toCamelCase)(schemaBaseName)}.mapper.spec.ts`), generatedCount, 'specs');
342
350
  });
343
351
  // 2. Generate Use Cases and Repositories from Paths/Tags
344
352
  // Generate per tag
345
353
  Object.keys(tagsMap).forEach((tag) => {
346
354
  const tagFilename = (0, name_formatter_1.toCamelCase)(tag);
355
+ const tagFolderPath = baseName ? `${baseName}/${tagFilename}` : tagFilename;
347
356
  const returnImports = [];
348
357
  const paramImports = [];
349
358
  Object.keys(schemas).forEach((s) => {
350
359
  const usedAsReturn = tagsMap[tag].some((op) => op.returnType === s || op.returnType === `${s}[]`);
351
360
  const usedAsParam = tagsMap[tag].some((op) => op.allParams.some((p) => p.dataType === s || p.dataType === `${s}[]`));
361
+ const schemaTag = schemaTagMap[s] || 'shared';
352
362
  const entry = {
353
363
  classname: s,
354
364
  classFilename: (0, name_formatter_1.toCamelCase)(s),
355
365
  classVarName: (0, name_formatter_1.toCamelCase)(s),
356
- tagFilename: schemaTagMap[s] || 'shared'
366
+ tagFilename: schemaTag,
367
+ tagFolderPath: baseName ? `${baseName}/${schemaTag}` : schemaTag
357
368
  };
358
369
  if (usedAsReturn) {
359
370
  returnImports.push(entry);
@@ -371,6 +382,7 @@ function generateCleanArchitecture(analysis, outputDir, templatesDir, tagApiKeyM
371
382
  classname: (0, name_formatter_1.toPascalCase)(tag),
372
383
  classFilename: tagFilename,
373
384
  classVarName: tagFilename,
385
+ tagFolderPath,
374
386
  constantName: tag.toUpperCase().replace(/[^A-Z0-9]/g, '_'),
375
387
  operation: tagsMap[tag],
376
388
  imports: [...returnImports, ...paramImports],
@@ -382,21 +394,21 @@ function generateCleanArchitecture(analysis, outputDir, templatesDir, tagApiKeyM
382
394
  ]
383
395
  }
384
396
  };
385
- renderTemplate(templatesDir, 'api.use-cases.contract.mustache', apiViewData, path_1.default.join(outputDir, 'domain/use-cases', tagFilename, `${tagFilename}.use-cases.contract.ts`), generatedCount, 'useCases');
386
- renderTemplate(templatesDir, 'api.use-cases.impl.mustache', apiViewData, path_1.default.join(outputDir, 'domain/use-cases', tagFilename, `${tagFilename}.use-cases.impl.ts`), generatedCount, 'useCases');
387
- renderTemplate(templatesDir, 'api.repository.contract.mustache', apiViewData, path_1.default.join(outputDir, 'domain/repositories', tagFilename, `${tagFilename}.repository.contract.ts`), generatedCount, 'repositories');
388
- renderTemplate(templatesDir, 'api.repository.impl.mustache', apiViewData, path_1.default.join(outputDir, 'data/repositories', tagFilename, `${tagFilename}.repository.impl.ts`), generatedCount, 'repositories');
389
- renderTemplate(templatesDir, 'use-cases.provider.mustache', apiViewData, path_1.default.join(outputDir, 'di/use-cases', tagFilename, `${tagFilename}.use-cases.provider.ts`), generatedCount, 'providers');
390
- renderTemplate(templatesDir, 'repository.provider.mustache', apiViewData, path_1.default.join(outputDir, 'di/repositories', tagFilename, `${tagFilename}.repository.provider.ts`), generatedCount, 'providers');
397
+ renderTemplate(templatesDir, 'api.use-cases.contract.mustache', apiViewData, path_1.default.join(outputDir, 'domain/use-cases', tagFolderPath, `${tagFilename}.use-cases.contract.ts`), generatedCount, 'useCases');
398
+ renderTemplate(templatesDir, 'api.use-cases.impl.mustache', apiViewData, path_1.default.join(outputDir, 'domain/use-cases', tagFolderPath, `${tagFilename}.use-cases.impl.ts`), generatedCount, 'useCases');
399
+ renderTemplate(templatesDir, 'api.repository.contract.mustache', apiViewData, path_1.default.join(outputDir, 'domain/repositories', tagFolderPath, `${tagFilename}.repository.contract.ts`), generatedCount, 'repositories');
400
+ renderTemplate(templatesDir, 'api.repository.impl.mustache', apiViewData, path_1.default.join(outputDir, 'data/repositories', tagFolderPath, `${tagFilename}.repository.impl.ts`), generatedCount, 'repositories');
401
+ renderTemplate(templatesDir, 'use-cases.provider.mustache', apiViewData, path_1.default.join(outputDir, 'di/use-cases', tagFolderPath, `${tagFilename}.use-cases.provider.ts`), generatedCount, 'providers');
402
+ renderTemplate(templatesDir, 'repository.provider.mustache', apiViewData, path_1.default.join(outputDir, 'di/repositories', tagFolderPath, `${tagFilename}.repository.provider.ts`), generatedCount, 'providers');
391
403
  // Mocks
392
- renderTemplate(templatesDir, 'api.repository.impl.mock.mustache', apiViewData, path_1.default.join(outputDir, 'data/repositories', tagFilename, `${tagFilename}.repository.impl.mock.ts`), generatedCount, 'mocks');
393
- renderTemplate(templatesDir, 'api.use-cases.mock.mustache', apiViewData, path_1.default.join(outputDir, 'domain/use-cases', tagFilename, `${tagFilename}.use-cases.mock.ts`), generatedCount, 'mocks');
394
- renderTemplate(templatesDir, 'repository.provider.mock.mustache', apiViewData, path_1.default.join(outputDir, 'di/repositories', tagFilename, `${tagFilename}.repository.provider.mock.ts`), generatedCount, 'mocks');
395
- renderTemplate(templatesDir, 'use-cases.provider.mock.mustache', apiViewData, path_1.default.join(outputDir, 'di/use-cases', tagFilename, `${tagFilename}.use-cases.provider.mock.ts`), generatedCount, 'mocks');
404
+ renderTemplate(templatesDir, 'api.repository.impl.mock.mustache', apiViewData, path_1.default.join(outputDir, 'data/repositories', tagFolderPath, `${tagFilename}.repository.impl.mock.ts`), generatedCount, 'mocks');
405
+ renderTemplate(templatesDir, 'api.use-cases.mock.mustache', apiViewData, path_1.default.join(outputDir, 'domain/use-cases', tagFolderPath, `${tagFilename}.use-cases.mock.ts`), generatedCount, 'mocks');
406
+ renderTemplate(templatesDir, 'repository.provider.mock.mustache', apiViewData, path_1.default.join(outputDir, 'di/repositories', tagFolderPath, `${tagFilename}.repository.provider.mock.ts`), generatedCount, 'mocks');
407
+ renderTemplate(templatesDir, 'use-cases.provider.mock.mustache', apiViewData, path_1.default.join(outputDir, 'di/use-cases', tagFolderPath, `${tagFilename}.use-cases.provider.mock.ts`), generatedCount, 'mocks');
396
408
  // Repository impl spec
397
- renderTemplate(templatesDir, 'api.repository.impl.spec.mustache', apiViewData, path_1.default.join(outputDir, 'data/repositories', tagFilename, `${tagFilename}.repository.impl.spec.ts`), generatedCount, 'specs');
409
+ renderTemplate(templatesDir, 'api.repository.impl.spec.mustache', apiViewData, path_1.default.join(outputDir, 'data/repositories', tagFolderPath, `${tagFilename}.repository.impl.spec.ts`), generatedCount, 'specs');
398
410
  // Use-cases impl spec
399
- renderTemplate(templatesDir, 'api.use-cases.impl.spec.mustache', apiViewData, path_1.default.join(outputDir, 'domain/use-cases', tagFilename, `${tagFilename}.use-cases.impl.spec.ts`), generatedCount, 'specs');
411
+ renderTemplate(templatesDir, 'api.use-cases.impl.spec.mustache', apiViewData, path_1.default.join(outputDir, 'domain/use-cases', tagFolderPath, `${tagFilename}.use-cases.impl.spec.ts`), generatedCount, 'specs');
400
412
  });
401
413
  (0, logger_1.logSuccess)(`${generatedCount.models} Models, ${generatedCount.repositories} Repos, ${generatedCount.useCases} Use Cases, ${generatedCount.mappers} Mappers, ${generatedCount.providers} Providers, ${generatedCount.mocks} Mocks, ${generatedCount.specs} Specs generated`);
402
414
  return generatedCount;
@@ -39,7 +39,7 @@ function generateCode(swaggerFile, templatesDir) {
39
39
  }
40
40
  }
41
41
  /** Copies the generated DTOs from the temporary directory to the output directory, organised by tag subfolder. */
42
- function organizeFiles(tempDir, outputDir, schemaTagMap = {}) {
42
+ function organizeFiles(tempDir, outputDir, schemaTagMap = {}, baseName = '') {
43
43
  (0, logger_1.logStep)('Organising generated DTO files...');
44
44
  const sourceDir = path_1.default.join(tempDir, 'model');
45
45
  const destDir = path_1.default.join(outputDir, 'data/dtos');
@@ -53,7 +53,9 @@ function organizeFiles(tempDir, outputDir, schemaTagMap = {}) {
53
53
  const pascalName = (0, name_formatter_1.toPascalCase)(camelName);
54
54
  const tagFolder = schemaTagMap[pascalName] || 'shared';
55
55
  const sourcePath = path_1.default.join(sourceDir, file);
56
- const destPath = path_1.default.join(destDir, tagFolder, file);
56
+ const destPath = baseName
57
+ ? path_1.default.join(destDir, baseName, tagFolder, file)
58
+ : path_1.default.join(destDir, tagFolder, file);
57
59
  fs_extra_1.default.ensureDirSync(path_1.default.dirname(destPath));
58
60
  fs_extra_1.default.copySync(sourcePath, destPath);
59
61
  filesMoved++;
@@ -63,9 +65,11 @@ function organizeFiles(tempDir, outputDir, schemaTagMap = {}) {
63
65
  (0, logger_1.logSuccess)(`${filesMoved} DTOs moved successfully`);
64
66
  }
65
67
  /** Post-processes the generated DTOs: adds cross-DTO imports and normalises Array<T> → T[]. */
66
- function addDtoImports(outputDir) {
68
+ function addDtoImports(outputDir, baseName = '') {
67
69
  (0, logger_1.logStep)('Post-processing generated DTOs...');
68
- const dtosDir = path_1.default.join(outputDir, 'data/dtos');
70
+ const dtosDir = baseName
71
+ ? path_1.default.join(outputDir, 'data/dtos', baseName)
72
+ : path_1.default.join(outputDir, 'data/dtos');
69
73
  if (!fs_extra_1.default.existsSync(dtosDir))
70
74
  return;
71
75
  // Collect all .dto.ts files from all subfolders (1 level deep)
@@ -66,6 +66,9 @@ function generateDefaultConfig(analysis, tagSummaries, cliOptions, apiKeys) {
66
66
  if (cliOptions.templates) {
67
67
  config.templates = cliOptions.templates;
68
68
  }
69
+ if (cliOptions.baseName) {
70
+ config.baseName = cliOptions.baseName;
71
+ }
69
72
  return config;
70
73
  }
71
74
  /**
@@ -1,9 +1,15 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.toPascalCase = toPascalCase;
4
7
  exports.toCamelCase = toCamelCase;
5
8
  exports.isReservedWord = isReservedWord;
6
9
  exports.safePropertyName = safePropertyName;
10
+ exports.deriveBaseName = deriveBaseName;
11
+ const path_1 = __importDefault(require("path"));
12
+ const logger_1 = require("./logger");
7
13
  /**
8
14
  * Converts a string to PascalCase, handling spaces, hyphens and underscores.
9
15
  * Used to derive class names from schema/tag names.
@@ -111,3 +117,31 @@ function isReservedWord(name) {
111
117
  function safePropertyName(name) {
112
118
  return isReservedWord(name) ? `_${name}` : name;
113
119
  }
120
+ /**
121
+ * Derives a baseName from a swagger file path, used as the top-level folder
122
+ * that groups all generated artefacts for that contract.
123
+ *
124
+ * Primary rule: takes the token immediately before `-swagger` (case-insensitive).
125
+ * Fallback: takes the last token of the basename and emits a warning.
126
+ *
127
+ * @example
128
+ * deriveBaseName('my-app-swagger.yaml') // 'app'
129
+ * deriveBaseName('aprovalm-swagger.yaml') // 'aprovalm'
130
+ * deriveBaseName('backoffice.yaml') // 'backoffice' + warning
131
+ * deriveBaseName('my-backoffice.yaml') // 'backoffice' + warning
132
+ */
133
+ function deriveBaseName(filepath) {
134
+ const base = path_1.default.basename(filepath, path_1.default.extname(filepath));
135
+ const tokens = base.split(/[-_]+/);
136
+ const swaggerIdx = tokens.findIndex((t) => t.toLowerCase() === 'swagger');
137
+ let raw;
138
+ if (swaggerIdx > 0) {
139
+ raw = tokens[swaggerIdx - 1];
140
+ }
141
+ else {
142
+ raw = tokens[tokens.length - 1];
143
+ (0, logger_1.logWarning)(`Could not find "-swagger" segment in "${base}". ` +
144
+ `Using "${raw}" as baseName. Use -k to override.`);
145
+ }
146
+ return toCamelCase(raw);
147
+ }
@@ -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/{{tagFilename}}/{{classFilename}}.model';
7
+ import { {{classname}} } from '@/entities/models/{{tagFolderPath}}/{{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}}/{{classFilename}}.repository.impl';
7
+ import { {{classname}}RepositoryImpl } from '@/data/repositories/{{tagFolderPath}}/{{classFilename}}.repository.impl';
8
8
  {{#returnImports}}
9
- import { mock{{classname}}Model } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model.mock';
9
+ import { mock{{classname}}Model } from '@/entities/models/{{tagFolderPath}}/{{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}}/{{classFilename}}.repository.contract';
12
+ import { {{classname}}Repository } from '@/domain/repositories/{{tagFolderPath}}/{{classFilename}}.repository.contract';
13
13
  {{#returnImports}}
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';
14
+ import { {{classname}}Dto } from '@/dtos/{{tagFolderPath}}/{{classFilename}}.dto';
15
+ import { {{classname}} } from '@/entities/models/{{tagFolderPath}}/{{classFilename}}.model';
16
+ import { {{classVarName}}Mapper } from '@/mappers/{{tagFolderPath}}/{{classFilename}}.mapper';
17
17
  {{/returnImports}}
18
18
  {{#paramImports}}
19
- import { {{classname}} } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model';
19
+ import { {{classname}} } from '@/entities/models/{{tagFolderPath}}/{{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/{{tagFilename}}/{{classFilename}}.dto.mock';
10
- import { mock{{classname}}Model } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model.mock';
9
+ import { mock{{classname}}Dto } from '@/dtos/{{tagFolderPath}}/{{classFilename}}.dto.mock';
10
+ import { mock{{classname}}Model } from '@/entities/models/{{tagFolderPath}}/{{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/{{tagFilename}}/{{classFilename}}.model';
7
+ import { {{classname}} } from '@/entities/models/{{tagFolderPath}}/{{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}}/{{classFilename}}.repository.contract';
9
+ import { {{constantName}}_REPOSITORY, {{classname}}Repository } from '@/domain/repositories/{{tagFolderPath}}/{{classFilename}}.repository.contract';
10
10
  {{#imports}}
11
- import { {{classname}} } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model';
11
+ import { {{classname}} } from '@/entities/models/{{tagFolderPath}}/{{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}}/{{classFilename}}.repository.contract';
9
+ import { {{constantName}}_REPOSITORY, {{classname}}Repository } from '@/domain/repositories/{{tagFolderPath}}/{{classFilename}}.repository.contract';
10
10
  {{#returnImports}}
11
- import { mock{{classname}}Model } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model.mock';
11
+ import { mock{{classname}}Model } from '@/entities/models/{{tagFolderPath}}/{{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}}/{{classFilename}}.use-cases.impl';
7
+ import { {{classname}}UseCasesImpl } from '@/domain/use-cases/{{tagFolderPath}}/{{classFilename}}.use-cases.impl';
8
8
  {{#returnImports}}
9
- import { mock{{classname}}Model } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model.mock';
9
+ import { mock{{classname}}Model } from '@/entities/models/{{tagFolderPath}}/{{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/{{tagFilename}}/{{classFilename}}.dto';
8
- import { {{classname}} } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model';
7
+ import { {{classname}}Dto } from '@/dtos/{{tagFolderPath}}/{{classFilename}}.dto';
8
+ import { {{classname}} } from '@/entities/models/{{tagFolderPath}}/{{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/{{tagFilename}}/{{classFilename}}.dto.mock';
6
- import { {{classname}} } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model';
5
+ import { mock{{classname}}Dto } from '@/dtos/{{tagFolderPath}}/{{classFilename}}.dto.mock';
6
+ import { {{classname}} } from '@/entities/models/{{tagFolderPath}}/{{classFilename}}.model';
7
7
 
8
8
  describe('{{classVarName}}Mapper', () => {
9
9
  {{#vars}}
@@ -1,7 +1,7 @@
1
1
  {{#models}}
2
2
  {{#model}}
3
3
  {{#imports}}
4
- import { {{classname}} } from '@/entities/models/{{tagFilename}}/{{classFilename}}.model';
4
+ import { {{classname}} } from '@/entities/models/{{tagFolderPath}}/{{classFilename}}.model';
5
5
  {{/imports}}
6
6
 
7
7
  /**
@@ -1,8 +1,8 @@
1
1
  {{#models}}
2
2
  {{#model}}
3
3
  import { {{classname}} } from './{{classFilename}}.model';
4
- import { {{classVarName}}Mapper } from '@/mappers/{{tagFilename}}/{{classFilename}}.mapper';
5
- import { mock{{classname}}Dto } from '@/dtos/{{tagFilename}}/{{classFilename}}.dto.mock';
4
+ import { {{classVarName}}Mapper } from '@/mappers/{{tagFolderPath}}/{{classFilename}}.mapper';
5
+ import { mock{{classname}}Dto } from '@/dtos/{{tagFolderPath}}/{{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}}/{{classFilename}}.repository.contract';
7
- import { mock{{classname}}RepositoryImpl } from '@/data/repositories/{{classFilename}}/{{classFilename}}.repository.impl.mock';
6
+ import { {{constantName}}_REPOSITORY } from '@/domain/repositories/{{tagFolderPath}}/{{classFilename}}.repository.contract';
7
+ import { mock{{classname}}RepositoryImpl } from '@/data/repositories/{{tagFolderPath}}/{{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}}/{{classFilename}}.repository.contract';
7
- import { {{classname}}RepositoryImpl } from '@/data/repositories/{{classFilename}}/{{classFilename}}.repository.impl';
6
+ import { {{constantName}}_REPOSITORY } from '@/domain/repositories/{{tagFolderPath}}/{{classFilename}}.repository.contract';
7
+ import { {{classname}}RepositoryImpl } from '@/data/repositories/{{tagFolderPath}}/{{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}}/{{classFilename}}.use-cases.contract';
7
- import { mock{{classname}}UseCasesImpl } from '@/domain/use-cases/{{classFilename}}/{{classFilename}}.use-cases.mock';
6
+ import { {{constantName}}_USE_CASES } from '@/domain/use-cases/{{tagFolderPath}}/{{classFilename}}.use-cases.contract';
7
+ import { mock{{classname}}UseCasesImpl } from '@/domain/use-cases/{{tagFolderPath}}/{{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}}/{{classFilename}}.use-cases.contract';
7
- import { {{classname}}UseCasesImpl } from '@/domain/use-cases/{{classFilename}}/{{classFilename}}.use-cases.impl';
6
+ import { {{constantName}}_USE_CASES } from '@/domain/use-cases/{{tagFolderPath}}/{{classFilename}}.use-cases.contract';
7
+ import { {{classname}}UseCasesImpl } from '@/domain/use-cases/{{tagFolderPath}}/{{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.15",
3
+ "version": "1.4.0",
4
4
  "description": "Angular Clean Architecture generator from OpenAPI/Swagger",
5
5
  "main": "dist/main.js",
6
6
  "bin": {