39 Commits

Author SHA1 Message Date
aa7c6cf338 chore: add dist to package.json
All checks were successful
Publish / publish (push) Successful in 1m47s
Lint / lint (pull_request) Successful in 13s
2026-03-27 14:53:39 +01:00
7c5af2f3ab chore: add dist to package.json
All checks were successful
Publish / publish (push) Successful in 1m44s
2026-03-27 14:45:53 +01:00
cbef98a077 chore: add dist to package.json
Some checks failed
Publish / publish (push) Has been cancelled
2026-03-27 14:26:09 +01:00
ddca01e4e9 chore: bump to version v1.3.10 2026-03-27 08:37:33 +00:00
59ff941fda Merge pull request 'chore: update installation instructions and add mock files to README' (#65) from feat/update-docu into main
Reviewed-on: #65
Reviewed-by: blas <me@blassanto.me>
2026-03-27 08:33:50 +00:00
8881e9494c chore: update installation instructions and add mock files to README
All checks were successful
Lint / lint (pull_request) Successful in 13s
Publish / publish (push) Successful in 2m48s
2026-03-27 09:28:51 +01:00
720748b73d chore: bump to version v1.3.9 2026-03-27 08:03:10 +00:00
7063796e28 Merge pull request 'chore: update installation instructions for npm registry in release body' (#64) from chore/change-registry-to-npm into main
All checks were successful
Publish / publish (push) Successful in 2m21s
Reviewed-on: #64
2026-03-27 08:02:13 +00:00
f349b7b2a3 chore: update installation instructions for npm registry in release body
All checks were successful
Lint / lint (pull_request) Successful in 19s
2026-03-27 08:59:28 +01:00
b59084dec6 chore: bump to version v1.3.8 2026-03-26 20:39:57 +00:00
5c83520f01 Merge pull request 'refactor: streamline npm registry authentication setup in publish workflow' (#63) from chore/update-publish into main
Some checks failed
Publish / publish (push) Failing after 32s
Reviewed-on: #63
2026-03-26 20:38:41 +00:00
cc0439e26e refactor: streamline npm registry authentication setup in publish workflow
All checks were successful
Lint / lint (pull_request) Successful in 14s
2026-03-26 21:32:24 +01:00
b5b3632f5b chore: bump to version v1.3.7 2026-03-26 20:24:26 +00:00
d78bc303fa Merge pull request 'chore: update-publish' (#62) from chore/update-publish into main
Some checks failed
Publish / publish (push) Failing after 5m32s
Reviewed-on: #62
Reviewed-by: blas <me@blassanto.me>
2026-03-26 20:23:35 +00:00
df9283556b Merge branch 'main' into chore/update-publish
All checks were successful
Lint / lint (pull_request) Successful in 14s
2026-03-26 21:21:07 +01:00
909f709659 fix: update environment variable for npm registry publishing 2026-03-26 21:20:50 +01:00
5878331abf chore: bump to version v1.3.6 2026-03-26 20:14:26 +00:00
7e8e6d7058 Merge pull request 'fix: update package name and installation instructions in publish workflow' (#61) from chore/update-publish into main
Some checks failed
Publish / publish (push) Failing after 5m30s
Reviewed-on: #61
Reviewed-by: blas <me@blassanto.me>
2026-03-26 20:12:32 +00:00
469697f636 fix: update package name and installation instructions in publish workflow
All checks were successful
Lint / lint (pull_request) Successful in 23s
2026-03-26 20:51:50 +01:00
2257e2141e Merge pull request 'feat/add-config-file' (#60) from feat/add-config-file into main
Reviewed-on: #60
2026-03-26 18:09:18 +00:00
0f64b51b63 Merge remote-tracking branch 'origin/main'
All checks were successful
Lint / lint (pull_request) Successful in 20s
# Conflicts:
#	main.ts
2026-03-26 19:02:16 +01:00
9c385191e2 feat: add configuration file strategy 2026-03-26 18:52:34 +01:00
d2f9eaa933 chore: bump to version v1.3.5 2026-03-26 16:08:21 +00:00
a600a60678 Merge pull request 'chore: update npm registry configuration in publish workflow' (#59) from chore/change-registry-to-npm into main
Some checks failed
Publish / publish (push) Failing after 5m27s
Reviewed-on: #59
2026-03-26 16:07:47 +00:00
a42063c1d9 chore: update npm registry configuration in publish workflow
All checks were successful
Lint / lint (pull_request) Successful in 14s
2026-03-26 17:05:10 +01:00
7f6feda81d chore: bump to version v1.3.4 2026-03-26 15:55:38 +00:00
12b2dd6b51 Merge pull request 'chore: update npm registry configuration in Bun settings' (#58) from chore/change-registry-to-npm into main
Some checks failed
Publish / publish (push) Has been cancelled
Reviewed-on: #58
2026-03-26 15:55:08 +00:00
84486e816a chore: update npm registry configuration in Bun settings
All checks were successful
Lint / lint (pull_request) Successful in 14s
2026-03-26 16:54:33 +01:00
942cf7f092 chore: bump to version v1.3.3 2026-03-26 15:52:35 +00:00
e0fb12a6c6 Merge pull request 'chore: add npm registry configuration to Bun settings' (#57) from chore/change-registry-to-npm into main
Some checks failed
Publish / publish (push) Failing after 27s
Reviewed-on: #57
2026-03-26 15:51:57 +00:00
2402b40059 chore: add npm registry configuration to Bun settings
All checks were successful
Lint / lint (pull_request) Successful in 14s
2026-03-26 16:48:15 +01:00
04962e32f5 chore: bump to version v1.3.2 2026-03-26 15:36:08 +00:00
144629bed6 chore: bump to version v1.3.2 2026-03-26 15:34:44 +00:00
0c58a63d01 chore: bump to version v1.3.2
Some checks failed
Publish / publish (push) Failing after 5m31s
2026-03-26 15:31:47 +00:00
74ac1c26a1 Merge pull request 'chore: update registry configuration from Gitea to npm' (#56) from chore/change-registry-to-npm into main
Reviewed-on: #56
2026-03-26 15:30:50 +00:00
db70f47bb7 chore: update registry configuration from Gitea to npm
All checks were successful
Lint / lint (pull_request) Successful in 18s
2026-03-26 16:29:34 +01:00
91e608415f chore: bump to version v1.3.1
Some checks failed
Publish / publish (push) Has been cancelled
2026-03-26 12:23:55 +00:00
058abf59c4 Merge pull request 'fix: assert repository call with specific parameters in observable completion' (#55) from fix/spec-without-expect into main
Reviewed-on: #55
Reviewed-by: blas <me@blassanto.me>
2026-03-26 12:22:55 +00:00
1d52da3805 test: assert repository call with specific parameters in observable completion
All checks were successful
Lint / lint (pull_request) Successful in 14s
2026-03-26 13:16:41 +01:00
8 changed files with 328 additions and 73 deletions

View File

@@ -62,21 +62,17 @@ jobs:
- name: Build binaries
run: bun run binaries
- name: Configure Gitea registry auth
- name: Configure npm registry auth
run: |
echo "@blas:registry=https://git.blassanto.me/api/packages/blas/npm/" >> ~/.npmrc
echo "//git.blassanto.me/api/packages/blas/npm/:_authToken=${NODE_AUTH_TOKEN}" >> ~/.npmrc
cat >> ~/.bunfig.toml << EOF
[install.scopes]
"@blas" = { registry = "https://git.blassanto.me/api/packages/blas/npm/", token = "${NODE_AUTH_TOKEN}" }
EOF
echo "registry=https://registry.npmjs.org" >> ~/.npmrc
echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" >> ~/.npmrc
env:
NODE_AUTH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish to Gitea registry
- name: Publish to npm registry
run: bun publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
BUN_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Create Gitea release and upload binaries
run: |
@@ -89,7 +85,7 @@ jobs:
-d "{
\"tag_name\": \"${GITHUB_REF_NAME}\",
\"name\": \"v${VERSION}\",
\"body\": \"## Installation\n\nDownload the binary for your platform or install via the npm registry:\n\n\`\`\`bash\nbun add -g @blas/openapi-clean-arch-generator --registry https://git.blassanto.me/api/packages/blas/npm/\n\`\`\`\",
\"body\": \"## Installation\n\nDownload the binary for your platform or install via the npm registry:\n\n\`\`\`bash\nbun add -g @0kmpo/openapi-clean-arch-generator\n\`\`\`\",
\"draft\": false,
\"prerelease\": false
}" | bun -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>console.log(JSON.parse(d).id))")

View File

@@ -15,29 +15,29 @@ Download the binary for your platform from the releases page and run it directly
```bash
# macOS (Apple Silicon)
curl -L <release-url>/generate-clean-arch-macos-arm64 -o generate-clean-arch
curl -L https://git.blassanto.me/blas/openapi-clean-arch-gen/releases/latest/download/generate-clean-arch-macos-arm64 -o generate-clean-arch
chmod +x generate-clean-arch && ./generate-clean-arch -i swagger.yaml
# macOS (Intel)
curl -L <release-url>/generate-clean-arch-macos-x64 -o generate-clean-arch
curl -L https://git.blassanto.me/blas/openapi-clean-arch-gen/releases/latest/download/generate-clean-arch-macos-x64 -o generate-clean-arch
chmod +x generate-clean-arch && ./generate-clean-arch -i swagger.yaml
# Linux x64
curl -L <release-url>/generate-clean-arch-linux-x64 -o generate-clean-arch
curl -L https://git.blassanto.me/blas/openapi-clean-arch-gen/releases/latest/download/generate-clean-arch-linux-x64 -o generate-clean-arch
chmod +x generate-clean-arch && ./generate-clean-arch -i swagger.yaml
# Windows (PowerShell)
curl -L <release-url>/generate-clean-arch-windows-x64.exe -o generate-clean-arch.exe
curl -L https://git.blassanto.me/blas/openapi-clean-arch-gen/releases/latest/download/generate-clean-arch-windows-x64.exe -o generate-clean-arch.exe
.\generate-clean-arch.exe -i swagger.yaml
```
### Option 1: Install as a global CLI from the registry
### Option 1: Install as a global CLI from npm
```bash
bun add -g @blas/openapi-clean-arch-generator --registry https://git.blassanto.me/api/packages/blas/npm/
bun add -g @0kmpo/openapi-clean-arch-generator
```
Or configure the registry in your `.npmrc` / `bunfig.toml` and then run:
Then run:
```bash
generate-clean-arch -i swagger.yaml
@@ -109,48 +109,54 @@ src/app/
├── data/ # Data layer
│ ├── dtos/ # Data Transfer Objects
│ │ ├── node/
│ │ │ ── node.dto.ts
│ │ │ ── node.dto.ts
│ │ │ └── node.dto.mock.ts
│ │ ├── order-type/
│ │ │ ── order-type.dto.ts
│ │ │ ── order-type.dto.ts
│ │ │ └── order-type.dto.mock.ts
│ │ └── supply-mode/
│ │ ── supply-mode.dto.ts
│ │ ── supply-mode.dto.ts
│ │ └── supply-mode.dto.mock.ts
│ ├── repositories/ # Repository implementations
│ │ ├── node.repository.impl.ts
│ │ ├── node.repository.impl.mock.ts
│ │ ├── node.repository.impl.spec.ts
│ │ ├── order-type.repository.impl.ts
│ │ ── supply-mode.repository.impl.ts
│ │ ── order-type.repository.impl.mock.ts
│ │ ├── order-type.repository.impl.spec.ts
│ │ └── ...
│ └── mappers/ # DTO → Entity transformers
│ ├── node.mapper.ts
│ ├── node.mapper.spec.ts
│ ├── order-type.mapper.ts
── supply-mode.mapper.ts
── order-type.mapper.spec.ts
│ └── ...
├── domain/ # Domain layer
│ ├── repositories/ # Repository contracts
│ │ ├── node.repository.contract.ts
│ │ ── order-type.repository.contract.ts
│ │ └── supply-mode.repository.contract.ts
│ │ ── ...
│ └── use-cases/ # Use cases
│ ├── node/
│ │ ├── node.use-cases.contract.ts
│ │ ── node.use-cases.impl.ts
├── order-type/
│ │ ── order-type.use-cases.contract.ts
│ └── order-type.use-cases.impl.ts
│ └── supply-mode/
│ ├── supply-mode.use-cases.contract.ts
│ └── supply-mode.use-cases.impl.ts
│ │ ── node.use-cases.impl.ts
│ ├── node.use-cases.mock.ts
│ │ ── node.use-cases.impl.spec.ts
└── ...
├── di/ # Dependency injection
│ ├── repositories/ # Repository providers
│ │ ├── node.repository.provider.ts
│ │ ├── order-type.repository.provider.ts
│ │ └── supply-mode.repository.provider.ts
│ │ ├── node.repository.provider.mock.ts
│ │ └── ...
│ └── use-cases/ # Use case providers
│ ├── node.use-cases.provider.ts
│ ├── order-type.use-cases.provider.ts
│ └── supply-mode.use-cases.provider.ts
│ ├── node.use-cases.provider.mock.ts
│ └── ...
└── entities/ # Domain entities
└── models/
├── node.model.ts
├── order-type.model.ts
── supply-mode.model.ts
├── node.model.mock.ts
── node.model.spec.ts
└── ...
```
## 🔧 Template Customization
@@ -160,14 +166,24 @@ Templates live in `templates/` and use [Mustache](https://mustache.github.io/) s
| Template | Generates |
|---|---|
| `model.mustache` | DTOs |
| `model.mock.mustache` | DTO mocks |
| `dto.mock.mustache` | DTO mocks (alternative) |
| `model-entity.mustache` | Domain entity models |
| `model-entity.spec.mustache` | Entity model specs |
| `mapper.mustache` | DTO → Entity mappers |
| `mapper.spec.mustache` | Mapper specs |
| `api.repository.contract.mustache` | Repository contracts |
| `api.repository.impl.mustache` | Repository implementations |
| `api.repository.impl.mock.mustache` | Repository mocks |
| `api.repository.impl.spec.mustache` | Repository specs |
| `api.use-cases.contract.mustache` | Use case contracts |
| `api.use-cases.impl.mustache` | Use case implementations |
| `api.use-cases.mock.mustache` | Use case mocks |
| `api.use-cases.impl.spec.mustache` | Use case specs |
| `repository.provider.mustache` | Repository DI providers |
| `repository.provider.mock.mustache` | Repository provider mocks |
| `use-cases.provider.mustache` | Use case DI providers |
| `use-cases.provider.mock.mustache` | Use case provider mocks |
### Available Mustache variables
@@ -194,12 +210,23 @@ After each run a `generation-report.json` file is created:
"timestamp": "2025-01-15T10:30:00.000Z",
"tags": 3,
"endpoints": 8,
"tagDetails": [
{ "name": "User", "description": "User operations", "endpoints": 3 },
{ "name": "Product", "description": "Product operations", "endpoints": 2 }
],
"outputDirectory": "./src/app",
"linting": {
"prettier": { "ran": true, "filesFormatted": 42 },
"eslint": { "ran": true, "filesFixed": 42 }
},
"structure": {
"dtos": 15,
"repositories": 9,
"mappers": 3,
"useCases": 6
"mappers": 5,
"useCases": 6,
"providers": 12,
"mocks": 18,
"specs": 14
}
}
```

24
generation-config.json Normal file
View File

@@ -0,0 +1,24 @@
{
"input": "example-swagger.yaml",
"output": "./src/app",
"skipLint": false,
"skipInstall": false,
"tags": {
"User": {
"baseUrl": "apiUrl",
"endpoints": [
"getUsers",
"createUser",
"getUserById",
"deleteUser"
]
},
"Product": {
"baseUrl": "apiUrl",
"endpoints": [
"getProducts"
]
}
},
"templates": "/Users/bsantome/Downloads/openapi-clean-arch-generator/templates"
}

65
main.ts
View File

@@ -26,6 +26,13 @@ import { generateReport } from './src/generators/report.generator';
import { lintGeneratedFiles } from './src/generators/lint.generator';
import { findEnvironmentFile, parseApiKeys } from './src/utils/environment-finder';
import { askApiKeysForTags, askSelectionFilter } from './src/utils/prompt';
import {
loadConfig,
generateDefaultConfig,
writeConfig,
deriveSelectionFilter,
deriveTagApiKeyMap
} from './src/utils/config';
import type { SelectionFilter, LintResult } from './src/types';
import type { CliOptions } from './src/types';
import packageJson from './package.json';
@@ -48,6 +55,8 @@ program
.option('--dry-run', 'Simulate without generating files')
.option('--skip-lint', 'Skip post-generation linting and formatting')
.option('-s, --select-endpoints', 'Interactively select which tags and endpoints to generate')
.option('-c, --config <file>', 'Use a JSON configuration file (skips interactive prompts)')
.option('--init-config [file]', 'Generate a JSON configuration file instead of generating code')
.parse(process.argv);
const options = program.opts<CliOptions>();
@@ -62,6 +71,21 @@ async function main(): Promise<void> {
const logPath = path.join(process.cwd(), 'generation.log');
initGenerationLog(logPath);
// ── CONFIG FILE: override CLI defaults with config values ─────────────────
const configFile = options.config;
const generationConfig = configFile ? loadConfig(configFile) : undefined;
if (generationConfig) {
if (generationConfig.input) options.input = generationConfig.input;
if (generationConfig.output) options.output = generationConfig.output;
if (generationConfig.templates) options.templates = generationConfig.templates;
if (generationConfig.skipInstall !== undefined)
options.skipInstall = generationConfig.skipInstall;
if (generationConfig.skipLint !== undefined) options.skipLint = generationConfig.skipLint;
logDetail('config', `Using configuration file: ${configFile}`);
}
logDetail('config', `Input: ${options.input}`);
logDetail('config', `Output: ${options.output}`);
logDetail('config', `Templates: ${options.templates}`);
@@ -90,6 +114,29 @@ async function main(): Promise<void> {
}
const analysis = analyzeSwagger(options.input);
const tagSummaries = extractTagsWithOperations(analysis);
// ── INIT CONFIG MODE: generate config file and exit ───────────────────────
if (options.initConfig !== undefined) {
const envFile = findEnvironmentFile(process.cwd());
let apiKeys: ReturnType<typeof parseApiKeys> = [];
if (envFile) {
const envContent = fs.readFileSync(envFile, 'utf8');
apiKeys = parseApiKeys(envContent);
}
const defaultConfig = generateDefaultConfig(analysis, tagSummaries, options, apiKeys);
const outputFile =
typeof options.initConfig === 'string' ? options.initConfig : 'generation-config.json';
writeConfig(defaultConfig, outputFile);
logSuccess(`Configuration file generated: ${outputFile}`);
logDetail(
'config',
'Edit the file to customise tags, endpoints and baseUrls, then run with --config'
);
return;
}
if (options.dryRun) {
logWarning('Finishing in DRY RUN mode');
@@ -99,9 +146,19 @@ async function main(): Promise<void> {
createDirectoryStructure(options.output);
// ── SELECTION: tags and endpoints ─────────────────────────────────────────
const tagSummaries = extractTagsWithOperations(analysis);
let selectionFilter: SelectionFilter = {};
let tagApiKeyMap: Record<string, string>;
if (generationConfig) {
// Config-driven: derive everything from the JSON file
selectionFilter = deriveSelectionFilter(generationConfig);
tagApiKeyMap = deriveTagApiKeyMap(generationConfig);
logDetail('config', `Tags from config: ${Object.keys(generationConfig.tags).join(', ')}`);
Object.entries(tagApiKeyMap).forEach(([tag, key]) => {
logDetail('config', `API key for "${tag}": environment.${key}.url`);
});
} else {
// Interactive mode (original behaviour)
if (options.selectEndpoints) {
selectionFilter = await askSelectionFilter(tagSummaries);
}
@@ -110,7 +167,7 @@ async function main(): Promise<void> {
? Object.keys(selectionFilter)
: tagSummaries.map((t) => t.tag);
// ── ENVIRONMENT API KEY SELECTION ──────────────────────────────────────────
// ── ENVIRONMENT API KEY SELECTION ────────────────────────────────────────
const envFile = findEnvironmentFile(process.cwd());
let apiKeys: ReturnType<typeof parseApiKeys> = [];
@@ -127,10 +184,12 @@ async function main(): Promise<void> {
logWarning('No environment.ts found. The key will be requested manually per repository.');
}
const tagApiKeyMap = await askApiKeysForTags(selectedTags, apiKeys);
tagApiKeyMap = await askApiKeysForTags(selectedTags, apiKeys);
Object.entries(tagApiKeyMap).forEach(([tag, key]) => {
logDetail('config', `API key for "${tag}": environment.${key}.url`);
});
}
// ──────────────────────────────────────────────────────────────────────────
const tempDir = generateCode(options.input, options.templates);

View File

@@ -1,6 +1,6 @@
{
"name": "@blas/openapi-clean-arch-generator",
"version": "1.3.0",
"name": "@0kmpo/openapi-clean-arch-generator",
"version": "1.3.10",
"description": "Angular Clean Architecture generator from OpenAPI/Swagger",
"main": "dist/main.js",
"bin": {
@@ -39,9 +39,14 @@
}
],
"license": "MIT",
"publishConfig": {
"registry": "https://git.blassanto.me/api/packages/blas/npm/"
},
"files": [
"dist/main.js",
"dist/package.json",
"dist/src/",
"dist/templates/",
"README.md",
"LICENSE"
],
"dependencies": {
"chalk": "^4.1.2",
"commander": "^11.1.0",

View File

@@ -10,4 +10,27 @@ export interface CliOptions {
dryRun?: boolean;
selectEndpoints?: boolean;
skipLint?: boolean;
config?: string;
initConfig?: string | boolean;
}
/**
* Per-tag configuration inside the generation config file.
*/
export interface TagConfig {
baseUrl: string;
endpoints: string[];
}
/**
* JSON configuration file schema.
* Allows full non-interactive control of the generation process.
*/
export interface GenerationConfig {
input: string;
output: string;
templates?: string;
skipInstall?: boolean;
skipLint?: boolean;
tags: Record<string, TagConfig>;
}

118
src/utils/config.ts Normal file
View File

@@ -0,0 +1,118 @@
import fs from 'fs-extra';
import { logInfo, logError } from './logger';
import type { GenerationConfig, TagConfig } from '../types';
import type { SwaggerAnalysis } from '../types';
import type { TagSummary } from '../types';
import type { ApiKeyInfo } from './environment-finder';
/**
* Loads and validates a GenerationConfig from a JSON file.
*/
export function loadConfig(filePath: string): GenerationConfig {
if (!fs.existsSync(filePath)) {
logError(`Configuration file not found: ${filePath}`);
process.exit(1);
}
const raw = fs.readFileSync(filePath, 'utf8');
let config: GenerationConfig;
try {
config = JSON.parse(raw) as GenerationConfig;
} catch {
logError(`Invalid JSON in configuration file: ${filePath}`);
process.exit(1);
}
if (!config.tags || typeof config.tags !== 'object') {
logError('Configuration file must contain a "tags" object');
process.exit(1);
}
for (const [tag, tagConfig] of Object.entries(config.tags)) {
if (!tagConfig.baseUrl || typeof tagConfig.baseUrl !== 'string') {
logError(`Tag "${tag}" must have a "baseUrl" string`);
process.exit(1);
}
if (!Array.isArray(tagConfig.endpoints) || tagConfig.endpoints.length === 0) {
logError(`Tag "${tag}" must have a non-empty "endpoints" array`);
process.exit(1);
}
}
return config;
}
/**
* Builds a default GenerationConfig from a swagger analysis, including all tags
* and all endpoints. Useful for --init-config to scaffold a config template.
*/
export function generateDefaultConfig(
analysis: SwaggerAnalysis,
tagSummaries: TagSummary[],
cliOptions: {
input: string;
output: string;
templates?: string;
skipLint?: boolean;
skipInstall?: boolean;
},
apiKeys: ApiKeyInfo[]
): GenerationConfig {
const tags: Record<string, TagConfig> = {};
for (const summary of tagSummaries) {
const matchingKey = apiKeys.find((k) =>
k.key.toLowerCase().includes(summary.tag.toLowerCase())
);
tags[summary.tag] = {
baseUrl: matchingKey?.key || 'apiUrl',
endpoints: summary.operations.map((op) => op.nickname)
};
}
const config: GenerationConfig = {
input: cliOptions.input,
output: cliOptions.output,
skipLint: cliOptions.skipLint ?? false,
skipInstall: cliOptions.skipInstall ?? false,
tags
};
if (cliOptions.templates) {
config.templates = cliOptions.templates;
}
return config;
}
/**
* Writes a GenerationConfig to a JSON file.
*/
export function writeConfig(config: GenerationConfig, filePath: string): void {
fs.writeFileSync(filePath, JSON.stringify(config, null, 2) + '\n', 'utf8');
logInfo(`Configuration file written to: ${filePath}`);
}
/**
* Derives the selectionFilter (tag → endpoint nicknames) from a GenerationConfig.
*/
export function deriveSelectionFilter(config: GenerationConfig): Record<string, string[]> {
const filter: Record<string, string[]> = {};
for (const [tag, tagConfig] of Object.entries(config.tags)) {
filter[tag] = [...tagConfig.endpoints];
}
return filter;
}
/**
* Derives the tagApiKeyMap (tag → baseUrl key) from a GenerationConfig.
*/
export function deriveTagApiKeyMap(config: GenerationConfig): Record<string, string> {
const map: Record<string, string> = {};
for (const [tag, tagConfig] of Object.entries(config.tags)) {
map[tag] = tagConfig.baseUrl;
}
return map;
}

View File

@@ -76,7 +76,10 @@ describe('{{classname}}UseCasesImpl', () => {
mockRepository.{{nickname}}.and.returnValue(of(undefined));
useCase.{{nickname}}({{#allParams}}{{{testValue}}}{{^-last}}, {{/-last}}{{/allParams}}).subscribe({
complete: () => done()
complete: () => {
expect(mockRepository.{{nickname}}).toHaveBeenCalledOnceWith({{#allParams}}{{{testValue}}}{{^-last}}, {{/-last}}{{/allParams}});
done();
}
});
{{/returnBaseType}}
{{/isListContainer}}