@ps-aux/api-client-gen 0.7.0-rc.2 → 0.7.0-rc.3
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 +7 -1
- package/dist/bin.cjs +7 -4
- package/dist/bin.mjs +7 -4
- package/dist/generateApiClient.cjs +1476 -1307
- package/dist/generateApiClient.mjs +1476 -1307
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +2101 -18
- package/dist/index.d.mts +2101 -18
- package/dist/index.d.ts +2101 -18
- package/dist/index.mjs +3 -3
- package/package.json +4 -3
- package/templates/http-client.eta +10 -1
- package/templates/procedure-call.ejs +2 -2
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import Path
|
|
1
|
+
import Path from 'path';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import fs__default from 'fs';
|
|
4
4
|
import fs$1 from 'fs/promises';
|
|
5
|
-
import Path from 'node:path';
|
|
6
|
-
import { readFile } from 'node:fs/promises';
|
|
7
|
-
import fs$2 from 'node:fs';
|
|
8
5
|
import { generateApi } from 'swagger-typescript-api';
|
|
9
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { readFile } from 'node:fs/promises';
|
|
8
|
+
import Path$1 from 'node:path';
|
|
9
|
+
import fs$2 from 'node:fs';
|
|
10
10
|
import { generate } from 'ts-to-zod';
|
|
11
11
|
|
|
12
12
|
/** A special constant with type `never` */
|
|
@@ -551,69 +551,6 @@ function formatError(error, mapper = (issue) => issue.message) {
|
|
|
551
551
|
processError(error);
|
|
552
552
|
return fieldErrors;
|
|
553
553
|
}
|
|
554
|
-
/** Format a ZodError as a human-readable string in the following form.
|
|
555
|
-
*
|
|
556
|
-
* From
|
|
557
|
-
*
|
|
558
|
-
* ```ts
|
|
559
|
-
* ZodError {
|
|
560
|
-
* issues: [
|
|
561
|
-
* {
|
|
562
|
-
* expected: 'string',
|
|
563
|
-
* code: 'invalid_type',
|
|
564
|
-
* path: [ 'username' ],
|
|
565
|
-
* message: 'Invalid input: expected string'
|
|
566
|
-
* },
|
|
567
|
-
* {
|
|
568
|
-
* expected: 'number',
|
|
569
|
-
* code: 'invalid_type',
|
|
570
|
-
* path: [ 'favoriteNumbers', 1 ],
|
|
571
|
-
* message: 'Invalid input: expected number'
|
|
572
|
-
* }
|
|
573
|
-
* ];
|
|
574
|
-
* }
|
|
575
|
-
* ```
|
|
576
|
-
*
|
|
577
|
-
* to
|
|
578
|
-
*
|
|
579
|
-
* ```
|
|
580
|
-
* username
|
|
581
|
-
* ✖ Expected number, received string at "username
|
|
582
|
-
* favoriteNumbers[0]
|
|
583
|
-
* ✖ Invalid input: expected number
|
|
584
|
-
* ```
|
|
585
|
-
*/
|
|
586
|
-
function toDotPath(_path) {
|
|
587
|
-
const segs = [];
|
|
588
|
-
const path = _path.map((seg) => (typeof seg === "object" ? seg.key : seg));
|
|
589
|
-
for (const seg of path) {
|
|
590
|
-
if (typeof seg === "number")
|
|
591
|
-
segs.push(`[${seg}]`);
|
|
592
|
-
else if (typeof seg === "symbol")
|
|
593
|
-
segs.push(`[${JSON.stringify(String(seg))}]`);
|
|
594
|
-
else if (/[^\w$]/.test(seg))
|
|
595
|
-
segs.push(`[${JSON.stringify(seg)}]`);
|
|
596
|
-
else {
|
|
597
|
-
if (segs.length)
|
|
598
|
-
segs.push(".");
|
|
599
|
-
segs.push(seg);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
return segs.join("");
|
|
603
|
-
}
|
|
604
|
-
function prettifyError(error) {
|
|
605
|
-
const lines = [];
|
|
606
|
-
// sort by path length
|
|
607
|
-
const issues = [...error.issues].sort((a, b) => (a.path ?? []).length - (b.path ?? []).length);
|
|
608
|
-
// Process each issue
|
|
609
|
-
for (const issue of issues) {
|
|
610
|
-
lines.push(`✖ ${issue.message}`);
|
|
611
|
-
if (issue.path?.length)
|
|
612
|
-
lines.push(` → at ${toDotPath(issue.path)}`);
|
|
613
|
-
}
|
|
614
|
-
// Convert Map to formatted string
|
|
615
|
-
return lines.join("\n");
|
|
616
|
-
}
|
|
617
554
|
|
|
618
555
|
const _parse = (_Err) => (schema, value, _ctx, _params) => {
|
|
619
556
|
const ctx = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
|
|
@@ -4082,6 +4019,53 @@ function superRefine(fn) {
|
|
|
4082
4019
|
return _superRefine(fn);
|
|
4083
4020
|
}
|
|
4084
4021
|
|
|
4022
|
+
const vNextOasGeneratorSchema = strictObject({
|
|
4023
|
+
selection: strictObject({
|
|
4024
|
+
ignoreOperationsWithTags: array(string()).default([]),
|
|
4025
|
+
allSchemas: boolean().default(true)
|
|
4026
|
+
}).optional(),
|
|
4027
|
+
codegen: strictObject({
|
|
4028
|
+
unwrap: boolean().default(true),
|
|
4029
|
+
withRequestParams: boolean().default(false),
|
|
4030
|
+
pathParamsStyle: _enum(["object", "positional"]).default("positional"),
|
|
4031
|
+
enumStyle: _enum(["enum", "union"]).default("enum")
|
|
4032
|
+
}),
|
|
4033
|
+
compat: strictObject({
|
|
4034
|
+
uppercaseEnumKeys: boolean(),
|
|
4035
|
+
swaggerTsApiRequiredBooleans: boolean()
|
|
4036
|
+
}).optional()
|
|
4037
|
+
});
|
|
4038
|
+
const legacyOasGeneratorSchema = strictObject({
|
|
4039
|
+
legacy: strictObject({
|
|
4040
|
+
ignoreOperationsWithTags: array(string()).optional()
|
|
4041
|
+
})
|
|
4042
|
+
});
|
|
4043
|
+
const configSchema = strictObject({
|
|
4044
|
+
srcSpec: string().trim().min(1),
|
|
4045
|
+
dstDir: string().trim().min(1),
|
|
4046
|
+
apiName: string().trim().min(1),
|
|
4047
|
+
openApiGenerator: union([
|
|
4048
|
+
vNextOasGeneratorSchema,
|
|
4049
|
+
legacyOasGeneratorSchema
|
|
4050
|
+
]),
|
|
4051
|
+
responseWrapper: strictObject({
|
|
4052
|
+
symbol: string().trim().min(1),
|
|
4053
|
+
import: string().trim().min(1).optional(),
|
|
4054
|
+
unwrapExpr: string().optional()
|
|
4055
|
+
}).optional(),
|
|
4056
|
+
zodSchemas: strictObject({
|
|
4057
|
+
enabled: boolean().optional(),
|
|
4058
|
+
localDateTimes: boolean().optional()
|
|
4059
|
+
}).optional()
|
|
4060
|
+
});
|
|
4061
|
+
const parseConfig = (userConfig, filePath) => {
|
|
4062
|
+
const parsed = configSchema.safeParse(userConfig);
|
|
4063
|
+
if (parsed.success) return parsed.data;
|
|
4064
|
+
throw new Error(`Invalid config at ${filePath}: ${parsed.error.message}`, {
|
|
4065
|
+
cause: parsed.error
|
|
4066
|
+
});
|
|
4067
|
+
};
|
|
4068
|
+
|
|
4085
4069
|
const downloadSpec = async (path, url) => {
|
|
4086
4070
|
let response;
|
|
4087
4071
|
try {
|
|
@@ -4101,6 +4085,86 @@ const downloadSpec = async (path, url) => {
|
|
|
4101
4085
|
await fs$1.writeFile(path, content);
|
|
4102
4086
|
};
|
|
4103
4087
|
|
|
4088
|
+
const toPascalCaseIdentifier = (str) => {
|
|
4089
|
+
const words = str.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
4090
|
+
const pascalCase = words.map((word) => word[0].toUpperCase() + word.substring(1)).join("");
|
|
4091
|
+
if (!pascalCase.length) return "Api";
|
|
4092
|
+
if (/^[0-9]/.test(pascalCase)) return `Api${pascalCase}`;
|
|
4093
|
+
return pascalCase;
|
|
4094
|
+
};
|
|
4095
|
+
const groupBy = (values, getKey) => {
|
|
4096
|
+
const groups = /* @__PURE__ */ new Map();
|
|
4097
|
+
for (const value of values) {
|
|
4098
|
+
const key = getKey(value);
|
|
4099
|
+
const existing = groups.get(key);
|
|
4100
|
+
if (existing) {
|
|
4101
|
+
existing.push(value);
|
|
4102
|
+
} else {
|
|
4103
|
+
groups.set(key, [value]);
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
return groups;
|
|
4107
|
+
};
|
|
4108
|
+
|
|
4109
|
+
const generateOpenApiClient = async (inputFile, {
|
|
4110
|
+
name,
|
|
4111
|
+
outputDir,
|
|
4112
|
+
ignoreOperationsWithTags
|
|
4113
|
+
}, log) => {
|
|
4114
|
+
log(`Will generate API client name=${name} to ${outputDir}`);
|
|
4115
|
+
const fileName = "index";
|
|
4116
|
+
const dstFile = Path.join(outputDir, `${fileName}.ts`);
|
|
4117
|
+
const prettier = await import('prettier');
|
|
4118
|
+
const prettierConfig = await prettier.resolveConfig(dstFile) ?? {};
|
|
4119
|
+
const prettierConfigForGenerator = {
|
|
4120
|
+
...prettierConfig,
|
|
4121
|
+
// swagger-typescript-api defaults to printWidth=120; keep Prettier default 80 unless explicitly configured.
|
|
4122
|
+
printWidth: prettierConfig.printWidth ?? 80
|
|
4123
|
+
};
|
|
4124
|
+
const ignoreTags = ignoreOperationsWithTags && new Set(ignoreOperationsWithTags);
|
|
4125
|
+
await generateApi({
|
|
4126
|
+
name: "index",
|
|
4127
|
+
output: outputDir,
|
|
4128
|
+
input: inputFile,
|
|
4129
|
+
// modular: true,
|
|
4130
|
+
httpClientType: "axios",
|
|
4131
|
+
templates: getTemplatesDir(),
|
|
4132
|
+
defaultResponseAsSuccess: true,
|
|
4133
|
+
sortTypes: true,
|
|
4134
|
+
// generateRouteTypes: true,
|
|
4135
|
+
singleHttpClient: true,
|
|
4136
|
+
// extractRequestBody: true,
|
|
4137
|
+
prettier: prettierConfigForGenerator,
|
|
4138
|
+
moduleNameFirstTag: true,
|
|
4139
|
+
apiClassName: toPascalCaseIdentifier(name),
|
|
4140
|
+
hooks: {
|
|
4141
|
+
onCreateRoute: (routeData) => {
|
|
4142
|
+
if (ignoreTags) {
|
|
4143
|
+
const ignore = routeData.raw.tags?.find(
|
|
4144
|
+
(t) => ignoreTags.has(t)
|
|
4145
|
+
);
|
|
4146
|
+
if (ignore) return false;
|
|
4147
|
+
}
|
|
4148
|
+
return routeData;
|
|
4149
|
+
}
|
|
4150
|
+
},
|
|
4151
|
+
// @ts-ignore
|
|
4152
|
+
codeGenConstructs: () => ({
|
|
4153
|
+
Keyword: {}
|
|
4154
|
+
})
|
|
4155
|
+
// extractRequestParams: true,
|
|
4156
|
+
});
|
|
4157
|
+
return { types: dstFile, promiseWrapper: [dstFile] };
|
|
4158
|
+
};
|
|
4159
|
+
const getThisScriptDirname = () => {
|
|
4160
|
+
return Path.dirname(fileURLToPath(import.meta.url));
|
|
4161
|
+
};
|
|
4162
|
+
const getTemplatesDir = () => {
|
|
4163
|
+
const currentDir = getThisScriptDirname();
|
|
4164
|
+
const templatesRelativePath = Path.basename(currentDir) === "dist" ? "../templates" : "../../../templates";
|
|
4165
|
+
return Path.resolve(currentDir, templatesRelativePath);
|
|
4166
|
+
};
|
|
4167
|
+
|
|
4104
4168
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4105
4169
|
const asRecord = (value) => {
|
|
4106
4170
|
return isRecord(value) ? value : void 0;
|
|
@@ -4526,31 +4590,6 @@ const syntheticOperationId = (method, path) => {
|
|
|
4526
4590
|
return `_${compact}`;
|
|
4527
4591
|
};
|
|
4528
4592
|
|
|
4529
|
-
const toPascalCaseIdentifier = (str) => {
|
|
4530
|
-
const words = str.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
4531
|
-
const pascalCase = words.map((word) => word[0].toUpperCase() + word.substring(1)).join("");
|
|
4532
|
-
if (!pascalCase.length) return "Api";
|
|
4533
|
-
if (/^[0-9]/.test(pascalCase)) return `Api${pascalCase}`;
|
|
4534
|
-
return pascalCase;
|
|
4535
|
-
};
|
|
4536
|
-
const groupBy = (values, getKey) => {
|
|
4537
|
-
const groups = /* @__PURE__ */ new Map();
|
|
4538
|
-
for (const value of values) {
|
|
4539
|
-
const key = getKey(value);
|
|
4540
|
-
const existing = groups.get(key);
|
|
4541
|
-
if (existing) {
|
|
4542
|
-
existing.push(value);
|
|
4543
|
-
} else {
|
|
4544
|
-
groups.set(key, [value]);
|
|
4545
|
-
}
|
|
4546
|
-
}
|
|
4547
|
-
return groups;
|
|
4548
|
-
};
|
|
4549
|
-
|
|
4550
|
-
var httpClientCommonTypesSource = "export type KnownRequestContentType =\n | 'application/json'\n | 'multipart/form-data'\n | 'application/x-www-form-urlencoded'\n\nexport type RequestContentType = KnownRequestContentType | string\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | QueryValue[]\n | Record<string, any>\n // Empty schema support\n | unknown\n\nexport type QueryParams = Record<string, QueryValue>\n\nexport type Request = {\n path: string\n method: 'GET' | 'POST' | 'PUT' | 'DELETE'\n format?: 'json' | 'document'\n headers?: Record<string, string>\n query?: QueryParams\n body?: any\n requestContentType?: RequestContentType\n}\n\nexport type QuerySerializer = (params: QueryParams) => string\n";
|
|
4551
|
-
|
|
4552
|
-
var httpClientPromiseTypesSource = "import type { Request } from './common-types'\n\nexport type HttpClient<RequestParams = never> = {\n request: <Data>(req: Request, params?: RequestParams) => Promise<Data>\n}\n";
|
|
4553
|
-
|
|
4554
4593
|
var __defProp$8 = Object.defineProperty;
|
|
4555
4594
|
var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4556
4595
|
var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -4559,10 +4598,14 @@ class TsCodegen {
|
|
|
4559
4598
|
this.typeExprCodegen = typeExprCodegen;
|
|
4560
4599
|
__publicField$8(this, "usedTypeRefs", []);
|
|
4561
4600
|
__publicField$8(this, "usedTypeRefKeys", /* @__PURE__ */ new Set());
|
|
4562
|
-
__publicField$8(this, "
|
|
4601
|
+
__publicField$8(this, "typeExpr", (typeExpr) => {
|
|
4563
4602
|
this.collectTypeRefsFromExpr(typeExpr);
|
|
4564
4603
|
return this.typeExprCodegen.toCode(typeExpr).code;
|
|
4565
4604
|
});
|
|
4605
|
+
__publicField$8(this, "declaration", (name, declaration) => {
|
|
4606
|
+
this.collectTypeRefsFromDeclaration(declaration);
|
|
4607
|
+
return this.toDeclarationCode(name, declaration);
|
|
4608
|
+
});
|
|
4566
4609
|
__publicField$8(this, "toChunk", (name, code, exports$1) => {
|
|
4567
4610
|
const exportedSymbols = new Set(exports$1);
|
|
4568
4611
|
const refs = this.getTypeRefs().filter((ref) => {
|
|
@@ -4578,6 +4621,26 @@ class TsCodegen {
|
|
|
4578
4621
|
__publicField$8(this, "getTypeRefs", () => {
|
|
4579
4622
|
return this.usedTypeRefs.map((ref) => ({ ...ref }));
|
|
4580
4623
|
});
|
|
4624
|
+
__publicField$8(this, "toDeclarationCode", (name, declaration) => {
|
|
4625
|
+
switch (declaration.kind) {
|
|
4626
|
+
case "typeAlias":
|
|
4627
|
+
return `type ${name} = ${this.typeExprCodegen.toCode(declaration.typeExpr).code}`;
|
|
4628
|
+
case "enum": {
|
|
4629
|
+
const members = declaration.members.map(
|
|
4630
|
+
(member) => ` ${member.name} = ${JSON.stringify(member.value)}`
|
|
4631
|
+
).join(",\n");
|
|
4632
|
+
return `enum ${name} {
|
|
4633
|
+
${members}
|
|
4634
|
+
}`;
|
|
4635
|
+
}
|
|
4636
|
+
default: {
|
|
4637
|
+
const exhaustive = declaration;
|
|
4638
|
+
throw new Error(
|
|
4639
|
+
`Unsupported TypeScript declaration: ${String(exhaustive)}`
|
|
4640
|
+
);
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
});
|
|
4581
4644
|
}
|
|
4582
4645
|
collectTypeRef(typeRef) {
|
|
4583
4646
|
if (typeRef.kind === "builtin") return;
|
|
@@ -4586,6 +4649,11 @@ class TsCodegen {
|
|
|
4586
4649
|
this.usedTypeRefKeys.add(key);
|
|
4587
4650
|
this.usedTypeRefs.push({ ...typeRef });
|
|
4588
4651
|
}
|
|
4652
|
+
collectTypeRefsFromDeclaration(declaration) {
|
|
4653
|
+
if (declaration.kind === "typeAlias") {
|
|
4654
|
+
this.collectTypeRefsFromExpr(declaration.typeExpr);
|
|
4655
|
+
}
|
|
4656
|
+
}
|
|
4589
4657
|
collectTypeRefsFromExpr(typeExpr) {
|
|
4590
4658
|
if (typeExpr.kind === "reference") {
|
|
4591
4659
|
this.collectTypeRef(typeExpr.ref);
|
|
@@ -4666,9 +4734,33 @@ const RESERVED_WORDS = /* @__PURE__ */ new Set([
|
|
|
4666
4734
|
"with",
|
|
4667
4735
|
"yield"
|
|
4668
4736
|
]);
|
|
4669
|
-
const TS_IDENTIFIER_PATTERN = /^[$A-Z_][0-9A-Z_$]*$/i;
|
|
4737
|
+
const TS_IDENTIFIER_PATTERN$1 = /^[$A-Z_][0-9A-Z_$]*$/i;
|
|
4670
4738
|
const isTsIdentifier = (value) => {
|
|
4671
|
-
return TS_IDENTIFIER_PATTERN.test(value);
|
|
4739
|
+
return TS_IDENTIFIER_PATTERN$1.test(value);
|
|
4740
|
+
};
|
|
4741
|
+
const splitIdentifierWords = (value) => {
|
|
4742
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
4743
|
+
};
|
|
4744
|
+
const toTsCamelIdentifier = (value, opts = {}) => {
|
|
4745
|
+
const words = splitIdentifierWords(value);
|
|
4746
|
+
if (!words.length) {
|
|
4747
|
+
throw new Error(
|
|
4748
|
+
`Could not derive a TypeScript identifier from "${value}".`
|
|
4749
|
+
);
|
|
4750
|
+
}
|
|
4751
|
+
const [firstWord, ...restWords] = words;
|
|
4752
|
+
let identifier = [
|
|
4753
|
+
firstWord[0].toLowerCase() + firstWord.substring(1),
|
|
4754
|
+
...restWords.map((word) => word[0].toUpperCase() + word.substring(1))
|
|
4755
|
+
].join("");
|
|
4756
|
+
if (/^[0-9]/.test(identifier)) {
|
|
4757
|
+
const prefix = opts.leadingDigitPrefix ?? "value";
|
|
4758
|
+
identifier = `${prefix}${identifier[0].toUpperCase()}${identifier.substring(1)}`;
|
|
4759
|
+
}
|
|
4760
|
+
if (RESERVED_WORDS.has(identifier)) {
|
|
4761
|
+
identifier = `${identifier}_`;
|
|
4762
|
+
}
|
|
4763
|
+
return identifier;
|
|
4672
4764
|
};
|
|
4673
4765
|
const toTsPropertyKey = (value) => {
|
|
4674
4766
|
return isTsIdentifier(value) ? value : JSON.stringify(value);
|
|
@@ -4785,1002 +4877,1268 @@ class TsCodegenFactory {
|
|
|
4785
4877
|
}
|
|
4786
4878
|
}
|
|
4787
4879
|
|
|
4880
|
+
const buildPathParamBindings = (paramNames) => {
|
|
4881
|
+
const usedBindings = /* @__PURE__ */ new Set();
|
|
4882
|
+
return paramNames.reduce((acc, paramName) => {
|
|
4883
|
+
acc[paramName] = toUniqueBindingName(paramName, usedBindings);
|
|
4884
|
+
return acc;
|
|
4885
|
+
}, {});
|
|
4886
|
+
};
|
|
4887
|
+
const toUniqueBindingName = (paramName, usedBindings) => {
|
|
4888
|
+
let base = toBindingBase(paramName);
|
|
4889
|
+
if (isReservedWord(base)) {
|
|
4890
|
+
base = `${base}_param`;
|
|
4891
|
+
}
|
|
4892
|
+
if (!usedBindings.has(base)) {
|
|
4893
|
+
usedBindings.add(base);
|
|
4894
|
+
return base;
|
|
4895
|
+
}
|
|
4896
|
+
let suffix = 2;
|
|
4897
|
+
let candidate = `${base}_${suffix}`;
|
|
4898
|
+
while (usedBindings.has(candidate)) {
|
|
4899
|
+
suffix += 1;
|
|
4900
|
+
candidate = `${base}_${suffix}`;
|
|
4901
|
+
}
|
|
4902
|
+
usedBindings.add(candidate);
|
|
4903
|
+
return candidate;
|
|
4904
|
+
};
|
|
4905
|
+
const toBindingBase = (paramName) => {
|
|
4906
|
+
if (isIdentifier(paramName)) {
|
|
4907
|
+
return paramName;
|
|
4908
|
+
}
|
|
4909
|
+
const sanitized = paramName.replace(/[^0-9A-Za-z_$]/g, "_");
|
|
4910
|
+
if (!sanitized.length) {
|
|
4911
|
+
return "pathParam";
|
|
4912
|
+
}
|
|
4913
|
+
if (/^[A-Za-z_$]/.test(sanitized)) {
|
|
4914
|
+
return sanitized;
|
|
4915
|
+
}
|
|
4916
|
+
return `_${sanitized}`;
|
|
4917
|
+
};
|
|
4918
|
+
const isIdentifier = (value) => {
|
|
4919
|
+
return /^[$A-Z_][0-9A-Z_$]*$/i.test(value);
|
|
4920
|
+
};
|
|
4921
|
+
const isReservedWord = (value) => {
|
|
4922
|
+
return RESERVED_WORDS.has(value);
|
|
4923
|
+
};
|
|
4924
|
+
|
|
4788
4925
|
var __defProp$5 = Object.defineProperty;
|
|
4789
4926
|
var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4790
4927
|
var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4791
|
-
class
|
|
4792
|
-
constructor(
|
|
4793
|
-
this.schemas = schemas;
|
|
4928
|
+
class ParamsConstructor {
|
|
4929
|
+
constructor(options) {
|
|
4794
4930
|
this.options = options;
|
|
4795
|
-
__publicField$5(this, "
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4931
|
+
__publicField$5(this, "process", (params, httpPath) => {
|
|
4932
|
+
const pathParamSpec = validatePathParams(params, httpPath);
|
|
4933
|
+
const pathParamBindings = pathParamSpec?.bindings;
|
|
4934
|
+
const funParams = params.flatMap(
|
|
4935
|
+
(param) => this.renderOperationParams(param, pathParamSpec)
|
|
4936
|
+
);
|
|
4937
|
+
const hasBody = params.some((p) => p.kind === "body");
|
|
4938
|
+
const hasQuery = params.some((p) => p.kind === "query");
|
|
4939
|
+
const path = this.renderPathTemplateLiteral(
|
|
4940
|
+
httpPath,
|
|
4941
|
+
this.options.paramNames.path,
|
|
4942
|
+
pathParamBindings
|
|
4943
|
+
);
|
|
4944
|
+
return {
|
|
4945
|
+
funParams,
|
|
4946
|
+
path,
|
|
4947
|
+
hasBody,
|
|
4948
|
+
hasQuery
|
|
4949
|
+
};
|
|
4804
4950
|
});
|
|
4805
|
-
__publicField$5(this, "
|
|
4806
|
-
if (!
|
|
4807
|
-
return
|
|
4951
|
+
__publicField$5(this, "renderOperationParams", (param, pathParamSpec) => {
|
|
4952
|
+
if (param.kind !== "path" || !pathParamSpec) {
|
|
4953
|
+
return [
|
|
4954
|
+
{
|
|
4955
|
+
identifier: this.paramName(param),
|
|
4956
|
+
typeExpr: param.typeExpr
|
|
4957
|
+
}
|
|
4958
|
+
];
|
|
4808
4959
|
}
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4960
|
+
if (this.options.pathParamsStyle === "positional") {
|
|
4961
|
+
return pathParamSpec.placeholderNames.map((name) => ({
|
|
4962
|
+
identifier: pathParamSpec.bindings[name] ?? name,
|
|
4963
|
+
typeExpr: pathParamSpec.propertiesByName[name].typeExpr
|
|
4964
|
+
}));
|
|
4812
4965
|
}
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4966
|
+
return [
|
|
4967
|
+
{
|
|
4968
|
+
identifier: this.renderPathParamDestructuring(
|
|
4969
|
+
pathParamSpec.bindings
|
|
4970
|
+
),
|
|
4971
|
+
typeExpr: param.typeExpr
|
|
4818
4972
|
}
|
|
4819
|
-
|
|
4820
|
-
const projected = this.fromSchemaCore(schema);
|
|
4821
|
-
const result = schema.nullable === true ? this.withNullable(projected) : projected;
|
|
4822
|
-
this.schemaCache.set(schema, result);
|
|
4823
|
-
if (typeof schema.$ref === "string") {
|
|
4824
|
-
this.refCache.set(this.refCacheKey(schema), result);
|
|
4825
|
-
}
|
|
4826
|
-
return result;
|
|
4973
|
+
];
|
|
4827
4974
|
});
|
|
4828
|
-
__publicField$5(this, "
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
if (member.kind === "inline" && member.expr.node === "union") {
|
|
4839
|
-
flatMembers.push(...member.expr.members);
|
|
4840
|
-
} else {
|
|
4841
|
-
flatMembers.push(member);
|
|
4842
|
-
}
|
|
4843
|
-
}
|
|
4844
|
-
if (flatMembers.length === 1) {
|
|
4845
|
-
return flatMembers[0];
|
|
4846
|
-
}
|
|
4847
|
-
return {
|
|
4848
|
-
kind: "inline",
|
|
4849
|
-
expr: {
|
|
4850
|
-
node: "union",
|
|
4851
|
-
members: flatMembers
|
|
4975
|
+
__publicField$5(this, "renderPathTemplateLiteral", (path, pathParamVarName, pathParamBindings) => {
|
|
4976
|
+
const escapedPath = path.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
4977
|
+
const pathWithParams = escapedPath.replace(
|
|
4978
|
+
/\{([^}]+)\}/g,
|
|
4979
|
+
(_, paramName) => {
|
|
4980
|
+
const binding = pathParamBindings?.[paramName];
|
|
4981
|
+
if (binding !== void 0) {
|
|
4982
|
+
return `\${${binding}}`;
|
|
4983
|
+
}
|
|
4984
|
+
return `\${${pathParamVarName}[${JSON.stringify(paramName)}]}`;
|
|
4852
4985
|
}
|
|
4853
|
-
|
|
4986
|
+
);
|
|
4987
|
+
return `\`${pathWithParams}\``;
|
|
4854
4988
|
});
|
|
4855
|
-
__publicField$5(this, "
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
}
|
|
4861
|
-
}));
|
|
4862
|
-
__publicField$5(this, "ref", (id) => {
|
|
4863
|
-
const name = this.refNameFromPath(id);
|
|
4864
|
-
return {
|
|
4865
|
-
kind: "reference",
|
|
4866
|
-
ref: {
|
|
4867
|
-
kind: "internal",
|
|
4868
|
-
name
|
|
4989
|
+
__publicField$5(this, "renderPathParamDestructuring", (pathParamBindings) => {
|
|
4990
|
+
const members = Object.entries(pathParamBindings).map(
|
|
4991
|
+
([paramName, binding]) => {
|
|
4992
|
+
const key = toTsPropertyKey(paramName);
|
|
4993
|
+
return binding === paramName ? key : `${key}: ${binding}`;
|
|
4869
4994
|
}
|
|
4870
|
-
};
|
|
4871
|
-
});
|
|
4872
|
-
__publicField$5(this, "builtinRef", (name) => ({
|
|
4873
|
-
kind: "reference",
|
|
4874
|
-
ref: {
|
|
4875
|
-
kind: "builtin",
|
|
4876
|
-
name
|
|
4877
|
-
}
|
|
4878
|
-
}));
|
|
4879
|
-
__publicField$5(this, "refNameFromPath", (ref) => {
|
|
4880
|
-
const parts = ref.split("/");
|
|
4881
|
-
const name = parts[parts.length - 1];
|
|
4882
|
-
if (!name) {
|
|
4883
|
-
throw new Error(`Unsupported schema reference: ${ref}`);
|
|
4884
|
-
}
|
|
4885
|
-
return name;
|
|
4886
|
-
});
|
|
4887
|
-
__publicField$5(this, "refCacheKey", (schema) => {
|
|
4888
|
-
return `${schema.$ref}|nullable:${schema.nullable === true}`;
|
|
4889
|
-
});
|
|
4890
|
-
__publicField$5(this, "isUnconstrainedSchema", (schema) => {
|
|
4891
|
-
const meaningfulKeys = Object.keys(schema).filter(
|
|
4892
|
-
(key) => key !== "nullable"
|
|
4893
4995
|
);
|
|
4894
|
-
return
|
|
4996
|
+
return `{ ${members.join(", ")} }`;
|
|
4895
4997
|
});
|
|
4896
|
-
__publicField$5(this, "
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
};
|
|
4911
|
-
this.schemaDefinitionsById.set(refId, definition);
|
|
4912
|
-
this.schemaDefinitions.push(definition);
|
|
4913
|
-
} finally {
|
|
4914
|
-
this.schemaDefinitionsInProgress.delete(refId);
|
|
4998
|
+
__publicField$5(this, "paramName", (p) => {
|
|
4999
|
+
switch (p.kind) {
|
|
5000
|
+
case "body":
|
|
5001
|
+
return this.options.paramNames.body;
|
|
5002
|
+
case "query":
|
|
5003
|
+
return this.options.paramNames.query;
|
|
5004
|
+
case "path":
|
|
5005
|
+
return this.options.paramNames.path;
|
|
5006
|
+
default: {
|
|
5007
|
+
const exhaustive = p;
|
|
5008
|
+
throw new Error(
|
|
5009
|
+
`Unsupported operation parameter kind: ${String(exhaustive)}`
|
|
5010
|
+
);
|
|
5011
|
+
}
|
|
4915
5012
|
}
|
|
4916
5013
|
});
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
const extractPathPlaceholderNames = (pathTemplate) => {
|
|
5017
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5018
|
+
const names = [];
|
|
5019
|
+
const matcher = /\{([^}]+)\}/g;
|
|
5020
|
+
let match = matcher.exec(pathTemplate);
|
|
5021
|
+
while (match) {
|
|
5022
|
+
const name = match[1];
|
|
5023
|
+
if (!seen.has(name)) {
|
|
5024
|
+
seen.add(name);
|
|
5025
|
+
names.push(name);
|
|
5026
|
+
}
|
|
5027
|
+
match = matcher.exec(pathTemplate);
|
|
5028
|
+
}
|
|
5029
|
+
return names;
|
|
5030
|
+
};
|
|
5031
|
+
const isPathParam = (param) => {
|
|
5032
|
+
return param.kind === "path";
|
|
5033
|
+
};
|
|
5034
|
+
const isInlineObjectType = (typeExpr) => typeExpr.kind === "inline" && typeExpr.expr.node === "object";
|
|
5035
|
+
const renderNameList = (items) => {
|
|
5036
|
+
const values = [...items];
|
|
5037
|
+
if (!values.length) {
|
|
5038
|
+
return "(none)";
|
|
5039
|
+
}
|
|
5040
|
+
return values.map((v) => JSON.stringify(v)).join(", ");
|
|
5041
|
+
};
|
|
5042
|
+
const validatePathParams = (params, httpPath) => {
|
|
5043
|
+
const placeholders = extractPathPlaceholderNames(httpPath);
|
|
5044
|
+
const placeholderSet = new Set(placeholders);
|
|
5045
|
+
const pathParams = params.filter(isPathParam);
|
|
5046
|
+
if (pathParams.length > 1) {
|
|
5047
|
+
throw new Error(
|
|
5048
|
+
`Path "${httpPath}" has ${pathParams.length} path parameter objects; expected at most one.`
|
|
5049
|
+
);
|
|
5050
|
+
}
|
|
5051
|
+
const pathParam = pathParams[0];
|
|
5052
|
+
if (!pathParam) {
|
|
5053
|
+
if (placeholderSet.size > 0) {
|
|
5054
|
+
throw new Error(
|
|
5055
|
+
`Path "${httpPath}" is missing a path parameter object for placeholders: ${renderNameList(
|
|
5056
|
+
placeholderSet
|
|
5057
|
+
)}.`
|
|
4920
5058
|
);
|
|
4921
|
-
}
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
5059
|
+
}
|
|
5060
|
+
return void 0;
|
|
5061
|
+
}
|
|
5062
|
+
const pathParamExpr = pathParam.typeExpr.expr;
|
|
5063
|
+
if (pathParamExpr.additionalProperties !== void 0 && pathParamExpr.additionalProperties !== false) {
|
|
5064
|
+
throw new Error(
|
|
5065
|
+
`Path "${httpPath}" path parameter object must not declare additionalProperties.`
|
|
5066
|
+
);
|
|
5067
|
+
}
|
|
5068
|
+
const nestedObjectProps = pathParamExpr.properties.filter((prop) => isInlineObjectType(prop.typeExpr)).map((prop) => prop.name);
|
|
5069
|
+
if (nestedObjectProps.length > 0) {
|
|
5070
|
+
throw new Error(
|
|
5071
|
+
`Path "${httpPath}" path parameters must be depth-1. Nested object properties: ${renderNameList(
|
|
5072
|
+
nestedObjectProps
|
|
5073
|
+
)}.`
|
|
5074
|
+
);
|
|
5075
|
+
}
|
|
5076
|
+
const optionalPathProps = pathParamExpr.properties.filter((prop) => !prop.required).map((prop) => prop.name);
|
|
5077
|
+
if (optionalPathProps.length > 0) {
|
|
5078
|
+
throw new Error(
|
|
5079
|
+
`Path "${httpPath}" path parameters must all be required. Optional properties: ${renderNameList(
|
|
5080
|
+
optionalPathProps
|
|
5081
|
+
)}.`
|
|
5082
|
+
);
|
|
5083
|
+
}
|
|
5084
|
+
const declaredNames = pathParamExpr.properties.map((prop) => prop.name);
|
|
5085
|
+
const declaredNameSet = new Set(declaredNames);
|
|
5086
|
+
const missingInObject = [...placeholderSet].filter(
|
|
5087
|
+
(name) => !declaredNameSet.has(name)
|
|
5088
|
+
);
|
|
5089
|
+
const missingInPath = declaredNames.filter(
|
|
5090
|
+
(name) => !placeholderSet.has(name)
|
|
5091
|
+
);
|
|
5092
|
+
if (missingInObject.length > 0 || missingInPath.length > 0) {
|
|
5093
|
+
throw new Error(
|
|
5094
|
+
`Path "${httpPath}" placeholders and path parameter object keys must match exactly. Missing in object: ${renderNameList(
|
|
5095
|
+
missingInObject
|
|
5096
|
+
)}. Missing in path: ${renderNameList(missingInPath)}.`
|
|
5097
|
+
);
|
|
5098
|
+
}
|
|
5099
|
+
const bindings = buildPathParamBindings(placeholders);
|
|
5100
|
+
const propertiesByName = Object.fromEntries(
|
|
5101
|
+
pathParamExpr.properties.map((prop) => [prop.name, prop])
|
|
5102
|
+
);
|
|
5103
|
+
return {
|
|
5104
|
+
placeholderNames: placeholders,
|
|
5105
|
+
bindings,
|
|
5106
|
+
propertiesByName
|
|
5107
|
+
};
|
|
5108
|
+
};
|
|
5109
|
+
|
|
5110
|
+
const EMPTY_LINE_MARKER = "/*__EMPTY_LINE_MARKER__*/";
|
|
5111
|
+
|
|
5112
|
+
var __defProp$4 = Object.defineProperty;
|
|
5113
|
+
var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5114
|
+
var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5115
|
+
const REQUEST_PARAMS_TYPE = "RequestParams";
|
|
5116
|
+
const REQUEST_PARAMS_DEFAULT = "never";
|
|
5117
|
+
const REQUEST_PARAMS_ARG = "params";
|
|
5118
|
+
class ApiClientCodegen {
|
|
5119
|
+
constructor(opts, tsCodegenFactory) {
|
|
5120
|
+
this.opts = opts;
|
|
5121
|
+
this.tsCodegenFactory = tsCodegenFactory;
|
|
5122
|
+
__publicField$4(this, "generate", (apiName, operations) => {
|
|
5123
|
+
const tsCodegen = this.tsCodegenFactory.forNewChunk();
|
|
5124
|
+
const httpClientType = tsCodegen.typeExpr(this.opts.httpClient.typeName);
|
|
5125
|
+
let clientType = httpClientType;
|
|
5126
|
+
let classTypeParams = "";
|
|
5127
|
+
if (this.opts.withRequestParams) {
|
|
5128
|
+
clientType = `${httpClientType}<${REQUEST_PARAMS_TYPE}>`;
|
|
5129
|
+
classTypeParams = `<${REQUEST_PARAMS_TYPE} = ${REQUEST_PARAMS_DEFAULT}>`;
|
|
4925
5130
|
}
|
|
4926
|
-
|
|
5131
|
+
const methodsCode = Array.isArray(operations) ? this.opsCode(tsCodegen, operations) : this.groupsOpsCode(tsCodegen, operations);
|
|
5132
|
+
const code = `
|
|
5133
|
+
export class ${apiName}${classTypeParams} {
|
|
5134
|
+
constructor(private readonly client: ${clientType}) {}
|
|
5135
|
+
|
|
5136
|
+
${methodsCode}
|
|
5137
|
+
}
|
|
5138
|
+
`;
|
|
5139
|
+
return tsCodegen.toChunk("api", code, [apiName]);
|
|
4927
5140
|
});
|
|
4928
|
-
__publicField$
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
}
|
|
5141
|
+
__publicField$4(this, "groupsOpsCode", (codegen, groupedOps) => Object.entries(groupedOps).map(([groupName, ops]) => {
|
|
5142
|
+
const methodsCode = this.opsCode(codegen, ops, "object");
|
|
5143
|
+
return `
|
|
5144
|
+
${toTsPropertyKey(groupName)} = {
|
|
5145
|
+
${methodsCode}
|
|
5146
|
+
}
|
|
5147
|
+
`;
|
|
5148
|
+
}).join("\n\n"));
|
|
5149
|
+
__publicField$4(this, "opsCode", (codegen, operations, target = "class") => {
|
|
5150
|
+
const separator = target === "object" ? `,
|
|
5151
|
+
${EMPTY_LINE_MARKER}
|
|
5152
|
+
` : "\n\n";
|
|
5153
|
+
const methodsCode = operations.map((op) => this.renderOp(op, codegen, target)).join(separator);
|
|
5154
|
+
return methodsCode;
|
|
4943
5155
|
});
|
|
4944
|
-
__publicField$
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
}
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
});
|
|
4960
|
-
__publicField$5(this, "projectObjectType", (schema) => {
|
|
4961
|
-
const requiredRaw = schema.required;
|
|
4962
|
-
if (requiredRaw !== void 0 && !Array.isArray(requiredRaw)) {
|
|
4963
|
-
throw new Error(
|
|
4964
|
-
"Unsupported object schema: required must be an array"
|
|
4965
|
-
);
|
|
4966
|
-
}
|
|
4967
|
-
const required = new Set(
|
|
4968
|
-
(requiredRaw ?? []).map((item) => {
|
|
4969
|
-
if (typeof item !== "string") {
|
|
4970
|
-
throw new Error(
|
|
4971
|
-
"Unsupported object schema: required items must be strings"
|
|
4972
|
-
);
|
|
4973
|
-
}
|
|
4974
|
-
return item;
|
|
4975
|
-
})
|
|
5156
|
+
__publicField$4(this, "renderOp", (op, tsCodegen, target) => {
|
|
5157
|
+
const { signature: sig, http } = op;
|
|
5158
|
+
const invocationVars = this.opts.httpClient.invocation.vars;
|
|
5159
|
+
const paramNames = {
|
|
5160
|
+
path: "path",
|
|
5161
|
+
query: invocationVars.query,
|
|
5162
|
+
body: invocationVars.body
|
|
5163
|
+
};
|
|
5164
|
+
const paramsHelper = new ParamsConstructor({
|
|
5165
|
+
paramNames,
|
|
5166
|
+
pathParamsStyle: this.opts.pathParamsStyle
|
|
5167
|
+
});
|
|
5168
|
+
const { path, funParams, hasBody, hasQuery } = paramsHelper.process(
|
|
5169
|
+
sig.parameters,
|
|
5170
|
+
http.path
|
|
4976
5171
|
);
|
|
4977
|
-
const
|
|
4978
|
-
|
|
4979
|
-
throw new Error(
|
|
4980
|
-
"Unsupported object schema: properties must be an object"
|
|
4981
|
-
);
|
|
4982
|
-
}
|
|
4983
|
-
const properties = Object.entries(propertiesRaw ?? {}).map(
|
|
4984
|
-
([name, propertySchema]) => {
|
|
4985
|
-
if (!this.isSchemaNode(propertySchema)) {
|
|
4986
|
-
throw new Error(
|
|
4987
|
-
`Unsupported object property schema for "${name}"`
|
|
4988
|
-
);
|
|
4989
|
-
}
|
|
4990
|
-
return {
|
|
4991
|
-
name,
|
|
4992
|
-
required: this.isRequiredProperty(
|
|
4993
|
-
name,
|
|
4994
|
-
required,
|
|
4995
|
-
propertySchema
|
|
4996
|
-
),
|
|
4997
|
-
typeExpr: this.fromSchema(propertySchema)
|
|
4998
|
-
};
|
|
4999
|
-
}
|
|
5172
|
+
const params = funParams.map(
|
|
5173
|
+
(r) => `${r.identifier}: ${tsCodegen.typeExpr(r.typeExpr)}`
|
|
5000
5174
|
);
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
if (typeof schema.additionalProperties === "boolean") {
|
|
5004
|
-
additionalProperties = schema.additionalProperties;
|
|
5005
|
-
} else if (this.isSchemaNode(schema.additionalProperties)) {
|
|
5006
|
-
additionalProperties = this.fromSchema(
|
|
5007
|
-
schema.additionalProperties
|
|
5008
|
-
);
|
|
5009
|
-
} else {
|
|
5010
|
-
throw new Error(
|
|
5011
|
-
"Unsupported object schema: additionalProperties must be boolean or schema object"
|
|
5012
|
-
);
|
|
5013
|
-
}
|
|
5014
|
-
}
|
|
5015
|
-
return {
|
|
5016
|
-
kind: "inline",
|
|
5017
|
-
expr: {
|
|
5018
|
-
node: "object",
|
|
5019
|
-
properties,
|
|
5020
|
-
additionalProperties
|
|
5021
|
-
}
|
|
5022
|
-
};
|
|
5023
|
-
});
|
|
5024
|
-
__publicField$5(this, "isRequiredProperty", (name, required, propertySchema) => {
|
|
5025
|
-
if (required.has(name)) {
|
|
5026
|
-
return true;
|
|
5027
|
-
}
|
|
5028
|
-
if (!this.options.quirks?.swaggerTsApiRequiredBooleans) {
|
|
5029
|
-
return false;
|
|
5030
|
-
}
|
|
5031
|
-
return propertySchema.required === true;
|
|
5032
|
-
});
|
|
5033
|
-
__publicField$5(this, "mapSchemaArrayMembers", (value, kind) => {
|
|
5034
|
-
if (!Array.isArray(value) || !value.length) {
|
|
5035
|
-
throw new Error(
|
|
5036
|
-
`Unsupported schema: ${kind} must be a non-empty array`
|
|
5037
|
-
);
|
|
5175
|
+
if (this.opts.withRequestParams) {
|
|
5176
|
+
params.push(`${REQUEST_PARAMS_ARG}?: ${REQUEST_PARAMS_TYPE}`);
|
|
5038
5177
|
}
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5178
|
+
const paramsCode = params.join(", ");
|
|
5179
|
+
const responseType = tsCodegen.typeExpr(sig.returnType);
|
|
5180
|
+
const returnType = this.wrapInResponseWrapper(sig.returnType, tsCodegen);
|
|
5181
|
+
return this.renderFunctionCode({
|
|
5182
|
+
funName: sig.name,
|
|
5183
|
+
responseType,
|
|
5184
|
+
returnType,
|
|
5185
|
+
params: paramsCode,
|
|
5186
|
+
path,
|
|
5187
|
+
method: http.method,
|
|
5188
|
+
hasQuery,
|
|
5189
|
+
hasBody,
|
|
5190
|
+
requestContentType: http.requestContentType,
|
|
5191
|
+
responseFormat: http.responseFormat,
|
|
5192
|
+
requestParamsVar: this.opts.withRequestParams ? REQUEST_PARAMS_ARG : void 0,
|
|
5193
|
+
unwrap: this.opts.unwrap,
|
|
5194
|
+
target
|
|
5046
5195
|
});
|
|
5047
5196
|
});
|
|
5048
|
-
__publicField$
|
|
5049
|
-
return
|
|
5197
|
+
__publicField$4(this, "wrapInResponseWrapper", (typeExpr, tsCodegen) => {
|
|
5198
|
+
return tsCodegen.typeExpr({
|
|
5199
|
+
...this.opts.httpClient.responseWrapper,
|
|
5200
|
+
typeArgs: [typeExpr]
|
|
5201
|
+
});
|
|
5050
5202
|
});
|
|
5051
|
-
__publicField$
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
}
|
|
5087
|
-
if (!this.isSchemaNode(schema.items)) {
|
|
5088
|
-
throw new Error(
|
|
5089
|
-
"Unsupported array schema: items must be a schema"
|
|
5090
|
-
);
|
|
5091
|
-
}
|
|
5092
|
-
return {
|
|
5093
|
-
kind: "inline",
|
|
5094
|
-
expr: {
|
|
5095
|
-
node: "array",
|
|
5096
|
-
element: this.fromSchema(schema.items)
|
|
5097
|
-
}
|
|
5098
|
-
};
|
|
5099
|
-
}
|
|
5100
|
-
if (schema.type === "object") {
|
|
5101
|
-
return this.projectObjectType(schema);
|
|
5102
|
-
}
|
|
5103
|
-
if (schema.oneOf !== void 0) {
|
|
5104
|
-
return this.union(this.mapSchemaArrayMembers(schema.oneOf, "oneOf"));
|
|
5105
|
-
}
|
|
5106
|
-
if (schema.anyOf !== void 0) {
|
|
5107
|
-
return this.union(this.mapSchemaArrayMembers(schema.anyOf, "anyOf"));
|
|
5108
|
-
}
|
|
5109
|
-
if (schema.allOf !== void 0) {
|
|
5110
|
-
return {
|
|
5111
|
-
kind: "inline",
|
|
5112
|
-
expr: {
|
|
5113
|
-
node: "intersection",
|
|
5114
|
-
members: this.mapSchemaArrayMembers(schema.allOf, "allOf")
|
|
5115
|
-
}
|
|
5116
|
-
};
|
|
5117
|
-
}
|
|
5118
|
-
if (this.isBinaryFileSchema(schema)) {
|
|
5119
|
-
return this.builtinRef("File");
|
|
5120
|
-
}
|
|
5121
|
-
if (this.isScalarName(schema.type)) {
|
|
5122
|
-
return this.scalar(schema.type);
|
|
5123
|
-
}
|
|
5124
|
-
throw new Error(
|
|
5125
|
-
`Unsupported schema construct: ${JSON.stringify(schema, null, 2)}`
|
|
5126
|
-
);
|
|
5203
|
+
__publicField$4(this, "renderFunctionCode", ({
|
|
5204
|
+
funName,
|
|
5205
|
+
responseType,
|
|
5206
|
+
returnType,
|
|
5207
|
+
params,
|
|
5208
|
+
path,
|
|
5209
|
+
method,
|
|
5210
|
+
hasQuery,
|
|
5211
|
+
hasBody,
|
|
5212
|
+
requestContentType,
|
|
5213
|
+
responseFormat,
|
|
5214
|
+
requestParamsVar,
|
|
5215
|
+
unwrap,
|
|
5216
|
+
target
|
|
5217
|
+
}) => {
|
|
5218
|
+
let invocation = this.opts.httpClient.invocation.expr({
|
|
5219
|
+
funName,
|
|
5220
|
+
returnType,
|
|
5221
|
+
responseType,
|
|
5222
|
+
params,
|
|
5223
|
+
path,
|
|
5224
|
+
method,
|
|
5225
|
+
hasQuery,
|
|
5226
|
+
hasBody,
|
|
5227
|
+
requestContentType,
|
|
5228
|
+
responseFormat,
|
|
5229
|
+
requestParamsVar,
|
|
5230
|
+
unwrap
|
|
5231
|
+
});
|
|
5232
|
+
invocation = invocation.replaceAll("\n", "");
|
|
5233
|
+
const operator = target === "object" ? ":" : "=";
|
|
5234
|
+
const returnTypeCode = this.opts.httpClient.inferMethodReturnType ? "" : `:${returnType}`;
|
|
5235
|
+
return `${funName} ${operator} (${params})${returnTypeCode} =>
|
|
5236
|
+
this.client${invocation}
|
|
5237
|
+
`;
|
|
5127
5238
|
});
|
|
5128
5239
|
}
|
|
5129
5240
|
}
|
|
5130
5241
|
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
}
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5242
|
+
const promiseHttpClientCodegenSpec = () => ({
|
|
5243
|
+
typeName: {
|
|
5244
|
+
kind: "reference",
|
|
5245
|
+
ref: {
|
|
5246
|
+
kind: "internal",
|
|
5247
|
+
name: "HttpClient"
|
|
5248
|
+
}
|
|
5249
|
+
},
|
|
5250
|
+
responseWrapper: {
|
|
5251
|
+
kind: "reference",
|
|
5252
|
+
ref: {
|
|
5253
|
+
kind: "builtin",
|
|
5254
|
+
name: "Promise"
|
|
5255
|
+
}
|
|
5256
|
+
},
|
|
5257
|
+
inferMethodReturnType: true,
|
|
5258
|
+
invocation: {
|
|
5259
|
+
vars: {
|
|
5260
|
+
body: "body",
|
|
5261
|
+
query: "query"
|
|
5262
|
+
},
|
|
5263
|
+
expr: ({
|
|
5264
|
+
responseType,
|
|
5265
|
+
path,
|
|
5266
|
+
method,
|
|
5267
|
+
hasBody,
|
|
5268
|
+
hasQuery,
|
|
5269
|
+
requestContentType,
|
|
5270
|
+
responseFormat,
|
|
5271
|
+
requestParamsVar,
|
|
5272
|
+
unwrap
|
|
5273
|
+
}) => `.request<${responseType}>({
|
|
5274
|
+
method: '${method}',
|
|
5275
|
+
path: ${path}
|
|
5276
|
+
${hasQuery ? `,
|
|
5277
|
+
query` : ""}
|
|
5278
|
+
${hasBody ? `,
|
|
5279
|
+
body` : ""}
|
|
5280
|
+
${requestContentType ? `,
|
|
5281
|
+
requestContentType: '${requestContentType}'` : ""}
|
|
5282
|
+
${responseFormat ? `,
|
|
5283
|
+
format: '${responseFormat}'` : ""}
|
|
5284
|
+
}${requestParamsVar ? `,
|
|
5285
|
+
${requestParamsVar}` : ""})${unwrap ? `.then(res => res.body)` : ""}
|
|
5286
|
+
`
|
|
5168
5287
|
}
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
const
|
|
5172
|
-
|
|
5173
|
-
|
|
5288
|
+
});
|
|
5289
|
+
|
|
5290
|
+
const mergeChunks = (name, chunks, options = {}) => {
|
|
5291
|
+
if (chunks.length === 0) {
|
|
5292
|
+
if (options.allowEmpty) {
|
|
5293
|
+
return {
|
|
5294
|
+
name,
|
|
5295
|
+
code: "export {}",
|
|
5296
|
+
exports: [],
|
|
5297
|
+
refs: []
|
|
5298
|
+
};
|
|
5299
|
+
}
|
|
5300
|
+
throw new Error("Cannot merge empty chunk list.");
|
|
5301
|
+
}
|
|
5302
|
+
const orderedChunks = options.preserveChunkOrder ? chunks : orderByInternalDependencies(chunks);
|
|
5303
|
+
const mergedCode = orderedChunks.map((chunk) => chunk.code).join("\n\n");
|
|
5304
|
+
const exportedSymbols = /* @__PURE__ */ new Set();
|
|
5305
|
+
const mergedExports = [];
|
|
5306
|
+
for (const chunk of orderedChunks) {
|
|
5307
|
+
for (const symbol of chunk.exports) {
|
|
5308
|
+
if (exportedSymbols.has(symbol)) continue;
|
|
5309
|
+
exportedSymbols.add(symbol);
|
|
5310
|
+
mergedExports.push(symbol);
|
|
5311
|
+
}
|
|
5312
|
+
}
|
|
5313
|
+
const seenRefKeys = /* @__PURE__ */ new Set();
|
|
5314
|
+
const mergedRefs = orderedChunks.flatMap((chunk) => chunk.refs).filter((ref) => {
|
|
5315
|
+
if (ref.kind === "internal" && exportedSymbols.has(ref.name)) {
|
|
5316
|
+
return false;
|
|
5317
|
+
}
|
|
5318
|
+
const key = ref.kind === "internal" ? `internal:${ref.name}` : ref.kind === "external" ? `external:${ref.package}:${ref.name}` : `builtin:${ref.name}`;
|
|
5319
|
+
if (seenRefKeys.has(key)) return false;
|
|
5320
|
+
seenRefKeys.add(key);
|
|
5321
|
+
return true;
|
|
5322
|
+
});
|
|
5174
5323
|
return {
|
|
5175
|
-
|
|
5176
|
-
|
|
5324
|
+
name,
|
|
5325
|
+
code: mergedCode,
|
|
5326
|
+
exports: mergedExports,
|
|
5327
|
+
refs: mergedRefs
|
|
5177
5328
|
};
|
|
5178
5329
|
};
|
|
5179
|
-
const
|
|
5180
|
-
const
|
|
5181
|
-
|
|
5330
|
+
const orderByInternalDependencies = (chunks) => {
|
|
5331
|
+
const chunkIndex = /* @__PURE__ */ new Map();
|
|
5332
|
+
const exportOwnerBySymbol = /* @__PURE__ */ new Map();
|
|
5333
|
+
chunks.forEach((chunk, index) => {
|
|
5334
|
+
chunkIndex.set(chunk.name, index);
|
|
5335
|
+
for (const symbol of chunk.exports) {
|
|
5336
|
+
if (exportOwnerBySymbol.has(symbol)) {
|
|
5337
|
+
throw new Error(
|
|
5338
|
+
`Assertion error. Symbol "${symbol}" exported multiple times while ordering chunks.`
|
|
5339
|
+
);
|
|
5340
|
+
}
|
|
5341
|
+
exportOwnerBySymbol.set(symbol, chunk);
|
|
5342
|
+
}
|
|
5343
|
+
});
|
|
5344
|
+
const dependentsByProvider = /* @__PURE__ */ new Map();
|
|
5345
|
+
const inDegreeByChunk = /* @__PURE__ */ new Map();
|
|
5346
|
+
for (const chunk of chunks) {
|
|
5347
|
+
dependentsByProvider.set(chunk, /* @__PURE__ */ new Set());
|
|
5348
|
+
inDegreeByChunk.set(chunk, 0);
|
|
5349
|
+
}
|
|
5350
|
+
for (const chunk of chunks) {
|
|
5351
|
+
const providers = /* @__PURE__ */ new Set();
|
|
5352
|
+
for (const ref of chunk.refs) {
|
|
5353
|
+
if (ref.kind !== "internal") continue;
|
|
5354
|
+
const provider = exportOwnerBySymbol.get(ref.name);
|
|
5355
|
+
if (!provider || provider === chunk) continue;
|
|
5356
|
+
providers.add(provider);
|
|
5357
|
+
}
|
|
5358
|
+
for (const provider of providers) {
|
|
5359
|
+
dependentsByProvider.get(provider).add(chunk);
|
|
5360
|
+
inDegreeByChunk.set(chunk, inDegreeByChunk.get(chunk) + 1);
|
|
5361
|
+
}
|
|
5362
|
+
}
|
|
5363
|
+
const ready = chunks.filter((chunk) => inDegreeByChunk.get(chunk) === 0).sort((a, b) => chunkIndex.get(a.name) - chunkIndex.get(b.name));
|
|
5364
|
+
const ordered = [];
|
|
5365
|
+
while (ready.length > 0) {
|
|
5366
|
+
const provider = ready.shift();
|
|
5367
|
+
ordered.push(provider);
|
|
5368
|
+
for (const dependent of dependentsByProvider.get(provider)) {
|
|
5369
|
+
const nextInDegree = inDegreeByChunk.get(dependent) - 1;
|
|
5370
|
+
inDegreeByChunk.set(dependent, nextInDegree);
|
|
5371
|
+
if (nextInDegree === 0) {
|
|
5372
|
+
ready.push(dependent);
|
|
5373
|
+
}
|
|
5374
|
+
}
|
|
5375
|
+
ready.sort((a, b) => chunkIndex.get(a.name) - chunkIndex.get(b.name));
|
|
5376
|
+
}
|
|
5377
|
+
if (ordered.length !== chunks.length) {
|
|
5378
|
+
const cycleChunkNames = chunks.filter((chunk) => inDegreeByChunk.get(chunk) > 0).map((chunk) => chunk.name).join(", ");
|
|
5379
|
+
throw new Error(
|
|
5380
|
+
`Cannot order chunks with cyclic internal dependencies: ${cycleChunkNames}`
|
|
5381
|
+
);
|
|
5382
|
+
}
|
|
5383
|
+
return ordered;
|
|
5182
5384
|
};
|
|
5183
|
-
|
|
5184
|
-
|
|
5385
|
+
|
|
5386
|
+
var httpClientCommonTypesSource = "export type KnownRequestContentType =\n | 'application/json'\n | 'multipart/form-data'\n | 'application/x-www-form-urlencoded'\n\nexport type RequestContentType = KnownRequestContentType | string\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | QueryValue[]\n | Record<string, any>\n // Empty schema support\n | unknown\n\nexport type QueryParams = Record<string, QueryValue>\n\nexport type Request = {\n path: string\n method: 'GET' | 'POST' | 'PUT' | 'DELETE'\n format?: 'json' | 'document'\n headers?: Record<string, string>\n query?: QueryParams\n body?: any\n requestContentType?: RequestContentType\n}\n\nexport type HttpResponse<Data> = {\n body: Data\n headers: Record<string, string | string[]>\n status: number\n}\n\nexport type QuerySerializer = (params: QueryParams) => string\n";
|
|
5387
|
+
|
|
5388
|
+
var httpClientPromiseTypesSource = "import type { HttpResponse, Request } from './common-types'\n\nexport type HttpClient<RequestParams = never> = {\n request: <Data>(\n req: Request,\n params?: RequestParams\n ) => Promise<HttpResponse<Data>>\n}\n";
|
|
5389
|
+
|
|
5390
|
+
const commonTypesCode = httpClientCommonTypesSource;
|
|
5391
|
+
const promiseHttpClientCode = httpClientPromiseTypesSource;
|
|
5392
|
+
const stripImports = (code) => code.replace(/^import[\s\S]*?from\s+['"][^'"]+['"]\s*;?\n?/gm, "").trim();
|
|
5393
|
+
const stripRequestParams = (code) => code.replace(/<RequestParams\s*=\s*never>/g, "").replace(/,\s*params\?:\s*RequestParams/g, "");
|
|
5394
|
+
const getHttpClientCode = (opts) => [
|
|
5395
|
+
commonTypesCode,
|
|
5396
|
+
opts.withRequestParams ? promiseHttpClientCode : stripRequestParams(promiseHttpClientCode)
|
|
5397
|
+
].map(stripImports).join("\n\n");
|
|
5398
|
+
const provideHttpClientCode = (gen, opts) => gen.toChunk(
|
|
5399
|
+
"HttpClient",
|
|
5400
|
+
getHttpClientCode({
|
|
5401
|
+
withRequestParams: opts.withRequestParams
|
|
5402
|
+
}),
|
|
5403
|
+
["HttpRequest", "HttpResponse", "HttpClient"]
|
|
5404
|
+
);
|
|
5405
|
+
|
|
5406
|
+
const generateTsCode = (clientName, projectResult, opts) => {
|
|
5407
|
+
const tsCodegenFac = new TsCodegenFactory();
|
|
5408
|
+
const { schemaDefinitions } = projectResult;
|
|
5409
|
+
const types = [...schemaDefinitions].sort((a, b) => a.name.localeCompare(b.name)).map((def) => {
|
|
5410
|
+
const cg = tsCodegenFac.forNewChunk();
|
|
5411
|
+
const code = `export ${cg.declaration(def.name, def.declaration)}`;
|
|
5412
|
+
return cg.toChunk(def.name, code, [def.name]);
|
|
5413
|
+
});
|
|
5414
|
+
const clientCodegen = new ApiClientCodegen(
|
|
5415
|
+
{ httpClient: promiseHttpClientCodegenSpec(), ...opts },
|
|
5416
|
+
tsCodegenFac
|
|
5417
|
+
);
|
|
5418
|
+
const generated = clientCodegen.generate(
|
|
5419
|
+
clientName,
|
|
5420
|
+
groupsOpsByTag(projectResult.operations)
|
|
5421
|
+
);
|
|
5422
|
+
const clientChunk = {
|
|
5423
|
+
...generated,
|
|
5424
|
+
name: `${clientName}.client`
|
|
5425
|
+
};
|
|
5426
|
+
const httpClientChunk = provideHttpClientCode(
|
|
5427
|
+
tsCodegenFac.forNewChunk(),
|
|
5428
|
+
opts
|
|
5429
|
+
);
|
|
5430
|
+
const typesChunk = mergeChunks(`${clientName}.types`, types, {
|
|
5431
|
+
preserveChunkOrder: true,
|
|
5432
|
+
allowEmpty: true
|
|
5433
|
+
});
|
|
5434
|
+
const indexChunk = createIndexChunk(clientName);
|
|
5435
|
+
const all = [typesChunk, httpClientChunk, clientChunk, indexChunk];
|
|
5436
|
+
return {
|
|
5437
|
+
all,
|
|
5438
|
+
typesName: typesChunk.name,
|
|
5439
|
+
promiseWrappersNames: [httpClientChunk.name, clientChunk.name]
|
|
5440
|
+
};
|
|
5185
5441
|
};
|
|
5186
|
-
const
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5442
|
+
const createIndexChunk = (clientName) => ({
|
|
5443
|
+
name: "index",
|
|
5444
|
+
code: [
|
|
5445
|
+
`export { ${clientName} } from './${clientName}.client'`,
|
|
5446
|
+
`export * from './${clientName}.types'`,
|
|
5447
|
+
"export * from './HttpClient'"
|
|
5448
|
+
].join("\n"),
|
|
5449
|
+
exports: [],
|
|
5450
|
+
refs: []
|
|
5451
|
+
});
|
|
5452
|
+
const groupsOpsByTag = (operations) => {
|
|
5453
|
+
const groupedOps = {};
|
|
5454
|
+
const rawTagsByNormalizedName = /* @__PURE__ */ new Map();
|
|
5455
|
+
operations.forEach((operation) => {
|
|
5456
|
+
const rawTag = operation.tags.find((tag) => tag.trim())?.trim() || "root";
|
|
5457
|
+
let groupName;
|
|
5458
|
+
try {
|
|
5459
|
+
groupName = toTsCamelIdentifier(rawTag, {
|
|
5460
|
+
leadingDigitPrefix: "tag"
|
|
5461
|
+
});
|
|
5462
|
+
} catch {
|
|
5463
|
+
throw new Error(
|
|
5464
|
+
`Invalid OpenAPI tag "${rawTag}": could not derive a client group name.`
|
|
5465
|
+
);
|
|
5207
5466
|
}
|
|
5208
|
-
|
|
5467
|
+
const existingRawTag = rawTagsByNormalizedName.get(groupName);
|
|
5468
|
+
if (existingRawTag && existingRawTag !== rawTag) {
|
|
5469
|
+
throw new Error(
|
|
5470
|
+
`Tag naming collision: "${existingRawTag}" and "${rawTag}" both normalize to "${groupName}". Rename one of these OpenAPI tags to continue.`
|
|
5471
|
+
);
|
|
5472
|
+
}
|
|
5473
|
+
rawTagsByNormalizedName.set(groupName, rawTag);
|
|
5474
|
+
const bucket = groupedOps[groupName] ?? [];
|
|
5475
|
+
bucket.push(operation.op);
|
|
5476
|
+
groupedOps[groupName] = bucket;
|
|
5477
|
+
});
|
|
5478
|
+
return groupedOps;
|
|
5209
5479
|
};
|
|
5210
|
-
|
|
5211
|
-
|
|
5480
|
+
|
|
5481
|
+
var __defProp$3 = Object.defineProperty;
|
|
5482
|
+
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5483
|
+
var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5484
|
+
const TS_IDENTIFIER_PATTERN = /^[$A-Z_][0-9A-Z_$]*$/i;
|
|
5485
|
+
class ToTypeExprConverter {
|
|
5486
|
+
constructor(schemas = {}, options) {
|
|
5487
|
+
this.schemas = schemas;
|
|
5212
5488
|
this.options = options;
|
|
5213
|
-
__publicField$
|
|
5214
|
-
__publicField$
|
|
5215
|
-
__publicField$
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
if (!operationName) {
|
|
5223
|
-
throw new Error(
|
|
5224
|
-
`Operation id is empty for ${operation.method.toUpperCase()} ${operation.path}`
|
|
5225
|
-
);
|
|
5226
|
-
}
|
|
5227
|
-
if (this.seenOperationIds.has(operationName)) {
|
|
5228
|
-
throw new Error(`Duplicate operation id: ${operationName}`);
|
|
5229
|
-
}
|
|
5230
|
-
return this.projectOne(operationName, operation);
|
|
5489
|
+
__publicField$3(this, "schemaCache", /* @__PURE__ */ new WeakMap());
|
|
5490
|
+
__publicField$3(this, "refCache", /* @__PURE__ */ new Map());
|
|
5491
|
+
__publicField$3(this, "schemaDefinitions", []);
|
|
5492
|
+
__publicField$3(this, "schemaDefinitionsById", /* @__PURE__ */ new Map());
|
|
5493
|
+
__publicField$3(this, "schemaDefinitionsInProgress", /* @__PURE__ */ new Set());
|
|
5494
|
+
__publicField$3(this, "getSchemaDefinitions", () => this.schemaDefinitions);
|
|
5495
|
+
__publicField$3(this, "registerAllSchemaDefinitions", () => {
|
|
5496
|
+
Object.keys(this.schemas).forEach((schemaName) => {
|
|
5497
|
+
this.ensureSchemaDefinition(`#/components/schemas/${schemaName}`);
|
|
5231
5498
|
});
|
|
5232
|
-
return {
|
|
5233
|
-
operations,
|
|
5234
|
-
schemaDefinitions: this.typeExprConverter.getSchemaDefinitions()
|
|
5235
|
-
};
|
|
5236
5499
|
});
|
|
5237
|
-
__publicField$
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
const pathParameter = this.projectPathParameter(operation);
|
|
5241
|
-
const queryParameter = this.projectQueryParameter(operation);
|
|
5242
|
-
const bodyParameter = this.projectBodyParameter(operation);
|
|
5243
|
-
if (pathParameter) parameters.push(pathParameter);
|
|
5244
|
-
if (queryParameter) parameters.push(queryParameter);
|
|
5245
|
-
if (bodyParameter) parameters.push(bodyParameter);
|
|
5246
|
-
return {
|
|
5247
|
-
op: {
|
|
5248
|
-
signature: {
|
|
5249
|
-
name: operationName,
|
|
5250
|
-
parameters,
|
|
5251
|
-
returnType: this.projectReturnType(operation)
|
|
5252
|
-
},
|
|
5253
|
-
http: {
|
|
5254
|
-
method: toHttpMethodUpper(operation.method),
|
|
5255
|
-
path: operation.path,
|
|
5256
|
-
requestContentType: this.projectRequestContentType(
|
|
5257
|
-
operation.requestBody
|
|
5258
|
-
),
|
|
5259
|
-
responseFormat: this.projectResponseFormat(operation)
|
|
5260
|
-
}
|
|
5261
|
-
},
|
|
5262
|
-
tags: [...operation.tags]
|
|
5263
|
-
};
|
|
5264
|
-
});
|
|
5265
|
-
__publicField$4(this, "projectRequestContentType", (requestBody) => {
|
|
5266
|
-
const { mediaType } = getPreferredMediaTypeEntry(
|
|
5267
|
-
requestBody?.content ?? {}
|
|
5268
|
-
);
|
|
5269
|
-
switch (mediaType) {
|
|
5270
|
-
case "application/json":
|
|
5271
|
-
case "multipart/form-data":
|
|
5272
|
-
case "application/x-www-form-urlencoded":
|
|
5273
|
-
return mediaType;
|
|
5274
|
-
default:
|
|
5275
|
-
return void 0;
|
|
5500
|
+
__publicField$3(this, "fromTypeExpr", (schema) => {
|
|
5501
|
+
if (!schema) {
|
|
5502
|
+
return this.scalar("unknown");
|
|
5276
5503
|
}
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
if (!selectedResponses.length) {
|
|
5281
|
-
return void 0;
|
|
5504
|
+
const bySchema = this.schemaCache.get(schema);
|
|
5505
|
+
if (bySchema) {
|
|
5506
|
+
return bySchema;
|
|
5282
5507
|
}
|
|
5283
|
-
if (
|
|
5284
|
-
|
|
5508
|
+
if (typeof schema.$ref === "string") {
|
|
5509
|
+
const byRef = this.refCache.get(this.refCacheKey(schema));
|
|
5510
|
+
if (byRef) {
|
|
5511
|
+
this.schemaCache.set(schema, byRef);
|
|
5512
|
+
return byRef;
|
|
5513
|
+
}
|
|
5285
5514
|
}
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
return "json";
|
|
5515
|
+
const projected = this.fromSchemaCore(schema);
|
|
5516
|
+
const result = schema.nullable === true ? this.withNullable(projected) : projected;
|
|
5517
|
+
this.schemaCache.set(schema, result);
|
|
5518
|
+
if (typeof schema.$ref === "string") {
|
|
5519
|
+
this.refCache.set(this.refCacheKey(schema), result);
|
|
5292
5520
|
}
|
|
5293
|
-
return
|
|
5521
|
+
return result;
|
|
5294
5522
|
});
|
|
5295
|
-
__publicField$
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5523
|
+
__publicField$3(this, "scalar", (name) => ({
|
|
5524
|
+
kind: "inline",
|
|
5525
|
+
expr: {
|
|
5526
|
+
node: "scalar",
|
|
5527
|
+
name
|
|
5528
|
+
}
|
|
5529
|
+
}));
|
|
5530
|
+
__publicField$3(this, "union", (members) => {
|
|
5531
|
+
const flatMembers = [];
|
|
5532
|
+
for (const member of members) {
|
|
5533
|
+
if (member.kind === "inline" && member.expr.node === "union") {
|
|
5534
|
+
flatMembers.push(...member.expr.members);
|
|
5535
|
+
} else {
|
|
5536
|
+
flatMembers.push(member);
|
|
5537
|
+
}
|
|
5538
|
+
}
|
|
5539
|
+
if (flatMembers.length === 1) {
|
|
5540
|
+
return flatMembers[0];
|
|
5541
|
+
}
|
|
5303
5542
|
return {
|
|
5304
5543
|
kind: "inline",
|
|
5305
5544
|
expr: {
|
|
5306
|
-
node: "
|
|
5307
|
-
|
|
5545
|
+
node: "union",
|
|
5546
|
+
members: flatMembers
|
|
5308
5547
|
}
|
|
5309
5548
|
};
|
|
5310
5549
|
});
|
|
5311
|
-
__publicField$
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
throw new Error("Unsupported path parameters: all must be required");
|
|
5550
|
+
__publicField$3(this, "literal", (value) => ({
|
|
5551
|
+
kind: "inline",
|
|
5552
|
+
expr: {
|
|
5553
|
+
node: "literal",
|
|
5554
|
+
value
|
|
5317
5555
|
}
|
|
5556
|
+
}));
|
|
5557
|
+
__publicField$3(this, "ref", (id) => {
|
|
5558
|
+
const name = this.refNameFromPath(id);
|
|
5318
5559
|
return {
|
|
5319
|
-
kind: "
|
|
5320
|
-
|
|
5321
|
-
|
|
5560
|
+
kind: "reference",
|
|
5561
|
+
ref: {
|
|
5562
|
+
kind: "internal",
|
|
5563
|
+
name
|
|
5564
|
+
}
|
|
5322
5565
|
};
|
|
5323
5566
|
});
|
|
5324
|
-
__publicField$
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5567
|
+
__publicField$3(this, "builtinRef", (name) => ({
|
|
5568
|
+
kind: "reference",
|
|
5569
|
+
ref: {
|
|
5570
|
+
kind: "builtin",
|
|
5571
|
+
name
|
|
5572
|
+
}
|
|
5573
|
+
}));
|
|
5574
|
+
__publicField$3(this, "refNameFromPath", (ref) => {
|
|
5575
|
+
const parts = ref.split("/");
|
|
5576
|
+
const name = parts[parts.length - 1];
|
|
5577
|
+
if (!name) {
|
|
5578
|
+
throw new Error(`Unsupported schema reference: ${ref}`);
|
|
5579
|
+
}
|
|
5580
|
+
return name;
|
|
5581
|
+
});
|
|
5582
|
+
__publicField$3(this, "refCacheKey", (schema) => {
|
|
5583
|
+
return `${schema.$ref}|nullable:${schema.nullable === true}`;
|
|
5584
|
+
});
|
|
5585
|
+
__publicField$3(this, "isUnconstrainedSchema", (schema) => {
|
|
5586
|
+
const meaningfulKeys = Object.keys(schema).filter(
|
|
5587
|
+
(key) => key !== "nullable"
|
|
5588
|
+
);
|
|
5589
|
+
return meaningfulKeys.length === 0;
|
|
5590
|
+
});
|
|
5591
|
+
__publicField$3(this, "ensureSchemaDefinition", (refId) => {
|
|
5592
|
+
if (this.schemaDefinitionsById.has(refId) || this.schemaDefinitionsInProgress.has(refId)) {
|
|
5593
|
+
return;
|
|
5594
|
+
}
|
|
5595
|
+
const schemaName = this.refNameFromPath(refId);
|
|
5596
|
+
const schema = this.schemas[schemaName];
|
|
5597
|
+
if (!schema) {
|
|
5598
|
+
return;
|
|
5599
|
+
}
|
|
5600
|
+
this.schemaDefinitionsInProgress.add(refId);
|
|
5601
|
+
try {
|
|
5602
|
+
const definition = {
|
|
5603
|
+
name: schemaName,
|
|
5604
|
+
declaration: this.toDeclaration(schema)
|
|
5605
|
+
};
|
|
5606
|
+
this.schemaDefinitionsById.set(refId, definition);
|
|
5607
|
+
this.schemaDefinitions.push(definition);
|
|
5608
|
+
} finally {
|
|
5609
|
+
this.schemaDefinitionsInProgress.delete(refId);
|
|
5610
|
+
}
|
|
5611
|
+
});
|
|
5612
|
+
__publicField$3(this, "isSchemaNode", (value) => {
|
|
5613
|
+
return Boolean(
|
|
5614
|
+
value && typeof value === "object" && !Array.isArray(value)
|
|
5615
|
+
);
|
|
5616
|
+
});
|
|
5617
|
+
__publicField$3(this, "toLiteralValue", (value) => {
|
|
5618
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
5619
|
+
return value;
|
|
5620
|
+
}
|
|
5621
|
+
throw new Error(`Unsupported literal value: ${String(value)}`);
|
|
5622
|
+
});
|
|
5623
|
+
__publicField$3(this, "toDeclaration", (schema) => {
|
|
5624
|
+
const enumDeclaration = this.toEnumDeclaration(schema);
|
|
5625
|
+
if (enumDeclaration) {
|
|
5626
|
+
return enumDeclaration;
|
|
5627
|
+
}
|
|
5328
5628
|
return {
|
|
5329
|
-
kind: "
|
|
5330
|
-
|
|
5331
|
-
typeExpr: this.projectParameterGroupTypeExpr(params)
|
|
5629
|
+
kind: "typeAlias",
|
|
5630
|
+
typeExpr: this.fromTypeExpr(schema)
|
|
5332
5631
|
};
|
|
5333
5632
|
});
|
|
5334
|
-
__publicField$
|
|
5335
|
-
|
|
5336
|
-
|
|
5633
|
+
__publicField$3(this, "toEnumDeclaration", (schema) => {
|
|
5634
|
+
if (this.options.enumStyle !== "enum" || !Array.isArray(schema.enum)) {
|
|
5635
|
+
return void 0;
|
|
5636
|
+
}
|
|
5637
|
+
const valueType = this.getEnumValueType(schema.enum);
|
|
5638
|
+
if (!valueType) {
|
|
5639
|
+
return void 0;
|
|
5640
|
+
}
|
|
5337
5641
|
return {
|
|
5338
|
-
kind: "
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
this.selectRequestBodySchema(requestBody)
|
|
5342
|
-
)
|
|
5642
|
+
kind: "enum",
|
|
5643
|
+
valueType,
|
|
5644
|
+
members: this.toEnumMembers(schema.enum)
|
|
5343
5645
|
};
|
|
5344
5646
|
});
|
|
5345
|
-
__publicField$
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
return this.typeExprConverter.scalar("void");
|
|
5647
|
+
__publicField$3(this, "getEnumValueType", (values) => {
|
|
5648
|
+
if (!values.length) {
|
|
5649
|
+
return void 0;
|
|
5349
5650
|
}
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5651
|
+
if (values.every((value) => typeof value === "string")) {
|
|
5652
|
+
return "string";
|
|
5653
|
+
}
|
|
5654
|
+
if (values.every((value) => typeof value === "number")) {
|
|
5655
|
+
return "number";
|
|
5656
|
+
}
|
|
5657
|
+
return void 0;
|
|
5658
|
+
});
|
|
5659
|
+
__publicField$3(this, "toEnumMembers", (values) => {
|
|
5660
|
+
const usedNames = /* @__PURE__ */ new Map();
|
|
5661
|
+
return values.map((value, index) => {
|
|
5662
|
+
const enumValue = value;
|
|
5663
|
+
const baseName = this.toEnumMemberBaseName(enumValue, index);
|
|
5664
|
+
const nextCount = (usedNames.get(baseName) ?? 0) + 1;
|
|
5665
|
+
usedNames.set(baseName, nextCount);
|
|
5666
|
+
return {
|
|
5667
|
+
name: nextCount === 1 ? baseName : `${baseName}${nextCount}`,
|
|
5668
|
+
value: enumValue
|
|
5669
|
+
};
|
|
5356
5670
|
});
|
|
5357
|
-
return this.typeExprConverter.union(responseTypes);
|
|
5358
5671
|
});
|
|
5359
|
-
__publicField$
|
|
5360
|
-
if (
|
|
5361
|
-
|
|
5672
|
+
__publicField$3(this, "toEnumMemberBaseName", (value, index) => {
|
|
5673
|
+
if (typeof value === "string" && this.options.uppercaseEnumKeys) {
|
|
5674
|
+
const compatName = this.toCompatEnumMemberName(value);
|
|
5675
|
+
if (compatName) {
|
|
5676
|
+
return compatName;
|
|
5677
|
+
}
|
|
5678
|
+
}
|
|
5679
|
+
if (typeof value === "string" && TS_IDENTIFIER_PATTERN.test(value) && !RESERVED_WORDS.has(value)) {
|
|
5680
|
+
return value;
|
|
5681
|
+
}
|
|
5682
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 0) {
|
|
5683
|
+
return `Value${value}`;
|
|
5684
|
+
}
|
|
5685
|
+
const pascalName = toPascalCaseIdentifier(String(value));
|
|
5686
|
+
return pascalName === "Api" ? `Value${index + 1}` : pascalName;
|
|
5362
5687
|
});
|
|
5363
|
-
__publicField$
|
|
5364
|
-
|
|
5688
|
+
__publicField$3(this, "toCompatEnumMemberName", (value) => {
|
|
5689
|
+
if (/^([A-Z_]{1,})$/g.test(value)) {
|
|
5690
|
+
return value;
|
|
5691
|
+
}
|
|
5692
|
+
const pascalName = toPascalCaseIdentifier(value);
|
|
5693
|
+
return pascalName === "Api" ? void 0 : pascalName;
|
|
5365
5694
|
});
|
|
5366
|
-
__publicField$
|
|
5367
|
-
|
|
5695
|
+
__publicField$3(this, "isScalarName", (value) => {
|
|
5696
|
+
switch (value) {
|
|
5697
|
+
case "string":
|
|
5698
|
+
case "number":
|
|
5699
|
+
case "boolean":
|
|
5700
|
+
case "integer":
|
|
5701
|
+
case "null":
|
|
5702
|
+
case "unknown":
|
|
5703
|
+
case "any":
|
|
5704
|
+
case "never":
|
|
5705
|
+
case "void":
|
|
5706
|
+
return true;
|
|
5707
|
+
default:
|
|
5708
|
+
return false;
|
|
5709
|
+
}
|
|
5368
5710
|
});
|
|
5369
|
-
this
|
|
5370
|
-
|
|
5711
|
+
__publicField$3(this, "hasNullMember", (expr) => {
|
|
5712
|
+
if (expr.kind !== "inline") return false;
|
|
5713
|
+
if (expr.expr.node === "scalar") {
|
|
5714
|
+
return expr.expr.name === "null";
|
|
5715
|
+
}
|
|
5716
|
+
if (expr.expr.node === "union") {
|
|
5717
|
+
return expr.expr.members.some((member) => this.hasNullMember(member));
|
|
5718
|
+
}
|
|
5719
|
+
return false;
|
|
5371
5720
|
});
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
suffix += 1;
|
|
5395
|
-
candidate = `${base}_${suffix}`;
|
|
5396
|
-
}
|
|
5397
|
-
usedBindings.add(candidate);
|
|
5398
|
-
return candidate;
|
|
5399
|
-
};
|
|
5400
|
-
const toBindingBase = (paramName) => {
|
|
5401
|
-
if (isIdentifier(paramName)) {
|
|
5402
|
-
return paramName;
|
|
5403
|
-
}
|
|
5404
|
-
const sanitized = paramName.replace(/[^0-9A-Za-z_$]/g, "_");
|
|
5405
|
-
if (!sanitized.length) {
|
|
5406
|
-
return "pathParam";
|
|
5407
|
-
}
|
|
5408
|
-
if (/^[A-Za-z_$]/.test(sanitized)) {
|
|
5409
|
-
return sanitized;
|
|
5410
|
-
}
|
|
5411
|
-
return `_${sanitized}`;
|
|
5412
|
-
};
|
|
5413
|
-
const isIdentifier = (value) => {
|
|
5414
|
-
return /^[$A-Z_][0-9A-Z_$]*$/i.test(value);
|
|
5415
|
-
};
|
|
5416
|
-
const isReservedWord = (value) => {
|
|
5417
|
-
return RESERVED_WORDS.has(value);
|
|
5418
|
-
};
|
|
5419
|
-
|
|
5420
|
-
var __defProp$3 = Object.defineProperty;
|
|
5421
|
-
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5422
|
-
var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5423
|
-
class ParamsConstructor {
|
|
5424
|
-
constructor(options) {
|
|
5425
|
-
this.options = options;
|
|
5426
|
-
__publicField$3(this, "process", (params, httpPath) => {
|
|
5427
|
-
const pathParamSpec = validatePathParams(params, httpPath);
|
|
5428
|
-
const pathParamBindings = pathParamSpec?.bindings;
|
|
5429
|
-
const funParams = params.flatMap(
|
|
5430
|
-
(param) => this.renderOperationParams(param, pathParamSpec)
|
|
5721
|
+
__publicField$3(this, "withNullable", (expr) => {
|
|
5722
|
+
if (this.hasNullMember(expr)) {
|
|
5723
|
+
return expr;
|
|
5724
|
+
}
|
|
5725
|
+
return this.union([expr, this.scalar("null")]);
|
|
5726
|
+
});
|
|
5727
|
+
__publicField$3(this, "projectObjectType", (schema) => {
|
|
5728
|
+
const requiredRaw = schema.required;
|
|
5729
|
+
if (requiredRaw !== void 0 && !Array.isArray(requiredRaw)) {
|
|
5730
|
+
throw new Error(
|
|
5731
|
+
"Unsupported object schema: required must be an array"
|
|
5732
|
+
);
|
|
5733
|
+
}
|
|
5734
|
+
const required = new Set(
|
|
5735
|
+
(requiredRaw ?? []).map((item) => {
|
|
5736
|
+
if (typeof item !== "string") {
|
|
5737
|
+
throw new Error(
|
|
5738
|
+
"Unsupported object schema: required items must be strings"
|
|
5739
|
+
);
|
|
5740
|
+
}
|
|
5741
|
+
return item;
|
|
5742
|
+
})
|
|
5431
5743
|
);
|
|
5432
|
-
const
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5744
|
+
const propertiesRaw = schema.properties;
|
|
5745
|
+
if (propertiesRaw !== void 0 && (!propertiesRaw || typeof propertiesRaw !== "object" || Array.isArray(propertiesRaw))) {
|
|
5746
|
+
throw new Error(
|
|
5747
|
+
"Unsupported object schema: properties must be an object"
|
|
5748
|
+
);
|
|
5749
|
+
}
|
|
5750
|
+
const properties = Object.entries(propertiesRaw ?? {}).map(
|
|
5751
|
+
([name, propertySchema]) => {
|
|
5752
|
+
if (!this.isSchemaNode(propertySchema)) {
|
|
5753
|
+
throw new Error(
|
|
5754
|
+
`Unsupported object property schema for "${name}"`
|
|
5755
|
+
);
|
|
5756
|
+
}
|
|
5757
|
+
return {
|
|
5758
|
+
name,
|
|
5759
|
+
required: this.isRequiredProperty(
|
|
5760
|
+
name,
|
|
5761
|
+
required,
|
|
5762
|
+
propertySchema
|
|
5763
|
+
),
|
|
5764
|
+
typeExpr: this.fromTypeExpr(propertySchema)
|
|
5765
|
+
};
|
|
5766
|
+
}
|
|
5438
5767
|
);
|
|
5768
|
+
let additionalProperties;
|
|
5769
|
+
if (schema.additionalProperties !== void 0) {
|
|
5770
|
+
if (typeof schema.additionalProperties === "boolean") {
|
|
5771
|
+
additionalProperties = schema.additionalProperties;
|
|
5772
|
+
} else if (this.isSchemaNode(schema.additionalProperties)) {
|
|
5773
|
+
additionalProperties = this.fromTypeExpr(
|
|
5774
|
+
schema.additionalProperties
|
|
5775
|
+
);
|
|
5776
|
+
} else {
|
|
5777
|
+
throw new Error(
|
|
5778
|
+
"Unsupported object schema: additionalProperties must be boolean or schema object"
|
|
5779
|
+
);
|
|
5780
|
+
}
|
|
5781
|
+
}
|
|
5439
5782
|
return {
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5783
|
+
kind: "inline",
|
|
5784
|
+
expr: {
|
|
5785
|
+
node: "object",
|
|
5786
|
+
properties,
|
|
5787
|
+
additionalProperties
|
|
5788
|
+
}
|
|
5444
5789
|
};
|
|
5445
5790
|
});
|
|
5446
|
-
__publicField$3(this, "
|
|
5447
|
-
if (
|
|
5448
|
-
return
|
|
5449
|
-
{
|
|
5450
|
-
identifier: this.paramName(param),
|
|
5451
|
-
typeExpr: param.typeExpr
|
|
5452
|
-
}
|
|
5453
|
-
];
|
|
5791
|
+
__publicField$3(this, "isRequiredProperty", (name, required, propertySchema) => {
|
|
5792
|
+
if (required.has(name)) {
|
|
5793
|
+
return true;
|
|
5454
5794
|
}
|
|
5455
|
-
if (this.options.
|
|
5456
|
-
return
|
|
5457
|
-
identifier: pathParamSpec.bindings[name] ?? name,
|
|
5458
|
-
typeExpr: pathParamSpec.propertiesByName[name].typeExpr
|
|
5459
|
-
}));
|
|
5795
|
+
if (!this.options.swaggerTsApiRequiredBooleans) {
|
|
5796
|
+
return false;
|
|
5460
5797
|
}
|
|
5461
|
-
return
|
|
5462
|
-
{
|
|
5463
|
-
identifier: this.renderPathParamDestructuring(
|
|
5464
|
-
pathParamSpec.bindings
|
|
5465
|
-
),
|
|
5466
|
-
typeExpr: param.typeExpr
|
|
5467
|
-
}
|
|
5468
|
-
];
|
|
5798
|
+
return propertySchema.required === true;
|
|
5469
5799
|
});
|
|
5470
|
-
__publicField$3(this, "
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5800
|
+
__publicField$3(this, "mapSchemaArrayMembers", (value, kind) => {
|
|
5801
|
+
if (!Array.isArray(value) || !value.length) {
|
|
5802
|
+
throw new Error(
|
|
5803
|
+
`Unsupported schema: ${kind} must be a non-empty array`
|
|
5804
|
+
);
|
|
5805
|
+
}
|
|
5806
|
+
return value.map((entry, index) => {
|
|
5807
|
+
if (!this.isSchemaNode(entry)) {
|
|
5808
|
+
throw new Error(
|
|
5809
|
+
`Unsupported schema: ${kind}[${index}] must be a schema object`
|
|
5810
|
+
);
|
|
5480
5811
|
}
|
|
5481
|
-
|
|
5482
|
-
|
|
5812
|
+
return this.fromTypeExpr(entry);
|
|
5813
|
+
});
|
|
5483
5814
|
});
|
|
5484
|
-
__publicField$3(this, "
|
|
5485
|
-
|
|
5486
|
-
([paramName, binding]) => {
|
|
5487
|
-
const key = toTsPropertyKey(paramName);
|
|
5488
|
-
return binding === paramName ? key : `${key}: ${binding}`;
|
|
5489
|
-
}
|
|
5490
|
-
);
|
|
5491
|
-
return `{ ${members.join(", ")} }`;
|
|
5815
|
+
__publicField$3(this, "isBinaryFileSchema", (schema) => {
|
|
5816
|
+
return schema.type === "string" && schema.format === "binary";
|
|
5492
5817
|
});
|
|
5493
|
-
__publicField$3(this, "
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5818
|
+
__publicField$3(this, "fromSchemaCore", (schema) => {
|
|
5819
|
+
if (this.isUnconstrainedSchema(schema)) {
|
|
5820
|
+
return this.scalar("unknown");
|
|
5821
|
+
}
|
|
5822
|
+
if (typeof schema.$ref === "string") {
|
|
5823
|
+
this.ensureSchemaDefinition(schema.$ref);
|
|
5824
|
+
return this.ref(schema.$ref);
|
|
5825
|
+
}
|
|
5826
|
+
if (schema.const !== void 0) {
|
|
5827
|
+
return this.literal(this.toLiteralValue(schema.const));
|
|
5828
|
+
}
|
|
5829
|
+
if (Array.isArray(schema.enum)) {
|
|
5830
|
+
if (!schema.enum.length) {
|
|
5503
5831
|
throw new Error(
|
|
5504
|
-
|
|
5832
|
+
"Unsupported enum schema: enum must be non-empty"
|
|
5833
|
+
);
|
|
5834
|
+
}
|
|
5835
|
+
return this.union(
|
|
5836
|
+
schema.enum.map(
|
|
5837
|
+
(value) => this.literal(this.toLiteralValue(value))
|
|
5838
|
+
)
|
|
5839
|
+
);
|
|
5840
|
+
}
|
|
5841
|
+
if (schema.type === "array") {
|
|
5842
|
+
if (schema.items === void 0) {
|
|
5843
|
+
return {
|
|
5844
|
+
kind: "inline",
|
|
5845
|
+
expr: {
|
|
5846
|
+
node: "array",
|
|
5847
|
+
element: this.scalar("unknown")
|
|
5848
|
+
}
|
|
5849
|
+
};
|
|
5850
|
+
}
|
|
5851
|
+
if (Array.isArray(schema.items)) {
|
|
5852
|
+
throw new Error("Unsupported array schema: tuple-style items");
|
|
5853
|
+
}
|
|
5854
|
+
if (!this.isSchemaNode(schema.items)) {
|
|
5855
|
+
throw new Error(
|
|
5856
|
+
"Unsupported array schema: items must be a schema"
|
|
5505
5857
|
);
|
|
5506
5858
|
}
|
|
5859
|
+
return {
|
|
5860
|
+
kind: "inline",
|
|
5861
|
+
expr: {
|
|
5862
|
+
node: "array",
|
|
5863
|
+
element: this.fromTypeExpr(schema.items)
|
|
5864
|
+
}
|
|
5865
|
+
};
|
|
5866
|
+
}
|
|
5867
|
+
if (schema.type === "object") {
|
|
5868
|
+
return this.projectObjectType(schema);
|
|
5869
|
+
}
|
|
5870
|
+
if (schema.oneOf !== void 0) {
|
|
5871
|
+
return this.union(this.mapSchemaArrayMembers(schema.oneOf, "oneOf"));
|
|
5872
|
+
}
|
|
5873
|
+
if (schema.anyOf !== void 0) {
|
|
5874
|
+
return this.union(this.mapSchemaArrayMembers(schema.anyOf, "anyOf"));
|
|
5875
|
+
}
|
|
5876
|
+
if (schema.allOf !== void 0) {
|
|
5877
|
+
return {
|
|
5878
|
+
kind: "inline",
|
|
5879
|
+
expr: {
|
|
5880
|
+
node: "intersection",
|
|
5881
|
+
members: this.mapSchemaArrayMembers(schema.allOf, "allOf")
|
|
5882
|
+
}
|
|
5883
|
+
};
|
|
5884
|
+
}
|
|
5885
|
+
if (this.isBinaryFileSchema(schema)) {
|
|
5886
|
+
return this.builtinRef("File");
|
|
5507
5887
|
}
|
|
5888
|
+
if (this.isScalarName(schema.type)) {
|
|
5889
|
+
return this.scalar(schema.type);
|
|
5890
|
+
}
|
|
5891
|
+
throw new Error(
|
|
5892
|
+
`Unsupported schema construct: ${JSON.stringify(schema, null, 2)}`
|
|
5893
|
+
);
|
|
5508
5894
|
});
|
|
5509
5895
|
}
|
|
5510
5896
|
}
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
return
|
|
5897
|
+
|
|
5898
|
+
var __defProp$2 = Object.defineProperty;
|
|
5899
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5900
|
+
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5901
|
+
const pickPreferredMediaType = (mediaTypes) => {
|
|
5902
|
+
if (!mediaTypes.length) return void 0;
|
|
5903
|
+
const exactJson = mediaTypes.find((media) => media === "application/json");
|
|
5904
|
+
if (exactJson) return exactJson;
|
|
5905
|
+
const jsonLike = mediaTypes.find((media) => /\+json$/i.test(media));
|
|
5906
|
+
if (jsonLike) return jsonLike;
|
|
5907
|
+
const wildcardJson = mediaTypes.find(
|
|
5908
|
+
(media) => /application\/\*\+json/i.test(media)
|
|
5909
|
+
);
|
|
5910
|
+
if (wildcardJson) return wildcardJson;
|
|
5911
|
+
return mediaTypes[0];
|
|
5525
5912
|
};
|
|
5526
|
-
const
|
|
5527
|
-
|
|
5913
|
+
const isSuccessStatusCode = (statusCode) => {
|
|
5914
|
+
const upper = statusCode.toUpperCase();
|
|
5915
|
+
if (/^2XX$/.test(upper)) {
|
|
5916
|
+
return true;
|
|
5917
|
+
}
|
|
5918
|
+
const numericCode = Number(statusCode);
|
|
5919
|
+
return Number.isFinite(numericCode) && numericCode >= 200 && numericCode < 300;
|
|
5528
5920
|
};
|
|
5529
|
-
const
|
|
5530
|
-
const
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
return "(none)";
|
|
5534
|
-
}
|
|
5535
|
-
return values.map((v) => JSON.stringify(v)).join(", ");
|
|
5536
|
-
};
|
|
5537
|
-
const validatePathParams = (params, httpPath) => {
|
|
5538
|
-
const placeholders = extractPathPlaceholderNames(httpPath);
|
|
5539
|
-
const placeholderSet = new Set(placeholders);
|
|
5540
|
-
const pathParams = params.filter(isPathParam);
|
|
5541
|
-
if (pathParams.length > 1) {
|
|
5542
|
-
throw new Error(
|
|
5543
|
-
`Path "${httpPath}" has ${pathParams.length} path parameter objects; expected at most one.`
|
|
5544
|
-
);
|
|
5545
|
-
}
|
|
5546
|
-
const pathParam = pathParams[0];
|
|
5547
|
-
if (!pathParam) {
|
|
5548
|
-
if (placeholderSet.size > 0) {
|
|
5549
|
-
throw new Error(
|
|
5550
|
-
`Path "${httpPath}" is missing a path parameter object for placeholders: ${renderNameList(
|
|
5551
|
-
placeholderSet
|
|
5552
|
-
)}.`
|
|
5553
|
-
);
|
|
5554
|
-
}
|
|
5555
|
-
return void 0;
|
|
5556
|
-
}
|
|
5557
|
-
const pathParamExpr = pathParam.typeExpr.expr;
|
|
5558
|
-
if (pathParamExpr.additionalProperties !== void 0 && pathParamExpr.additionalProperties !== false) {
|
|
5559
|
-
throw new Error(
|
|
5560
|
-
`Path "${httpPath}" path parameter object must not declare additionalProperties.`
|
|
5561
|
-
);
|
|
5562
|
-
}
|
|
5563
|
-
const nestedObjectProps = pathParamExpr.properties.filter((prop) => isInlineObjectType(prop.typeExpr)).map((prop) => prop.name);
|
|
5564
|
-
if (nestedObjectProps.length > 0) {
|
|
5565
|
-
throw new Error(
|
|
5566
|
-
`Path "${httpPath}" path parameters must be depth-1. Nested object properties: ${renderNameList(
|
|
5567
|
-
nestedObjectProps
|
|
5568
|
-
)}.`
|
|
5569
|
-
);
|
|
5921
|
+
const selectReturnResponses = (responses) => {
|
|
5922
|
+
const entries = Object.entries(responses);
|
|
5923
|
+
if (!entries.length) {
|
|
5924
|
+
return [];
|
|
5570
5925
|
}
|
|
5571
|
-
const
|
|
5572
|
-
if (
|
|
5573
|
-
|
|
5574
|
-
`Path "${httpPath}" path parameters must all be required. Optional properties: ${renderNameList(
|
|
5575
|
-
optionalPathProps
|
|
5576
|
-
)}.`
|
|
5577
|
-
);
|
|
5926
|
+
const success = entries.filter(([statusCode]) => isSuccessStatusCode(statusCode)).map(([, response]) => response);
|
|
5927
|
+
if (success.length) {
|
|
5928
|
+
return success;
|
|
5578
5929
|
}
|
|
5579
|
-
const
|
|
5580
|
-
|
|
5581
|
-
const missingInObject = [...placeholderSet].filter(
|
|
5582
|
-
(name) => !declaredNameSet.has(name)
|
|
5583
|
-
);
|
|
5584
|
-
const missingInPath = declaredNames.filter(
|
|
5585
|
-
(name) => !placeholderSet.has(name)
|
|
5930
|
+
const defaultResponse = entries.find(
|
|
5931
|
+
([statusCode]) => statusCode.toLowerCase() === "default"
|
|
5586
5932
|
);
|
|
5587
|
-
if (
|
|
5588
|
-
|
|
5589
|
-
`Path "${httpPath}" placeholders and path parameter object keys must match exactly. Missing in object: ${renderNameList(
|
|
5590
|
-
missingInObject
|
|
5591
|
-
)}. Missing in path: ${renderNameList(missingInPath)}.`
|
|
5592
|
-
);
|
|
5933
|
+
if (defaultResponse) {
|
|
5934
|
+
return [defaultResponse[1]];
|
|
5593
5935
|
}
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
);
|
|
5936
|
+
return entries.map(([, response]) => response);
|
|
5937
|
+
};
|
|
5938
|
+
const getPreferredMediaTypeEntry = (content) => {
|
|
5939
|
+
const mediaType = pickPreferredMediaType(Object.keys(content));
|
|
5940
|
+
if (!mediaType) return {};
|
|
5598
5941
|
return {
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
propertiesByName
|
|
5942
|
+
mediaType,
|
|
5943
|
+
media: content[mediaType]
|
|
5602
5944
|
};
|
|
5603
5945
|
};
|
|
5604
|
-
|
|
5605
|
-
const
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
const
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5946
|
+
const isBinaryFileResponse = (response) => {
|
|
5947
|
+
const { mediaType, media } = getPreferredMediaTypeEntry(response.content);
|
|
5948
|
+
return media?.schema?.type === "string" && media.schema?.format === "binary" && mediaType !== "multipart/form-data";
|
|
5949
|
+
};
|
|
5950
|
+
const isJsonLikeMediaType = (mediaType) => {
|
|
5951
|
+
return mediaType === "application/json" || typeof mediaType === "string" && /\+json$/i.test(mediaType);
|
|
5952
|
+
};
|
|
5953
|
+
const toHttpMethodUpper = (method) => {
|
|
5954
|
+
switch (method) {
|
|
5955
|
+
case "get":
|
|
5956
|
+
return "GET";
|
|
5957
|
+
case "post":
|
|
5958
|
+
return "POST";
|
|
5959
|
+
case "put":
|
|
5960
|
+
return "PUT";
|
|
5961
|
+
case "delete":
|
|
5962
|
+
return "DELETE";
|
|
5963
|
+
case "patch":
|
|
5964
|
+
return "PATCH";
|
|
5965
|
+
case "options":
|
|
5966
|
+
return "OPTIONS";
|
|
5967
|
+
case "head":
|
|
5968
|
+
return "HEAD";
|
|
5969
|
+
case "trace":
|
|
5970
|
+
return "TRACE";
|
|
5971
|
+
default: {
|
|
5972
|
+
const exhaustive = method;
|
|
5973
|
+
throw new Error(`Unsupported HTTP method: ${String(exhaustive)}`);
|
|
5974
|
+
}
|
|
5975
|
+
}
|
|
5976
|
+
};
|
|
5977
|
+
class OperationProjector {
|
|
5978
|
+
constructor(options) {
|
|
5979
|
+
this.options = options;
|
|
5980
|
+
__publicField$2(this, "seenOperationIds", /* @__PURE__ */ new Set());
|
|
5981
|
+
__publicField$2(this, "typeExprConverter");
|
|
5982
|
+
__publicField$2(this, "project", (openApi) => {
|
|
5983
|
+
this.seenOperationIds.clear();
|
|
5984
|
+
this.typeExprConverter = new ToTypeExprConverter(
|
|
5985
|
+
openApi.schemas,
|
|
5986
|
+
this.options.typeExtraction
|
|
5987
|
+
);
|
|
5988
|
+
if (this.options.includeAllSchema) {
|
|
5989
|
+
this.typeExprConverter.registerAllSchemaDefinitions();
|
|
5625
5990
|
}
|
|
5626
|
-
const
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
return
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
`;
|
|
5643
|
-
}).join("\n\n"));
|
|
5644
|
-
__publicField$2(this, "opsCode", (codegen, operations, target = "class") => {
|
|
5645
|
-
const separator = target === "object" ? `,
|
|
5646
|
-
${EMPTY_LINE_MARKER}
|
|
5647
|
-
` : "\n\n";
|
|
5648
|
-
const methodsCode = operations.map((op) => this.renderOp(op, codegen, target)).join(separator);
|
|
5649
|
-
return methodsCode;
|
|
5991
|
+
const operations = openApi.operations.map((operation) => {
|
|
5992
|
+
const operationName = (operation.operationId ?? syntheticOperationId(operation.method, operation.path)).trim();
|
|
5993
|
+
if (!operationName) {
|
|
5994
|
+
throw new Error(
|
|
5995
|
+
`Operation id is empty for ${operation.method.toUpperCase()} ${operation.path}`
|
|
5996
|
+
);
|
|
5997
|
+
}
|
|
5998
|
+
if (this.seenOperationIds.has(operationName)) {
|
|
5999
|
+
throw new Error(`Duplicate operation id: ${operationName}`);
|
|
6000
|
+
}
|
|
6001
|
+
return this.projectOne(operationName, operation);
|
|
6002
|
+
});
|
|
6003
|
+
return {
|
|
6004
|
+
operations,
|
|
6005
|
+
schemaDefinitions: this.typeExprConverter.getSchemaDefinitions()
|
|
6006
|
+
};
|
|
5650
6007
|
});
|
|
5651
|
-
__publicField$2(this, "
|
|
5652
|
-
|
|
5653
|
-
const
|
|
5654
|
-
const
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
6008
|
+
__publicField$2(this, "projectOne", (operationName, operation) => {
|
|
6009
|
+
this.seenOperationIds.add(operationName);
|
|
6010
|
+
const parameters = [];
|
|
6011
|
+
const pathParameter = this.projectPathParameter(operation);
|
|
6012
|
+
const queryParameter = this.projectQueryParameter(operation);
|
|
6013
|
+
const bodyParameter = this.projectBodyParameter(operation);
|
|
6014
|
+
if (pathParameter) parameters.push(pathParameter);
|
|
6015
|
+
if (queryParameter) parameters.push(queryParameter);
|
|
6016
|
+
if (bodyParameter) parameters.push(bodyParameter);
|
|
6017
|
+
return {
|
|
6018
|
+
op: {
|
|
6019
|
+
signature: {
|
|
6020
|
+
name: operationName,
|
|
6021
|
+
parameters,
|
|
6022
|
+
returnType: this.projectReturnType(operation)
|
|
6023
|
+
},
|
|
6024
|
+
http: {
|
|
6025
|
+
method: toHttpMethodUpper(operation.method),
|
|
6026
|
+
path: operation.path,
|
|
6027
|
+
requestContentType: this.projectRequestContentType(
|
|
6028
|
+
operation.requestBody
|
|
6029
|
+
),
|
|
6030
|
+
responseFormat: this.projectResponseFormat(operation)
|
|
6031
|
+
}
|
|
6032
|
+
},
|
|
6033
|
+
tags: [...operation.tags]
|
|
5658
6034
|
};
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
const { path, funParams, hasBody, hasQuery } = paramsHelper.process(
|
|
5664
|
-
sig.parameters,
|
|
5665
|
-
http.path
|
|
5666
|
-
);
|
|
5667
|
-
const params = funParams.map(
|
|
5668
|
-
(r) => `${r.identifier}: ${tsCodegen.toCode(r.typeExpr)}`
|
|
6035
|
+
});
|
|
6036
|
+
__publicField$2(this, "projectRequestContentType", (requestBody) => {
|
|
6037
|
+
const { mediaType } = getPreferredMediaTypeEntry(
|
|
6038
|
+
requestBody?.content ?? {}
|
|
5669
6039
|
);
|
|
5670
|
-
|
|
5671
|
-
|
|
6040
|
+
switch (mediaType) {
|
|
6041
|
+
case "application/json":
|
|
6042
|
+
case "multipart/form-data":
|
|
6043
|
+
case "application/x-www-form-urlencoded":
|
|
6044
|
+
return mediaType;
|
|
6045
|
+
default:
|
|
6046
|
+
return void 0;
|
|
5672
6047
|
}
|
|
5673
|
-
const paramsCode = params.join(", ");
|
|
5674
|
-
const responseType = tsCodegen.toCode(sig.returnType);
|
|
5675
|
-
const returnType = this.wrapInResponseWrapper(sig.returnType, tsCodegen);
|
|
5676
|
-
return this.renderFunctionCode({
|
|
5677
|
-
funName: sig.name,
|
|
5678
|
-
responseType,
|
|
5679
|
-
returnType,
|
|
5680
|
-
params: paramsCode,
|
|
5681
|
-
path,
|
|
5682
|
-
method: http.method,
|
|
5683
|
-
hasQuery,
|
|
5684
|
-
hasBody,
|
|
5685
|
-
requestContentType: http.requestContentType,
|
|
5686
|
-
responseFormat: http.responseFormat,
|
|
5687
|
-
requestParamsVar: this.opts.requestParams ? REQUEST_PARAMS_ARG : void 0,
|
|
5688
|
-
unwrap: this.opts.unwrap ?? false,
|
|
5689
|
-
target
|
|
5690
|
-
});
|
|
5691
6048
|
});
|
|
5692
|
-
__publicField$2(this, "
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
}
|
|
6049
|
+
__publicField$2(this, "projectResponseFormat", (operation) => {
|
|
6050
|
+
const selectedResponses = selectReturnResponses(operation.responses);
|
|
6051
|
+
if (!selectedResponses.length) {
|
|
6052
|
+
return void 0;
|
|
6053
|
+
}
|
|
6054
|
+
if (selectedResponses.some((response) => isBinaryFileResponse(response))) {
|
|
6055
|
+
return "document";
|
|
6056
|
+
}
|
|
6057
|
+
if (selectedResponses.some(
|
|
6058
|
+
(response) => isJsonLikeMediaType(
|
|
6059
|
+
getPreferredMediaTypeEntry(response.content).mediaType
|
|
6060
|
+
)
|
|
6061
|
+
)) {
|
|
6062
|
+
return "json";
|
|
6063
|
+
}
|
|
6064
|
+
return void 0;
|
|
5697
6065
|
});
|
|
5698
|
-
__publicField$2(this, "
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
const
|
|
5729
|
-
const
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
6066
|
+
__publicField$2(this, "projectParameterGroupTypeExpr", (params) => {
|
|
6067
|
+
const properties = Object.entries(params).map(([name, parameter]) => ({
|
|
6068
|
+
name,
|
|
6069
|
+
required: parameter.required,
|
|
6070
|
+
typeExpr: this.typeExprConverter.fromTypeExpr(
|
|
6071
|
+
this.selectParameterSchema(parameter)
|
|
6072
|
+
)
|
|
6073
|
+
}));
|
|
6074
|
+
return {
|
|
6075
|
+
kind: "inline",
|
|
6076
|
+
expr: {
|
|
6077
|
+
node: "object",
|
|
6078
|
+
properties
|
|
6079
|
+
}
|
|
6080
|
+
};
|
|
6081
|
+
});
|
|
6082
|
+
__publicField$2(this, "projectPathParameter", (operation) => {
|
|
6083
|
+
const params = operation.parameters.path;
|
|
6084
|
+
const entries = Object.values(params);
|
|
6085
|
+
if (!entries.length) return null;
|
|
6086
|
+
if (entries.some((parameter) => !parameter.required)) {
|
|
6087
|
+
throw new Error("Unsupported path parameters: all must be required");
|
|
6088
|
+
}
|
|
6089
|
+
return {
|
|
6090
|
+
kind: "path",
|
|
6091
|
+
optional: false,
|
|
6092
|
+
typeExpr: this.projectParameterGroupTypeExpr(params)
|
|
6093
|
+
};
|
|
6094
|
+
});
|
|
6095
|
+
__publicField$2(this, "projectQueryParameter", (operation) => {
|
|
6096
|
+
const params = operation.parameters.query;
|
|
6097
|
+
const entries = Object.values(params);
|
|
6098
|
+
if (!entries.length) return null;
|
|
6099
|
+
return {
|
|
6100
|
+
kind: "query",
|
|
6101
|
+
optional: !entries.some((parameter) => parameter.required),
|
|
6102
|
+
typeExpr: this.projectParameterGroupTypeExpr(params)
|
|
6103
|
+
};
|
|
6104
|
+
});
|
|
6105
|
+
__publicField$2(this, "projectBodyParameter", (operation) => {
|
|
6106
|
+
const requestBody = operation.requestBody;
|
|
6107
|
+
if (!requestBody) return null;
|
|
6108
|
+
return {
|
|
6109
|
+
kind: "body",
|
|
6110
|
+
optional: !requestBody.required,
|
|
6111
|
+
typeExpr: this.typeExprConverter.fromTypeExpr(
|
|
6112
|
+
this.selectRequestBodySchema(requestBody)
|
|
6113
|
+
)
|
|
6114
|
+
};
|
|
6115
|
+
});
|
|
6116
|
+
__publicField$2(this, "projectReturnType", (operation) => {
|
|
6117
|
+
const selectedResponses = selectReturnResponses(operation.responses);
|
|
6118
|
+
if (!selectedResponses.length) {
|
|
6119
|
+
return this.typeExprConverter.scalar("void");
|
|
6120
|
+
}
|
|
6121
|
+
const responseTypes = selectedResponses.map((response) => {
|
|
6122
|
+
const schema = this.selectResponseSchema(response);
|
|
6123
|
+
if (!schema) {
|
|
6124
|
+
return this.typeExprConverter.scalar("void");
|
|
6125
|
+
}
|
|
6126
|
+
return this.typeExprConverter.fromTypeExpr(schema);
|
|
6127
|
+
});
|
|
6128
|
+
return this.typeExprConverter.union(responseTypes);
|
|
6129
|
+
});
|
|
6130
|
+
__publicField$2(this, "selectParameterSchema", (parameter) => {
|
|
6131
|
+
if (parameter.schema) return parameter.schema;
|
|
6132
|
+
return getPreferredMediaTypeEntry(parameter.content).media?.schema;
|
|
6133
|
+
});
|
|
6134
|
+
__publicField$2(this, "selectRequestBodySchema", (requestBody) => {
|
|
6135
|
+
return getPreferredMediaTypeEntry(requestBody.content).media?.schema;
|
|
6136
|
+
});
|
|
6137
|
+
__publicField$2(this, "selectResponseSchema", (response) => {
|
|
6138
|
+
return getPreferredMediaTypeEntry(response.content).media?.schema;
|
|
5733
6139
|
});
|
|
5734
6140
|
}
|
|
5735
|
-
}
|
|
5736
|
-
|
|
5737
|
-
const promiseHttpClientCodegenSpec = () => ({
|
|
5738
|
-
typeName: {
|
|
5739
|
-
kind: "reference",
|
|
5740
|
-
ref: {
|
|
5741
|
-
kind: "internal",
|
|
5742
|
-
name: "HttpClient"
|
|
5743
|
-
}
|
|
5744
|
-
},
|
|
5745
|
-
responseWrapper: {
|
|
5746
|
-
kind: "reference",
|
|
5747
|
-
ref: {
|
|
5748
|
-
kind: "builtin",
|
|
5749
|
-
name: "Promise"
|
|
5750
|
-
}
|
|
5751
|
-
},
|
|
5752
|
-
inferMethodReturnType: true,
|
|
5753
|
-
invocation: {
|
|
5754
|
-
vars: {
|
|
5755
|
-
body: "body",
|
|
5756
|
-
query: "query"
|
|
5757
|
-
},
|
|
5758
|
-
expr: ({
|
|
5759
|
-
responseType,
|
|
5760
|
-
path,
|
|
5761
|
-
method,
|
|
5762
|
-
hasBody,
|
|
5763
|
-
hasQuery,
|
|
5764
|
-
requestContentType,
|
|
5765
|
-
responseFormat,
|
|
5766
|
-
requestParamsVar,
|
|
5767
|
-
unwrap
|
|
5768
|
-
}) => `.request<${responseType}>({
|
|
5769
|
-
method: '${method}',
|
|
5770
|
-
path: ${path}
|
|
5771
|
-
${hasQuery ? `,
|
|
5772
|
-
query` : ""}
|
|
5773
|
-
${hasBody ? `,
|
|
5774
|
-
body` : ""}
|
|
5775
|
-
${requestContentType ? `,
|
|
5776
|
-
requestContentType: '${requestContentType}'` : ""}
|
|
5777
|
-
${responseFormat ? `,
|
|
5778
|
-
format: '${responseFormat}'` : ""}
|
|
5779
|
-
}${requestParamsVar ? `,
|
|
5780
|
-
${requestParamsVar}` : ""})${unwrap ? `.then(res => res.body)` : ""}
|
|
5781
|
-
`
|
|
5782
|
-
}
|
|
5783
|
-
});
|
|
6141
|
+
}
|
|
5784
6142
|
|
|
5785
6143
|
var __defProp$1 = Object.defineProperty;
|
|
5786
6144
|
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -5796,7 +6154,7 @@ class CodeFormatter {
|
|
|
5796
6154
|
constructor(opts) {
|
|
5797
6155
|
this.opts = opts;
|
|
5798
6156
|
__publicField$1(this, "format", async (code) => {
|
|
5799
|
-
const filePath = Path.resolve(this.opts.resolveConfFrom, "generated.ts");
|
|
6157
|
+
const filePath = Path$1.resolve(this.opts.resolveConfFrom, "generated.ts");
|
|
5800
6158
|
const prettier = await import('prettier');
|
|
5801
6159
|
const prettierConfig = await prettier.resolveConfig(filePath) ?? {};
|
|
5802
6160
|
const formattedCode = await prettier.format(code, {
|
|
@@ -5890,185 +6248,76 @@ class CodeWriter {
|
|
|
5890
6248
|
}
|
|
5891
6249
|
const ensureSingleTrailingNewline = (code) => code.replace(/\n+$/u, "\n");
|
|
5892
6250
|
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
const orderedChunks = orderByInternalDependencies(chunks);
|
|
5898
|
-
const mergedCode = orderedChunks.map((chunk) => chunk.code).join("\n\n");
|
|
5899
|
-
const exportedSymbols = /* @__PURE__ */ new Set();
|
|
5900
|
-
const mergedExports = [];
|
|
5901
|
-
for (const chunk of orderedChunks) {
|
|
5902
|
-
for (const symbol of chunk.exports) {
|
|
5903
|
-
if (exportedSymbols.has(symbol)) continue;
|
|
5904
|
-
exportedSymbols.add(symbol);
|
|
5905
|
-
mergedExports.push(symbol);
|
|
5906
|
-
}
|
|
5907
|
-
}
|
|
5908
|
-
const seenRefKeys = /* @__PURE__ */ new Set();
|
|
5909
|
-
const mergedRefs = orderedChunks.flatMap((chunk) => chunk.refs).filter((ref) => {
|
|
5910
|
-
if (ref.kind === "internal" && exportedSymbols.has(ref.name)) {
|
|
5911
|
-
return false;
|
|
5912
|
-
}
|
|
5913
|
-
const key = ref.kind === "internal" ? `internal:${ref.name}` : ref.kind === "external" ? `external:${ref.package}:${ref.name}` : `builtin:${ref.name}`;
|
|
5914
|
-
if (seenRefKeys.has(key)) return false;
|
|
5915
|
-
seenRefKeys.add(key);
|
|
5916
|
-
return true;
|
|
5917
|
-
});
|
|
5918
|
-
return {
|
|
5919
|
-
name,
|
|
5920
|
-
code: mergedCode,
|
|
5921
|
-
exports: mergedExports,
|
|
5922
|
-
refs: mergedRefs
|
|
5923
|
-
};
|
|
5924
|
-
};
|
|
5925
|
-
const orderByInternalDependencies = (chunks) => {
|
|
5926
|
-
const chunkIndex = /* @__PURE__ */ new Map();
|
|
5927
|
-
const exportOwnerBySymbol = /* @__PURE__ */ new Map();
|
|
5928
|
-
chunks.forEach((chunk, index) => {
|
|
5929
|
-
chunkIndex.set(chunk.name, index);
|
|
5930
|
-
for (const symbol of chunk.exports) {
|
|
5931
|
-
if (exportOwnerBySymbol.has(symbol)) {
|
|
5932
|
-
throw new Error(
|
|
5933
|
-
`Assertion error. Symbol "${symbol}" exported multiple times while ordering chunks.`
|
|
5934
|
-
);
|
|
5935
|
-
}
|
|
5936
|
-
exportOwnerBySymbol.set(symbol, chunk);
|
|
5937
|
-
}
|
|
5938
|
-
});
|
|
5939
|
-
const dependentsByProvider = /* @__PURE__ */ new Map();
|
|
5940
|
-
const inDegreeByChunk = /* @__PURE__ */ new Map();
|
|
5941
|
-
for (const chunk of chunks) {
|
|
5942
|
-
dependentsByProvider.set(chunk, /* @__PURE__ */ new Set());
|
|
5943
|
-
inDegreeByChunk.set(chunk, 0);
|
|
5944
|
-
}
|
|
5945
|
-
for (const chunk of chunks) {
|
|
5946
|
-
const providers = /* @__PURE__ */ new Set();
|
|
5947
|
-
for (const ref of chunk.refs) {
|
|
5948
|
-
if (ref.kind !== "internal") continue;
|
|
5949
|
-
const provider = exportOwnerBySymbol.get(ref.name);
|
|
5950
|
-
if (!provider || provider === chunk) continue;
|
|
5951
|
-
providers.add(provider);
|
|
5952
|
-
}
|
|
5953
|
-
for (const provider of providers) {
|
|
5954
|
-
dependentsByProvider.get(provider).add(chunk);
|
|
5955
|
-
inDegreeByChunk.set(chunk, inDegreeByChunk.get(chunk) + 1);
|
|
5956
|
-
}
|
|
6251
|
+
class VNextOasClientGenerator {
|
|
6252
|
+
constructor(options, log) {
|
|
6253
|
+
this.options = options;
|
|
6254
|
+
this.log = log;
|
|
5957
6255
|
}
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
const
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
6256
|
+
async generate(cmd) {
|
|
6257
|
+
const { inputFile, outputDir, apiName } = cmd;
|
|
6258
|
+
this.log(`Will generate API client name=${apiName} to ${outputDir}`);
|
|
6259
|
+
const sourceSchema = await loadSourceSchema(inputFile);
|
|
6260
|
+
const normalizedSchema = this.normalizeSchema(sourceSchema, inputFile);
|
|
6261
|
+
const openApiIr = this.filterOperations(normalizedSchema);
|
|
6262
|
+
const projectResult = new OperationProjector({
|
|
6263
|
+
includeAllSchema: this.options.selection?.allSchemas === true,
|
|
6264
|
+
typeExtraction: {
|
|
6265
|
+
enumStyle: this.options.codegen.enumStyle,
|
|
6266
|
+
uppercaseEnumKeys: this.options.compat?.uppercaseEnumKeys,
|
|
6267
|
+
swaggerTsApiRequiredBooleans: this.options.compat?.swaggerTsApiRequiredBooleans
|
|
5968
6268
|
}
|
|
5969
|
-
}
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
`Cannot order chunks with cyclic internal dependencies: ${cycleChunkNames}`
|
|
6269
|
+
}).project(openApiIr);
|
|
6270
|
+
const clientName = toPascalCaseIdentifier(apiName);
|
|
6271
|
+
const chunks = generateTsCode(
|
|
6272
|
+
clientName,
|
|
6273
|
+
projectResult,
|
|
6274
|
+
this.options.codegen
|
|
5976
6275
|
);
|
|
6276
|
+
const codeFormatter = new CodeFormatter({
|
|
6277
|
+
resolveConfFrom: outputDir
|
|
6278
|
+
});
|
|
6279
|
+
const writer = new CodeWriter(codeFormatter);
|
|
6280
|
+
await writer.write(outputDir, chunks.all);
|
|
6281
|
+
const tsFilePath = (name) => Path.join(outputDir, `${name}.ts`);
|
|
6282
|
+
return {
|
|
6283
|
+
promiseWrapper: chunks.promiseWrappersNames.map(tsFilePath),
|
|
6284
|
+
types: tsFilePath(chunks.typesName)
|
|
6285
|
+
};
|
|
5977
6286
|
}
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
const generateFromIr = async ({
|
|
5982
|
-
openApiIr,
|
|
5983
|
-
clientName,
|
|
5984
|
-
outputDir,
|
|
5985
|
-
outputFilename,
|
|
5986
|
-
codeFormattingConfigDir,
|
|
5987
|
-
quirks,
|
|
5988
|
-
requestParams: withRequestParams
|
|
5989
|
-
}) => {
|
|
5990
|
-
const tsCodegenFac = new TsCodegenFactory();
|
|
5991
|
-
const projectResult = new OperationProjector({
|
|
5992
|
-
quirks
|
|
5993
|
-
}).project(openApiIr);
|
|
5994
|
-
const { schemaDefinitions } = projectResult;
|
|
5995
|
-
const requestParams = withRequestParams;
|
|
5996
|
-
const types = schemaDefinitions.map((def) => {
|
|
5997
|
-
const cg = tsCodegenFac.forNewChunk();
|
|
5998
|
-
const typeName = def.name;
|
|
5999
|
-
const code = `export type ${typeName} = ${cg.toCode(def.typeExpr)}`;
|
|
6000
|
-
return cg.toChunk(typeName, code, [typeName]);
|
|
6001
|
-
});
|
|
6002
|
-
const clientCodegen = new ApiClientCodegen(
|
|
6003
|
-
{
|
|
6004
|
-
httpClient: promiseHttpClientCodegenSpec(),
|
|
6005
|
-
requestParams,
|
|
6006
|
-
// TODO make configurable
|
|
6007
|
-
pathParamsStyle: "positional"
|
|
6008
|
-
},
|
|
6009
|
-
tsCodegenFac
|
|
6010
|
-
);
|
|
6011
|
-
const generated = clientCodegen.generate(
|
|
6012
|
-
clientName,
|
|
6013
|
-
groupsOpsByTag(projectResult.operations)
|
|
6014
|
-
);
|
|
6015
|
-
const httpClientChunk = tsCodegenFac.forNewChunk().toChunk(
|
|
6016
|
-
"HttpClient",
|
|
6017
|
-
getHttpClientCode(),
|
|
6018
|
-
["HttpRequest", "HttpResponse", "HttpClient"]
|
|
6019
|
-
);
|
|
6020
|
-
const codeFormatter = new CodeFormatter({
|
|
6021
|
-
resolveConfFrom: codeFormattingConfigDir
|
|
6022
|
-
});
|
|
6023
|
-
const writer = new CodeWriter(codeFormatter);
|
|
6024
|
-
let chunks = [...types, httpClientChunk, generated];
|
|
6025
|
-
chunks = [mergeChunks(outputFilename, chunks)];
|
|
6026
|
-
await writer.write(outputDir, chunks);
|
|
6027
|
-
};
|
|
6028
|
-
const groupsOpsByTag = (operations) => {
|
|
6029
|
-
const groupedOps = {};
|
|
6030
|
-
operations.forEach((operation) => {
|
|
6031
|
-
const groupName = operation.tags[0]?.trim() || "root";
|
|
6032
|
-
const bucket = groupedOps[groupName] ?? [];
|
|
6033
|
-
bucket.push(operation.op);
|
|
6034
|
-
groupedOps[groupName] = bucket;
|
|
6035
|
-
});
|
|
6036
|
-
return groupedOps;
|
|
6037
|
-
};
|
|
6038
|
-
const commonTypesCode = httpClientCommonTypesSource;
|
|
6039
|
-
const promiseHttpClientCode = httpClientPromiseTypesSource;
|
|
6040
|
-
const stripImports = (code) => code.replace(/^import[\s\S]*?from\s+['"][^'"]+['"]\s*;?\n?/gm, "").trim();
|
|
6041
|
-
const getHttpClientCode = (opts) => [
|
|
6042
|
-
commonTypesCode,
|
|
6043
|
-
promiseHttpClientCode
|
|
6044
|
-
].map(stripImports).join("\n\n");
|
|
6045
|
-
|
|
6046
|
-
const generateOpenApiClient$1 = async ({ input, name, outputDir, quirks, ignoreOperationsWithTags }, log) => {
|
|
6047
|
-
log(`Will generate API client name=${name} to ${outputDir}`);
|
|
6048
|
-
const sourceSchema = await loadSourceSchema(input);
|
|
6049
|
-
const { result, problems } = new OpenApiNormalizer(sourceSchema).load();
|
|
6050
|
-
problems.forEach((problem) => {
|
|
6051
|
-
log(`[open-api:${problem.level}] ${problem.path}: ${problem.message}`);
|
|
6052
|
-
});
|
|
6053
|
-
const errors = problems.filter((problem) => problem.level === "error");
|
|
6054
|
-
if (errors.length) {
|
|
6055
|
-
throw new Error(
|
|
6056
|
-
`Failed to load OpenAPI IR from ${input}: ${errors.length} error(s).`
|
|
6287
|
+
filterOperations(openApiIr) {
|
|
6288
|
+
const ignoreTags = new Set(
|
|
6289
|
+
this.options.selection?.ignoreOperationsWithTags || []
|
|
6057
6290
|
);
|
|
6291
|
+
return {
|
|
6292
|
+
...openApiIr,
|
|
6293
|
+
operations: openApiIr.operations.filter((operation) => {
|
|
6294
|
+
const hasUsableTags = operation.tags.some((tag) => tag.trim());
|
|
6295
|
+
if (!hasUsableTags) {
|
|
6296
|
+
this.log(
|
|
6297
|
+
`[open-api:warning] Ignoring operation ${operation.method.toUpperCase()} ${operation.path} (${operation.operationId ?? "<missing operationId>"}): no tags`
|
|
6298
|
+
);
|
|
6299
|
+
return false;
|
|
6300
|
+
}
|
|
6301
|
+
return !operation.tags.some((tag) => ignoreTags.has(tag));
|
|
6302
|
+
})
|
|
6303
|
+
};
|
|
6058
6304
|
}
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
}
|
|
6305
|
+
normalizeSchema(rawSchema, inputFile) {
|
|
6306
|
+
const { result, problems } = new OpenApiNormalizer(rawSchema).load();
|
|
6307
|
+
problems.forEach((problem) => {
|
|
6308
|
+
this.log(
|
|
6309
|
+
`[open-api:${problem.level}] ${problem.path}: ${problem.message}`
|
|
6310
|
+
);
|
|
6311
|
+
});
|
|
6312
|
+
const errors = problems.filter((problem) => problem.level === "error");
|
|
6313
|
+
if (errors.length) {
|
|
6314
|
+
throw new Error(
|
|
6315
|
+
`Failed to load OpenAPI IR from ${inputFile}: ${errors.length} error(s).`
|
|
6316
|
+
);
|
|
6317
|
+
}
|
|
6318
|
+
return result;
|
|
6319
|
+
}
|
|
6320
|
+
}
|
|
6072
6321
|
const loadSourceSchema = async (input) => {
|
|
6073
6322
|
let rawContent;
|
|
6074
6323
|
try {
|
|
@@ -6091,109 +6340,60 @@ const loadSourceSchema = async (input) => {
|
|
|
6091
6340
|
}
|
|
6092
6341
|
return parsed;
|
|
6093
6342
|
};
|
|
6094
|
-
const filterOperations = (openApiIr, log, ignoreOperationsWithTags) => {
|
|
6095
|
-
const ignoreTags = new Set(ignoreOperationsWithTags);
|
|
6096
|
-
return {
|
|
6097
|
-
...openApiIr,
|
|
6098
|
-
operations: openApiIr.operations.filter((operation) => {
|
|
6099
|
-
const hasUsableTags = operation.tags.some((tag) => tag.trim());
|
|
6100
|
-
if (!hasUsableTags) {
|
|
6101
|
-
log(
|
|
6102
|
-
`[open-api:warning] Ignoring operation ${operation.method.toUpperCase()} ${operation.path} (${operation.operationId ?? "<missing operationId>"}): no tags`
|
|
6103
|
-
);
|
|
6104
|
-
return false;
|
|
6105
|
-
}
|
|
6106
|
-
return !operation.tags.some((tag) => ignoreTags.has(tag));
|
|
6107
|
-
})
|
|
6108
|
-
};
|
|
6109
|
-
};
|
|
6110
6343
|
const toErrorMessage = (error) => {
|
|
6111
6344
|
return error instanceof Error ? error.message : String(error);
|
|
6112
6345
|
};
|
|
6113
6346
|
|
|
6114
|
-
const
|
|
6115
|
-
|
|
6116
|
-
const
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
(t) => ignoreTags.has(t)
|
|
6146
|
-
);
|
|
6147
|
-
if (ignore) return false;
|
|
6148
|
-
}
|
|
6149
|
-
return routeData;
|
|
6150
|
-
}
|
|
6151
|
-
},
|
|
6152
|
-
// @ts-ignore
|
|
6153
|
-
codeGenConstructs: () => ({
|
|
6154
|
-
Keyword: {}
|
|
6155
|
-
})
|
|
6156
|
-
// extractRequestParams: true,
|
|
6157
|
-
});
|
|
6158
|
-
return dstFile;
|
|
6159
|
-
};
|
|
6160
|
-
const getThisScriptDirname = () => {
|
|
6161
|
-
return Path$1.dirname(fileURLToPath(import.meta.url));
|
|
6162
|
-
};
|
|
6163
|
-
const getTemplatesDir = () => {
|
|
6164
|
-
const currentDir = getThisScriptDirname();
|
|
6165
|
-
const templatesRelativePath = Path$1.basename(currentDir) === "dist" ? "../templates" : "../../../templates";
|
|
6166
|
-
return Path$1.resolve(currentDir, templatesRelativePath);
|
|
6167
|
-
};
|
|
6168
|
-
|
|
6169
|
-
const SUPPORTED_GENERATORS = [
|
|
6170
|
-
"swagger-ts-api",
|
|
6171
|
-
"api-client-generator"
|
|
6172
|
-
];
|
|
6173
|
-
const OPEN_API_MODEL_GENERATORS = {
|
|
6174
|
-
"swagger-ts-api": generateOpenApiClient,
|
|
6175
|
-
"api-client-generator": generateOpenApiClient$1
|
|
6176
|
-
};
|
|
6177
|
-
const generateOpenApiModel = async (generator, cmd, log) => {
|
|
6178
|
-
const generatorFun = OPEN_API_MODEL_GENERATORS[generator];
|
|
6179
|
-
const outputPath = await generatorFun(cmd, log);
|
|
6180
|
-
const outputModifiers = getOutputModifiers(cmd, log);
|
|
6181
|
-
log(`Will modify the outputs ${JSON.stringify(outputModifiers)}`);
|
|
6182
|
-
await modifyOutput(outputPath, outputModifiers);
|
|
6183
|
-
return outputPath;
|
|
6347
|
+
const generateOpenApiModel = async (spectPath, config, log) => {
|
|
6348
|
+
let outFiles;
|
|
6349
|
+
const { openApiGenerator, responseWrapper } = config;
|
|
6350
|
+
if ("legacy" in openApiGenerator) {
|
|
6351
|
+
outFiles = await generateOpenApiClient(
|
|
6352
|
+
spectPath,
|
|
6353
|
+
{
|
|
6354
|
+
ignoreOperationsWithTags: openApiGenerator.legacy.ignoreOperationsWithTags,
|
|
6355
|
+
name: config.apiName,
|
|
6356
|
+
outputDir: config.dstDir
|
|
6357
|
+
},
|
|
6358
|
+
log
|
|
6359
|
+
);
|
|
6360
|
+
} else {
|
|
6361
|
+
outFiles = await new VNextOasClientGenerator(
|
|
6362
|
+
openApiGenerator,
|
|
6363
|
+
log
|
|
6364
|
+
).generate({
|
|
6365
|
+
inputFile: spectPath,
|
|
6366
|
+
apiName: config.apiName,
|
|
6367
|
+
outputDir: config.dstDir
|
|
6368
|
+
});
|
|
6369
|
+
}
|
|
6370
|
+
if (responseWrapper) {
|
|
6371
|
+
await modifyHttpClientAsyncWrapper(
|
|
6372
|
+
outFiles.promiseWrapper,
|
|
6373
|
+
responseWrapper,
|
|
6374
|
+
log
|
|
6375
|
+
);
|
|
6376
|
+
}
|
|
6377
|
+
return { typesFilePath: outFiles.types };
|
|
6184
6378
|
};
|
|
6185
|
-
const
|
|
6379
|
+
const modifyHttpClientAsyncWrapper = async (filePaths, responseWrapper, log) => {
|
|
6380
|
+
log(
|
|
6381
|
+
`Will use response wrapper '${JSON.stringify(responseWrapper)}' on file ${filePaths.join(", ")}`
|
|
6382
|
+
);
|
|
6186
6383
|
const addImports = [];
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6384
|
+
if (responseWrapper.import) {
|
|
6385
|
+
addImports.push(responseWrapper.import);
|
|
6386
|
+
}
|
|
6387
|
+
const replaces = [["Promise", responseWrapper.symbol]];
|
|
6388
|
+
if (responseWrapper.unwrapExpr) {
|
|
6389
|
+
replaces.push([".then(res => res.body)", responseWrapper.unwrapExpr]);
|
|
6390
|
+
}
|
|
6391
|
+
for (const filePath of filePaths) {
|
|
6392
|
+
await modifyOutput(filePath, {
|
|
6393
|
+
addImports,
|
|
6394
|
+
replaces
|
|
6395
|
+
});
|
|
6192
6396
|
}
|
|
6193
|
-
return {
|
|
6194
|
-
addImports,
|
|
6195
|
-
replaces
|
|
6196
|
-
};
|
|
6197
6397
|
};
|
|
6198
6398
|
const modifyOutput = async (path, cmd) => {
|
|
6199
6399
|
let content = await fs$1.readFile(path).then((r) => r.toString());
|
|
@@ -6259,9 +6459,7 @@ const generateSchemas = async (inputFile, outputFile, opts = {}) => {
|
|
|
6259
6459
|
const { getZodSchemasFile } = generate({
|
|
6260
6460
|
sourceText: removeGenericTypes(code)
|
|
6261
6461
|
});
|
|
6262
|
-
|
|
6263
|
-
let f = getZodSchemasFile(`./${fileName.replace(".ts", "")}`);
|
|
6264
|
-
f = f.replaceAll('"./index";', '"./client"');
|
|
6462
|
+
let f = getZodSchemasFile(getModuleImportPath(inputFile, outputFile));
|
|
6265
6463
|
f = f.replaceAll(".optional()", ".nullable()");
|
|
6266
6464
|
if (opts.localDateTimes) {
|
|
6267
6465
|
f = f.replaceAll(
|
|
@@ -6277,50 +6475,25 @@ const generateSchemas = async (inputFile, outputFile, opts = {}) => {
|
|
|
6277
6475
|
});
|
|
6278
6476
|
fs__default.writeFileSync(outputFile, formatted);
|
|
6279
6477
|
};
|
|
6280
|
-
|
|
6281
|
-
const
|
|
6282
|
-
const
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
generator: _enum(SUPPORTED_GENERATORS).default(DEFAULT_GENERATOR),
|
|
6287
|
-
quirks: strictObject({
|
|
6288
|
-
swaggerTsApiRequiredBooleans: boolean().optional()
|
|
6289
|
-
}).optional(),
|
|
6290
|
-
responseWrapper: strictObject({
|
|
6291
|
-
symbol: string().trim().min(1),
|
|
6292
|
-
import: string().trim().min(1).optional()
|
|
6293
|
-
}).optional(),
|
|
6294
|
-
ignoreOperationsWithTags: array(string()).optional(),
|
|
6295
|
-
zodSchemas: strictObject({
|
|
6296
|
-
enabled: boolean().optional(),
|
|
6297
|
-
localDateTimes: boolean().optional()
|
|
6298
|
-
}).optional()
|
|
6299
|
-
});
|
|
6300
|
-
const parseGenerateApiClientParams = (params) => {
|
|
6301
|
-
const parsed = generateApiClientParamsSchema.safeParse(params);
|
|
6302
|
-
if (parsed.success) return parsed.data;
|
|
6303
|
-
throw new Error(prettifyError(parsed.error));
|
|
6478
|
+
const getModuleImportPath = (inputFile, outputFile) => {
|
|
6479
|
+
const sourceDir = Path.dirname(outputFile);
|
|
6480
|
+
const relativePath = Path.relative(sourceDir, inputFile);
|
|
6481
|
+
const withoutExtension = relativePath.replace(/\.ts$/u, "");
|
|
6482
|
+
const normalizedPath = withoutExtension.split(Path.sep).join("/");
|
|
6483
|
+
return normalizedPath.startsWith(".") ? normalizedPath : `./${normalizedPath}`;
|
|
6304
6484
|
};
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
quirks,
|
|
6311
|
-
responseWrapper,
|
|
6312
|
-
ignoreOperationsWithTags,
|
|
6313
|
-
zodSchemas,
|
|
6314
|
-
generator
|
|
6315
|
-
} = parseGenerateApiClientParams(params);
|
|
6316
|
-
const dir = Path$1.resolve(dstDir, apiName);
|
|
6485
|
+
|
|
6486
|
+
const generateApiClient = async (params, configFilePath, log = console.log) => {
|
|
6487
|
+
const config = parseConfig(params, configFilePath);
|
|
6488
|
+
const { dstDir, apiName, srcSpec, zodSchemas } = config;
|
|
6489
|
+
const dir = Path.resolve(dstDir, apiName);
|
|
6317
6490
|
if (!fs.existsSync(dir)) {
|
|
6318
6491
|
log(`Creating dir ${dir}`);
|
|
6319
6492
|
fs.mkdirSync(dir, {
|
|
6320
6493
|
recursive: true
|
|
6321
6494
|
});
|
|
6322
6495
|
}
|
|
6323
|
-
const clientDir = Path
|
|
6496
|
+
const clientDir = Path.resolve(dir, "client");
|
|
6324
6497
|
const specPath = await getSpecPath(srcSpec, dir, log);
|
|
6325
6498
|
log(`Cleaning client output dir ${clientDir}`);
|
|
6326
6499
|
fs.rmSync(clientDir, {
|
|
@@ -6330,23 +6503,19 @@ const generateApiClient = async (params, log = console.log) => {
|
|
|
6330
6503
|
fs.mkdirSync(clientDir, {
|
|
6331
6504
|
recursive: true
|
|
6332
6505
|
});
|
|
6333
|
-
const
|
|
6334
|
-
|
|
6506
|
+
const { typesFilePath } = await generateOpenApiModel(
|
|
6507
|
+
specPath,
|
|
6335
6508
|
{
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
outputDir: clientDir,
|
|
6339
|
-
quirks,
|
|
6340
|
-
ignoreOperationsWithTags,
|
|
6341
|
-
responseWrapper
|
|
6509
|
+
...config,
|
|
6510
|
+
dstDir: clientDir
|
|
6342
6511
|
},
|
|
6343
6512
|
log
|
|
6344
6513
|
);
|
|
6345
6514
|
if (zodSchemas?.enabled === false) return;
|
|
6346
6515
|
log("Generating Zod schemas");
|
|
6347
6516
|
await generateSchemas(
|
|
6348
|
-
|
|
6349
|
-
Path
|
|
6517
|
+
typesFilePath,
|
|
6518
|
+
Path.resolve(dir, "./zod.ts"),
|
|
6350
6519
|
zodSchemas
|
|
6351
6520
|
);
|
|
6352
6521
|
};
|
|
@@ -6356,7 +6525,7 @@ const getSpecPath = async (urlOrPath, dir, log) => {
|
|
|
6356
6525
|
throw new Error(`Spec file ${urlOrPath} does not exists`);
|
|
6357
6526
|
return urlOrPath;
|
|
6358
6527
|
}
|
|
6359
|
-
const specPath = Path
|
|
6528
|
+
const specPath = Path.resolve(dir, `spec.json`);
|
|
6360
6529
|
log(`Will download the API spec from ${urlOrPath} to ${specPath}`);
|
|
6361
6530
|
await downloadSpec(specPath, urlOrPath);
|
|
6362
6531
|
return specPath;
|