hono-takibi 0.9.70 → 0.9.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +111 -53
  2. package/dist/cli/index.d.ts +0 -36
  3. package/dist/cli/index.js +317 -3
  4. package/dist/config/index.d.ts +1 -1
  5. package/dist/config/index.js +62 -1
  6. package/dist/core/components/examples.js +42 -6
  7. package/dist/core/components/headers.js +2 -2
  8. package/dist/core/components/parameters.js +2 -2
  9. package/dist/core/components/requestBodies.js +2 -2
  10. package/dist/core/components/responses.js +2 -2
  11. package/dist/core/components/schemas.js +2 -2
  12. package/dist/core/route/index.js +237 -2
  13. package/dist/core/rpc/index.js +1159 -227
  14. package/dist/core/takibi/index.d.ts +1 -1
  15. package/dist/core/takibi/index.js +501 -2
  16. package/dist/core/type/index.d.ts +0 -28
  17. package/dist/core/type/index.js +546 -119
  18. package/dist/format/index.js +18 -0
  19. package/dist/fsp/index.js +87 -0
  20. package/dist/generator/zod-openapi-hono/app/index.js +116 -0
  21. package/dist/generator/zod-openapi-hono/openapi/components/callbacks.js +61 -0
  22. package/dist/generator/zod-openapi-hono/openapi/components/examples.d.ts +137 -0
  23. package/dist/generator/zod-openapi-hono/openapi/components/examples.js +405 -2
  24. package/dist/generator/zod-openapi-hono/openapi/components/headers.js +46 -0
  25. package/dist/generator/zod-openapi-hono/openapi/components/index.js +100 -0
  26. package/dist/generator/zod-openapi-hono/openapi/components/links.js +34 -0
  27. package/dist/generator/zod-openapi-hono/openapi/components/parameters.js +53 -0
  28. package/dist/generator/zod-openapi-hono/openapi/components/request-bodies.js +49 -0
  29. package/dist/generator/zod-openapi-hono/openapi/components/responses.js +43 -0
  30. package/dist/generator/zod-openapi-hono/openapi/components/schemas.js +72 -0
  31. package/dist/generator/zod-openapi-hono/openapi/components/securitySchemes.js +36 -0
  32. package/dist/generator/zod-openapi-hono/openapi/index.js +460 -0
  33. package/dist/generator/zod-openapi-hono/openapi/routes/create-route.js +36 -0
  34. package/dist/generator/zod-openapi-hono/openapi/routes/index.js +44 -0
  35. package/dist/generator/zod-to-openapi/index.js +781 -26
  36. package/dist/generator/zod-to-openapi/z/enum.js +27 -0
  37. package/dist/generator/zod-to-openapi/z/index.js +27 -0
  38. package/dist/generator/zod-to-openapi/z/integer.js +139 -0
  39. package/dist/generator/zod-to-openapi/z/number.js +45 -0
  40. package/dist/generator/zod-to-openapi/z/object.d.ts +6 -0
  41. package/dist/generator/zod-to-openapi/z/object.js +101 -55
  42. package/dist/generator/zod-to-openapi/z/string.js +38 -0
  43. package/dist/helper/ast.d.ts +15 -31
  44. package/dist/helper/ast.js +314 -7
  45. package/dist/helper/barell.js +32 -0
  46. package/dist/helper/code.js +36 -1
  47. package/dist/helper/core.js +18 -0
  48. package/dist/helper/exports.d.ts +22 -0
  49. package/dist/helper/exports.js +104 -3
  50. package/dist/helper/handler.js +2 -2
  51. package/dist/helper/index.d.ts +0 -1
  52. package/dist/helper/index.js +14 -0
  53. package/dist/helper/openapi.d.ts +40 -3
  54. package/dist/helper/openapi.js +901 -9
  55. package/dist/helper/schema.d.ts +4 -4
  56. package/dist/helper/schema.js +210 -1
  57. package/dist/helper/type.js +232 -0
  58. package/dist/helper/wrap.js +279 -1
  59. package/dist/index.js +2178 -10
  60. package/dist/openapi/index.d.ts +83 -4
  61. package/dist/openapi/index.js +253 -0
  62. package/dist/utils/index.d.ts +1 -78
  63. package/dist/utils/index.js +265 -100
  64. package/dist/vite-plugin/index.js +155 -0
  65. package/package.json +1 -5
