feat: сделать split-клиент режимом по умолчанию

- добавлен operationsTree для сборки полного клиента
- удален режим генерации both
- обновлена документация под npm SDK workflow
- поднята версия пакета до 4.0.0
This commit is contained in:
2026-06-30 10:46:15 +03:00
parent bf340b3dbe
commit fe5d3ae091
9 changed files with 445 additions and 109 deletions

View File

@@ -21,7 +21,7 @@ describe('Generator', () => {
});
describe('корректная генерация', () => {
test('должен создать выходной файл', async () => {
test('должен по умолчанию создать split структуру', async () => {
const outputPath = join(tempDir, 'output');
const config: GeneratorConfig = {
inputPath: FIXTURES.MINIMAL,
@@ -31,9 +31,10 @@ describe('Generator', () => {
await generate(config);
const generatedFile = join(outputPath, 'TestApi.ts');
const exists = await fileExists(generatedFile);
expect(exists).toBe(true);
expect(await fileExists(join(outputPath, 'index.ts'))).toBe(true);
expect(await fileExists(join(outputPath, 'http-client.ts'))).toBe(true);
expect(await fileExists(join(outputPath, 'operations-tree.ts'))).toBe(true);
expect(await fileExists(join(outputPath, 'operations', 'index.ts'))).toBe(true);
}, 30000);
test('должен добавлять русскую подпись в generated файлы', async () => {
@@ -42,6 +43,7 @@ describe('Generator', () => {
inputPath: FIXTURES.MINIMAL,
outputPath,
fileName: 'TestApi',
mode: 'single',
};
await generate(config);
@@ -91,12 +93,77 @@ describe('Generator', () => {
const indexFile = join(outputPath, 'index.ts');
const httpClientFile = join(outputPath, 'http-client.ts');
const operationsTreeFile = join(outputPath, 'operations-tree.ts');
const indexContent = await readTextFile(indexFile);
const httpClientContent = await readTextFile(httpClientFile);
const operationsTreeContent = await readTextFile(operationsTreeFile);
// Проверяем наличие основных элементов
expect(indexContent).toContain('createApiClient');
expect(indexContent).toContain('export { operationsTree } from "./operations-tree"');
expect(indexContent).toContain('export type { OperationsTree } from "./operations-tree"');
expect(indexContent).toContain('export * as operations from "./operations"');
expect(httpClientContent).toContain('export class HttpClient');
expect(operationsTreeContent).toContain('export const operationsTree');
expect(operationsTreeContent).toContain('export type OperationsTree');
}, 30000);
test('должен генерировать operationsTree с группировкой по тегам', async () => {
const inputPath = join(tempDir, 'tagged.json');
const outputPath = join(tempDir, 'output');
await Bun.write(inputPath, JSON.stringify({
openapi: '3.0.0',
info: {
title: 'Tagged API',
version: '1.0.0',
},
paths: {
'/users': {
get: {
tags: ['users'],
operationId: 'UserController_getAll',
responses: {
200: { description: 'OK' },
},
},
post: {
tags: ['users'],
operationId: 'UserController_create',
responses: {
201: { description: 'Created' },
},
},
},
'/auth/login': {
post: {
tags: ['auth'],
operationId: 'AuthController_login',
responses: {
200: { description: 'OK' },
},
},
},
},
}));
await generate({
inputPath,
outputPath,
fileName: 'TaggedApi',
mode: 'split',
});
const content = await readTextFile(join(outputPath, 'operations-tree.ts'));
expect(content).toContain('import { create } from "./operations/create"');
expect(content).toContain('import { getAll } from "./operations/get-all"');
expect(content).toContain('import { login } from "./operations/login"');
expect(content).toContain('users: {');
expect(content).toContain('getAll: getAll');
expect(content).toContain('create: create');
expect(content).toContain('auth: {');
expect(content).toContain('login: login');
}, 30000);
test('должен обработать все HTTP методы', async () => {
@@ -123,6 +190,26 @@ describe('Generator', () => {
expect(content).toContain('deleteUsersId');
}, 30000);
test('должен генерировать индексный реэкспорт всех operations', async () => {
const outputPath = join(tempDir, 'output');
const config: GeneratorConfig = {
inputPath: FIXTURES.VALID,
outputPath,
fileName: 'TestApi',
mode: 'split',
};
await generate(config);
const content = await readTextFile(join(outputPath, 'operations', 'index.ts'));
expect(content).toContain('export { create } from "./create";');
expect(content).toContain('export { deleteUsersId } from "./delete-users-id";');
expect(content).toContain('export { getAll } from "./get-all";');
expect(content).toContain('export { getById } from "./get-by-id";');
expect(content).toContain('export { update } from "./update";');
}, 30000);
test('должен генерировать типы для request и response', async () => {
const outputPath = join(tempDir, 'output');
const config: GeneratorConfig = {
@@ -235,7 +322,7 @@ describe('Generator', () => {
// Генерация должна пройти успешно
await generate(config);
const generatedFile = join(outputPath, 'TestApi.ts');
const generatedFile = join(outputPath, 'index.ts');
const exists = await fileExists(generatedFile);
expect(exists).toBe(true);
}, 30000);
@@ -250,7 +337,7 @@ describe('Generator', () => {
await generate(config);
const generatedFile = join(outputPath, 'TestApi.ts');
const generatedFile = join(outputPath, 'index.ts');
const exists = await fileExists(generatedFile);
expect(exists).toBe(true);
}, 30000);
@@ -285,7 +372,7 @@ describe('Generator', () => {
// Генерация должна пройти успешно даже с Unicode
await generate(config);
const generatedFile = join(outputPath, 'TestApi.ts');
const generatedFile = join(outputPath, 'index.ts');
const exists = await fileExists(generatedFile);
expect(exists).toBe(true);
}, 30000);