+5
.changeset/short-phones-count.md
+5
.changeset/short-phones-count.md
+1
.gitignore
+1
.gitignore
+3
-6
.vscode/launch.json
+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/graph-hotspots.js
dev/graph-hotspots.js
debug-helpers/json-to-dot.js
dev/json-to-dot.js
debug-helpers/json-to-dot.js
dev/json-to-dot.js
+2
package.json
+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
+1
packages/openapi-ts-tests/main/.gitignore
+5
-5
packages/openapi-ts-tests/main/test/openapi-ts.config.ts
dev/openapi-ts.config.ts
+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
-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
+1
-1
packages/openapi-ts/package.json
+142
packages/openapi-ts/src/cli.ts
+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
+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
+1
-1
packages/openapi-ts/src/ir/types.d.ts
+2
-2
packages/openapi-ts/src/openApi/index.ts
+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,
+1
-1
packages/openapi-ts/tsdown.config.ts
+1
-1
packages/openapi-ts/tsdown.config.ts
+11
-5
pnpm-lock.yaml
+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