hono-takibi 0.9.21 → 0.9.23
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 +11 -3
- package/dist/config/index.d.ts +1 -6
- package/dist/config/index.js +3 -3
- package/dist/core/core.js +4 -4
- package/dist/core/takibi.js +1 -8
- package/dist/generator/rpc/index.js +24 -77
- package/dist/helper/get-route-maps.js +3 -1
- package/dist/utils/index.d.ts +14 -0
- package/dist/utils/index.js +39 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import core from '../core/core.js';
|
|
|
5
5
|
import { takibi } from '../core/takibi.js';
|
|
6
6
|
import rpc from '../generator/rpc/index.js';
|
|
7
7
|
// import { honoRpcWithSWR } from '../generator/swr/index.js'
|
|
8
|
-
import { parseCli } from '../utils/index.js';
|
|
8
|
+
import { parseCli, parseIO } from '../utils/index.js';
|
|
9
9
|
const HELP_TEXT = `Usage: hono-takibi <input.{yaml,json,tsp}> -o <routes.ts> [options]
|
|
10
10
|
|
|
11
11
|
Options:
|
|
@@ -81,13 +81,21 @@ export async function honoTakibi() {
|
|
|
81
81
|
return { ok: false, error: configResult.error };
|
|
82
82
|
}
|
|
83
83
|
const c = configResult.value;
|
|
84
|
-
const
|
|
85
|
-
|
|
84
|
+
const zodOpenAPIConfigResult = parseIO(c['zod-openapi']);
|
|
85
|
+
if (!zodOpenAPIConfigResult.ok) {
|
|
86
|
+
return { ok: false, error: zodOpenAPIConfigResult.error };
|
|
87
|
+
}
|
|
88
|
+
const takibiResult = c['zod-openapi']
|
|
89
|
+
? await takibi(c['zod-openapi']?.input, c['zod-openapi']?.output, c['zod-openapi']?.exportSchema ?? false, c['zod-openapi']?.exportType ?? false, false, // template
|
|
86
90
|
false)
|
|
87
91
|
: undefined;
|
|
88
92
|
if (takibiResult && !takibiResult.ok) {
|
|
89
93
|
return { ok: false, error: takibiResult.error };
|
|
90
94
|
}
|
|
95
|
+
const rpcConfigResult = parseIO(c.rpc);
|
|
96
|
+
if (!rpcConfigResult.ok) {
|
|
97
|
+
return { ok: false, error: rpcConfigResult.error };
|
|
98
|
+
}
|
|
91
99
|
const rpcResult = c.rpc
|
|
92
100
|
? await core(c.rpc.input, c.rpc.output, c.rpc.import, 'Generated RPC code written to', rpc)
|
|
93
101
|
: undefined;
|
package/dist/config/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
type Config = {
|
|
2
|
-
'
|
|
2
|
+
'zod-openapi'?: {
|
|
3
3
|
input: `${string}.yaml` | `${string}.json` | `${string}.tsp`;
|
|
4
4
|
output: `${string}.ts`;
|
|
5
5
|
exportType?: boolean;
|
|
@@ -10,11 +10,6 @@ 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
|
-
};
|
|
18
13
|
};
|
|
19
14
|
export declare function config(): Promise<{
|
|
20
15
|
ok: true;
|
package/dist/config/index.js
CHANGED
|
@@ -9,9 +9,9 @@ export async function config() {
|
|
|
9
9
|
register();
|
|
10
10
|
try {
|
|
11
11
|
const mod = await import(pathToFileURL(abs).href);
|
|
12
|
-
if (!('default' in mod)) {
|
|
13
|
-
|
|
14
|
-
}
|
|
12
|
+
// if (!('default' in mod)) {
|
|
13
|
+
// return { ok: false, error: 'Config must export default object' }
|
|
14
|
+
// }
|
|
15
15
|
return { ok: true, value: mod.default };
|
|
16
16
|
}
|
|
17
17
|
catch (e) {
|
package/dist/core/core.js
CHANGED
|
@@ -8,15 +8,15 @@ export default async function core(input, output, importCode, value, fn) {
|
|
|
8
8
|
return { ok: false, error: openAPIResult.error };
|
|
9
9
|
}
|
|
10
10
|
const openAPI = openAPIResult.value;
|
|
11
|
-
const
|
|
12
|
-
if (!
|
|
13
|
-
return { ok: false, error:
|
|
11
|
+
const fnResult = await fmt(fn(openAPI, importCode));
|
|
12
|
+
if (!fnResult.ok) {
|
|
13
|
+
return { ok: false, error: fnResult.error };
|
|
14
14
|
}
|
|
15
15
|
const mkdirResult = await mkdir(path.dirname(output));
|
|
16
16
|
if (!mkdirResult.ok) {
|
|
17
17
|
return { ok: false, error: mkdirResult.error };
|
|
18
18
|
}
|
|
19
|
-
const writeResult = await writeFile(output,
|
|
19
|
+
const writeResult = await writeFile(output, fnResult.value);
|
|
20
20
|
if (!writeResult.ok) {
|
|
21
21
|
return { ok: false, error: writeResult.error };
|
|
22
22
|
}
|
package/dist/core/takibi.js
CHANGED
|
@@ -4,7 +4,7 @@ import { mkdir, readdir, writeFile } from '../fsp/index.js';
|
|
|
4
4
|
import { app } from '../generator/zod-openapi-hono/app/index.js';
|
|
5
5
|
import zodOpenAPIHono from '../generator/zod-openapi-hono/openapi/index.js';
|
|
6
6
|
import { parseOpenAPI } from '../openapi/index.js';
|
|
7
|
-
import { groupHandlersByFileName, methodPath } from '../utils/index.js';
|
|
7
|
+
import { groupHandlersByFileName, isHttpMethod, methodPath } from '../utils/index.js';
|
|
8
8
|
/**
|
|
9
9
|
* Generates TypeScript code from an OpenAPI spec and optional templates.
|
|
10
10
|
*
|
|
@@ -109,13 +109,6 @@ export async function takibi(input, output, exportSchema, exportType, template,
|
|
|
109
109
|
async function zodOpenapiHonoHandler(openapi, output, test) {
|
|
110
110
|
const paths = openapi.paths;
|
|
111
111
|
const handlers = [];
|
|
112
|
-
const isHttpMethod = (v) => {
|
|
113
|
-
for (const m of ['get', 'put', 'post', 'delete', 'patch', 'options', 'head', 'trace']) {
|
|
114
|
-
if (m === v)
|
|
115
|
-
return true;
|
|
116
|
-
}
|
|
117
|
-
return false;
|
|
118
|
-
};
|
|
119
112
|
for (const [path, pathItem] of Object.entries(paths)) {
|
|
120
113
|
for (const [method] of Object.entries(pathItem)) {
|
|
121
114
|
if (!isHttpMethod(method))
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { methodPath } from '../../utils/index.js';
|
|
2
2
|
/* ─────────────────────────────── Guards ─────────────────────────────── */
|
|
3
|
-
/** Narrow to generic object records */
|
|
4
3
|
const isRecord = (v) => typeof v === 'object' && v !== null;
|
|
5
|
-
/** Narrow to OpenAPI paths object (shallow structural check) */
|
|
6
4
|
const isOpenAPIPaths = (v) => {
|
|
7
5
|
if (!isRecord(v))
|
|
8
6
|
return false;
|
|
@@ -11,20 +9,11 @@ const isOpenAPIPaths = (v) => {
|
|
|
11
9
|
return false;
|
|
12
10
|
return true;
|
|
13
11
|
};
|
|
14
|
-
/** Treat any object as Schema (we rely on downstream field checks) */
|
|
15
12
|
const isSchema = (v) => isRecord(v);
|
|
16
13
|
/* ─────────────────────────────── Formatters ─────────────────────────────── */
|
|
17
|
-
/** JS identifier check */
|
|
18
14
|
const isValidIdent = (s) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(s);
|
|
19
|
-
/** Escape single quotes and backslashes for single-quoted strings */
|
|
20
15
|
const esc = (s) => s.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
21
|
-
/**
|
|
22
|
-
* Convert an OpenAPI path to a client access chain.
|
|
23
|
-
* examples:
|
|
24
|
-
* '/' -> ".index"
|
|
25
|
-
* '/hono-x' -> "['hono-x']"
|
|
26
|
-
* '/posts/hono/{id}' -> ".posts.hono[':id']"
|
|
27
|
-
*/
|
|
16
|
+
/** '/'->'.index' | '/hono-x'->"['hono-x']" | '/posts/hono/{id}'->".posts.hono[':id']" */
|
|
28
17
|
const formatPath = (path) => {
|
|
29
18
|
const segs = (path === '/' ? ['index'] : path.replace(/^\/+/, '').split('/')).filter(Boolean);
|
|
30
19
|
return segs
|
|
@@ -35,7 +24,6 @@ const formatPath = (path) => {
|
|
|
35
24
|
: `['${esc(seg)}']`)
|
|
36
25
|
.join('');
|
|
37
26
|
};
|
|
38
|
-
/** 'type' to normalized list for uniform checks */
|
|
39
27
|
const isJSONTypeName = (s) => typeof s === 'string' &&
|
|
40
28
|
(s === 'object' ||
|
|
41
29
|
s === 'array' ||
|
|
@@ -51,7 +39,6 @@ const toTypeArray = (t) => {
|
|
|
51
39
|
return t.filter(isJSONTypeName);
|
|
52
40
|
return [];
|
|
53
41
|
};
|
|
54
|
-
/** Build literal union from enum values (kept compact) */
|
|
55
42
|
const literalFromEnum = (vals) => {
|
|
56
43
|
const toLit = (v) => typeof v === 'string'
|
|
57
44
|
? `'${v.replace(/'/g, "\\'")}'`
|
|
@@ -62,7 +49,6 @@ const literalFromEnum = (vals) => {
|
|
|
62
49
|
: 'unknown';
|
|
63
50
|
return vals.map(toLit).join('|');
|
|
64
51
|
};
|
|
65
|
-
/** Create a $ref resolver for #/components/schemas/... */
|
|
66
52
|
const createResolveRef = (schemas) => (ref) => {
|
|
67
53
|
if (!ref)
|
|
68
54
|
return undefined;
|
|
@@ -72,60 +58,52 @@ const createResolveRef = (schemas) => (ref) => {
|
|
|
72
58
|
const target = schemas[m[1]];
|
|
73
59
|
return isSchema(target) ? target : undefined;
|
|
74
60
|
};
|
|
75
|
-
/**
|
|
61
|
+
/** TS type printer (handles $ref / enums / combinators / additionalProperties / nullable) */
|
|
76
62
|
const createTsTypeFromSchema = (resolveRef) => {
|
|
77
63
|
const tt = (schema, seen = new Set()) => {
|
|
78
64
|
if (!schema)
|
|
79
65
|
return 'unknown';
|
|
80
|
-
// $ref resolution
|
|
81
66
|
if (schema.$ref) {
|
|
82
67
|
const tgt = resolveRef(schema.$ref);
|
|
83
68
|
return tt(tgt, seen);
|
|
84
69
|
}
|
|
85
|
-
// recursion guard
|
|
86
70
|
if (seen.has(schema))
|
|
87
71
|
return 'unknown';
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
// combinators
|
|
72
|
+
const next = new Set(seen);
|
|
73
|
+
next.add(schema);
|
|
91
74
|
if (Array.isArray(schema.oneOf) && schema.oneOf.length)
|
|
92
|
-
return schema.oneOf.map((s) => tt(s,
|
|
75
|
+
return schema.oneOf.map((s) => tt(s, next)).join('|') || 'unknown';
|
|
93
76
|
if (Array.isArray(schema.anyOf) && schema.anyOf.length)
|
|
94
|
-
return schema.anyOf.map((s) => tt(s,
|
|
77
|
+
return schema.anyOf.map((s) => tt(s, next)).join('|') || 'unknown';
|
|
95
78
|
if (Array.isArray(schema.allOf) && schema.allOf.length)
|
|
96
|
-
return schema.allOf.map((s) => tt(s,
|
|
97
|
-
// enum
|
|
79
|
+
return schema.allOf.map((s) => tt(s, next)).join('&') || 'unknown';
|
|
98
80
|
if (Array.isArray(schema.enum) && schema.enum.length) {
|
|
99
81
|
const base = literalFromEnum(schema.enum);
|
|
100
82
|
return schema.nullable ? `${base}|null` : base;
|
|
101
83
|
}
|
|
102
84
|
const types = toTypeArray(schema.type);
|
|
103
|
-
// array
|
|
85
|
+
// array (parentheses when inner contains union/intersection)
|
|
104
86
|
if (types.includes('array')) {
|
|
105
|
-
const
|
|
106
|
-
const
|
|
87
|
+
const item = isSchema(schema.items) ? schema.items : undefined;
|
|
88
|
+
const inner = tt(item, next);
|
|
89
|
+
const needParens = /[|&]/.test(inner) && !/^\(.*\)$/.test(inner);
|
|
90
|
+
const core = `${needParens ? `(${inner})` : inner}[]`;
|
|
107
91
|
return schema.nullable ? `${core}|null` : core;
|
|
108
92
|
}
|
|
109
|
-
// object
|
|
110
93
|
if (types.includes('object')) {
|
|
111
94
|
const req = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
112
95
|
const props = schema.properties ?? {};
|
|
113
96
|
const fields = Object.entries(props).map(([k, v]) => {
|
|
114
97
|
const opt = req.has(k) ? '' : '?';
|
|
115
98
|
const child = isSchema(v) ? v : undefined;
|
|
116
|
-
return `${k}${opt}:${tt(child,
|
|
99
|
+
return `${k}${opt}:${tt(child, next)}`;
|
|
117
100
|
});
|
|
118
101
|
const ap = schema.additionalProperties;
|
|
119
|
-
const addl = ap === true
|
|
120
|
-
? '[key:string]:unknown'
|
|
121
|
-
: isSchema(ap)
|
|
122
|
-
? `[key:string]:${tt(ap, nextSeen)}`
|
|
123
|
-
: '';
|
|
102
|
+
const addl = ap === true ? '[key:string]:unknown' : isSchema(ap) ? `[key:string]:${tt(ap, next)}` : '';
|
|
124
103
|
const members = [...fields, addl].filter(Boolean).join(',');
|
|
125
104
|
const core = `{${members}}`;
|
|
126
105
|
return schema.nullable ? `${core}|null` : core;
|
|
127
106
|
}
|
|
128
|
-
// primitives
|
|
129
107
|
if (types.length === 0)
|
|
130
108
|
return schema.nullable ? 'unknown|null' : 'unknown';
|
|
131
109
|
const prim = types
|
|
@@ -144,13 +122,11 @@ const isParameterObject = (v) => {
|
|
|
144
122
|
const pos = v.in;
|
|
145
123
|
return pos === 'path' || pos === 'query' || pos === 'header' || pos === 'cookie';
|
|
146
124
|
};
|
|
147
|
-
/** Extract components/parameters name from a ref-like value */
|
|
148
125
|
const refParamName = (refLike) => {
|
|
149
126
|
const ref = typeof refLike === 'string' ? refLike : isRefObject(refLike) ? refLike.$ref : undefined;
|
|
150
127
|
const m = ref?.match(/^#\/components\/parameters\/(.+)$/);
|
|
151
128
|
return m ? m[1] : undefined;
|
|
152
129
|
};
|
|
153
|
-
/** Build a resolver that returns normalized ParameterLike (resolving $ref) */
|
|
154
130
|
const createResolveParameter = (componentsParameters) => (p) => {
|
|
155
131
|
if (isParameterObject(p))
|
|
156
132
|
return p;
|
|
@@ -158,7 +134,6 @@ const createResolveParameter = (componentsParameters) => (p) => {
|
|
|
158
134
|
const cand = name ? componentsParameters[name] : undefined;
|
|
159
135
|
return isParameterObject(cand) ? cand : undefined;
|
|
160
136
|
};
|
|
161
|
-
/** Convert raw parameters array into ParameterLike[] */
|
|
162
137
|
const createToParameterLikes = (resolveParam) => (arr) => Array.isArray(arr)
|
|
163
138
|
? arr.reduce((acc, x) => {
|
|
164
139
|
const r = resolveParam(x);
|
|
@@ -178,7 +153,7 @@ const HTTP_METHODS = [
|
|
|
178
153
|
'patch',
|
|
179
154
|
'trace',
|
|
180
155
|
];
|
|
181
|
-
|
|
156
|
+
const hasSchemaProp = (v) => isRecord(v) && 'schema' in v;
|
|
182
157
|
const pickBodySchema = (op) => {
|
|
183
158
|
const rb = op.requestBody;
|
|
184
159
|
if (!isRecord(rb))
|
|
@@ -196,14 +171,12 @@ const pickBodySchema = (op) => {
|
|
|
196
171
|
];
|
|
197
172
|
for (const k of order) {
|
|
198
173
|
const media = isRecord(content[k]) ? content[k] : undefined;
|
|
199
|
-
if (
|
|
174
|
+
if (hasSchemaProp(media) && isSchema(media.schema))
|
|
200
175
|
return media.schema;
|
|
201
|
-
}
|
|
202
176
|
}
|
|
203
177
|
return undefined;
|
|
204
178
|
};
|
|
205
179
|
/* ─────────────────────────────── Args builders ─────────────────────────────── */
|
|
206
|
-
/** Build TS type for params arg (compact formatting) */
|
|
207
180
|
const createBuildParamsType = (tsTypeFromSchema) => (pathParams, queryParams) => {
|
|
208
181
|
const parts = [];
|
|
209
182
|
if (pathParams.length) {
|
|
@@ -216,7 +189,6 @@ const createBuildParamsType = (tsTypeFromSchema) => (pathParams, queryParams) =>
|
|
|
216
189
|
}
|
|
217
190
|
return parts.length ? `{${parts.join(',')}}` : '';
|
|
218
191
|
};
|
|
219
|
-
/** Build function argument signature */
|
|
220
192
|
const buildArgSignature = (paramsType, bodyType) => paramsType && bodyType
|
|
221
193
|
? `params:${paramsType}, body:${bodyType}`
|
|
222
194
|
: paramsType
|
|
@@ -224,20 +196,7 @@ const buildArgSignature = (paramsType, bodyType) => paramsType && bodyType
|
|
|
224
196
|
: bodyType
|
|
225
197
|
? `body:${bodyType}`
|
|
226
198
|
: '';
|
|
227
|
-
/**
|
|
228
|
-
const buildQueryPiece = (p) => {
|
|
229
|
-
const types = toTypeArray(p.schema?.type);
|
|
230
|
-
const isArr = types.includes('array');
|
|
231
|
-
const itemsInt = isArr && isSchema(p.schema?.items) && toTypeArray(p.schema?.items?.type).includes('integer');
|
|
232
|
-
const isInt = types.includes('integer');
|
|
233
|
-
const rhs = itemsInt
|
|
234
|
-
? `(params.query.${p.name}??[]).map((v:unknown)=>String(v))`
|
|
235
|
-
: isInt
|
|
236
|
-
? `String(params.query.${p.name})`
|
|
237
|
-
: `params.query.${p.name}`;
|
|
238
|
-
return `${p.name}:${rhs}`;
|
|
239
|
-
};
|
|
240
|
-
/** Build client call argument object (compact formatting) */
|
|
199
|
+
/** pass query as-is (keep numbers/arrays) */
|
|
241
200
|
const buildClientArgs = (pathParams, queryParams, hasBody) => {
|
|
242
201
|
const pieces = [];
|
|
243
202
|
if (pathParams.length) {
|
|
@@ -245,7 +204,7 @@ const buildClientArgs = (pathParams, queryParams, hasBody) => {
|
|
|
245
204
|
pieces.push(`param:{${inner}}`);
|
|
246
205
|
}
|
|
247
206
|
if (queryParams.length) {
|
|
248
|
-
const inner = queryParams.map(
|
|
207
|
+
const inner = queryParams.map((p) => `${p.name}:params.query.${p.name}`).join(',');
|
|
249
208
|
pieces.push(`query:{${inner}}`);
|
|
250
209
|
}
|
|
251
210
|
if (hasBody)
|
|
@@ -276,36 +235,25 @@ const generateOperationCode = (path, method, item, deps) => {
|
|
|
276
235
|
: `${deps.client}${clientAccess}.$${method}()`;
|
|
277
236
|
const summary = typeof op.summary === 'string' ? op.summary : '';
|
|
278
237
|
const description = typeof op.description === 'string' ? op.description : '';
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
` * ${method.toUpperCase()} ${path}\n` +
|
|
283
|
-
' */\n' +
|
|
284
|
-
`export async function ${funcName}(${argSig}) {\n` +
|
|
285
|
-
` return await ${call}\n` +
|
|
286
|
-
'}');
|
|
238
|
+
const summaryBlock = summary ? ` * ${summary}\n *\n` : '';
|
|
239
|
+
const descriptionBlock = description ? ` * ${description}\n *\n` : '';
|
|
240
|
+
return `/**\n${summaryBlock}${descriptionBlock} * ${method.toUpperCase()} ${path}\n */\nexport async function ${funcName}(${argSig}){return await ${call}}`;
|
|
287
241
|
};
|
|
288
242
|
/* ─────────────────────────────── Entry ─────────────────────────────── */
|
|
289
243
|
export default function rpc(openapi, importCode) {
|
|
290
244
|
const client = 'client';
|
|
291
245
|
const out = [];
|
|
292
|
-
|
|
293
|
-
const header =
|
|
294
|
-
const s = (importCode ?? '').trim();
|
|
295
|
-
return s.length ? `${s}\n\n` : '';
|
|
296
|
-
})();
|
|
297
|
-
// paths guard
|
|
246
|
+
const s = (importCode ?? '').trim();
|
|
247
|
+
const header = s.length ? `${s}\n\n` : '';
|
|
298
248
|
const pathsMaybe = openapi.paths;
|
|
299
249
|
if (!isOpenAPIPaths(pathsMaybe))
|
|
300
250
|
return header;
|
|
301
|
-
// schema & parameter resolvers
|
|
302
251
|
const schemas = openapi.components?.schemas ?? {};
|
|
303
252
|
const resolveRef = createResolveRef(schemas);
|
|
304
253
|
const tsTypeFromSchema = createTsTypeFromSchema(resolveRef);
|
|
305
254
|
const componentsParameters = openapi.components?.parameters ?? {};
|
|
306
255
|
const resolveParameter = createResolveParameter(componentsParameters);
|
|
307
256
|
const toParameterLikes = createToParameterLikes(resolveParameter);
|
|
308
|
-
// iterate path items & operations
|
|
309
257
|
for (const path in pathsMaybe) {
|
|
310
258
|
const rawItem = pathsMaybe[path];
|
|
311
259
|
if (!isRecord(rawItem))
|
|
@@ -331,6 +279,5 @@ export default function rpc(openapi, importCode) {
|
|
|
331
279
|
out.push(code);
|
|
332
280
|
}
|
|
333
281
|
}
|
|
334
|
-
|
|
335
|
-
return header + out.join('\n\n') + (out.length ? '\n' : '');
|
|
282
|
+
return `${header}${out.join('\n\n')}${out.length ? '\n' : ''}`;
|
|
336
283
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { methodPath } from '../utils/index.js';
|
|
1
|
+
import { isHttpMethod, methodPath } from '../utils/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Extracts route mappings from an OpenAPI specification.
|
|
4
4
|
*
|
|
@@ -9,6 +9,8 @@ export function getRouteMaps(openapi) {
|
|
|
9
9
|
const paths = openapi.paths;
|
|
10
10
|
const routeMappings = Object.entries(paths).flatMap(([path, pathItem]) => {
|
|
11
11
|
return Object.entries(pathItem).flatMap(([method]) => {
|
|
12
|
+
if (!isHttpMethod(method))
|
|
13
|
+
return [];
|
|
12
14
|
return {
|
|
13
15
|
routeName: `${methodPath(method, path)}Route`,
|
|
14
16
|
handlerName: `${methodPath(method, path)}RouteHandler`,
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -34,6 +34,13 @@ export declare function parseCli(args: readonly string[]): {
|
|
|
34
34
|
ok: false;
|
|
35
35
|
error: string;
|
|
36
36
|
};
|
|
37
|
+
export declare function parseIO<T>(section: T): {
|
|
38
|
+
ok: true;
|
|
39
|
+
value: T;
|
|
40
|
+
} | {
|
|
41
|
+
ok: false;
|
|
42
|
+
error: string;
|
|
43
|
+
};
|
|
37
44
|
/**
|
|
38
45
|
* Normalize a JSON Schema `type` value into an array of type strings.
|
|
39
46
|
*
|
|
@@ -241,6 +248,13 @@ export declare function isRefObject(value: unknown): value is {
|
|
|
241
248
|
$ref?: string;
|
|
242
249
|
[key: string]: unknown;
|
|
243
250
|
};
|
|
251
|
+
/**
|
|
252
|
+
* Checks if a string is a valid HTTP method.
|
|
253
|
+
*
|
|
254
|
+
* @param method - The HTTP method to check.
|
|
255
|
+
* @returns `true` if the method is a valid HTTP method; otherwise `false`.
|
|
256
|
+
*/
|
|
257
|
+
export declare function isHttpMethod(method: string): method is 'get' | 'put' | 'post' | 'delete' | 'patch' | 'options' | 'head' | 'trace';
|
|
244
258
|
/**
|
|
245
259
|
* Checks if all given content types share the same schema definition.
|
|
246
260
|
*
|
package/dist/utils/index.js
CHANGED
|
@@ -51,6 +51,29 @@ export function parseCli(args) {
|
|
|
51
51
|
},
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
+
export function parseIO(section) {
|
|
55
|
+
const inputExts = ['yaml', 'json', 'tsp'];
|
|
56
|
+
const outputExts = ['ts'];
|
|
57
|
+
const isString = (x) => typeof x === 'string';
|
|
58
|
+
const hasExt = (path, exts) => exts.some((e) => path.endsWith(`.${e}`));
|
|
59
|
+
if (section == null)
|
|
60
|
+
return { ok: true, value: section };
|
|
61
|
+
if (typeof section !== 'object')
|
|
62
|
+
return { ok: true, value: section };
|
|
63
|
+
if (Reflect.has(section, 'input')) {
|
|
64
|
+
const input = Reflect.get(section, 'input');
|
|
65
|
+
if (isString(input) && !hasExt(input, inputExts)) {
|
|
66
|
+
return { ok: false, error: 'input must be a .yaml, .json, or .tsp file' };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (Reflect.has(section, 'output')) {
|
|
70
|
+
const output = Reflect.get(section, 'output');
|
|
71
|
+
if (isString(output) && !hasExt(output, outputExts)) {
|
|
72
|
+
return { ok: false, error: 'output must be a .ts file' };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { ok: true, value: section };
|
|
76
|
+
}
|
|
54
77
|
/**
|
|
55
78
|
* Normalize a JSON Schema `type` value into an array of type strings.
|
|
56
79
|
*
|
|
@@ -302,6 +325,22 @@ export function getHandlerImports(handlerMaps) {
|
|
|
302
325
|
export function isRefObject(value) {
|
|
303
326
|
return typeof value === 'object' && value !== null;
|
|
304
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* Checks if a string is a valid HTTP method.
|
|
330
|
+
*
|
|
331
|
+
* @param method - The HTTP method to check.
|
|
332
|
+
* @returns `true` if the method is a valid HTTP method; otherwise `false`.
|
|
333
|
+
*/
|
|
334
|
+
export function isHttpMethod(method) {
|
|
335
|
+
return (method === 'get' ||
|
|
336
|
+
method === 'put' ||
|
|
337
|
+
method === 'post' ||
|
|
338
|
+
method === 'delete' ||
|
|
339
|
+
method === 'patch' ||
|
|
340
|
+
method === 'options' ||
|
|
341
|
+
method === 'head' ||
|
|
342
|
+
method === 'trace');
|
|
343
|
+
}
|
|
305
344
|
/**
|
|
306
345
|
* Checks if all given content types share the same schema definition.
|
|
307
346
|
*
|