hono-takibi 0.9.26 → 0.9.30
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/README.md +25 -25
- package/dist/cli/index.d.ts +10 -11
- package/dist/cli/index.js +24 -31
- package/dist/config/index.d.ts +7 -1
- package/dist/config/index.js +13 -130
- package/dist/core/route.js +40 -37
- package/dist/core/rpc.d.ts +13 -0
- package/dist/{generator/rpc/index.js → core/rpc.js} +99 -30
- package/dist/core/schema.d.ts +20 -0
- package/dist/core/schema.js +39 -17
- package/dist/generator/zod-openapi-hono/app/index.js +7 -1
- package/dist/generator/zod-to-openapi/z/object.js +21 -1
- package/dist/helper/get-route-maps.d.ts +1 -1
- package/dist/openapi/index.d.ts +3 -3
- package/dist/openapi/index.js +4 -4
- package/dist/utils/index.d.ts +66 -15
- package/dist/utils/index.js +162 -10
- package/dist/vite-plugin/index.d.ts +1 -41
- package/dist/vite-plugin/index.js +457 -69
- package/package.json +3 -7
- package/dist/core/core.d.ts +0 -8
- package/dist/core/core.js +0 -27
- package/dist/generator/rpc/index.d.ts +0 -2
- package/dist/generator/swr/index.d.ts +0 -1
- package/dist/generator/swr/index.js +0 -1
package/README.md
CHANGED
|
@@ -33,31 +33,6 @@ If you have OpenAPI specifications, Hono Takibi automates the conversion process
|
|
|
33
33
|
npx hono-takibi path/to/input.{yaml,json,tsp} -o path/to/output.ts
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
## CLI
|
|
37
|
-
|
|
38
|
-
### Options
|
|
39
|
-
|
|
40
|
-
basic
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
Options:
|
|
44
|
-
--export-type export TypeScript type aliases
|
|
45
|
-
--export-schema export Zod schema objects
|
|
46
|
-
--template generate app file and handler stubs
|
|
47
|
-
--test generate empty *.test.ts files
|
|
48
|
-
--base-path <path> api prefix (default: /)
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
template
|
|
52
|
-
|
|
53
|
-
> **⚠️** When using the `--template` option, you must specify a valid directory path. Ensure the directory exists before executing the
|
|
54
|
-
|
|
55
|
-
### Example
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
npx hono-takibi path/to/input.{yaml,json,tsp} -o path/to/output.ts --export-type --export-schema --template --base-path '/api/v1'
|
|
59
|
-
```
|
|
60
|
-
|
|
61
36
|
input:
|
|
62
37
|
|
|
63
38
|
```yaml
|
|
@@ -112,6 +87,31 @@ export const getRoute = createRoute({
|
|
|
112
87
|
|
|
113
88
|

|
|
114
89
|
|
|
90
|
+
## CLI
|
|
91
|
+
|
|
92
|
+
### Options
|
|
93
|
+
|
|
94
|
+
basic
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
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: /)
|
|
103
|
+
```
|
|
104
|
+
|
|
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
|
+
### Example
|
|
110
|
+
|
|
111
|
+
```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'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
115
|
## HonoTakibiVite
|
|
116
116
|
|
|
117
117
|
### Automatic Code Regeneration & HMR
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -5,17 +5,16 @@
|
|
|
5
5
|
*
|
|
6
6
|
* ```mermaid
|
|
7
7
|
* flowchart TD
|
|
8
|
-
* A["Start honoTakibi
|
|
9
|
-
* B --> C{"
|
|
10
|
-
* C
|
|
11
|
-
* C
|
|
12
|
-
* E --> F{"cliResult.ok
|
|
13
|
-
* F
|
|
14
|
-
* F
|
|
15
|
-
* H --> I
|
|
16
|
-
* I --> J
|
|
17
|
-
*
|
|
18
|
-
* J -->|Yes| L["return { ok:true, value: takibiResult.value }"]
|
|
8
|
+
* A["Start honoTakibi"] --> B["Parse args"]
|
|
9
|
+
* B --> C{"Help requested?"}
|
|
10
|
+
* C -- Yes --> D["Return help text"]
|
|
11
|
+
* C -- No --> E["parseCli(args)"]
|
|
12
|
+
* E --> F{"cliResult.ok?"}
|
|
13
|
+
* F -- No --> G["Return parse error"]
|
|
14
|
+
* F -- Yes --> H["Run takibi"]
|
|
15
|
+
* H --> I{"takibi.ok?"}
|
|
16
|
+
* I -- No --> J["Return takibi error"]
|
|
17
|
+
* I -- Yes --> K["Return success message"]
|
|
19
18
|
* ```
|
|
20
19
|
*
|
|
21
20
|
* **Options**
|
package/dist/cli/index.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { config } from '../config/index.js';
|
|
4
|
-
import { core } from '../core/core.js';
|
|
5
4
|
import { route } from '../core/route.js';
|
|
5
|
+
import { rpc } from '../core/rpc.js';
|
|
6
6
|
import { schema } from '../core/schema.js';
|
|
7
7
|
import { takibi } from '../core/takibi.js';
|
|
8
|
-
import { rpc } from '../generator/rpc/index.js';
|
|
9
8
|
// import { honoRpcWithSWR } from '../generator/swr/index.js'
|
|
10
9
|
import { parseCli } from '../utils/index.js';
|
|
10
|
+
/**
|
|
11
|
+
* CLI usage help text shown when `-h`/`--help` is provided.
|
|
12
|
+
* Kept as a single template for easy updates and snapshot stability.
|
|
13
|
+
*/
|
|
11
14
|
const HELP_TEXT = `Usage: hono-takibi <input.{yaml,json,tsp}> -o <routes.ts> [options]
|
|
12
15
|
|
|
13
16
|
Options:
|
|
@@ -24,17 +27,16 @@ Options:
|
|
|
24
27
|
*
|
|
25
28
|
* ```mermaid
|
|
26
29
|
* flowchart TD
|
|
27
|
-
* A["Start honoTakibi
|
|
28
|
-
* B --> C{"
|
|
29
|
-
* C
|
|
30
|
-
* C
|
|
31
|
-
* E --> F{"cliResult.ok
|
|
32
|
-
* F
|
|
33
|
-
* F
|
|
34
|
-
* H --> I
|
|
35
|
-
* I --> J
|
|
36
|
-
*
|
|
37
|
-
* J -->|Yes| L["return { ok:true, value: takibiResult.value }"]
|
|
30
|
+
* A["Start honoTakibi"] --> B["Parse args"]
|
|
31
|
+
* B --> C{"Help requested?"}
|
|
32
|
+
* C -- Yes --> D["Return help text"]
|
|
33
|
+
* C -- No --> E["parseCli(args)"]
|
|
34
|
+
* E --> F{"cliResult.ok?"}
|
|
35
|
+
* F -- No --> G["Return parse error"]
|
|
36
|
+
* F -- Yes --> H["Run takibi"]
|
|
37
|
+
* H --> I{"takibi.ok?"}
|
|
38
|
+
* I -- No --> J["Return takibi error"]
|
|
39
|
+
* I -- Yes --> K["Return success message"]
|
|
38
40
|
* ```
|
|
39
41
|
*
|
|
40
42
|
* **Options**
|
|
@@ -50,7 +52,7 @@ Options:
|
|
|
50
52
|
* - `{ ok: false, error: string }` on validation or generation errors
|
|
51
53
|
*/
|
|
52
54
|
export async function honoTakibi() {
|
|
53
|
-
|
|
55
|
+
/** Slice the arguments to remove the first two (node and script path) */
|
|
54
56
|
const args = process.argv.slice(2);
|
|
55
57
|
const isHelpRequested = (args) => {
|
|
56
58
|
return args.length === 1 && (args[0] === '--help' || args[0] === '-h');
|
|
@@ -63,11 +65,11 @@ export async function honoTakibi() {
|
|
|
63
65
|
};
|
|
64
66
|
}
|
|
65
67
|
const abs = resolve(process.cwd(), 'hono-takibi.config.ts');
|
|
68
|
+
/** If config file does not exist, parse CLI arguments */
|
|
66
69
|
if (!existsSync(abs)) {
|
|
67
70
|
const cliResult = parseCli(args);
|
|
68
|
-
if (!cliResult.ok)
|
|
71
|
+
if (!cliResult.ok)
|
|
69
72
|
return { ok: false, error: cliResult.error };
|
|
70
|
-
}
|
|
71
73
|
const cli = cliResult.value;
|
|
72
74
|
const takibiResult = await takibi(cli.input, cli.output, cli.exportSchema ?? false, cli.exportType ?? false, cli.template ?? false, cli.test ?? false, cli.basePath);
|
|
73
75
|
if (!takibiResult.ok) {
|
|
@@ -78,11 +80,13 @@ export async function honoTakibi() {
|
|
|
78
80
|
value: takibiResult.value,
|
|
79
81
|
};
|
|
80
82
|
}
|
|
83
|
+
/** If config file exists, parse config file */
|
|
81
84
|
const configResult = await config();
|
|
82
85
|
if (!configResult.ok) {
|
|
83
86
|
return { ok: false, error: configResult.error };
|
|
84
87
|
}
|
|
85
88
|
const c = configResult.value;
|
|
89
|
+
/** takibi */
|
|
86
90
|
const takibiResult = c['zod-openapi']?.output
|
|
87
91
|
? await takibi(c.input, c['zod-openapi']?.output, c['zod-openapi']?.exportSchema ?? false, c['zod-openapi']?.exportType ?? false, false, // template
|
|
88
92
|
false)
|
|
@@ -90,38 +94,27 @@ export async function honoTakibi() {
|
|
|
90
94
|
if (takibiResult && !takibiResult.ok) {
|
|
91
95
|
return { ok: false, error: takibiResult.error };
|
|
92
96
|
}
|
|
93
|
-
|
|
97
|
+
/** schema */
|
|
94
98
|
const schemaResult = c['zod-openapi']?.schema
|
|
95
99
|
? await schema(c.input, c['zod-openapi'].schema.output, c['zod-openapi'].schema.exportType ?? false, c['zod-openapi']?.schema.split ?? false)
|
|
96
100
|
: undefined;
|
|
97
101
|
if (schemaResult && !schemaResult.ok) {
|
|
98
102
|
return { ok: false, error: schemaResult.error };
|
|
99
103
|
}
|
|
100
|
-
|
|
104
|
+
/** route */
|
|
101
105
|
const routeResult = c['zod-openapi']?.route
|
|
102
106
|
? await route(c.input, c['zod-openapi'].route.output, c['zod-openapi'].route.import, c['zod-openapi'].route.split ?? false)
|
|
103
107
|
: undefined;
|
|
104
108
|
if (routeResult && !routeResult.ok) {
|
|
105
109
|
return { ok: false, error: routeResult.error };
|
|
106
110
|
}
|
|
111
|
+
/** rpc */
|
|
107
112
|
const rpcResult = c.rpc
|
|
108
|
-
? await
|
|
113
|
+
? await rpc(c.input, c.rpc.output, c.rpc.import, c.rpc.split ?? false)
|
|
109
114
|
: undefined;
|
|
110
115
|
if (rpcResult && !rpcResult.ok) {
|
|
111
116
|
return { ok: false, error: rpcResult.error };
|
|
112
117
|
}
|
|
113
|
-
// const swrResult = c.swr
|
|
114
|
-
// ? await core(
|
|
115
|
-
// c.swr.input,
|
|
116
|
-
// c.swr.output,
|
|
117
|
-
// c.swr.import,
|
|
118
|
-
// 'Generated SWR code written to',
|
|
119
|
-
// honoRpcWithSWR,
|
|
120
|
-
// )
|
|
121
|
-
// : undefined
|
|
122
|
-
// if (swrResult && !swrResult.ok) {
|
|
123
|
-
// return { ok: false, error: swrResult.error }
|
|
124
|
-
// }
|
|
125
118
|
const results = [takibiResult?.value, rpcResult?.value].filter((v) => Boolean(v));
|
|
126
119
|
return {
|
|
127
120
|
ok: true,
|
package/dist/config/index.d.ts
CHANGED
|
@@ -16,8 +16,9 @@ type Config = {
|
|
|
16
16
|
};
|
|
17
17
|
};
|
|
18
18
|
readonly rpc?: {
|
|
19
|
-
readonly output: `${string}.ts`;
|
|
19
|
+
readonly output: string | `${string}.ts`;
|
|
20
20
|
readonly import: string;
|
|
21
|
+
readonly split?: boolean;
|
|
21
22
|
};
|
|
22
23
|
};
|
|
23
24
|
export declare function config(): Promise<{
|
|
@@ -27,5 +28,10 @@ export declare function config(): Promise<{
|
|
|
27
28
|
readonly ok: false;
|
|
28
29
|
readonly error: string;
|
|
29
30
|
}>;
|
|
31
|
+
/**
|
|
32
|
+
* Helper to define a config with full type completion.
|
|
33
|
+
*
|
|
34
|
+
* @see config
|
|
35
|
+
*/
|
|
30
36
|
export declare function defineConfig(c: Config): Config;
|
|
31
37
|
export {};
|
package/dist/config/index.js
CHANGED
|
@@ -2,149 +2,32 @@ import { existsSync } from 'node:fs';
|
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
import { register } from 'tsx/esm/api';
|
|
5
|
-
|
|
6
|
-
const isTs = (o) => typeof o === 'string' && o.endsWith('.ts');
|
|
5
|
+
import { parseConfig } from '../utils/index.js';
|
|
7
6
|
export async function config() {
|
|
8
7
|
const abs = resolve(process.cwd(), 'hono-takibi.config.ts');
|
|
9
8
|
if (!existsSync(abs))
|
|
10
9
|
return { ok: false, error: `Config not found: ${abs}` };
|
|
11
10
|
try {
|
|
12
11
|
register();
|
|
13
|
-
const
|
|
14
|
-
|
|
12
|
+
const url = pathToFileURL(abs).href;
|
|
13
|
+
const mod = await import(/* @vite-ignore */ url);
|
|
14
|
+
if (!('default' in mod) || mod.default === undefined) {
|
|
15
15
|
return { ok: false, error: 'Config must export default object' };
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
ok: false,
|
|
22
|
-
error: `Invalid input format for zod-openapi: ${String(mod.default.input)}`,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
// zod-openapi
|
|
26
|
-
const zo = mod.default['zod-openapi'];
|
|
27
|
-
if (zo) {
|
|
28
|
-
// boolean flags
|
|
29
|
-
if (zo.exportSchema !== undefined && typeof zo.exportSchema !== 'boolean') {
|
|
30
|
-
return {
|
|
31
|
-
ok: false,
|
|
32
|
-
error: `Invalid exportSchema format for zod-openapi: ${String(zo.exportSchema)}`,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
if (zo.exportType !== undefined && typeof zo.exportType !== 'boolean') {
|
|
36
|
-
return {
|
|
37
|
-
ok: false,
|
|
38
|
-
error: `Invalid exportType format for zod-openapi: ${String(zo.exportType)}`,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
const hasSchema = zo.schema !== undefined;
|
|
42
|
-
const hasRoute = zo.route !== undefined;
|
|
43
|
-
if (hasSchema || hasRoute) {
|
|
44
|
-
if (Object.hasOwn(zo, 'output')) {
|
|
45
|
-
return {
|
|
46
|
-
ok: false,
|
|
47
|
-
error: "Invalid config: When using 'zod-openapi.schema' or 'zod-openapi.route', do NOT set 'zod-openapi.output'.",
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
if (!isTs(zo.output)) {
|
|
53
|
-
return {
|
|
54
|
-
ok: false,
|
|
55
|
-
error: `Invalid output format for zod-openapi: ${String(zo.output)}`,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
if (hasSchema) {
|
|
60
|
-
const s = zo.schema;
|
|
61
|
-
if (!s)
|
|
62
|
-
return { ok: false, error: 'Invalid config: zod-openapi.schema is undefined' };
|
|
63
|
-
if (s.split !== undefined && typeof s.split !== 'boolean') {
|
|
64
|
-
return {
|
|
65
|
-
ok: false,
|
|
66
|
-
error: `Invalid schema split format for zod-openapi: ${String(s.split)}`,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
if (typeof s.output !== 'string') {
|
|
70
|
-
return { ok: false, error: `Invalid schema output path: ${String(s.output)}` };
|
|
71
|
-
}
|
|
72
|
-
if (s.split === true) {
|
|
73
|
-
if (isTs(s.output)) {
|
|
74
|
-
return {
|
|
75
|
-
ok: false,
|
|
76
|
-
error: `Invalid schema output path for split mode (must be a directory, not .ts): ${s.output}`,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
if (!isTs(s.output)) {
|
|
82
|
-
return {
|
|
83
|
-
ok: false,
|
|
84
|
-
error: `Invalid schema output path for non-split mode (must be .ts file): ${s.output}`,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if (s.exportType !== undefined && typeof s.exportType !== 'boolean') {
|
|
89
|
-
return {
|
|
90
|
-
ok: false,
|
|
91
|
-
error: `Invalid schema exportType format for zod-openapi: ${String(s.exportType)}`,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (hasRoute) {
|
|
96
|
-
const r = zo.route;
|
|
97
|
-
if (!r)
|
|
98
|
-
return { ok: false, error: 'Invalid config: zod-openapi.route is undefined' };
|
|
99
|
-
if (typeof r.import !== 'string') {
|
|
100
|
-
return {
|
|
101
|
-
ok: false,
|
|
102
|
-
error: `Invalid route import format for zod-openapi: ${String(r.import)}`,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
if (r.split !== undefined && typeof r.split !== 'boolean') {
|
|
106
|
-
return {
|
|
107
|
-
ok: false,
|
|
108
|
-
error: `Invalid route split format for zod-openapi: ${String(r.split)}`,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
if (typeof r.output !== 'string') {
|
|
112
|
-
return { ok: false, error: `Invalid route output path: ${String(r.output)}` };
|
|
113
|
-
}
|
|
114
|
-
if (r.split === true) {
|
|
115
|
-
if (isTs(r.output)) {
|
|
116
|
-
return {
|
|
117
|
-
ok: false,
|
|
118
|
-
error: `Invalid route output path for split mode (must be a directory, not .ts): ${r.output}`,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
if (!isTs(r.output)) {
|
|
124
|
-
return {
|
|
125
|
-
ok: false,
|
|
126
|
-
error: `Invalid route output path for non-split mode (must be .ts file): ${r.output}`,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
const rpc = mod.default.rpc;
|
|
133
|
-
if (rpc) {
|
|
134
|
-
if (!isTs(rpc.output)) {
|
|
135
|
-
return { ok: false, error: `Invalid output format for rpc: ${String(rpc.output)}` };
|
|
136
|
-
}
|
|
137
|
-
if (typeof rpc.import !== 'string') {
|
|
138
|
-
return { ok: false, error: `Invalid import format for rpc: ${String(rpc.import)}` };
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return { ok: true, value: mod.default };
|
|
17
|
+
const result = parseConfig(mod.default);
|
|
18
|
+
if (!result.ok)
|
|
19
|
+
return { ok: false, error: result.error };
|
|
20
|
+
return { ok: true, value: result.value };
|
|
143
21
|
}
|
|
144
22
|
catch (e) {
|
|
145
23
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
146
24
|
}
|
|
147
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Helper to define a config with full type completion.
|
|
28
|
+
*
|
|
29
|
+
* @see config
|
|
30
|
+
*/
|
|
148
31
|
export function defineConfig(c) {
|
|
149
32
|
return c;
|
|
150
33
|
}
|
package/dist/core/route.js
CHANGED
|
@@ -35,16 +35,16 @@ export async function route(input, output, importPath, split) {
|
|
|
35
35
|
const importHono = `import { createRoute${includeZ ? ', z' : ''} } from '@hono/zod-openapi'`;
|
|
36
36
|
const importSchemas = schemaTokens.length > 0 ? `import { ${schemaTokens.join(',')} } from '${importPath}'` : '';
|
|
37
37
|
const finalSrc = [importHono, importSchemas, '\n', routesSrc].filter(Boolean).join('\n');
|
|
38
|
-
const
|
|
39
|
-
if (!
|
|
40
|
-
return { ok: false, error:
|
|
41
|
-
const
|
|
42
|
-
if (!
|
|
43
|
-
return { ok: false, error:
|
|
44
|
-
const
|
|
45
|
-
return
|
|
38
|
+
const fmtResult = await fmt(finalSrc);
|
|
39
|
+
if (!fmtResult.ok)
|
|
40
|
+
return { ok: false, error: fmtResult.error };
|
|
41
|
+
const mkdirResult = await mkdir(path.dirname(output));
|
|
42
|
+
if (!mkdirResult.ok)
|
|
43
|
+
return { ok: false, error: mkdirResult.error };
|
|
44
|
+
const writeResult = await writeFile(output, fmtResult.value);
|
|
45
|
+
return writeResult.ok
|
|
46
46
|
? { ok: true, value: `Generated route code written to ${output}` }
|
|
47
|
-
: { ok: false, error:
|
|
47
|
+
: { ok: false, error: writeResult.error };
|
|
48
48
|
}
|
|
49
49
|
const outDir = output.replace(/\.ts$/, '');
|
|
50
50
|
const blocks = extractRouteBlocks(routesSrc);
|
|
@@ -54,16 +54,16 @@ export async function route(input, output, importPath, split) {
|
|
|
54
54
|
const importHono = `import { createRoute${includeZ ? ', z' : ''} } from '@hono/zod-openapi'`;
|
|
55
55
|
const importSchemas = schemaTokens.length > 0 ? `import { ${schemaTokens.join(',')} } from '${importPath}'` : '';
|
|
56
56
|
const finalSrc = [importHono, importSchemas, '\n', routesSrc].filter(Boolean).join('\n');
|
|
57
|
-
const
|
|
58
|
-
if (!
|
|
59
|
-
return { ok: false, error:
|
|
60
|
-
const
|
|
61
|
-
if (!
|
|
62
|
-
return { ok: false, error:
|
|
63
|
-
const
|
|
64
|
-
return
|
|
57
|
+
const fmtResult = await fmt(finalSrc);
|
|
58
|
+
if (!fmtResult.ok)
|
|
59
|
+
return { ok: false, error: fmtResult.error };
|
|
60
|
+
const mkdirResult = await mkdir(path.dirname(output));
|
|
61
|
+
if (!mkdirResult.ok)
|
|
62
|
+
return { ok: false, error: mkdirResult.error };
|
|
63
|
+
const writeResult = await writeFile(output, fmtResult.value);
|
|
64
|
+
return writeResult.ok
|
|
65
65
|
? { ok: true, value: `Generated route code written to ${output}` }
|
|
66
|
-
: { ok: false, error:
|
|
66
|
+
: { ok: false, error: writeResult.error };
|
|
67
67
|
}
|
|
68
68
|
for (const { name, block } of blocks) {
|
|
69
69
|
const includeZ = block.includes('z.');
|
|
@@ -71,26 +71,29 @@ export async function route(input, output, importPath, split) {
|
|
|
71
71
|
const importHono = `import { createRoute${includeZ ? ', z' : ''} } from '@hono/zod-openapi'`;
|
|
72
72
|
const importSchemas = schemaTokens.length > 0 ? `import { ${schemaTokens.join(',')} } from '${importPath}'` : '';
|
|
73
73
|
const fileSrc = [importHono, importSchemas, '\n', block, ''].filter(Boolean).join('\n');
|
|
74
|
-
const
|
|
75
|
-
if (!
|
|
76
|
-
return { ok: false, error:
|
|
74
|
+
const fmtResult = await fmt(fileSrc);
|
|
75
|
+
if (!fmtResult.ok)
|
|
76
|
+
return { ok: false, error: fmtResult.error };
|
|
77
77
|
const filePath = `${outDir}/${lowerFirst(name)}.ts`;
|
|
78
|
-
const
|
|
79
|
-
if (!
|
|
80
|
-
return { ok: false, error:
|
|
81
|
-
const
|
|
82
|
-
if (!
|
|
83
|
-
return { ok: false, error:
|
|
78
|
+
const mkdirResult = await mkdir(path.dirname(filePath));
|
|
79
|
+
if (!mkdirResult.ok)
|
|
80
|
+
return { ok: false, error: mkdirResult.error };
|
|
81
|
+
const writeResult = await writeFile(filePath, fmtResult.value);
|
|
82
|
+
if (!writeResult.ok)
|
|
83
|
+
return { ok: false, error: writeResult.error };
|
|
84
84
|
}
|
|
85
|
-
const indexBody = `${blocks
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
if (!
|
|
91
|
-
return { ok: false, error:
|
|
92
|
-
const
|
|
93
|
-
if (!
|
|
94
|
-
return { ok: false, error:
|
|
85
|
+
const indexBody = `${blocks
|
|
86
|
+
.sort()
|
|
87
|
+
.map(({ name }) => `export * from './${lowerFirst(name)}'`)
|
|
88
|
+
.join('\n')}\n`;
|
|
89
|
+
const fmtResult = await fmt(indexBody);
|
|
90
|
+
if (!fmtResult.ok)
|
|
91
|
+
return { ok: false, error: fmtResult.error };
|
|
92
|
+
const mkdirResult = await mkdir(path.dirname(`${outDir}/index.ts`));
|
|
93
|
+
if (!mkdirResult.ok)
|
|
94
|
+
return { ok: false, error: mkdirResult.error };
|
|
95
|
+
const writeResult = await writeFile(`${outDir}/index.ts`, fmtResult.value);
|
|
96
|
+
if (!writeResult.ok)
|
|
97
|
+
return { ok: false, error: writeResult.error };
|
|
95
98
|
return { ok: true, value: `Generated route code written to ${outDir}/*.ts (index.ts included)` };
|
|
96
99
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate RPC client wrappers from an OpenAPI/TypeSpec source.
|
|
3
|
+
*
|
|
4
|
+
* - When `split=true`, writes one file per RPC function under `output` (directory) and an `index.ts` barrel.
|
|
5
|
+
* - Otherwise, emits a single `.ts` file at `output`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function rpc(input: `${string}.yaml` | `${string}.json` | `${string}.tsp`, output: string | `${string}.ts`, importPath: string, split?: boolean): Promise<{
|
|
8
|
+
readonly ok: true;
|
|
9
|
+
readonly value: string;
|
|
10
|
+
} | {
|
|
11
|
+
readonly ok: false;
|
|
12
|
+
readonly error: string;
|
|
13
|
+
}>;
|