Merge pull request 'feat: add mocks-generator' (#47) from feat/mocks-generator into main
Some checks failed
Publish / publish (push) Failing after 57s
Some checks failed
Publish / publish (push) Failing after 57s
Reviewed-on: #47 Reviewed-by: blas <me@blassanto.me>
This commit was merged in pull request #47.
This commit is contained in:
7
main.ts
7
main.ts
@@ -15,6 +15,7 @@ import {
|
|||||||
extractTagsWithOperations
|
extractTagsWithOperations
|
||||||
} from './src/generators/clean-arch.generator';
|
} from './src/generators/clean-arch.generator';
|
||||||
import { generateReport } from './src/generators/report.generator';
|
import { generateReport } from './src/generators/report.generator';
|
||||||
|
import { lintGeneratedFiles } from './src/generators/lint.generator';
|
||||||
import { findEnvironmentFile, parseApiKeys } from './src/utils/environment-finder';
|
import { findEnvironmentFile, parseApiKeys } from './src/utils/environment-finder';
|
||||||
import { askApiKeysForTags, askSelectionFilter } from './src/utils/prompt';
|
import { askApiKeysForTags, askSelectionFilter } from './src/utils/prompt';
|
||||||
import type { SelectionFilter } from './src/types';
|
import type { SelectionFilter } from './src/types';
|
||||||
@@ -37,6 +38,7 @@ program
|
|||||||
.option('-t, --templates <dir>', 'Custom templates directory', path.join(__dirname, 'templates'))
|
.option('-t, --templates <dir>', 'Custom templates directory', path.join(__dirname, 'templates'))
|
||||||
.option('--skip-install', 'Skip dependency installation')
|
.option('--skip-install', 'Skip dependency installation')
|
||||||
.option('--dry-run', 'Simulate without generating files')
|
.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('-s, --select-endpoints', 'Interactively select which tags and endpoints to generate')
|
||||||
.parse(process.argv);
|
.parse(process.argv);
|
||||||
|
|
||||||
@@ -132,6 +134,10 @@ async function main(): Promise<void> {
|
|||||||
);
|
);
|
||||||
cleanup(tempDir);
|
cleanup(tempDir);
|
||||||
|
|
||||||
|
if (!options.skipLint) {
|
||||||
|
lintGeneratedFiles(options.output);
|
||||||
|
}
|
||||||
|
|
||||||
const report = generateReport(options.output, analysis);
|
const report = generateReport(options.output, analysis);
|
||||||
|
|
||||||
console.log('\n' + '='.repeat(60));
|
console.log('\n' + '='.repeat(60));
|
||||||
@@ -143,6 +149,7 @@ async function main(): Promise<void> {
|
|||||||
console.log(` - Mappers: ${report.structure.mappers}`);
|
console.log(` - Mappers: ${report.structure.mappers}`);
|
||||||
console.log(` - Use Cases: ${report.structure.useCases}`);
|
console.log(` - Use Cases: ${report.structure.useCases}`);
|
||||||
console.log(` - Providers: ${report.structure.providers}`);
|
console.log(` - Providers: ${report.structure.providers}`);
|
||||||
|
console.log(` - Mocks: ${report.structure.mocks}`);
|
||||||
console.log(`\n📁 Files generated in: ${colors.cyan}${options.output}${colors.reset}\n`);
|
console.log(`\n📁 Files generated in: ${colors.cyan}${options.output}${colors.reset}\n`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import mustache from 'mustache';
|
|||||||
import { logStep, logSuccess, logInfo } from '../utils/logger';
|
import { logStep, logSuccess, logInfo } from '../utils/logger';
|
||||||
import { mapSwaggerTypeToTs } from '../utils/type-mapper';
|
import { mapSwaggerTypeToTs } from '../utils/type-mapper';
|
||||||
import { toCamelCase } from '../utils/name-formatter';
|
import { toCamelCase } from '../utils/name-formatter';
|
||||||
|
import { resolveMockValue } from '../utils/mock-value-resolver';
|
||||||
import type {
|
import type {
|
||||||
SwaggerAnalysis,
|
SwaggerAnalysis,
|
||||||
OpenApiSchema,
|
OpenApiSchema,
|
||||||
@@ -72,7 +73,8 @@ export function generateCleanArchitecture(
|
|||||||
repositories: 0,
|
repositories: 0,
|
||||||
mappers: 0,
|
mappers: 0,
|
||||||
useCases: 0,
|
useCases: 0,
|
||||||
providers: 0
|
providers: 0,
|
||||||
|
mocks: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
const schemas =
|
const schemas =
|
||||||
@@ -166,6 +168,48 @@ export function generateCleanArchitecture(
|
|||||||
fs.writeFileSync(destPath, output);
|
fs.writeFileSync(destPath, output);
|
||||||
generatedCount.mappers++;
|
generatedCount.mappers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DTO mock — values resolved from raw schema (example, format, type)
|
||||||
|
const dtoMockVarsMap = Object.keys(rawProperties).map((k) => ({
|
||||||
|
name: k,
|
||||||
|
mockValue: resolveMockValue(k, rawProperties[k], 'dto')
|
||||||
|
}));
|
||||||
|
const dtoMockImports = [...referencedTypes]
|
||||||
|
.filter(Boolean)
|
||||||
|
.map((name) => ({ classname: name, classFilename: toCamelCase(name) }));
|
||||||
|
|
||||||
|
const dtoMockViewData = {
|
||||||
|
models: [
|
||||||
|
{
|
||||||
|
model: {
|
||||||
|
classname: baseName,
|
||||||
|
classFilename: toCamelCase(baseName),
|
||||||
|
classVarName: toCamelCase(baseName),
|
||||||
|
mockImports: dtoMockImports,
|
||||||
|
vars: dtoMockVarsMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
renderTemplate(
|
||||||
|
templatesDir,
|
||||||
|
'dto.mock.mustache',
|
||||||
|
dtoMockViewData,
|
||||||
|
path.join(outputDir, 'data/dtos', `${toCamelCase(baseName)}.dto.mock.ts`),
|
||||||
|
generatedCount,
|
||||||
|
'mocks'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Model mock — delegates to mapper + DTO mock (no property values needed)
|
||||||
|
renderTemplate(
|
||||||
|
templatesDir,
|
||||||
|
'model.mock.mustache',
|
||||||
|
modelViewData,
|
||||||
|
path.join(outputDir, 'entities/models', `${toCamelCase(baseName)}.model.mock.ts`),
|
||||||
|
generatedCount,
|
||||||
|
'mocks'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. Generate Use Cases and Repositories from Paths/Tags
|
// 2. Generate Use Cases and Repositories from Paths/Tags
|
||||||
@@ -357,10 +401,47 @@ export function generateCleanArchitecture(
|
|||||||
generatedCount,
|
generatedCount,
|
||||||
'providers'
|
'providers'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Mocks — repository impl, use-cases impl, repository provider, use-cases provider
|
||||||
|
renderTemplate(
|
||||||
|
templatesDir,
|
||||||
|
'api.repository.impl.mock.mustache',
|
||||||
|
apiViewData,
|
||||||
|
path.join(outputDir, 'data/repositories', `${toCamelCase(tag)}.repository.impl.mock.ts`),
|
||||||
|
generatedCount,
|
||||||
|
'mocks'
|
||||||
|
);
|
||||||
|
|
||||||
|
renderTemplate(
|
||||||
|
templatesDir,
|
||||||
|
'api.use-cases.mock.mustache',
|
||||||
|
apiViewData,
|
||||||
|
path.join(outputDir, 'domain/use-cases', `${toCamelCase(tag)}.use-cases.mock.ts`),
|
||||||
|
generatedCount,
|
||||||
|
'mocks'
|
||||||
|
);
|
||||||
|
|
||||||
|
renderTemplate(
|
||||||
|
templatesDir,
|
||||||
|
'repository.provider.mock.mustache',
|
||||||
|
apiViewData,
|
||||||
|
path.join(outputDir, 'di/repositories', `${toCamelCase(tag)}.repository.provider.mock.ts`),
|
||||||
|
generatedCount,
|
||||||
|
'mocks'
|
||||||
|
);
|
||||||
|
|
||||||
|
renderTemplate(
|
||||||
|
templatesDir,
|
||||||
|
'use-cases.provider.mock.mustache',
|
||||||
|
apiViewData,
|
||||||
|
path.join(outputDir, 'di/use-cases', `${toCamelCase(tag)}.use-cases.provider.mock.ts`),
|
||||||
|
generatedCount,
|
||||||
|
'mocks'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
logSuccess(
|
logSuccess(
|
||||||
`${generatedCount.models} Models, ${generatedCount.repositories} Repos, ${generatedCount.useCases} Use Cases, ${generatedCount.mappers} Mappers, ${generatedCount.providers} Providers generados con Mustache`
|
`${generatedCount.models} Models, ${generatedCount.repositories} Repos, ${generatedCount.useCases} Use Cases, ${generatedCount.mappers} Mappers, ${generatedCount.providers} Providers, ${generatedCount.mocks} Mocks generated`
|
||||||
);
|
);
|
||||||
return generatedCount;
|
return generatedCount;
|
||||||
}
|
}
|
||||||
|
|||||||
106
src/generators/lint.generator.ts
Normal file
106
src/generators/lint.generator.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import fs from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import { spawnSync } from 'child_process';
|
||||||
|
import { logStep, logSuccess, logWarning, logInfo } from '../utils/logger';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walks up the directory tree from `startDir` to find the nearest
|
||||||
|
* directory containing a `package.json` (i.e. the project root).
|
||||||
|
* Returns `null` if none is found before reaching the filesystem root.
|
||||||
|
*/
|
||||||
|
function findProjectRoot(startDir: string): string | null {
|
||||||
|
let current = path.resolve(startDir);
|
||||||
|
while (true) {
|
||||||
|
if (fs.existsSync(path.join(current, 'package.json'))) return current;
|
||||||
|
const parent = path.dirname(current);
|
||||||
|
if (parent === current) return null;
|
||||||
|
current = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects all `.ts` files recursively inside a directory.
|
||||||
|
*/
|
||||||
|
function collectTsFiles(dir: string): string[] {
|
||||||
|
if (!fs.existsSync(dir)) return [];
|
||||||
|
const results: string[] = [];
|
||||||
|
fs.readdirSync(dir).forEach((entry) => {
|
||||||
|
const full = path.join(dir, entry);
|
||||||
|
if (fs.statSync(full).isDirectory()) {
|
||||||
|
results.push(...collectTsFiles(full));
|
||||||
|
} else if (entry.endsWith('.ts')) {
|
||||||
|
results.push(full);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a command synchronously and returns whether it succeeded.
|
||||||
|
* Prints stdout/stderr to the console only on failure.
|
||||||
|
*/
|
||||||
|
function run(cmd: string, args: string[], cwd: string): boolean {
|
||||||
|
const result = spawnSync(cmd, args, { cwd, encoding: 'utf8', shell: true });
|
||||||
|
if (result.status !== 0) {
|
||||||
|
if (result.stderr) process.stderr.write(result.stderr);
|
||||||
|
if (result.stdout) process.stdout.write(result.stdout);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs Prettier and ESLint (--fix) on all generated `.ts` files inside `outputDir`.
|
||||||
|
* Both tools are looked up via `npx` in the nearest project root so that the
|
||||||
|
* target Angular project's own configuration and plugins are used.
|
||||||
|
*
|
||||||
|
* - Prettier: always attempted; logs a warning if not found.
|
||||||
|
* - ESLint: optional; silently skipped if no config is found in the project root.
|
||||||
|
*/
|
||||||
|
export function lintGeneratedFiles(outputDir: string): void {
|
||||||
|
logStep('Linting generated files...');
|
||||||
|
|
||||||
|
const projectRoot = findProjectRoot(outputDir);
|
||||||
|
if (!projectRoot) {
|
||||||
|
logWarning('Could not locate a project root (package.json). Skipping lint.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logInfo(` Project root: ${projectRoot}`);
|
||||||
|
|
||||||
|
const files = collectTsFiles(outputDir);
|
||||||
|
if (files.length === 0) {
|
||||||
|
logWarning('No TypeScript files found in output directory. Skipping lint.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const relativePaths = files.map((f) => path.relative(projectRoot, f));
|
||||||
|
|
||||||
|
// --- Prettier ---
|
||||||
|
const prettierOk = run('npx', ['prettier', '--write', ...relativePaths], projectRoot);
|
||||||
|
if (prettierOk) {
|
||||||
|
logSuccess(`Prettier formatted ${files.length} files`);
|
||||||
|
} else {
|
||||||
|
logWarning('Prettier not available or encountered errors. Skipping formatting.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- ESLint (only if a config exists in the project root) ---
|
||||||
|
const hasEslintConfig =
|
||||||
|
fs.existsSync(path.join(projectRoot, 'eslint.config.js')) ||
|
||||||
|
fs.existsSync(path.join(projectRoot, 'eslint.config.mjs')) ||
|
||||||
|
fs.existsSync(path.join(projectRoot, '.eslintrc.js')) ||
|
||||||
|
fs.existsSync(path.join(projectRoot, '.eslintrc.json')) ||
|
||||||
|
fs.existsSync(path.join(projectRoot, '.eslintrc.yml')) ||
|
||||||
|
fs.existsSync(path.join(projectRoot, '.eslintrc.yaml'));
|
||||||
|
|
||||||
|
if (!hasEslintConfig) {
|
||||||
|
logWarning('No ESLint config found in project root. Skipping ESLint fix.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const eslintOk = run('npx', ['eslint', '--fix', ...relativePaths], projectRoot);
|
||||||
|
if (eslintOk) {
|
||||||
|
logSuccess(`ESLint fixed ${files.length} files`);
|
||||||
|
} else {
|
||||||
|
logWarning('ESLint reported errors that could not be auto-fixed. Review the output above.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,15 @@ import path from 'path';
|
|||||||
import { logStep, logSuccess } from '../utils/logger';
|
import { logStep, logSuccess } from '../utils/logger';
|
||||||
import type { SwaggerAnalysis, GenerationReport } from '../types';
|
import type { SwaggerAnalysis, GenerationReport } from '../types';
|
||||||
|
|
||||||
|
/** Counts files ending with `.mock.ts` in a directory (returns 0 if directory does not exist). */
|
||||||
|
function countMockFiles(dir: string): number {
|
||||||
|
try {
|
||||||
|
return fs.readdirSync(dir).filter((f) => f.endsWith('.mock.ts')).length;
|
||||||
|
} catch {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Generates and persists the `generation-report.json` file with process statistics. */
|
/** Generates and persists the `generation-report.json` file with process statistics. */
|
||||||
export function generateReport(outputDir: string, analysis: SwaggerAnalysis): GenerationReport {
|
export function generateReport(outputDir: string, analysis: SwaggerAnalysis): GenerationReport {
|
||||||
logStep('Generating report...');
|
logStep('Generating report...');
|
||||||
@@ -19,7 +28,14 @@ export function generateReport(outputDir: string, analysis: SwaggerAnalysis): Ge
|
|||||||
useCases: fs.readdirSync(path.join(outputDir, 'domain/use-cases')).length,
|
useCases: fs.readdirSync(path.join(outputDir, 'domain/use-cases')).length,
|
||||||
providers:
|
providers:
|
||||||
fs.readdirSync(path.join(outputDir, 'di/repositories')).length +
|
fs.readdirSync(path.join(outputDir, 'di/repositories')).length +
|
||||||
fs.readdirSync(path.join(outputDir, 'di/use-cases')).length
|
fs.readdirSync(path.join(outputDir, 'di/use-cases')).length,
|
||||||
|
mocks:
|
||||||
|
countMockFiles(path.join(outputDir, 'data/dtos')) +
|
||||||
|
countMockFiles(path.join(outputDir, 'data/repositories')) +
|
||||||
|
countMockFiles(path.join(outputDir, 'di/repositories')) +
|
||||||
|
countMockFiles(path.join(outputDir, 'di/use-cases')) +
|
||||||
|
countMockFiles(path.join(outputDir, 'domain/use-cases')) +
|
||||||
|
countMockFiles(path.join(outputDir, 'entities/models'))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,4 +9,5 @@ export interface CliOptions {
|
|||||||
skipInstall?: boolean;
|
skipInstall?: boolean;
|
||||||
dryRun?: boolean;
|
dryRun?: boolean;
|
||||||
selectEndpoints?: boolean;
|
selectEndpoints?: boolean;
|
||||||
|
skipLint?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface GeneratedCount {
|
|||||||
mappers: number;
|
mappers: number;
|
||||||
useCases: number;
|
useCases: number;
|
||||||
providers: number;
|
providers: number;
|
||||||
|
mocks: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,5 +24,6 @@ export interface GenerationReport {
|
|||||||
mappers: number;
|
mappers: number;
|
||||||
useCases: number;
|
useCases: number;
|
||||||
providers: number;
|
providers: number;
|
||||||
|
mocks: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,9 +30,12 @@ export interface OpenApiSchema {
|
|||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
type?: string;
|
type?: string;
|
||||||
|
format?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
example?: unknown;
|
||||||
|
enum?: unknown[];
|
||||||
$ref?: string;
|
$ref?: string;
|
||||||
items?: { $ref?: string };
|
items?: { $ref?: string; type?: string };
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
required?: string[];
|
required?: string[];
|
||||||
|
|||||||
70
src/utils/mock-value-resolver.ts
Normal file
70
src/utils/mock-value-resolver.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* Resolves a TypeScript literal string to use as a mock value for a single schema property.
|
||||||
|
*
|
||||||
|
* Priority chain:
|
||||||
|
* $ref mock call → array $ref mock call → enum[0] → example → format fallback → type default
|
||||||
|
*
|
||||||
|
* @param propName Property name (used for format heuristics such as "email").
|
||||||
|
* @param prop Raw OpenAPI property definition.
|
||||||
|
* @param context 'dto' generates `mockFooDto()`, 'model' generates `mockFooModel()`.
|
||||||
|
*/
|
||||||
|
export function resolveMockValue(
|
||||||
|
propName: string,
|
||||||
|
prop: {
|
||||||
|
type?: string;
|
||||||
|
format?: string;
|
||||||
|
example?: unknown;
|
||||||
|
enum?: unknown[];
|
||||||
|
$ref?: string;
|
||||||
|
items?: { $ref?: string; type?: string };
|
||||||
|
},
|
||||||
|
context: 'dto' | 'model' = 'dto'
|
||||||
|
): string {
|
||||||
|
const suffix = context === 'dto' ? 'Dto' : 'Model';
|
||||||
|
|
||||||
|
// 1. Direct $ref → call the referenced mock factory
|
||||||
|
if (prop.$ref) {
|
||||||
|
const refName = prop.$ref.split('/').pop()!;
|
||||||
|
return `mock${refName}${suffix}()`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Array of $ref → wrap referenced mock in an array
|
||||||
|
if (prop.type === 'array' && prop.items?.$ref) {
|
||||||
|
const refName = prop.items.$ref.split('/').pop()!;
|
||||||
|
return `[mock${refName}${suffix}()]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Array of primitives
|
||||||
|
if (prop.type === 'array') return '[]';
|
||||||
|
|
||||||
|
// 4. Enum → first declared value
|
||||||
|
if (prop.enum?.length) {
|
||||||
|
const first = prop.enum[0];
|
||||||
|
return typeof first === 'string' ? `'${first}'` : String(first);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Example value from the swagger spec (highest fidelity)
|
||||||
|
if (prop.example !== undefined) return formatLiteral(prop.example);
|
||||||
|
|
||||||
|
// 6. Format-aware fallbacks (when no example is provided)
|
||||||
|
if (prop.format === 'date-time') return `'2024-01-01T00:00:00.000Z'`;
|
||||||
|
if (prop.format === 'date') return `'2024-01-01'`;
|
||||||
|
if (prop.format === 'uuid') return `'00000000-0000-0000-0000-000000000000'`;
|
||||||
|
if (prop.format === 'uri') return `'https://example.com'`;
|
||||||
|
if (prop.format === 'email' || propName.toLowerCase().includes('email'))
|
||||||
|
return `'user@example.com'`;
|
||||||
|
|
||||||
|
// 7. Type defaults
|
||||||
|
if (prop.type === 'string') return `'value'`;
|
||||||
|
if (prop.type === 'integer' || prop.type === 'number') return `0`;
|
||||||
|
if (prop.type === 'boolean') return `false`;
|
||||||
|
|
||||||
|
return 'undefined';
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatLiteral(value: unknown): string {
|
||||||
|
if (typeof value === 'string') return `'${value}'`;
|
||||||
|
if (typeof value === 'number') return `${value}`;
|
||||||
|
if (typeof value === 'boolean') return `${value}`;
|
||||||
|
return `'${String(value)}'`;
|
||||||
|
}
|
||||||
21
templates/api.repository.impl.mock.mustache
Normal file
21
templates/api.repository.impl.mock.mustache
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
{{#operations}}
|
||||||
|
import { MockService } from 'ng-mocks';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
|
import { {{classname}}RepositoryImpl } from '@/data/repositories/{{classFilename}}.repository.impl';
|
||||||
|
{{#returnImports}}
|
||||||
|
import { mock{{classname}}Model } from '@/entities/models/{{classFilename}}.model.mock';
|
||||||
|
{{/returnImports}}
|
||||||
|
|
||||||
|
export const mock{{classname}}RepositoryImpl = () =>
|
||||||
|
MockService({{classname}}RepositoryImpl, {
|
||||||
|
{{#operation}}
|
||||||
|
{{nickname}}: () => of({{#isListContainer}}[mock{{returnBaseType}}Model()]{{/isListContainer}}{{^isListContainer}}{{#returnBaseType}}mock{{returnBaseType}}Model(){{/returnBaseType}}{{^returnBaseType}}undefined{{/returnBaseType}}{{/isListContainer}}),
|
||||||
|
{{/operation}}
|
||||||
|
});
|
||||||
|
|
||||||
|
{{/operations}}
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
21
templates/api.use-cases.mock.mustache
Normal file
21
templates/api.use-cases.mock.mustache
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
{{#operations}}
|
||||||
|
import { MockService } from 'ng-mocks';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
|
import { {{classname}}UseCasesImpl } from '@/domain/use-cases/{{classFilename}}.use-cases.impl';
|
||||||
|
{{#returnImports}}
|
||||||
|
import { mock{{classname}}Model } from '@/entities/models/{{classFilename}}.model.mock';
|
||||||
|
{{/returnImports}}
|
||||||
|
|
||||||
|
export const mock{{classname}}UseCasesImpl = () =>
|
||||||
|
MockService({{classname}}UseCasesImpl, {
|
||||||
|
{{#operation}}
|
||||||
|
{{nickname}}: () => of({{#isListContainer}}[mock{{returnBaseType}}Model()]{{/isListContainer}}{{^isListContainer}}{{#returnBaseType}}mock{{returnBaseType}}Model(){{/returnBaseType}}{{^returnBaseType}}undefined{{/returnBaseType}}{{/isListContainer}}),
|
||||||
|
{{/operation}}
|
||||||
|
});
|
||||||
|
|
||||||
|
{{/operations}}
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
16
templates/dto.mock.mustache
Normal file
16
templates/dto.mock.mustache
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{{#models}}
|
||||||
|
{{#model}}
|
||||||
|
{{#mockImports}}
|
||||||
|
import { mock{{classname}}Dto } from './{{classFilename}}.dto.mock';
|
||||||
|
{{/mockImports}}
|
||||||
|
import { {{classname}}Dto } from './{{classFilename}}.dto';
|
||||||
|
|
||||||
|
export const mock{{classname}}Dto = (overrides: Partial<{{classname}}Dto> = {}): {{classname}}Dto => ({
|
||||||
|
{{#vars}}
|
||||||
|
{{name}}: {{{mockValue}}},
|
||||||
|
{{/vars}}
|
||||||
|
...overrides
|
||||||
|
});
|
||||||
|
|
||||||
|
{{/model}}
|
||||||
|
{{/models}}
|
||||||
@@ -16,7 +16,7 @@ export class {{classname}} {
|
|||||||
* {{description}}
|
* {{description}}
|
||||||
*/
|
*/
|
||||||
{{/description}}
|
{{/description}}
|
||||||
{{name}}{{^required}}?{{/required}}: {{{dataType}}};
|
{{name}}{{^required}}?{{/required}}{{#required}}!{{/required}}: {{{dataType}}};
|
||||||
{{/vars}}
|
{{/vars}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
templates/model.mock.mustache
Normal file
14
templates/model.mock.mustache
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{{#models}}
|
||||||
|
{{#model}}
|
||||||
|
import { {{classname}} } from './{{classFilename}}.model';
|
||||||
|
import { {{classVarName}}Mapper } from '@/mappers/{{classFilename}}.mapper';
|
||||||
|
import { mock{{classname}}Dto } from '@/dtos/{{classFilename}}.dto.mock';
|
||||||
|
|
||||||
|
export const mock{{classname}}Model = (overrides: Partial<{{classname}}> = {}): {{classname}} =>
|
||||||
|
Object.assign(new {{classname}}(), {
|
||||||
|
...{{classVarName}}Mapper(mock{{classname}}Dto()),
|
||||||
|
...overrides
|
||||||
|
});
|
||||||
|
|
||||||
|
{{/model}}
|
||||||
|
{{/models}}
|
||||||
20
templates/repository.provider.mock.mustache
Normal file
20
templates/repository.provider.mock.mustache
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
{{#operations}}
|
||||||
|
import { Provider } from '@angular/core';
|
||||||
|
|
||||||
|
import { {{constantName}}_REPOSITORY } from '@/domain/repositories/{{classFilename}}.repository.contract';
|
||||||
|
import { mock{{classname}}RepositoryImpl } from '@/data/repositories/{{classFilename}}.repository.impl.mock';
|
||||||
|
|
||||||
|
export function mock{{classname}}Repository(): Provider[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
provide: {{constantName}}_REPOSITORY,
|
||||||
|
useFactory: () => mock{{classname}}RepositoryImpl()
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
{{/operations}}
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
20
templates/use-cases.provider.mock.mustache
Normal file
20
templates/use-cases.provider.mock.mustache
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
{{#operations}}
|
||||||
|
import { Provider } from '@angular/core';
|
||||||
|
|
||||||
|
import { {{constantName}}_USE_CASES } from '@/domain/use-cases/{{classFilename}}.use-cases.contract';
|
||||||
|
import { mock{{classname}}UseCasesImpl } from '@/domain/use-cases/{{classFilename}}.use-cases.mock';
|
||||||
|
|
||||||
|
export function mock{{classname}}UseCases(): Provider[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
provide: {{constantName}}_USE_CASES,
|
||||||
|
useFactory: () => mock{{classname}}UseCasesImpl()
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
{{/operations}}
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
Reference in New Issue
Block a user