package/README.md CHANGED
@@ -91,66 +91,142 @@ export const getRoute = createRoute({
91
91
 
92
92
  ### Options
93
93
 
94
- basic
95
-
96
94
  ```bash
97
95
  Options:
98
- --export-type export TypeScript type aliases
99
- --export-schema export Zod schema objects
100
- --template generate app file and handler stubs
101
- --test generate empty *.test.ts files
102
- --base-path <path> api prefix (default: /)
96
+ --export-schemas-types export schemas types
97
+ --export-schemas export schemas
98
+ --export-parameters-types export parameters types
99
+ --export-parameters export parameters
100
+ --export-security-schemes export securitySchemes
101
+ --export-request-bodies export requestBodies
102
+ --export-responses export responses
103
+ --export-headers-types export headers types
104
+ --export-headers export headers
105
+ --export-examples export examples
106
+ --export-links export links
107
+ --export-callbacks export callbacks
108
+ --template generate app file and handler stubs
109
+ --test generate empty *.test.ts files
110
+ --base-path <path> api prefix (default: /)
111
+ -h, --help display help for command
103
112
  ```
104
113
 
105
- template
106
-
107
- > **⚠️** When using the `--template` option, you must specify a valid directory path. Ensure the directory exists before executing the
108
-
109
114
  ### Example
110
115
 
111
116
  ```bash
112
- npx hono-takibi path/to/input.{yaml,json,tsp} -o path/to/output.ts --export-type --export-schema --template --base-path '/api/v1'
117
+ npx hono-takibi path/to/input.{yaml,json,tsp} -o path/to/output.ts --export-schemas --export-schemas-types --template --base-path '/api/v1'
113
118
  ```
114
119
 
115
120
  ## Configuration File (`hono-takibi.config.ts`)
116
121
 
117
122
  Config used by both the CLI and the Vite plugin.
118
123
 
119
- ## Essentials
120
-
121
- * Put **`hono-takibi.config.ts`** at repo root.
122
- * Default‑export with `defineConfig(...)`.
123
- * `input`: **`openapi.yaml`** (recommended), or `*.json` / `*.tsp`.
124
-
125
- > **About `split`**
126
- >
127
- > * `split: true` → `output` is a **directory**; many files + `index.ts`.
128
- > * `split` **omitted** or `false` → `output` is a **single `*.ts` file** (one file only).
124
+ ### Config Reference
129
125
 
130
- ---
131
-
132
- ## Single‑file
133
-
134
- One file. Set top‑level `output` (don’t define `schema`/`route`).
126
+ All available options are shown below. In practice, use only the options you need.
135
127
 
136
128
  ```ts
129
+ // hono-takibi.config.ts
137
130
  import { defineConfig } from 'hono-takibi/config'
138
131
 
139
132
  export default defineConfig({
140
133
  input: 'openapi.yaml',
141
134
  'zod-openapi': {
142
135
  output: './src/index.ts',
143
- exportSchema: true,
144
- exportType: true,
136
+ exportSchemas: true,
137
+ exportSchemasTypes: true,
138
+ exportParameters: true,
139
+ exportParametersTypes: true,
140
+ exportSecuritySchemes: true,
141
+ exportRequestBodies: true,
142
+ exportResponses: true,
143
+ exportHeaders: true,
144
+ exportHeadersTypes: true,
145
+ exportExamples: true,
146
+ exportLinks: true,
147
+ exportCallbacks: true,
148
+ routes: {
149
+ output: './src/routes',
150
+ split: true,
151
+ },
152
+ components: {
153
+ schemas: {
154
+ output: './src/schemas',
155
+ exportTypes: true,
156
+ split: true,
157
+ import: '../schemas',
158
+ },
159
+ parameters: {
160
+ output: './src/parameters',
161
+ exportTypes: true,
162
+ split: true,
163
+ import: '../parameters',
164
+ },
165
+ securitySchemes: {
166
+ output: './src/securitySchemes',
167
+ split: true,
168
+ import: '../securitySchemes',
169
+ },
170
+ requestBodies: {
171
+ output: './src/requestBodies',
172
+ split: true,
173
+ import: '../requestBodies',
174
+ },
175
+ responses: {
176
+ output: './src/responses',
177
+ split: true,
178
+ import: '../responses',
179
+ },
180
+ headers: {
181
+ output: './src/headers',
182
+ exportTypes: true,
183
+ split: true,
184
+ import: '../headers',
185
+ },
186
+ examples: {
187
+ output: './src/examples',
188
+ split: true,
189
+ import: '../examples',
190
+ },
191
+ links: {
192
+ output: './src/links',
193
+ split: true,
194
+ import: '../links',
195
+ },
196
+ callbacks: {
197
+ output: './src/callbacks',
198
+ split: true,
199
+ import: '../callbacks',
200
+ },
201
+ },
202
+ },
203
+ type: {
204
+ output: './src/types.ts',
205
+ },
206
+ rpc: {
207
+ output: './src/rpc',
208
+ import: '../client',
209
+ split: true,
145
210
  },
146
211
  })
147
212
  ```
148
213
 
214
+ ## Essentials
215
+
216
+ * Put **`hono-takibi.config.ts`** at repo root.
217
+ * Default‑export with `defineConfig(...)`.
218
+ * `input`: **`openapi.yaml`** (recommended), or `*.json` / `*.tsp`.
219
+
220
+ > **About `split`**
221
+ >
222
+ > * `split: true` → `output` is a **directory**; many files + `index.ts`.
223
+ > * `split` **omitted** or `false` → `output` is a **single `*.ts` file** (one file only).
224
+
149
225
  ---
150
226
 
151
- ## Schemas & Routes
227
+ ## Single‑file
152
228
 
153
- Define **both** `schema` and `route` (dont set top‑level `output`).
229
+ One file. Set top‑level `output` (don't define `components`/`routes`).
154
230
 
155
231
  ```ts
156
232
  import { defineConfig } from 'hono-takibi/config'
@@ -158,13 +234,9 @@ import { defineConfig } from 'hono-takibi/config'
158
234
  export default defineConfig({
159
235
  input: 'openapi.yaml',
160
236
  'zod-openapi': {
161
- // split ON → outputs are directories
162
- schema: { output: './src/schemas', split: true },
163
- route: { output: './src/routes', import: '../schemas', split: true },
164
-
165
- // split OFF example (one file each):
166
- // schema: { output: './src/schemas/index.ts' },
167
- // route: { output: './src/routes/index.ts', import: '../schemas' },
237
+ output: './src/index.ts',
238
+ exportSchemas: true,
239
+ exportSchemasTypes: true,
168
240
  },
169
241
  })
170
242
  ```
@@ -178,30 +250,16 @@ Works with either pattern.
178
250
  * `split: true` → `output` is a **directory**; many files + `index.ts`.
179
251
  * `split` **omitted** or `false` → `output` is **one `*.ts` file**.
180
252
 
181
- **Example (split: true)**
182
-
183
253
  ```ts
184
254
  import { defineConfig } from 'hono-takibi/config'
185
255
 
186
256
  export default defineConfig({
187
257
  input: 'openapi.yaml',
188
- 'zod-openapi': { output: './src/index.ts', exportSchema: true, exportType: true },
258
+ 'zod-openapi': { output: './src/index.ts', exportSchemas: true, exportSchemasTypes: true },
189
259
  rpc: { output: './src/rpc', import: '../client', split: true },
190
260
  })
191
261
  ```
192
262
 
193
- **Example (single file; split omitted/false)**
194
-
195
- ```ts
196
- import { defineConfig } from 'hono-takibi/config'
197
-
198
- export default defineConfig({
199
- input: 'openapi.yaml',
200
- 'zod-openapi': { output: './src/index.ts', exportSchema: true, exportType: true },
201
- rpc: { output: './src/rpc/index.ts', import: '../client' },
202
- })
203
- ```
204
-
205
263
  ---
206
264
 
207
265
  ## Vite Plugin (`honoTakibiVite`)
@@ -1,39 +1,3 @@
1
- /**
2
- * Main CLI entry point for hono-takibi.
3
- *
4
- * Processes command-line arguments or config file to generate TypeScript
5
- * code from OpenAPI specifications. Supports both CLI mode and config file mode.
6
- *
7
- * ```mermaid
8
- * flowchart TD
9
- * A["Start"] --> B{"Args: --help/-h?"}
10
- * B -->|Yes| C["Return help text"]
11
- * B -->|No| D{"Config file exists?"}
12
- * D -->|No| E["CLI Mode"]
13
- * D -->|Yes| F["Config Mode"]
14
- * E --> G["parseCli(args)"]
15
- * G --> H["parseOpenAPI(input)"]
16
- * H --> I["takibi(openAPI, ...)"]
17
- * F --> J["config()"]
18
- * J --> K["parseOpenAPI(config.input)"]
19
- * K --> L["Generate all components"]
20
- * L --> M["Return results"]
21
- * I --> M
22
- * ```
23
- *
24
- * @returns Promise resolving to success with output message or error
25
- *
26
- * @example
27
- * ```ts
28
- * // CLI usage
29
- * const result = await honoTakibi()
30
- * if (result.ok) {
31
- * console.log(result.value) // "Generated code written to routes.ts"
32
- * } else {
33
- * console.error(result.error)
34
- * }
35
- * ```
36
- */
37
1
  export declare function honoTakibi(): Promise<{
38
2
  readonly ok: true;
39
3
  readonly value: string;
package/dist/cli/index.js CHANGED
@@ -21,10 +21,9 @@
21
21
  */
22
22
  import { existsSync } from 'node:fs';
23
23
  import { resolve } from 'node:path';
24
- import { loadConfig } from '../config/index.js';
24
+ import { readConfig } from '../config/index.js';
25
25
  import { callbacks, examples, headers, links, parameters, requestBodies, responses, route, rpc, schemas, securitySchemes, takibi, type, } from '../core/index.js';
26
26
  import { parseOpenAPI } from '../openapi/index.js';
27
- import { parseCli } from '../utils/index.js';
28
27
  const HELP_TEXT = `Usage: hono-takibi <input.{yaml,json,tsp}> -o <routes.ts> [options]
29
28
 
30
29
  Options:
@@ -80,6 +79,71 @@ Options:
80
79
  * }
81
80
  * ```
82
81
  */
82
+ /**
83
+ * Parse raw CLI arguments into structured options.
84
+ *
85
+ * - Validates `<input>` ends with `.yaml`/`.json`/`.tsp`
86
+ * - Requires `-o <output.ts>`
87
+ * - Extracts boolean flags for component exports and templates/tests
88
+ * - Extracts optional `--base-path <path>`
89
+ *
90
+ * ```mermaid
91
+ * flowchart TD
92
+ * A["parseCli(args)"] --> B["Extract input & output (-o)"]
93
+ * B --> C{"input endsWith .yaml/.json/.tsp AND output endsWith .ts?"}
94
+ * C -->|No| D["return { ok:false, error:'Usage: hono-takibi ...' }"]
95
+ * C -->|Yes| E["Read flags (--export-schemas-types, --export-schemas, ..., --template, --test)"]
96
+ * E --> F["Read optional --base-path value"]
97
+ * F --> G["return { ok:true, value:{ input, output, flags... } }"]
98
+ * ```
99
+ *
100
+ * @param args - Raw CLI arguments (e.g., `process.argv.slice(2)`).
101
+ * @returns `{ ok:true, value }` on success; `{ ok:false, error }` on invalid usage.
102
+ */
103
+ function parseCli(args) {
104
+ const input = args[0];
105
+ const oIdx = args.indexOf('-o');
106
+ const output = oIdx !== -1 ? args[oIdx + 1] : undefined;
107
+ /** yaml or json or tsp */
108
+ const isYamlOrJsonOrTsp = (i) => i.endsWith('.yaml') || i.endsWith('.json') || i.endsWith('.tsp');
109
+ const isTs = (o) => o.endsWith('.ts');
110
+ const getFlagValue = (args, flag) => {
111
+ const idx = args.indexOf(flag);
112
+ if (idx !== -1 && args[idx + 1] && !args[idx + 1].startsWith('-'))
113
+ return args[idx + 1];
114
+ return undefined;
115
+ };
116
+ if (!(input && output && isYamlOrJsonOrTsp(input) && isTs(output))) {
117
+ return {
118
+ ok: false,
119
+ error: HELP_TEXT,
120
+ };
121
+ }
122
+ return {
123
+ ok: true,
124
+ value: {
125
+ input,
126
+ output,
127
+ template: args.includes('--template'),
128
+ test: args.includes('--test'),
129
+ basePath: getFlagValue(args, '--base-path') ?? '/', // default: /
130
+ componentsOptions: {
131
+ exportSchemas: args.includes('--export-schemas') ?? false,
132
+ exportSchemasTypes: args.includes('--export-schemas-types') ?? false,
133
+ exportParameters: args.includes('--export-parameters') ?? false,
134
+ exportParametersTypes: args.includes('--export-parameters-types') ?? false,
135
+ exportSecuritySchemes: args.includes('--export-security-schemes') ?? false,
136
+ exportRequestBodies: args.includes('--export-request-bodies') ?? false,
137
+ exportResponses: args.includes('--export-responses') ?? false,
138
+ exportHeaders: args.includes('--export-headers') ?? false,
139
+ exportHeadersTypes: args.includes('--export-headers-types') ?? false,
140
+ exportExamples: args.includes('--export-examples') ?? false,
141
+ exportLinks: args.includes('--export-links') ?? false,
142
+ exportCallbacks: args.includes('--export-callbacks') ?? false,
143
+ },
144
+ },
145
+ };
146
+ }
83
147
  export async function honoTakibi() {
84
148
  const args = process.argv.slice(2);
85
149
  if (args.length === 1 && (args[0] === '--help' || args[0] === '-h')) {
@@ -101,7 +165,7 @@ export async function honoTakibi() {
101
165
  return { ok: false, error: takibiResult.error };
102
166
  return { ok: true, value: takibiResult.value };
103
167
  }
104
- const loadConfigResult = await loadConfig();
168
+ const loadConfigResult = await readConfig();
105
169
  if (!loadConfigResult.ok)
106
170
  return { ok: false, error: loadConfigResult.error };
107
171
  const config = loadConfigResult.value;
@@ -204,3 +268,253 @@ export async function honoTakibi() {
204
268
  ].filter((v) => v !== undefined);
205
269
  return { ok: true, value: results.join('\n') };
206
270
  }
271
+ // Test run
272
+ // pnpm vitest run ./packages/hono-takibi/src/cli/index.ts
273
+ if (import.meta.vitest) {
274
+ const { describe, it, expect, beforeAll, afterAll } = import.meta.vitest;
275
+ const fs = await import('node:fs');
276
+ const openapi = {
277
+ openapi: '3.1.0',
278
+ info: {
279
+ title: 'HonoTakibi',
280
+ version: 'v1',
281
+ },
282
+ tags: [{ name: 'Hono' }, { name: 'HonoX' }, { name: 'ZodOpenAPIHono' }],
283
+ paths: {
284
+ '/hono': {
285
+ get: {
286
+ tags: ['Hono'],
287
+ summary: 'Hono',
288
+ description: 'Hono',
289
+ responses: {
290
+ '200': {
291
+ description: 'OK',
292
+ content: {
293
+ 'application/json': {
294
+ schema: {
295
+ type: 'object',
296
+ properties: {
297
+ message: {
298
+ type: 'string',
299
+ example: 'Hono',
300
+ },
301
+ },
302
+ required: ['message'],
303
+ },
304
+ },
305
+ },
306
+ },
307
+ },
308
+ },
309
+ },
310
+ '/hono-x': {
311
+ get: {
312
+ tags: ['HonoX'],
313
+ summary: 'HonoX',
314
+ description: 'HonoX',
315
+ responses: {
316
+ '200': {
317
+ description: 'OK',
318
+ content: {
319
+ 'application/json': {
320
+ schema: {
321
+ type: 'object',
322
+ properties: {
323
+ message: {
324
+ type: 'string',
325
+ example: 'HonoX',
326
+ },
327
+ },
328
+ required: ['message'],
329
+ },
330
+ },
331
+ },
332
+ },
333
+ },
334
+ },
335
+ },
336
+ '/zod-openapi-hono': {
337
+ get: {
338
+ tags: ['ZodOpenAPIHono'],
339
+ summary: 'ZodOpenAPIHono',
340
+ description: 'ZodOpenAPIHono',
341
+ responses: {
342
+ '200': {
343
+ description: 'OK',
344
+ content: {
345
+ 'application/json': {
346
+ schema: {
347
+ type: 'object',
348
+ properties: {
349
+ message: {
350
+ type: 'string',
351
+ example: 'ZodOpenAPIHono',
352
+ },
353
+ },
354
+ required: ['message'],
355
+ },
356
+ },
357
+ },
358
+ },
359
+ },
360
+ },
361
+ },
362
+ },
363
+ };
364
+ describe('honoTakibi', () => {
365
+ beforeAll(() => {
366
+ process.argv = [
367
+ '*/*/bin/node',
368
+ '*/dist/index.js',
369
+ 'openapi.json',
370
+ '-o',
371
+ 'zod-openapi-hono.ts',
372
+ ];
373
+ fs.writeFileSync('openapi.json', JSON.stringify(openapi));
374
+ });
375
+ afterAll(() => {
376
+ fs.rmSync('openapi.json', { force: true });
377
+ fs.rmSync('zod-openapi-hono.ts', { force: true });
378
+ });
379
+ it('honoTakibi generated', async () => {
380
+ const result = await honoTakibi();
381
+ expect(result).toEqual({
382
+ ok: true,
383
+ value: 'Generated code written to zod-openapi-hono.ts',
384
+ });
385
+ const generatedCode = fs.readFileSync('zod-openapi-hono.ts', 'utf-8');
386
+ const expectedCode = `import { createRoute, z } from '@hono/zod-openapi'
387
+
388
+ export const getHonoRoute = createRoute({
389
+ method: 'get',
390
+ path: '/hono',
391
+ tags: ['Hono'],
392
+ summary: 'Hono',
393
+ description: 'Hono',
394
+ responses: {
395
+ 200: {
396
+ description: 'OK',
397
+ content: {
398
+ 'application/json': {
399
+ schema: z
400
+ .object({ message: z.string().openapi({ example: 'Hono' }) })
401
+ .openapi({ required: ['message'] }),
402
+ },
403
+ },
404
+ },
405
+ },
406
+ })
407
+
408
+ export const getHonoXRoute = createRoute({
409
+ method: 'get',
410
+ path: '/hono-x',
411
+ tags: ['HonoX'],
412
+ summary: 'HonoX',
413
+ description: 'HonoX',
414
+ responses: {
415
+ 200: {
416
+ description: 'OK',
417
+ content: {
418
+ 'application/json': {
419
+ schema: z
420
+ .object({ message: z.string().openapi({ example: 'HonoX' }) })
421
+ .openapi({ required: ['message'] }),
422
+ },
423
+ },
424
+ },
425
+ },
426
+ })
427
+
428
+ export const getZodOpenapiHonoRoute = createRoute({
429
+ method: 'get',
430
+ path: '/zod-openapi-hono',
431
+ tags: ['ZodOpenAPIHono'],
432
+ summary: 'ZodOpenAPIHono',
433
+ description: 'ZodOpenAPIHono',
434
+ responses: {
435
+ 200: {
436
+ description: 'OK',
437
+ content: {
438
+ 'application/json': {
439
+ schema: z
440
+ .object({ message: z.string().openapi({ example: 'ZodOpenAPIHono' }) })
441
+ .openapi({ required: ['message'] }),
442
+ },
443
+ },
444
+ },
445
+ },
446
+ })
447
+ `;
448
+ expect(generatedCode).toBe(expectedCode);
449
+ });
450
+ });
451
+ describe('honoTakibi --help', () => {
452
+ beforeAll(() => {
453
+ process.argv = ['*/*/bin/node', '*/dist/index.js', '--help'];
454
+ });
455
+ it('honoTakibi help requested --help', async () => {
456
+ const result = await honoTakibi();
457
+ expect(result).toStrictEqual({
458
+ ok: true,
459
+ value: `Usage: hono-takibi <input.{yaml,json,tsp}> -o <routes.ts> [options]
460
+
461
+ Options:
462
+ --export-schemas-types export schemas types
463
+ --export-schemas export schemas
464
+ --export-parameters-types export parameters types
465
+ --export-parameters export parameters
466
+ --export-security-schemes export securitySchemes
467
+ --export-request-bodies export requestBodies
468
+ --export-responses export responses
469
+ --export-headers-types export headers types
470
+ --export-headers export headers
471
+ --export-examples export examples
472
+ --export-links export links
473
+ --export-callbacks export callbacks
474
+ --template generate app file and handler stubs
475
+ --test generate empty *.test.ts files
476
+ --base-path <path> api prefix (default: /)
477
+ -h, --help display help for command`,
478
+ });
479
+ });
480
+ });
481
+ describe('honoTakibi -h', () => {
482
+ beforeAll(() => {
483
+ process.argv = ['*/*/bin/node', '*/dist/index.js', '-h'];
484
+ });
485
+ it('honoTakibi help requested -h', async () => {
486
+ const result = await honoTakibi();
487
+ expect(result).toStrictEqual({
488
+ ok: true,
489
+ value: `Usage: hono-takibi <input.{yaml,json,tsp}> -o <routes.ts> [options]
490
+
491
+ Options:
492
+ --export-schemas-types export schemas types
493
+ --export-schemas export schemas
494
+ --export-parameters-types export parameters types
495
+ --export-parameters export parameters
496
+ --export-security-schemes export securitySchemes
497
+ --export-request-bodies export requestBodies
498
+ --export-responses export responses
499
+ --export-headers-types export headers types
500
+ --export-headers export headers
501
+ --export-examples export examples
502
+ --export-links export links
503
+ --export-callbacks export callbacks
504
+ --template generate app file and handler stubs
505
+ --test generate empty *.test.ts files
506
+ --base-path <path> api prefix (default: /)
507
+ -h, --help display help for command`,
508
+ });
509
+ });
510
+ describe('honoTakibi missing output', () => {
511
+ beforeAll(() => {
512
+ process.argv = ['node', 'dist/index.js', 'openapi.yaml'];
513
+ });
514
+ it('should fail if output is not specified', async () => {
515
+ const result = await honoTakibi();
516
+ expect(result.ok).toBe(false);
517
+ });
518
+ });
519
+ });
520
+ }
@@ -85,7 +85,7 @@ export declare function parseConfig(config: Config): {
85
85
  readonly ok: false;
86
86
  readonly error: string;
87
87
  };
88
- export declare function loadConfig(): Promise<{
88
+ export declare function readConfig(): Promise<{
89
89
  readonly ok: true;
90
90
  readonly value: Config;
91
91
  } | {
@@ -225,7 +225,7 @@ export function parseConfig(config) {
225
225
  }
226
226
  return { ok: true, value: config };
227
227
  }
228
- export async function loadConfig() {
228
+ export async function readConfig() {
229
229
  const abs = resolve(process.cwd(), 'hono-takibi.config.ts');
230
230
  if (!existsSync(abs))
231
231
  return { ok: false, error: `Config not found: ${abs}` };
@@ -252,3 +252,64 @@ export async function loadConfig() {
252
252
  export function defineConfig(config) {
253
253
  return config;
254
254
  }
255
+ // Test run
256
+ // pnpm vitest run ./packages/hono-takibi/src/config/index.ts
257
+ if (import.meta.vitest) {
258
+ const { describe, it, expect, beforeEach, afterEach, vi } = import.meta.vitest;
259
+ const fs = await import('node:fs');
260
+ const os = await import('node:os');
261
+ const path = await import('node:path');
262
+ describe('loadConfig()', () => {
263
+ const origCwd = process.cwd();
264
+ beforeEach(() => {
265
+ vi.resetModules();
266
+ const tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'hono-takibi-config-ts-'));
267
+ process.chdir(tmpdir);
268
+ });
269
+ afterEach(() => {
270
+ const cwd = process.cwd();
271
+ process.chdir(origCwd);
272
+ fs.rmSync(cwd, { recursive: true, force: true });
273
+ });
274
+ it('passes: legacy top-level output mode', async () => {
275
+ const p = path.join(process.cwd(), 'hono-takibi.config.ts');
276
+ const c = `
277
+ export default {
278
+ input: 'openapi.yaml',
279
+ 'zod-openapi': {
280
+ output: 'routes/index.ts',
281
+ exportSchemasTypes: true,
282
+ exportSchemas: true
283
+ },
284
+ rpc: {
285
+ output: 'rpc/index.ts',
286
+ import: '../client'
287
+ }
288
+ }
289
+ `;
290
+ fs.writeFileSync(p, c, 'utf-8');
291
+ await expect(readConfig()).resolves.toStrictEqual({
292
+ ok: true,
293
+ value: {
294
+ input: 'openapi.yaml',
295
+ 'zod-openapi': {
296
+ output: 'routes/index.ts',
297
+ exportSchemasTypes: true,
298
+ exportSchemas: true,
299
+ },
300
+ rpc: {
301
+ output: 'rpc/index.ts',
302
+ import: '../client',
303
+ },
304
+ },
305
+ });
306
+ });
307
+ it('fails: config file missing', async () => {
308
+ const result = await readConfig();
309
+ expect(result.ok).toBe(false);
310
+ if (!result.ok) {
311
+ expect(result.error).toMatch(/Config not found:/);
312
+ }
313
+ });
314
+ });
315
+ }