apigen-ts 1.2.1 → 1.3.1
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/_template.ts +1 -1
- package/dist/cli.js +1 -1
- package/dist/{main-BZrWxHPM.mjs → main-BiX2OIVV.js} +86 -14
- package/dist/main.cjs +570 -11
- package/dist/main.d.cts +5 -2
- package/dist/main.d.mts +5 -2
- package/dist/main.js +1 -1
- package/dist/main.mjs +572 -10
- package/package.json +22 -24
- package/readme.md +101 -78
- package/dist/cli.cjs +0 -18
- package/dist/cli.mjs +0 -16
- package/dist/main-BLaUzCCM.cjs +0 -585
- package/dist/main-BZrWxHPM.js +0 -581
package/dist/_template.ts
CHANGED
|
@@ -69,7 +69,7 @@ export class ApiClient {
|
|
|
69
69
|
const headers = new Headers({ ...configHeaders, ...opts.headers })
|
|
70
70
|
const ct = headers.get("content-type") ?? "application/json"
|
|
71
71
|
|
|
72
|
-
let body: FormData | URLSearchParams | string |
|
|
72
|
+
let body: FormData | URLSearchParams | string | null = null
|
|
73
73
|
|
|
74
74
|
if (ct === "multipart/form-data" || ct === "application/x-www-form-urlencoded") {
|
|
75
75
|
// https://stackoverflow.com/a/61053359/3664464
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@ import fs from 'fs/promises';
|
|
|
2
2
|
import { join, dirname } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { cli } from 'cleye';
|
|
5
|
-
import
|
|
5
|
+
import { bundle, BaseResolver, createConfig } from '@redocly/openapi-core';
|
|
6
6
|
import { filterEmpty, filterNullable } from 'array-utils-ts';
|
|
7
7
|
import { get, uniq, upperFirst, isArray, isBoolean, sortBy, isObject, lowerFirst, uniqBy } from 'lodash-es';
|
|
8
8
|
import { convertObj } from 'swagger2openapi';
|
|
@@ -10,7 +10,7 @@ import ts from 'typescript';
|
|
|
10
10
|
import path from 'node:path';
|
|
11
11
|
|
|
12
12
|
var name = "apigen-ts";
|
|
13
|
-
var version = "1.
|
|
13
|
+
var version = "1.3.1";
|
|
14
14
|
|
|
15
15
|
const initCtx = (config) => {
|
|
16
16
|
return {
|
|
@@ -20,6 +20,7 @@ const initCtx = (config) => {
|
|
|
20
20
|
doc: { openapi: "3.1.0" },
|
|
21
21
|
parseDates: false,
|
|
22
22
|
inlineEnums: false,
|
|
23
|
+
fetchOptions: false,
|
|
23
24
|
headers: {},
|
|
24
25
|
...config,
|
|
25
26
|
logTag: "",
|
|
@@ -55,21 +56,51 @@ const getCliConfig = () => {
|
|
|
55
56
|
description: "Use inline enums instead of enum types",
|
|
56
57
|
default: false
|
|
57
58
|
},
|
|
59
|
+
fetchOptions: {
|
|
60
|
+
type: Boolean,
|
|
61
|
+
description: "Add fetch options (e.g. AbortSignal) as last argument to each method",
|
|
62
|
+
default: false
|
|
63
|
+
},
|
|
58
64
|
header: {
|
|
59
65
|
type: [String],
|
|
60
66
|
alias: "H",
|
|
61
67
|
description: 'HTTP header as key=value (e.g., -H "x-api-key: your-key"). Used only when generating code.',
|
|
62
68
|
default: []
|
|
69
|
+
},
|
|
70
|
+
filterPaths: {
|
|
71
|
+
type: String,
|
|
72
|
+
description: "Filter endpoints by path regex (e.g., --filter-paths '^/accounts')"
|
|
73
|
+
},
|
|
74
|
+
includeTags: {
|
|
75
|
+
type: [String],
|
|
76
|
+
description: "Only include operations with these tags (comma-separated or repeated flag)",
|
|
77
|
+
default: []
|
|
78
|
+
},
|
|
79
|
+
excludeTags: {
|
|
80
|
+
type: [String],
|
|
81
|
+
description: "Exclude operations with these tags (comma-separated or repeated flag)",
|
|
82
|
+
default: []
|
|
63
83
|
}
|
|
64
84
|
}
|
|
65
85
|
});
|
|
86
|
+
const parseTags = (items) => {
|
|
87
|
+
const tags = items.flatMap((x) => x.split(",")).map((x) => x.trim()).filter(Boolean);
|
|
88
|
+
return tags.length ? tags : void 0;
|
|
89
|
+
};
|
|
90
|
+
const filterPaths = argv.flags.filterPaths ? new RegExp(argv.flags.filterPaths) : void 0;
|
|
91
|
+
const includeTags = parseTags(argv.flags.includeTags);
|
|
92
|
+
const excludeTags = parseTags(argv.flags.excludeTags);
|
|
66
93
|
const config = {
|
|
67
94
|
source: argv._.source,
|
|
68
95
|
output: argv._.output ?? null,
|
|
69
96
|
name: argv.flags.name,
|
|
70
97
|
parseDates: argv.flags.parseDates,
|
|
71
98
|
inlineEnums: argv.flags.inlineEnums,
|
|
72
|
-
|
|
99
|
+
fetchOptions: argv.flags.fetchOptions,
|
|
100
|
+
headers: parseHeaders(argv.flags.header),
|
|
101
|
+
...filterPaths ? { filterPaths } : {},
|
|
102
|
+
...includeTags ? { includeTags } : {},
|
|
103
|
+
...excludeTags ? { excludeTags } : {}
|
|
73
104
|
};
|
|
74
105
|
return config;
|
|
75
106
|
};
|
|
@@ -108,8 +139,10 @@ const getReqSchema = (ctx, config) => {
|
|
|
108
139
|
return void 0;
|
|
109
140
|
};
|
|
110
141
|
const getRepSchema = (ctx, config) => {
|
|
111
|
-
const successCodes = Object.keys(config.responses ?? {}).filter((x) => x.startsWith("2")).filter((x) => get(config, ["responses", x
|
|
112
|
-
const
|
|
142
|
+
const successCodes = Object.keys(config.responses ?? {}).filter((x) => x.startsWith("2")).filter((x) => get(config, ["responses", x]));
|
|
143
|
+
const firstSuccess = unref(ctx, get(config, ["responses", successCodes[0]], {}));
|
|
144
|
+
if (!firstSuccess || !("content" in firstSuccess)) return void 0;
|
|
145
|
+
const cts = Object.entries(firstSuccess.content ?? {}).filter((x) => x[1].schema);
|
|
113
146
|
if (cts.length === 0) return void 0;
|
|
114
147
|
const ctJson = cts.find((x) => x[0].startsWith("application/json"));
|
|
115
148
|
if (ctJson) return ctJson[1].schema;
|
|
@@ -205,8 +238,16 @@ const makeInlineEnum = (s) => {
|
|
|
205
238
|
return f$2.createUnionTypeNode(tokens.map((x) => f$2.createLiteralTypeNode(x)));
|
|
206
239
|
}
|
|
207
240
|
if (s.type === "number") {
|
|
208
|
-
const tokens = uniq(values).map((x) =>
|
|
209
|
-
|
|
241
|
+
const tokens = uniq(values).map((x) => {
|
|
242
|
+
const n = x;
|
|
243
|
+
if (n < 0) {
|
|
244
|
+
return f$2.createLiteralTypeNode(
|
|
245
|
+
f$2.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, f$2.createNumericLiteral(-n))
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
return f$2.createLiteralTypeNode(f$2.createNumericLiteral(n));
|
|
249
|
+
});
|
|
250
|
+
return f$2.createUnionTypeNode(tokens);
|
|
210
251
|
}
|
|
211
252
|
if (s.type === "boolean") {
|
|
212
253
|
const tokens = [];
|
|
@@ -256,19 +297,24 @@ const makeType = (ctx, s) => {
|
|
|
256
297
|
if (t) return isArray2 ? f$2.createArrayTypeNode(t) : t;
|
|
257
298
|
}
|
|
258
299
|
if ("properties" in s && s.properties) {
|
|
259
|
-
|
|
300
|
+
let t = f$2.createTypeLiteralNode(
|
|
260
301
|
Object.entries(s.properties).map(([k, v]) => {
|
|
261
302
|
const r = s.required ?? [];
|
|
262
303
|
const q = r.includes(k) ? void 0 : f$2.createToken(ts.SyntaxKind.QuestionToken);
|
|
263
304
|
return f$2.createPropertySignature(void 0, f$2.createStringLiteral(k), q, mk(v));
|
|
264
305
|
})
|
|
265
306
|
);
|
|
307
|
+
if ("nullable" in s && s.nullable) {
|
|
308
|
+
return f$2.createUnionTypeNode([t, f$2.createLiteralTypeNode(f$2.createNull())]);
|
|
309
|
+
}
|
|
310
|
+
return t;
|
|
266
311
|
}
|
|
267
312
|
if ("type" in s) {
|
|
268
313
|
let t;
|
|
269
314
|
if (s.type === "object") t = makeObject(ctx, s);
|
|
270
315
|
else if (s.type === "boolean") t = f$2.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
|
|
271
316
|
else if (s.type === "number") t = f$2.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
|
|
317
|
+
else if (isConstantString(s)) t = f$2.createLiteralTypeNode(f$2.createStringLiteral(s.const));
|
|
272
318
|
else if (s.type === "string") t = f$2.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
|
|
273
319
|
else if (s.type === "null") t = f$2.createLiteralTypeNode(f$2.createNull());
|
|
274
320
|
else if (isArray(s.type)) t = makeLiteralUnion(ctx, s.type);
|
|
@@ -299,6 +345,9 @@ const isStringEnum = (s) => {
|
|
|
299
345
|
const isPrefixItems = (s) => {
|
|
300
346
|
return s.prefixItems !== void 0;
|
|
301
347
|
};
|
|
348
|
+
const isConstantString = (s) => {
|
|
349
|
+
return s.type === "string" && s.const !== void 0;
|
|
350
|
+
};
|
|
302
351
|
const makeTypeAlias = (ctx, name, s) => {
|
|
303
352
|
if (isStringEnum(s) && !ctx.inlineEnums) {
|
|
304
353
|
const tokens1 = uniq(s.enum);
|
|
@@ -390,7 +439,19 @@ const prepareOp = (ctx, cfg, opName) => {
|
|
|
390
439
|
urlReplacements[x.name] = name;
|
|
391
440
|
return f$1.createParameterDeclaration(void 0, void 0, name, void 0, type);
|
|
392
441
|
});
|
|
442
|
+
if (ctx.fetchOptions) {
|
|
443
|
+
fnArgs.push(
|
|
444
|
+
f$1.createParameterDeclaration(
|
|
445
|
+
void 0,
|
|
446
|
+
void 0,
|
|
447
|
+
"opts",
|
|
448
|
+
f$1.createToken(ts.SyntaxKind.QuestionToken),
|
|
449
|
+
f$1.createTypeReferenceNode(f$1.createIdentifier("ApigenRequest"), void 0)
|
|
450
|
+
)
|
|
451
|
+
);
|
|
452
|
+
}
|
|
393
453
|
const cbArgs = filterNullable([
|
|
454
|
+
ctx.fetchOptions ? f$1.createSpreadAssignment(f$1.createIdentifier("opts")) : void 0,
|
|
394
455
|
search.length ? f$1.createShorthandPropertyAssignment("search") : void 0,
|
|
395
456
|
reqSchema && f$1.createShorthandPropertyAssignment("body"),
|
|
396
457
|
reqSchema && reqSchema[0] !== "application/json" ? f$1.createPropertyAssignment(
|
|
@@ -444,6 +505,10 @@ const prepareRoutes = async (ctx) => {
|
|
|
444
505
|
for (const [path, pathConfig] of Object.entries(ctx.doc.paths ?? {})) {
|
|
445
506
|
ctx.logTag = `${"[ALL]".toUpperCase().padEnd(6, " ")} ${path}`;
|
|
446
507
|
if (!isObject(pathConfig)) continue;
|
|
508
|
+
if (ctx.filterPaths) {
|
|
509
|
+
const match = ctx.filterPaths instanceof RegExp ? ctx.filterPaths.test(path) : ctx.filterPaths(path);
|
|
510
|
+
if (!match) continue;
|
|
511
|
+
}
|
|
447
512
|
if ("$ref" in pathConfig) {
|
|
448
513
|
console.warn(`${ctx.logTag} $ref should be resolved before (skipping)`);
|
|
449
514
|
continue;
|
|
@@ -455,6 +520,9 @@ const prepareRoutes = async (ctx) => {
|
|
|
455
520
|
if (pathConfig.parameters) {
|
|
456
521
|
config.parameters = [...config.parameters ?? [], ...pathConfig.parameters];
|
|
457
522
|
}
|
|
523
|
+
const opTags = config.tags ?? [];
|
|
524
|
+
if (ctx.includeTags?.length && !opTags.some((t) => ctx.includeTags.includes(t))) continue;
|
|
525
|
+
if (ctx.excludeTags?.length && opTags.some((t) => ctx.excludeTags.includes(t))) continue;
|
|
458
526
|
const [ns, op] = getOpName(ctx, { ...config, method, path });
|
|
459
527
|
if (!routes[ns]) routes[ns] = [];
|
|
460
528
|
const joined = [ns, op].join(".");
|
|
@@ -501,9 +569,9 @@ const loadSchema = async ({
|
|
|
501
569
|
headers = {}
|
|
502
570
|
}) => {
|
|
503
571
|
if (url.startsWith("file://")) url = url.substring(7);
|
|
504
|
-
const { bundle } = await
|
|
572
|
+
const { bundle: bundle$1 } = await bundle({
|
|
505
573
|
ref: url,
|
|
506
|
-
config: await
|
|
574
|
+
config: await createConfig({}),
|
|
507
575
|
removeUnusedComponents: false,
|
|
508
576
|
externalRefResolver: new BaseResolver({
|
|
509
577
|
http: {
|
|
@@ -513,11 +581,12 @@ const loadSchema = async ({
|
|
|
513
581
|
}
|
|
514
582
|
})
|
|
515
583
|
});
|
|
516
|
-
|
|
517
|
-
|
|
584
|
+
const parsed = bundle$1.parsed;
|
|
585
|
+
if ("swagger" in parsed && upgrade) {
|
|
586
|
+
const { openapi } = await convertObj(parsed, { patch: true });
|
|
518
587
|
return openapi;
|
|
519
588
|
}
|
|
520
|
-
return
|
|
589
|
+
return parsed;
|
|
521
590
|
};
|
|
522
591
|
|
|
523
592
|
const f = ts.factory;
|
|
@@ -549,7 +618,10 @@ const formatCode = async (code) => {
|
|
|
549
618
|
};
|
|
550
619
|
|
|
551
620
|
const apigen = async (config) => {
|
|
552
|
-
const doc = await loadSchema({
|
|
621
|
+
const doc = await loadSchema({
|
|
622
|
+
url: config.source,
|
|
623
|
+
...config.headers ? { headers: config.headers } : {}
|
|
624
|
+
});
|
|
553
625
|
const ctx = initCtx({ ...config, doc });
|
|
554
626
|
const { modules, types } = await generateAst(ctx);
|
|
555
627
|
const filepath = join(dirname(fileURLToPath(import.meta.url)), "_template.ts");
|