e2e интеграционные тесты
This commit is contained in:
@@ -15,6 +15,7 @@ program
|
||||
.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)')
|
||||
.option('--swr', 'Generate SWR hooks for React')
|
||||
.action(async (options) => {
|
||||
try {
|
||||
// Создание конфигурации
|
||||
@@ -22,6 +23,7 @@ program
|
||||
inputPath: options.input,
|
||||
outputPath: options.output,
|
||||
fileName: options.name,
|
||||
useSwr: options.swr || false,
|
||||
};
|
||||
|
||||
// Валидация конфигурации
|
||||
@@ -38,7 +40,7 @@ program
|
||||
// Генерация API
|
||||
await generate(config as GeneratorConfig);
|
||||
|
||||
console.log(chalk.green('\n✨ Done!\n'));
|
||||
console.log(chalk.green('\n✨ API client generated successfully!\n'));
|
||||
} catch (error) {
|
||||
console.error(chalk.red('\n❌ Error:'), error instanceof Error ? error.message : error);
|
||||
console.error();
|
||||
|
||||
@@ -8,6 +8,8 @@ export interface GeneratorConfig {
|
||||
outputPath: string;
|
||||
/** Имя сгенерированного файла (без расширения) */
|
||||
fileName?: string;
|
||||
/** Генерировать SWR hooks для React */
|
||||
useSwr?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,25 +18,34 @@ export async function generate(config: GeneratorConfig): Promise<void> {
|
||||
// Путь к кастомным шаблонам
|
||||
const templatesPath = resolve(__dirname, '../src/templates');
|
||||
|
||||
|
||||
// Читаем OpenAPI спецификацию
|
||||
const inputPath = config.inputPath.startsWith('http://') || config.inputPath.startsWith('https://')
|
||||
? config.inputPath
|
||||
: resolve(config.inputPath);
|
||||
const spec = await readJsonFile<any>(inputPath);
|
||||
// Проверяем тип входного пути
|
||||
const isUrl = config.inputPath.startsWith('http://') || config.inputPath.startsWith('https://');
|
||||
|
||||
// Для локальных файлов читаем спецификацию
|
||||
let spec: any = null;
|
||||
let inputPath: string | undefined = undefined;
|
||||
let url: string | undefined = undefined;
|
||||
|
||||
if (isUrl) {
|
||||
url = config.inputPath;
|
||||
// Для URL не читаем спецификацию заранее, swagger-typescript-api сделает это сам
|
||||
} else {
|
||||
inputPath = resolve(config.inputPath);
|
||||
spec = await readJsonFile<any>(inputPath);
|
||||
}
|
||||
|
||||
// Определяем имя файла
|
||||
let fileName = config.fileName;
|
||||
if (!fileName) {
|
||||
// Пытаемся получить имя из OpenAPI спецификации
|
||||
fileName = spec.info?.title
|
||||
fileName = spec?.info?.title
|
||||
? spec.info.title.replace(/[^a-zA-Z0-9]/g, '')
|
||||
: 'Api';
|
||||
}
|
||||
|
||||
try {
|
||||
await swaggerGenerateApi({
|
||||
input: inputPath,
|
||||
...(isUrl ? { url } : { input: inputPath }),
|
||||
output: resolve(config.outputPath),
|
||||
fileName: `${fileName}.ts`,
|
||||
httpClientType: 'fetch',
|
||||
@@ -60,7 +69,7 @@ export async function generate(config: GeneratorConfig): Promise<void> {
|
||||
sortRoutes: false,
|
||||
extractResponseError: false,
|
||||
fixInvalidEnumKeyPrefix: 'KEY',
|
||||
silent: false,
|
||||
silent: true,
|
||||
defaultResponseType: 'void',
|
||||
typePrefix: '',
|
||||
typeSuffix: '',
|
||||
@@ -90,18 +99,18 @@ export async function generate(config: GeneratorConfig): Promise<void> {
|
||||
},
|
||||
onInit: (configuration) => {
|
||||
// Получаем дефолтный baseUrl из OpenAPI спецификации
|
||||
const defaultBaseUrl = spec.servers?.[0]?.url || '';
|
||||
const apiConfig = (configuration as any).apiConfig || {};
|
||||
const defaultBaseUrl = spec?.servers?.[0]?.url || apiConfig.baseUrl || '';
|
||||
(configuration as any).apiConfig = (configuration as any).apiConfig || {};
|
||||
(configuration as any).apiConfig.baseUrl = defaultBaseUrl;
|
||||
// Передаем флаг useSwr в шаблоны
|
||||
(configuration as any).useSwr = config.useSwr || false;
|
||||
return configuration;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Generated files in ${config.outputPath}:`);
|
||||
console.log(` - ${fileName}.ts (API endpoints)`);
|
||||
console.log(' - http-client.ts (HTTP client)');
|
||||
console.log(' - data-contracts.ts (TypeScript types)');
|
||||
// Генерация успешна
|
||||
} catch (error) {
|
||||
console.error('❌ Generation failed:', error);
|
||||
throw error;
|
||||
|
||||
@@ -26,8 +26,9 @@ const descriptionLines = _.compact([
|
||||
|
||||
%>
|
||||
|
||||
<% if (config.useSwr) { %>
|
||||
import useSWR from "swr";
|
||||
import { fetcher } from "./http-client";
|
||||
<% } %>
|
||||
|
||||
<% if (config.httpClientType === config.constants.HTTP_CLIENT.AXIOS) { %> import type { AxiosRequestConfig, AxiosResponse } from "axios"; <% } %>
|
||||
|
||||
@@ -44,8 +45,8 @@ export class <%~ config.apiClassName %><SecurityDataType extends unknown><% if (
|
||||
<% if(config.singleHttpClient) { %>
|
||||
http: HttpClient<SecurityDataType>;
|
||||
|
||||
constructor (http: HttpClient<SecurityDataType>) {
|
||||
this.http = http;
|
||||
constructor (http?: HttpClient<SecurityDataType>) {
|
||||
this.http = http || new HttpClient<SecurityDataType>();
|
||||
}
|
||||
<% } %>
|
||||
|
||||
|
||||
@@ -102,9 +102,9 @@ const isValidIdentifier = (name) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
||||
...<%~ _.get(requestConfigParam, "name") %>,
|
||||
})<%~ route.namespace ? ',' : '' %>
|
||||
<%
|
||||
// Генерируем use* функцию для GET запросов
|
||||
// Генерируем use* функцию для GET запросов (только если включен флаг useSwr)
|
||||
const isGetRequest = _.upperCase(method) === 'GET';
|
||||
if (isGetRequest) {
|
||||
if (config.useSwr && isGetRequest) {
|
||||
const useMethodName = 'use' + _.upperFirst(route.routeName.usage);
|
||||
const argsWithoutParams = rawWrapperArgs.filter(arg => arg.name !== requestConfigParam.name);
|
||||
const useWrapperArgs = _
|
||||
|
||||
Reference in New Issue
Block a user