hono-takibi 0.9.1 → 0.9.2
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 +18 -2
- package/dist/config/index.d.ts +6 -1
- package/dist/config/index.js +1 -1
- package/dist/core/core.d.ts +8 -0
- package/dist/core/{rpc.js → core.js} +3 -4
- package/dist/core/takibi.js +1 -1
- package/dist/generator/rpc/index.d.ts +1 -1
- package/dist/generator/rpc/index.js +1 -3
- package/dist/generator/swr/index.d.ts +1 -0
- package/dist/generator/swr/index.js +1 -0
- package/dist/generator/zod-openapi-hono/openapi/route/response/index.js +66 -33
- package/package.json +10 -6
- package/dist/core/rpc.d.ts +0 -7
package/dist/cli/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { config } from '../config/index.js';
|
|
4
|
-
import
|
|
4
|
+
import core from '../core/core.js';
|
|
5
5
|
import { takibi } from '../core/takibi.js';
|
|
6
|
+
import rpc from '../generator/rpc/index.js';
|
|
7
|
+
// import { honoRpcWithSWR } from '../generator/swr/index.js'
|
|
6
8
|
import { parseCli } from '../utils/index.js';
|
|
7
9
|
const HELP_TEXT = `Usage: hono-takibi <input.{yaml,json,tsp}> -o <routes.ts> [options]
|
|
8
10
|
|
|
@@ -86,10 +88,24 @@ export async function honoTakibi() {
|
|
|
86
88
|
if (takibiResult && !takibiResult.ok) {
|
|
87
89
|
return { ok: false, error: takibiResult.error };
|
|
88
90
|
}
|
|
89
|
-
const rpcResult = c.rpc
|
|
91
|
+
const rpcResult = c.rpc
|
|
92
|
+
? await core(c.rpc.input, c.rpc.output, c.rpc.import, 'Generated RPC code written to', rpc)
|
|
93
|
+
: undefined;
|
|
90
94
|
if (rpcResult && !rpcResult.ok) {
|
|
91
95
|
return { ok: false, error: rpcResult.error };
|
|
92
96
|
}
|
|
97
|
+
// const swrResult = c.swr
|
|
98
|
+
// ? await core(
|
|
99
|
+
// c.swr.input,
|
|
100
|
+
// c.swr.output,
|
|
101
|
+
// c.swr.import,
|
|
102
|
+
// 'Generated SWR code written to',
|
|
103
|
+
// honoRpcWithSWR,
|
|
104
|
+
// )
|
|
105
|
+
// : undefined
|
|
106
|
+
// if (swrResult && !swrResult.ok) {
|
|
107
|
+
// return { ok: false, error: swrResult.error }
|
|
108
|
+
// }
|
|
93
109
|
const results = [takibiResult?.value, rpcResult?.value].filter((v) => Boolean(v));
|
|
94
110
|
return {
|
|
95
111
|
ok: true,
|
package/dist/config/index.d.ts
CHANGED
|
@@ -10,6 +10,11 @@ type Config = {
|
|
|
10
10
|
output: `${string}.ts`;
|
|
11
11
|
import: string;
|
|
12
12
|
};
|
|
13
|
+
swr?: {
|
|
14
|
+
input: `${string}.yaml` | `${string}.json` | `${string}.tsp`;
|
|
15
|
+
output: `${string}.ts`;
|
|
16
|
+
import: string;
|
|
17
|
+
};
|
|
13
18
|
};
|
|
14
19
|
export declare function config(): Promise<{
|
|
15
20
|
ok: true;
|
|
@@ -18,5 +23,5 @@ export declare function config(): Promise<{
|
|
|
18
23
|
ok: false;
|
|
19
24
|
error: string;
|
|
20
25
|
}>;
|
|
21
|
-
export
|
|
26
|
+
export default function defineConfig(config: Config): Config;
|
|
22
27
|
export {};
|
package/dist/config/index.js
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type OpenAPI } from '../openapi/index.js';
|
|
2
|
+
export default function core(input: `${string}.yaml` | `${string}.json` | `${string}.tsp`, output: `${string}.ts`, importCode: string, value: string, fn: (openapi: OpenAPI, importCode: string) => string): Promise<{
|
|
3
|
+
ok: true;
|
|
4
|
+
value: string;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
error: string;
|
|
8
|
+
}>;
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { fmt } from '../format/index.js';
|
|
3
3
|
import { mkdir, writeFile } from '../fsp/index.js';
|
|
4
|
-
import { honoRpc } from '../generator/rpc/index.js';
|
|
5
4
|
import { parseOpenAPI } from '../openapi/index.js';
|
|
6
|
-
export async function
|
|
5
|
+
export default async function core(input, output, importCode, value, fn) {
|
|
7
6
|
const openAPIResult = await parseOpenAPI(input);
|
|
8
7
|
if (!openAPIResult.ok) {
|
|
9
8
|
return { ok: false, error: openAPIResult.error };
|
|
10
9
|
}
|
|
11
10
|
const openAPI = openAPIResult.value;
|
|
12
|
-
const honoRpcResult = await fmt(
|
|
11
|
+
const honoRpcResult = await fmt(fn(openAPI, importCode));
|
|
13
12
|
if (!honoRpcResult.ok) {
|
|
14
13
|
return { ok: false, error: honoRpcResult.error };
|
|
15
14
|
}
|
|
@@ -23,6 +22,6 @@ export async function rpc(input, output, importCode) {
|
|
|
23
22
|
}
|
|
24
23
|
return {
|
|
25
24
|
ok: true,
|
|
26
|
-
value:
|
|
25
|
+
value: `${value} ${output}`,
|
|
27
26
|
};
|
|
28
27
|
}
|
package/dist/core/takibi.js
CHANGED
|
@@ -111,7 +111,7 @@ async function zodOpenapiHonoHandler(openapi, output, test) {
|
|
|
111
111
|
const handlers = [];
|
|
112
112
|
for (const [path, pathItem] of Object.entries(paths)) {
|
|
113
113
|
for (const [method] of Object.entries(pathItem)) {
|
|
114
|
-
const routeHandlerContent = `export const ${methodPath(method, path)}RouteHandler:RouteHandler<typeof ${methodPath(method, path)}>=async(c)=>{}`;
|
|
114
|
+
const routeHandlerContent = `export const ${methodPath(method, path)}RouteHandler:RouteHandler<typeof ${methodPath(method, path)}Route>=async(c)=>{}`;
|
|
115
115
|
const rawSegment = path.replace(/^\/+/, '').split('/')[0] ?? '';
|
|
116
116
|
const pathName = (rawSegment === '' ? 'index' : rawSegment)
|
|
117
117
|
.replace(/\{([^}]+)\}/g, '$1')
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { OpenAPI } from '../../openapi/index.js';
|
|
2
|
-
export
|
|
2
|
+
export default function rpc(openapi: OpenAPI, importCode: string): string;
|
|
@@ -14,8 +14,6 @@ const isOpenAPIPaths = (v) => {
|
|
|
14
14
|
/** Treat any object as Schema (we rely on downstream field checks) */
|
|
15
15
|
const isSchema = (v) => isRecord(v);
|
|
16
16
|
/* ─────────────────────────────── Formatters ─────────────────────────────── */
|
|
17
|
-
/** Uppercase the first character */
|
|
18
|
-
const upperHead = (s) => (s ? s.charAt(0).toUpperCase() + s.slice(1) : s);
|
|
19
17
|
/** JS identifier check */
|
|
20
18
|
const isValidIdent = (s) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(s);
|
|
21
19
|
/** Escape single quotes and backslashes for single-quoted strings */
|
|
@@ -288,7 +286,7 @@ const generateOperationCode = (path, method, item, deps) => {
|
|
|
288
286
|
'}');
|
|
289
287
|
};
|
|
290
288
|
/* ─────────────────────────────── Entry ─────────────────────────────── */
|
|
291
|
-
export function
|
|
289
|
+
export default function rpc(openapi, importCode) {
|
|
292
290
|
const client = 'client';
|
|
293
291
|
const out = [];
|
|
294
292
|
// import header (kept as-is, then a blank line if present)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -12,42 +12,75 @@ import { zodToOpenAPI } from '../../../../zod-to-openapi/index.js';
|
|
|
12
12
|
* - Deduplicates content types if all share the same schema.
|
|
13
13
|
* - Escapes all descriptions safely for inline code.
|
|
14
14
|
*/
|
|
15
|
+
// export function response(responses: Responses): string {
|
|
16
|
+
// // 1. get response codes (200, 404, etc.)
|
|
17
|
+
// const responseCodes = Object.keys(responses)
|
|
18
|
+
// // 2. processing for each response code
|
|
19
|
+
// const responseEntries = responseCodes.map((code) => {
|
|
20
|
+
// const response = responses[code]
|
|
21
|
+
// // 2.1 no content (description only response)
|
|
22
|
+
// if (!response.content)
|
|
23
|
+
// return `${code}:{description:'${escapeStringLiteral(response.description ?? '')}',},`
|
|
24
|
+
// // check duplication
|
|
25
|
+
// const contentTypes = Object.keys(response.content)
|
|
26
|
+
// const isUniqueSchema = isUniqueContentSchema(contentTypes, response.content)
|
|
27
|
+
// // all duplication same schema
|
|
28
|
+
// if (isUniqueSchema) {
|
|
29
|
+
// const contentParts: string[] = []
|
|
30
|
+
// for (const contentType of contentTypes) {
|
|
31
|
+
// const content = response.content[contentType]
|
|
32
|
+
// const z = zodToOpenAPI(content.schema)
|
|
33
|
+
// const examples = content.examples
|
|
34
|
+
// const exampleString =
|
|
35
|
+
// examples && Object.keys(examples).length > 0
|
|
36
|
+
// ? `,examples:{${Object.entries(examples)
|
|
37
|
+
// .map(([key, example]) => {
|
|
38
|
+
// const parts = []
|
|
39
|
+
// if (example.summary) parts.push(`summary:${JSON.stringify(example.summary)}`)
|
|
40
|
+
// if (example.value !== undefined)
|
|
41
|
+
// parts.push(`value:${JSON.stringify(example.value)}`)
|
|
42
|
+
// return `${JSON.stringify(key)}:{${parts.join(',')}}`
|
|
43
|
+
// })
|
|
44
|
+
// .join(',')}}`
|
|
45
|
+
// : ''
|
|
46
|
+
// contentParts.push(`'${contentType}':{schema:${z}${exampleString}}`)
|
|
47
|
+
// }
|
|
48
|
+
// return `${code}:{description:'${escapeStringLiteral(response.description ?? '')}',content:{${contentParts.join(',')}}},`
|
|
49
|
+
// }
|
|
50
|
+
// })
|
|
51
|
+
// // 3.combine all response definitions
|
|
52
|
+
// return responseEntries.join('')
|
|
53
|
+
// }
|
|
15
54
|
export function response(responses) {
|
|
16
55
|
// 1. get response codes (200, 404, etc.)
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (!response.content)
|
|
23
|
-
return `${code}:{description:'${escapeStringLiteral(response.description ?? '')}',},`;
|
|
24
|
-
// check duplication
|
|
25
|
-
const contentTypes = Object.keys(response.content);
|
|
26
|
-
const isUniqueSchema = isUniqueContentSchema(contentTypes, response.content);
|
|
27
|
-
// all duplication same schema
|
|
28
|
-
if (isUniqueSchema) {
|
|
29
|
-
const contentParts = [];
|
|
30
|
-
for (const contentType of contentTypes) {
|
|
31
|
-
const content = response.content[contentType];
|
|
32
|
-
const z = zodToOpenAPI(content.schema);
|
|
33
|
-
const examples = content.examples;
|
|
34
|
-
const exampleString = examples && Object.keys(examples).length > 0
|
|
35
|
-
? `,examples:{${Object.entries(examples)
|
|
36
|
-
.map(([key, example]) => {
|
|
37
|
-
const parts = [];
|
|
38
|
-
if (example.summary)
|
|
39
|
-
parts.push(`summary:${JSON.stringify(example.summary)}`);
|
|
40
|
-
if (example.value !== undefined)
|
|
41
|
-
parts.push(`value:${JSON.stringify(example.value)}`);
|
|
42
|
-
return `${JSON.stringify(key)}:{${parts.join(',')}}`;
|
|
43
|
-
})
|
|
44
|
-
.join(',')}}`
|
|
45
|
-
: '';
|
|
46
|
-
contentParts.push(`'${contentType}':{schema:${z}${exampleString}}`);
|
|
47
|
-
}
|
|
48
|
-
return `${code}:{description:'${escapeStringLiteral(response.description ?? '')}',content:{${contentParts.join(',')}}},`;
|
|
56
|
+
const responseEntries = Object.keys(responses).map((code) => {
|
|
57
|
+
const res = responses[code];
|
|
58
|
+
const content = res.content;
|
|
59
|
+
if (!content) {
|
|
60
|
+
return `${code}:{description:'${escapeStringLiteral(res.description ?? '')}',},`;
|
|
49
61
|
}
|
|
62
|
+
const contentTypes = Object.keys(content);
|
|
63
|
+
const isUnique = isUniqueContentSchema(contentTypes, content);
|
|
64
|
+
const sharedZ = isUnique ? zodToOpenAPI(content[contentTypes[0]].schema) : undefined;
|
|
65
|
+
const contentParts = contentTypes.map((ct) => {
|
|
66
|
+
const media = content[ct];
|
|
67
|
+
const z = sharedZ ?? zodToOpenAPI(media.schema);
|
|
68
|
+
const examples = media.examples;
|
|
69
|
+
const exampleString = examples && Object.keys(examples).length > 0
|
|
70
|
+
? `,examples:{${Object.entries(examples)
|
|
71
|
+
.map(([k, v]) => {
|
|
72
|
+
const parts = [];
|
|
73
|
+
if (v.summary)
|
|
74
|
+
parts.push(`summary:${JSON.stringify(v.summary)}`);
|
|
75
|
+
if (v.value !== undefined)
|
|
76
|
+
parts.push(`value:${JSON.stringify(v.value)}`);
|
|
77
|
+
return `${JSON.stringify(k)}:{${parts.join(',')}}`;
|
|
78
|
+
})
|
|
79
|
+
.join(',')}}`
|
|
80
|
+
: '';
|
|
81
|
+
return `'${ct}':{schema:${z}${exampleString}}`;
|
|
82
|
+
});
|
|
83
|
+
return `${code}:{description:'${escapeStringLiteral(res.description ?? '')}',content:{${contentParts.join(',')}}},`;
|
|
50
84
|
});
|
|
51
|
-
// 3.combine all response definitions
|
|
52
85
|
return responseEntries.join('');
|
|
53
86
|
}
|
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.
|
|
4
|
+
"version": "0.9.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
|
@@ -33,16 +33,20 @@
|
|
|
33
33
|
"import": "./dist/vite-plugin/index.js"
|
|
34
34
|
},
|
|
35
35
|
"./config": {
|
|
36
|
-
"types": "./dist/
|
|
37
|
-
"import": "./dist/
|
|
36
|
+
"types": "./dist/config/index.d.ts",
|
|
37
|
+
"import": "./dist/config/index.js"
|
|
38
38
|
},
|
|
39
39
|
"./zod-openapi-hono": {
|
|
40
40
|
"types": "./dist/generator/zod-openapi-hono/openapi/index.d.ts",
|
|
41
41
|
"import": "./dist/generator/zod-openapi-hono/openapi/index.js"
|
|
42
42
|
},
|
|
43
|
-
"./
|
|
44
|
-
"types": "./dist/core/
|
|
45
|
-
"import": "./dist/core/
|
|
43
|
+
"./core": {
|
|
44
|
+
"types": "./dist/core/core.d.ts",
|
|
45
|
+
"import": "./dist/core/core.js"
|
|
46
|
+
},
|
|
47
|
+
"./rpc": {
|
|
48
|
+
"types": "./dist/generator/rpc/index.d.ts",
|
|
49
|
+
"import": "./dist/generator/rpc/index.js"
|
|
46
50
|
}
|
|
47
51
|
},
|
|
48
52
|
"dependencies": {
|