hono-takibi 0.9.51 → 0.9.60

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.
package/dist/cli/index.js CHANGED
@@ -72,9 +72,8 @@ export async function honoTakibi() {
72
72
  return { ok: false, error: cliResult.error };
73
73
  const cli = cliResult.value;
74
74
  const takibiResult = await takibi(cli.input, cli.output, cli.exportSchema ?? false, cli.exportType ?? false, cli.template ?? false, cli.test ?? false, cli.basePath);
75
- if (!takibiResult.ok) {
75
+ if (!takibiResult.ok)
76
76
  return { ok: false, error: takibiResult.error };
77
- }
78
77
  return {
79
78
  ok: true,
80
79
  value: takibiResult.value,
@@ -91,30 +90,26 @@ export async function honoTakibi() {
91
90
  ? await takibi(c.input, c['zod-openapi']?.output, c['zod-openapi']?.exportSchema ?? false, c['zod-openapi']?.exportType ?? false, false, // template
92
91
  false)
93
92
  : undefined;
94
- if (takibiResult && !takibiResult.ok) {
93
+ if (takibiResult && !takibiResult.ok)
95
94
  return { ok: false, error: takibiResult.error };
96
- }
97
95
  /** schema */
98
96
  const schemaResult = c['zod-openapi']?.schema
99
97
  ? await schema(c.input, c['zod-openapi'].schema.output, c['zod-openapi'].schema.exportType ?? false, c['zod-openapi']?.schema.split ?? false)
100
98
  : undefined;
101
- if (schemaResult && !schemaResult.ok) {
99
+ if (schemaResult && !schemaResult.ok)
102
100
  return { ok: false, error: schemaResult.error };
103
- }
104
101
  /** route */
105
102
  const routeResult = c['zod-openapi']?.route
106
103
  ? await route(c.input, c['zod-openapi'].route.output, c['zod-openapi'].route.import, c['zod-openapi'].route.split ?? false)
107
104
  : undefined;
108
- if (routeResult && !routeResult.ok) {
105
+ if (routeResult && !routeResult.ok)
109
106
  return { ok: false, error: routeResult.error };
110
- }
111
107
  /** rpc */
112
108
  const rpcResult = c.rpc
113
109
  ? await rpc(c.input, c.rpc.output, c.rpc.import, c.rpc.split ?? false)
114
110
  : undefined;
115
- if (rpcResult && !rpcResult.ok) {
111
+ if (rpcResult && !rpcResult.ok)
116
112
  return { ok: false, error: rpcResult.error };
117
- }
118
113
  const results = [takibiResult?.value, rpcResult?.value].filter((v) => Boolean(v));
119
114
  return {
120
115
  ok: true,
@@ -11,9 +11,8 @@ export async function config() {
11
11
  register();
12
12
  const url = pathToFileURL(abs).href;
13
13
  const mod = await import(/* @vite-ignore */ url);
14
- if (!('default' in mod) || mod.default === undefined) {
14
+ if (!('default' in mod) || mod.default === undefined)
15
15
  return { ok: false, error: 'Config must export default object' };
16
- }
17
16
  const result = parseConfig(mod.default);
18
17
  if (!result.ok)
19
18
  return { ok: false, error: result.error };
@@ -24,9 +24,8 @@ const extractRouteBlocks = (src) => {
24
24
  const lowerFirst = (s) => (s ? s.charAt(0).toLowerCase() + s.slice(1) : s);
25
25
  export async function route(input, output, importPath, split) {
26
26
  const openAPIResult = await parseOpenAPI(input);
27
- if (!openAPIResult.ok) {
27
+ if (!openAPIResult.ok)
28
28
  return { ok: false, error: openAPIResult.error };
29
- }
30
29
  const openAPI = openAPIResult.value;
31
30
  const routesSrc = routeCode(openAPI.paths);
32
31
  if (!split) {
@@ -42,9 +41,9 @@ export async function route(input, output, importPath, split) {
42
41
  if (!mkdirResult.ok)
43
42
  return { ok: false, error: mkdirResult.error };
44
43
  const writeResult = await writeFile(output, fmtResult.value);
45
- return writeResult.ok
46
- ? { ok: true, value: `Generated route code written to ${output}` }
47
- : { ok: false, error: writeResult.error };
44
+ if (!writeResult.ok)
45
+ return { ok: false, error: writeResult.error };
46
+ return { ok: true, value: `Generated route code written to ${output}` };
48
47
  }
49
48
  const outDir = output.replace(/\.ts$/, '');
50
49
  const blocks = extractRouteBlocks(routesSrc);
@@ -61,9 +60,9 @@ export async function route(input, output, importPath, split) {
61
60
  if (!mkdirResult.ok)
62
61
  return { ok: false, error: mkdirResult.error };
63
62
  const writeResult = await writeFile(output, fmtResult.value);
64
- return writeResult.ok
65
- ? { ok: true, value: `Generated route code written to ${output}` }
66
- : { ok: false, error: writeResult.error };
63
+ if (!writeResult.ok)
64
+ return { ok: false, error: writeResult.error };
65
+ return { ok: true, value: `Generated route code written to ${output}` };
67
66
  }
68
67
  for (const { name, block } of blocks) {
69
68
  const includeZ = block.includes('z.');
package/dist/core/rpc.js CHANGED
@@ -236,9 +236,15 @@ const generateOperationCode = (pathStr, method, item, deps) => {
236
236
  : `${deps.client}${clientAccess}.$${method}()`;
237
237
  const summary = typeof op.summary === 'string' ? op.summary : '';
238
238
  const description = typeof op.description === 'string' ? op.description : '';
239
- const summaryBlock = summary ? ` * ${summary}\n *\n` : '';
240
- const descriptionBlock = description ? ` * ${description}\n *\n` : '';
241
- return `/**\n${summaryBlock}${descriptionBlock} * ${method.toUpperCase()} ${pathStr}\n */\nexport async function ${funcName}(${argSig}){return await ${call}}`;
239
+ const docs = [
240
+ '/**',
241
+ ` * ${method.toUpperCase()} ${pathStr}`,
242
+ ...(summary ? [' *', ` * ${summary.trimEnd()}`] : []),
243
+ ...(description ? [' *', ` * ${description.trimEnd()}`] : []),
244
+ ' */',
245
+ ].join('\n');
246
+ const func = `export async function ${funcName}(${argSig}){return await ${call}}`;
247
+ return `${docs}\n${func}`;
242
248
  };
243
249
  /* ─────────────────────────────── Split ─────────────────────────────── */
244
250
  const resolveSplitOutDir = (output) => {
@@ -256,9 +262,8 @@ const resolveSplitOutDir = (output) => {
256
262
  */
257
263
  export async function rpc(input, output, importPath, split) {
258
264
  const openAPIResult = await parseOpenAPI(input);
259
- if (!openAPIResult.ok) {
265
+ if (!openAPIResult.ok)
260
266
  return { ok: false, error: openAPIResult.error };
261
- }
262
267
  const openAPI = openAPIResult.value;
263
268
  const client = 'client';
264
269
  const s = `import { client } from '${importPath}'`;
@@ -309,12 +314,12 @@ export async function rpc(input, output, importPath, split) {
309
314
  return { ok: false, error: fmtResult.error };
310
315
  const { outDir } = resolveSplitOutDir(output);
311
316
  const filePath = path.join(outDir, `${funcName}.ts`);
312
- const mk = await mkdir(path.dirname(filePath));
313
- if (!mk.ok)
314
- return { ok: false, error: mk.error };
315
- const wr = await writeFile(filePath, fmtResult.value);
316
- if (!wr.ok)
317
- return { ok: false, error: wr.error };
317
+ const mkdirResult = await mkdir(path.dirname(filePath));
318
+ if (!mkdirResult.ok)
319
+ return { ok: false, error: mkdirResult.error };
320
+ const writeResult = await writeFile(filePath, fmtResult.value);
321
+ if (!writeResult.ok)
322
+ return { ok: false, error: writeResult.error };
318
323
  splitExports.add(`export * from './${funcName}'`);
319
324
  }
320
325
  else {
@@ -324,9 +329,9 @@ export async function rpc(input, output, importPath, split) {
324
329
  }
325
330
  // Non-split: write single file
326
331
  if (!split) {
327
- const mk = await mkdir(path.dirname(output));
328
- if (!mk.ok)
329
- return { ok: false, error: mk.error };
332
+ const mkdirResult = await mkdir(path.dirname(output));
333
+ if (!mkdirResult.ok)
334
+ return { ok: false, error: mkdirResult.error };
330
335
  const code = `${header}${combinedOut.join('\n\n')}${combinedOut.length ? '\n' : ''}`;
331
336
  const fmtResult = await fmt(code);
332
337
  if (!fmtResult.ok)
@@ -338,8 +343,8 @@ export async function rpc(input, output, importPath, split) {
338
343
  }
339
344
  // Split: write index.ts (barrel)
340
345
  const { outDir, indexPath } = resolveSplitOutDir(output);
341
- const indexBody = `${Array.from(splitExports).sort().join('\n')}\n`;
342
- const fmtResult = await fmt(indexBody);
346
+ const index = `${Array.from(splitExports).sort().join('\n')}\n`;
347
+ const fmtResult = await fmt(index);
343
348
  if (!fmtResult.ok)
344
349
  return { ok: false, error: fmtResult.error };
345
350
  const mkdirResult = await mkdir(path.dirname(indexPath));
@@ -43,9 +43,8 @@ export async function schema(input, output, exportType, split) {
43
43
  }
44
44
  const openAPI = openAPIResult.value;
45
45
  const { schemas } = openAPI.components ? openAPI.components : {};
46
- if (!schemas) {
46
+ if (!schemas)
47
47
  return { ok: false, error: 'No schemas found' };
48
- }
49
48
  // split
50
49
  if (split) {
51
50
  const outDir = output.replace(/\.ts$/, '');
@@ -60,37 +59,31 @@ export async function schema(input, output, exportType, split) {
60
59
  ? deps.map((d) => `import { ${d}Schema } from './${lowerFirst(d)}'`).join('\n')
61
60
  : '';
62
61
  const fileCode = [importZ, depImports, '\n', zs].filter(Boolean).join('\n');
62
+ const filePath = `${outDir}/${lowerFirst(schemaName)}.ts`;
63
63
  const fmtResult = await fmt(fileCode);
64
- if (!fmtResult.ok) {
64
+ if (!fmtResult.ok)
65
65
  return { ok: false, error: fmtResult.error };
66
- }
67
- const filePath = `${outDir}/${lowerFirst(schemaName)}.ts`;
68
66
  const mkdirResult = await mkdir(path.dirname(filePath));
69
- if (!mkdirResult.ok) {
67
+ if (!mkdirResult.ok)
70
68
  return { ok: false, error: mkdirResult.error };
71
- }
72
69
  const writeResult = await writeFile(filePath, fmtResult.value);
73
- if (!writeResult.ok) {
70
+ if (!writeResult.ok)
74
71
  return { ok: false, error: writeResult.error };
75
- }
76
72
  }
77
73
  // index.ts
78
- const indexBody = `${Object.keys(schemas)
74
+ const index = `${Object.keys(schemas)
79
75
  .sort()
80
76
  .map((n) => `export * from './${lowerFirst(n)}'`)
81
77
  .join('\n')}\n`;
82
- const fmtResult = await fmt(indexBody);
83
- if (!fmtResult.ok) {
78
+ const fmtResult = await fmt(index);
79
+ if (!fmtResult.ok)
84
80
  return { ok: false, error: fmtResult.error };
85
- }
86
81
  const mkdirResult = await mkdir(path.dirname(`${outDir}/index.ts`));
87
- if (!mkdirResult.ok) {
82
+ if (!mkdirResult.ok)
88
83
  return { ok: false, error: mkdirResult.error };
89
- }
90
84
  const writeResult = await writeFile(`${outDir}/index.ts`, fmtResult.value);
91
- if (!writeResult.ok) {
85
+ if (!writeResult.ok)
92
86
  return { ok: false, error: writeResult.error };
93
- }
94
87
  return {
95
88
  ok: true,
96
89
  value: `Generated schema code written to ${outDir}/*.ts (index.ts included)`,
@@ -110,16 +103,13 @@ export async function schema(input, output, exportType, split) {
110
103
  const importCode = `import { z } from '@hono/zod-openapi'`;
111
104
  const schemaDefinitionsCode = `${importCode}\n\n${schemaDefinitions}`;
112
105
  const fmtResult = await fmt(schemaDefinitionsCode);
113
- if (!fmtResult.ok) {
106
+ if (!fmtResult.ok)
114
107
  return { ok: false, error: fmtResult.error };
115
- }
116
108
  const mkdirResult = await mkdir(path.dirname(output));
117
- if (!mkdirResult.ok) {
109
+ if (!mkdirResult.ok)
118
110
  return { ok: false, error: mkdirResult.error };
119
- }
120
111
  const writeResult = await writeFile(output, fmtResult.value);
121
- if (!writeResult.ok) {
112
+ if (!writeResult.ok)
122
113
  return { ok: false, error: writeResult.error };
123
- }
124
114
  return { ok: true, value: `Generated schema code written to ${output}` };
125
115
  }
@@ -53,49 +53,46 @@ import { isHttpMethod, methodPath } from '../utils/index.js';
53
53
  * @returns A `Result` containing a success message or an error string.
54
54
  */
55
55
  export async function takibi(input, output, exportSchema, exportType, template, test, basePath) {
56
- const openAPIResult = await parseOpenAPI(input);
57
- if (!openAPIResult.ok) {
58
- return { ok: false, error: openAPIResult.error };
59
- }
60
- const openAPI = openAPIResult.value;
61
- const honoResult = await fmt(zodOpenAPIHono(openAPI, exportSchema, exportType));
62
- if (!honoResult.ok) {
63
- return { ok: false, error: honoResult.error };
64
- }
65
- const mkdirResult = await mkdir(path.dirname(output));
66
- if (!mkdirResult.ok) {
67
- return { ok: false, error: mkdirResult.error };
68
- }
69
- const writeResult = await writeFile(output, honoResult.value);
70
- if (!writeResult.ok) {
71
- return { ok: false, error: writeResult.error };
72
- }
73
- /** template */
74
- if (template && output.includes('/')) {
75
- const appResult = await fmt(app(openAPI, output, basePath));
76
- if (!appResult.ok) {
77
- return { ok: false, error: appResult.error };
78
- }
79
- const dir = path.dirname(output);
80
- const readdirResult = await readdir(dir);
81
- if (!readdirResult.ok) {
82
- return { ok: false, error: readdirResult.error };
83
- }
84
- const target = path.join(dir, 'index.ts');
85
- const writeResult = await writeFile(target, appResult.value);
86
- if (!writeResult.ok) {
56
+ try {
57
+ const openAPIResult = await parseOpenAPI(input);
58
+ if (!openAPIResult.ok)
59
+ return { ok: false, error: openAPIResult.error };
60
+ const openAPI = openAPIResult.value;
61
+ const honoResult = await fmt(zodOpenAPIHono(openAPI, exportSchema, exportType));
62
+ if (!honoResult.ok)
63
+ return { ok: false, error: honoResult.error };
64
+ const mkdirResult = await mkdir(path.dirname(output));
65
+ if (!mkdirResult.ok)
66
+ return { ok: false, error: mkdirResult.error };
67
+ const writeResult = await writeFile(output, honoResult.value);
68
+ if (!writeResult.ok)
87
69
  return { ok: false, error: writeResult.error };
70
+ /** template */
71
+ if (template && output.includes('/')) {
72
+ const appResult = await fmt(app(openAPI, output, basePath));
73
+ if (!appResult.ok)
74
+ return { ok: false, error: appResult.error };
75
+ const dir = path.dirname(output);
76
+ const readdirResult = await readdir(dir);
77
+ if (!readdirResult.ok)
78
+ return { ok: false, error: readdirResult.error };
79
+ const target = path.join(dir, 'index.ts');
80
+ const writeResult = await writeFile(target, appResult.value);
81
+ if (!writeResult.ok)
82
+ return { ok: false, error: writeResult.error };
83
+ const zodOpenapiHonoHandlerResult = await zodOpenapiHonoHandler(openAPI, output, test);
84
+ if (!zodOpenapiHonoHandlerResult.ok)
85
+ return { ok: false, error: zodOpenapiHonoHandlerResult.error };
86
+ return { ok: true, value: 'Generated code and template files written' };
88
87
  }
89
- const zodOpenapiHonoHandlerResult = await zodOpenapiHonoHandler(openAPI, output, test);
90
- if (!zodOpenapiHonoHandlerResult.ok) {
91
- return { ok: false, error: zodOpenapiHonoHandlerResult.error };
92
- }
93
- return { ok: true, value: 'Generated code and template files written' };
88
+ return {
89
+ ok: true,
90
+ value: `Generated code written to ${output}`,
91
+ };
92
+ }
93
+ catch (e) {
94
+ return { ok: false, error: e instanceof Error ? e.message : String(e) };
94
95
  }
95
- return {
96
- ok: true,
97
- value: `Generated code written to ${output}`,
98
- };
99
96
  }
100
97
  /**
101
98
  * Generates route handler files for a Hono app using Zod and OpenAPI.
@@ -156,10 +153,7 @@ async function zodOpenapiHonoHandler(openapi, output, test) {
156
153
  const importFrom = `../${routeEntryBasename.replace(/\.ts$/, '')}`;
157
154
  const mkdirResult = await mkdir(handlerPath);
158
155
  if (!mkdirResult.ok)
159
- return {
160
- ok: false,
161
- error: mkdirResult.error,
162
- };
156
+ return { ok: false, error: mkdirResult.error };
163
157
  for (const handler of mergedHandlers) {
164
158
  const routeTypes = Array.from(new Set(handler.routeNames)).join(', ');
165
159
  const importRouteTypes = routeTypes ? `import type { ${routeTypes} } from '${importFrom}';` : '';
@@ -167,38 +161,23 @@ async function zodOpenapiHonoHandler(openapi, output, test) {
167
161
  const fileContent = `${importStatements}\n\n${handler.routeHandlerContents.join('\n\n')}`;
168
162
  const fmtResult = await fmt(fileContent);
169
163
  if (!fmtResult.ok)
170
- return {
171
- ok: false,
172
- error: fmtResult.error,
173
- };
164
+ return { ok: false, error: fmtResult.error };
174
165
  const writeResult = await writeFile(`${handlerPath}/${handler.fileName}`, fmtResult.value);
175
166
  if (!writeResult.ok)
176
- return {
177
- ok: false,
178
- error: writeResult.error,
179
- };
167
+ return { ok: false, error: writeResult.error };
180
168
  if (test) {
181
169
  const writeResult = await writeFile(`${handlerPath}/${handler.testFileName}`, '');
182
170
  if (!writeResult.ok)
183
- return {
184
- ok: false,
185
- error: writeResult.error,
186
- };
171
+ return { ok: false, error: writeResult.error };
187
172
  }
188
173
  }
189
174
  const sorted = mergedHandlers.map((h) => h.fileName).sort();
190
175
  const exports = sorted.map((h) => `export * from './${h}'`).join('\n');
191
176
  const fmtResult = await fmt(exports);
192
177
  if (!fmtResult.ok)
193
- return {
194
- ok: false,
195
- error: fmtResult.error,
196
- };
178
+ return { ok: false, error: fmtResult.error };
197
179
  const writeResult = await writeFile(`${handlerPath}/index.ts`, fmtResult.value);
198
180
  if (!writeResult.ok)
199
- return {
200
- ok: false,
201
- error: writeResult.error,
202
- };
181
+ return { ok: false, error: writeResult.error };
203
182
  return { ok: true, value: undefined };
204
183
  }
@@ -1,24 +1,26 @@
1
1
  export function _enum(schema) {
2
- /* -------------------------- helpers -------------------------- */
2
+ /* hasType */
3
3
  const hasType = (t) => schema.type === t || (Array.isArray(schema.type) && schema.type.some((x) => x === t));
4
+ /* lit */
4
5
  const lit = (v) => v === null ? 'null' : typeof v === 'string' ? `'${v}'` : String(v);
6
+ /* tuple */
5
7
  const tuple = (arr) => `z.tuple([${arr.map((i) => `z.literal(${lit(i)})`).join(',')}])`;
6
- /* --------------------------- guard --------------------------- */
8
+ /* guard */
7
9
  if (!schema.enum || schema.enum.length === 0)
8
10
  return 'z.any()';
9
- /* ------------------- number / integer enum ------------------- */
11
+ /* number / integer enum */
10
12
  if (hasType('number') || hasType('integer')) {
11
13
  return schema.enum.length > 1
12
14
  ? `z.union([${schema.enum.map((v) => `z.literal(${v})`).join(',')}])`
13
15
  : `z.literal(${schema.enum[0]})`;
14
16
  }
15
- /* ----------------------- boolean enum ------------------------ */
17
+ /* boolean enum */
16
18
  if (hasType('boolean')) {
17
19
  return schema.enum.length > 1
18
20
  ? `z.union([${schema.enum.map((v) => `z.literal(${v})`).join(',')}])`
19
21
  : `z.literal(${schema.enum[0]})`;
20
22
  }
21
- /* ----------------------- array enum -------------------------- */
23
+ /* array enum */
22
24
  if (hasType('array')) {
23
25
  if (schema.enum.length === 1 && Array.isArray(schema.enum[0])) {
24
26
  return tuple(schema.enum[0]);
@@ -26,13 +28,13 @@ export function _enum(schema) {
26
28
  const parts = schema.enum.map((v) => (Array.isArray(v) ? tuple(v) : `z.literal(${lit(v)})`));
27
29
  return `z.union([${parts.join(',')}])`;
28
30
  }
29
- /* ----------------------- string enum ------------------------- */
31
+ /* string enum */
30
32
  if (schema.enum.every((v) => typeof v === 'string')) {
31
33
  return schema.enum.length > 1
32
34
  ? `z.enum(${JSON.stringify(schema.enum)})`
33
35
  : `z.literal('${schema.enum[0]}')`;
34
36
  }
35
- /* -------------------- mixed / null only ---------------------- */
37
+ /* mixed / null only */
36
38
  if (schema.enum.length > 1) {
37
39
  const parts = schema.enum.map((v) => `z.literal(${lit(v)})`);
38
40
  return `z.union([${parts.join(',')}])`;
@@ -1,10 +1,10 @@
1
1
  export function wrap(zod, schema, paramName, paramIn) {
2
2
  const formatLiteral = (v) => {
3
- // boolean true or false
3
+ /* boolean true or false */
4
4
  if (typeof v === 'boolean') {
5
5
  return `${v}`;
6
6
  }
7
- // number
7
+ /* number */
8
8
  if (typeof v === 'number') {
9
9
  if (schema.format === 'int64') {
10
10
  return `${v}n`;
@@ -14,18 +14,18 @@ export function wrap(zod, schema, paramName, paramIn) {
14
14
  }
15
15
  return `${v}`;
16
16
  }
17
- // date
17
+ /* date */
18
18
  if (schema.type === 'date' && typeof v === 'string') {
19
19
  return `new Date(${JSON.stringify(v)})`;
20
20
  }
21
- // string
21
+ /* string */
22
22
  if (typeof v === 'string') {
23
23
  return JSON.stringify(v);
24
24
  }
25
- // other
25
+ /* other */
26
26
  return JSON.stringify(v);
27
27
  };
28
- // why schema.default !== undefined becasue schema.default === 0 // → falsy
28
+ /* why schema.default !== undefined becasue schema.default === 0 // → falsy */
29
29
  const s = schema.default !== undefined ? `${zod}.default(${formatLiteral(schema.default)})` : zod;
30
30
  const isNullable = schema.nullable === true ||
31
31
  (Array.isArray(schema.type) ? schema.type.includes('null') : schema.type === 'null');
@@ -35,15 +35,15 @@ export function wrap(zod, schema, paramName, paramIn) {
35
35
  const required = paramIn === 'path' ? true : !!schema.required;
36
36
  openapiProps.push(`param:{in:"${paramIn}",name:${JSON.stringify(paramName)},required:${required}}`);
37
37
  }
38
- // Add 'example' if defined
38
+ /* 'example' if defined */
39
39
  if ('example' in schema && schema.example !== undefined) {
40
40
  openapiProps.push(`example:${JSON.stringify(schema.example)}`);
41
41
  }
42
- // Add 'examples' if defined
42
+ /* 'examples' if defined */
43
43
  if ('examples' in schema && Array.isArray(schema.examples) && schema.examples.length > 0) {
44
44
  openapiProps.push(`examples:${JSON.stringify(schema.examples)}`);
45
45
  }
46
- // Add 'description' if defined
46
+ /* 'description' if defined */
47
47
  if ('description' in schema && schema.description !== undefined) {
48
48
  openapiProps.push(`description:${JSON.stringify(schema.description)}`);
49
49
  }
@@ -1,5 +1,5 @@
1
1
  import path from 'node:path';
2
- import { compile, logDiagnostics, NodeHost } from '@typespec/compiler';
2
+ import { compile, NodeHost } from '@typespec/compiler';
3
3
  import { getOpenAPI3 } from '@typespec/openapi3';
4
4
  /**
5
5
  * Compiles a TypeSpec (`.tsp`) file and returns the generated OpenAPI document.
@@ -32,7 +32,8 @@ export async function typeSpecToOpenAPI(input) {
32
32
  noEmit: true,
33
33
  });
34
34
  if (program.diagnostics.length) {
35
- logDiagnostics(program.diagnostics, program.host.logSink);
35
+ // logDiagnostics(program.diagnostics, program.host.logSink)
36
+ console.log(JSON.stringify(program.diagnostics, null, 2));
36
37
  return {
37
38
  ok: false,
38
39
  error: 'TypeSpec compile failed',
@@ -88,19 +88,6 @@ export declare function parseCli(args: readonly string[]): {
88
88
  /**
89
89
  * Normalize a JSON Schema `type` value into an array of type strings.
90
90
  *
91
- * - `undefined` → `[]`
92
- * - `'string'` → `['string']`
93
- * - `['string','number']` → unchanged
94
- *
95
- * ```mermaid
96
- * graph TD
97
- * A1[normalizeTypes] --> B1{is undefined}
98
- * B1 -->|Yes| C1[return empty array]
99
- * B1 -->|No| D1{is array}
100
- * D1 -->|Yes| E1[return t]
101
- * D1 -->|No| F1[return array with t]
102
- * ```
103
- *
104
91
  * @param t - JSON Schema `type` as a single value or an array of values.
105
92
  * @returns A flat array of type strings.
106
93
  */
@@ -111,41 +98,20 @@ export declare function normalizeTypes(t?: 'string' | 'number' | 'integer' | 'da
111
98
  /**
112
99
  * Generates registration code for OpenAPI `securitySchemes`.
113
100
  *
114
- * The code calls:
115
- * ```
116
- * app.openAPIRegistry.registerComponent('securitySchemes', name, scheme)
117
- * ```
118
- * for each entry in the provided record.
119
- *
120
- * ```mermaid
121
- * graph TD
122
- * A[Start registerComponent] --> B[Iterate over securitySchemes]
123
- * B --> C[Build registration string for each name + scheme]
124
- * C --> D[Join all strings with newline]
125
- * D --> E[Return final code string]
126
- * ```
127
- *
128
101
  * @param securitySchemes - Record of scheme name to scheme properties.
129
102
  * @returns Multiline string of registration statements.
130
103
  */
131
104
  export declare function registerComponent(securitySchemes: {
132
- [key: string]: {
133
- type?: string;
134
- name?: string;
135
- scheme?: string;
136
- bearerFormat?: string;
105
+ readonly [key: string]: {
106
+ readonly type?: string;
107
+ readonly name?: string;
108
+ readonly scheme?: string;
109
+ readonly bearerFormat?: string;
137
110
  };
138
111
  }): string;
139
112
  /**
140
113
  * Checks if a value is a non-null object (e.g., a potential `$ref` object).
141
114
  *
142
- * ```mermaid
143
- * graph TD
144
- * A[Start isRefObject] --> B[Check typeof value is object]
145
- * B --> C[Check value is not null]
146
- * C --> D[Return true or false]
147
- * ```
148
- *
149
115
  * @param value - The value to check.
150
116
  * @returns `true` if the value is a non-null object.
151
117
  *
@@ -170,16 +136,6 @@ export declare function isHttpMethod(method: string): method is 'get' | 'put' |
170
136
  /**
171
137
  * Checks if all given content types share the same schema definition.
172
138
  *
173
- * ```mermaid
174
- * graph TD
175
- * A[Start isUniqueContentSchema] --> B[Create empty set]
176
- * B --> C[Loop over content types]
177
- * C --> D[Read schema for type]
178
- * D --> E[Stringify and add to set]
179
- * E --> F[After loop check size]
180
- * F --> G[Return true if size is one]
181
- * ```
182
- *
183
139
  * @param contentTypes - Array of content type keys (e.g., ['application/json', 'application/xml']).
184
140
  * @param content - OpenAPI content object mapping content types to media objects.
185
141
  * @returns `true` if all specified content types refer to the same schema; otherwise `false`.
@@ -193,8 +149,8 @@ export declare function isHttpMethod(method: string): method is 'get' | 'put' |
193
149
  * ```
194
150
  */
195
151
  export declare function isUniqueContentSchema(contentTypes: readonly string[], content: {
196
- [key: string]: {
197
- schema: {
152
+ readonly [key: string]: {
153
+ readonly schema: {
198
154
  readonly $ref?: `#/components/schemas/${string}`;
199
155
  };
200
156
  };
@@ -202,14 +158,6 @@ export declare function isUniqueContentSchema(contentTypes: readonly string[], c
202
158
  /**
203
159
  * Extracts the type name from an OpenAPI `$ref` string.
204
160
  *
205
- * ```mermaid
206
- * graph TD
207
- * A["Start refSchema"] --> B["Split $ref by slash"]
208
- * B --> C["Take last segment"]
209
- * C --> D["Append Schema suffix"]
210
- * D --> E["Return result string"]
211
- * ```
212
- *
213
161
  * @param $ref - A reference path like `#/components/schemas/Address`.
214
162
  * @returns The extracted type name with `Schema` suffix.
215
163
  *
@@ -223,16 +171,6 @@ export declare function refSchema($ref: `#/components/schemas/${string}`): strin
223
171
  /**
224
172
  * Generates a PascalCase route name from HTTP method and path.
225
173
  *
226
- * ```mermaid
227
- * graph TD
228
- * A[Start routeName] --> B[Replace special chars with space]
229
- * B --> C[Trim and split by spaces]
230
- * C --> D[Capitalize each segment]
231
- * D --> E[Join segments into single string]
232
- * E --> F[Prefix with method and suffix with Route]
233
- * F --> G[Return final route name]
234
- * ```
235
- *
236
174
  * @param method - HTTP method (e.g., 'get', 'post').
237
175
  * @param path - URL path (e.g., '/users/{id}/posts').
238
176
  * @returns A route name string (e.g., 'getUsersIdPostsRoute').
@@ -244,14 +182,6 @@ export declare function methodPath(method: string, path: string): string;
244
182
  /**
245
183
  * Generates a Hono route definition as a TypeScript export string.
246
184
  *
247
- * ```mermaid
248
- * graph TD
249
- * A[Start createRoute] --> B[Collect properties from args]
250
- * B --> C[Join properties into one string]
251
- * C --> D[Build export createRoute template]
252
- * D --> E[Return final code string]
253
- * ```
254
- *
255
185
  * @param args - Route metadata and OpenAPI friendly fragments (`method`, `path`, `requestParams`, `responses`, etc.).
256
186
  * @returns A string representing an `export const <name> = createRoute({ ... })` statement.
257
187
  *
@@ -279,6 +209,7 @@ export declare function createRoute(args: {
279
209
  }): string;
280
210
  /**
281
211
  * Generates an array of Zod validator strings from OpenAPI parameter objects.
212
+ *
282
213
  * @param parameters - An object containing `query`, `path`, and `header` parameters.
283
214
  * @returns An array of strings like `'query:z.object({...})'` or `'params:z.object({...})'`.
284
215
  */
@@ -286,18 +217,6 @@ export declare const requestParamsArray: (parameters: Record<string, Record<stri
286
217
  /**
287
218
  * Escapes a string for safe use in TypeScript string literals.
288
219
  *
289
- * ```mermaid
290
- * graph TD
291
- * A[Start escapeStringLiteral] --> B[Replace newline and tab with space]
292
- * B --> C[Remove zero width and BOM characters]
293
- * C --> D[Replace full width spaces with normal space]
294
- * D --> E[Collapse multiple spaces into one]
295
- * E --> F[Escape backslashes]
296
- * F --> G[Escape single quotes]
297
- * G --> H[Trim leading and trailing spaces]
298
- * H --> I[Return escaped string]
299
- * ```
300
- *
301
220
  * @param text - The input text to escape.
302
221
  * @returns The escaped string.
303
222
  */
@@ -305,14 +224,8 @@ export declare function escapeStringLiteral(text: string): string;
305
224
  /**
306
225
  * Converts a string to a safe TypeScript object key.
307
226
  *
308
- * ```mermaid
309
- * graph TD
310
- * A[Start getToSafeIdentifier] --> B[Check if matches identifier regex]
311
- * B --> C[If matches, return string as is]
312
- * B --> D[If not, wrap with JSON stringify]
313
- * C --> E[Return result]
314
- * D --> E[Return result]
315
- * ```
227
+ * @param text - The string to convert to a safe identifier.
228
+ * @returns A safe identifier string.
316
229
  *
317
230
  * @example
318
231
  * ```ts
@@ -323,19 +236,11 @@ export declare function escapeStringLiteral(text: string): string;
323
236
  * getToSafeIdentifier('if') // → 'if'
324
237
  * ```
325
238
  */
326
- export declare function getToSafeIdentifier(str: string): string;
239
+ export declare function getToSafeIdentifier(text: string): string;
327
240
  /**
328
- * Converts a string to a safe TypeScript identifier.
329
- *
330
- * ```mermaid
331
- * graph TD
332
- * A[Start sanitizeIdentifier] --> B[Replace invalid characters with underscore]
333
- * B --> C[Return sanitized string]
334
- * ```
335
- *
336
241
  * Replaces any character not matching `[A-Za-z0-9_$]` with `_`.
337
242
  *
338
- * @param str - The raw string to sanitize.
243
+ * @param text - The raw string to sanitize.
339
244
  * @returns A valid identifier string.
340
245
  *
341
246
  * @example
@@ -347,23 +252,10 @@ export declare function getToSafeIdentifier(str: string): string;
347
252
  * sanitizeIdentifier('valid_Name') // → 'valid_Name'
348
253
  * ```
349
254
  */
350
- export declare function sanitizeIdentifier(str: string): string;
255
+ export declare function sanitizeIdentifier(text: string): string;
351
256
  /**
352
257
  * Appends a properly escaped `.regex(/pattern/)` clause.
353
258
  *
354
- * Any unescaped forward-slash within the pattern is escaped so the final
355
- * string remains a valid JavaScript RegExp literal.
356
- *
357
- * ```mermaid
358
- * graph TD
359
- * A["Start regex(pattern)"] --> B["Receive raw regex pattern without slashes"]
360
- * B --> C["Find all '/' not preceded by '\\'"]
361
- * C --> D["Escape them to '\\/'"]
362
- * D --> E["Wrap pattern in '/ ... /'"]
363
- * E --> F["Prefix with '.regex(' and suffix with ')' "]
364
- * F --> G["Return generated string"]
365
- * ```
366
- *
367
259
  * @param pattern - A raw regex pattern **without** the surrounding slashes.
368
260
  * @returns A string like `'.regex(/^[a-z]+$/)'`.
369
261
  */
@@ -5,6 +5,7 @@ export function parseConfig(config) {
5
5
  if (!isYamlOrJsonOrTsp(c.input)) {
6
6
  return { ok: false, error: `Invalid input: ${String(c.input)} (must be .yaml | .json | .tsp)` };
7
7
  }
8
+ // zod-openapi
8
9
  const zo = c['zod-openapi'];
9
10
  if (zo !== undefined) {
10
11
  // boolean flags
@@ -20,15 +21,15 @@ export function parseConfig(config) {
20
21
  error: `Invalid exportType format for zod-openapi: ${String(zo.exportType)}`,
21
22
  };
22
23
  }
23
- const hasSchema = zo.schema !== undefined;
24
- const hasRoute = zo.route !== undefined;
25
- if (hasSchema !== hasRoute) {
24
+ const hs = zo.schema !== undefined;
25
+ const hr = zo.route !== undefined;
26
+ if (hs !== hr) {
26
27
  return {
27
28
  ok: false,
28
29
  error: "Invalid config: 'zod-openapi.schema' and 'zod-openapi.route' must be defined together (both or neither).",
29
30
  };
30
31
  }
31
- if (hasSchema || hasRoute) {
32
+ if (hs || hr) {
32
33
  if (Object.hasOwn(zo, 'output')) {
33
34
  return {
34
35
  ok: false,
@@ -44,7 +45,7 @@ export function parseConfig(config) {
44
45
  };
45
46
  }
46
47
  }
47
- if (hasSchema) {
48
+ if (hs) {
48
49
  const s = zo.schema;
49
50
  if (!s)
50
51
  return { ok: false, error: 'Invalid config: zod-openapi.schema is undefined' };
@@ -80,7 +81,7 @@ export function parseConfig(config) {
80
81
  };
81
82
  }
82
83
  }
83
- if (hasRoute) {
84
+ if (hr) {
84
85
  const r = zo.route;
85
86
  if (!r)
86
87
  return { ok: false, error: 'Invalid config: zod-openapi.route is undefined' };
@@ -206,19 +207,6 @@ export function parseCli(args) {
206
207
  /**
207
208
  * Normalize a JSON Schema `type` value into an array of type strings.
208
209
  *
209
- * - `undefined` → `[]`
210
- * - `'string'` → `['string']`
211
- * - `['string','number']` → unchanged
212
- *
213
- * ```mermaid
214
- * graph TD
215
- * A1[normalizeTypes] --> B1{is undefined}
216
- * B1 -->|Yes| C1[return empty array]
217
- * B1 -->|No| D1{is array}
218
- * D1 -->|Yes| E1[return t]
219
- * D1 -->|No| F1[return array with t]
220
- * ```
221
- *
222
210
  * @param t - JSON Schema `type` as a single value or an array of values.
223
211
  * @returns A flat array of type strings.
224
212
  */
@@ -228,20 +216,6 @@ export function normalizeTypes(t) {
228
216
  /**
229
217
  * Generates registration code for OpenAPI `securitySchemes`.
230
218
  *
231
- * The code calls:
232
- * ```
233
- * app.openAPIRegistry.registerComponent('securitySchemes', name, scheme)
234
- * ```
235
- * for each entry in the provided record.
236
- *
237
- * ```mermaid
238
- * graph TD
239
- * A[Start registerComponent] --> B[Iterate over securitySchemes]
240
- * B --> C[Build registration string for each name + scheme]
241
- * C --> D[Join all strings with newline]
242
- * D --> E[Return final code string]
243
- * ```
244
- *
245
219
  * @param securitySchemes - Record of scheme name to scheme properties.
246
220
  * @returns Multiline string of registration statements.
247
221
  */
@@ -255,13 +229,6 @@ export function registerComponent(securitySchemes) {
255
229
  /**
256
230
  * Checks if a value is a non-null object (e.g., a potential `$ref` object).
257
231
  *
258
- * ```mermaid
259
- * graph TD
260
- * A[Start isRefObject] --> B[Check typeof value is object]
261
- * B --> C[Check value is not null]
262
- * C --> D[Return true or false]
263
- * ```
264
- *
265
232
  * @param value - The value to check.
266
233
  * @returns `true` if the value is a non-null object.
267
234
  *
@@ -294,16 +261,6 @@ export function isHttpMethod(method) {
294
261
  /**
295
262
  * Checks if all given content types share the same schema definition.
296
263
  *
297
- * ```mermaid
298
- * graph TD
299
- * A[Start isUniqueContentSchema] --> B[Create empty set]
300
- * B --> C[Loop over content types]
301
- * C --> D[Read schema for type]
302
- * D --> E[Stringify and add to set]
303
- * E --> F[After loop check size]
304
- * F --> G[Return true if size is one]
305
- * ```
306
- *
307
264
  * @param contentTypes - Array of content type keys (e.g., ['application/json', 'application/xml']).
308
265
  * @param content - OpenAPI content object mapping content types to media objects.
309
266
  * @returns `true` if all specified content types refer to the same schema; otherwise `false`.
@@ -323,14 +280,6 @@ export function isUniqueContentSchema(contentTypes, content) {
323
280
  /**
324
281
  * Extracts the type name from an OpenAPI `$ref` string.
325
282
  *
326
- * ```mermaid
327
- * graph TD
328
- * A["Start refSchema"] --> B["Split $ref by slash"]
329
- * B --> C["Take last segment"]
330
- * C --> D["Append Schema suffix"]
331
- * D --> E["Return result string"]
332
- * ```
333
- *
334
283
  * @param $ref - A reference path like `#/components/schemas/Address`.
335
284
  * @returns The extracted type name with `Schema` suffix.
336
285
  *
@@ -351,16 +300,6 @@ export function refSchema($ref) {
351
300
  /**
352
301
  * Generates a PascalCase route name from HTTP method and path.
353
302
  *
354
- * ```mermaid
355
- * graph TD
356
- * A[Start routeName] --> B[Replace special chars with space]
357
- * B --> C[Trim and split by spaces]
358
- * C --> D[Capitalize each segment]
359
- * D --> E[Join segments into single string]
360
- * E --> F[Prefix with method and suffix with Route]
361
- * F --> G[Return final route name]
362
- * ```
363
- *
364
303
  * @param method - HTTP method (e.g., 'get', 'post').
365
304
  * @param path - URL path (e.g., '/users/{id}/posts').
366
305
  * @returns A route name string (e.g., 'getUsersIdPostsRoute').
@@ -386,14 +325,6 @@ export function methodPath(method, path) {
386
325
  /**
387
326
  * Generates a Hono route definition as a TypeScript export string.
388
327
  *
389
- * ```mermaid
390
- * graph TD
391
- * A[Start createRoute] --> B[Collect properties from args]
392
- * B --> C[Join properties into one string]
393
- * C --> D[Build export createRoute template]
394
- * D --> E[Return final code string]
395
- * ```
396
- *
397
328
  * @param args - Route metadata and OpenAPI friendly fragments (`method`, `path`, `requestParams`, `responses`, etc.).
398
329
  * @returns A string representing an `export const <name> = createRoute({ ... })` statement.
399
330
  *
@@ -423,6 +354,7 @@ export function createRoute(args) {
423
354
  }
424
355
  /**
425
356
  * Generates an array of Zod validator strings from OpenAPI parameter objects.
357
+ *
426
358
  * @param parameters - An object containing `query`, `path`, and `header` parameters.
427
359
  * @returns An array of strings like `'query:z.object({...})'` or `'params:z.object({...})'`.
428
360
  */
@@ -438,18 +370,6 @@ export const requestParamsArray = (parameters) => Object.entries(parameters)
438
370
  /**
439
371
  * Escapes a string for safe use in TypeScript string literals.
440
372
  *
441
- * ```mermaid
442
- * graph TD
443
- * A[Start escapeStringLiteral] --> B[Replace newline and tab with space]
444
- * B --> C[Remove zero width and BOM characters]
445
- * C --> D[Replace full width spaces with normal space]
446
- * D --> E[Collapse multiple spaces into one]
447
- * E --> F[Escape backslashes]
448
- * F --> G[Escape single quotes]
449
- * G --> H[Trim leading and trailing spaces]
450
- * H --> I[Return escaped string]
451
- * ```
452
- *
453
373
  * @param text - The input text to escape.
454
374
  * @returns The escaped string.
455
375
  */
@@ -466,14 +386,8 @@ export function escapeStringLiteral(text) {
466
386
  /**
467
387
  * Converts a string to a safe TypeScript object key.
468
388
  *
469
- * ```mermaid
470
- * graph TD
471
- * A[Start getToSafeIdentifier] --> B[Check if matches identifier regex]
472
- * B --> C[If matches, return string as is]
473
- * B --> D[If not, wrap with JSON stringify]
474
- * C --> E[Return result]
475
- * D --> E[Return result]
476
- * ```
389
+ * @param text - The string to convert to a safe identifier.
390
+ * @returns A safe identifier string.
477
391
  *
478
392
  * @example
479
393
  * ```ts
@@ -484,21 +398,13 @@ export function escapeStringLiteral(text) {
484
398
  * getToSafeIdentifier('if') // → 'if'
485
399
  * ```
486
400
  */
487
- export function getToSafeIdentifier(str) {
488
- return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(str) ? str : JSON.stringify(str);
401
+ export function getToSafeIdentifier(text) {
402
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(text) ? text : JSON.stringify(text);
489
403
  }
490
404
  /**
491
- * Converts a string to a safe TypeScript identifier.
492
- *
493
- * ```mermaid
494
- * graph TD
495
- * A[Start sanitizeIdentifier] --> B[Replace invalid characters with underscore]
496
- * B --> C[Return sanitized string]
497
- * ```
498
- *
499
405
  * Replaces any character not matching `[A-Za-z0-9_$]` with `_`.
500
406
  *
501
- * @param str - The raw string to sanitize.
407
+ * @param text - The raw string to sanitize.
502
408
  * @returns A valid identifier string.
503
409
  *
504
410
  * @example
@@ -510,25 +416,12 @@ export function getToSafeIdentifier(str) {
510
416
  * sanitizeIdentifier('valid_Name') // → 'valid_Name'
511
417
  * ```
512
418
  */
513
- export function sanitizeIdentifier(str) {
514
- return str.replace(/[^A-Za-z0-9_$]/g, '_');
419
+ export function sanitizeIdentifier(text) {
420
+ return text.replace(/[^A-Za-z0-9_$]/g, '_');
515
421
  }
516
422
  /**
517
423
  * Appends a properly escaped `.regex(/pattern/)` clause.
518
424
  *
519
- * Any unescaped forward-slash within the pattern is escaped so the final
520
- * string remains a valid JavaScript RegExp literal.
521
- *
522
- * ```mermaid
523
- * graph TD
524
- * A["Start regex(pattern)"] --> B["Receive raw regex pattern without slashes"]
525
- * B --> C["Find all '/' not preceded by '\\'"]
526
- * C --> D["Escape them to '\\/'"]
527
- * D --> E["Wrap pattern in '/ ... /'"]
528
- * E --> F["Prefix with '.regex(' and suffix with ')' "]
529
- * F --> G["Return generated string"]
530
- * ```
531
- *
532
425
  * @param pattern - A raw regex pattern **without** the surrounding slashes.
533
426
  * @returns A string like `'.regex(/^[a-z]+$/)'`.
534
427
  */
@@ -75,14 +75,15 @@ const deleteAllTsShallow = async (dir) => listTsShallow(dir).then((files) => Pro
75
75
  const pruneDir = async (dir, expected) => fsp
76
76
  .stat(dir)
77
77
  .then((st) => st.isDirectory()
78
- ? fsp.readdir(dir, { withFileTypes: true }).then((ents) => {
78
+ ? fsp.readdir(dir, { withFileTypes: true }).then(async (ents) => {
79
79
  const targets = ents
80
80
  .filter((e) => e.isFile() && e.name.endsWith('.ts') && !expected.has(e.name))
81
81
  .map((e) => path.join(dir, e.name));
82
- return Promise.all(targets.map((f) => fsp
82
+ const res = await Promise.all(targets.map((f) => fsp
83
83
  .unlink(f)
84
84
  .then(() => f)
85
- .catch(() => null))).then((res) => res.filter((x) => x !== null));
85
+ .catch(() => null)));
86
+ return res.filter((x) => x !== null);
86
87
  })
87
88
  : [])
88
89
  .catch(() => []);
@@ -151,9 +152,6 @@ const extractRouteBlocks = (src) => {
151
152
  return { name: h.name, block: src.slice(start, end).trim() };
152
153
  });
153
154
  };
154
- /* ──────────────────────────────────────────────────────────────
155
- * Split-mode filename calculators (no `as` cast)
156
- * ────────────────────────────────────────────────────────────── */
157
155
  const computeRpcSplitFiles = async (input) => {
158
156
  const spec = await parseOpenAPI(input);
159
157
  if (!spec.ok)
@@ -194,9 +192,6 @@ const computeSchemaSplitFiles = async (input) => {
194
192
  acc.add('index.ts');
195
193
  return acc;
196
194
  };
197
- /* ──────────────────────────────────────────────────────────────
198
- * Debounce (no `let`)
199
- * ────────────────────────────────────────────────────────────── */
200
195
  const debounce = (ms, fn) => {
201
196
  const bucket = new WeakMap();
202
197
  const wrapped = () => {
@@ -207,36 +202,38 @@ const debounce = (ms, fn) => {
207
202
  };
208
203
  return wrapped;
209
204
  };
210
- /* ──────────────────────────────────────────────────────────────
211
- * Run generators for a given config(parseConfig 済み前提)
212
- * ────────────────────────────────────────────────────────────── */
213
205
  const runAllWithConf = async (c) => {
214
206
  const jobs = [];
215
207
  const zo = c['zod-openapi'];
216
208
  if (zo) {
217
209
  const exportType = zo.exportType === true;
218
210
  const exportSchema = zo.exportSchema !== false;
219
- const hasSchema = !!zo.schema;
220
- const hasRoute = !!zo.route;
211
+ const hs = !!zo.schema;
212
+ const hr = !!zo.route;
221
213
  // top-level zod-openapi (non-split)
222
- if (!(hasSchema || hasRoute)) {
214
+ if (!(hs || hr)) {
223
215
  const runZo = async () => {
224
- const spec = await parseOpenAPI(c.input);
225
- if (!spec.ok)
226
- return `✗ zod-openapi: ${spec.error}`;
227
- const code = await fmt(zodOpenAPIHono(spec.value, exportSchema, exportType));
228
- if (!code.ok)
229
- return `✗ zod-openapi fmt: ${code.error}`;
230
- const outputMaybe = zo.output;
231
- if (typeof outputMaybe !== 'string') {
232
- return `✗ zod-openapi: Invalid output format for zod-openapi: ${String(outputMaybe)}`;
216
+ try {
217
+ const spec = await parseOpenAPI(c.input);
218
+ if (!spec.ok)
219
+ return `✗ zod-openapi: ${spec.error}`;
220
+ const code = await fmt(zodOpenAPIHono(spec.value, exportSchema, exportType));
221
+ if (!code.ok)
222
+ return `✗ zod-openapi fmt: ${code.error}`;
223
+ const outputMaybe = zo.output;
224
+ if (typeof outputMaybe !== 'string') {
225
+ return `✗ zod-openapi: Invalid output format for zod-openapi: ${String(outputMaybe)}`;
226
+ }
227
+ const out = toAbs(outputMaybe);
228
+ const mk = await mkdir(path.dirname(out));
229
+ if (!mk.ok)
230
+ return `✗ zod-openapi mkdir: ${mk.error}`;
231
+ const wr = await writeFile(out, code.value);
232
+ return wr.ok ? `✓ zod-openapi -> ${out}` : `✗ zod-openapi write: ${wr.error}`;
233
+ }
234
+ catch (e) {
235
+ return `✗ zod-openapi: ${e instanceof Error ? e.message : String(e)}`;
233
236
  }
234
- const out = toAbs(outputMaybe);
235
- const mk = await mkdir(path.dirname(out));
236
- if (!mk.ok)
237
- return `✗ zod-openapi mkdir: ${mk.error}`;
238
- const wr = await writeFile(out, code.value);
239
- return wr.ok ? `✓ zod-openapi -> ${out}` : `✗ zod-openapi write: ${wr.error}`;
240
237
  };
241
238
  jobs.push(runZo());
242
239
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hono-takibi",
3
3
  "description": "Hono Takibi is a CLI tool that generates Hono routes from OpenAPI specifications.",
4
- "version": "0.9.51",
4
+ "version": "0.9.60",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -46,26 +46,25 @@
46
46
  }
47
47
  },
48
48
  "dependencies": {
49
- "@apidevtools/swagger-parser": "^12.0.0",
50
- "@typespec/compiler": "^1.3.0",
51
- "@typespec/openapi3": "^1.3.0",
49
+ "@apidevtools/swagger-parser": "^12.1.0",
50
+ "@typespec/compiler": "^1.5.0",
51
+ "@typespec/openapi3": "^1.5.0",
52
52
  "prettier": "^3.6.2",
53
- "tsx": "^4.20.4"
53
+ "tsx": "^4.20.6"
54
54
  },
55
55
  "devDependencies": {
56
- "@hono/zod-openapi": "1.1.0",
57
- "@types/node": "^22.16.5",
58
- "@typespec/http": "^1.3.0",
59
- "@typespec/rest": "^0.73.0",
60
- "@typespec/versioning": "^0.73.0",
61
- "@vitest/coverage-v8": "^3.2.4",
62
- "typescript": "^5.8.3",
63
- "vite": "^7.0.6",
64
- "vitest": "^3.2.4",
65
- "zod": "^4.0.15"
56
+ "@hono/zod-openapi": "1.1.4",
57
+ "@types/node": "^24.9.1",
58
+ "@typespec/http": "^1.5.0",
59
+ "@typespec/rest": "^0.75.0",
60
+ "@typespec/versioning": "^0.75.0",
61
+ "@vitest/coverage-v8": "^4.0.3",
62
+ "typescript": "^5.9.3",
63
+ "vite": "^7.1.12",
64
+ "vitest": "^4.0.3",
65
+ "zod": "^4.1.12"
66
66
  },
67
67
  "scripts": {
68
- "takibis": "pnpm build && tsx exec.ts",
69
68
  "dev": "vite --host",
70
69
  "deps": "rm -rf node_modules && pnpm install",
71
70
  "build": "rm -rf ./dist/* && tsc",