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

fix(cli): move cli script to typescript

Lubos b677f893 32925810

+5
.changeset/short-phones-count.md
··· 1 + --- 2 + '@hey-api/openapi-ts': patch 3 + --- 4 + 5 + fix(cli): move cli script to typescript
+1
.gitignore
··· 20 20 .turbo 21 21 22 22 # test files 23 + .gen/ 23 24 test/generated 24 25 25 26 # debug files
+3 -6
.vscode/launch.json
··· 14 14 "name": "openapi-ts", 15 15 "skipFiles": ["<node_internals>/**"], 16 16 "runtimeExecutable": "node", 17 - "runtimeArgs": [], 18 - "program": "${workspaceFolder}/packages/openapi-ts/bin/index.cjs", 19 - "args": [ 20 - "-f", 21 - "${workspaceFolder}/packages/openapi-ts-tests/main/test/openapi-ts.config.ts" 22 - ] 17 + "runtimeArgs": ["-r", "ts-node/register/transpile-only"], 18 + "program": "${workspaceFolder}/packages/openapi-ts/src/cli.ts", 19 + "args": ["-f", "${workspaceFolder}/dev/openapi-ts.config.ts"] 23 20 } 24 21 ] 25 22 }
debug-helpers/graph-hotspots.js dev/graph-hotspots.js
debug-helpers/json-to-dot.js dev/json-to-dot.js
+2
package.json
··· 48 48 "@config/vite-base": "workspace:*", 49 49 "@eslint/js": "9.32.0", 50 50 "@hey-api/custom-client": "workspace:*", 51 + "@hey-api/openapi-ts": "workspace:*", 51 52 "@types/node": "22.10.5", 52 53 "@typescript-eslint/eslint-plugin": "8.29.1", 53 54 "@vitest/coverage-v8": "3.1.1", ··· 65 66 "prettier": "3.4.2", 66 67 "rollup": "4.31.0", 67 68 "rollup-plugin-dts": "6.1.1", 69 + "ts-node": "10.9.2", 68 70 "tsdown": "0.15.8", 69 71 "turbo": "2.5.8", 70 72 "typescript": "5.9.3",
+1
packages/openapi-ts-tests/main/.gitignore
··· 16 16 .env 17 17 18 18 # test files 19 + .gen/ 19 20 test/generated 20 21 generated/
+5 -5
packages/openapi-ts-tests/main/test/openapi-ts.config.ts dev/openapi-ts.config.ts
··· 6 6 // @ts-ignore 7 7 import { defineConfig, utils } from '@hey-api/openapi-ts'; 8 8 9 - import { getSpecsPath } from '../../utils'; 10 9 // @ts-ignore 11 - import { myClientPlugin } from './custom/client/plugin'; 10 + import { myClientPlugin } from '../packages/openapi-ts-tests/main/test/custom/client/plugin'; 11 + import { getSpecsPath } from '../packages/openapi-ts-tests/utils'; 12 12 13 13 // @ts-ignore 14 14 // eslint-disable-next-line arrow-body-style ··· 96 96 // importFileExtension: '.ts', 97 97 // // indexFile: false, 98 98 // // lint: 'eslint', 99 - // path: path.resolve(__dirname, 'generated', 'sample'), 99 + // path: path.resolve(__dirname, '.gen'), 100 100 // tsConfigPath: path.resolve( 101 101 // __dirname, 102 102 // 'tsconfig', 103 103 // 'tsconfig.nodenext.json', 104 104 // ), 105 105 // }, 106 - path.resolve(__dirname, 'generated', 'sample'), 106 + path.resolve(__dirname, '.gen'), 107 107 ], 108 108 parser: { 109 109 filters: { ··· 478 478 // // level: 'debug', 479 479 // path: './logs', 480 480 // }, 481 - // output: path.resolve(__dirname, 'generated', 'sample'), 481 + // output: path.resolve(__dirname, '.gen'), 482 482 // }, 483 483 ]; 484 484 });
-148
packages/openapi-ts/bin/index.cjs
··· 1 - #!/usr/bin/env node 2 - 3 - 'use strict'; 4 - 5 - const path = require('path'); 6 - 7 - const { program } = require('commander'); 8 - const pkg = require('../package.json'); 9 - 10 - const params = program 11 - .name(Object.keys(pkg.bin)[0]) 12 - .usage('[options]') 13 - .version(pkg.version) 14 - .option( 15 - '-c, --client <value>', 16 - 'HTTP client to generate [@hey-api/client-axios, @hey-api/client-fetch, @hey-api/client-next, @hey-api/client-nuxt, legacy/angular, legacy/axios, legacy/fetch, legacy/node, legacy/xhr]', 17 - ) 18 - .option('-d, --debug', 'Set log level to debug') 19 - .option('--dry-run [value]', 'Skip writing files to disk?') 20 - .option( 21 - '-e, --experimental-parser [value]', 22 - 'Opt-in to the experimental parser?', 23 - ) 24 - .option('-f, --file [value]', 'Path to the config file') 25 - .option( 26 - '-i, --input <value>', 27 - 'OpenAPI specification (path, url, or string content)', 28 - ) 29 - .option('-l, --logs [value]', 'Logs folder') 30 - .option('-o, --output <value>', 'Output folder') 31 - .option('-p, --plugins [value...]', "List of plugins you'd like to use") 32 - .option( 33 - '--base [value]', 34 - 'DEPRECATED. Manually set base in OpenAPI config instead of inferring from server value', 35 - ) 36 - .option('-s, --silent', 'Set log level to silent') 37 - .option( 38 - '--no-log-file', 39 - 'Disable writing a log file. Works like --silent but without suppressing console output', 40 - ) 41 - .option( 42 - '-w, --watch [value]', 43 - 'Regenerate the client when the input file changes?', 44 - ) 45 - .option('--exportCore [value]', 'DEPRECATED. Write core files to disk') 46 - .option('--name <value>', 'DEPRECATED. Custom client class name') 47 - .option('--request <value>', 'DEPRECATED. Path to custom request file') 48 - .option( 49 - '--useOptions [value]', 50 - 'DEPRECATED. Use options instead of arguments?', 51 - ) 52 - .parse(process.argv) 53 - .opts(); 54 - 55 - const stringToBoolean = (value) => { 56 - if (value === 'true') { 57 - return true; 58 - } 59 - if (value === 'false') { 60 - return false; 61 - } 62 - return value; 63 - }; 64 - 65 - const processParams = (obj, booleanKeys) => { 66 - for (const key of booleanKeys) { 67 - const value = obj[key]; 68 - if (typeof value === 'string') { 69 - const parsedValue = stringToBoolean(value); 70 - delete obj[key]; 71 - obj[key] = parsedValue; 72 - } 73 - } 74 - if (obj.file) { 75 - obj.configFile = obj.file; 76 - } 77 - return obj; 78 - }; 79 - 80 - async function start() { 81 - let userConfig; 82 - 83 - try { 84 - const { createClient } = require( 85 - path.resolve(__dirname, '../dist/index.cjs'), 86 - ); 87 - 88 - userConfig = processParams(params, [ 89 - 'dryRun', 90 - 'logFile', 91 - 'experimentalParser', 92 - 'exportCore', 93 - 'useOptions', 94 - ]); 95 - 96 - if (params.plugins === true) { 97 - userConfig.plugins = []; 98 - } else if (params.plugins) { 99 - userConfig.plugins = params.plugins; 100 - } else if (userConfig.client) { 101 - userConfig.plugins = ['@hey-api/typescript', '@hey-api/sdk']; 102 - } 103 - 104 - if (userConfig.client) { 105 - userConfig.plugins.push(userConfig.client); 106 - delete userConfig.client; 107 - } 108 - 109 - userConfig.logs = userConfig.logs 110 - ? { 111 - path: userConfig.logs, 112 - } 113 - : {}; 114 - 115 - if (userConfig.debug || stringToBoolean(process.env.DEBUG)) { 116 - userConfig.logs.level = 'debug'; 117 - } else if (userConfig.silent) { 118 - userConfig.logs.level = 'silent'; 119 - } 120 - 121 - userConfig.logs.file = userConfig.logFile; 122 - delete userConfig.logFile; 123 - 124 - if (typeof params.watch === 'string') { 125 - userConfig.watch = Number.parseInt(params.watch, 10); 126 - } 127 - 128 - if (!Object.keys(userConfig.logs).length) { 129 - delete userConfig.logs; 130 - } 131 - 132 - const context = await createClient(userConfig); 133 - if ( 134 - !context[0] || 135 - !context[0].config || 136 - !context[0].config.input || 137 - !context[0].config.input.some( 138 - (input) => input.watch && input.watch.enabled, 139 - ) 140 - ) { 141 - process.exit(0); 142 - } 143 - } catch { 144 - process.exit(1); 145 - } 146 - } 147 - 148 - start();
+1 -1
packages/openapi-ts/package.json
··· 66 66 "./package.json": "./package.json" 67 67 }, 68 68 "bin": { 69 - "openapi-ts": "bin/index.cjs" 69 + "openapi-ts": "./dist/cli.cjs" 70 70 }, 71 71 "files": [ 72 72 "bin",
+142
packages/openapi-ts/src/cli.ts
··· 1 + #!/usr/bin/env node 2 + 3 + 'use strict'; 4 + 5 + import { program } from 'commander'; 6 + 7 + import { createClient } from '~/index'; 8 + 9 + import pkg from '../package.json' assert { type: 'json' }; 10 + 11 + const params = program 12 + .name(Object.keys(pkg.bin)[0]!) 13 + .usage('[options]') 14 + .version(pkg.version) 15 + .option( 16 + '-c, --client <value>', 17 + 'HTTP client to generate [@hey-api/client-axios, @hey-api/client-fetch, @hey-api/client-next, @hey-api/client-nuxt, legacy/angular, legacy/axios, legacy/fetch, legacy/node, legacy/xhr]', 18 + ) 19 + .option('-d, --debug', 'Set log level to debug') 20 + .option('--dry-run [value]', 'Skip writing files to disk?') 21 + .option( 22 + '-e, --experimental-parser [value]', 23 + 'Opt-in to the experimental parser?', 24 + ) 25 + .option('-f, --file [value]', 'Path to the config file') 26 + .option( 27 + '-i, --input <value>', 28 + 'OpenAPI specification (path, url, or string content)', 29 + ) 30 + .option('-l, --logs [value]', 'Logs folder') 31 + .option('-o, --output <value>', 'Output folder') 32 + .option('-p, --plugins [value...]', "List of plugins you'd like to use") 33 + .option( 34 + '--base [value]', 35 + 'DEPRECATED. Manually set base in OpenAPI config instead of inferring from server value', 36 + ) 37 + .option('-s, --silent', 'Set log level to silent') 38 + .option( 39 + '--no-log-file', 40 + 'Disable writing a log file. Works like --silent but without suppressing console output', 41 + ) 42 + .option( 43 + '-w, --watch [value]', 44 + 'Regenerate the client when the input file changes?', 45 + ) 46 + .option('--exportCore [value]', 'DEPRECATED. Write core files to disk') 47 + .option('--name <value>', 'DEPRECATED. Custom client class name') 48 + .option('--request <value>', 'DEPRECATED. Path to custom request file') 49 + .option( 50 + '--useOptions [value]', 51 + 'DEPRECATED. Use options instead of arguments?', 52 + ) 53 + .parse(process.argv) 54 + .opts(); 55 + 56 + const stringToBoolean = (value: any) => { 57 + if (value === 'true') { 58 + return true; 59 + } 60 + if (value === 'false') { 61 + return false; 62 + } 63 + return value; 64 + }; 65 + 66 + const processParams = (obj: any, booleanKeys: any) => { 67 + for (const key of booleanKeys) { 68 + const value = obj[key]; 69 + if (typeof value === 'string') { 70 + const parsedValue = stringToBoolean(value); 71 + delete obj[key]; 72 + obj[key] = parsedValue; 73 + } 74 + } 75 + if (obj.file) { 76 + obj.configFile = obj.file; 77 + } 78 + return obj; 79 + }; 80 + 81 + async function start() { 82 + let userConfig; 83 + 84 + try { 85 + userConfig = processParams(params, [ 86 + 'dryRun', 87 + 'logFile', 88 + 'experimentalParser', 89 + 'exportCore', 90 + 'useOptions', 91 + ]); 92 + 93 + if (params.plugins === true) { 94 + userConfig.plugins = []; 95 + } else if (params.plugins) { 96 + userConfig.plugins = params.plugins; 97 + } else if (userConfig.client) { 98 + userConfig.plugins = ['@hey-api/typescript', '@hey-api/sdk']; 99 + } 100 + 101 + if (userConfig.client) { 102 + userConfig.plugins.push(userConfig.client); 103 + delete userConfig.client; 104 + } 105 + 106 + userConfig.logs = userConfig.logs 107 + ? { 108 + path: userConfig.logs, 109 + } 110 + : {}; 111 + 112 + if (userConfig.debug || stringToBoolean(process.env.DEBUG)) { 113 + userConfig.logs.level = 'debug'; 114 + } else if (userConfig.silent) { 115 + userConfig.logs.level = 'silent'; 116 + } 117 + 118 + userConfig.logs.file = userConfig.logFile; 119 + delete userConfig.logFile; 120 + 121 + if (typeof params.watch === 'string') { 122 + userConfig.watch = Number.parseInt(params.watch, 10); 123 + } 124 + 125 + if (!Object.keys(userConfig.logs).length) { 126 + delete userConfig.logs; 127 + } 128 + 129 + const context = await createClient(userConfig); 130 + if ( 131 + !context[0]?.config.input.some( 132 + (input) => input.watch && input.watch.enabled, 133 + ) 134 + ) { 135 + process.exit(0); 136 + } 137 + } catch { 138 + process.exit(1); 139 + } 140 + } 141 + 142 + start();
+1 -1
packages/openapi-ts/src/ir/context.ts
··· 14 14 15 15 import type { IR } from './types'; 16 16 17 - export class IRContext<Spec extends Record<string, any> = any> { 17 + export class Context<Spec extends Record<string, any> = any> { 18 18 /** 19 19 * Configuration for parsing and generating the output. This 20 20 * is a mix of user-provided and default values.
+1 -1
packages/openapi-ts/src/ir/types.d.ts
··· 4 4 ServerObject, 5 5 } from '~/openApi/3.1.x/types/spec'; 6 6 7 - import type { IRContext } from './context'; 7 + import type { Context as IRContext } from './context'; 8 8 import type { IRMediaType } from './mediaType'; 9 9 10 10 interface IRBodyObject {
+2 -2
packages/openapi-ts/src/openApi/index.ts
··· 1 1 import { satisfies } from '~/config/utils/package'; 2 - import { IRContext } from '~/ir/context'; 2 + import { Context } from '~/ir/context'; 3 3 import type { IR } from '~/ir/types'; 4 4 import { parseV2_0_X } from '~/openApi/2.0.x'; 5 5 import { parseV3_0_X } from '~/openApi/3.0.x'; ··· 74 74 logger: Logger; 75 75 spec: unknown; 76 76 }): IR.Context | undefined => { 77 - const context = new IRContext({ 77 + const context = new Context({ 78 78 config, 79 79 dependencies, 80 80 logger,
+2 -2
packages/openapi-ts/src/openApi/shared/utils/graph.ts
··· 503 503 504 504 eventBuildGraph.timeEnd(); 505 505 506 - // functions creating data for debug scripts located in `debug-helpers/` 506 + // functions creating data for debug scripts located in `dev/` 507 507 // const { maxChildren, maxDepth, totalNodes } = debugTools.graph.analyzeStructure(graph); 508 508 // const nodesForViz = debugTools.graph.exportForVisualization(graph); 509 - // fs.writeFileSync('debug-helpers/graph.json', JSON.stringify(nodesForViz, null, 2)); 509 + // fs.writeFileSync('dev/graph.json', JSON.stringify(nodesForViz, null, 2)); 510 510 511 511 return { graph }; 512 512 };
+1 -1
packages/openapi-ts/tsdown.config.ts
··· 29 29 }, 30 30 clean: true, 31 31 dts: true, 32 - entry: ['src/index.ts', 'src/internal.ts'], 32 + entry: ['./src/{index,internal,cli}.ts'], 33 33 format: ['cjs', 'esm'], 34 34 minify: !options.watch, 35 35 onSuccess: async () => {
+11 -5
pnpm-lock.yaml
··· 37 37 '@hey-api/custom-client': 38 38 specifier: workspace:* 39 39 version: link:packages/custom-client 40 + '@hey-api/openapi-ts': 41 + specifier: workspace:* 42 + version: link:packages/openapi-ts 40 43 '@types/node': 41 44 specifier: 22.10.5 42 45 version: 22.10.5 ··· 88 91 rollup-plugin-dts: 89 92 specifier: 6.1.1 90 93 version: 6.1.1(rollup@4.31.0)(typescript@5.9.3) 94 + ts-node: 95 + specifier: 10.9.2 96 + version: 10.9.2(@types/node@22.10.5)(typescript@5.9.3) 91 97 tsdown: 92 98 specifier: 0.15.8 93 99 version: 0.15.8(@arethetypeswrong/core@0.18.2)(typescript@5.9.3) ··· 170 176 devDependencies: 171 177 '@angular-devkit/build-angular': 172 178 specifier: 19.2.0 173 - version: 19.2.0(3d70bfaaf57777265a4e229c41aeb4c6) 179 + version: 19.2.0(a969acb6c0970aa981df1cb7672d7c2e) 174 180 '@angular/cli': 175 181 specifier: 19.2.0 176 182 version: 19.2.0(@types/node@22.10.5)(chokidar@4.0.3) ··· 264 270 devDependencies: 265 271 '@angular-devkit/build-angular': 266 272 specifier: 19.2.0 267 - version: 19.2.0(a969acb6c0970aa981df1cb7672d7c2e) 273 + version: 19.2.0(3d70bfaaf57777265a4e229c41aeb4c6) 268 274 '@angular/cli': 269 275 specifier: 19.2.0 270 276 version: 19.2.0(@types/node@22.10.5)(chokidar@4.0.3) ··· 23183 23189 eslint: 9.17.0(jiti@2.6.1) 23184 23190 eslint-import-resolver-node: 0.3.9 23185 23191 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)) 23186 - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.17.0(jiti@2.6.1)) 23192 + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)) 23187 23193 eslint-plugin-jsx-a11y: 6.10.2(eslint@9.17.0(jiti@2.6.1)) 23188 23194 eslint-plugin-react: 7.37.5(eslint@9.17.0(jiti@2.6.1)) 23189 23195 eslint-plugin-react-hooks: 5.2.0(eslint@9.17.0(jiti@2.6.1)) ··· 23221 23227 tinyglobby: 0.2.14 23222 23228 unrs-resolver: 1.11.1 23223 23229 optionalDependencies: 23224 - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.17.0(jiti@2.6.1)) 23230 + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)) 23225 23231 transitivePeerDependencies: 23226 23232 - supports-color 23227 23233 ··· 23236 23242 transitivePeerDependencies: 23237 23243 - supports-color 23238 23244 23239 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.17.0(jiti@2.6.1)): 23245 + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)): 23240 23246 dependencies: 23241 23247 '@rtsao/scc': 1.1.0 23242 23248 array-includes: 3.1.9
-7
pnpm-workspace.yaml
··· 3 3 - examples/**/* 4 4 - packages/**/* 5 5 6 - onlyBuiltDependencies: 7 - - esbuild 8 - - lmdb 9 - - msgpackr-extract 10 - - sharp 11 - - unrs-resolver 12 - 13 6 patchedDependencies: 14 7 vitepress: patches/vitepress.patch