+4
-4
.github/copilot-instructions.md
+4
-4
.github/copilot-instructions.md
···
49
49
# Server starts on http://localhost:5173/
50
50
51
51
# Run CLI tool directly
52
-
node packages/openapi-ts/bin/index.cjs --help
52
+
node packages/openapi-ts/dist/run.js --help
53
53
# or after building
54
54
npx @hey-api/openapi-ts --help
55
55
```
···
85
85
86
86
```bash
87
87
# Test CLI help
88
-
node packages/openapi-ts/bin/index.cjs --help
88
+
node packages/openapi-ts/dist/run.js --help
89
89
90
90
# Test CLI version
91
-
node packages/openapi-ts/bin/index.cjs --version
91
+
node packages/openapi-ts/dist/run.js --version
92
92
93
93
# Test basic code generation with a simple OpenAPI spec
94
94
# Create a minimal test spec and generate client code
95
-
node packages/openapi-ts/bin/index.cjs -i path/to/spec.json -o ./test-output --plugins "@hey-api/client-fetch" "@hey-api/typescript"
95
+
node packages/openapi-ts/dist/run.js -i path/to/spec.json -o ./test-output --plugins "@hey-api/client-fetch" "@hey-api/typescript"
96
96
```
97
97
98
98
2. **Example Application Test**:
+1
-1
packages/openapi-ts/package.json
+1
-1
packages/openapi-ts/package.json
+133
packages/openapi-ts/src/generate.ts
+133
packages/openapi-ts/src/generate.ts
···
1
+
import { checkNodeVersion } from '~/config/engine';
2
+
import type { Configs } from '~/config/init';
3
+
import { initConfigs } from '~/config/init';
4
+
import { getLogs } from '~/config/logs';
5
+
import { createClient as pCreateClient } from '~/createClient';
6
+
import {
7
+
ConfigValidationError,
8
+
JobError,
9
+
logCrashReport,
10
+
openGitHubIssueWithCrashReport,
11
+
printCrashReport,
12
+
shouldReportCrash,
13
+
} from '~/error';
14
+
import type { IR } from '~/ir/types';
15
+
import type { Client } from '~/types/client';
16
+
import type { UserConfig } from '~/types/config';
17
+
import type { LazyOrAsync, MaybeArray } from '~/types/utils';
18
+
import { printCliIntro } from '~/utils/cli';
19
+
import { registerHandlebarTemplates } from '~/utils/handlebars';
20
+
import { Logger } from '~/utils/logger';
21
+
22
+
/**
23
+
* Generate a client from the provided configuration.
24
+
*
25
+
* @param userConfig User provided {@link UserConfig} configuration(s).
26
+
*/
27
+
export const createClient = async (
28
+
userConfig?: LazyOrAsync<MaybeArray<UserConfig>>,
29
+
logger = new Logger(),
30
+
): Promise<ReadonlyArray<Client | IR.Context>> => {
31
+
const resolvedConfig =
32
+
typeof userConfig === 'function' ? await userConfig() : userConfig;
33
+
const userConfigs = resolvedConfig
34
+
? resolvedConfig instanceof Array
35
+
? resolvedConfig
36
+
: [resolvedConfig]
37
+
: [];
38
+
39
+
let rawLogs = userConfigs.find(
40
+
(config) => getLogs(config).level !== 'silent',
41
+
)?.logs;
42
+
if (typeof rawLogs === 'string') {
43
+
rawLogs = getLogs({ logs: rawLogs });
44
+
}
45
+
46
+
let configs: Configs | undefined;
47
+
48
+
try {
49
+
checkNodeVersion();
50
+
51
+
const eventCreateClient = logger.timeEvent('createClient');
52
+
53
+
const eventConfig = logger.timeEvent('config');
54
+
configs = await initConfigs({ logger, userConfigs });
55
+
const printIntro = configs.results.some(
56
+
(result) => result.config.logs.level !== 'silent',
57
+
);
58
+
if (printIntro) {
59
+
printCliIntro();
60
+
}
61
+
eventConfig.timeEnd();
62
+
63
+
const allConfigErrors = configs.results.flatMap((result) =>
64
+
result.errors.map((error) => ({ error, jobIndex: result.jobIndex })),
65
+
);
66
+
if (allConfigErrors.length) {
67
+
throw new ConfigValidationError(allConfigErrors);
68
+
}
69
+
70
+
const eventHandlebars = logger.timeEvent('handlebars');
71
+
const templates = registerHandlebarTemplates();
72
+
eventHandlebars.timeEnd();
73
+
74
+
const clients = await Promise.all(
75
+
configs.results.map(async (result) => {
76
+
try {
77
+
return await pCreateClient({
78
+
config: result.config,
79
+
dependencies: configs!.dependencies,
80
+
jobIndex: result.jobIndex,
81
+
logger,
82
+
templates,
83
+
});
84
+
} catch (error) {
85
+
throw new JobError('', {
86
+
error,
87
+
jobIndex: result.jobIndex,
88
+
});
89
+
}
90
+
}),
91
+
);
92
+
const result = clients.filter((client) => Boolean(client)) as ReadonlyArray<
93
+
Client | IR.Context
94
+
>;
95
+
96
+
eventCreateClient.timeEnd();
97
+
98
+
const printLogs = configs.results.some(
99
+
(result) => result.config.logs.level === 'debug',
100
+
);
101
+
logger.report(printLogs);
102
+
103
+
return result;
104
+
} catch (error) {
105
+
const results = configs?.results ?? [];
106
+
107
+
const logs =
108
+
results.find((result) => result.config.logs.level !== 'silent')?.config
109
+
.logs ??
110
+
results[0]?.config.logs ??
111
+
rawLogs;
112
+
const dryRun =
113
+
results.some((result) => result.config.dryRun) ??
114
+
userConfigs.some((config) => config.dryRun) ??
115
+
false;
116
+
const logPath =
117
+
logs?.file && !dryRun
118
+
? logCrashReport(error, logs.path ?? '')
119
+
: undefined;
120
+
if (!logs || logs.level !== 'silent') {
121
+
printCrashReport({ error, logPath });
122
+
const isInteractive =
123
+
results.some((result) => result.config.interactive) ??
124
+
userConfigs.some((config) => config.interactive) ??
125
+
false;
126
+
if (await shouldReportCrash({ error, isInteractive })) {
127
+
await openGitHubIssueWithCrashReport(error);
128
+
}
129
+
}
130
+
131
+
throw error;
132
+
}
133
+
};
+1
-130
packages/openapi-ts/src/index.ts
+1
-130
packages/openapi-ts/src/index.ts
···
35
35
// @ts-expect-error
36
36
import colorSupport from 'color-support';
37
37
38
-
import { checkNodeVersion } from '~/config/engine';
39
-
import type { Configs } from '~/config/init';
40
-
import { initConfigs } from '~/config/init';
41
-
import { getLogs } from '~/config/logs';
42
-
import { createClient as pCreateClient } from '~/createClient';
43
-
import {
44
-
ConfigValidationError,
45
-
JobError,
46
-
logCrashReport,
47
-
openGitHubIssueWithCrashReport,
48
-
printCrashReport,
49
-
shouldReportCrash,
50
-
} from '~/error';
51
-
import type { IR } from '~/ir/types';
52
-
import type { Client } from '~/types/client';
53
38
import type { UserConfig } from '~/types/config';
54
39
import type { LazyOrAsync, MaybeArray } from '~/types/utils';
55
-
import { printCliIntro } from '~/utils/cli';
56
-
import { registerHandlebarTemplates } from '~/utils/handlebars';
57
-
import { Logger } from '~/utils/logger';
58
40
59
41
colors.enabled = colorSupport().hasBasic;
60
42
61
-
/**
62
-
* Generate a client from the provided configuration.
63
-
*
64
-
* @param userConfig User provided {@link UserConfig} configuration(s).
65
-
*/
66
-
export const createClient = async (
67
-
userConfig?: LazyOrAsync<MaybeArray<UserConfig>>,
68
-
logger = new Logger(),
69
-
): Promise<ReadonlyArray<Client | IR.Context>> => {
70
-
const resolvedConfig =
71
-
typeof userConfig === 'function' ? await userConfig() : userConfig;
72
-
const userConfigs = resolvedConfig
73
-
? resolvedConfig instanceof Array
74
-
? resolvedConfig
75
-
: [resolvedConfig]
76
-
: [];
77
-
78
-
let rawLogs = userConfigs.find(
79
-
(config) => getLogs(config).level !== 'silent',
80
-
)?.logs;
81
-
if (typeof rawLogs === 'string') {
82
-
rawLogs = getLogs({ logs: rawLogs });
83
-
}
84
-
85
-
let configs: Configs | undefined;
86
-
87
-
try {
88
-
checkNodeVersion();
89
-
90
-
const eventCreateClient = logger.timeEvent('createClient');
91
-
92
-
const eventConfig = logger.timeEvent('config');
93
-
configs = await initConfigs({ logger, userConfigs });
94
-
const printIntro = configs.results.some(
95
-
(result) => result.config.logs.level !== 'silent',
96
-
);
97
-
if (printIntro) {
98
-
printCliIntro();
99
-
}
100
-
eventConfig.timeEnd();
101
-
102
-
const allConfigErrors = configs.results.flatMap((result) =>
103
-
result.errors.map((error) => ({ error, jobIndex: result.jobIndex })),
104
-
);
105
-
if (allConfigErrors.length) {
106
-
throw new ConfigValidationError(allConfigErrors);
107
-
}
108
-
109
-
const eventHandlebars = logger.timeEvent('handlebars');
110
-
const templates = registerHandlebarTemplates();
111
-
eventHandlebars.timeEnd();
112
-
113
-
const clients = await Promise.all(
114
-
configs.results.map(async (result) => {
115
-
try {
116
-
return await pCreateClient({
117
-
config: result.config,
118
-
dependencies: configs!.dependencies,
119
-
jobIndex: result.jobIndex,
120
-
logger,
121
-
templates,
122
-
});
123
-
} catch (error) {
124
-
throw new JobError('', {
125
-
error,
126
-
jobIndex: result.jobIndex,
127
-
});
128
-
}
129
-
}),
130
-
);
131
-
const result = clients.filter((client) => Boolean(client)) as ReadonlyArray<
132
-
Client | IR.Context
133
-
>;
134
-
135
-
eventCreateClient.timeEnd();
136
-
137
-
const printLogs = configs.results.some(
138
-
(result) => result.config.logs.level === 'debug',
139
-
);
140
-
logger.report(printLogs);
141
-
142
-
return result;
143
-
} catch (error) {
144
-
const results = configs?.results ?? [];
145
-
146
-
const logs =
147
-
results.find((result) => result.config.logs.level !== 'silent')?.config
148
-
.logs ??
149
-
results[0]?.config.logs ??
150
-
rawLogs;
151
-
const dryRun =
152
-
results.some((result) => result.config.dryRun) ??
153
-
userConfigs.some((config) => config.dryRun) ??
154
-
false;
155
-
const logPath =
156
-
logs?.file && !dryRun
157
-
? logCrashReport(error, logs.path ?? '')
158
-
: undefined;
159
-
if (!logs || logs.level !== 'silent') {
160
-
printCrashReport({ error, logPath });
161
-
const isInteractive =
162
-
results.some((result) => result.config.interactive) ??
163
-
userConfigs.some((config) => config.interactive) ??
164
-
false;
165
-
if (await shouldReportCrash({ error, isInteractive })) {
166
-
await openGitHubIssueWithCrashReport(error);
167
-
}
168
-
}
169
-
170
-
throw error;
171
-
}
172
-
};
43
+
export { createClient } from './generate';
173
44
174
45
/**
175
46
* Type helper for openapi-ts.config.ts, returns {@link MaybeArray<UserConfig>} object(s)
+24
scripts/examples-generate.sh
+24
scripts/examples-generate.sh
···
11
11
12
12
echo "⏳ Generating client code for all examples..."
13
13
14
+
# Build the CLI package and show diagnostics so CI can report why the bin may be missing
15
+
echo "Building @hey-api/openapi-ts (required for example generation)..."
16
+
if command -v pnpm >/dev/null 2>&1; then
17
+
if pnpm -w -s --version >/dev/null 2>&1; then
18
+
pnpm -w -s --filter "@hey-api/openapi-ts" build || pnpm -s --filter "@hey-api/openapi-ts" build || true
19
+
else
20
+
pnpm -s --filter "@hey-api/openapi-ts" build || true
21
+
fi
22
+
fi
23
+
24
+
CLI_PKG_DIR="$ROOT_DIR/packages/openapi-ts"
25
+
echo "-> Debug: showing $CLI_PKG_DIR/package.json"
26
+
if [ -f "$CLI_PKG_DIR/package.json" ]; then
27
+
cat "$CLI_PKG_DIR/package.json"
28
+
else
29
+
echo "-> Debug: package.json missing at $CLI_PKG_DIR"
30
+
fi
31
+
32
+
echo "-> Debug: listing $CLI_PKG_DIR top-level files"
33
+
ls -la "$CLI_PKG_DIR" || true
34
+
echo "-> Debug: listing $CLI_PKG_DIR/dist"
35
+
ls -la "$CLI_PKG_DIR/dist" 2>/dev/null || echo "-> Debug: dist missing"
36
+
37
+
14
38
# Find all examples with openapi-ts script and generate code in parallel
15
39
# Concurrency control: adjust this number depending on CI machine resources
16
40
CONCURRENCY=${CONCURRENCY:-4}