apigen-ts 1.0.1 → 1.1.0
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.cjs +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/{main-Cic4LkJH.cjs → main-B2qgp9dv.cjs} +37 -30
- package/dist/{main-CRZklgfk.js → main-BvB08bJo.js} +36 -29
- package/dist/{main-CRZklgfk.mjs → main-BvB08bJo.mjs} +36 -29
- package/dist/main.cjs +1 -1
- package/dist/main.d.cts +1 -0
- package/dist/main.d.mts +1 -0
- package/dist/main.js +1 -1
- package/dist/main.mjs +1 -1
- package/package.json +9 -9
- package/readme.md +21 -0
package/dist/cli.cjs
CHANGED
package/dist/cli.js
CHANGED
package/dist/cli.mjs
CHANGED
|
@@ -13,15 +13,16 @@ var path = require('node:path');
|
|
|
13
13
|
|
|
14
14
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
15
15
|
var name = "apigen-ts";
|
|
16
|
-
var version = "1.0
|
|
16
|
+
var version = "1.1.0";
|
|
17
17
|
|
|
18
18
|
const initCtx = (config) => {
|
|
19
19
|
return {
|
|
20
20
|
source: "",
|
|
21
21
|
output: "",
|
|
22
22
|
name: "ApiClient",
|
|
23
|
-
parseDates: false,
|
|
24
23
|
doc: { openapi: "3.1.0" },
|
|
24
|
+
parseDates: false,
|
|
25
|
+
inlineEnums: false,
|
|
25
26
|
...config,
|
|
26
27
|
logTag: "",
|
|
27
28
|
usedNames: /* @__PURE__ */ new Set()
|
|
@@ -42,6 +43,11 @@ const getCliConfig = () => {
|
|
|
42
43
|
type: Boolean,
|
|
43
44
|
description: "parse dates as Date objects",
|
|
44
45
|
default: false
|
|
46
|
+
},
|
|
47
|
+
inlineEnums: {
|
|
48
|
+
type: Boolean,
|
|
49
|
+
description: "use inline enums instead of enum types",
|
|
50
|
+
default: false
|
|
45
51
|
}
|
|
46
52
|
}
|
|
47
53
|
});
|
|
@@ -49,13 +55,14 @@ const getCliConfig = () => {
|
|
|
49
55
|
source: argv._.source,
|
|
50
56
|
output: argv._.output ?? null,
|
|
51
57
|
name: argv.flags.name,
|
|
52
|
-
parseDates: argv.flags.parseDates
|
|
58
|
+
parseDates: argv.flags.parseDates,
|
|
59
|
+
inlineEnums: argv.flags.inlineEnums
|
|
53
60
|
};
|
|
54
61
|
return config;
|
|
55
62
|
};
|
|
56
63
|
|
|
57
64
|
const unref = (ctx, s) => {
|
|
58
|
-
if (!s) return
|
|
65
|
+
if (!s) return undefined;
|
|
59
66
|
if ("$ref" in s && s.$ref) {
|
|
60
67
|
const parts = s.$ref.replace("#/", "").split("/");
|
|
61
68
|
const obj = parts.reduce(
|
|
@@ -65,15 +72,15 @@ const unref = (ctx, s) => {
|
|
|
65
72
|
);
|
|
66
73
|
if (obj) return obj;
|
|
67
74
|
console.warn(`${ctx.logTag} ref ${s.$ref} not found`);
|
|
68
|
-
return
|
|
75
|
+
return undefined;
|
|
69
76
|
}
|
|
70
77
|
return s;
|
|
71
78
|
};
|
|
72
79
|
const getReqSchema = (ctx, config) => {
|
|
73
80
|
const req = unref(ctx, config.requestBody);
|
|
74
|
-
if (!req) return
|
|
81
|
+
if (!req) return undefined;
|
|
75
82
|
const cts = Object.entries(req.content ?? {}).map((x) => [x[0].split(";")[0], x[1].schema]).filter((x) => x[1]);
|
|
76
|
-
if (cts.length === 0) return
|
|
83
|
+
if (cts.length === 0) return undefined;
|
|
77
84
|
const pretenders = [
|
|
78
85
|
"application/json",
|
|
79
86
|
"text/",
|
|
@@ -85,18 +92,18 @@ const getReqSchema = (ctx, config) => {
|
|
|
85
92
|
if (ct) return ct;
|
|
86
93
|
}
|
|
87
94
|
cts.map((x) => x[0]);
|
|
88
|
-
return
|
|
95
|
+
return undefined;
|
|
89
96
|
};
|
|
90
97
|
const getRepSchema = (ctx, config) => {
|
|
91
98
|
const successCodes = Object.keys(config.responses ?? {}).filter((x) => x.startsWith("2")).filter((x) => lodashEs.get(config, ["responses", x, "content"]));
|
|
92
99
|
const cts = Object.entries(lodashEs.get(config, ["responses", successCodes[0], "content"], {})).filter((x) => x[1].schema);
|
|
93
|
-
if (cts.length === 0) return
|
|
100
|
+
if (cts.length === 0) return undefined;
|
|
94
101
|
const ctJson = cts.find((x) => x[0].startsWith("application/json"));
|
|
95
102
|
if (ctJson) return ctJson[1].schema;
|
|
96
103
|
const ctText = cts.find((x) => x[0].startsWith("text/"));
|
|
97
104
|
if (ctText) return { type: "string" };
|
|
98
105
|
cts.map((x) => x[0]).join(", ");
|
|
99
|
-
return
|
|
106
|
+
return undefined;
|
|
100
107
|
};
|
|
101
108
|
|
|
102
109
|
const f$2 = ts.factory;
|
|
@@ -172,9 +179,9 @@ const normalizeIdentifier = (val, asVar = false) => {
|
|
|
172
179
|
return name;
|
|
173
180
|
};
|
|
174
181
|
const makeInlineEnum = (s) => {
|
|
175
|
-
if (!s.enum) return
|
|
182
|
+
if (!s.enum) return undefined;
|
|
176
183
|
const values = arrayUtilsTs.filterEmpty(s.enum);
|
|
177
|
-
if (!values.length) return
|
|
184
|
+
if (!values.length) return undefined;
|
|
178
185
|
if (!s.type) {
|
|
179
186
|
if (values.every((x) => typeof x === "string")) s.type = "string";
|
|
180
187
|
if (values.every((x) => typeof x === "number")) s.type = "number";
|
|
@@ -195,7 +202,7 @@ const makeInlineEnum = (s) => {
|
|
|
195
202
|
return f$2.createUnionTypeNode(tokens.map((x) => f$2.createLiteralTypeNode(x)));
|
|
196
203
|
}
|
|
197
204
|
console.warn(`enum with unknown type "${s.type}" in`, s);
|
|
198
|
-
return
|
|
205
|
+
return undefined;
|
|
199
206
|
};
|
|
200
207
|
const makeObject = (ctx, s) => {
|
|
201
208
|
if (s.type !== "object") throw new Error(`makeObject: not an object ${JSON.stringify(s)}`);
|
|
@@ -209,7 +216,7 @@ const makeObject = (ctx, s) => {
|
|
|
209
216
|
};
|
|
210
217
|
const makeType = (ctx, s) => {
|
|
211
218
|
const mk = makeType.bind(null, ctx);
|
|
212
|
-
if (s ===
|
|
219
|
+
if (s === undefined) return f$2.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword);
|
|
213
220
|
if (s === null) return f$2.createLiteralTypeNode(f$2.createNull());
|
|
214
221
|
if ("$ref" in s && s.$ref) {
|
|
215
222
|
const parts = s.$ref.replace("#/", "").split("/");
|
|
@@ -233,8 +240,8 @@ const makeType = (ctx, s) => {
|
|
|
233
240
|
return f$2.createTypeLiteralNode(
|
|
234
241
|
Object.entries(s.properties).map(([k, v]) => {
|
|
235
242
|
const r = s.required ?? [];
|
|
236
|
-
const q = r.includes(k) ?
|
|
237
|
-
return f$2.createPropertySignature(
|
|
243
|
+
const q = r.includes(k) ? undefined : f$2.createToken(ts.SyntaxKind.QuestionToken);
|
|
244
|
+
return f$2.createPropertySignature(undefined, f$2.createStringLiteral(k), q, mk(v));
|
|
238
245
|
})
|
|
239
246
|
);
|
|
240
247
|
}
|
|
@@ -274,7 +281,7 @@ const isStringEnum = (s) => {
|
|
|
274
281
|
return false;
|
|
275
282
|
};
|
|
276
283
|
const makeTypeAlias = (ctx, name, s) => {
|
|
277
|
-
if (isStringEnum(s)) {
|
|
284
|
+
if (isStringEnum(s) && !ctx.inlineEnums) {
|
|
278
285
|
const tokens1 = lodashEs.uniq(s.enum);
|
|
279
286
|
const tokens2 = arrayUtilsTs.filterEmpty(tokens1);
|
|
280
287
|
if (tokens1.length !== tokens2.length) {
|
|
@@ -291,7 +298,7 @@ const makeTypeAlias = (ctx, name, s) => {
|
|
|
291
298
|
return f$2.createTypeAliasDeclaration(
|
|
292
299
|
[f$2.createToken(ts.SyntaxKind.ExportKeyword)],
|
|
293
300
|
f$2.createIdentifier(normalizeIdentifier(name, true)),
|
|
294
|
-
|
|
301
|
+
undefined,
|
|
295
302
|
makeType(ctx, s)
|
|
296
303
|
);
|
|
297
304
|
};
|
|
@@ -320,7 +327,7 @@ const getOpName = (ctx, op) => {
|
|
|
320
327
|
if (ctx.resolveName) {
|
|
321
328
|
const res = ctx.resolveName(ctx, op, proposal);
|
|
322
329
|
if (Array.isArray(res) && res.length === 2) return res;
|
|
323
|
-
if (res !==
|
|
330
|
+
if (res !== undefined) {
|
|
324
331
|
console.warn(`${ctx.logTag} resolveName should return [ns, fn] or undefined (skipping)`);
|
|
325
332
|
}
|
|
326
333
|
}
|
|
@@ -362,10 +369,10 @@ const prepareOp = (ctx, cfg, opName) => {
|
|
|
362
369
|
const name = normalizeIdentifier(x.name, true);
|
|
363
370
|
const type = makeType(ctx, x.schema);
|
|
364
371
|
urlReplacements[x.name] = name;
|
|
365
|
-
return f$1.createParameterDeclaration(
|
|
372
|
+
return f$1.createParameterDeclaration(undefined, undefined, name, undefined, type);
|
|
366
373
|
});
|
|
367
374
|
const cbArgs = arrayUtilsTs.filterNullable([
|
|
368
|
-
search.length ? f$1.createShorthandPropertyAssignment("search") :
|
|
375
|
+
search.length ? f$1.createShorthandPropertyAssignment("search") : undefined,
|
|
369
376
|
reqSchema && f$1.createShorthandPropertyAssignment("body"),
|
|
370
377
|
reqSchema && reqSchema[0] !== "application/json" ? f$1.createPropertyAssignment(
|
|
371
378
|
"headers",
|
|
@@ -375,16 +382,16 @@ const prepareOp = (ctx, cfg, opName) => {
|
|
|
375
382
|
f$1.createStringLiteral(reqSchema[0])
|
|
376
383
|
)
|
|
377
384
|
])
|
|
378
|
-
) :
|
|
385
|
+
) : undefined
|
|
379
386
|
]);
|
|
380
387
|
return f$1.createPropertyAssignment(
|
|
381
388
|
f$1.createIdentifier(normalizeIdentifier(opName)),
|
|
382
389
|
f$1.createArrowFunction(
|
|
383
|
-
|
|
384
|
-
|
|
390
|
+
undefined,
|
|
391
|
+
undefined,
|
|
385
392
|
fnArgs,
|
|
386
|
-
|
|
387
|
-
|
|
393
|
+
undefined,
|
|
394
|
+
undefined,
|
|
388
395
|
f$1.createBlock([
|
|
389
396
|
f$1.createReturnStatement(
|
|
390
397
|
f$1.createCallExpression(
|
|
@@ -406,10 +413,10 @@ const prepareOp = (ctx, cfg, opName) => {
|
|
|
406
413
|
};
|
|
407
414
|
const prepareNs = (ctx, name, handlers) => {
|
|
408
415
|
return f$1.createPropertyDeclaration(
|
|
409
|
-
|
|
416
|
+
undefined,
|
|
410
417
|
normalizeIdentifier(name),
|
|
411
|
-
|
|
412
|
-
|
|
418
|
+
undefined,
|
|
419
|
+
undefined,
|
|
413
420
|
f$1.createObjectLiteralExpression(handlers)
|
|
414
421
|
);
|
|
415
422
|
};
|
|
@@ -515,7 +522,7 @@ const apigen = async (config) => {
|
|
|
515
522
|
const doc = await loadSchema(config.source);
|
|
516
523
|
const ctx = initCtx({ ...config, doc });
|
|
517
524
|
const { modules, types } = await generateAst(ctx);
|
|
518
|
-
const filepath = path$1.join(path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('main-
|
|
525
|
+
const filepath = path$1.join(path$1.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('main-B2qgp9dv.cjs', document.baseURI).href)))), "_template.ts");
|
|
519
526
|
const file = await fs.readFile(filepath, "utf-8");
|
|
520
527
|
let code = [
|
|
521
528
|
`// Auto-generated by https://github.com/vladkens/apigen-ts`,
|
|
@@ -10,15 +10,16 @@ import ts from 'typescript';
|
|
|
10
10
|
import path from 'node:path';
|
|
11
11
|
|
|
12
12
|
var name = "apigen-ts";
|
|
13
|
-
var version = "1.0
|
|
13
|
+
var version = "1.1.0";
|
|
14
14
|
|
|
15
15
|
const initCtx = (config) => {
|
|
16
16
|
return {
|
|
17
17
|
source: "",
|
|
18
18
|
output: "",
|
|
19
19
|
name: "ApiClient",
|
|
20
|
-
parseDates: false,
|
|
21
20
|
doc: { openapi: "3.1.0" },
|
|
21
|
+
parseDates: false,
|
|
22
|
+
inlineEnums: false,
|
|
22
23
|
...config,
|
|
23
24
|
logTag: "",
|
|
24
25
|
usedNames: /* @__PURE__ */ new Set()
|
|
@@ -39,6 +40,11 @@ const getCliConfig = () => {
|
|
|
39
40
|
type: Boolean,
|
|
40
41
|
description: "parse dates as Date objects",
|
|
41
42
|
default: false
|
|
43
|
+
},
|
|
44
|
+
inlineEnums: {
|
|
45
|
+
type: Boolean,
|
|
46
|
+
description: "use inline enums instead of enum types",
|
|
47
|
+
default: false
|
|
42
48
|
}
|
|
43
49
|
}
|
|
44
50
|
});
|
|
@@ -46,13 +52,14 @@ const getCliConfig = () => {
|
|
|
46
52
|
source: argv._.source,
|
|
47
53
|
output: argv._.output ?? null,
|
|
48
54
|
name: argv.flags.name,
|
|
49
|
-
parseDates: argv.flags.parseDates
|
|
55
|
+
parseDates: argv.flags.parseDates,
|
|
56
|
+
inlineEnums: argv.flags.inlineEnums
|
|
50
57
|
};
|
|
51
58
|
return config;
|
|
52
59
|
};
|
|
53
60
|
|
|
54
61
|
const unref = (ctx, s) => {
|
|
55
|
-
if (!s) return
|
|
62
|
+
if (!s) return undefined;
|
|
56
63
|
if ("$ref" in s && s.$ref) {
|
|
57
64
|
const parts = s.$ref.replace("#/", "").split("/");
|
|
58
65
|
const obj = parts.reduce(
|
|
@@ -62,15 +69,15 @@ const unref = (ctx, s) => {
|
|
|
62
69
|
);
|
|
63
70
|
if (obj) return obj;
|
|
64
71
|
console.warn(`${ctx.logTag} ref ${s.$ref} not found`);
|
|
65
|
-
return
|
|
72
|
+
return undefined;
|
|
66
73
|
}
|
|
67
74
|
return s;
|
|
68
75
|
};
|
|
69
76
|
const getReqSchema = (ctx, config) => {
|
|
70
77
|
const req = unref(ctx, config.requestBody);
|
|
71
|
-
if (!req) return
|
|
78
|
+
if (!req) return undefined;
|
|
72
79
|
const cts = Object.entries(req.content ?? {}).map((x) => [x[0].split(";")[0], x[1].schema]).filter((x) => x[1]);
|
|
73
|
-
if (cts.length === 0) return
|
|
80
|
+
if (cts.length === 0) return undefined;
|
|
74
81
|
const pretenders = [
|
|
75
82
|
"application/json",
|
|
76
83
|
"text/",
|
|
@@ -82,18 +89,18 @@ const getReqSchema = (ctx, config) => {
|
|
|
82
89
|
if (ct) return ct;
|
|
83
90
|
}
|
|
84
91
|
cts.map((x) => x[0]);
|
|
85
|
-
return
|
|
92
|
+
return undefined;
|
|
86
93
|
};
|
|
87
94
|
const getRepSchema = (ctx, config) => {
|
|
88
95
|
const successCodes = Object.keys(config.responses ?? {}).filter((x) => x.startsWith("2")).filter((x) => get(config, ["responses", x, "content"]));
|
|
89
96
|
const cts = Object.entries(get(config, ["responses", successCodes[0], "content"], {})).filter((x) => x[1].schema);
|
|
90
|
-
if (cts.length === 0) return
|
|
97
|
+
if (cts.length === 0) return undefined;
|
|
91
98
|
const ctJson = cts.find((x) => x[0].startsWith("application/json"));
|
|
92
99
|
if (ctJson) return ctJson[1].schema;
|
|
93
100
|
const ctText = cts.find((x) => x[0].startsWith("text/"));
|
|
94
101
|
if (ctText) return { type: "string" };
|
|
95
102
|
cts.map((x) => x[0]).join(", ");
|
|
96
|
-
return
|
|
103
|
+
return undefined;
|
|
97
104
|
};
|
|
98
105
|
|
|
99
106
|
const f$2 = ts.factory;
|
|
@@ -169,9 +176,9 @@ const normalizeIdentifier = (val, asVar = false) => {
|
|
|
169
176
|
return name;
|
|
170
177
|
};
|
|
171
178
|
const makeInlineEnum = (s) => {
|
|
172
|
-
if (!s.enum) return
|
|
179
|
+
if (!s.enum) return undefined;
|
|
173
180
|
const values = filterEmpty(s.enum);
|
|
174
|
-
if (!values.length) return
|
|
181
|
+
if (!values.length) return undefined;
|
|
175
182
|
if (!s.type) {
|
|
176
183
|
if (values.every((x) => typeof x === "string")) s.type = "string";
|
|
177
184
|
if (values.every((x) => typeof x === "number")) s.type = "number";
|
|
@@ -192,7 +199,7 @@ const makeInlineEnum = (s) => {
|
|
|
192
199
|
return f$2.createUnionTypeNode(tokens.map((x) => f$2.createLiteralTypeNode(x)));
|
|
193
200
|
}
|
|
194
201
|
console.warn(`enum with unknown type "${s.type}" in`, s);
|
|
195
|
-
return
|
|
202
|
+
return undefined;
|
|
196
203
|
};
|
|
197
204
|
const makeObject = (ctx, s) => {
|
|
198
205
|
if (s.type !== "object") throw new Error(`makeObject: not an object ${JSON.stringify(s)}`);
|
|
@@ -206,7 +213,7 @@ const makeObject = (ctx, s) => {
|
|
|
206
213
|
};
|
|
207
214
|
const makeType = (ctx, s) => {
|
|
208
215
|
const mk = makeType.bind(null, ctx);
|
|
209
|
-
if (s ===
|
|
216
|
+
if (s === undefined) return f$2.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword);
|
|
210
217
|
if (s === null) return f$2.createLiteralTypeNode(f$2.createNull());
|
|
211
218
|
if ("$ref" in s && s.$ref) {
|
|
212
219
|
const parts = s.$ref.replace("#/", "").split("/");
|
|
@@ -230,8 +237,8 @@ const makeType = (ctx, s) => {
|
|
|
230
237
|
return f$2.createTypeLiteralNode(
|
|
231
238
|
Object.entries(s.properties).map(([k, v]) => {
|
|
232
239
|
const r = s.required ?? [];
|
|
233
|
-
const q = r.includes(k) ?
|
|
234
|
-
return f$2.createPropertySignature(
|
|
240
|
+
const q = r.includes(k) ? undefined : f$2.createToken(ts.SyntaxKind.QuestionToken);
|
|
241
|
+
return f$2.createPropertySignature(undefined, f$2.createStringLiteral(k), q, mk(v));
|
|
235
242
|
})
|
|
236
243
|
);
|
|
237
244
|
}
|
|
@@ -271,7 +278,7 @@ const isStringEnum = (s) => {
|
|
|
271
278
|
return false;
|
|
272
279
|
};
|
|
273
280
|
const makeTypeAlias = (ctx, name, s) => {
|
|
274
|
-
if (isStringEnum(s)) {
|
|
281
|
+
if (isStringEnum(s) && !ctx.inlineEnums) {
|
|
275
282
|
const tokens1 = uniq(s.enum);
|
|
276
283
|
const tokens2 = filterEmpty(tokens1);
|
|
277
284
|
if (tokens1.length !== tokens2.length) {
|
|
@@ -288,7 +295,7 @@ const makeTypeAlias = (ctx, name, s) => {
|
|
|
288
295
|
return f$2.createTypeAliasDeclaration(
|
|
289
296
|
[f$2.createToken(ts.SyntaxKind.ExportKeyword)],
|
|
290
297
|
f$2.createIdentifier(normalizeIdentifier(name, true)),
|
|
291
|
-
|
|
298
|
+
undefined,
|
|
292
299
|
makeType(ctx, s)
|
|
293
300
|
);
|
|
294
301
|
};
|
|
@@ -317,7 +324,7 @@ const getOpName = (ctx, op) => {
|
|
|
317
324
|
if (ctx.resolveName) {
|
|
318
325
|
const res = ctx.resolveName(ctx, op, proposal);
|
|
319
326
|
if (Array.isArray(res) && res.length === 2) return res;
|
|
320
|
-
if (res !==
|
|
327
|
+
if (res !== undefined) {
|
|
321
328
|
console.warn(`${ctx.logTag} resolveName should return [ns, fn] or undefined (skipping)`);
|
|
322
329
|
}
|
|
323
330
|
}
|
|
@@ -359,10 +366,10 @@ const prepareOp = (ctx, cfg, opName) => {
|
|
|
359
366
|
const name = normalizeIdentifier(x.name, true);
|
|
360
367
|
const type = makeType(ctx, x.schema);
|
|
361
368
|
urlReplacements[x.name] = name;
|
|
362
|
-
return f$1.createParameterDeclaration(
|
|
369
|
+
return f$1.createParameterDeclaration(undefined, undefined, name, undefined, type);
|
|
363
370
|
});
|
|
364
371
|
const cbArgs = filterNullable([
|
|
365
|
-
search.length ? f$1.createShorthandPropertyAssignment("search") :
|
|
372
|
+
search.length ? f$1.createShorthandPropertyAssignment("search") : undefined,
|
|
366
373
|
reqSchema && f$1.createShorthandPropertyAssignment("body"),
|
|
367
374
|
reqSchema && reqSchema[0] !== "application/json" ? f$1.createPropertyAssignment(
|
|
368
375
|
"headers",
|
|
@@ -372,16 +379,16 @@ const prepareOp = (ctx, cfg, opName) => {
|
|
|
372
379
|
f$1.createStringLiteral(reqSchema[0])
|
|
373
380
|
)
|
|
374
381
|
])
|
|
375
|
-
) :
|
|
382
|
+
) : undefined
|
|
376
383
|
]);
|
|
377
384
|
return f$1.createPropertyAssignment(
|
|
378
385
|
f$1.createIdentifier(normalizeIdentifier(opName)),
|
|
379
386
|
f$1.createArrowFunction(
|
|
380
|
-
|
|
381
|
-
|
|
387
|
+
undefined,
|
|
388
|
+
undefined,
|
|
382
389
|
fnArgs,
|
|
383
|
-
|
|
384
|
-
|
|
390
|
+
undefined,
|
|
391
|
+
undefined,
|
|
385
392
|
f$1.createBlock([
|
|
386
393
|
f$1.createReturnStatement(
|
|
387
394
|
f$1.createCallExpression(
|
|
@@ -403,10 +410,10 @@ const prepareOp = (ctx, cfg, opName) => {
|
|
|
403
410
|
};
|
|
404
411
|
const prepareNs = (ctx, name, handlers) => {
|
|
405
412
|
return f$1.createPropertyDeclaration(
|
|
406
|
-
|
|
413
|
+
undefined,
|
|
407
414
|
normalizeIdentifier(name),
|
|
408
|
-
|
|
409
|
-
|
|
415
|
+
undefined,
|
|
416
|
+
undefined,
|
|
410
417
|
f$1.createObjectLiteralExpression(handlers)
|
|
411
418
|
);
|
|
412
419
|
};
|
|
@@ -10,15 +10,16 @@ import ts from 'typescript';
|
|
|
10
10
|
import path from 'node:path';
|
|
11
11
|
|
|
12
12
|
var name = "apigen-ts";
|
|
13
|
-
var version = "1.0
|
|
13
|
+
var version = "1.1.0";
|
|
14
14
|
|
|
15
15
|
const initCtx = (config) => {
|
|
16
16
|
return {
|
|
17
17
|
source: "",
|
|
18
18
|
output: "",
|
|
19
19
|
name: "ApiClient",
|
|
20
|
-
parseDates: false,
|
|
21
20
|
doc: { openapi: "3.1.0" },
|
|
21
|
+
parseDates: false,
|
|
22
|
+
inlineEnums: false,
|
|
22
23
|
...config,
|
|
23
24
|
logTag: "",
|
|
24
25
|
usedNames: /* @__PURE__ */ new Set()
|
|
@@ -39,6 +40,11 @@ const getCliConfig = () => {
|
|
|
39
40
|
type: Boolean,
|
|
40
41
|
description: "parse dates as Date objects",
|
|
41
42
|
default: false
|
|
43
|
+
},
|
|
44
|
+
inlineEnums: {
|
|
45
|
+
type: Boolean,
|
|
46
|
+
description: "use inline enums instead of enum types",
|
|
47
|
+
default: false
|
|
42
48
|
}
|
|
43
49
|
}
|
|
44
50
|
});
|
|
@@ -46,13 +52,14 @@ const getCliConfig = () => {
|
|
|
46
52
|
source: argv._.source,
|
|
47
53
|
output: argv._.output ?? null,
|
|
48
54
|
name: argv.flags.name,
|
|
49
|
-
parseDates: argv.flags.parseDates
|
|
55
|
+
parseDates: argv.flags.parseDates,
|
|
56
|
+
inlineEnums: argv.flags.inlineEnums
|
|
50
57
|
};
|
|
51
58
|
return config;
|
|
52
59
|
};
|
|
53
60
|
|
|
54
61
|
const unref = (ctx, s) => {
|
|
55
|
-
if (!s) return
|
|
62
|
+
if (!s) return undefined;
|
|
56
63
|
if ("$ref" in s && s.$ref) {
|
|
57
64
|
const parts = s.$ref.replace("#/", "").split("/");
|
|
58
65
|
const obj = parts.reduce(
|
|
@@ -62,15 +69,15 @@ const unref = (ctx, s) => {
|
|
|
62
69
|
);
|
|
63
70
|
if (obj) return obj;
|
|
64
71
|
console.warn(`${ctx.logTag} ref ${s.$ref} not found`);
|
|
65
|
-
return
|
|
72
|
+
return undefined;
|
|
66
73
|
}
|
|
67
74
|
return s;
|
|
68
75
|
};
|
|
69
76
|
const getReqSchema = (ctx, config) => {
|
|
70
77
|
const req = unref(ctx, config.requestBody);
|
|
71
|
-
if (!req) return
|
|
78
|
+
if (!req) return undefined;
|
|
72
79
|
const cts = Object.entries(req.content ?? {}).map((x) => [x[0].split(";")[0], x[1].schema]).filter((x) => x[1]);
|
|
73
|
-
if (cts.length === 0) return
|
|
80
|
+
if (cts.length === 0) return undefined;
|
|
74
81
|
const pretenders = [
|
|
75
82
|
"application/json",
|
|
76
83
|
"text/",
|
|
@@ -82,18 +89,18 @@ const getReqSchema = (ctx, config) => {
|
|
|
82
89
|
if (ct) return ct;
|
|
83
90
|
}
|
|
84
91
|
cts.map((x) => x[0]);
|
|
85
|
-
return
|
|
92
|
+
return undefined;
|
|
86
93
|
};
|
|
87
94
|
const getRepSchema = (ctx, config) => {
|
|
88
95
|
const successCodes = Object.keys(config.responses ?? {}).filter((x) => x.startsWith("2")).filter((x) => get(config, ["responses", x, "content"]));
|
|
89
96
|
const cts = Object.entries(get(config, ["responses", successCodes[0], "content"], {})).filter((x) => x[1].schema);
|
|
90
|
-
if (cts.length === 0) return
|
|
97
|
+
if (cts.length === 0) return undefined;
|
|
91
98
|
const ctJson = cts.find((x) => x[0].startsWith("application/json"));
|
|
92
99
|
if (ctJson) return ctJson[1].schema;
|
|
93
100
|
const ctText = cts.find((x) => x[0].startsWith("text/"));
|
|
94
101
|
if (ctText) return { type: "string" };
|
|
95
102
|
cts.map((x) => x[0]).join(", ");
|
|
96
|
-
return
|
|
103
|
+
return undefined;
|
|
97
104
|
};
|
|
98
105
|
|
|
99
106
|
const f$2 = ts.factory;
|
|
@@ -169,9 +176,9 @@ const normalizeIdentifier = (val, asVar = false) => {
|
|
|
169
176
|
return name;
|
|
170
177
|
};
|
|
171
178
|
const makeInlineEnum = (s) => {
|
|
172
|
-
if (!s.enum) return
|
|
179
|
+
if (!s.enum) return undefined;
|
|
173
180
|
const values = filterEmpty(s.enum);
|
|
174
|
-
if (!values.length) return
|
|
181
|
+
if (!values.length) return undefined;
|
|
175
182
|
if (!s.type) {
|
|
176
183
|
if (values.every((x) => typeof x === "string")) s.type = "string";
|
|
177
184
|
if (values.every((x) => typeof x === "number")) s.type = "number";
|
|
@@ -192,7 +199,7 @@ const makeInlineEnum = (s) => {
|
|
|
192
199
|
return f$2.createUnionTypeNode(tokens.map((x) => f$2.createLiteralTypeNode(x)));
|
|
193
200
|
}
|
|
194
201
|
console.warn(`enum with unknown type "${s.type}" in`, s);
|
|
195
|
-
return
|
|
202
|
+
return undefined;
|
|
196
203
|
};
|
|
197
204
|
const makeObject = (ctx, s) => {
|
|
198
205
|
if (s.type !== "object") throw new Error(`makeObject: not an object ${JSON.stringify(s)}`);
|
|
@@ -206,7 +213,7 @@ const makeObject = (ctx, s) => {
|
|
|
206
213
|
};
|
|
207
214
|
const makeType = (ctx, s) => {
|
|
208
215
|
const mk = makeType.bind(null, ctx);
|
|
209
|
-
if (s ===
|
|
216
|
+
if (s === undefined) return f$2.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword);
|
|
210
217
|
if (s === null) return f$2.createLiteralTypeNode(f$2.createNull());
|
|
211
218
|
if ("$ref" in s && s.$ref) {
|
|
212
219
|
const parts = s.$ref.replace("#/", "").split("/");
|
|
@@ -230,8 +237,8 @@ const makeType = (ctx, s) => {
|
|
|
230
237
|
return f$2.createTypeLiteralNode(
|
|
231
238
|
Object.entries(s.properties).map(([k, v]) => {
|
|
232
239
|
const r = s.required ?? [];
|
|
233
|
-
const q = r.includes(k) ?
|
|
234
|
-
return f$2.createPropertySignature(
|
|
240
|
+
const q = r.includes(k) ? undefined : f$2.createToken(ts.SyntaxKind.QuestionToken);
|
|
241
|
+
return f$2.createPropertySignature(undefined, f$2.createStringLiteral(k), q, mk(v));
|
|
235
242
|
})
|
|
236
243
|
);
|
|
237
244
|
}
|
|
@@ -271,7 +278,7 @@ const isStringEnum = (s) => {
|
|
|
271
278
|
return false;
|
|
272
279
|
};
|
|
273
280
|
const makeTypeAlias = (ctx, name, s) => {
|
|
274
|
-
if (isStringEnum(s)) {
|
|
281
|
+
if (isStringEnum(s) && !ctx.inlineEnums) {
|
|
275
282
|
const tokens1 = uniq(s.enum);
|
|
276
283
|
const tokens2 = filterEmpty(tokens1);
|
|
277
284
|
if (tokens1.length !== tokens2.length) {
|
|
@@ -288,7 +295,7 @@ const makeTypeAlias = (ctx, name, s) => {
|
|
|
288
295
|
return f$2.createTypeAliasDeclaration(
|
|
289
296
|
[f$2.createToken(ts.SyntaxKind.ExportKeyword)],
|
|
290
297
|
f$2.createIdentifier(normalizeIdentifier(name, true)),
|
|
291
|
-
|
|
298
|
+
undefined,
|
|
292
299
|
makeType(ctx, s)
|
|
293
300
|
);
|
|
294
301
|
};
|
|
@@ -317,7 +324,7 @@ const getOpName = (ctx, op) => {
|
|
|
317
324
|
if (ctx.resolveName) {
|
|
318
325
|
const res = ctx.resolveName(ctx, op, proposal);
|
|
319
326
|
if (Array.isArray(res) && res.length === 2) return res;
|
|
320
|
-
if (res !==
|
|
327
|
+
if (res !== undefined) {
|
|
321
328
|
console.warn(`${ctx.logTag} resolveName should return [ns, fn] or undefined (skipping)`);
|
|
322
329
|
}
|
|
323
330
|
}
|
|
@@ -359,10 +366,10 @@ const prepareOp = (ctx, cfg, opName) => {
|
|
|
359
366
|
const name = normalizeIdentifier(x.name, true);
|
|
360
367
|
const type = makeType(ctx, x.schema);
|
|
361
368
|
urlReplacements[x.name] = name;
|
|
362
|
-
return f$1.createParameterDeclaration(
|
|
369
|
+
return f$1.createParameterDeclaration(undefined, undefined, name, undefined, type);
|
|
363
370
|
});
|
|
364
371
|
const cbArgs = filterNullable([
|
|
365
|
-
search.length ? f$1.createShorthandPropertyAssignment("search") :
|
|
372
|
+
search.length ? f$1.createShorthandPropertyAssignment("search") : undefined,
|
|
366
373
|
reqSchema && f$1.createShorthandPropertyAssignment("body"),
|
|
367
374
|
reqSchema && reqSchema[0] !== "application/json" ? f$1.createPropertyAssignment(
|
|
368
375
|
"headers",
|
|
@@ -372,16 +379,16 @@ const prepareOp = (ctx, cfg, opName) => {
|
|
|
372
379
|
f$1.createStringLiteral(reqSchema[0])
|
|
373
380
|
)
|
|
374
381
|
])
|
|
375
|
-
) :
|
|
382
|
+
) : undefined
|
|
376
383
|
]);
|
|
377
384
|
return f$1.createPropertyAssignment(
|
|
378
385
|
f$1.createIdentifier(normalizeIdentifier(opName)),
|
|
379
386
|
f$1.createArrowFunction(
|
|
380
|
-
|
|
381
|
-
|
|
387
|
+
undefined,
|
|
388
|
+
undefined,
|
|
382
389
|
fnArgs,
|
|
383
|
-
|
|
384
|
-
|
|
390
|
+
undefined,
|
|
391
|
+
undefined,
|
|
385
392
|
f$1.createBlock([
|
|
386
393
|
f$1.createReturnStatement(
|
|
387
394
|
f$1.createCallExpression(
|
|
@@ -403,10 +410,10 @@ const prepareOp = (ctx, cfg, opName) => {
|
|
|
403
410
|
};
|
|
404
411
|
const prepareNs = (ctx, name, handlers) => {
|
|
405
412
|
return f$1.createPropertyDeclaration(
|
|
406
|
-
|
|
413
|
+
undefined,
|
|
407
414
|
normalizeIdentifier(name),
|
|
408
|
-
|
|
409
|
-
|
|
415
|
+
undefined,
|
|
416
|
+
undefined,
|
|
410
417
|
f$1.createObjectLiteralExpression(handlers)
|
|
411
418
|
);
|
|
412
419
|
};
|
package/dist/main.cjs
CHANGED
package/dist/main.d.cts
CHANGED
package/dist/main.d.mts
CHANGED
package/dist/main.js
CHANGED
package/dist/main.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "apigen-ts",
|
|
4
|
-
"version": "1.0
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "vladkens <v.pronsky@gmail.com>",
|
|
7
7
|
"repository": "vladkens/apigen-ts",
|
|
@@ -22,23 +22,23 @@
|
|
|
22
22
|
"ci": "tsc --noEmit && yarn test-cov && yarn build"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@redocly/openapi-core": "1.
|
|
25
|
+
"@redocly/openapi-core": "1.27.2",
|
|
26
26
|
"@types/lodash-es": "4.17.12",
|
|
27
27
|
"@types/swagger2openapi": "7.0.4",
|
|
28
|
-
"array-utils-ts": "0.
|
|
28
|
+
"array-utils-ts": "1.0.2",
|
|
29
29
|
"cleye": "1.3.2",
|
|
30
30
|
"lodash-es": "4.17.21",
|
|
31
31
|
"swagger2openapi": "7.0.8"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@types/node": "22.7
|
|
35
|
-
"c8": "10.1.
|
|
36
|
-
"fetch-mock": "
|
|
37
|
-
"pkgroll": "2.
|
|
38
|
-
"prettier": "3.
|
|
34
|
+
"@types/node": "22.10.7",
|
|
35
|
+
"c8": "10.1.3",
|
|
36
|
+
"fetch-mock": "12.2.0",
|
|
37
|
+
"pkgroll": "2.6.1",
|
|
38
|
+
"prettier": "3.4.2",
|
|
39
39
|
"prettier-plugin-organize-imports": "4.1.0",
|
|
40
40
|
"tsm": "2.3.0",
|
|
41
|
-
"typescript": "5.
|
|
41
|
+
"typescript": "5.7.3",
|
|
42
42
|
"uvu": "0.5.6"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
package/readme.md
CHANGED
|
@@ -92,6 +92,26 @@ const pet = await api.pet.getPetById(1)
|
|
|
92
92
|
const createdAt: Date = pet.createdAt // date parsed from string with format=date-time
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
+
### String union as enums
|
|
96
|
+
|
|
97
|
+
You can generate string literal union instead of native enums in case you want to run in Node.js environment with [type-stripping](https://nodejs.org/api/typescript.html#type-stripping). To achive this pass `--inline-enums` command line argument or use `inlineEnums: true` in Node.js API.
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
yarn apigen-ts ./openapi.json ./api-client.ts --inline-enums
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This will generate:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
type MyEnum = "OptionA" | "OptionB"
|
|
107
|
+
|
|
108
|
+
// instead of
|
|
109
|
+
enum MyEnum = {
|
|
110
|
+
OptionA = "OptionA",
|
|
111
|
+
OptionB = "OptionB"
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
95
115
|
### Errors handling
|
|
96
116
|
|
|
97
117
|
An exception will be thrown for all unsuccessful return codes.
|
|
@@ -156,6 +176,7 @@ await apigen({
|
|
|
156
176
|
// everything below is optional
|
|
157
177
|
name: "MyApiClient", // default "ApiClient"
|
|
158
178
|
parseDates: true, // default false
|
|
179
|
+
inlineEnums: false, // default false, use string literal union instead of enum
|
|
159
180
|
resolveName(ctx, op, proposal) {
|
|
160
181
|
// proposal is [string, string] which represents module.funcName
|
|
161
182
|
if (proposal[0] === "users") return // will use default proposal
|