Files
datacat/back/src/modules/docs-generation/docs-generation.service.ts
z3n 1adb6820dd refactor: fix bugs et réduire duplication + extraire modales BrowseComponent
- fix(dto): ajouter @IsEmail() sur contactFunctionalEmail/TechnicalEmail dans UpdateApiEntryDto
- fix(docs): corriger stringify des erreurs (String(error) → error.message)
- refactor(mapper): extraire toApiEntryListItem() dans api-entry.mapper.ts partagé
- refactor(categories): supprimer CONVENTION_LABELS et toApiEntryListItem locaux dupliqués
- refactor(browse): extraire CategoryFormModalComponent et CategoryDeleteModalComponent
- refactor(api-detail): convertir editPreviewTitle() en computed()

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-06-11 15:10:38 +00:00

69 lines
2.4 KiB
TypeScript

import { Injectable, Inject, forwardRef } from '@nestjs/common';
import { execFile } from 'child_process';
import { promisify } from 'util';
import * as fs from 'fs/promises';
import * as path from 'path';
// eslint-disable-next-line @typescript-eslint/no-require-imports
const AsyncApiGenerator = require('@asyncapi/generator');
import { ApisService } from '../apis/apis.service';
const execFileAsync = promisify(execFile);
/* Ajoute node_modules/.bin au PATH pour trouver redocly en local */
const localBin = path.join(process.cwd(), 'node_modules', '.bin');
const execEnv = {
...process.env,
PATH: `${localBin}${path.delimiter}${process.env.PATH ?? ''}`,
};
@Injectable()
export class DocsGenerationService {
private readonly outputDir = process.env.DOCS_OUTPUT_DIR ?? './docs-output';
constructor(
@Inject(forwardRef(() => ApisService))
private readonly apisService: ApisService,
) {}
async generate(entryId: string): Promise<void> {
const entry = await this.apisService.findOneOrThrow(entryId);
const entryDir = path.join(this.outputDir, entryId);
await fs.mkdir(entryDir, { recursive: true });
const yamlPath = path.join(entryDir, 'input.yaml');
await fs.writeFile(yamlPath, entry.yamlContent, 'utf-8');
try {
if (entry.type === 'ASYNCAPI') {
await this.generateAsyncApi(yamlPath, entryDir);
} else {
await this.generateOpenApi(yamlPath, entryDir);
}
const htmlPath = path.join(entryDir, 'index.html');
await this.apisService.updateInternal(entryId, { htmlPath, status: 'GENERATED' });
} catch (error) {
await this.apisService.updateInternal(entryId, {
status: 'ERROR',
errorMessage: error instanceof Error ? error.message : String(error),
});
}
}
private async generateAsyncApi(yamlPath: string, outputDir: string): Promise<void> {
/* API programmatique — aucun appel réseau, template résolu localement */
const templatePath = path.join(process.cwd(), 'node_modules', '@asyncapi', 'html-template');
const generator = new AsyncApiGenerator(templatePath, outputDir, { forceWrite: true });
await generator.generateFromFile(yamlPath);
}
private async generateOpenApi(yamlPath: string, outputDir: string): Promise<void> {
await execFileAsync('redocly', [
'build-docs',
yamlPath,
'--output', path.join(outputDir, 'index.html'),
], { shell: true, env: execEnv });
}
}