fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #2137 from hey-api/fix/legacy-client-export-from-index

fix(parser): respect exportFromIndex option when using legacy clients

authored by

Lubos and committed by
GitHub
3126e799 80da2696

+150 -134
+5
.changeset/tender-bananas-dress.md
··· 1 + --- 2 + '@hey-api/openapi-ts': patch 3 + --- 4 + 5 + fix(parser): respect exportFromIndex option when using legacy clients
+1
docs/.vitepress/theme/custom.css
··· 239 239 background-color: var(--vp-c-brand-3); 240 240 border-radius: 10px; 241 241 border: 1px solid transparent; 242 + color: var(--vp-button-brand-text); 242 243 column-gap: 3rem; 243 244 display: flex; 244 245 flex-direction: column;
+6 -9
packages/openapi-ts-tests/test/openapi-ts.config.ts
··· 51 51 // 'invalid', 52 52 // 'servers-entry.yaml', 53 53 // ), 54 - path: path.resolve( 55 - __dirname, 56 - 'spec', 57 - '3.1.x', 58 - 'discriminator-one-of.yaml', 59 - ), 54 + path: path.resolve(__dirname, 'spec', '3.1.x', 'full.json'), 60 55 // path: 'http://localhost:4000/', 61 56 // path: 'https://get.heyapi.dev/', 62 57 // path: 'https://get.heyapi.dev/hey-api/backend?branch=main&version=1.0.0', ··· 98 93 // bundle: true, 99 94 // bundleSource_EXPERIMENTAL: true, 100 95 // exportFromIndex: true, 101 - name: '@hey-api/client-fetch', 96 + // name: '@hey-api/client-fetch', 97 + name: 'legacy/fetch', 102 98 // strictBaseUrl: true, 103 99 }, 104 100 { 105 - // name: '@hey-api/schemas', 101 + exportFromIndex: true, 102 + name: '@hey-api/schemas', 106 103 // type: 'json', 107 104 }, 108 105 { ··· 142 139 }, 143 140 { 144 141 exportFromIndex: true, 145 - name: '@tanstack/react-query', 142 + // name: '@tanstack/react-query', 146 143 }, 147 144 { 148 145 // comments: false,
+2 -1
packages/openapi-ts/src/createClient.ts
··· 2 2 3 3 import colors from 'ansi-colors'; 4 4 5 - import { generateLegacyOutput, generateOutput } from './generate/output'; 5 + import { generateLegacyOutput } from './generate/legacy/output'; 6 + import { generateOutput } from './generate/output'; 6 7 import { getSpec } from './getSpec'; 7 8 import type { IR } from './ir/types'; 8 9 import { parseLegacy, parseOpenApiSpec } from './openApi';
+2 -2
packages/openapi-ts/src/generate/__tests__/index.test.ts packages/openapi-ts/src/generate/legacy/__tests__/index.test.ts
··· 3 3 4 4 import { describe, expect, it, vi } from 'vitest'; 5 5 6 - import { setConfig } from '../../utils/config'; 7 - import { TypeScriptFile } from '../files'; 6 + import { setConfig } from '../../../utils/config'; 7 + import { TypeScriptFile } from '../../files'; 8 8 import { generateIndexFile } from '../indexFile'; 9 9 10 10 vi.mock('node:fs');
+4 -4
packages/openapi-ts/src/generate/__tests__/output.test.ts packages/openapi-ts/src/generate/legacy/__tests__/output.test.ts
··· 2 2 3 3 import { describe, expect, it, vi } from 'vitest'; 4 4 5 - import type { Client } from '../../types/client'; 6 - import type { Config } from '../../types/config'; 7 - import { setConfig } from '../../utils/config'; 5 + import type { Client } from '../../../types/client'; 6 + import type { Config } from '../../../types/config'; 7 + import { setConfig } from '../../../utils/config'; 8 + import { mockTemplates, openApi } from '../../__tests__/mocks'; 8 9 import { generateLegacyOutput } from '../output'; 9 - import { mockTemplates, openApi } from './mocks'; 10 10 11 11 vi.mock('node:fs', () => { 12 12 const exports = {
+6 -6
packages/openapi-ts/src/generate/indexFile.ts packages/openapi-ts/src/generate/legacy/indexFile.ts
··· 1 - import { compiler } from '../compiler'; 2 - import { getClientPlugin } from '../plugins/@hey-api/client-core/utils'; 3 - import type { Files } from '../types/utils'; 4 - import { getConfig, legacyNameFromConfig } from '../utils/config'; 5 - import { TypeScriptFile } from './files'; 1 + import { compiler } from '../../compiler'; 2 + import { getClientPlugin } from '../../plugins/@hey-api/client-core/utils'; 3 + import type { Files } from '../../types/utils'; 4 + import { getConfig, legacyNameFromConfig } from '../../utils/config'; 5 + import { TypeScriptFile } from '../files'; 6 6 7 7 export const generateIndexFile = ({ files }: { files: Files }): void => { 8 8 const config = getConfig(); ··· 71 71 return; 72 72 } 73 73 74 - if (['sdk', 'types'].includes(name)) { 74 + if (file.exportFromIndex) { 75 75 files.index!.add( 76 76 compiler.exportAllDeclaration({ 77 77 module: `./${file.nameWithoutExtension()}`,
+118
packages/openapi-ts/src/generate/legacy/output.ts
··· 1 + import path from 'node:path'; 2 + 3 + import type { OpenApi } from '../../openApi'; 4 + import { getClientPlugin } from '../../plugins/@hey-api/client-core/utils'; 5 + import type { Client } from '../../types/client'; 6 + import type { Files } from '../../types/utils'; 7 + import { getConfig, isLegacyClient } from '../../utils/config'; 8 + import type { Templates } from '../../utils/handlebars'; 9 + import { generateLegacyClientClass } from '../class'; 10 + import { generateClientBundle } from '../client'; 11 + import { generateLegacyCore } from '../core'; 12 + import { TypeScriptFile } from '../files'; 13 + import { findTsConfigPath, loadTsConfig } from '../tsConfig'; 14 + import { removeDirSync } from '../utils'; 15 + import { generateIndexFile } from './indexFile'; 16 + 17 + /** 18 + * Write our OpenAPI client, using the given templates at the given output 19 + * @param openApi {@link OpenApi} Dereferenced OpenAPI specification 20 + * @param client Client containing models, schemas, and services 21 + * @param templates Templates wrapper with all loaded Handlebars templates 22 + */ 23 + export const generateLegacyOutput = async ({ 24 + client, 25 + openApi, 26 + templates, 27 + }: { 28 + client: Client; 29 + openApi: unknown; 30 + templates: Templates; 31 + }): Promise<void> => { 32 + const config = getConfig(); 33 + 34 + const spec = openApi as OpenApi; 35 + 36 + // TODO: parser - move to config.input 37 + if (client) { 38 + if ( 39 + config.plugins['@hey-api/sdk']?.include && 40 + config.plugins['@hey-api/sdk'].asClass 41 + ) { 42 + const regexp = new RegExp(config.plugins['@hey-api/sdk'].include); 43 + client.services = client.services.filter((service) => 44 + regexp.test(service.name), 45 + ); 46 + } 47 + 48 + if (config.plugins['@hey-api/typescript']?.include) { 49 + const regexp = new RegExp(config.plugins['@hey-api/typescript'].include); 50 + client.models = client.models.filter((model) => regexp.test(model.name)); 51 + } 52 + } 53 + 54 + const outputPath = path.resolve(config.output.path); 55 + 56 + if (config.output.clean) { 57 + removeDirSync(outputPath); 58 + } 59 + 60 + const clientPlugin = getClientPlugin(config); 61 + if ( 62 + !isLegacyClient(config) && 63 + 'bundle' in clientPlugin && 64 + clientPlugin.bundle 65 + ) { 66 + generateClientBundle({ 67 + outputPath, 68 + plugin: clientPlugin, 69 + }); 70 + } 71 + 72 + // deprecated files 73 + await generateLegacyClientClass(spec, outputPath, client, templates); 74 + await generateLegacyCore( 75 + path.resolve(config.output.path, 'core'), 76 + client, 77 + templates, 78 + ); 79 + 80 + const files: Files = {}; 81 + 82 + for (const name of config.pluginOrder) { 83 + const plugin = config.plugins[name]!; 84 + const outputParts = (plugin.output ?? '').split('/'); 85 + const outputDir = path.resolve( 86 + config.output.path, 87 + ...outputParts.slice(0, outputParts.length - 1), 88 + ); 89 + files[plugin.name] = new TypeScriptFile({ 90 + dir: outputDir, 91 + id: `legacy-unused-${plugin.name}`, 92 + name: `${outputParts[outputParts.length - 1]}.ts`, 93 + }); 94 + plugin._handlerLegacy({ 95 + client, 96 + files, 97 + openApi: spec, 98 + plugin: plugin as never, 99 + }); 100 + } 101 + 102 + // TODO: exports do not support .js extensions 103 + generateIndexFile({ files }); 104 + 105 + const tsConfig = loadTsConfig(findTsConfigPath(config.output.tsConfigPath)); 106 + 107 + Object.entries(files).forEach(([name, file]) => { 108 + if (config.dryRun) { 109 + return; 110 + } 111 + 112 + if (name === 'index') { 113 + file.write('\n', tsConfig); 114 + } else { 115 + file.write('\n\n', tsConfig); 116 + } 117 + }); 118 + };
-112
packages/openapi-ts/src/generate/output.ts
··· 5 5 import { compiler } from '../compiler'; 6 6 import { parseIR } from '../ir/parser'; 7 7 import type { IR } from '../ir/types'; 8 - import type { OpenApi } from '../openApi'; 9 8 import { getClientPlugin } from '../plugins/@hey-api/client-core/utils'; 10 - import type { Client } from '../types/client'; 11 - import type { Files } from '../types/utils'; 12 - import { getConfig, isLegacyClient } from '../utils/config'; 13 - import type { Templates } from '../utils/handlebars'; 14 - import { generateLegacyClientClass } from './class'; 15 9 import { generateClientBundle } from './client'; 16 - import { generateLegacyCore } from './core'; 17 - import { TypeScriptFile } from './files'; 18 - import { generateIndexFile } from './indexFile'; 19 10 import { findTsConfigPath, loadTsConfig } from './tsConfig'; 20 11 import { removeDirSync } from './utils'; 21 - 22 - /** 23 - * Write our OpenAPI client, using the given templates at the given output 24 - * @param openApi {@link OpenApi} Dereferenced OpenAPI specification 25 - * @param client Client containing models, schemas, and services 26 - * @param templates Templates wrapper with all loaded Handlebars templates 27 - */ 28 - export const generateLegacyOutput = async ({ 29 - client, 30 - openApi, 31 - templates, 32 - }: { 33 - client: Client; 34 - openApi: unknown; 35 - templates: Templates; 36 - }): Promise<void> => { 37 - const config = getConfig(); 38 - 39 - const spec = openApi as OpenApi; 40 - 41 - // TODO: parser - move to config.input 42 - if (client) { 43 - if ( 44 - config.plugins['@hey-api/sdk']?.include && 45 - config.plugins['@hey-api/sdk'].asClass 46 - ) { 47 - const regexp = new RegExp(config.plugins['@hey-api/sdk'].include); 48 - client.services = client.services.filter((service) => 49 - regexp.test(service.name), 50 - ); 51 - } 52 - 53 - if (config.plugins['@hey-api/typescript']?.include) { 54 - const regexp = new RegExp(config.plugins['@hey-api/typescript'].include); 55 - client.models = client.models.filter((model) => regexp.test(model.name)); 56 - } 57 - } 58 - 59 - const outputPath = path.resolve(config.output.path); 60 - 61 - if (config.output.clean) { 62 - removeDirSync(outputPath); 63 - } 64 - 65 - const clientPlugin = getClientPlugin(config); 66 - if ( 67 - !isLegacyClient(config) && 68 - 'bundle' in clientPlugin && 69 - clientPlugin.bundle 70 - ) { 71 - generateClientBundle({ 72 - outputPath, 73 - plugin: clientPlugin, 74 - }); 75 - } 76 - 77 - // deprecated files 78 - await generateLegacyClientClass(spec, outputPath, client, templates); 79 - await generateLegacyCore( 80 - path.resolve(config.output.path, 'core'), 81 - client, 82 - templates, 83 - ); 84 - 85 - const files: Files = {}; 86 - 87 - for (const name of config.pluginOrder) { 88 - const plugin = config.plugins[name]!; 89 - const outputParts = (plugin.output ?? '').split('/'); 90 - const outputDir = path.resolve( 91 - config.output.path, 92 - ...outputParts.slice(0, outputParts.length - 1), 93 - ); 94 - files[plugin.name] = new TypeScriptFile({ 95 - dir: outputDir, 96 - id: `legacy-unused-${plugin.name}`, 97 - name: `${outputParts[outputParts.length - 1]}.ts`, 98 - }); 99 - plugin._handlerLegacy({ 100 - client, 101 - files, 102 - openApi: spec, 103 - plugin: plugin as never, 104 - }); 105 - } 106 - 107 - // TODO: exports do not support .js extensions 108 - generateIndexFile({ files }); 109 - 110 - const tsConfig = loadTsConfig(findTsConfigPath(config.output.tsConfigPath)); 111 - 112 - Object.entries(files).forEach(([name, file]) => { 113 - if (config.dryRun) { 114 - return; 115 - } 116 - 117 - if (name === 'index') { 118 - file.write('\n', tsConfig); 119 - } else { 120 - file.write('\n\n', tsConfig); 121 - } 122 - }); 123 - }; 124 12 125 13 export const generateOutput = async ({ context }: { context: IR.Context }) => { 126 14 const outputPath = path.resolve(context.config.output.path);
+2
packages/openapi-ts/src/plugins/@hey-api/schemas/plugin-legacy.ts
··· 78 78 export const handlerLegacy: Plugin.LegacyHandler<Config> = ({ 79 79 files, 80 80 openApi, 81 + plugin, 81 82 }) => { 82 83 const config = getConfig(); 83 84 84 85 files.schemas = new TypeScriptFile({ 85 86 dir: config.output.path, 87 + exportFromIndex: plugin.exportFromIndex, 86 88 id: 'schemas', 87 89 name: 'schemas.ts', 88 90 });
+2
packages/openapi-ts/src/plugins/@hey-api/sdk/plugin-legacy.ts
··· 802 802 export const handlerLegacy: Plugin.LegacyHandler<Config> = ({ 803 803 client, 804 804 files, 805 + plugin, 805 806 }) => { 806 807 const config = getConfig(); 807 808 ··· 811 812 812 813 files.sdk = new TypeScriptFile({ 813 814 dir: config.output.path, 815 + exportFromIndex: plugin.exportFromIndex, 814 816 id: 'sdk', 815 817 name: `${sdkOutput}.ts`, 816 818 });
+2
packages/openapi-ts/src/plugins/@hey-api/typescript/plugin-legacy.ts
··· 609 609 export const handlerLegacy: Plugin.LegacyHandler<Config> = ({ 610 610 client, 611 611 files, 612 + plugin, 612 613 }) => { 613 614 const config = getConfig(); 614 615 615 616 files.types = new TypeScriptFile({ 616 617 dir: config.output.path, 618 + exportFromIndex: plugin.exportFromIndex, 617 619 id: 'types', 618 620 name: 'types.ts', 619 621 });