feat: автоматическое определение baseUrl, добавлена документация проекта
This commit is contained in:
@@ -12,7 +12,6 @@ program
|
||||
.name('api-codegen')
|
||||
.description('Generate TypeScript API client from OpenAPI specification')
|
||||
.version('1.0.0')
|
||||
.requiredOption('-u, --url <url>', 'Base API URL (e.g., https://api.example.com)')
|
||||
.requiredOption('-i, --input <path>', 'Path to OpenAPI specification file (JSON or YAML)')
|
||||
.requiredOption('-o, --output <path>', 'Output directory for generated files')
|
||||
.option('-n, --name <name>', 'Name of generated file (without extension)')
|
||||
@@ -20,7 +19,6 @@ program
|
||||
try {
|
||||
// Создание конфигурации
|
||||
const config: Partial<GeneratorConfig> = {
|
||||
apiUrl: options.url,
|
||||
inputPath: options.input,
|
||||
outputPath: options.output,
|
||||
fileName: options.name,
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
* Конфигурация генератора API
|
||||
*/
|
||||
export interface GeneratorConfig {
|
||||
/** Базовый URL API */
|
||||
apiUrl: string;
|
||||
/** Путь к файлу OpenAPI спецификации */
|
||||
inputPath: string;
|
||||
/** Путь для сохранения сгенерированных файлов */
|
||||
@@ -18,12 +16,6 @@ export interface GeneratorConfig {
|
||||
export function validateConfig(config: Partial<GeneratorConfig>): config is GeneratorConfig {
|
||||
const errors: string[] = [];
|
||||
|
||||
if (!config.apiUrl) {
|
||||
errors.push('API URL is required (--url)');
|
||||
} else if (!isValidUrl(config.apiUrl)) {
|
||||
errors.push('API URL must be a valid URL');
|
||||
}
|
||||
|
||||
if (!config.inputPath) {
|
||||
errors.push('Input path is required (--input)');
|
||||
}
|
||||
@@ -39,15 +31,3 @@ export function validateConfig(config: Partial<GeneratorConfig>): config is Gene
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверка валидности URL
|
||||
*/
|
||||
function isValidUrl(url: string): boolean {
|
||||
try {
|
||||
new URL(url);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { generateApi as swaggerGenerateApi } from 'swagger-typescript-api';
|
||||
import { resolve, join } from 'path';
|
||||
import { resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'path';
|
||||
import { unlink } from 'fs/promises';
|
||||
import type { GeneratorConfig } from './config.js';
|
||||
import { ensureDir, readJsonFile, writeFileWithDirs } from './utils/file.js';
|
||||
import { ensureDir, readJsonFile } from './utils/file.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
@@ -20,7 +19,7 @@ export async function generate(config: GeneratorConfig): Promise<void> {
|
||||
const templatesPath = resolve(__dirname, '../src/templates');
|
||||
|
||||
|
||||
// Читаем и модифицируем OpenAPI спецификацию
|
||||
// Читаем OpenAPI спецификацию
|
||||
const inputPath = config.inputPath.startsWith('http://') || config.inputPath.startsWith('https://')
|
||||
? config.inputPath
|
||||
: resolve(config.inputPath);
|
||||
@@ -34,17 +33,10 @@ export async function generate(config: GeneratorConfig): Promise<void> {
|
||||
? spec.info.title.replace(/[^a-zA-Z0-9]/g, '')
|
||||
: 'Api';
|
||||
}
|
||||
|
||||
// Добавляем или обновляем servers с baseUrl
|
||||
spec.servers = [{ url: config.apiUrl }];
|
||||
|
||||
// Сохраняем модифицированную спецификацию во временный файл
|
||||
const tempSpecPath = join(config.outputPath, '.openapi-temp.json');
|
||||
await writeFileWithDirs(tempSpecPath, JSON.stringify(spec, null, 2));
|
||||
|
||||
try {
|
||||
await swaggerGenerateApi({
|
||||
input: tempSpecPath,
|
||||
input: inputPath,
|
||||
output: resolve(config.outputPath),
|
||||
fileName: `${fileName}.ts`,
|
||||
httpClientType: 'fetch',
|
||||
@@ -96,10 +88,11 @@ export async function generate(config: GeneratorConfig): Promise<void> {
|
||||
|
||||
return templateRouteName;
|
||||
},
|
||||
onInit: (configuration, codeGenProcess) => {
|
||||
// Передаём baseUrl в конфигурацию для шаблонов
|
||||
onInit: (configuration) => {
|
||||
// Получаем дефолтный baseUrl из OpenAPI спецификации
|
||||
const defaultBaseUrl = spec.servers?.[0]?.url || '';
|
||||
(configuration as any).apiConfig = (configuration as any).apiConfig || {};
|
||||
(configuration as any).apiConfig.baseUrl = config.apiUrl;
|
||||
(configuration as any).apiConfig.baseUrl = defaultBaseUrl;
|
||||
return configuration;
|
||||
},
|
||||
},
|
||||
@@ -109,21 +102,8 @@ export async function generate(config: GeneratorConfig): Promise<void> {
|
||||
console.log(` - ${fileName}.ts (API endpoints)`);
|
||||
console.log(' - http-client.ts (HTTP client)');
|
||||
console.log(' - data-contracts.ts (TypeScript types)');
|
||||
|
||||
// Удаляем временный файл
|
||||
try {
|
||||
await unlink(tempSpecPath);
|
||||
} catch (e) {
|
||||
// Игнорируем ошибки удаления
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Generation failed:', error);
|
||||
// Удаляем временный файл даже при ошибке
|
||||
try {
|
||||
await unlink(tempSpecPath);
|
||||
} catch (e) {
|
||||
// Игнорируем ошибки удаления
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user