@povio/openapi-codegen-cli 2.0.8-rc.5 → 2.0.8-rc.7
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 +63 -0
- package/dist/acl.d.mts +48 -0
- package/dist/acl.mjs +62 -7
- package/dist/auth.context-DKjzWiaA.mjs +59 -0
- package/dist/config-Cu_GYfai.d.mts +6 -0
- package/dist/generate.runner-DNldmk0f.mjs +98 -0
- package/dist/generateCodeFromOpenAPIDoc-B5lnFNGB.mjs +4522 -0
- package/dist/generator.d.mts +65 -0
- package/dist/generator.mjs +144 -0
- package/dist/index.d.mts +246 -0
- package/dist/index.mjs +365 -22
- package/dist/options-DBz5YE3s.d.mts +90 -0
- package/dist/sh.d.mts +1 -0
- package/dist/sh.mjs +439 -0
- package/dist/vite.d.mts +8 -0
- package/dist/vite.mjs +50 -0
- package/package.json +50 -45
- package/src/assets/useMutationEffects.ts +6 -1
- package/src/generators/templates/endpoints.hbs +0 -1
- package/dist/acl.d.ts +0 -4
- package/dist/commands/check.command.d.ts +0 -2
- package/dist/commands/check.d.ts +0 -7
- package/dist/commands/generate.command.d.ts +0 -2
- package/dist/commands/generate.d.ts +0 -8
- package/dist/generator.d.ts +0 -3
- package/dist/generator.js +0 -78
- package/dist/generators/checkOpenAPIDoc.d.ts +0 -3
- package/dist/generators/const/acl.const.d.ts +0 -13
- package/dist/generators/const/buildConfigs.const.d.ts +0 -1
- package/dist/generators/const/deps.const.d.ts +0 -38
- package/dist/generators/const/endpoints.const.d.ts +0 -11
- package/dist/generators/const/js.const.d.ts +0 -1
- package/dist/generators/const/openapi.const.d.ts +0 -7
- package/dist/generators/const/options.const.d.ts +0 -2
- package/dist/generators/const/package.const.d.ts +0 -2
- package/dist/generators/const/queries.const.d.ts +0 -8
- package/dist/generators/const/validation.const.d.ts +0 -53
- package/dist/generators/const/zod.const.d.ts +0 -19
- package/dist/generators/core/SchemaResolver.class.d.ts +0 -71
- package/dist/generators/core/endpoints/getEndpointAcl.d.ts +0 -8
- package/dist/generators/core/endpoints/getEndpointBody.d.ts +0 -13
- package/dist/generators/core/endpoints/getEndpointParameter.d.ts +0 -11
- package/dist/generators/core/endpoints/getEndpointsFromOpenAPIDoc.d.ts +0 -3
- package/dist/generators/core/endpoints/getEndpointsFromOpenAPIDoc.test.d.ts +0 -1
- package/dist/generators/core/getDataFromOpenAPIDoc.d.ts +0 -8
- package/dist/generators/core/getMetadataFromOpenAPIDoc.d.ts +0 -4
- package/dist/generators/core/getMetadataFromOpenAPIDoc.test.d.ts +0 -1
- package/dist/generators/core/openapi/getOpenAPISchemaComplexity.d.ts +0 -2
- package/dist/generators/core/openapi/getOpenAPISchemaComplexity.test.d.ts +0 -1
- package/dist/generators/core/openapi/getOpenAPISchemaDependencyGraph.d.ts +0 -6
- package/dist/generators/core/openapi/getOpenAPISchemaDependencyGraph.test.d.ts +0 -1
- package/dist/generators/core/openapi/getSchemaRefObjs.d.ts +0 -4
- package/dist/generators/core/openapi/iterateSchema.d.ts +0 -22
- package/dist/generators/core/resolveConfig.d.ts +0 -7
- package/dist/generators/core/zod/ZodSchema.class.d.ts +0 -26
- package/dist/generators/core/zod/enumExtraction/resolveExtractedEnumZodSchemaNames.d.ts +0 -2
- package/dist/generators/core/zod/enumExtraction/resolveExtractedEnumZodSchemaTags.d.ts +0 -2
- package/dist/generators/core/zod/enumExtraction/updateExtractedEnumZodSchemaData.d.ts +0 -17
- package/dist/generators/core/zod/getZodChain.d.ts +0 -8
- package/dist/generators/core/zod/getZodSchema.d.ts +0 -17
- package/dist/generators/core/zod/getZodSchema.test.d.ts +0 -1
- package/dist/generators/core/zod/getZodSchemaRefs.d.ts +0 -6
- package/dist/generators/core/zod/getZodSchemasFromOpenAPIDoc.d.ts +0 -6
- package/dist/generators/core/zod/resolveZodSchemaName.d.ts +0 -10
- package/dist/generators/core/zod/sortZodSchemasByTopology.d.ts +0 -4
- package/dist/generators/generate/generateAcl.d.ts +0 -3
- package/dist/generators/generate/generateAclCheck.d.ts +0 -2
- package/dist/generators/generate/generateAppRestClient.d.ts +0 -2
- package/dist/generators/generate/generateConfigs.d.ts +0 -2
- package/dist/generators/generate/generateEndpoints.d.ts +0 -2
- package/dist/generators/generate/generateModels.d.ts +0 -2
- package/dist/generators/generate/generateQueries.d.ts +0 -2
- package/dist/generators/generate/generateQueryModules.d.ts +0 -2
- package/dist/generators/generate/generateZodExtended.d.ts +0 -2
- package/dist/generators/generateCodeFromOpenAPIDoc.d.ts +0 -4
- package/dist/generators/types/builder-config.d.ts +0 -48
- package/dist/generators/types/common.d.ts +0 -27
- package/dist/generators/types/config.d.ts +0 -2
- package/dist/generators/types/endpoint.d.ts +0 -50
- package/dist/generators/types/generate.d.ts +0 -39
- package/dist/generators/types/metadata.d.ts +0 -51
- package/dist/generators/types/openapi.d.ts +0 -22
- package/dist/generators/types/options.d.ts +0 -66
- package/dist/generators/types/validation.d.ts +0 -5
- package/dist/generators/utils/array.utils.d.ts +0 -1
- package/dist/generators/utils/endpoint.utils.d.ts +0 -12
- package/dist/generators/utils/endpoint.utils.test.d.ts +0 -1
- package/dist/generators/utils/file.utils.d.ts +0 -8
- package/dist/generators/utils/generate/generate.acl.utils.d.ts +0 -23
- package/dist/generators/utils/generate/generate.configs.utils.d.ts +0 -15
- package/dist/generators/utils/generate/generate.endpoints.utils.d.ts +0 -39
- package/dist/generators/utils/generate/generate.imports.utils.d.ts +0 -39
- package/dist/generators/utils/generate/generate.imports.utils.test.d.ts +0 -1
- package/dist/generators/utils/generate/generate.openapi.utils.d.ts +0 -2
- package/dist/generators/utils/generate/generate.query.utils.d.ts +0 -6
- package/dist/generators/utils/generate/generate.utils.d.ts +0 -18
- package/dist/generators/utils/generate/generate.zod.utils.d.ts +0 -13
- package/dist/generators/utils/generate-files.utils.d.ts +0 -6
- package/dist/generators/utils/hbs/hbs-template.utils.d.ts +0 -3
- package/dist/generators/utils/hbs/hbs.acl.utils.d.ts +0 -2
- package/dist/generators/utils/hbs/hbs.common.utils.d.ts +0 -1
- package/dist/generators/utils/hbs/hbs.endpoints.utils.d.ts +0 -2
- package/dist/generators/utils/hbs/hbs.imports.utils.d.ts +0 -1
- package/dist/generators/utils/hbs/hbs.partials.utils.d.ts +0 -2
- package/dist/generators/utils/hbs/hbs.query.utils.d.ts +0 -2
- package/dist/generators/utils/hbs/hbs.zod.utils.d.ts +0 -2
- package/dist/generators/utils/js.utils.d.ts +0 -2
- package/dist/generators/utils/js.utils.test.d.ts +0 -1
- package/dist/generators/utils/math.utils.d.ts +0 -1
- package/dist/generators/utils/namespace.utils.d.ts +0 -7
- package/dist/generators/utils/object.utils.d.ts +0 -13
- package/dist/generators/utils/object.utils.test.d.ts +0 -1
- package/dist/generators/utils/openapi-schema.utils.d.ts +0 -15
- package/dist/generators/utils/openapi.utils.d.ts +0 -23
- package/dist/generators/utils/openapi.utils.test.d.ts +0 -1
- package/dist/generators/utils/operation.utils.d.ts +0 -22
- package/dist/generators/utils/operation.utils.test.d.ts +0 -1
- package/dist/generators/utils/query.utils.d.ts +0 -7
- package/dist/generators/utils/sort.utils.d.ts +0 -7
- package/dist/generators/utils/string.utils.d.ts +0 -14
- package/dist/generators/utils/string.utils.test.d.ts +0 -1
- package/dist/generators/utils/tag.utils.d.ts +0 -7
- package/dist/generators/utils/ts.utils.d.ts +0 -16
- package/dist/generators/utils/validation.utils.d.ts +0 -17
- package/dist/generators/utils/zod-schema.utils.d.ts +0 -15
- package/dist/helpers/cli.helper.d.ts +0 -22
- package/dist/helpers/config.helper.d.ts +0 -3
- package/dist/helpers/version.helper.d.ts +0 -4
- package/dist/helpers/yargs.helper.d.ts +0 -10
- package/dist/index.d.ts +0 -15
- package/dist/lib/acl/AclGuard.d.ts +0 -8
- package/dist/lib/acl/AclGuard.mjs +0 -14
- package/dist/lib/acl/Can.d.ts +0 -9
- package/dist/lib/acl/Can.mjs +0 -11
- package/dist/lib/acl/ability.context.d.ts +0 -15
- package/dist/lib/acl/ability.context.mjs +0 -37
- package/dist/lib/acl/appAbility.types.d.ts +0 -3
- package/dist/lib/assets/locales/en/translation.json.mjs +0 -8
- package/dist/lib/assets/locales/sl/translation.json.mjs +0 -8
- package/dist/lib/auth/AuthGuard.d.ts +0 -6
- package/dist/lib/auth/AuthGuard.mjs +0 -26
- package/dist/lib/auth/auth.context.d.ts +0 -22
- package/dist/lib/auth/auth.context.mjs +0 -41
- package/dist/lib/config/i18n.d.ts +0 -32
- package/dist/lib/config/i18n.mjs +0 -31
- package/dist/lib/config/queryConfig.context.d.ts +0 -17
- package/dist/lib/config/queryConfig.context.mjs +0 -26
- package/dist/lib/config/router.context.d.ts +0 -9
- package/dist/lib/config/router.context.mjs +0 -20
- package/dist/lib/react-query.types.d.ts +0 -10
- package/dist/lib/rest/error-handling.d.ts +0 -30
- package/dist/lib/rest/error-handling.mjs +0 -132
- package/dist/lib/rest/rest-client.d.ts +0 -22
- package/dist/lib/rest/rest-client.mjs +0 -62
- package/dist/lib/rest/rest-client.types.d.ts +0 -23
- package/dist/lib/rest/rest-interceptor.d.ts +0 -8
- package/dist/lib/rest/rest-interceptor.mjs +0 -21
- package/dist/lib/rest/rest.utils.d.ts +0 -7
- package/dist/lib/rest/rest.utils.mjs +0 -51
- package/dist/sh.d.ts +0 -2
- package/dist/sh.js +0 -635
|
@@ -0,0 +1,4522 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { match } from "ts-pattern";
|
|
3
|
+
import { OpenAPIV3 } from "openapi-types";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
|
|
7
|
+
//#region src/generators/const/validation.const.ts
|
|
8
|
+
const HTTP_STATUS_CODES = {
|
|
9
|
+
"100": "Continue",
|
|
10
|
+
"101": "Switching Protocols",
|
|
11
|
+
"102": "Processing",
|
|
12
|
+
"103": "Early Hints",
|
|
13
|
+
"200": "OK",
|
|
14
|
+
"201": "Created",
|
|
15
|
+
"202": "Accepted",
|
|
16
|
+
"203": "Non-Authoritative Information",
|
|
17
|
+
"204": "No Content",
|
|
18
|
+
"205": "Reset Content",
|
|
19
|
+
"206": "Partial Content",
|
|
20
|
+
"300": "Ambiguous",
|
|
21
|
+
"301": "Moved Permanently",
|
|
22
|
+
"302": "Found",
|
|
23
|
+
"303": "See Other",
|
|
24
|
+
"304": "Not Modified",
|
|
25
|
+
"307": "Temporary Redirect",
|
|
26
|
+
"308": "Permanent Redirect",
|
|
27
|
+
"400": "Bad Request",
|
|
28
|
+
"401": "Unauthorized",
|
|
29
|
+
"402": "Payment Required",
|
|
30
|
+
"403": "Forbidden",
|
|
31
|
+
"404": "Not Found",
|
|
32
|
+
"405": "Method Not Allowed",
|
|
33
|
+
"406": "Not Acceptable",
|
|
34
|
+
"407": "Proxy Authentication Required",
|
|
35
|
+
"408": "Request Timeout",
|
|
36
|
+
"409": "Conflict",
|
|
37
|
+
"410": "Gone",
|
|
38
|
+
"411": "Length Required",
|
|
39
|
+
"412": "Precondition Failed",
|
|
40
|
+
"413": "Payload Too Large",
|
|
41
|
+
"414": "URI Too Long",
|
|
42
|
+
"415": "Unsupported Media Type",
|
|
43
|
+
"416": "Requested Range Not Satisfiable",
|
|
44
|
+
"417": "Expectation Failed",
|
|
45
|
+
"418": "I Am a Teapot",
|
|
46
|
+
"421": "Misdirected Request",
|
|
47
|
+
"422": "Unprocessable Entity",
|
|
48
|
+
"424": "Failed Dependency",
|
|
49
|
+
"428": "Precondition Required",
|
|
50
|
+
"429": "Too Many Requests",
|
|
51
|
+
"500": "Internal Server Error",
|
|
52
|
+
"501": "Not Implemented",
|
|
53
|
+
"502": "Bad Gateway",
|
|
54
|
+
"503": "Service Unavailable",
|
|
55
|
+
"504": "Gateway Timeout",
|
|
56
|
+
"505": "HTTP Version Not Supported"
|
|
57
|
+
};
|
|
58
|
+
const VALIDATION_ERROR_TYPE_TITLE = {
|
|
59
|
+
"invalid-schema": "Invalid OpenAPI Schemas",
|
|
60
|
+
"invalid-operation-id": "Invalid Operation IDs",
|
|
61
|
+
"missing-path-parameter": "Missing Path Parameters",
|
|
62
|
+
"not-allowed-inline-enum": "Not Allowed Inline Enums",
|
|
63
|
+
"not-allowed-circular-schema": "Not Allowed Circular Schemas",
|
|
64
|
+
"missing-acl-condition-property": "Missing x-acl Condition Properties",
|
|
65
|
+
"missing-status-code": "Missing HTTP Status Codes",
|
|
66
|
+
"invalid-status-code": "Invalid HTTP Status Codes",
|
|
67
|
+
"multiple-success-status-codes": "Multiple Success HTTP Status Codes"
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/helpers/profile.helper.ts
|
|
72
|
+
function nowMs() {
|
|
73
|
+
return Number(process.hrtime.bigint()) / 1e6;
|
|
74
|
+
}
|
|
75
|
+
var Profiler = class {
|
|
76
|
+
entries = /* @__PURE__ */ new Map();
|
|
77
|
+
constructor(enabled) {
|
|
78
|
+
this.enabled = enabled;
|
|
79
|
+
}
|
|
80
|
+
add(label, elapsedMs) {
|
|
81
|
+
if (!this.enabled) return;
|
|
82
|
+
const prev = this.entries.get(label);
|
|
83
|
+
if (prev) {
|
|
84
|
+
prev.totalMs += elapsedMs;
|
|
85
|
+
prev.count += 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.entries.set(label, {
|
|
89
|
+
totalMs: elapsedMs,
|
|
90
|
+
count: 1
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
runSync(label, fn) {
|
|
94
|
+
if (!this.enabled) return fn();
|
|
95
|
+
const startMs = nowMs();
|
|
96
|
+
try {
|
|
97
|
+
return fn();
|
|
98
|
+
} finally {
|
|
99
|
+
this.add(label, nowMs() - startMs);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async runAsync(label, fn) {
|
|
103
|
+
if (!this.enabled) return await fn();
|
|
104
|
+
const startMs = nowMs();
|
|
105
|
+
try {
|
|
106
|
+
return await fn();
|
|
107
|
+
} finally {
|
|
108
|
+
this.add(label, nowMs() - startMs);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
formatLines() {
|
|
112
|
+
if (!this.enabled) return [];
|
|
113
|
+
return Array.from(this.entries.entries()).sort((a, b) => b[1].totalMs - a[1].totalMs).map(([label, entry]) => {
|
|
114
|
+
const avgMs = entry.totalMs / entry.count;
|
|
115
|
+
return `${label}: ${entry.totalMs.toFixed(1)}ms (count: ${entry.count}, avg: ${avgMs.toFixed(2)}ms)`;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/generators/utils/string.utils.ts
|
|
122
|
+
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
123
|
+
const decapitalize = (str) => str.charAt(0).toLowerCase() + str.slice(1);
|
|
124
|
+
const kebabToCamel = (str) => str.replace(/(-\w)/g, (group) => group[1].toUpperCase());
|
|
125
|
+
const snakeToCamel = (str) => str.replace(/(_\w)/g, (group) => group[1].toUpperCase());
|
|
126
|
+
const nonWordCharactersToCamel = (str) => str.replace(/[\W_]+(\w)?/g, (_, char) => char?.toUpperCase() ?? "");
|
|
127
|
+
const suffixIfNeeded = (text, suffix = "") => text.endsWith(suffix) ? text : `${text}${suffix}`;
|
|
128
|
+
const removeSuffix = (text, suffix) => text.replace(new RegExp(`${suffix}$`), "");
|
|
129
|
+
const getLongestMostCommon = (strs) => {
|
|
130
|
+
const counter = strs.reduce((acc, str) => ({
|
|
131
|
+
...acc,
|
|
132
|
+
[str]: (acc[str] ?? 0) + 1
|
|
133
|
+
}), {});
|
|
134
|
+
return Object.entries(counter).toSorted((a, b) => {
|
|
135
|
+
if (a[1] === b[1]) return b[0].length - a[0].length;
|
|
136
|
+
return b[1] - a[1];
|
|
137
|
+
})[0]?.[0];
|
|
138
|
+
};
|
|
139
|
+
const getMostCommonAdjacentCombinationSplit = (strs) => {
|
|
140
|
+
return getLongestMostCommon(strs.flatMap((str) => getAdjacentStringCombinations(splitByUppercase(capitalize(str)))));
|
|
141
|
+
};
|
|
142
|
+
const splitByUppercase = (str) => {
|
|
143
|
+
return str.split(/(?<![A-Z])(?=[A-Z])/).filter(Boolean);
|
|
144
|
+
};
|
|
145
|
+
const camelToSpaceSeparated = (text) => splitByUppercase(text).join(" ");
|
|
146
|
+
const getAdjacentStringCombinations = (strs, ignoreStrs = [
|
|
147
|
+
"dto",
|
|
148
|
+
"by",
|
|
149
|
+
"for",
|
|
150
|
+
"of",
|
|
151
|
+
"in",
|
|
152
|
+
"to",
|
|
153
|
+
"and",
|
|
154
|
+
"with"
|
|
155
|
+
]) => {
|
|
156
|
+
const combinations = [];
|
|
157
|
+
for (let i = 0; i < strs.length; i++) {
|
|
158
|
+
if (ignoreStrs.includes(strs[i].toLowerCase())) continue;
|
|
159
|
+
for (let j = i + 1; j <= strs.length; j++) {
|
|
160
|
+
if (ignoreStrs.includes(strs[j - 1]?.toLowerCase())) continue;
|
|
161
|
+
combinations.push(strs.slice(i, j).join(""));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return combinations;
|
|
165
|
+
};
|
|
166
|
+
const removeWord = (source, wordToRemove) => {
|
|
167
|
+
const singularWordToRemove = wordToRemove.replace(/es$|s$/g, "");
|
|
168
|
+
const pattern = new RegExp(`(${decapitalize(singularWordToRemove)}|${capitalize(singularWordToRemove)})[a-z]*(?=$|[A-Z])`, "g");
|
|
169
|
+
return source.replace(pattern, "");
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
//#endregion
|
|
173
|
+
//#region src/generators/utils/tag.utils.ts
|
|
174
|
+
function formatTag(tag) {
|
|
175
|
+
return nonWordCharactersToCamel(tag);
|
|
176
|
+
}
|
|
177
|
+
function getOperationTag(operation, options) {
|
|
178
|
+
const tag = operation.tags?.[0];
|
|
179
|
+
return formatTag(tag ?? options.defaultTag);
|
|
180
|
+
}
|
|
181
|
+
function getEndpointTag(endpoint, options) {
|
|
182
|
+
return formatTag((options.splitByTags ? endpoint.tags?.[0] : options.defaultTag) ?? options.defaultTag);
|
|
183
|
+
}
|
|
184
|
+
function isTagExcluded(tag, options) {
|
|
185
|
+
return options.excludeTags.some((excludeTag) => excludeTag.toLowerCase() === tag.toLowerCase());
|
|
186
|
+
}
|
|
187
|
+
function shouldInlineEndpointsForTag(tag, options) {
|
|
188
|
+
if (!options.inlineEndpoints) return false;
|
|
189
|
+
return !(options.inlineEndpointsExcludeModules ?? []).some((moduleName) => formatTag(moduleName).toLowerCase() === tag.toLowerCase());
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/generators/const/endpoints.const.ts
|
|
194
|
+
const JSON_APPLICATION_FORMAT = "application/json";
|
|
195
|
+
const DEFAULT_HEADERS = {
|
|
196
|
+
"Content-Type": JSON_APPLICATION_FORMAT,
|
|
197
|
+
Accept: JSON_APPLICATION_FORMAT
|
|
198
|
+
};
|
|
199
|
+
const BODY_PARAMETER_NAME = "data";
|
|
200
|
+
const AXIOS_DEFAULT_IMPORT_NAME = "axios";
|
|
201
|
+
const AXIOS_REQUEST_CONFIG_NAME = "config";
|
|
202
|
+
const AXIOS_REQUEST_CONFIG_TYPE = "AxiosRequestConfig";
|
|
203
|
+
const AXIOS_IMPORT = {
|
|
204
|
+
defaultImport: AXIOS_DEFAULT_IMPORT_NAME,
|
|
205
|
+
bindings: [AXIOS_REQUEST_CONFIG_TYPE],
|
|
206
|
+
from: "axios"
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
//#endregion
|
|
210
|
+
//#region src/generators/const/zod.const.ts
|
|
211
|
+
const SCHEMA_SUFFIX = "Schema";
|
|
212
|
+
const ENUM_SUFFIX = "Enum";
|
|
213
|
+
const BODY_SCHEMA_SUFFIX = "Body";
|
|
214
|
+
const PARAM_SCHEMA_SUFFIX = "Param";
|
|
215
|
+
const RESPONSE_SCHEMA_SUFFIX = "Response";
|
|
216
|
+
const ERROR_RESPONSE_SCHEMA_SUFFIX = "ErrorResponse";
|
|
217
|
+
const VOID_SCHEMA = "z.void()";
|
|
218
|
+
const ANY_SCHEMA = "z.any()";
|
|
219
|
+
const BLOB_SCHEMA = "z.instanceof(Blob)";
|
|
220
|
+
const ENUM_SCHEMA = "z.enum";
|
|
221
|
+
const INT_SCHEMA = "z.int()";
|
|
222
|
+
const NUMBER_SCHEMA = "z.number()";
|
|
223
|
+
const STRING_SCHEMA = "z.string()";
|
|
224
|
+
const EMAIL_SCHEMA = "z.email()";
|
|
225
|
+
const URL_SCHEMA = "z.url()";
|
|
226
|
+
const UUID_SCHEMA = "z.uuid()";
|
|
227
|
+
const DATETIME_SCHEMA = "z.iso.datetime({ offset: true })";
|
|
228
|
+
const ZOD_IMPORT = {
|
|
229
|
+
bindings: ["z"],
|
|
230
|
+
from: "zod"
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region src/generators/utils/js.utils.ts
|
|
235
|
+
const isValidPropertyName = (str) => /^(?:[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+)$/.test(str);
|
|
236
|
+
const invalidVariableNameCharactersToCamel = (str) => str.replace(/^[^a-zA-Z_$]*/g, "").replace(/[^a-zA-Z0-9_$]+(\w)?/g, (_, char) => char?.toUpperCase() ?? "");
|
|
237
|
+
|
|
238
|
+
//#endregion
|
|
239
|
+
//#region src/generators/utils/openapi-schema.utils.ts
|
|
240
|
+
function isReferenceObject(obj) {
|
|
241
|
+
return obj != null && Object.prototype.hasOwnProperty.call(obj, "$ref");
|
|
242
|
+
}
|
|
243
|
+
function isSchemaObject(schema) {
|
|
244
|
+
return !isReferenceObject(schema);
|
|
245
|
+
}
|
|
246
|
+
function isArraySchemaObject(schema) {
|
|
247
|
+
return schema.type === "array";
|
|
248
|
+
}
|
|
249
|
+
function inferRequiredSchema(schema) {
|
|
250
|
+
if (!schema.allOf) throw new Error("Function inferRequiredSchema is specialized to handle item with required only in an allOf array.");
|
|
251
|
+
const [standaloneRequisites, noRequiredOnlyAllof] = schema.allOf.reduce((acc, cur) => {
|
|
252
|
+
if (isBrokenAllOfItem(cur)) {
|
|
253
|
+
const required = cur.required;
|
|
254
|
+
acc[0].push(...required ?? []);
|
|
255
|
+
} else acc[1].push(cur);
|
|
256
|
+
return acc;
|
|
257
|
+
}, [[], []]);
|
|
258
|
+
const composedRequiredSchema = {
|
|
259
|
+
properties: standaloneRequisites.reduce((acc, cur) => {
|
|
260
|
+
acc[cur] = {};
|
|
261
|
+
return acc;
|
|
262
|
+
}, {}),
|
|
263
|
+
type: "object",
|
|
264
|
+
required: standaloneRequisites
|
|
265
|
+
};
|
|
266
|
+
return {
|
|
267
|
+
noRequiredOnlyAllof,
|
|
268
|
+
composedRequiredSchema,
|
|
269
|
+
patchRequiredSchemaInLoop: (prop, getSchemaByRef) => {
|
|
270
|
+
if (isReferenceObject(prop)) {
|
|
271
|
+
const refType = getSchemaByRef(prop.$ref);
|
|
272
|
+
if (refType) composedRequiredSchema.required.forEach((required) => {
|
|
273
|
+
composedRequiredSchema.properties[required] = refType?.properties?.[required] ?? {};
|
|
274
|
+
});
|
|
275
|
+
} else {
|
|
276
|
+
const properties = prop["properties"] ?? {};
|
|
277
|
+
composedRequiredSchema.required.forEach((required) => {
|
|
278
|
+
if (properties[required]) composedRequiredSchema.properties[required] = properties[required] ?? {};
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
const isBrokenAllOfItem = (item) => {
|
|
285
|
+
return !isReferenceObject(item) && !!item.required && !item.type && !item.properties && !item?.allOf && !item?.anyOf && !item.oneOf;
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
//#endregion
|
|
289
|
+
//#region src/generators/const/openapi.const.ts
|
|
290
|
+
const COMPLEXITY_THRESHOLD = 2;
|
|
291
|
+
const ALLOWED_PARAM_MEDIA_TYPES = [
|
|
292
|
+
"application/octet-stream",
|
|
293
|
+
"multipart/form-data",
|
|
294
|
+
"application/x-www-form-urlencoded",
|
|
295
|
+
"*/*"
|
|
296
|
+
];
|
|
297
|
+
const ALLOWED_PATH_IN = [
|
|
298
|
+
"query",
|
|
299
|
+
"header",
|
|
300
|
+
"path"
|
|
301
|
+
];
|
|
302
|
+
const ALLOWED_METHODS = [
|
|
303
|
+
OpenAPIV3.HttpMethods.GET,
|
|
304
|
+
OpenAPIV3.HttpMethods.PUT,
|
|
305
|
+
OpenAPIV3.HttpMethods.POST,
|
|
306
|
+
OpenAPIV3.HttpMethods.DELETE,
|
|
307
|
+
OpenAPIV3.HttpMethods.OPTIONS,
|
|
308
|
+
OpenAPIV3.HttpMethods.HEAD,
|
|
309
|
+
OpenAPIV3.HttpMethods.PATCH,
|
|
310
|
+
OpenAPIV3.HttpMethods.TRACE
|
|
311
|
+
];
|
|
312
|
+
const PRIMITIVE_TYPE_LIST = [
|
|
313
|
+
"string",
|
|
314
|
+
"number",
|
|
315
|
+
"integer",
|
|
316
|
+
"boolean"
|
|
317
|
+
];
|
|
318
|
+
const COMPOSITE_KEYWORDS = [
|
|
319
|
+
"allOf",
|
|
320
|
+
"anyOf",
|
|
321
|
+
"oneOf"
|
|
322
|
+
];
|
|
323
|
+
|
|
324
|
+
//#endregion
|
|
325
|
+
//#region src/generators/utils/openapi.utils.ts
|
|
326
|
+
const getSchemaRef = (schemaName) => `#/components/schemas/${schemaName}`;
|
|
327
|
+
const autocorrectRef = (ref) => ref[1] === "/" ? ref : "#/" + ref.slice(1);
|
|
328
|
+
const getSchemaNameByRef = (ref) => autocorrectRef(ref).split("/").at(-1);
|
|
329
|
+
function normalizeString(text) {
|
|
330
|
+
return snakeToCamel(prefixStringStartingWithNumberIfNeeded(text).normalize("NFKD").trim().replace(/\s+/g, "_").replace(/--+/g, "-").replace(/-+/g, "_").replace(/[^\w-]+/g, "_"));
|
|
331
|
+
}
|
|
332
|
+
function wrapWithQuotesIfNeeded(str) {
|
|
333
|
+
if (/^[a-zA-Z]\w*$/.test(str)) return str;
|
|
334
|
+
return `"${str}"`;
|
|
335
|
+
}
|
|
336
|
+
function unwrapQuotesIfNeeded(value) {
|
|
337
|
+
if (typeof value === "string" && value.startsWith("\"") && value.endsWith("\"")) return value.slice(1, -1);
|
|
338
|
+
return value;
|
|
339
|
+
}
|
|
340
|
+
function prefixStringStartingWithNumberIfNeeded(str) {
|
|
341
|
+
const firstAsNumber = Number(str[0]);
|
|
342
|
+
if (typeof firstAsNumber === "number" && !Number.isNaN(firstAsNumber)) return "_" + str;
|
|
343
|
+
return str;
|
|
344
|
+
}
|
|
345
|
+
function pathParamToVariableName(name) {
|
|
346
|
+
return snakeToCamel(name.replaceAll("_", "#").replaceAll("-", "_")).replaceAll("#", "_");
|
|
347
|
+
}
|
|
348
|
+
const isPrimitiveType = (type) => PRIMITIVE_TYPE_LIST.includes(type);
|
|
349
|
+
function escapeControlCharacters(str) {
|
|
350
|
+
return str.replace(/\t/g, "\\t").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/([\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F\uFFFE\uFFFF])/g, (_m, p1) => {
|
|
351
|
+
const dec = p1.codePointAt();
|
|
352
|
+
const hex = dec.toString(16);
|
|
353
|
+
if (dec <= 255) return `\\x${`00${hex}`.slice(-2)}`;
|
|
354
|
+
return `\\u${`0000${hex}`.slice(-4)}`;
|
|
355
|
+
}).replace(/\//g, "\\/");
|
|
356
|
+
}
|
|
357
|
+
function isParamMediaTypeAllowed(mediaType) {
|
|
358
|
+
return mediaType.includes("application/") && mediaType.includes("json") || ALLOWED_PARAM_MEDIA_TYPES.includes(mediaType) || mediaType.includes("text/");
|
|
359
|
+
}
|
|
360
|
+
function isMainResponseStatus(status) {
|
|
361
|
+
return status >= 200 && status < 300;
|
|
362
|
+
}
|
|
363
|
+
function isErrorStatus(status) {
|
|
364
|
+
return !(status >= 200 && status < 300);
|
|
365
|
+
}
|
|
366
|
+
function isMediaTypeAllowed(mediaType) {
|
|
367
|
+
return mediaType.startsWith("application/");
|
|
368
|
+
}
|
|
369
|
+
const PATH_PARAM_WITH_BRACKETS_REGEX = /({\w+})/g;
|
|
370
|
+
const WORD_PRECEDED_BY_NON_WORD_CHARACTER = /[^\w\-]+/g;
|
|
371
|
+
/** @example turns `/media-objects/{id}` into `MediaObjectsById` */
|
|
372
|
+
function pathToVariableName(path) {
|
|
373
|
+
path = capitalize(kebabToCamel(path.replaceAll("/", "-")).replaceAll("-", ""));
|
|
374
|
+
const pathParams = [...path.matchAll(PATH_PARAM_WITH_BRACKETS_REGEX)];
|
|
375
|
+
if (pathParams.length > 0) {
|
|
376
|
+
const lastPathParam = pathParams.toSorted((a, b) => a.index - b.index)[pathParams.length - 1][0];
|
|
377
|
+
path = `${path.replace(PATH_PARAM_WITH_BRACKETS_REGEX, "")}By${capitalize(lastPathParam.slice(1, -1))}`;
|
|
378
|
+
}
|
|
379
|
+
return path.replace(WORD_PRECEDED_BY_NON_WORD_CHARACTER, "_");
|
|
380
|
+
}
|
|
381
|
+
const MATCHER_REGEX = /{(\b\w+(?:-\w+)*\b)}/g;
|
|
382
|
+
function replaceHyphenatedPath(path) {
|
|
383
|
+
const matches = path.match(MATCHER_REGEX);
|
|
384
|
+
if (matches === null) return path.replaceAll(MATCHER_REGEX, ":$1");
|
|
385
|
+
matches.forEach((match) => {
|
|
386
|
+
const replacement = pathParamToVariableName(match.replaceAll(MATCHER_REGEX, ":$1"));
|
|
387
|
+
path = path.replaceAll(match, replacement);
|
|
388
|
+
});
|
|
389
|
+
return path;
|
|
390
|
+
}
|
|
391
|
+
const isSortingParameterObject = (param) => {
|
|
392
|
+
const enumNames = param["x-enumNames"];
|
|
393
|
+
const hasEnumNames = Array.isArray(enumNames) && enumNames.length > 0;
|
|
394
|
+
const isStringSchema = !!param.schema && isSchemaObject(param.schema) && param.schema.type === "string";
|
|
395
|
+
return hasEnumNames && isStringSchema;
|
|
396
|
+
};
|
|
397
|
+
const isPathExcluded = (path, options) => {
|
|
398
|
+
if (!options.excludePathRegex) return false;
|
|
399
|
+
return new RegExp(options.excludePathRegex).test(path);
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
//#endregion
|
|
403
|
+
//#region src/generators/utils/validation.utils.ts
|
|
404
|
+
function getInvalidSchemaError(message) {
|
|
405
|
+
return {
|
|
406
|
+
type: "invalid-schema",
|
|
407
|
+
message
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
function getInvalidOperationIdError(operationId) {
|
|
411
|
+
return {
|
|
412
|
+
type: "invalid-operation-id",
|
|
413
|
+
message: `Operation ${operationId}`
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function getMissingPathParameterError(params, path) {
|
|
417
|
+
return {
|
|
418
|
+
type: "missing-path-parameter",
|
|
419
|
+
message: `Path ${path} is missing [${params.map(({ name }) => name).join(", ")}]`
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
function getNotAllowedInlineEnumError(enumProperty) {
|
|
423
|
+
return {
|
|
424
|
+
type: "not-allowed-inline-enum",
|
|
425
|
+
message: `${enumProperty} is missing @IsEnum() and @ApiProperty(enum:, enumName:)`
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
function getMissingAclConditionPropertyError(propertyName, operation, endpoint) {
|
|
429
|
+
return {
|
|
430
|
+
type: "missing-acl-condition-property",
|
|
431
|
+
message: `Condition property ${propertyName} is not found in parameters or body in operation ${getOperationDescriptor(operation, endpoint)}`
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
function getMissingStatusCodeError(statusCode, operation, endpoint) {
|
|
435
|
+
return {
|
|
436
|
+
type: "missing-status-code",
|
|
437
|
+
message: `Missing HTTP status code ${getStatusCodeDescription(statusCode)} in operation ${getOperationDescriptor(operation, endpoint)}`
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
function getInvalidStatusCodeError(statusCode, operation, endpoint) {
|
|
441
|
+
return {
|
|
442
|
+
type: "invalid-status-code",
|
|
443
|
+
message: `Operation ${getOperationDescriptor(operation, endpoint)} expected HTTP status code ${getStatusCodeDescription(statusCode.expected)} but received ${getStatusCodeDescription(statusCode.received)}`
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
function getMultipleSuccessStatusCodesError(statusCodes, operation, endpoint) {
|
|
447
|
+
return {
|
|
448
|
+
type: "multiple-success-status-codes",
|
|
449
|
+
message: `Operation ${getOperationDescriptor(operation, endpoint)} has multiple success HTTP status codes: ${statusCodes.map(getStatusCodeDescription).join(", ")}`
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
function getOperationDescriptor(operation, endpoint) {
|
|
453
|
+
return operation.operationId ?? `${endpoint.method} ${endpoint.path}`;
|
|
454
|
+
}
|
|
455
|
+
function getStatusCodeDescription(statusCode) {
|
|
456
|
+
return `${statusCode} (${HTTP_STATUS_CODES[statusCode]})`;
|
|
457
|
+
}
|
|
458
|
+
function groupByType(validationErrors) {
|
|
459
|
+
return validationErrors.reduce((acc, err) => ({
|
|
460
|
+
...acc,
|
|
461
|
+
[err.type]: [...acc[err.type] ?? [], err.message]
|
|
462
|
+
}), {});
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
//#endregion
|
|
466
|
+
//#region src/generators/const/package.const.ts
|
|
467
|
+
const PACKAGE_IMPORT_PATH = "@povio/openapi-codegen-cli";
|
|
468
|
+
const ACL_PACKAGE_IMPORT_PATH = "@povio/openapi-codegen-cli/acl";
|
|
469
|
+
|
|
470
|
+
//#endregion
|
|
471
|
+
//#region src/generators/const/deps.const.ts
|
|
472
|
+
const APP_REST_CLIENT_NAME = "AppRestClient";
|
|
473
|
+
const APP_REST_CLIENT_FILE = {
|
|
474
|
+
fileName: "app-rest-client",
|
|
475
|
+
extension: "ts"
|
|
476
|
+
};
|
|
477
|
+
const QUERY_OPTIONS_TYPES = {
|
|
478
|
+
query: "AppQueryOptions",
|
|
479
|
+
infiniteQuery: "AppInfiniteQueryOptions",
|
|
480
|
+
mutation: "AppMutationOptions"
|
|
481
|
+
};
|
|
482
|
+
const TEMPLATE_DATA_FILE_PATH = "src/data";
|
|
483
|
+
const ERROR_HANDLERS = {
|
|
484
|
+
ErrorHandler: "ErrorHandler",
|
|
485
|
+
SharedErrorHandler: "SharedErrorHandler"
|
|
486
|
+
};
|
|
487
|
+
const ERROR_HANDLING_IMPORT = {
|
|
488
|
+
bindings: [ERROR_HANDLERS.ErrorHandler, ERROR_HANDLERS.SharedErrorHandler],
|
|
489
|
+
from: PACKAGE_IMPORT_PATH
|
|
490
|
+
};
|
|
491
|
+
const ABILITY_CONTEXT = "AbilityContext";
|
|
492
|
+
const ABILITY_CONTEXT_IMPORT = {
|
|
493
|
+
bindings: [ABILITY_CONTEXT],
|
|
494
|
+
from: ACL_PACKAGE_IMPORT_PATH
|
|
495
|
+
};
|
|
496
|
+
const BUILDERS_UTILS = {
|
|
497
|
+
dynamicInputs: "dynamicInputs",
|
|
498
|
+
dynamicColumns: "dynamicColumns"
|
|
499
|
+
};
|
|
500
|
+
const QUERY_MODULE_ENUM = "QueryModule";
|
|
501
|
+
const QUERY_MODULES_FILE = {
|
|
502
|
+
fileName: "queryModules",
|
|
503
|
+
extension: "ts"
|
|
504
|
+
};
|
|
505
|
+
const MUTATION_EFFECTS = {
|
|
506
|
+
optionsType: "MutationEffectsOptions",
|
|
507
|
+
hookName: "useMutationEffects",
|
|
508
|
+
runFunctionName: "runMutationEffects"
|
|
509
|
+
};
|
|
510
|
+
const MUTATION_EFFECTS_FILE = {
|
|
511
|
+
fileName: "useMutationEffects",
|
|
512
|
+
extension: "ts"
|
|
513
|
+
};
|
|
514
|
+
const CROSS_TAB_QUERY_INVALIDATION_FILE = {
|
|
515
|
+
fileName: "useCrossTabQueryInvalidation",
|
|
516
|
+
extension: "ts"
|
|
517
|
+
};
|
|
518
|
+
const ZOD_EXTENDED = {
|
|
519
|
+
namespace: "ZodExtended",
|
|
520
|
+
exports: {
|
|
521
|
+
parse: "parse",
|
|
522
|
+
sortExp: "sortExp"
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
const ZOD_EXTENDED_FILE = {
|
|
526
|
+
fileName: "zod.extended",
|
|
527
|
+
extension: "ts"
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
//#endregion
|
|
531
|
+
//#region src/generators/utils/zod-schema.utils.ts
|
|
532
|
+
const getZodSchemaName = (name, schemaSuffix) => suffixIfNeeded(capitalize(normalizeString(name)), schemaSuffix);
|
|
533
|
+
const getEnumZodSchemaName = (name, enumSuffix, schemaSuffix) => suffixIfNeeded(capitalize(normalizeString(name)), `${enumSuffix}${schemaSuffix}`);
|
|
534
|
+
const isNamedZodSchema = (schema) => ["z.", `${ZOD_EXTENDED.namespace}.`].every((searchString) => !schema.startsWith(searchString));
|
|
535
|
+
const isEnumZodSchema = (schema) => schema.startsWith(ENUM_SCHEMA);
|
|
536
|
+
const getZodSchemaOperationName = (operationName, isUniqueOperationName, tag) => isUniqueOperationName ? operationName : `${tag}_${operationName}`;
|
|
537
|
+
const getBodyZodSchemaName = (operationName) => snakeToCamel(`${operationName}_${BODY_SCHEMA_SUFFIX}`);
|
|
538
|
+
const getParamZodSchemaName = (operationName, paramName) => snakeToCamel(`${operationName}_${paramName}${PARAM_SCHEMA_SUFFIX}`);
|
|
539
|
+
const getMainResponseZodSchemaName = (operationName) => snakeToCamel(`${operationName}${RESPONSE_SCHEMA_SUFFIX}`);
|
|
540
|
+
const getErrorResponseZodSchemaName = (operationName, statusCode) => snakeToCamel(`${operationName}_${statusCode}_${ERROR_RESPONSE_SCHEMA_SUFFIX}`);
|
|
541
|
+
function getResponseZodSchemaName({ statusCode, operationName, isUniqueOperationName, tag }) {
|
|
542
|
+
const status = Number(statusCode);
|
|
543
|
+
const zodSchemaOperationName = getZodSchemaOperationName(operationName, isUniqueOperationName, tag);
|
|
544
|
+
if (!isMainResponseStatus(status) && statusCode !== "default" && isErrorStatus(status)) return getErrorResponseZodSchemaName(zodSchemaOperationName, statusCode);
|
|
545
|
+
return getMainResponseZodSchemaName(zodSchemaOperationName);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
//#endregion
|
|
549
|
+
//#region src/generators/utils/endpoint.utils.ts
|
|
550
|
+
const isGetEndpoint = (endpoint) => endpoint.method === OpenAPIV3.HttpMethods.GET;
|
|
551
|
+
const isPaginatedGetEndpoint = (endpoint, options) => isGetEndpoint(endpoint) && Object.values(options.infiniteQueryParamNames).every((infiniteQueryParam) => endpoint.parameters.some((param) => param.name === infiniteQueryParam && param.type === "Query"));
|
|
552
|
+
const isReadAllEndpoint = (endpoint, options) => endpoint.method === OpenAPIV3.HttpMethods.GET && !isPathSegmentParam(endpoint.pathSegments.at(-1)) && isPaginatedGetEndpoint(endpoint, options);
|
|
553
|
+
const isReadEndpoint = (endpoint, readAllEndpoint) => endpoint.method === OpenAPIV3.HttpMethods.GET && hasMatchingPathWithTrailingParam(endpoint, readAllEndpoint);
|
|
554
|
+
const isCreateEndpoint = (endpoint, readAllEndpoint) => endpoint.method === OpenAPIV3.HttpMethods.POST && hasMatchingPathWithoutTrailingParam(endpoint, readAllEndpoint);
|
|
555
|
+
const isUpdateEndpoint = (endpoint, readAllEndpoint) => [OpenAPIV3.HttpMethods.PUT, OpenAPIV3.HttpMethods.PATCH].includes(endpoint.method) && hasMatchingPathWithTrailingParam(endpoint, readAllEndpoint);
|
|
556
|
+
const isDeleteEndpoint = (endpoint, readAllEndpoint) => endpoint.method === OpenAPIV3.HttpMethods.DELETE && hasMatchingPathWithTrailingParam(endpoint, readAllEndpoint);
|
|
557
|
+
const isBulkDeleteEndpoint = (endpoint, readAllEndpoint) => endpoint.method === OpenAPIV3.HttpMethods.DELETE && hasMatchingPathWithoutTrailingParam(endpoint, readAllEndpoint);
|
|
558
|
+
const getPathSegments = (path) => path.split("/").filter(Boolean);
|
|
559
|
+
const isPathSegmentParam = (pathSegment) => pathSegment?.startsWith(":");
|
|
560
|
+
const hasMatchingPath = (endpoint, readAllEndpoint) => readAllEndpoint.pathSegments.every((segment, index) => isPathSegmentParam(segment) && isPathSegmentParam(endpoint.pathSegments[index]) || segment === endpoint.pathSegments[index]);
|
|
561
|
+
const hasMatchingPathWithoutTrailingParam = (endpoint, readAllEndpoint) => endpoint.pathSegments.length === readAllEndpoint.pathSegments.length && hasMatchingPath(endpoint, readAllEndpoint);
|
|
562
|
+
const hasMatchingPathWithTrailingParam = (endpoint, readAllEndpoint) => endpoint.pathSegments.length - 1 === readAllEndpoint.pathSegments.length && isPathSegmentParam(endpoint.pathSegments.at(-1)) && hasMatchingPath(endpoint, readAllEndpoint);
|
|
563
|
+
|
|
564
|
+
//#endregion
|
|
565
|
+
//#region src/generators/types/generate.ts
|
|
566
|
+
let GenerateType = /* @__PURE__ */ function(GenerateType) {
|
|
567
|
+
GenerateType["Models"] = "models";
|
|
568
|
+
GenerateType["Endpoints"] = "endpoints";
|
|
569
|
+
GenerateType["Queries"] = "queries";
|
|
570
|
+
GenerateType["Acl"] = "acl";
|
|
571
|
+
GenerateType["Configs"] = "configs";
|
|
572
|
+
return GenerateType;
|
|
573
|
+
}({});
|
|
574
|
+
|
|
575
|
+
//#endregion
|
|
576
|
+
//#region src/generators/utils/namespace.utils.ts
|
|
577
|
+
const getNamespaceName = ({ type, tag, options }) => `${capitalize(tag)}${options.configs[type].namespaceSuffix}`;
|
|
578
|
+
|
|
579
|
+
//#endregion
|
|
580
|
+
//#region src/generators/const/acl.const.ts
|
|
581
|
+
const ACL_APP_ABILITY_FILE = {
|
|
582
|
+
fileName: "acl/app.ability",
|
|
583
|
+
extension: "ts"
|
|
584
|
+
};
|
|
585
|
+
const ACL_APP_ABILITIES = "AppAbilities";
|
|
586
|
+
const ACL_CHECK_FILE = {
|
|
587
|
+
fileName: "acl/useAclCheck",
|
|
588
|
+
extension: "ts"
|
|
589
|
+
};
|
|
590
|
+
const ACL_CHECK_HOOK = "useAclCheck";
|
|
591
|
+
const CASL_ABILITY_BINDING = {
|
|
592
|
+
abilityTuple: "AbilityTuple",
|
|
593
|
+
pureAbility: "PureAbility",
|
|
594
|
+
forcedSubject: "ForcedSubject",
|
|
595
|
+
subjectType: "Subject",
|
|
596
|
+
subject: "subject"
|
|
597
|
+
};
|
|
598
|
+
const CASL_ABILITY_IMPORT = {
|
|
599
|
+
bindings: [
|
|
600
|
+
CASL_ABILITY_BINDING.abilityTuple,
|
|
601
|
+
CASL_ABILITY_BINDING.pureAbility,
|
|
602
|
+
CASL_ABILITY_BINDING.forcedSubject,
|
|
603
|
+
CASL_ABILITY_BINDING.subjectType,
|
|
604
|
+
CASL_ABILITY_BINDING.subject
|
|
605
|
+
],
|
|
606
|
+
from: "@casl/ability"
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
//#endregion
|
|
610
|
+
//#region src/generators/const/options.const.ts
|
|
611
|
+
const DEFAULT_GENERATE_OPTIONS = {
|
|
612
|
+
input: "http://localhost:4000/docs-json/",
|
|
613
|
+
output: "output",
|
|
614
|
+
incremental: true,
|
|
615
|
+
splitByTags: true,
|
|
616
|
+
defaultTag: "Common",
|
|
617
|
+
excludeTags: [],
|
|
618
|
+
excludePathRegex: "",
|
|
619
|
+
excludeRedundantZodSchemas: true,
|
|
620
|
+
tsNamespaces: true,
|
|
621
|
+
tsPath: "@/data",
|
|
622
|
+
importPath: "ts",
|
|
623
|
+
configs: {
|
|
624
|
+
[GenerateType.Models]: {
|
|
625
|
+
outputFileNameSuffix: "models",
|
|
626
|
+
namespaceSuffix: "Models"
|
|
627
|
+
},
|
|
628
|
+
[GenerateType.Endpoints]: {
|
|
629
|
+
outputFileNameSuffix: "api",
|
|
630
|
+
namespaceSuffix: "Api"
|
|
631
|
+
},
|
|
632
|
+
[GenerateType.Queries]: {
|
|
633
|
+
outputFileNameSuffix: "queries",
|
|
634
|
+
namespaceSuffix: "Queries"
|
|
635
|
+
},
|
|
636
|
+
[GenerateType.Acl]: {
|
|
637
|
+
outputFileNameSuffix: "acl",
|
|
638
|
+
namespaceSuffix: "Acl"
|
|
639
|
+
},
|
|
640
|
+
[GenerateType.Configs]: {
|
|
641
|
+
outputFileNameSuffix: "configs",
|
|
642
|
+
namespaceSuffix: "Configs"
|
|
643
|
+
}
|
|
644
|
+
},
|
|
645
|
+
baseUrl: "",
|
|
646
|
+
modelsOnly: false,
|
|
647
|
+
standalone: false,
|
|
648
|
+
schemaSuffix: SCHEMA_SUFFIX,
|
|
649
|
+
enumSuffix: ENUM_SUFFIX,
|
|
650
|
+
modelsInCommon: false,
|
|
651
|
+
withDefaultValues: true,
|
|
652
|
+
extractEnums: true,
|
|
653
|
+
replaceOptionalWithNullish: false,
|
|
654
|
+
restClientImportPath: "",
|
|
655
|
+
errorHandlingImportPath: "",
|
|
656
|
+
removeOperationPrefixEndingWith: "Controller_",
|
|
657
|
+
parseRequestParams: true,
|
|
658
|
+
inlineEndpoints: false,
|
|
659
|
+
inlineEndpointsExcludeModules: [],
|
|
660
|
+
queryTypesImportPath: PACKAGE_IMPORT_PATH,
|
|
661
|
+
axiosRequestConfig: false,
|
|
662
|
+
mutationEffects: true,
|
|
663
|
+
workspaceContext: false,
|
|
664
|
+
infiniteQueries: false,
|
|
665
|
+
infiniteQueryParamNames: { page: "page" },
|
|
666
|
+
infiniteQueryResponseParamNames: {
|
|
667
|
+
page: "page",
|
|
668
|
+
totalItems: "totalItems",
|
|
669
|
+
limit: "limit"
|
|
670
|
+
},
|
|
671
|
+
acl: true,
|
|
672
|
+
checkAcl: true,
|
|
673
|
+
abilityContextGenericAppAbilities: false,
|
|
674
|
+
abilityContextImportPath: "",
|
|
675
|
+
builderConfigs: false,
|
|
676
|
+
filterParamName: "filter",
|
|
677
|
+
dataResponseParamNames: ["data", "items"],
|
|
678
|
+
dynamicInputsImportPath: "@povio/ui",
|
|
679
|
+
dynamicColumnsImportPath: "@povio/ui"
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
//#endregion
|
|
683
|
+
//#region src/generators/utils/array.utils.ts
|
|
684
|
+
const getUniqueArray = (...arrs) => [...new Set(arrs.flat())];
|
|
685
|
+
|
|
686
|
+
//#endregion
|
|
687
|
+
//#region src/generators/utils/generate/generate.acl.utils.ts
|
|
688
|
+
const getAbilityFunctionName = (endpoint) => `canUse${capitalize(snakeToCamel(endpoint.operationName))}`;
|
|
689
|
+
const getImportedAbilityFunctionName = (endpoint, options) => {
|
|
690
|
+
return `${options.tsNamespaces ? `${getNamespaceName({
|
|
691
|
+
type: GenerateType.Acl,
|
|
692
|
+
tag: getEndpointTag(endpoint, options),
|
|
693
|
+
options
|
|
694
|
+
})}.` : ""}${getAbilityFunctionName(endpoint)}`;
|
|
695
|
+
};
|
|
696
|
+
const getAbilityAction = (endpoint) => endpoint.acl?.[0].action;
|
|
697
|
+
const getAbilitySubject = (endpoint) => endpoint.acl?.[0].subject;
|
|
698
|
+
const hasAbilityConditions = (endpoint) => !!getAbilityConditionsTypes(endpoint)?.length;
|
|
699
|
+
const getAbilityConditionsTypes = (endpoint) => endpoint.acl?.[0].conditionsTypes?.sort((a, b) => a.name.localeCompare(b.name));
|
|
700
|
+
const getAbilityDescription = (endpoint) => endpoint.acl?.[0]?.description;
|
|
701
|
+
const getAbilitySubjectTypes = (endpoint) => {
|
|
702
|
+
const abilitySubject = getAbilitySubject(endpoint);
|
|
703
|
+
const types = [`"${abilitySubject ?? ""}"`];
|
|
704
|
+
if (hasAbilityConditions(endpoint)) types.push(`ForcedSubject<"${abilitySubject}"> & { ${getAbilityConditionsTypes(endpoint)?.map((conditionType) => `${conditionType.name}${conditionType.required ? "" : "?"}: ${conditionType.type ?? ""}${conditionType.zodSchemaName ?? ""},`).join(" ")} }`);
|
|
705
|
+
return types;
|
|
706
|
+
};
|
|
707
|
+
function getAclData({ resolver, data, tag }) {
|
|
708
|
+
const endpoints = data.get(tag)?.endpoints.filter(({ acl }) => acl && acl.length > 0);
|
|
709
|
+
if (!endpoints || endpoints.length === 0) return;
|
|
710
|
+
return {
|
|
711
|
+
endpoints,
|
|
712
|
+
hasAdditionalAbilityImports: endpoints.some(({ acl }) => acl?.[0].conditions && Object.keys(acl[0].conditions).length > 0),
|
|
713
|
+
modelsImports: getModelsImports({
|
|
714
|
+
resolver,
|
|
715
|
+
tag,
|
|
716
|
+
zodSchemasAsTypes: getUniqueArray(endpoints.reduce((acc, endpoint) => {
|
|
717
|
+
const zodSchemas = endpoint.acl?.[0].conditionsTypes?.reduce((acc, propertyType) => [...acc, ...propertyType?.zodSchemaName ? [propertyType.zodSchemaName] : []], []);
|
|
718
|
+
return [...acc, ...zodSchemas ?? []];
|
|
719
|
+
}, []))
|
|
720
|
+
})
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
const getAppAbilitiesType = ({ resolver, data }) => {
|
|
724
|
+
const appAbilitiesTypeMap = /* @__PURE__ */ new Map();
|
|
725
|
+
const modelsImportsArr = [];
|
|
726
|
+
let hasAdditionalAbilityImports = false;
|
|
727
|
+
data.forEach((_, tag) => {
|
|
728
|
+
const aclData = getAclData({
|
|
729
|
+
resolver,
|
|
730
|
+
data,
|
|
731
|
+
tag
|
|
732
|
+
});
|
|
733
|
+
if (!aclData) return;
|
|
734
|
+
const { modelsImports: tagModelsImports, hasAdditionalAbilityImports: tagHasAdditionalAbilityImports, endpoints } = aclData;
|
|
735
|
+
modelsImportsArr.push(tagModelsImports);
|
|
736
|
+
hasAdditionalAbilityImports = hasAdditionalAbilityImports || tagHasAdditionalAbilityImports;
|
|
737
|
+
endpoints.forEach((endpoint) => {
|
|
738
|
+
const abilityAction = getAbilityAction(endpoint);
|
|
739
|
+
if (abilityAction) appAbilitiesTypeMap.set(abilityAction, new Set([...appAbilitiesTypeMap.get(abilityAction) ?? [], ...getAbilitySubjectTypes(endpoint)]));
|
|
740
|
+
});
|
|
741
|
+
});
|
|
742
|
+
const modelsImports = mergeImports(resolver.options, ...modelsImportsArr);
|
|
743
|
+
return {
|
|
744
|
+
appAbilitiesType: appAbilitiesTypeMap.size > 0 ? Object.fromEntries(Array.from(appAbilitiesTypeMap.entries()).map(([key, valueSet]) => [key, Array.from(valueSet)])) : void 0,
|
|
745
|
+
modelsImports,
|
|
746
|
+
hasAdditionalAbilityImports
|
|
747
|
+
};
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
//#endregion
|
|
751
|
+
//#region src/generators/utils/generate/generate.query.utils.ts
|
|
752
|
+
const getQueryName = (endpoint, mutation) => {
|
|
753
|
+
const addMutationSuffix = isQuery(endpoint) && isMutation(endpoint) && mutation;
|
|
754
|
+
return `use${capitalize(snakeToCamel(endpoint.operationName))}${addMutationSuffix ? "Mutation" : ""}`;
|
|
755
|
+
};
|
|
756
|
+
const getInfiniteQueryName = (endpoint) => `use${capitalize(snakeToCamel(endpoint.operationName))}Infinite`;
|
|
757
|
+
const getImportedQueryName = (endpoint, options) => {
|
|
758
|
+
return `${options.tsNamespaces ? `${getNamespaceName({
|
|
759
|
+
type: GenerateType.Queries,
|
|
760
|
+
tag: getEndpointTag(endpoint, options),
|
|
761
|
+
options
|
|
762
|
+
})}.` : ""}${getQueryName(endpoint)}`;
|
|
763
|
+
};
|
|
764
|
+
const getImportedInfiniteQueryName = (endpoint, options) => {
|
|
765
|
+
return `${options.tsNamespaces ? `${getNamespaceName({
|
|
766
|
+
type: GenerateType.Queries,
|
|
767
|
+
tag: getEndpointTag(endpoint, options),
|
|
768
|
+
options
|
|
769
|
+
})}.` : ""}${getInfiniteQueryName(endpoint)}`;
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
//#endregion
|
|
773
|
+
//#region src/generators/core/openapi/iterateSchema.ts
|
|
774
|
+
function iterateSchema(schema, options) {
|
|
775
|
+
if (!schema) return;
|
|
776
|
+
const { data, onSchema } = options;
|
|
777
|
+
if (isReferenceObject(schema) && onSchema({
|
|
778
|
+
type: "reference",
|
|
779
|
+
schema,
|
|
780
|
+
data
|
|
781
|
+
}) === true) return;
|
|
782
|
+
const schemaObj = schema;
|
|
783
|
+
if (COMPOSITE_KEYWORDS.some((prop) => prop in schemaObj && schemaObj[prop])) {
|
|
784
|
+
const schemaObjs = schemaObj.allOf ?? schemaObj.anyOf ?? schemaObj.oneOf ?? [];
|
|
785
|
+
for (const compositeObj of schemaObjs) {
|
|
786
|
+
if (onSchema?.({
|
|
787
|
+
type: "composite",
|
|
788
|
+
parentSchema: schema,
|
|
789
|
+
schema: compositeObj,
|
|
790
|
+
data
|
|
791
|
+
}) === true) continue;
|
|
792
|
+
iterateSchema(compositeObj, {
|
|
793
|
+
data,
|
|
794
|
+
onSchema
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
if (schemaObj.properties) for (const [propertyName, propertyObj] of Object.entries(schemaObj.properties)) {
|
|
799
|
+
if (onSchema({
|
|
800
|
+
type: "property",
|
|
801
|
+
parentSchema: schema,
|
|
802
|
+
schema: propertyObj,
|
|
803
|
+
data,
|
|
804
|
+
propertyName
|
|
805
|
+
}) === true) continue;
|
|
806
|
+
iterateSchema(propertyObj, options);
|
|
807
|
+
}
|
|
808
|
+
if (schemaObj.additionalProperties && typeof schemaObj.additionalProperties === "object") {
|
|
809
|
+
if (onSchema({
|
|
810
|
+
type: "additionalProperties",
|
|
811
|
+
parentSchema: schema,
|
|
812
|
+
schema: schemaObj.additionalProperties,
|
|
813
|
+
data
|
|
814
|
+
}) === true) return;
|
|
815
|
+
iterateSchema(schemaObj.additionalProperties, options);
|
|
816
|
+
}
|
|
817
|
+
if (schemaObj.type === "array") {
|
|
818
|
+
const arrayObj = schema.items;
|
|
819
|
+
if (onSchema({
|
|
820
|
+
type: "array",
|
|
821
|
+
parentSchema: schema,
|
|
822
|
+
schema: arrayObj,
|
|
823
|
+
data
|
|
824
|
+
}) === true) return;
|
|
825
|
+
iterateSchema(arrayObj, options);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
//#endregion
|
|
830
|
+
//#region src/generators/utils/generate/generate.openapi.utils.ts
|
|
831
|
+
const schemaDescriptionsCache = /* @__PURE__ */ new WeakMap();
|
|
832
|
+
function getSchemaDescriptions(schemaObj) {
|
|
833
|
+
const cachedSchemaDescriptions = schemaDescriptionsCache.get(schemaObj);
|
|
834
|
+
if (cachedSchemaDescriptions) return cachedSchemaDescriptions;
|
|
835
|
+
const schemaDescriptions = [
|
|
836
|
+
"minimum",
|
|
837
|
+
"exclusiveMinimum",
|
|
838
|
+
"maximum",
|
|
839
|
+
"exclusiveMaximum",
|
|
840
|
+
"minItems",
|
|
841
|
+
"minLength",
|
|
842
|
+
"minProperties",
|
|
843
|
+
"maxItems",
|
|
844
|
+
"maxLength",
|
|
845
|
+
"maxProperties",
|
|
846
|
+
"default",
|
|
847
|
+
"example"
|
|
848
|
+
].filter((key) => schemaObj[key] !== void 0).reduce((acc, key) => [...acc, `${capitalize(camelToSpaceSeparated(key))}: \`${schemaObj[key]}\``], []);
|
|
849
|
+
schemaDescriptionsCache.set(schemaObj, schemaDescriptions);
|
|
850
|
+
return schemaDescriptions;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
//#endregion
|
|
854
|
+
//#region src/generators/utils/generate/generate.zod.utils.ts
|
|
855
|
+
const getZodSchemaInferedTypeName = (zodSchemaName, options) => removeSuffix(zodSchemaName, options.schemaSuffix);
|
|
856
|
+
const getImportedZodSchemaName = (resolver, zodSchemaName) => {
|
|
857
|
+
if (!isNamedZodSchema(zodSchemaName)) return zodSchemaName;
|
|
858
|
+
return `${resolver.options.tsNamespaces ? `${getNamespaceName({
|
|
859
|
+
type: GenerateType.Models,
|
|
860
|
+
tag: resolver.getTagByZodSchemaName(zodSchemaName),
|
|
861
|
+
options: resolver.options
|
|
862
|
+
})}.` : ""}${zodSchemaName}`;
|
|
863
|
+
};
|
|
864
|
+
const getImportedZodSchemaInferedTypeName = (resolver, zodSchemaName, currentTag) => {
|
|
865
|
+
if (!isNamedZodSchema(zodSchemaName)) return zodSchemaName === VOID_SCHEMA ? "void" : zodSchemaName;
|
|
866
|
+
const tag = resolver.getTagByZodSchemaName(zodSchemaName);
|
|
867
|
+
return `${resolver.options.tsNamespaces && tag !== currentTag ? `${getNamespaceName({
|
|
868
|
+
type: GenerateType.Models,
|
|
869
|
+
tag,
|
|
870
|
+
options: resolver.options
|
|
871
|
+
})}.` : ""}${getZodSchemaInferedTypeName(zodSchemaName, resolver.options)}`;
|
|
872
|
+
};
|
|
873
|
+
function getZodSchemaType(data) {
|
|
874
|
+
return data.isEnum ? "enum" : data.schemaObj?.type ?? "object";
|
|
875
|
+
}
|
|
876
|
+
function getZodSchemaDescription(data) {
|
|
877
|
+
if (!data.schemaObj) return;
|
|
878
|
+
return [data.schemaObj.description, ...getSchemaDescriptions(data.schemaObj)].filter(Boolean).join(". ");
|
|
879
|
+
}
|
|
880
|
+
function getType(resolver, schemaObj, tag) {
|
|
881
|
+
if (isReferenceObject(schemaObj)) {
|
|
882
|
+
const zodSchemaName = resolver.getZodSchemaNameByRef(schemaObj.$ref);
|
|
883
|
+
return zodSchemaName ? getImportedZodSchemaInferedTypeName(resolver, zodSchemaName, tag) : void 0;
|
|
884
|
+
}
|
|
885
|
+
if (isArraySchemaObject(schemaObj)) {
|
|
886
|
+
if (!isReferenceObject(schemaObj.items)) return `${schemaObj.items?.type ?? "unknown"}[]`;
|
|
887
|
+
const zodSchemaName = resolver.getZodSchemaNameByRef(schemaObj.items.$ref);
|
|
888
|
+
return zodSchemaName ? `${getImportedZodSchemaInferedTypeName(resolver, zodSchemaName, tag)}[]` : void 0;
|
|
889
|
+
}
|
|
890
|
+
if (COMPOSITE_KEYWORDS.some((prop) => prop in schemaObj && schemaObj[prop])) {
|
|
891
|
+
const schemaObjs = schemaObj.allOf ?? schemaObj.anyOf ?? schemaObj.oneOf ?? [];
|
|
892
|
+
if (schemaObjs.length > 0) return getType(resolver, schemaObjs[0], tag);
|
|
893
|
+
}
|
|
894
|
+
return schemaObj.type;
|
|
895
|
+
}
|
|
896
|
+
function getZodSchemaPropertyDescriptions(resolver, data, tag) {
|
|
897
|
+
if (!data.schemaObj) return [];
|
|
898
|
+
const ARRAY_INDEX = "[0]";
|
|
899
|
+
const ADDITIONAL_PROPERTIES_KEY = "[key]";
|
|
900
|
+
const properties = {};
|
|
901
|
+
const onSchema = (schemaData) => {
|
|
902
|
+
if (schemaData.type === "reference") return true;
|
|
903
|
+
if (schemaData.type === "composite") return;
|
|
904
|
+
const segments = [...schemaData.data?.pathSegments ?? []];
|
|
905
|
+
if (schemaData.type === "array") segments.push(ARRAY_INDEX);
|
|
906
|
+
else if (schemaData.type === "property") segments.push(schemaData.propertyName);
|
|
907
|
+
else if (schemaData.type === "additionalProperties") segments.push(ADDITIONAL_PROPERTIES_KEY);
|
|
908
|
+
if (schemaData.schema && segments[segments.length - 1] !== ARRAY_INDEX) {
|
|
909
|
+
const resolvedSchema = resolver.resolveObject(schemaData.schema);
|
|
910
|
+
const schemaDescriptions = [resolvedSchema?.description, ...getSchemaDescriptions(resolvedSchema)].filter(Boolean);
|
|
911
|
+
const propertyKey = segments.join(".");
|
|
912
|
+
if (!(properties[propertyKey] && "type" in schemaData.schema && schemaData.schema.type === "object")) {
|
|
913
|
+
delete properties[propertyKey];
|
|
914
|
+
properties[propertyKey] = {
|
|
915
|
+
type: getType(resolver, schemaData.schema, tag) ?? "unknown",
|
|
916
|
+
description: schemaDescriptions.join(". ")
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
iterateSchema(schemaData.schema, {
|
|
921
|
+
data: { pathSegments: [...segments] },
|
|
922
|
+
onSchema
|
|
923
|
+
});
|
|
924
|
+
return true;
|
|
925
|
+
};
|
|
926
|
+
if ("allOf" in data.schemaObj && data.schemaObj.allOf) data.schemaObj.allOf.forEach((schemaObj) => {
|
|
927
|
+
if (isReferenceObject(schemaObj)) iterateSchema(resolver.resolveObject(schemaObj), {
|
|
928
|
+
data: { pathSegments: [] },
|
|
929
|
+
onSchema
|
|
930
|
+
});
|
|
931
|
+
});
|
|
932
|
+
iterateSchema(data.schemaObj, {
|
|
933
|
+
data: { pathSegments: [] },
|
|
934
|
+
onSchema
|
|
935
|
+
});
|
|
936
|
+
return properties;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
//#endregion
|
|
940
|
+
//#region src/generators/utils/generate/generate.imports.utils.ts
|
|
941
|
+
function getModelsImports({ resolver, tag, zodSchemas = [], zodSchemasAsTypes = [] }) {
|
|
942
|
+
const type = GenerateType.Models;
|
|
943
|
+
const getTag = (zodSchemaName) => resolver.getTagByZodSchemaName(zodSchemaName);
|
|
944
|
+
const zodSchemaImports = getImports({
|
|
945
|
+
type,
|
|
946
|
+
tag,
|
|
947
|
+
entities: zodSchemas,
|
|
948
|
+
getTag,
|
|
949
|
+
getEntityName: (zodSchema) => zodSchema,
|
|
950
|
+
options: resolver.options
|
|
951
|
+
});
|
|
952
|
+
const zodSchemaTypeImports = getImports({
|
|
953
|
+
type,
|
|
954
|
+
tag,
|
|
955
|
+
entities: zodSchemasAsTypes,
|
|
956
|
+
getTag,
|
|
957
|
+
getEntityName: (zodSchema) => getZodSchemaInferedTypeName(zodSchema, resolver.options),
|
|
958
|
+
options: resolver.options
|
|
959
|
+
});
|
|
960
|
+
return mergeImports(resolver.options, zodSchemaImports, zodSchemaTypeImports);
|
|
961
|
+
}
|
|
962
|
+
function getEndpointsImports({ tag, endpoints, options }) {
|
|
963
|
+
return getImports({
|
|
964
|
+
type: GenerateType.Endpoints,
|
|
965
|
+
tag,
|
|
966
|
+
entities: endpoints,
|
|
967
|
+
getTag: (endpoint) => getEndpointTag(endpoint, options),
|
|
968
|
+
getEntityName: getEndpointName,
|
|
969
|
+
options
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
function getQueriesImports({ tag, endpoints, options }) {
|
|
973
|
+
return getImports({
|
|
974
|
+
type: GenerateType.Queries,
|
|
975
|
+
tag,
|
|
976
|
+
entities: endpoints,
|
|
977
|
+
getTag: (endpoint) => getEndpointTag(endpoint, options),
|
|
978
|
+
getEntityName: getQueryName,
|
|
979
|
+
options
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
function getInfiniteQueriesImports({ tag, endpoints, options }) {
|
|
983
|
+
return getImports({
|
|
984
|
+
type: GenerateType.Queries,
|
|
985
|
+
tag,
|
|
986
|
+
entities: endpoints,
|
|
987
|
+
getTag: (endpoint) => getEndpointTag(endpoint, options),
|
|
988
|
+
getEntityName: getInfiniteQueryName,
|
|
989
|
+
options
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
function getAclImports({ tag, endpoints, options }) {
|
|
993
|
+
return getImports({
|
|
994
|
+
type: GenerateType.Acl,
|
|
995
|
+
tag,
|
|
996
|
+
entities: endpoints,
|
|
997
|
+
getTag: (endpoint) => getEndpointTag(endpoint, options),
|
|
998
|
+
getEntityName: getAbilityFunctionName,
|
|
999
|
+
options
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
function getImportPath(options, fromRoot = false) {
|
|
1003
|
+
let importPath = options.tsPath;
|
|
1004
|
+
if (options.importPath === "relative") importPath = fromRoot ? "./" : "../";
|
|
1005
|
+
else if (options.importPath === "absolute") importPath = options.output;
|
|
1006
|
+
else if (new RegExp(`${TEMPLATE_DATA_FILE_PATH}`, "g").test(options.output)) importPath = options.output.replace(new RegExp(`.*${TEMPLATE_DATA_FILE_PATH}`, "g"), options.tsPath);
|
|
1007
|
+
return `${importPath}/`.replace(/\/\//g, "/");
|
|
1008
|
+
}
|
|
1009
|
+
function getImports({ type = GenerateType.Models, tag: currentTag, entities, getTag, getEntityName, options }) {
|
|
1010
|
+
const imports = /* @__PURE__ */ new Map();
|
|
1011
|
+
entities.forEach((entity) => {
|
|
1012
|
+
const tag = type === GenerateType.Models && options.modelsInCommon && options.splitByTags ? currentTag : getTag(entity);
|
|
1013
|
+
if (!imports.has(tag)) {
|
|
1014
|
+
const sameTagDir = currentTag === tag;
|
|
1015
|
+
imports.set(tag, {
|
|
1016
|
+
bindings: [options.tsNamespaces ? getNamespaceName({
|
|
1017
|
+
type,
|
|
1018
|
+
tag,
|
|
1019
|
+
options
|
|
1020
|
+
}) : getEntityName(entity)],
|
|
1021
|
+
from: `${sameTagDir ? "./" : getImportPath(options)}${getTagImportPath({
|
|
1022
|
+
type,
|
|
1023
|
+
tag,
|
|
1024
|
+
includeTagDir: !sameTagDir,
|
|
1025
|
+
options
|
|
1026
|
+
})}`
|
|
1027
|
+
});
|
|
1028
|
+
} else if (!options.tsNamespaces) imports.get(tag).bindings.push(getEntityName(entity));
|
|
1029
|
+
});
|
|
1030
|
+
return Array.from(imports.values());
|
|
1031
|
+
}
|
|
1032
|
+
function mergeImports(options, ...importArrs) {
|
|
1033
|
+
const merged = /* @__PURE__ */ new Map();
|
|
1034
|
+
importArrs.forEach((imports) => {
|
|
1035
|
+
imports.forEach((importItem) => {
|
|
1036
|
+
if (!merged.has(importItem.from)) merged.set(importItem.from, importItem);
|
|
1037
|
+
else if (!options.tsNamespaces) merged.get(importItem.from).bindings.push(...importItem.bindings);
|
|
1038
|
+
});
|
|
1039
|
+
});
|
|
1040
|
+
return Array.from(merged.values()).map((importItem) => ({
|
|
1041
|
+
...importItem,
|
|
1042
|
+
bindings: getUniqueArray(importItem.bindings)
|
|
1043
|
+
}));
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
//#endregion
|
|
1047
|
+
//#region src/generators/utils/generate/generate.utils.ts
|
|
1048
|
+
function getFileNameWithExtension({ fileName, extension }) {
|
|
1049
|
+
return `${fileName}.${extension}`;
|
|
1050
|
+
}
|
|
1051
|
+
function getTagFileNameWithoutExtension({ type, tag, options, includeTagDir = true }) {
|
|
1052
|
+
const outputFileNameSuffix = options.configs[type].outputFileNameSuffix;
|
|
1053
|
+
if (!tag) return outputFileNameSuffix;
|
|
1054
|
+
return `${includeTagDir ? `${decapitalize(tag)}/` : ""}${decapitalize(tag)}.${outputFileNameSuffix}`;
|
|
1055
|
+
}
|
|
1056
|
+
function getTagImportPath(...args) {
|
|
1057
|
+
return getTagFileNameWithoutExtension(...args);
|
|
1058
|
+
}
|
|
1059
|
+
function getTagFileName(...args) {
|
|
1060
|
+
return `${getTagFileNameWithoutExtension(...args)}.ts`;
|
|
1061
|
+
}
|
|
1062
|
+
function getAppRestClientImportPath(options) {
|
|
1063
|
+
if (options.restClientImportPath === DEFAULT_GENERATE_OPTIONS.restClientImportPath) return `${getImportPath(options)}${APP_REST_CLIENT_FILE.fileName}`;
|
|
1064
|
+
return options.restClientImportPath;
|
|
1065
|
+
}
|
|
1066
|
+
function getQueryModulesImportPath(options) {
|
|
1067
|
+
return `${getImportPath(options)}${QUERY_MODULES_FILE.fileName}`;
|
|
1068
|
+
}
|
|
1069
|
+
function getQueryTypesImportPath(options) {
|
|
1070
|
+
return options.queryTypesImportPath;
|
|
1071
|
+
}
|
|
1072
|
+
function getMutationEffectsImportPath(options) {
|
|
1073
|
+
return `${getImportPath(options)}${MUTATION_EFFECTS_FILE.fileName}`;
|
|
1074
|
+
}
|
|
1075
|
+
function getAclCheckImportPath(options) {
|
|
1076
|
+
return `${getImportPath(options)}${ACL_CHECK_FILE.fileName}`;
|
|
1077
|
+
}
|
|
1078
|
+
function getZodExtendedImportPath(options) {
|
|
1079
|
+
return `${getImportPath(options)}${ZOD_EXTENDED_FILE.fileName}`;
|
|
1080
|
+
}
|
|
1081
|
+
function getAppAbilitiesImportPath(options) {
|
|
1082
|
+
return `${getImportPath(options)}${ACL_APP_ABILITY_FILE.fileName}`;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
//#endregion
|
|
1086
|
+
//#region src/generators/utils/ts.utils.ts
|
|
1087
|
+
function primitiveTypeToTsType(type) {
|
|
1088
|
+
return match(type).with("string", () => "string").with("number", () => "number").with("integer", () => "number").with("boolean", () => "boolean").exhaustive();
|
|
1089
|
+
}
|
|
1090
|
+
function getTsTypeBase({ zodSchemaName, schema, resolver }) {
|
|
1091
|
+
let type = "void";
|
|
1092
|
+
let tag;
|
|
1093
|
+
if (zodSchemaName && isNamedZodSchema(zodSchemaName)) {
|
|
1094
|
+
type = getImportedZodSchemaInferedTypeName(resolver, zodSchemaName);
|
|
1095
|
+
tag = resolver.getTagByZodSchemaName(zodSchemaName);
|
|
1096
|
+
} else if (schema?.type && isPrimitiveType(schema?.type)) type = primitiveTypeToTsType(schema?.type);
|
|
1097
|
+
const splitType = type.split(".");
|
|
1098
|
+
return {
|
|
1099
|
+
type: splitType[splitType.length - 1],
|
|
1100
|
+
...splitType.length > 1 ? { namespace: splitType[0] } : {},
|
|
1101
|
+
...tag ? { importPath: getTagImportPath({
|
|
1102
|
+
type: GenerateType.Models,
|
|
1103
|
+
tag,
|
|
1104
|
+
includeTagDir: true,
|
|
1105
|
+
options: resolver.options
|
|
1106
|
+
}) } : {}
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
function getSchemaTsMetaType({ schema, isCircular, parentTypes, resolver }) {
|
|
1110
|
+
if (!schema) return { metaType: "primitive" };
|
|
1111
|
+
for (const compositeKeyword of COMPOSITE_KEYWORDS) {
|
|
1112
|
+
const compositeObjs = schema[compositeKeyword];
|
|
1113
|
+
if (!compositeObjs) continue;
|
|
1114
|
+
if (compositeObjs.length > 1) {
|
|
1115
|
+
const metaTypes = compositeObjs.map((compositeObj) => {
|
|
1116
|
+
return getSchemaTsMetaType({
|
|
1117
|
+
schema: resolver.resolveObject(compositeObj),
|
|
1118
|
+
parentTypes,
|
|
1119
|
+
resolver
|
|
1120
|
+
});
|
|
1121
|
+
});
|
|
1122
|
+
if (metaTypes.every(({ metaType }) => metaType === "object")) return {
|
|
1123
|
+
metaType: "object",
|
|
1124
|
+
objectProperties: metaTypes.reduce((acc, { objectProperties }) => {
|
|
1125
|
+
const objectPropertyNames = new Set(objectProperties.map(({ name }) => name));
|
|
1126
|
+
return [...acc.filter(({ name }) => !objectPropertyNames.has(name)), ...objectProperties];
|
|
1127
|
+
}, [])
|
|
1128
|
+
};
|
|
1129
|
+
else return {
|
|
1130
|
+
metaType: "composite",
|
|
1131
|
+
[compositeKeyword]: metaTypes
|
|
1132
|
+
};
|
|
1133
|
+
} else schema = resolver.resolveObject(compositeObjs[0]);
|
|
1134
|
+
}
|
|
1135
|
+
if (schema.type === "array") return {
|
|
1136
|
+
metaType: "array",
|
|
1137
|
+
arrayType: getArraySchemaTsType({
|
|
1138
|
+
arraySchema: schema,
|
|
1139
|
+
resolver,
|
|
1140
|
+
parentTypes
|
|
1141
|
+
})
|
|
1142
|
+
};
|
|
1143
|
+
else if ((schema.type === "object" || schema.properties) && isCircular) return {
|
|
1144
|
+
metaType: "object",
|
|
1145
|
+
objectProperties: [],
|
|
1146
|
+
isCircular: true
|
|
1147
|
+
};
|
|
1148
|
+
else if (schema.type === "object" || schema.properties) return {
|
|
1149
|
+
metaType: "object",
|
|
1150
|
+
objectProperties: getSchemaTsProperties({
|
|
1151
|
+
schema,
|
|
1152
|
+
parentTypes,
|
|
1153
|
+
resolver
|
|
1154
|
+
})
|
|
1155
|
+
};
|
|
1156
|
+
return { metaType: "primitive" };
|
|
1157
|
+
}
|
|
1158
|
+
function getArraySchemaTsType({ arraySchema, parentTypes, resolver }) {
|
|
1159
|
+
let zodSchemaName;
|
|
1160
|
+
let schema;
|
|
1161
|
+
if (isReferenceObject(arraySchema.items)) {
|
|
1162
|
+
const ref = arraySchema.items.$ref;
|
|
1163
|
+
zodSchemaName = resolver.getZodSchemaNameByRef(ref);
|
|
1164
|
+
schema = resolver.getSchemaByRef(ref);
|
|
1165
|
+
} else schema = arraySchema.items;
|
|
1166
|
+
const tsType = getTsTypeBase({
|
|
1167
|
+
zodSchemaName,
|
|
1168
|
+
schema,
|
|
1169
|
+
resolver
|
|
1170
|
+
});
|
|
1171
|
+
const isCircular = getIsCircular(tsType, parentTypes);
|
|
1172
|
+
const tsMetaType = getSchemaTsMetaType({
|
|
1173
|
+
schema,
|
|
1174
|
+
isCircular,
|
|
1175
|
+
parentTypes: [...parentTypes, tsType],
|
|
1176
|
+
resolver
|
|
1177
|
+
});
|
|
1178
|
+
return {
|
|
1179
|
+
...tsType,
|
|
1180
|
+
...tsMetaType
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
function getSchemaTsProperties({ schema, parentTypes, resolver }) {
|
|
1184
|
+
return Object.entries(schema?.properties ?? {}).map(([name, property]) => {
|
|
1185
|
+
const isRequired = schema?.required?.includes(name) ?? false;
|
|
1186
|
+
if (isReferenceObject(property)) {
|
|
1187
|
+
const zodSchemaName = resolver.getZodSchemaNameByRef(property.$ref);
|
|
1188
|
+
const schema = resolver.getSchemaByRef(property.$ref);
|
|
1189
|
+
const tsType = getTsTypeBase({
|
|
1190
|
+
zodSchemaName,
|
|
1191
|
+
schema,
|
|
1192
|
+
resolver
|
|
1193
|
+
});
|
|
1194
|
+
const tsMetaType = getSchemaTsMetaType({
|
|
1195
|
+
schema,
|
|
1196
|
+
isCircular: getIsCircular(tsType, parentTypes),
|
|
1197
|
+
parentTypes: [...parentTypes, tsType],
|
|
1198
|
+
resolver
|
|
1199
|
+
});
|
|
1200
|
+
return {
|
|
1201
|
+
name,
|
|
1202
|
+
isRequired,
|
|
1203
|
+
...tsType,
|
|
1204
|
+
...tsMetaType
|
|
1205
|
+
};
|
|
1206
|
+
} else if (property.type === "array") return {
|
|
1207
|
+
name,
|
|
1208
|
+
isRequired,
|
|
1209
|
+
type: "array",
|
|
1210
|
+
metaType: "array",
|
|
1211
|
+
arrayType: getArraySchemaTsType({
|
|
1212
|
+
arraySchema: property,
|
|
1213
|
+
parentTypes,
|
|
1214
|
+
resolver
|
|
1215
|
+
})
|
|
1216
|
+
};
|
|
1217
|
+
else if (isPrimitiveType(property.type)) return {
|
|
1218
|
+
name,
|
|
1219
|
+
isRequired,
|
|
1220
|
+
type: primitiveTypeToTsType(property.type),
|
|
1221
|
+
metaType: "primitive"
|
|
1222
|
+
};
|
|
1223
|
+
return {
|
|
1224
|
+
name,
|
|
1225
|
+
isRequired,
|
|
1226
|
+
type: "void",
|
|
1227
|
+
metaType: "primitive"
|
|
1228
|
+
};
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
function getIsCircular(tsType, parentTypes) {
|
|
1232
|
+
return parentTypes.findIndex(({ type, namespace }) => type === tsType.type && namespace === tsType.namespace) > -1;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
//#endregion
|
|
1236
|
+
//#region src/generators/utils/generate/generate.endpoints.utils.ts
|
|
1237
|
+
const getEndpointName = (endpoint) => decapitalize(snakeToCamel(endpoint.operationName));
|
|
1238
|
+
function getImportedEndpointName(endpoint, options) {
|
|
1239
|
+
return `${options.tsNamespaces ? `${getNamespaceName({
|
|
1240
|
+
type: GenerateType.Endpoints,
|
|
1241
|
+
tag: getEndpointTag(endpoint, options),
|
|
1242
|
+
options
|
|
1243
|
+
})}.` : ""}${getEndpointName(endpoint)}`;
|
|
1244
|
+
}
|
|
1245
|
+
const requiresBody = (endpoint) => endpoint.method !== OpenAPIV3.HttpMethods.GET;
|
|
1246
|
+
const getEndpointBody$1 = (endpoint) => endpoint.parameters.find((param) => param.type === "Body");
|
|
1247
|
+
const hasEndpointConfig = (endpoint, resolver) => {
|
|
1248
|
+
const endpointConfig = getEndpointConfig(endpoint);
|
|
1249
|
+
const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
|
|
1250
|
+
return Object.keys(endpointConfig).length > 0 || hasAxiosRequestConfig;
|
|
1251
|
+
};
|
|
1252
|
+
const getEndpointPath = (endpoint) => endpoint.path.replace(/:([a-zA-Z0-9_]+)/g, "${$1}");
|
|
1253
|
+
function mapEndpointParamsToFunctionParams(resolver, endpoint, options) {
|
|
1254
|
+
const params = endpoint.parameters.map((param) => {
|
|
1255
|
+
let type = "string";
|
|
1256
|
+
if (isNamedZodSchema(param.zodSchema)) type = getImportedZodSchemaInferedTypeName(resolver, param.zodSchema);
|
|
1257
|
+
else if (param.parameterObject?.schema && isSchemaObject(param.parameterObject.schema)) {
|
|
1258
|
+
const openApiSchemaType = (param.parameterObject?.schema)?.type;
|
|
1259
|
+
if (openApiSchemaType && isPrimitiveType(openApiSchemaType)) type = primitiveTypeToTsType(openApiSchemaType);
|
|
1260
|
+
}
|
|
1261
|
+
return {
|
|
1262
|
+
name: invalidVariableNameCharactersToCamel(param.name),
|
|
1263
|
+
type,
|
|
1264
|
+
paramType: param.type,
|
|
1265
|
+
required: param.parameterObject?.required ?? true,
|
|
1266
|
+
parameterObject: param.parameterObject,
|
|
1267
|
+
bodyObject: param.bodyObject
|
|
1268
|
+
};
|
|
1269
|
+
});
|
|
1270
|
+
if (options?.includeFileParam && endpoint.mediaUpload) params.push({
|
|
1271
|
+
name: "file",
|
|
1272
|
+
type: "File",
|
|
1273
|
+
paramType: "Body",
|
|
1274
|
+
required: false,
|
|
1275
|
+
parameterObject: void 0,
|
|
1276
|
+
bodyObject: void 0
|
|
1277
|
+
});
|
|
1278
|
+
return params.toSorted((a, b) => {
|
|
1279
|
+
if (a.required === b.required) {
|
|
1280
|
+
const sortedParamTypes = [
|
|
1281
|
+
"Path",
|
|
1282
|
+
"Body",
|
|
1283
|
+
"Query",
|
|
1284
|
+
"Header"
|
|
1285
|
+
];
|
|
1286
|
+
return sortedParamTypes.indexOf(a.paramType) - sortedParamTypes.indexOf(b.paramType);
|
|
1287
|
+
}
|
|
1288
|
+
return a.required ? -1 : 1;
|
|
1289
|
+
}).filter((param) => (!options?.excludeBodyParam || param.name !== BODY_PARAMETER_NAME) && (!options?.excludePageParam || param.name !== resolver.options.infiniteQueryParamNames.page) && (!options?.includeOnlyRequiredParams || param.required)).map((param) => ({
|
|
1290
|
+
...param,
|
|
1291
|
+
name: options?.replacePageParam && param.name === resolver.options.infiniteQueryParamNames.page ? "pageParam" : param.name,
|
|
1292
|
+
required: options?.optionalPathParams && param.paramType === "Path" ? false : param.required && (param.paramType === "Path" || !options?.pathParamsRequiredOnly)
|
|
1293
|
+
}));
|
|
1294
|
+
}
|
|
1295
|
+
function getEndpointConfig(endpoint) {
|
|
1296
|
+
const params = endpoint.parameters.filter((param) => param.type === "Query").map((param) => {
|
|
1297
|
+
const paramPropertyName = isValidPropertyName(param.name) ? param.name : `"${param.name}"`;
|
|
1298
|
+
const paramVariableName = invalidVariableNameCharactersToCamel(param.name);
|
|
1299
|
+
return {
|
|
1300
|
+
...param,
|
|
1301
|
+
name: paramPropertyName,
|
|
1302
|
+
value: paramVariableName
|
|
1303
|
+
};
|
|
1304
|
+
});
|
|
1305
|
+
const headers = {};
|
|
1306
|
+
if (endpoint.requestFormat !== DEFAULT_HEADERS["Content-Type"]) headers["Content-Type"] = `'${endpoint.requestFormat}'`;
|
|
1307
|
+
if (endpoint.responseFormat && endpoint.responseFormat !== DEFAULT_HEADERS.Accept) headers.Accept = `'${endpoint.responseFormat}'`;
|
|
1308
|
+
endpoint.parameters.filter((param) => param.type === "Header").forEach((param) => {
|
|
1309
|
+
headers[param.name] = invalidVariableNameCharactersToCamel(param.name);
|
|
1310
|
+
});
|
|
1311
|
+
return {
|
|
1312
|
+
...params.length > 0 ? { params } : {},
|
|
1313
|
+
...Object.keys(headers).length ? { headers } : {}
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
//#endregion
|
|
1318
|
+
//#region src/generators/utils/query.utils.ts
|
|
1319
|
+
const isQuery = (endpoint) => isGetEndpoint(endpoint);
|
|
1320
|
+
const isMutation = (endpoint) => !isGetEndpoint(endpoint) || !!endpoint.mediaDownload;
|
|
1321
|
+
const isInfiniteQuery = (endpoint, options) => isPaginatedGetEndpoint(endpoint, options);
|
|
1322
|
+
const getDestructuredVariables = (resolver, endpoint, updateQueryEndpoints) => {
|
|
1323
|
+
const requiredUpdateQueryParams = updateQueryEndpoints.reduce((acc, updateEndpoint) => [...acc, ...mapEndpointParamsToFunctionParams(resolver, updateEndpoint, { includeOnlyRequiredParams: true }).map((param) => param.name)], []);
|
|
1324
|
+
return mapEndpointParamsToFunctionParams(resolver, endpoint, {
|
|
1325
|
+
includeOnlyRequiredParams: true,
|
|
1326
|
+
excludeBodyParam: true
|
|
1327
|
+
}).filter((param) => requiredUpdateQueryParams.includes(param.name)).map((param) => param.name);
|
|
1328
|
+
};
|
|
1329
|
+
|
|
1330
|
+
//#endregion
|
|
1331
|
+
//#region src/generators/core/endpoints/getEndpointAcl.ts
|
|
1332
|
+
function getEndpointAcl({ resolver, endpoint, operation }) {
|
|
1333
|
+
const acl = operation["x-acl"];
|
|
1334
|
+
return acl?.map((item) => {
|
|
1335
|
+
const conditionsTypes = Object.keys(item.conditions ?? {}).reduce((acc, name) => {
|
|
1336
|
+
const propertyType = getEndpointAclConditionPropertyType({
|
|
1337
|
+
resolver,
|
|
1338
|
+
endpoint,
|
|
1339
|
+
acl,
|
|
1340
|
+
name
|
|
1341
|
+
});
|
|
1342
|
+
if (!propertyType) {
|
|
1343
|
+
resolver.validationErrors.push(getMissingAclConditionPropertyError(name, operation, endpoint));
|
|
1344
|
+
return acc;
|
|
1345
|
+
}
|
|
1346
|
+
return [...acc, propertyType];
|
|
1347
|
+
}, []);
|
|
1348
|
+
return {
|
|
1349
|
+
...item,
|
|
1350
|
+
conditionsTypes
|
|
1351
|
+
};
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
function getEndpointAclConditionPropertyType({ resolver, endpoint, acl, name }) {
|
|
1355
|
+
const conditionPropertyPath = acl[0]?.conditions?.[name];
|
|
1356
|
+
if (!conditionPropertyPath) return;
|
|
1357
|
+
const pathSplits = conditionPropertyPath.replace(/^\$[^.]*\./, "").split(".");
|
|
1358
|
+
let schema = void 0;
|
|
1359
|
+
let required = void 0;
|
|
1360
|
+
let info = void 0;
|
|
1361
|
+
let index = 0;
|
|
1362
|
+
const parameter = endpoint.parameters.find(({ name }) => name === pathSplits[index]);
|
|
1363
|
+
if (parameter) {
|
|
1364
|
+
required = parameter.parameterObject?.required;
|
|
1365
|
+
schema = parameter.parameterObject?.schema;
|
|
1366
|
+
info = `${parameter.name} ${decapitalize(parameter.type)} parameter`;
|
|
1367
|
+
index++;
|
|
1368
|
+
} else {
|
|
1369
|
+
const bodyParameter = endpoint.parameters.find(({ bodyObject }) => !!bodyObject);
|
|
1370
|
+
const matchingMediaType = Object.keys(bodyParameter?.bodyObject?.content ?? {}).find(isParamMediaTypeAllowed);
|
|
1371
|
+
if (matchingMediaType) {
|
|
1372
|
+
schema = bodyParameter?.bodyObject?.content?.[matchingMediaType]?.schema;
|
|
1373
|
+
info = `${isQuery(endpoint) ? "query" : "mutation"} data`;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
while (schema && index < pathSplits.length) {
|
|
1377
|
+
const resolvedSchema = resolver.resolveObject(schema);
|
|
1378
|
+
schema = Object.entries(resolvedSchema.properties ?? {}).find(([key]) => key === pathSplits[index])?.[1];
|
|
1379
|
+
required = resolvedSchema.required?.includes(pathSplits[index]) ?? false;
|
|
1380
|
+
index++;
|
|
1381
|
+
}
|
|
1382
|
+
if (!schema) return;
|
|
1383
|
+
return {
|
|
1384
|
+
name,
|
|
1385
|
+
type: isReferenceObject(schema) ? void 0 : schema.type,
|
|
1386
|
+
zodSchemaName: isReferenceObject(schema) ? resolver.getZodSchemaNameByRef(schema.$ref) : void 0,
|
|
1387
|
+
required,
|
|
1388
|
+
info
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
//#endregion
|
|
1393
|
+
//#region src/generators/core/zod/getZodChain.ts
|
|
1394
|
+
function getZodChain({ schema, meta, options }) {
|
|
1395
|
+
const chains = [];
|
|
1396
|
+
match(schema.type).with("string", () => chains.push(getZodChainableStringValidations(schema))).with("number", "integer", () => chains.push(getZodChainableNumberValidations(schema))).with("array", () => chains.push(getZodChainableArrayValidations(schema))).otherwise(() => void 0);
|
|
1397
|
+
if (typeof schema.description === "string" && schema.description !== "" && options.withDescription) chains.push(`describe(${JSON.stringify(schema.description)})`);
|
|
1398
|
+
const output = chains.concat(getZodChainablePresence({
|
|
1399
|
+
schema,
|
|
1400
|
+
meta,
|
|
1401
|
+
options
|
|
1402
|
+
}), options.withDefaultValues !== false ? getZodChainableDefault(schema) : []).filter(Boolean).join(".");
|
|
1403
|
+
return output ? `.${output}` : "";
|
|
1404
|
+
}
|
|
1405
|
+
function getZodChainablePresence({ schema, meta, options }) {
|
|
1406
|
+
if (schema.nullable && !meta?.isRequired) return "nullish()";
|
|
1407
|
+
if (schema.nullable || options.replaceOptionalWithNullish && meta?.isParentPartial) return "nullable()";
|
|
1408
|
+
if (!meta?.isRequired) return options.replaceOptionalWithNullish ? "nullish()" : "optional()";
|
|
1409
|
+
return "";
|
|
1410
|
+
}
|
|
1411
|
+
function getZodChainableDefault(schema) {
|
|
1412
|
+
if (schema.default !== void 0) return `default(${match(schema.type).with("number", "integer", () => unwrapQuotesIfNeeded(schema.default)).otherwise(() => JSON.stringify(schema.default))})`;
|
|
1413
|
+
return "";
|
|
1414
|
+
}
|
|
1415
|
+
function getZodChainableStringValidations(schema) {
|
|
1416
|
+
const validations = [];
|
|
1417
|
+
if (!schema.enum) {
|
|
1418
|
+
if (schema.minLength !== void 0) validations.push(`min(${schema.minLength})`);
|
|
1419
|
+
if (schema.maxLength !== void 0) validations.push(`max(${schema.maxLength})`);
|
|
1420
|
+
}
|
|
1421
|
+
if (schema.pattern) validations.push(`regex(${formatPatternIfNeeded(schema.pattern)})`);
|
|
1422
|
+
return validations.join(".");
|
|
1423
|
+
}
|
|
1424
|
+
function formatPatternIfNeeded(pattern) {
|
|
1425
|
+
if (pattern.startsWith("/") && pattern.endsWith("/")) pattern = pattern.slice(1, -1);
|
|
1426
|
+
pattern = escapeControlCharacters(pattern);
|
|
1427
|
+
return `/${pattern}/`;
|
|
1428
|
+
}
|
|
1429
|
+
function getZodChainableNumberValidations(schema) {
|
|
1430
|
+
const validations = [];
|
|
1431
|
+
if (schema.enum) return "";
|
|
1432
|
+
if (schema.minimum !== void 0) if (schema.exclusiveMinimum === true) validations.push(`gt(${schema.minimum})`);
|
|
1433
|
+
else validations.push(`gte(${schema.minimum})`);
|
|
1434
|
+
else if (typeof schema.exclusiveMinimum === "number") validations.push(`gt(${schema.exclusiveMinimum})`);
|
|
1435
|
+
if (schema.maximum !== void 0) if (schema.exclusiveMaximum === true) validations.push(`lt(${schema.maximum})`);
|
|
1436
|
+
else validations.push(`lte(${schema.maximum})`);
|
|
1437
|
+
else if (typeof schema.exclusiveMaximum === "number") validations.push(`lt(${schema.exclusiveMaximum})`);
|
|
1438
|
+
if (schema.multipleOf) validations.push(`multipleOf(${schema.multipleOf})`);
|
|
1439
|
+
return validations.join(".");
|
|
1440
|
+
}
|
|
1441
|
+
function getZodChainableArrayValidations(schema) {
|
|
1442
|
+
const validations = [];
|
|
1443
|
+
if (schema.minItems) validations.push(`min(${schema.minItems})`);
|
|
1444
|
+
if (schema.maxItems) validations.push(`max(${schema.maxItems})`);
|
|
1445
|
+
return validations.join(".");
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
//#endregion
|
|
1449
|
+
//#region src/generators/core/zod/getZodSchemaRefs.ts
|
|
1450
|
+
function getZodSchemaRefs(resolver, zodSchemaName) {
|
|
1451
|
+
const schemaRef = resolver.getRefByZodSchemaName(zodSchemaName);
|
|
1452
|
+
if (schemaRef) {
|
|
1453
|
+
const refs = Array.from(resolver.dependencyGraph.refsDependencyGraph[schemaRef] ?? []).map((ref) => resolver.getZodSchemaNameByRef(ref));
|
|
1454
|
+
const enumRefs = resolver.getExtractedEnumZodSchemaNamesReferencedBySchemaRef(schemaRef);
|
|
1455
|
+
return [...refs, ...enumRefs];
|
|
1456
|
+
}
|
|
1457
|
+
const zodSchema = resolver.getCompositeZodSchemaByZodSchemaName(zodSchemaName);
|
|
1458
|
+
if (zodSchema) return Array.from(getSchemaRefs(zodSchema)).map((schemaRef) => resolver.getZodSchemaNameByRef(schemaRef));
|
|
1459
|
+
return [];
|
|
1460
|
+
}
|
|
1461
|
+
function getSchemaRefs(zodSchema, { skipObjectSchema = false } = {}) {
|
|
1462
|
+
return zodSchema.children.reduce((acc, child) => {
|
|
1463
|
+
const ref = child.ref ?? child.enumRef;
|
|
1464
|
+
if (ref) acc.add(ref);
|
|
1465
|
+
if (child.children.length > 0 && (!skipObjectSchema || !isSchemaObject(child.schema) || child.schema.type !== "object")) getSchemaRefs(child).forEach((ref) => acc.add(ref));
|
|
1466
|
+
return acc;
|
|
1467
|
+
}, /* @__PURE__ */ new Set());
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
//#endregion
|
|
1471
|
+
//#region src/generators/utils/math.utils.ts
|
|
1472
|
+
const sum = (arr) => arr.reduce((acc, item) => acc + item, 0);
|
|
1473
|
+
|
|
1474
|
+
//#endregion
|
|
1475
|
+
//#region src/generators/core/openapi/getOpenAPISchemaComplexity.ts
|
|
1476
|
+
function getOpenAPISchemaComplexity(current, schema) {
|
|
1477
|
+
if (!schema) return current;
|
|
1478
|
+
if (isReferenceObject(schema)) return current + 2;
|
|
1479
|
+
if (Array.isArray(schema.type)) {
|
|
1480
|
+
if (schema.type.length === 1) return complexityByComposite("oneOf") + getOpenAPISchemaComplexity(current, {
|
|
1481
|
+
...schema,
|
|
1482
|
+
type: schema.type[0]
|
|
1483
|
+
});
|
|
1484
|
+
return current + complexityByComposite("oneOf") + sum(schema.type.map((prop) => getOpenAPISchemaComplexity(0, {
|
|
1485
|
+
...schema,
|
|
1486
|
+
type: prop
|
|
1487
|
+
})));
|
|
1488
|
+
}
|
|
1489
|
+
if (schema.oneOf) {
|
|
1490
|
+
if (schema.oneOf.length === 1) return complexityByComposite("oneOf") + getOpenAPISchemaComplexity(current, schema.oneOf[0]);
|
|
1491
|
+
return current + complexityByComposite("oneOf") + sum(schema.oneOf.map((prop) => getOpenAPISchemaComplexity(0, prop)));
|
|
1492
|
+
}
|
|
1493
|
+
if (schema.anyOf) {
|
|
1494
|
+
if (schema.anyOf.length === 1) return complexityByComposite("anyOf") + getOpenAPISchemaComplexity(current, schema.anyOf[0]);
|
|
1495
|
+
return current + complexityByComposite("anyOf") + sum(schema.anyOf.map((prop) => getOpenAPISchemaComplexity(0, prop)));
|
|
1496
|
+
}
|
|
1497
|
+
if (schema.allOf) {
|
|
1498
|
+
if (schema.allOf.length === 1) return complexityByComposite("allOf") + getOpenAPISchemaComplexity(current, schema.allOf[0]);
|
|
1499
|
+
return current + complexityByComposite("allOf") + sum(schema.allOf.map((prop) => getOpenAPISchemaComplexity(0, prop)));
|
|
1500
|
+
}
|
|
1501
|
+
if (!schema.type) return current;
|
|
1502
|
+
if (isPrimitiveType(schema.type)) {
|
|
1503
|
+
if (schema.enum) return current + complexityByType(schema) + complexityByComposite("enum") + sum(schema.enum.map((prop) => getOpenAPISchemaComplexity(0, prop)));
|
|
1504
|
+
return current + complexityByType(schema);
|
|
1505
|
+
}
|
|
1506
|
+
if (schema.type === "array") {
|
|
1507
|
+
if (schema.items) return complexityByComposite("array") + getOpenAPISchemaComplexity(current, schema.items);
|
|
1508
|
+
return complexityByComposite("array") + getOpenAPISchemaComplexity(current);
|
|
1509
|
+
}
|
|
1510
|
+
if (schema.type === "object" || schema.properties || schema.additionalProperties) {
|
|
1511
|
+
if (schema.properties) {
|
|
1512
|
+
const props = Object.values(schema.properties);
|
|
1513
|
+
current += complexityByComposite("object") + sum(props.map((prop) => getOpenAPISchemaComplexity(0, prop)));
|
|
1514
|
+
} else current += complexityByComposite("empty-object");
|
|
1515
|
+
if (schema.additionalProperties) if (typeof schema.additionalProperties === "object") current += getOpenAPISchemaComplexity(0, schema.additionalProperties);
|
|
1516
|
+
else current += getOpenAPISchemaComplexity(1);
|
|
1517
|
+
}
|
|
1518
|
+
return current;
|
|
1519
|
+
}
|
|
1520
|
+
function complexityByType(schema) {
|
|
1521
|
+
return match(schema.type).with("string", "number", "integer", "boolean", () => 1).otherwise(() => 0);
|
|
1522
|
+
}
|
|
1523
|
+
function complexityByComposite(type) {
|
|
1524
|
+
return match(type).with("oneOf", () => 2).with("anyOf", () => 3).with("allOf", () => 2).with("enum", "array", "empty-object", () => 1).with("object", () => 2).otherwise(() => 0);
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
//#endregion
|
|
1528
|
+
//#region src/generators/core/zod/ZodSchema.class.ts
|
|
1529
|
+
var ZodSchema = class {
|
|
1530
|
+
code;
|
|
1531
|
+
ref;
|
|
1532
|
+
enumRef;
|
|
1533
|
+
children = [];
|
|
1534
|
+
meta;
|
|
1535
|
+
constructor(schema, resolver, meta = { referencedBy: [] }, enumRef) {
|
|
1536
|
+
this.schema = schema;
|
|
1537
|
+
this.resolver = resolver;
|
|
1538
|
+
if (isReferenceObject(schema)) this.ref = schema.$ref;
|
|
1539
|
+
if (enumRef) this.enumRef = enumRef;
|
|
1540
|
+
this.meta = {
|
|
1541
|
+
...meta,
|
|
1542
|
+
referencedBy: [...meta?.referencedBy ?? []]
|
|
1543
|
+
};
|
|
1544
|
+
if (this.ref) this.meta.referencedBy.push(this);
|
|
1545
|
+
}
|
|
1546
|
+
getCodeString(tag, options) {
|
|
1547
|
+
if (!this.ref && this.code) return this.code;
|
|
1548
|
+
if (!this.ref) throw new Error("Zod schema is missing both ref and code");
|
|
1549
|
+
const zodSchemaName = this.resolver?.getZodSchemaNameByRef(this.ref);
|
|
1550
|
+
if (!zodSchemaName) return this.ref;
|
|
1551
|
+
const zodSchemaTag = this.resolver?.getTagByZodSchemaName(zodSchemaName);
|
|
1552
|
+
if (options?.tsNamespaces && zodSchemaTag && zodSchemaTag !== tag) return `${getNamespaceName({
|
|
1553
|
+
type: GenerateType.Models,
|
|
1554
|
+
tag: zodSchemaTag,
|
|
1555
|
+
options
|
|
1556
|
+
})}.${zodSchemaName}`;
|
|
1557
|
+
return zodSchemaName;
|
|
1558
|
+
}
|
|
1559
|
+
get complexity() {
|
|
1560
|
+
return getOpenAPISchemaComplexity(0, this.schema);
|
|
1561
|
+
}
|
|
1562
|
+
assign(code) {
|
|
1563
|
+
this.code = code;
|
|
1564
|
+
return this;
|
|
1565
|
+
}
|
|
1566
|
+
inherit(parent) {
|
|
1567
|
+
if (parent) parent.children.push(this);
|
|
1568
|
+
return this;
|
|
1569
|
+
}
|
|
1570
|
+
};
|
|
1571
|
+
function getParentRef(meta) {
|
|
1572
|
+
if (!meta) return;
|
|
1573
|
+
if (meta.parent?.ref) return meta.parent.ref;
|
|
1574
|
+
return getParentRef(meta.parent?.meta);
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
//#endregion
|
|
1578
|
+
//#region src/generators/core/zod/getZodSchema.ts
|
|
1579
|
+
/**
|
|
1580
|
+
* @see https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#schemaObject
|
|
1581
|
+
* @see https://github.com/colinhacks/zod
|
|
1582
|
+
*/
|
|
1583
|
+
function getZodSchema({ schema, resolver, meta: inheritedMeta, tag }) {
|
|
1584
|
+
const zodSchema = new ZodSchema(schema, resolver, inheritedMeta);
|
|
1585
|
+
const meta = {
|
|
1586
|
+
parent: zodSchema.inherit(inheritedMeta?.parent),
|
|
1587
|
+
referencedBy: [...zodSchema.meta.referencedBy]
|
|
1588
|
+
};
|
|
1589
|
+
const params = {
|
|
1590
|
+
resolver,
|
|
1591
|
+
meta,
|
|
1592
|
+
tag
|
|
1593
|
+
};
|
|
1594
|
+
if (isReferenceObject(schema)) return getReferenceZodSchema({
|
|
1595
|
+
schema,
|
|
1596
|
+
zodSchema,
|
|
1597
|
+
resolver,
|
|
1598
|
+
meta,
|
|
1599
|
+
tag
|
|
1600
|
+
});
|
|
1601
|
+
const arrayZodSchema = getArrayZodSchema({
|
|
1602
|
+
schema,
|
|
1603
|
+
zodSchema,
|
|
1604
|
+
resolver,
|
|
1605
|
+
meta,
|
|
1606
|
+
tag
|
|
1607
|
+
});
|
|
1608
|
+
if (arrayZodSchema) return arrayZodSchema;
|
|
1609
|
+
const oneOfZodSchema = getOneOfZodSchema({
|
|
1610
|
+
schema,
|
|
1611
|
+
zodSchema,
|
|
1612
|
+
resolver,
|
|
1613
|
+
meta,
|
|
1614
|
+
tag
|
|
1615
|
+
});
|
|
1616
|
+
if (oneOfZodSchema) return oneOfZodSchema;
|
|
1617
|
+
const anyOfZodSchema = getAnyOfZodSchema({
|
|
1618
|
+
schema,
|
|
1619
|
+
zodSchema,
|
|
1620
|
+
resolver,
|
|
1621
|
+
meta,
|
|
1622
|
+
tag
|
|
1623
|
+
});
|
|
1624
|
+
if (anyOfZodSchema) return anyOfZodSchema;
|
|
1625
|
+
const allOfZodSchema = getAllOfZodSchema({
|
|
1626
|
+
schema,
|
|
1627
|
+
zodSchema,
|
|
1628
|
+
resolver,
|
|
1629
|
+
meta,
|
|
1630
|
+
tag
|
|
1631
|
+
});
|
|
1632
|
+
if (allOfZodSchema) return allOfZodSchema;
|
|
1633
|
+
const primitiveZodSchema = getPrimitiveZodSchema({
|
|
1634
|
+
schema,
|
|
1635
|
+
zodSchema,
|
|
1636
|
+
resolver,
|
|
1637
|
+
meta,
|
|
1638
|
+
tag
|
|
1639
|
+
});
|
|
1640
|
+
if (primitiveZodSchema) return primitiveZodSchema;
|
|
1641
|
+
const readonly = resolver.options.allReadonly ? ".readonly()" : "";
|
|
1642
|
+
if (isArraySchemaObject(schema)) {
|
|
1643
|
+
if (schema.items) return zodSchema.assign(`z.array(${getZodSchema({
|
|
1644
|
+
...params,
|
|
1645
|
+
schema: schema.items
|
|
1646
|
+
}).getCodeString(tag, resolver.options)}${getZodChain({
|
|
1647
|
+
schema: schema.items,
|
|
1648
|
+
meta: {
|
|
1649
|
+
...meta,
|
|
1650
|
+
isRequired: true
|
|
1651
|
+
},
|
|
1652
|
+
options: resolver.options
|
|
1653
|
+
})})${readonly}`);
|
|
1654
|
+
return zodSchema.assign(`z.array(${ANY_SCHEMA})${readonly}`);
|
|
1655
|
+
}
|
|
1656
|
+
const schemaType = schema.type ? schema.type.toLowerCase() : void 0;
|
|
1657
|
+
if (schemaType === "object" || schema.properties || schema.additionalProperties) {
|
|
1658
|
+
const hasRequiredArray = schema.required && schema.required.length > 0;
|
|
1659
|
+
const isPartial = resolver.options.withImplicitRequiredProps ? false : schema.properties && !schema.required?.length;
|
|
1660
|
+
let properties = "{}";
|
|
1661
|
+
if (schema.properties) properties = `{ ${Object.entries(schema.properties).map(([prop, propSchema]) => {
|
|
1662
|
+
const propMetadata = {
|
|
1663
|
+
...meta,
|
|
1664
|
+
isRequired: isPartial ? true : hasRequiredArray ? schema.required?.includes(prop) : resolver.options.withImplicitRequiredProps,
|
|
1665
|
+
name: prop,
|
|
1666
|
+
isParentPartial: isPartial
|
|
1667
|
+
};
|
|
1668
|
+
let propActualSchema = propSchema;
|
|
1669
|
+
if (isReferenceObject(propSchema) && resolver) {
|
|
1670
|
+
propActualSchema = resolver.getSchemaByRef(propSchema.$ref);
|
|
1671
|
+
if (!propActualSchema) throw new Error(`Schema ${propSchema.$ref} not found`);
|
|
1672
|
+
}
|
|
1673
|
+
const zodSchema = getZodSchema({
|
|
1674
|
+
...params,
|
|
1675
|
+
schema: propSchema,
|
|
1676
|
+
meta: propMetadata
|
|
1677
|
+
});
|
|
1678
|
+
const propZodSchema = zodSchema.getCodeString(tag, resolver.options) + getZodChain({
|
|
1679
|
+
schema: propActualSchema,
|
|
1680
|
+
meta: propMetadata,
|
|
1681
|
+
options: resolver.options
|
|
1682
|
+
});
|
|
1683
|
+
let isCircular = false;
|
|
1684
|
+
const parentRef = getParentRef(inheritedMeta);
|
|
1685
|
+
if (parentRef) isCircular = [...isReferenceObject(propSchema) ? [propSchema.$ref] : [], ...getSchemaRefs(zodSchema, { skipObjectSchema: true })].some((ref) => resolver.dependencyGraph.deepDependencyGraph[ref]?.has(parentRef));
|
|
1686
|
+
return [
|
|
1687
|
+
prop,
|
|
1688
|
+
propZodSchema,
|
|
1689
|
+
isCircular
|
|
1690
|
+
];
|
|
1691
|
+
}).map(([prop, propSchema, isCircular]) => isCircular ? `get ${wrapWithQuotesIfNeeded(prop)}() { return ${propSchema} }` : `${wrapWithQuotesIfNeeded(prop)}: ${propSchema}`).join(", ")} }`;
|
|
1692
|
+
let additionalPropsSchema = "";
|
|
1693
|
+
if (schema.additionalProperties) additionalPropsSchema = `.catchall(${typeof schema.additionalProperties === "object" && Object.keys(schema.additionalProperties).length > 0 ? getZodSchema({
|
|
1694
|
+
...params,
|
|
1695
|
+
schema: schema.additionalProperties
|
|
1696
|
+
}).getCodeString(tag, resolver.options) + getZodChain({
|
|
1697
|
+
schema: schema.additionalProperties,
|
|
1698
|
+
meta: {
|
|
1699
|
+
...meta,
|
|
1700
|
+
isRequired: true
|
|
1701
|
+
},
|
|
1702
|
+
options: resolver.options
|
|
1703
|
+
}) : ANY_SCHEMA})`;
|
|
1704
|
+
const zodObject = `z.object(${properties})${isPartial ? ".partial()" : ""}${additionalPropsSchema}${readonly}`;
|
|
1705
|
+
return zodSchema.assign(zodObject);
|
|
1706
|
+
}
|
|
1707
|
+
if (schemaType === "any") return zodSchema.assign(ANY_SCHEMA);
|
|
1708
|
+
if (schemaType === "null") return zodSchema.assign("z.null()");
|
|
1709
|
+
if (!schemaType) return zodSchema.assign("z.unknown()");
|
|
1710
|
+
throw new Error(`Unsupported schema type: ${schemaType}`);
|
|
1711
|
+
}
|
|
1712
|
+
function getReferenceZodSchema({ schema, zodSchema, resolver, meta, tag }) {
|
|
1713
|
+
if (!isReferenceObject(schema)) return;
|
|
1714
|
+
const refsPath = zodSchema.meta.referencedBy.slice(0, -1).map((prev) => prev.ref ? resolver.getZodSchemaNameByRef(prev.ref) ?? prev.ref : void 0).filter(Boolean);
|
|
1715
|
+
const zodSchemaName = resolver.getZodSchemaNameByRef(schema.$ref);
|
|
1716
|
+
if (refsPath.length > 1 && refsPath.includes(zodSchemaName)) return zodSchema.assign(resolver.getCodeByZodSchemaName(zodSchema.ref));
|
|
1717
|
+
let result = resolver.getCodeByZodSchemaName(schema.$ref);
|
|
1718
|
+
if (!result) {
|
|
1719
|
+
const actualSchema = resolver.getSchemaByRef(schema.$ref);
|
|
1720
|
+
if (!actualSchema) throw new Error(`Schema ${schema.$ref} not found`);
|
|
1721
|
+
result = getZodSchema({
|
|
1722
|
+
schema: actualSchema,
|
|
1723
|
+
resolver,
|
|
1724
|
+
meta,
|
|
1725
|
+
tag
|
|
1726
|
+
}).getCodeString(tag, resolver.options);
|
|
1727
|
+
}
|
|
1728
|
+
if (resolver.getCodeByZodSchemaName(zodSchemaName)) return zodSchema;
|
|
1729
|
+
resolver.setZodSchema(zodSchemaName, result, tag);
|
|
1730
|
+
return zodSchema;
|
|
1731
|
+
}
|
|
1732
|
+
function getOneOfZodSchema({ schema, zodSchema, resolver, meta, tag }) {
|
|
1733
|
+
if (!isSchemaObject(schema) || !schema.oneOf) return;
|
|
1734
|
+
if (schema.oneOf.length === 1) {
|
|
1735
|
+
const type = getZodSchema({
|
|
1736
|
+
schema: schema.oneOf[0],
|
|
1737
|
+
resolver,
|
|
1738
|
+
meta,
|
|
1739
|
+
tag
|
|
1740
|
+
});
|
|
1741
|
+
return zodSchema.assign(type.getCodeString(tag, resolver.options));
|
|
1742
|
+
}
|
|
1743
|
+
const hasMultipleAllOf = schema.oneOf?.some((obj) => isSchemaObject(obj) && (obj?.allOf || []).length > 1);
|
|
1744
|
+
if (schema.discriminator && !hasMultipleAllOf) {
|
|
1745
|
+
const propertyName = schema.discriminator.propertyName;
|
|
1746
|
+
return zodSchema.assign(`
|
|
1747
|
+
z.discriminatedUnion("${propertyName}", [${schema.oneOf.map((schema) => getZodSchema({
|
|
1748
|
+
schema,
|
|
1749
|
+
resolver,
|
|
1750
|
+
meta,
|
|
1751
|
+
tag
|
|
1752
|
+
}).getCodeString(tag, resolver.options)).join(", ")}])
|
|
1753
|
+
`);
|
|
1754
|
+
}
|
|
1755
|
+
return zodSchema.assign(`z.union([${schema.oneOf.map((schema) => getZodSchema({
|
|
1756
|
+
schema,
|
|
1757
|
+
resolver,
|
|
1758
|
+
meta,
|
|
1759
|
+
tag
|
|
1760
|
+
}).getCodeString(tag, resolver.options)).join(", ")}])`);
|
|
1761
|
+
}
|
|
1762
|
+
function getArrayZodSchema({ schema, zodSchema, resolver, meta, tag }) {
|
|
1763
|
+
if (!isSchemaObject(schema) || !Array.isArray(schema.type)) return;
|
|
1764
|
+
if (schema.type.length === 1) return getZodSchema({
|
|
1765
|
+
schema: {
|
|
1766
|
+
...schema,
|
|
1767
|
+
type: schema.type[0]
|
|
1768
|
+
},
|
|
1769
|
+
resolver,
|
|
1770
|
+
meta,
|
|
1771
|
+
tag
|
|
1772
|
+
});
|
|
1773
|
+
return zodSchema.assign(`z.union([${schema.type.map((prop) => getZodSchema({
|
|
1774
|
+
schema: {
|
|
1775
|
+
...schema,
|
|
1776
|
+
type: prop
|
|
1777
|
+
},
|
|
1778
|
+
resolver,
|
|
1779
|
+
meta,
|
|
1780
|
+
tag
|
|
1781
|
+
}).getCodeString(tag, resolver.options)).join(", ")}])`);
|
|
1782
|
+
}
|
|
1783
|
+
function getAnyOfZodSchema({ schema, zodSchema, resolver, meta, tag }) {
|
|
1784
|
+
if (!isSchemaObject(schema) || !schema.anyOf) return;
|
|
1785
|
+
if (schema.anyOf.length === 1) {
|
|
1786
|
+
const type = getZodSchema({
|
|
1787
|
+
schema: schema.anyOf[0],
|
|
1788
|
+
resolver,
|
|
1789
|
+
meta,
|
|
1790
|
+
tag
|
|
1791
|
+
});
|
|
1792
|
+
return zodSchema.assign(type.getCodeString(tag, resolver.options));
|
|
1793
|
+
}
|
|
1794
|
+
const types = schema.anyOf.map((schema) => getZodSchema({
|
|
1795
|
+
schema,
|
|
1796
|
+
resolver,
|
|
1797
|
+
meta,
|
|
1798
|
+
tag
|
|
1799
|
+
})).map((type) => type.getCodeString(tag, resolver.options)).join(", ");
|
|
1800
|
+
return zodSchema.assign(`z.union([${types}])`);
|
|
1801
|
+
}
|
|
1802
|
+
function getAllOfZodSchema({ schema, zodSchema, resolver, meta, tag }) {
|
|
1803
|
+
if (!isSchemaObject(schema) || !schema.allOf) return;
|
|
1804
|
+
if (schema.allOf.length === 1) {
|
|
1805
|
+
const type = getZodSchema({
|
|
1806
|
+
schema: schema.allOf[0],
|
|
1807
|
+
resolver,
|
|
1808
|
+
meta,
|
|
1809
|
+
tag
|
|
1810
|
+
});
|
|
1811
|
+
return zodSchema.assign(type.getCodeString(tag, resolver.options));
|
|
1812
|
+
}
|
|
1813
|
+
const { patchRequiredSchemaInLoop, noRequiredOnlyAllof, composedRequiredSchema } = inferRequiredSchema(schema);
|
|
1814
|
+
const types = noRequiredOnlyAllof.map((schema) => {
|
|
1815
|
+
const type = getZodSchema({
|
|
1816
|
+
schema,
|
|
1817
|
+
resolver,
|
|
1818
|
+
meta,
|
|
1819
|
+
tag
|
|
1820
|
+
});
|
|
1821
|
+
if (resolver) patchRequiredSchemaInLoop(schema, resolver.getSchemaByRef.bind(resolver));
|
|
1822
|
+
return type;
|
|
1823
|
+
});
|
|
1824
|
+
if (composedRequiredSchema.required.length) types.push(getZodSchema({
|
|
1825
|
+
schema: composedRequiredSchema,
|
|
1826
|
+
resolver,
|
|
1827
|
+
meta,
|
|
1828
|
+
tag
|
|
1829
|
+
}));
|
|
1830
|
+
const first = types.at(0);
|
|
1831
|
+
const rest = types.slice(1).map((type) => `...${type.getCodeString(tag, resolver.options)}.shape`).join(", ");
|
|
1832
|
+
return zodSchema.assign(`z.object({ ...${first.getCodeString(tag, resolver.options)}.shape, ${rest} })`);
|
|
1833
|
+
}
|
|
1834
|
+
function getPrimitiveZodSchema({ schema, zodSchema, resolver, meta, tag }) {
|
|
1835
|
+
if (!isSchemaObject(schema)) return;
|
|
1836
|
+
const schemaType = schema.type ? schema.type.toLowerCase() : void 0;
|
|
1837
|
+
if (schemaType && isPrimitiveType(schemaType)) {
|
|
1838
|
+
if (schema.enum) {
|
|
1839
|
+
if (schemaType === "string") return getEnumZodSchema({
|
|
1840
|
+
schema,
|
|
1841
|
+
zodSchema,
|
|
1842
|
+
resolver,
|
|
1843
|
+
meta,
|
|
1844
|
+
tag
|
|
1845
|
+
});
|
|
1846
|
+
if (schema.enum.some((e) => typeof e === "string")) return zodSchema.assign("z.never()");
|
|
1847
|
+
if (schema.enum.length === 1) {
|
|
1848
|
+
const value = schema.enum[0];
|
|
1849
|
+
return zodSchema.assign(`z.literal(${value === null ? "null" : value})`);
|
|
1850
|
+
}
|
|
1851
|
+
return zodSchema.assign(`z.union([${schema.enum.map((value) => `z.literal(${value === null ? "null" : value})`).join(", ")}])`);
|
|
1852
|
+
}
|
|
1853
|
+
return zodSchema.assign(match(schemaType).with("integer", () => match(schema.type).with("integer", () => INT_SCHEMA).otherwise(() => NUMBER_SCHEMA)).with("string", () => match(schema.format).with("binary", () => BLOB_SCHEMA).with("email", () => EMAIL_SCHEMA).with("hostname", "uri", () => URL_SCHEMA).with("uuid", () => UUID_SCHEMA).with("date-time", () => DATETIME_SCHEMA).otherwise(() => STRING_SCHEMA)).otherwise((type) => `z.${type}()`));
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
function getEnumZodSchema({ resolver, schema, zodSchema, meta, tag }) {
|
|
1857
|
+
if (!isSchemaObject(schema)) return;
|
|
1858
|
+
const code = getEnumZodSchemaCode(schema);
|
|
1859
|
+
if (!resolver.options.extractEnums) return zodSchema.assign(code);
|
|
1860
|
+
const enumZodSchema = resolver.getEnumZodSchemaDataByCode(code);
|
|
1861
|
+
if (enumZodSchema) {
|
|
1862
|
+
if (zodSchema.meta.parent?.ref === resolver.getRefByZodSchemaName(enumZodSchema.zodSchemaName)) return zodSchema.assign(enumZodSchema.code);
|
|
1863
|
+
return new ZodSchema({ $ref: resolver.getRefByZodSchemaName(enumZodSchema.zodSchemaName) }, resolver, meta).inherit(zodSchema).assign(code);
|
|
1864
|
+
}
|
|
1865
|
+
const extractedEnumZodSchema = resolver.getExtractedEnumZodSchemaDataByCode(code);
|
|
1866
|
+
if (!extractedEnumZodSchema) return zodSchema.assign(code);
|
|
1867
|
+
if (!extractedEnumZodSchema.zodSchemaName || !extractedEnumZodSchema.tag) throw new Error(`Enum zod schema name or tag not resolved for code: ${code}`);
|
|
1868
|
+
const namespacePrefix = resolver.options.tsNamespaces && extractedEnumZodSchema.tag !== tag ? `${getNamespaceName({
|
|
1869
|
+
type: GenerateType.Models,
|
|
1870
|
+
tag: extractedEnumZodSchema.tag,
|
|
1871
|
+
options: resolver.options
|
|
1872
|
+
})}.` : "";
|
|
1873
|
+
return zodSchema.assign(`${namespacePrefix}${extractedEnumZodSchema.zodSchemaName}`);
|
|
1874
|
+
}
|
|
1875
|
+
function getEnumZodSchemaCode(schema) {
|
|
1876
|
+
return `${ENUM_SCHEMA}([${schema.enum?.map((value) => value === null ? "null" : `"${value}"`).join(", ")}])`;
|
|
1877
|
+
}
|
|
1878
|
+
function getEnumZodSchemaCodeFromEnumNames(enumNames) {
|
|
1879
|
+
return `${ENUM_SCHEMA}([${enumNames.map((value) => `"${value}"`).join(", ")}])`;
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
//#endregion
|
|
1883
|
+
//#region src/generators/core/zod/resolveZodSchemaName.ts
|
|
1884
|
+
const resolverResolveZodSchemaNameCache = /* @__PURE__ */ new WeakMap();
|
|
1885
|
+
function resolveZodSchemaName({ schema, zodSchema, fallbackName, resolver, tag }) {
|
|
1886
|
+
const result = zodSchema.getCodeString();
|
|
1887
|
+
const cacheKey = `${zodSchema.ref ?? ""}|${fallbackName ?? ""}|${tag}|${zodSchema.complexity}|${result}`;
|
|
1888
|
+
let cacheForResolver = resolverResolveZodSchemaNameCache.get(resolver);
|
|
1889
|
+
if (!cacheForResolver) {
|
|
1890
|
+
cacheForResolver = /* @__PURE__ */ new Map();
|
|
1891
|
+
resolverResolveZodSchemaNameCache.set(resolver, cacheForResolver);
|
|
1892
|
+
}
|
|
1893
|
+
const cachedName = cacheForResolver.get(cacheKey);
|
|
1894
|
+
if (cachedName) return cachedName;
|
|
1895
|
+
if ((!isNamedZodSchema(result) || zodSchema.ref === void 0) && fallbackName) {
|
|
1896
|
+
if (zodSchema.complexity < COMPLEXITY_THRESHOLD) return result;
|
|
1897
|
+
const zodSchemaName = getZodSchemaName(fallbackName, resolver.options.schemaSuffix);
|
|
1898
|
+
while (resolver.getCodeByZodSchemaName(zodSchemaName)) if (resolver.getZodSchemaNamesByCompositeCode(result)?.includes(zodSchemaName)) return zodSchemaName;
|
|
1899
|
+
else if (resolver.getCodeByZodSchemaName(zodSchemaName) === zodSchemaName) return zodSchemaName;
|
|
1900
|
+
else throw new Error(`Can't uniquely resolve zod schema name: ${zodSchemaName}`);
|
|
1901
|
+
resolver.setZodSchema(zodSchemaName, result, tag);
|
|
1902
|
+
resolver.addZodSchemaForCompositeCode(result, zodSchema, zodSchemaName, schema);
|
|
1903
|
+
cacheForResolver.set(cacheKey, zodSchemaName);
|
|
1904
|
+
return zodSchemaName;
|
|
1905
|
+
}
|
|
1906
|
+
let resolvedSchema = resolver.getCodeByZodSchemaName(result);
|
|
1907
|
+
if (!resolvedSchema && zodSchema.ref) resolvedSchema = resolver.getCodeByZodSchemaName(resolver.getZodSchemaNameByRef(zodSchema.ref));
|
|
1908
|
+
if (zodSchema.ref && resolvedSchema) {
|
|
1909
|
+
if (getOpenAPISchemaComplexity(0, resolver.getSchemaByRef(zodSchema.ref)) < COMPLEXITY_THRESHOLD) {
|
|
1910
|
+
const resolvedName = resolver.getCodeByZodSchemaName(result);
|
|
1911
|
+
cacheForResolver.set(cacheKey, resolvedName);
|
|
1912
|
+
return resolvedName;
|
|
1913
|
+
}
|
|
1914
|
+
cacheForResolver.set(cacheKey, result);
|
|
1915
|
+
return result;
|
|
1916
|
+
}
|
|
1917
|
+
if (zodSchema.ref) {
|
|
1918
|
+
const resolvedRefName = resolver.getZodSchemaNameByRef(zodSchema.ref);
|
|
1919
|
+
cacheForResolver.set(cacheKey, resolvedRefName);
|
|
1920
|
+
return resolvedRefName;
|
|
1921
|
+
}
|
|
1922
|
+
throw new Error(`Invalid ref: ${zodSchema.ref}`);
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
//#endregion
|
|
1926
|
+
//#region src/generators/core/endpoints/resolveEndpointZodSchema.ts
|
|
1927
|
+
const resolverEndpointZodSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
1928
|
+
function getResolverSchemaCache(resolver) {
|
|
1929
|
+
let schemaCache = resolverEndpointZodSchemaCache.get(resolver);
|
|
1930
|
+
if (!schemaCache) {
|
|
1931
|
+
schemaCache = {
|
|
1932
|
+
byObject: /* @__PURE__ */ new WeakMap(),
|
|
1933
|
+
byRef: /* @__PURE__ */ new Map()
|
|
1934
|
+
};
|
|
1935
|
+
resolverEndpointZodSchemaCache.set(resolver, schemaCache);
|
|
1936
|
+
}
|
|
1937
|
+
return schemaCache;
|
|
1938
|
+
}
|
|
1939
|
+
function getOrCreateSchemaEntries(schemaCache, schema) {
|
|
1940
|
+
if (isReferenceObject(schema)) {
|
|
1941
|
+
let entries = schemaCache.byRef.get(schema.$ref);
|
|
1942
|
+
if (!entries) {
|
|
1943
|
+
entries = /* @__PURE__ */ new Map();
|
|
1944
|
+
schemaCache.byRef.set(schema.$ref, entries);
|
|
1945
|
+
}
|
|
1946
|
+
return entries;
|
|
1947
|
+
}
|
|
1948
|
+
let entries = schemaCache.byObject.get(schema);
|
|
1949
|
+
if (!entries) {
|
|
1950
|
+
entries = /* @__PURE__ */ new Map();
|
|
1951
|
+
schemaCache.byObject.set(schema, entries);
|
|
1952
|
+
}
|
|
1953
|
+
return entries;
|
|
1954
|
+
}
|
|
1955
|
+
function resolveEndpointZodSchema({ resolver, schema, meta, tag, fallbackName, composeBeforeResolve }) {
|
|
1956
|
+
const entries = getOrCreateSchemaEntries(getResolverSchemaCache(resolver), schema);
|
|
1957
|
+
const isRefSchema = isReferenceObject(schema);
|
|
1958
|
+
const normalizedFallbackName = isRefSchema ? "" : fallbackName ?? "";
|
|
1959
|
+
const normalizedTag = isRefSchema ? "" : tag;
|
|
1960
|
+
const metaKey = `required:${Boolean(meta.isRequired)}|name:${meta.name ?? ""}|parentPartial:${Boolean(meta.isParentPartial)}|fallback:${normalizedFallbackName}|tag:${normalizedTag}|compose:${composeBeforeResolve ? 1 : 0}`;
|
|
1961
|
+
const cached = entries.get(metaKey);
|
|
1962
|
+
if (cached) return cached;
|
|
1963
|
+
const zodSchema = getZodSchema({
|
|
1964
|
+
schema,
|
|
1965
|
+
resolver,
|
|
1966
|
+
meta,
|
|
1967
|
+
tag
|
|
1968
|
+
});
|
|
1969
|
+
const schemaObject = resolver.resolveObject(schema);
|
|
1970
|
+
const zodChain = getZodChain({
|
|
1971
|
+
schema: schemaObject,
|
|
1972
|
+
meta: zodSchema.meta,
|
|
1973
|
+
options: resolver.options
|
|
1974
|
+
});
|
|
1975
|
+
const resolved = composeBeforeResolve ? resolveZodSchemaName({
|
|
1976
|
+
schema: schemaObject,
|
|
1977
|
+
zodSchema: zodSchema.assign(zodSchema.getCodeString(tag) + zodChain),
|
|
1978
|
+
fallbackName,
|
|
1979
|
+
resolver,
|
|
1980
|
+
tag
|
|
1981
|
+
}) : `${resolveZodSchemaName({
|
|
1982
|
+
schema: schemaObject,
|
|
1983
|
+
zodSchema,
|
|
1984
|
+
fallbackName,
|
|
1985
|
+
resolver,
|
|
1986
|
+
tag
|
|
1987
|
+
})}${zodChain}`;
|
|
1988
|
+
entries.set(metaKey, resolved);
|
|
1989
|
+
return resolved;
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
//#endregion
|
|
1993
|
+
//#region src/generators/core/endpoints/getEndpointBody.ts
|
|
1994
|
+
function getEndpointBody({ resolver, operation, operationName, isUniqueOperationName, tag }) {
|
|
1995
|
+
const requestBodyObj = resolver.resolveObject(operation.requestBody);
|
|
1996
|
+
if (!requestBodyObj) return;
|
|
1997
|
+
const matchingMediaType = Object.keys(requestBodyObj.content ?? {}).find(isParamMediaTypeAllowed);
|
|
1998
|
+
if (!matchingMediaType) return;
|
|
1999
|
+
const schema = requestBodyObj.content?.[matchingMediaType]?.schema;
|
|
2000
|
+
if (!schema) return;
|
|
2001
|
+
const zodSchema = resolveEndpointZodSchema({
|
|
2002
|
+
resolver,
|
|
2003
|
+
schema,
|
|
2004
|
+
meta: { isRequired: requestBodyObj.required ?? true },
|
|
2005
|
+
tag,
|
|
2006
|
+
fallbackName: getBodyZodSchemaName(getZodSchemaOperationName(operationName, isUniqueOperationName, tag)),
|
|
2007
|
+
composeBeforeResolve: false
|
|
2008
|
+
});
|
|
2009
|
+
return {
|
|
2010
|
+
endpointParameter: {
|
|
2011
|
+
name: BODY_PARAMETER_NAME,
|
|
2012
|
+
type: "Body",
|
|
2013
|
+
description: requestBodyObj.description,
|
|
2014
|
+
zodSchema,
|
|
2015
|
+
bodyObject: requestBodyObj
|
|
2016
|
+
},
|
|
2017
|
+
requestFormat: matchingMediaType
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
//#endregion
|
|
2022
|
+
//#region src/generators/core/endpoints/getEndpointParameter.ts
|
|
2023
|
+
function getEndpointParameter({ resolver, param, operationName, isUniqueOperationName, tag }) {
|
|
2024
|
+
const paramObj = resolver.resolveObject(param);
|
|
2025
|
+
if (!ALLOWED_PATH_IN.includes(paramObj.in)) return;
|
|
2026
|
+
let schema = {};
|
|
2027
|
+
if (paramObj.content) {
|
|
2028
|
+
const mediaTypes = Object.keys(paramObj.content ?? {});
|
|
2029
|
+
const matchingMediaType = mediaTypes.find(isParamMediaTypeAllowed);
|
|
2030
|
+
if (!matchingMediaType) throw new Error(`Unsupported media type for param ${paramObj.name}: ${mediaTypes.join(", ")}`);
|
|
2031
|
+
const mediaTypeObject = paramObj.content?.[matchingMediaType];
|
|
2032
|
+
if (!mediaTypeObject) throw new Error(`No content with media type for param ${paramObj.name}: ${matchingMediaType}`);
|
|
2033
|
+
schema = mediaTypeObject?.schema ?? mediaTypeObject;
|
|
2034
|
+
} else if (paramObj.schema) schema = paramObj.schema;
|
|
2035
|
+
if (resolver.options.withDescription && schema) schema.description = (paramObj.description ?? "").trim();
|
|
2036
|
+
const fallbackName = getParamZodSchemaName(getZodSchemaOperationName(operationName, isUniqueOperationName, tag), paramObj.name);
|
|
2037
|
+
let parameterSortingEnumSchemaName = void 0;
|
|
2038
|
+
if (isSortingParameterObject(paramObj)) {
|
|
2039
|
+
const enumZodSchemaName = getEnumZodSchemaName(fallbackName, resolver.options.enumSuffix, resolver.options.schemaSuffix);
|
|
2040
|
+
const code = getEnumZodSchemaCodeFromEnumNames(paramObj["x-enumNames"]);
|
|
2041
|
+
resolver.setZodSchema(enumZodSchemaName, code, tag);
|
|
2042
|
+
parameterSortingEnumSchemaName = enumZodSchemaName;
|
|
2043
|
+
}
|
|
2044
|
+
const zodSchemaName = resolveEndpointZodSchema({
|
|
2045
|
+
resolver,
|
|
2046
|
+
schema,
|
|
2047
|
+
meta: { isRequired: paramObj.in === "path" ? true : paramObj.required ?? false },
|
|
2048
|
+
tag,
|
|
2049
|
+
fallbackName,
|
|
2050
|
+
composeBeforeResolve: true
|
|
2051
|
+
});
|
|
2052
|
+
return {
|
|
2053
|
+
name: match(paramObj.in).with("path", () => pathParamToVariableName(paramObj.name)).otherwise(() => paramObj.name),
|
|
2054
|
+
type: match(paramObj.in).with("header", () => "Header").with("query", () => "Query").with("path", () => "Path").run(),
|
|
2055
|
+
zodSchema: zodSchemaName,
|
|
2056
|
+
parameterObject: paramObj,
|
|
2057
|
+
parameterSortingEnumSchemaName
|
|
2058
|
+
};
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
//#endregion
|
|
2062
|
+
//#region src/generators/core/endpoints/getEndpointsFromOpenAPIDoc.ts
|
|
2063
|
+
function getEndpointsFromOpenAPIDoc(resolver, profiler) {
|
|
2064
|
+
const endpoints = [];
|
|
2065
|
+
const p = profiler ?? new Profiler(false);
|
|
2066
|
+
for (const context of resolver.getOperationContexts()) endpoints.push(buildEndpointFromOperationContext(resolver, context, p));
|
|
2067
|
+
return endpoints;
|
|
2068
|
+
}
|
|
2069
|
+
function buildEndpointFromOperationContext(resolver, context, profiler) {
|
|
2070
|
+
const p = profiler ?? new Profiler(false);
|
|
2071
|
+
const { path, method, operation, operationName, isUniqueOperationName, tag, parameters, responses } = context;
|
|
2072
|
+
const invalidOperationId = operation.operationId && operation.operationId !== invalidVariableNameCharactersToCamel(operation.operationId);
|
|
2073
|
+
if (operation.operationId && invalidOperationId) resolver.validationErrors.push(getInvalidOperationIdError(operation.operationId));
|
|
2074
|
+
const endpoint = {
|
|
2075
|
+
method,
|
|
2076
|
+
path: replaceHyphenatedPath(path),
|
|
2077
|
+
operationName,
|
|
2078
|
+
description: operation.description,
|
|
2079
|
+
summary: operation.summary,
|
|
2080
|
+
tags: operation.tags?.map(formatTag),
|
|
2081
|
+
requestFormat: JSON_APPLICATION_FORMAT,
|
|
2082
|
+
parameters: [],
|
|
2083
|
+
response: "",
|
|
2084
|
+
errors: [],
|
|
2085
|
+
responseStatusCodes: [],
|
|
2086
|
+
mediaUpload: !!operation["x-media-upload"],
|
|
2087
|
+
mediaDownload: !!operation["x-media-download"]
|
|
2088
|
+
};
|
|
2089
|
+
p.runSync("endpoints.requestBody", () => {
|
|
2090
|
+
if (operation.requestBody) {
|
|
2091
|
+
const body = getEndpointBody({
|
|
2092
|
+
resolver,
|
|
2093
|
+
operation,
|
|
2094
|
+
operationName,
|
|
2095
|
+
isUniqueOperationName,
|
|
2096
|
+
tag
|
|
2097
|
+
});
|
|
2098
|
+
if (body) {
|
|
2099
|
+
endpoint.parameters.push(body.endpointParameter);
|
|
2100
|
+
endpoint.requestFormat = body.requestFormat;
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
});
|
|
2104
|
+
p.runSync("endpoints.params", () => {
|
|
2105
|
+
for (const param of parameters) {
|
|
2106
|
+
const endpointParameter = getEndpointParameter({
|
|
2107
|
+
resolver,
|
|
2108
|
+
param,
|
|
2109
|
+
operationName,
|
|
2110
|
+
isUniqueOperationName,
|
|
2111
|
+
tag
|
|
2112
|
+
});
|
|
2113
|
+
if (endpointParameter) endpoint.parameters.push(endpointParameter);
|
|
2114
|
+
}
|
|
2115
|
+
});
|
|
2116
|
+
p.runSync("endpoints.pathParams", () => {
|
|
2117
|
+
const missingPathParameters = getMissingPathParameters(endpoint);
|
|
2118
|
+
missingPathParameters.forEach((pathParam) => {
|
|
2119
|
+
endpoint.parameters.push(pathParam);
|
|
2120
|
+
});
|
|
2121
|
+
if (missingPathParameters.length > 0) resolver.validationErrors.push(getMissingPathParameterError(missingPathParameters, path));
|
|
2122
|
+
});
|
|
2123
|
+
p.runSync("endpoints.responses", () => {
|
|
2124
|
+
for (const responseData of responses) {
|
|
2125
|
+
const { statusCode, responseObj, matchingMediaType, schema } = responseData;
|
|
2126
|
+
endpoint.responseStatusCodes.push(statusCode);
|
|
2127
|
+
let responseZodSchema;
|
|
2128
|
+
if (matchingMediaType) endpoint.responseFormat = matchingMediaType;
|
|
2129
|
+
else {
|
|
2130
|
+
responseZodSchema = VOID_SCHEMA;
|
|
2131
|
+
if (statusCode === "200") resolver.validationErrors.push(getInvalidStatusCodeError({
|
|
2132
|
+
received: "200",
|
|
2133
|
+
expected: "204"
|
|
2134
|
+
}, operation, endpoint));
|
|
2135
|
+
}
|
|
2136
|
+
if (schema) responseZodSchema = resolveEndpointZodSchema({
|
|
2137
|
+
resolver,
|
|
2138
|
+
schema,
|
|
2139
|
+
meta: { isRequired: true },
|
|
2140
|
+
tag,
|
|
2141
|
+
fallbackName: isReferenceObject(schema) ? void 0 : getResponseZodSchemaName({
|
|
2142
|
+
statusCode,
|
|
2143
|
+
operationName,
|
|
2144
|
+
isUniqueOperationName,
|
|
2145
|
+
tag
|
|
2146
|
+
}),
|
|
2147
|
+
composeBeforeResolve: false
|
|
2148
|
+
});
|
|
2149
|
+
if (responseZodSchema) {
|
|
2150
|
+
const status = Number(statusCode);
|
|
2151
|
+
if (isMainResponseStatus(status) && !endpoint.response) {
|
|
2152
|
+
endpoint.response = responseZodSchema;
|
|
2153
|
+
endpoint.responseObject = responseObj;
|
|
2154
|
+
endpoint.responseDescription = responseObj?.description;
|
|
2155
|
+
} else if (statusCode !== "default" && isErrorStatus(status)) endpoint.errors.push({
|
|
2156
|
+
zodSchema: responseZodSchema,
|
|
2157
|
+
status,
|
|
2158
|
+
description: responseObj?.description
|
|
2159
|
+
});
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
});
|
|
2163
|
+
if (!endpoint.response) endpoint.response = VOID_SCHEMA;
|
|
2164
|
+
p.runSync("endpoints.statusValidation", () => {
|
|
2165
|
+
const mainStatusCodes = Object.keys(operation.responses).map(Number).filter(isMainResponseStatus);
|
|
2166
|
+
if (mainStatusCodes.length > 1) resolver.validationErrors.push(getMultipleSuccessStatusCodesError(mainStatusCodes.map(String), operation, endpoint));
|
|
2167
|
+
});
|
|
2168
|
+
p.runSync("endpoints.acl", () => {
|
|
2169
|
+
endpoint.acl = getEndpointAcl({
|
|
2170
|
+
resolver,
|
|
2171
|
+
endpoint,
|
|
2172
|
+
operation
|
|
2173
|
+
});
|
|
2174
|
+
});
|
|
2175
|
+
if (operation.security?.[0].Authorization && !endpoint.responseStatusCodes.includes("401")) resolver.validationErrors.push(getMissingStatusCodeError("401", operation, endpoint));
|
|
2176
|
+
if (endpoint.acl?.[0] && !endpoint.responseStatusCodes.includes("403")) resolver.validationErrors.push(getMissingStatusCodeError("403", operation, endpoint));
|
|
2177
|
+
return endpoint;
|
|
2178
|
+
}
|
|
2179
|
+
function getMissingPathParameters(endpoint) {
|
|
2180
|
+
return [...endpoint.path.matchAll(/:([a-zA-Z0-9_]+)/g)].map((param) => param[1]).filter((pathParam) => endpoint.parameters.findIndex(({ name }) => name === pathParam) === -1).map((name) => getPathParameterFromName(name));
|
|
2181
|
+
}
|
|
2182
|
+
function getPathParameterFromName(name) {
|
|
2183
|
+
return {
|
|
2184
|
+
name,
|
|
2185
|
+
type: "Path",
|
|
2186
|
+
zodSchema: STRING_SCHEMA,
|
|
2187
|
+
parameterObject: {
|
|
2188
|
+
name,
|
|
2189
|
+
required: true,
|
|
2190
|
+
in: "path",
|
|
2191
|
+
schema: { type: "string" }
|
|
2192
|
+
}
|
|
2193
|
+
};
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
//#endregion
|
|
2197
|
+
//#region src/generators/utils/object.utils.ts
|
|
2198
|
+
/** Pick given properties in object */
|
|
2199
|
+
function pick(obj, paths) {
|
|
2200
|
+
const result = {};
|
|
2201
|
+
Object.keys(obj).forEach((key) => {
|
|
2202
|
+
if (!paths.includes(key)) return;
|
|
2203
|
+
result[key] = obj[key];
|
|
2204
|
+
});
|
|
2205
|
+
return result;
|
|
2206
|
+
}
|
|
2207
|
+
/**
|
|
2208
|
+
* Deep merge two or more objects/arrays recursively.
|
|
2209
|
+
* Arrays are concatenated, objects are merged recursively.
|
|
2210
|
+
* Later arguments take precedence over earlier ones.
|
|
2211
|
+
* Returns a new object/array without mutating the originals.
|
|
2212
|
+
*/
|
|
2213
|
+
function deepMerge(source, ...sources) {
|
|
2214
|
+
if (sources.length === 0) return source;
|
|
2215
|
+
let result = source;
|
|
2216
|
+
for (const source of sources) result = mergeTwoValues(result, source);
|
|
2217
|
+
return result;
|
|
2218
|
+
}
|
|
2219
|
+
/**
|
|
2220
|
+
* Merge two values recursively
|
|
2221
|
+
*/
|
|
2222
|
+
function mergeTwoValues(target, source) {
|
|
2223
|
+
if (source === null || source === void 0) return target;
|
|
2224
|
+
if (target === null || target === void 0) return deepClone(source);
|
|
2225
|
+
if (Array.isArray(target) && Array.isArray(source)) return [...target, ...source];
|
|
2226
|
+
if (isPlainObject(target) && isPlainObject(source)) {
|
|
2227
|
+
const result = {};
|
|
2228
|
+
for (const [key, targetValue] of Object.entries(target)) result[key] = deepClone(targetValue);
|
|
2229
|
+
for (const [key, sourceValue] of Object.entries(source)) {
|
|
2230
|
+
const targetValue = result[key];
|
|
2231
|
+
if (sourceValue === void 0) continue;
|
|
2232
|
+
else if (sourceValue === null) result[key] = sourceValue;
|
|
2233
|
+
else if (isPlainObject(targetValue) && isPlainObject(sourceValue)) result[key] = mergeTwoValues(targetValue, sourceValue);
|
|
2234
|
+
else if (Array.isArray(targetValue) && Array.isArray(sourceValue)) result[key] = [...targetValue, ...sourceValue];
|
|
2235
|
+
else result[key] = deepClone(sourceValue);
|
|
2236
|
+
}
|
|
2237
|
+
return result;
|
|
2238
|
+
}
|
|
2239
|
+
return deepClone(source);
|
|
2240
|
+
}
|
|
2241
|
+
/**
|
|
2242
|
+
* Deep clone an object or array to avoid reference sharing.
|
|
2243
|
+
* Helper function for deepMerge.
|
|
2244
|
+
*/
|
|
2245
|
+
function deepClone(obj) {
|
|
2246
|
+
if (obj === null || obj === void 0 || typeof obj !== "object") return obj;
|
|
2247
|
+
if (Array.isArray(obj)) return obj.map((item) => deepClone(item));
|
|
2248
|
+
if (isPlainObject(obj)) {
|
|
2249
|
+
const result = {};
|
|
2250
|
+
for (const [key, value] of Object.entries(obj)) result[key] = deepClone(value);
|
|
2251
|
+
return result;
|
|
2252
|
+
}
|
|
2253
|
+
return obj;
|
|
2254
|
+
}
|
|
2255
|
+
/**
|
|
2256
|
+
* Check if a value is a plain object (not an array, Date, etc.)
|
|
2257
|
+
*/
|
|
2258
|
+
function isPlainObject(obj) {
|
|
2259
|
+
return obj !== null && typeof obj === "object" && !Array.isArray(obj) && Object.prototype.toString.call(obj) === "[object Object]";
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
//#endregion
|
|
2263
|
+
//#region src/generators/const/js.const.ts
|
|
2264
|
+
const RESERVED_WORDS = [
|
|
2265
|
+
"break",
|
|
2266
|
+
"case",
|
|
2267
|
+
"catch",
|
|
2268
|
+
"class",
|
|
2269
|
+
"const",
|
|
2270
|
+
"continue",
|
|
2271
|
+
"debugger",
|
|
2272
|
+
"default",
|
|
2273
|
+
"delete",
|
|
2274
|
+
"do",
|
|
2275
|
+
"else",
|
|
2276
|
+
"export",
|
|
2277
|
+
"extends",
|
|
2278
|
+
"false",
|
|
2279
|
+
"finally",
|
|
2280
|
+
"for",
|
|
2281
|
+
"function",
|
|
2282
|
+
"if",
|
|
2283
|
+
"import",
|
|
2284
|
+
"in",
|
|
2285
|
+
"instanceof",
|
|
2286
|
+
"new",
|
|
2287
|
+
"null",
|
|
2288
|
+
"return",
|
|
2289
|
+
"super",
|
|
2290
|
+
"switch",
|
|
2291
|
+
"this",
|
|
2292
|
+
"throw",
|
|
2293
|
+
"true",
|
|
2294
|
+
"try",
|
|
2295
|
+
"typeof",
|
|
2296
|
+
"var",
|
|
2297
|
+
"void",
|
|
2298
|
+
"while",
|
|
2299
|
+
"with"
|
|
2300
|
+
];
|
|
2301
|
+
|
|
2302
|
+
//#endregion
|
|
2303
|
+
//#region src/generators/utils/operation.utils.ts
|
|
2304
|
+
function isOperationExcluded(operation, options) {
|
|
2305
|
+
const isDeprecated = operation.deprecated && !options.withDeprecatedEndpoints;
|
|
2306
|
+
const isExcluded = isTagExcluded(getOperationTag(operation, options), options);
|
|
2307
|
+
return isDeprecated || isExcluded;
|
|
2308
|
+
}
|
|
2309
|
+
function getOperationName({ path, method, operation, options, tag, keepOperationTag, keepOperationPrefix }) {
|
|
2310
|
+
const pathOperationName = `${method}${pathToVariableName(path)}`;
|
|
2311
|
+
let operationName = operation.operationId ? invalidVariableNameCharactersToCamel(operation.operationId) : pathOperationName;
|
|
2312
|
+
if (options.removeOperationPrefixEndingWith && keepOperationPrefix) operationName = operationName.split(options.removeOperationPrefixEndingWith).map((split, index) => index === 0 ? split : capitalize(split)).join("");
|
|
2313
|
+
else if (options.removeOperationPrefixEndingWith && !keepOperationPrefix) {
|
|
2314
|
+
const regex = new RegExp(`^.*${options.removeOperationPrefixEndingWith}`);
|
|
2315
|
+
operationName = operationName.replace(regex, "");
|
|
2316
|
+
}
|
|
2317
|
+
if (options.tsNamespaces && !keepOperationTag) {
|
|
2318
|
+
const operationNameWithoutTag = removeWord(operationName, tag);
|
|
2319
|
+
if (operationNameWithoutTag === "") operationName = method.toLowerCase();
|
|
2320
|
+
else if (!RESERVED_WORDS.includes(operationNameWithoutTag)) operationName = operationNameWithoutTag;
|
|
2321
|
+
}
|
|
2322
|
+
return RESERVED_WORDS.includes(operationName) ? pathOperationName : operationName;
|
|
2323
|
+
}
|
|
2324
|
+
function getUniqueOperationName({ operationsByTag, ...params }) {
|
|
2325
|
+
const { operation, options } = params;
|
|
2326
|
+
const tag = options.splitByTags ? getOperationTag(operation, options) : options.defaultTag;
|
|
2327
|
+
const operationName = (keepOperationTag) => {
|
|
2328
|
+
const name = getOperationName({
|
|
2329
|
+
...params,
|
|
2330
|
+
tag,
|
|
2331
|
+
keepOperationTag
|
|
2332
|
+
});
|
|
2333
|
+
if (operationsByTag[tag].filter((operation) => getOperationName({
|
|
2334
|
+
...params,
|
|
2335
|
+
operation,
|
|
2336
|
+
tag,
|
|
2337
|
+
keepOperationTag
|
|
2338
|
+
}) === name).length === 1) return name;
|
|
2339
|
+
};
|
|
2340
|
+
return operationName() ?? operationName(true) ?? getOperationName({
|
|
2341
|
+
...params,
|
|
2342
|
+
tag,
|
|
2343
|
+
keepOperationTag: true,
|
|
2344
|
+
keepOperationPrefix: true
|
|
2345
|
+
});
|
|
2346
|
+
}
|
|
2347
|
+
function getUniqueOperationNamesWithoutSplitByTags(openApiDoc, operationsByTag, options) {
|
|
2348
|
+
const operationNames = [];
|
|
2349
|
+
for (const path in openApiDoc.paths) {
|
|
2350
|
+
if (isPathExcluded(path, options)) continue;
|
|
2351
|
+
const pathItemObj = openApiDoc.paths[path];
|
|
2352
|
+
const pathItem = pick(pathItemObj, ALLOWED_METHODS);
|
|
2353
|
+
for (const method in pathItem) {
|
|
2354
|
+
const operation = pathItem[method];
|
|
2355
|
+
if (!operation || isOperationExcluded(operation, options)) continue;
|
|
2356
|
+
const operationName = getUniqueOperationName({
|
|
2357
|
+
path,
|
|
2358
|
+
method,
|
|
2359
|
+
operation,
|
|
2360
|
+
operationsByTag,
|
|
2361
|
+
options
|
|
2362
|
+
});
|
|
2363
|
+
operationNames.push(operationName);
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
return operationNames;
|
|
2367
|
+
}
|
|
2368
|
+
function getOperationsByTag(openApiDoc, options) {
|
|
2369
|
+
const operationsByTag = {};
|
|
2370
|
+
for (const path in openApiDoc.paths) {
|
|
2371
|
+
if (isPathExcluded(path, options)) continue;
|
|
2372
|
+
const pathItemObj = openApiDoc.paths[path];
|
|
2373
|
+
const pathItem = pick(pathItemObj, ALLOWED_METHODS);
|
|
2374
|
+
for (const method in pathItem) {
|
|
2375
|
+
const operation = pathItem[method];
|
|
2376
|
+
if (!operation || isOperationExcluded(operation, options)) continue;
|
|
2377
|
+
const tag = options.splitByTags ? getOperationTag(operation, options) : options.defaultTag;
|
|
2378
|
+
if (!operationsByTag[tag]) operationsByTag[tag] = [];
|
|
2379
|
+
operationsByTag[tag].push(operation);
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
return operationsByTag;
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
//#endregion
|
|
2386
|
+
//#region src/generators/core/openapi/getOpenAPISchemaDependencyGraph.ts
|
|
2387
|
+
function getOpenAPISchemaDependencyGraph(schemaRef, getSchemaByRef) {
|
|
2388
|
+
const refsDependencyGraph = getRefsDependencyGraph(schemaRef, getSchemaByRef);
|
|
2389
|
+
return {
|
|
2390
|
+
refsDependencyGraph,
|
|
2391
|
+
deepDependencyGraph: getDeepRefsDependencyGraph(schemaRef, refsDependencyGraph)
|
|
2392
|
+
};
|
|
2393
|
+
}
|
|
2394
|
+
function getRefsDependencyGraph(schemaRef, getSchemaByRef) {
|
|
2395
|
+
const visitedRefs = {};
|
|
2396
|
+
const refsDependencyGraph = {};
|
|
2397
|
+
schemaRef.forEach((ref) => getSchemaRefsDependencyGraph({
|
|
2398
|
+
schema: getSchemaByRef(ref),
|
|
2399
|
+
fromRef: ref,
|
|
2400
|
+
getSchemaByRef,
|
|
2401
|
+
visitedRefs,
|
|
2402
|
+
refsDependencyGraph
|
|
2403
|
+
}));
|
|
2404
|
+
return refsDependencyGraph;
|
|
2405
|
+
}
|
|
2406
|
+
function getDeepRefsDependencyGraph(schemaRef, refsDependencyGraph) {
|
|
2407
|
+
const visitedDeepRefs = {};
|
|
2408
|
+
const deepDependencyGraph = {};
|
|
2409
|
+
const visit = (dep, ref) => {
|
|
2410
|
+
deepDependencyGraph[ref].add(dep);
|
|
2411
|
+
if (refsDependencyGraph[dep] && ref !== dep) refsDependencyGraph[dep].forEach((transitive) => {
|
|
2412
|
+
const refName = `${ref}__${transitive}`;
|
|
2413
|
+
if (visitedDeepRefs[refName]) return;
|
|
2414
|
+
visitedDeepRefs[refName] = true;
|
|
2415
|
+
visit(transitive, ref);
|
|
2416
|
+
});
|
|
2417
|
+
};
|
|
2418
|
+
schemaRef.forEach((ref) => {
|
|
2419
|
+
const deps = refsDependencyGraph[ref];
|
|
2420
|
+
if (!deps) return;
|
|
2421
|
+
if (!deepDependencyGraph[ref]) deepDependencyGraph[ref] = /* @__PURE__ */ new Set();
|
|
2422
|
+
deps.forEach((dep) => visit(dep, ref));
|
|
2423
|
+
});
|
|
2424
|
+
return deepDependencyGraph;
|
|
2425
|
+
}
|
|
2426
|
+
function getSchemaRefsDependencyGraph({ schema, fromRef, getSchemaByRef, visitedRefs = {}, refsDependencyGraph = {} }) {
|
|
2427
|
+
const onSchema = (callbackData) => {
|
|
2428
|
+
if (callbackData.type !== "reference" || !callbackData.data) return;
|
|
2429
|
+
const { schema, data } = callbackData;
|
|
2430
|
+
if (!refsDependencyGraph[data.fromRef]) refsDependencyGraph[data.fromRef] = /* @__PURE__ */ new Set();
|
|
2431
|
+
refsDependencyGraph[data.fromRef].add(schema.$ref);
|
|
2432
|
+
if (visitedRefs[schema.$ref]) return true;
|
|
2433
|
+
visitedRefs[data.fromRef] = true;
|
|
2434
|
+
iterateSchema(getSchemaByRef(schema.$ref), {
|
|
2435
|
+
data: { fromRef: schema.$ref },
|
|
2436
|
+
onSchema
|
|
2437
|
+
});
|
|
2438
|
+
};
|
|
2439
|
+
iterateSchema(schema, {
|
|
2440
|
+
data: { fromRef },
|
|
2441
|
+
onSchema
|
|
2442
|
+
});
|
|
2443
|
+
return {
|
|
2444
|
+
visitedRefs,
|
|
2445
|
+
refsDependencyGraph
|
|
2446
|
+
};
|
|
2447
|
+
}
|
|
2448
|
+
|
|
2449
|
+
//#endregion
|
|
2450
|
+
//#region src/generators/core/openapi/getSchemaRefObjs.ts
|
|
2451
|
+
function getSchemaRefObjs(resolver, schema, schemaInfo) {
|
|
2452
|
+
const schemaRefObjs = [];
|
|
2453
|
+
const onSchema = (data) => {
|
|
2454
|
+
if (data.type === "reference") schemaRefObjs.push(data.schema);
|
|
2455
|
+
else if (isReferenceObject(data.parentSchema)) {
|
|
2456
|
+
if (data.type === "property") resolver.validationErrors.push(getInvalidSchemaError(`${schemaInfo} has both reference and properties`));
|
|
2457
|
+
else if (data.type === "additionalProperties") resolver.validationErrors.push(getInvalidSchemaError(`${schemaInfo} has both reference and additionalProperties`));
|
|
2458
|
+
else if (data.type === "array") resolver.validationErrors.push(getInvalidSchemaError(`${schemaInfo} is both reference and array schema`));
|
|
2459
|
+
else if (data.type === "composite") resolver.validationErrors.push(getInvalidSchemaError(`${schemaInfo} has both reference and composite keyword`));
|
|
2460
|
+
}
|
|
2461
|
+
};
|
|
2462
|
+
iterateSchema(schema, { onSchema });
|
|
2463
|
+
return schemaRefObjs;
|
|
2464
|
+
}
|
|
2465
|
+
function getDeepSchemaRefObjs(resolver, schemaRefs) {
|
|
2466
|
+
return schemaRefs.map((schemaRef) => autocorrectRef(schemaRef.$ref)).reduce((acc, schemaRef) => {
|
|
2467
|
+
const refs = resolver.dependencyGraph.deepDependencyGraph[schemaRef];
|
|
2468
|
+
return [
|
|
2469
|
+
...acc,
|
|
2470
|
+
schemaRef,
|
|
2471
|
+
...Array.from(refs ?? [])
|
|
2472
|
+
];
|
|
2473
|
+
}, []);
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
//#endregion
|
|
2477
|
+
//#region src/generators/core/zod/enumExtraction/resolveExtractedEnumZodSchemaNames.ts
|
|
2478
|
+
function resolveExtractedEnumZodSchemaNames(resolver) {
|
|
2479
|
+
resolver.extractedEnumZodSchemaData.forEach((enumData) => {
|
|
2480
|
+
const mostCommonLastSegment = getMostCommonAdjacentCombinationSplit(enumData.meta.zodSchemaNameSegments.map((arr) => arr[arr.length - 1]).filter(Boolean));
|
|
2481
|
+
if (!mostCommonLastSegment) throw new Error(`No common last segment found for enum: ${enumData.code}`);
|
|
2482
|
+
enumData.zodSchemaName = getEnumZodSchemaName(mostCommonLastSegment, resolver.options.enumSuffix, resolver.options.schemaSuffix);
|
|
2483
|
+
});
|
|
2484
|
+
let nameResolutionIterationsCounter = 0;
|
|
2485
|
+
while (nameResolutionIterationsCounter < 5) {
|
|
2486
|
+
if (allExtractedEnumZodSchemaNamesAreUnique(resolver)) break;
|
|
2487
|
+
additionalResolveExtractedEnumZodSchemaName(resolver, nameResolutionIterationsCounter + 2);
|
|
2488
|
+
nameResolutionIterationsCounter++;
|
|
2489
|
+
}
|
|
2490
|
+
if (!allExtractedEnumZodSchemaNamesAreUnique(resolver)) resolver.extractedEnumZodSchemaData.filter((enumData) => !isUnique(resolver, enumData)).forEach((enumData) => {
|
|
2491
|
+
enumData.zodSchemaName = getEnumZodSchemaName(enumData.meta.zodSchemaNameSegments[0].map((name) => sanitizeName(capitalize(name))).join(""), resolver.options.enumSuffix, resolver.options.schemaSuffix);
|
|
2492
|
+
});
|
|
2493
|
+
if (!allExtractedEnumZodSchemaNamesAreUnique(resolver)) throw new Error("Failed to resolve unique names for enum zod schemas");
|
|
2494
|
+
}
|
|
2495
|
+
function allExtractedEnumZodSchemaNamesAreUnique(resolver) {
|
|
2496
|
+
return resolver.extractedEnumZodSchemaData.every((enumData) => isUnique(resolver, enumData));
|
|
2497
|
+
}
|
|
2498
|
+
function additionalResolveExtractedEnumZodSchemaName(resolver, index) {
|
|
2499
|
+
resolver.extractedEnumZodSchemaData.forEach((enumData) => {
|
|
2500
|
+
const enumsDataWithSameName = resolver.extractedEnumZodSchemaData.filter(({ zodSchemaName }) => enumData.zodSchemaName === zodSchemaName);
|
|
2501
|
+
if (enumsDataWithSameName.length === 1) return;
|
|
2502
|
+
suffixWithPreviousSegmentName(enumsDataWithSameName, index);
|
|
2503
|
+
});
|
|
2504
|
+
}
|
|
2505
|
+
function suffixWithPreviousSegmentName(enumsData, index = 2) {
|
|
2506
|
+
enumsData.forEach((data) => {
|
|
2507
|
+
const precedingLastFragments = data.meta.zodSchemaNameSegments.map((arr) => arr[arr.length - index]).filter(Boolean);
|
|
2508
|
+
if (precedingLastFragments.length === 1) data.zodSchemaName = [sanitizeName(capitalize(precedingLastFragments[0])), data.zodSchemaName].filter(Boolean).join("");
|
|
2509
|
+
else {
|
|
2510
|
+
const secondLastFragmentSplit = getMostCommonAdjacentCombinationSplit(precedingLastFragments);
|
|
2511
|
+
data.zodSchemaName = [secondLastFragmentSplit ? sanitizeName(capitalize(secondLastFragmentSplit)) : "", data.zodSchemaName].filter(Boolean).join("");
|
|
2512
|
+
}
|
|
2513
|
+
});
|
|
2514
|
+
}
|
|
2515
|
+
function isUnique(resolver, enumData) {
|
|
2516
|
+
return resolver.extractedEnumZodSchemaData.filter(({ zodSchemaName }) => enumData.zodSchemaName === zodSchemaName).length === 1;
|
|
2517
|
+
}
|
|
2518
|
+
function sanitizeName(name) {
|
|
2519
|
+
return name.replace(/(Dto|DTO|Response|Request)/g, "");
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
//#endregion
|
|
2523
|
+
//#region src/generators/core/zod/enumExtraction/resolveExtractedEnumZodSchemaTags.ts
|
|
2524
|
+
function resolveExtractedEnumZodSchemaTags(resolver) {
|
|
2525
|
+
resolver.extractedEnumZodSchemaData.forEach((enumData) => {
|
|
2526
|
+
const tags = getUniqueArray(enumData.meta.tags);
|
|
2527
|
+
enumData.tag = tags.length === 1 ? tags[0] : resolver.options.defaultTag;
|
|
2528
|
+
});
|
|
2529
|
+
}
|
|
2530
|
+
|
|
2531
|
+
//#endregion
|
|
2532
|
+
//#region src/generators/core/zod/enumExtraction/updateExtractedEnumZodSchemaData.ts
|
|
2533
|
+
function updateExtractedEnumZodSchemaData({ schema, nameSegments = [], includeSelf, ...params }) {
|
|
2534
|
+
if (includeSelf) handleExtractedEnumZodSchemaDataUpdate({
|
|
2535
|
+
schema,
|
|
2536
|
+
nameSegments,
|
|
2537
|
+
...params
|
|
2538
|
+
});
|
|
2539
|
+
const onSchema = (data) => {
|
|
2540
|
+
if (data.type === "reference") return true;
|
|
2541
|
+
const segments = [...data.data?.nameSegments ?? []];
|
|
2542
|
+
if (data.type === "property") segments.push(data.propertyName);
|
|
2543
|
+
handleExtractedEnumZodSchemaDataUpdate({
|
|
2544
|
+
schema: data.schema,
|
|
2545
|
+
nameSegments: [...segments],
|
|
2546
|
+
...params
|
|
2547
|
+
});
|
|
2548
|
+
};
|
|
2549
|
+
iterateSchema(schema, {
|
|
2550
|
+
data: { nameSegments },
|
|
2551
|
+
onSchema
|
|
2552
|
+
});
|
|
2553
|
+
}
|
|
2554
|
+
function handleExtractedEnumZodSchemaDataUpdate({ resolver, schema, schemaRef, schemaInfo, tags, nameSegments = [] }) {
|
|
2555
|
+
if (!schema || isReferenceObject(schema) || !schema.enum) return;
|
|
2556
|
+
const code = getEnumZodSchemaCode(schema);
|
|
2557
|
+
const enumZodSchema = resolver.extractedEnumZodSchemaData.find((data) => data.code === code);
|
|
2558
|
+
if (enumZodSchema) {
|
|
2559
|
+
enumZodSchema.meta.zodSchemaNameSegments.push(nameSegments);
|
|
2560
|
+
enumZodSchema.meta.tags.push(...tags);
|
|
2561
|
+
enumZodSchema.meta.schemaRefs.push(...schemaRef ? [schemaRef] : []);
|
|
2562
|
+
enumZodSchema.meta.schemas.push(...schema ? [schema] : []);
|
|
2563
|
+
} else resolver.extractedEnumZodSchemaData.push({
|
|
2564
|
+
code,
|
|
2565
|
+
meta: {
|
|
2566
|
+
zodSchemaNameSegments: [nameSegments],
|
|
2567
|
+
tags: [...tags],
|
|
2568
|
+
schemaRefs: schemaRef ? [schemaRef] : [],
|
|
2569
|
+
schemas: schema ? [schema] : []
|
|
2570
|
+
}
|
|
2571
|
+
});
|
|
2572
|
+
resolver.validationErrors.push(getNotAllowedInlineEnumError(schemaRef ? `${getSchemaNameByRef(schemaRef)}.${nameSegments[nameSegments.length - 1]}` : schemaInfo ?? nameSegments.join(".")));
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
//#endregion
|
|
2576
|
+
//#region src/generators/core/zod/getZodSchemasFromOpenAPIDoc.ts
|
|
2577
|
+
function getZodSchemasFromOpenAPIDoc(resolver, profiler) {
|
|
2578
|
+
const p = profiler ?? new Profiler(false);
|
|
2579
|
+
const zodSchemas = {};
|
|
2580
|
+
const enumZodSchemas = {};
|
|
2581
|
+
Object.entries(resolver.openApiDoc.components?.schemas ?? {}).forEach(([name, schema]) => p.runSync("zod.extract.schemaEntry", () => {
|
|
2582
|
+
const schemaData = resolver.getSchemaDataByName(name);
|
|
2583
|
+
if (resolver.options.excludeRedundantZodSchemas && (!schemaData || schemaData.deepRefOperations.length === 0 && schemaData.tags.length === 0)) return;
|
|
2584
|
+
const zodSchemaName = getZodSchemaName(name, resolver.options.schemaSuffix);
|
|
2585
|
+
if (zodSchemas[zodSchemaName]) return;
|
|
2586
|
+
const tag = resolver.getTagByZodSchemaName(zodSchemaName);
|
|
2587
|
+
const schemaObject = resolver.resolveObject(schema);
|
|
2588
|
+
if (schemaObject.enum) enumZodSchemas[zodSchemaName] = getEnumZodSchemaCode(schemaObject);
|
|
2589
|
+
else zodSchemas[zodSchemaName] = p.runSync("zod.extract.schemaToCode", () => getZodSchema({
|
|
2590
|
+
schema,
|
|
2591
|
+
resolver,
|
|
2592
|
+
tag
|
|
2593
|
+
}).getCodeString(tag));
|
|
2594
|
+
}));
|
|
2595
|
+
return {
|
|
2596
|
+
zodSchemas,
|
|
2597
|
+
enumZodSchemas
|
|
2598
|
+
};
|
|
2599
|
+
}
|
|
2600
|
+
function getEnumZodSchemasFromOpenAPIDoc(resolver) {
|
|
2601
|
+
const enumZodSchemas = [];
|
|
2602
|
+
Object.entries(resolver.openApiDoc.components?.schemas ?? {}).forEach(([name, schema]) => {
|
|
2603
|
+
const zodSchemaName = getZodSchemaName(name, resolver.options.schemaSuffix);
|
|
2604
|
+
const schemaObject = resolver.resolveObject(schema);
|
|
2605
|
+
if (!enumZodSchemas.find((enumZodSchema) => enumZodSchema.zodSchemaName === zodSchemaName) && schemaObject.enum) enumZodSchemas.push({
|
|
2606
|
+
zodSchemaName,
|
|
2607
|
+
code: getEnumZodSchemaCode(schemaObject)
|
|
2608
|
+
});
|
|
2609
|
+
});
|
|
2610
|
+
return enumZodSchemas;
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
//#endregion
|
|
2614
|
+
//#region src/generators/core/SchemaResolver.class.ts
|
|
2615
|
+
var SchemaResolver = class {
|
|
2616
|
+
schemaData = [];
|
|
2617
|
+
zodSchemaData = [];
|
|
2618
|
+
compositeZodSchemaData = [];
|
|
2619
|
+
schemaRefs;
|
|
2620
|
+
schemaByRef = /* @__PURE__ */ new Map();
|
|
2621
|
+
schemaDataByRef = /* @__PURE__ */ new Map();
|
|
2622
|
+
schemaDataByName = /* @__PURE__ */ new Map();
|
|
2623
|
+
refByZodSchemaName = /* @__PURE__ */ new Map();
|
|
2624
|
+
zodSchemaDataByName = /* @__PURE__ */ new Map();
|
|
2625
|
+
compositeByCode = /* @__PURE__ */ new Map();
|
|
2626
|
+
compositeSchemaByZodSchemaName = /* @__PURE__ */ new Map();
|
|
2627
|
+
dependencyGraph;
|
|
2628
|
+
enumZodSchemas = [];
|
|
2629
|
+
extractedEnumZodSchemaData = [];
|
|
2630
|
+
operationsByTag = {};
|
|
2631
|
+
operationNames = [];
|
|
2632
|
+
operationNameCounts = /* @__PURE__ */ new Map();
|
|
2633
|
+
operationContexts = [];
|
|
2634
|
+
validationErrors = [];
|
|
2635
|
+
get docSchemas() {
|
|
2636
|
+
return this.openApiDoc.components?.schemas ?? {};
|
|
2637
|
+
}
|
|
2638
|
+
constructor(openApiDoc, options, profiler) {
|
|
2639
|
+
this.openApiDoc = openApiDoc;
|
|
2640
|
+
this.options = options;
|
|
2641
|
+
this.profiler = profiler;
|
|
2642
|
+
this.schemaRefs = Object.keys(this.docSchemas).map(getSchemaRef);
|
|
2643
|
+
this.dependencyGraph = getOpenAPISchemaDependencyGraph(this.schemaRefs, this.getSchemaByRef.bind(this));
|
|
2644
|
+
this.enumZodSchemas = getEnumZodSchemasFromOpenAPIDoc(this);
|
|
2645
|
+
this.operationsByTag = getOperationsByTag(openApiDoc, options);
|
|
2646
|
+
this.operationNames = getUniqueOperationNamesWithoutSplitByTags(openApiDoc, this.operationsByTag, options);
|
|
2647
|
+
for (const name of this.operationNames) this.operationNameCounts.set(name, (this.operationNameCounts.get(name) ?? 0) + 1);
|
|
2648
|
+
this.initialize();
|
|
2649
|
+
}
|
|
2650
|
+
getSchemaByRef(ref) {
|
|
2651
|
+
const correctRef = autocorrectRef(ref);
|
|
2652
|
+
const cachedSchema = this.schemaByRef.get(correctRef);
|
|
2653
|
+
if (cachedSchema) return cachedSchema;
|
|
2654
|
+
const schema = this.docSchemas[getSchemaNameByRef(correctRef)];
|
|
2655
|
+
this.schemaByRef.set(correctRef, schema);
|
|
2656
|
+
return schema;
|
|
2657
|
+
}
|
|
2658
|
+
getSchemaDataByName(name) {
|
|
2659
|
+
return this.schemaDataByName.get(name);
|
|
2660
|
+
}
|
|
2661
|
+
getZodSchemaNameByRef(ref) {
|
|
2662
|
+
const zodSchemaName = this.getSchemaDataByRef(autocorrectRef(ref))?.zodSchemaName ?? this.extractedEnumZodSchemaData.find((data) => data.zodSchemaName === ref)?.zodSchemaName;
|
|
2663
|
+
if (!zodSchemaName) throw new Error(`Zod schema not found for ref: ${ref}`);
|
|
2664
|
+
return zodSchemaName;
|
|
2665
|
+
}
|
|
2666
|
+
getRefByZodSchemaName(zodSchemaName) {
|
|
2667
|
+
return this.refByZodSchemaName.get(zodSchemaName);
|
|
2668
|
+
}
|
|
2669
|
+
getTagByZodSchemaName(zodSchemaName) {
|
|
2670
|
+
if (!this.options.splitByTags) return this.options.defaultTag;
|
|
2671
|
+
const extractedEnumZodSchema = this.extractedEnumZodSchemaData.find((data) => data.zodSchemaName === zodSchemaName);
|
|
2672
|
+
if (extractedEnumZodSchema) return formatTag(extractedEnumZodSchema.tag ?? this.options.defaultTag);
|
|
2673
|
+
const schemaRef = this.getRefByZodSchemaName(zodSchemaName);
|
|
2674
|
+
const tags = getUniqueArray(schemaRef ? this.getSchemaDataByRef(schemaRef)?.tags ?? [] : [], this.zodSchemaDataByName.get(zodSchemaName)?.tags ?? []);
|
|
2675
|
+
return formatTag((tags.length === 1 ? tags[0] : this.options.defaultTag) ?? this.options.defaultTag);
|
|
2676
|
+
}
|
|
2677
|
+
getCodeByZodSchemaName(name) {
|
|
2678
|
+
return this.zodSchemaDataByName.get(name)?.code;
|
|
2679
|
+
}
|
|
2680
|
+
getZodSchemaNamesByCompositeCode(code) {
|
|
2681
|
+
return this.compositeByCode.get(code)?.zodSchemas.map((schema) => schema.zodSchemaName);
|
|
2682
|
+
}
|
|
2683
|
+
setZodSchema(name, code, tag) {
|
|
2684
|
+
const zodSchema = this.zodSchemaDataByName.get(name);
|
|
2685
|
+
if (zodSchema) {
|
|
2686
|
+
zodSchema.code = code;
|
|
2687
|
+
zodSchema.tags = (zodSchema.tags ?? []).concat(tag);
|
|
2688
|
+
} else {
|
|
2689
|
+
const newZodSchemaData = {
|
|
2690
|
+
zodSchemaName: name,
|
|
2691
|
+
code,
|
|
2692
|
+
tags: [tag]
|
|
2693
|
+
};
|
|
2694
|
+
this.zodSchemaData.push(newZodSchemaData);
|
|
2695
|
+
this.zodSchemaDataByName.set(name, newZodSchemaData);
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
addZodSchemaForCompositeCode(code, zodSchema, zodSchemaName, schema) {
|
|
2699
|
+
const compositeZodSchema = {
|
|
2700
|
+
zodSchemaName,
|
|
2701
|
+
zodSchema,
|
|
2702
|
+
schema
|
|
2703
|
+
};
|
|
2704
|
+
const compositeData = this.compositeByCode.get(code);
|
|
2705
|
+
if (compositeData) compositeData.zodSchemas.push(compositeZodSchema);
|
|
2706
|
+
else {
|
|
2707
|
+
const newCompositeData = {
|
|
2708
|
+
code,
|
|
2709
|
+
zodSchemas: [compositeZodSchema]
|
|
2710
|
+
};
|
|
2711
|
+
this.compositeZodSchemaData.push(newCompositeData);
|
|
2712
|
+
this.compositeByCode.set(code, newCompositeData);
|
|
2713
|
+
}
|
|
2714
|
+
this.compositeSchemaByZodSchemaName.set(zodSchemaName, {
|
|
2715
|
+
zodSchema,
|
|
2716
|
+
schema
|
|
2717
|
+
});
|
|
2718
|
+
}
|
|
2719
|
+
getCompositeZodSchemaByZodSchemaName(zodSchemaName) {
|
|
2720
|
+
return this.compositeSchemaByZodSchemaName.get(zodSchemaName)?.zodSchema;
|
|
2721
|
+
}
|
|
2722
|
+
getSchemaByCompositeZodSchemaName(compositeZodSchemaName) {
|
|
2723
|
+
return this.compositeSchemaByZodSchemaName.get(compositeZodSchemaName)?.schema;
|
|
2724
|
+
}
|
|
2725
|
+
getEnumZodSchemaDataByCode(code) {
|
|
2726
|
+
return this.enumZodSchemas.find((data) => data.code === code);
|
|
2727
|
+
}
|
|
2728
|
+
getExtractedEnumZodSchemaDataByCode(code) {
|
|
2729
|
+
return this.extractedEnumZodSchemaData.find((data) => data.code === code);
|
|
2730
|
+
}
|
|
2731
|
+
getExtractedEnumZodSchemaNamesReferencedBySchemaRef(schemaRef) {
|
|
2732
|
+
return this.extractedEnumZodSchemaData.reduce((acc, { zodSchemaName, meta }) => {
|
|
2733
|
+
if (zodSchemaName && meta.schemaRefs.includes(schemaRef)) return [...acc, zodSchemaName];
|
|
2734
|
+
return acc;
|
|
2735
|
+
}, []);
|
|
2736
|
+
}
|
|
2737
|
+
getZodSchemas() {
|
|
2738
|
+
const zodSchemas = {};
|
|
2739
|
+
for (const { zodSchemaName, code } of this.zodSchemaData) zodSchemas[zodSchemaName] = code;
|
|
2740
|
+
return zodSchemas;
|
|
2741
|
+
}
|
|
2742
|
+
getExtractedEnumZodSchemas() {
|
|
2743
|
+
const zodSchemas = {};
|
|
2744
|
+
for (const { zodSchemaName, code } of this.extractedEnumZodSchemaData) if (zodSchemaName) zodSchemas[zodSchemaName] = code;
|
|
2745
|
+
return zodSchemas;
|
|
2746
|
+
}
|
|
2747
|
+
resolveObject(obj) {
|
|
2748
|
+
return isReferenceObject(obj) ? this.getSchemaByRef(obj.$ref) : obj;
|
|
2749
|
+
}
|
|
2750
|
+
isSchemaCircular(ref) {
|
|
2751
|
+
return this.dependencyGraph.deepDependencyGraph[ref]?.has(ref);
|
|
2752
|
+
}
|
|
2753
|
+
getCircularSchemaChain(ref, currentRef = ref, chain = [], visited = []) {
|
|
2754
|
+
if (visited.includes(currentRef)) return [];
|
|
2755
|
+
visited.push(currentRef);
|
|
2756
|
+
if (this.dependencyGraph.refsDependencyGraph[currentRef]?.has(ref)) return [
|
|
2757
|
+
...chain,
|
|
2758
|
+
currentRef,
|
|
2759
|
+
ref
|
|
2760
|
+
];
|
|
2761
|
+
return Array.from(this.dependencyGraph.refsDependencyGraph[currentRef]?.values() ?? []).flatMap((childRef) => {
|
|
2762
|
+
const childChain = this.getCircularSchemaChain(ref, childRef, chain, visited);
|
|
2763
|
+
return childChain.length > 0 ? [currentRef, ...childChain] : childChain;
|
|
2764
|
+
});
|
|
2765
|
+
}
|
|
2766
|
+
getBaseUrl() {
|
|
2767
|
+
const serverUrl = this.openApiDoc.servers?.[0]?.url;
|
|
2768
|
+
if (this.options.baseUrl === "" && serverUrl) return serverUrl;
|
|
2769
|
+
return this.options.baseUrl;
|
|
2770
|
+
}
|
|
2771
|
+
isOperationNameUnique(operationName) {
|
|
2772
|
+
return (this.operationNameCounts.get(operationName) ?? 0) <= 1;
|
|
2773
|
+
}
|
|
2774
|
+
getOperationContexts() {
|
|
2775
|
+
return this.operationContexts;
|
|
2776
|
+
}
|
|
2777
|
+
getZodSchemaObj(zodSchemaName) {
|
|
2778
|
+
const ref = this.getRefByZodSchemaName(zodSchemaName);
|
|
2779
|
+
if (ref) return this.getSchemaByRef(ref);
|
|
2780
|
+
const schema = this.getSchemaByCompositeZodSchemaName(zodSchemaName);
|
|
2781
|
+
if (schema) return schema;
|
|
2782
|
+
const enumZodSchemaData = this.getExtractedEnumZodSchemaDataByName(zodSchemaName);
|
|
2783
|
+
if (enumZodSchemaData) {
|
|
2784
|
+
const schemaObject = {};
|
|
2785
|
+
for (const schema of enumZodSchemaData.meta.schemas) Object.assign(schemaObject, this.resolveObject(schema));
|
|
2786
|
+
return schemaObject;
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
getSchemaDataByRef(ref) {
|
|
2790
|
+
return this.schemaDataByRef.get(ref);
|
|
2791
|
+
}
|
|
2792
|
+
getExtractedEnumZodSchemaDataByName(enumZodSchemaName) {
|
|
2793
|
+
return this.extractedEnumZodSchemaData.find(({ zodSchemaName }) => zodSchemaName === enumZodSchemaName);
|
|
2794
|
+
}
|
|
2795
|
+
initialize() {
|
|
2796
|
+
const p = this.profiler ?? new Profiler(false);
|
|
2797
|
+
p.runSync("resolver.init.seedSchemas", () => {
|
|
2798
|
+
this.schemaRefs.forEach((ref) => {
|
|
2799
|
+
const correctRef = autocorrectRef(ref);
|
|
2800
|
+
const name = getSchemaNameByRef(correctRef);
|
|
2801
|
+
const zodSchemaName = getZodSchemaName(name, this.options.schemaSuffix);
|
|
2802
|
+
const data = {
|
|
2803
|
+
ref: correctRef,
|
|
2804
|
+
name,
|
|
2805
|
+
zodSchemaName,
|
|
2806
|
+
tags: [],
|
|
2807
|
+
deepRefOperations: []
|
|
2808
|
+
};
|
|
2809
|
+
this.schemaData.push(data);
|
|
2810
|
+
this.schemaDataByRef.set(correctRef, data);
|
|
2811
|
+
this.schemaDataByName.set(name, data);
|
|
2812
|
+
this.refByZodSchemaName.set(zodSchemaName, correctRef);
|
|
2813
|
+
});
|
|
2814
|
+
});
|
|
2815
|
+
p.runSync("resolver.init.operationsLoop", () => {
|
|
2816
|
+
for (const path in this.openApiDoc.paths) {
|
|
2817
|
+
if (isPathExcluded(path, this.options)) continue;
|
|
2818
|
+
const pathItemObj = this.openApiDoc.paths[path];
|
|
2819
|
+
const pathParameters = this.getParameters(pathItemObj.parameters ?? []);
|
|
2820
|
+
const pathItem = pick(pathItemObj, ALLOWED_METHODS);
|
|
2821
|
+
for (const method in pathItem) {
|
|
2822
|
+
const operation = pathItem[method];
|
|
2823
|
+
if (!operation || isOperationExcluded(operation, this.options)) continue;
|
|
2824
|
+
const tag = getOperationTag(operation, this.options);
|
|
2825
|
+
const operationName = getUniqueOperationName({
|
|
2826
|
+
path,
|
|
2827
|
+
method,
|
|
2828
|
+
operation,
|
|
2829
|
+
operationsByTag: this.operationsByTag,
|
|
2830
|
+
options: this.options
|
|
2831
|
+
});
|
|
2832
|
+
const isUniqueOperationName = this.isOperationNameUnique(operationName);
|
|
2833
|
+
const parameters = p.runSync("resolver.init.parameters.mergeResolve", () => Object.entries({
|
|
2834
|
+
...pathParameters,
|
|
2835
|
+
...this.getParameters(operation.parameters ?? [])
|
|
2836
|
+
}).map(([, param]) => this.resolveObject(param)));
|
|
2837
|
+
const responses = p.runSync("resolver.init.responses.prepare", () => Object.entries(operation.responses).map(([statusCode, response]) => {
|
|
2838
|
+
const responseObj = this.resolveObject(response);
|
|
2839
|
+
const matchingMediaType = Object.keys(responseObj?.content ?? {}).find(isMediaTypeAllowed);
|
|
2840
|
+
return {
|
|
2841
|
+
statusCode,
|
|
2842
|
+
responseObj,
|
|
2843
|
+
matchingMediaType,
|
|
2844
|
+
schema: matchingMediaType ? responseObj.content?.[matchingMediaType]?.schema : void 0
|
|
2845
|
+
};
|
|
2846
|
+
}));
|
|
2847
|
+
const zodSchemaOperationName = snakeToCamel(getZodSchemaOperationName(operationName, isUniqueOperationName, tag));
|
|
2848
|
+
const schemaRefObjs = [];
|
|
2849
|
+
p.runSync("resolver.init.parameters.refs", () => {
|
|
2850
|
+
parameters.forEach((parameter) => {
|
|
2851
|
+
const parameterObject = this.resolveObject(parameter);
|
|
2852
|
+
const parameterSchema = parameterObject.schema;
|
|
2853
|
+
const schemaInfo = `Operation ${operation.operationId ?? path} parameter ${parameterObject.name}`;
|
|
2854
|
+
schemaRefObjs.push(...getSchemaRefObjs(this, parameterSchema, schemaInfo));
|
|
2855
|
+
if (this.options.extractEnums) updateExtractedEnumZodSchemaData({
|
|
2856
|
+
resolver: this,
|
|
2857
|
+
schema: parameterSchema,
|
|
2858
|
+
schemaInfo,
|
|
2859
|
+
tags: [tag],
|
|
2860
|
+
nameSegments: [zodSchemaOperationName, parameterObject.name],
|
|
2861
|
+
includeSelf: true
|
|
2862
|
+
});
|
|
2863
|
+
});
|
|
2864
|
+
});
|
|
2865
|
+
p.runSync("resolver.init.requestBody.refs", () => {
|
|
2866
|
+
if (operation.requestBody) {
|
|
2867
|
+
const requestBodyObj = this.resolveObject(operation.requestBody);
|
|
2868
|
+
const matchingMediaType = Object.keys(requestBodyObj.content ?? {}).find(isParamMediaTypeAllowed);
|
|
2869
|
+
if (matchingMediaType) {
|
|
2870
|
+
const matchingMediaSchema = requestBodyObj.content?.[matchingMediaType]?.schema;
|
|
2871
|
+
const schemaInfo = `Operation ${operation.operationId} request body`;
|
|
2872
|
+
schemaRefObjs.push(...getSchemaRefObjs(this, matchingMediaSchema, schemaInfo));
|
|
2873
|
+
if (this.options.extractEnums) updateExtractedEnumZodSchemaData({
|
|
2874
|
+
resolver: this,
|
|
2875
|
+
schema: matchingMediaSchema,
|
|
2876
|
+
schemaInfo,
|
|
2877
|
+
tags: [tag],
|
|
2878
|
+
nameSegments: [getBodyZodSchemaName(zodSchemaOperationName)]
|
|
2879
|
+
});
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
});
|
|
2883
|
+
p.runSync("resolver.init.responses.refs", () => {
|
|
2884
|
+
for (const responseData of responses) {
|
|
2885
|
+
if (!responseData.matchingMediaType) continue;
|
|
2886
|
+
const schemaInfo = `Operation ${operation.operationId} response body`;
|
|
2887
|
+
schemaRefObjs.push(...getSchemaRefObjs(this, responseData.schema, schemaInfo));
|
|
2888
|
+
if (this.options.extractEnums) updateExtractedEnumZodSchemaData({
|
|
2889
|
+
resolver: this,
|
|
2890
|
+
schema: responseData.schema,
|
|
2891
|
+
schemaInfo,
|
|
2892
|
+
tags: [tag],
|
|
2893
|
+
nameSegments: [getResponseZodSchemaName({
|
|
2894
|
+
statusCode: responseData.statusCode,
|
|
2895
|
+
operationName,
|
|
2896
|
+
isUniqueOperationName,
|
|
2897
|
+
tag
|
|
2898
|
+
})]
|
|
2899
|
+
});
|
|
2900
|
+
}
|
|
2901
|
+
});
|
|
2902
|
+
const deepRefs = p.runSync("resolver.init.deepRefs", () => getDeepSchemaRefObjs(this, schemaRefObjs));
|
|
2903
|
+
const operationContext = {
|
|
2904
|
+
path,
|
|
2905
|
+
method,
|
|
2906
|
+
operation,
|
|
2907
|
+
tag,
|
|
2908
|
+
operationName,
|
|
2909
|
+
isUniqueOperationName,
|
|
2910
|
+
parameters,
|
|
2911
|
+
deepRefs,
|
|
2912
|
+
responses
|
|
2913
|
+
};
|
|
2914
|
+
this.operationContexts.push(operationContext);
|
|
2915
|
+
deepRefs.forEach((schemaRef) => {
|
|
2916
|
+
const schemaData = this.getSchemaDataByRef(schemaRef);
|
|
2917
|
+
if (schemaData) {
|
|
2918
|
+
schemaData.tags.push(tag);
|
|
2919
|
+
schemaData.deepRefOperations.push(operation);
|
|
2920
|
+
}
|
|
2921
|
+
});
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
});
|
|
2925
|
+
if (this.options.extractEnums) p.runSync("resolver.init.enums.finalize", () => {
|
|
2926
|
+
this.schemaRefs.forEach((ref) => {
|
|
2927
|
+
const schemaRef = autocorrectRef(ref);
|
|
2928
|
+
updateExtractedEnumZodSchemaData({
|
|
2929
|
+
resolver: this,
|
|
2930
|
+
schema: this.getSchemaByRef(schemaRef),
|
|
2931
|
+
schemaRef,
|
|
2932
|
+
tags: this.getSchemaDataByRef(schemaRef)?.tags ?? [],
|
|
2933
|
+
nameSegments: [getSchemaNameByRef(schemaRef)]
|
|
2934
|
+
});
|
|
2935
|
+
});
|
|
2936
|
+
resolveExtractedEnumZodSchemaTags(this);
|
|
2937
|
+
this.handleDuplicateEnumZodSchemas();
|
|
2938
|
+
resolveExtractedEnumZodSchemaNames(this);
|
|
2939
|
+
});
|
|
2940
|
+
}
|
|
2941
|
+
handleDuplicateEnumZodSchemas() {
|
|
2942
|
+
const codes = new Set(this.enumZodSchemas.map(({ code }) => code));
|
|
2943
|
+
const duplicates = this.enumZodSchemas.filter(({ code }) => codes.has(code));
|
|
2944
|
+
this.schemaData.forEach((schemaData) => {
|
|
2945
|
+
const duplicateCode = duplicates.find(({ zodSchemaName }) => zodSchemaName === schemaData.zodSchemaName)?.code;
|
|
2946
|
+
if (!duplicateCode) return;
|
|
2947
|
+
const duplicate = this.extractedEnumZodSchemaData.find(({ code }) => code === duplicateCode);
|
|
2948
|
+
if (!duplicate || this.getEnumZodSchemaDataByCode(duplicate.code)?.zodSchemaName !== schemaData.zodSchemaName) return;
|
|
2949
|
+
schemaData.tags.push(...duplicate.meta.tags ?? []);
|
|
2950
|
+
duplicate.meta.schemaRefs.forEach((ref) => {
|
|
2951
|
+
if (!this.dependencyGraph.refsDependencyGraph[ref]) this.dependencyGraph.refsDependencyGraph[ref] = /* @__PURE__ */ new Set();
|
|
2952
|
+
this.dependencyGraph.refsDependencyGraph[ref].add(schemaData.ref);
|
|
2953
|
+
if (!this.dependencyGraph.deepDependencyGraph[ref]) this.dependencyGraph.deepDependencyGraph[ref] = /* @__PURE__ */ new Set();
|
|
2954
|
+
this.dependencyGraph.deepDependencyGraph[ref].add(schemaData.ref);
|
|
2955
|
+
});
|
|
2956
|
+
});
|
|
2957
|
+
this.extractedEnumZodSchemaData.splice(0, this.extractedEnumZodSchemaData.length, ...this.extractedEnumZodSchemaData.filter(({ code }) => !codes.has(code)));
|
|
2958
|
+
}
|
|
2959
|
+
getParameters(parameters) {
|
|
2960
|
+
return Object.fromEntries((parameters ?? []).map((param) => [isReferenceObject(param) ? param.$ref : param.name, param]));
|
|
2961
|
+
}
|
|
2962
|
+
};
|
|
2963
|
+
|
|
2964
|
+
//#endregion
|
|
2965
|
+
//#region src/generators/utils/sort.utils.ts
|
|
2966
|
+
/** @see https://gist.github.com/RubyTuesdayDONO/5006455 */
|
|
2967
|
+
function topologicalSort(graph) {
|
|
2968
|
+
const sorted = [];
|
|
2969
|
+
const visited = {};
|
|
2970
|
+
function visit(name, ancestors) {
|
|
2971
|
+
if (!Array.isArray(ancestors)) ancestors = [];
|
|
2972
|
+
ancestors.push(name);
|
|
2973
|
+
visited[name] = true;
|
|
2974
|
+
if (graph[name]) graph[name].forEach((dep) => {
|
|
2975
|
+
if (ancestors.includes(dep)) return;
|
|
2976
|
+
if (visited[dep]) return;
|
|
2977
|
+
visit(dep, ancestors.slice(0));
|
|
2978
|
+
});
|
|
2979
|
+
if (!sorted.includes(name)) sorted.push(name);
|
|
2980
|
+
}
|
|
2981
|
+
Object.keys(graph).forEach((name) => visit(name, []));
|
|
2982
|
+
return sorted;
|
|
2983
|
+
}
|
|
2984
|
+
/** Sort object keys using a reference order array, sort keys not in reference order in lasts positions */
|
|
2985
|
+
function sortObjKeysFromArray(obj, orderedKeys) {
|
|
2986
|
+
const entries = Object.entries(obj);
|
|
2987
|
+
const sortedEntries = entries.filter(([key]) => orderedKeys.includes(key)).toSorted(([a], [b]) => orderedKeys.indexOf(a) - orderedKeys.indexOf(b)).concat(entries.filter(([key]) => !orderedKeys.includes(key)));
|
|
2988
|
+
return Object.fromEntries(sortedEntries);
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
//#endregion
|
|
2992
|
+
//#region src/generators/core/zod/sortZodSchemasByTopology.ts
|
|
2993
|
+
function sortZodSchemasByTopology(resolver, zodSchemas) {
|
|
2994
|
+
return sortObjKeysFromArray(zodSchemas, topologicalSort(resolver.dependencyGraph.deepDependencyGraph).map((ref) => resolver.getZodSchemaNameByRef(ref)));
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2997
|
+
//#endregion
|
|
2998
|
+
//#region src/generators/core/getDataFromOpenAPIDoc.ts
|
|
2999
|
+
function getDataFromOpenAPIDoc(openApiDoc, options, profiler) {
|
|
3000
|
+
const p = profiler ?? new Profiler(false);
|
|
3001
|
+
const resolver = p.runSync("data.resolver.init", () => new SchemaResolver(openApiDoc, options, p));
|
|
3002
|
+
const endpoints = p.runSync("data.endpoints.extract", () => getEndpointsFromOpenAPIDoc(resolver, p));
|
|
3003
|
+
const zodSchemasFromDocSchemas = p.runSync("data.zod.extract", () => getZodSchemasFromOpenAPIDoc(resolver, p));
|
|
3004
|
+
let zodSchemas = {
|
|
3005
|
+
...zodSchemasFromDocSchemas.zodSchemas,
|
|
3006
|
+
...resolver.getZodSchemas(),
|
|
3007
|
+
...zodSchemasFromDocSchemas.enumZodSchemas
|
|
3008
|
+
};
|
|
3009
|
+
zodSchemas = p.runSync("data.zod.sortTopology", () => sortZodSchemasByTopology(resolver, zodSchemas));
|
|
3010
|
+
zodSchemas = {
|
|
3011
|
+
...resolver.getExtractedEnumZodSchemas(),
|
|
3012
|
+
...zodSchemas
|
|
3013
|
+
};
|
|
3014
|
+
return {
|
|
3015
|
+
resolver,
|
|
3016
|
+
data: p.runSync("data.splitByTags", () => splitDataByTags({
|
|
3017
|
+
resolver,
|
|
3018
|
+
endpoints,
|
|
3019
|
+
zodSchemas,
|
|
3020
|
+
options
|
|
3021
|
+
}))
|
|
3022
|
+
};
|
|
3023
|
+
}
|
|
3024
|
+
function splitDataByTags({ resolver, endpoints, zodSchemas, options }) {
|
|
3025
|
+
const data = /* @__PURE__ */ new Map();
|
|
3026
|
+
if (!options.splitByTags) {
|
|
3027
|
+
data.set(options.defaultTag, {
|
|
3028
|
+
endpoints,
|
|
3029
|
+
zodSchemas
|
|
3030
|
+
});
|
|
3031
|
+
return data;
|
|
3032
|
+
}
|
|
3033
|
+
endpoints.forEach((endpoint) => {
|
|
3034
|
+
getTagElement(getEndpointTag(endpoint, options), data).endpoints.push(endpoint);
|
|
3035
|
+
});
|
|
3036
|
+
Object.entries(zodSchemas).forEach(([zodSchemaName, zodSchemaCode]) => {
|
|
3037
|
+
const tag = options.modelsInCommon ? options.defaultTag : resolver.getTagByZodSchemaName(zodSchemaName);
|
|
3038
|
+
if (tag) getTagElement(tag, data).zodSchemas[zodSchemaName] = zodSchemaCode;
|
|
3039
|
+
});
|
|
3040
|
+
return data;
|
|
3041
|
+
}
|
|
3042
|
+
function getTagElement(tag, data) {
|
|
3043
|
+
if (!data.has(tag)) data.set(tag, {
|
|
3044
|
+
endpoints: [],
|
|
3045
|
+
zodSchemas: {}
|
|
3046
|
+
});
|
|
3047
|
+
return data.get(tag);
|
|
3048
|
+
}
|
|
3049
|
+
|
|
3050
|
+
//#endregion
|
|
3051
|
+
//#region src/generators/utils/file.utils.ts
|
|
3052
|
+
function readFileSync(filePath) {
|
|
3053
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
3054
|
+
const candidates = [
|
|
3055
|
+
path.resolve(process.cwd(), filePath),
|
|
3056
|
+
path.resolve(moduleDir, "../../../", filePath),
|
|
3057
|
+
path.resolve(moduleDir, "../", filePath)
|
|
3058
|
+
];
|
|
3059
|
+
for (const candidatePath of candidates) if (fs.existsSync(candidatePath)) return fs.readFileSync(candidatePath, "utf-8");
|
|
3060
|
+
throw new Error(`Cannot read file: ${filePath}`);
|
|
3061
|
+
}
|
|
3062
|
+
function readAssetSync(fileName) {
|
|
3063
|
+
return readFileSync(`src/assets/${fileName}`);
|
|
3064
|
+
}
|
|
3065
|
+
function getOutputFileName({ output, fileName }) {
|
|
3066
|
+
return `${output}/${fileName}`;
|
|
3067
|
+
}
|
|
3068
|
+
function writeFileWithDirSync(file, data) {
|
|
3069
|
+
const dir = path.dirname(file);
|
|
3070
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
3071
|
+
if (fs.existsSync(file)) {
|
|
3072
|
+
if (fs.readFileSync(file, "utf-8") === data) return;
|
|
3073
|
+
}
|
|
3074
|
+
fs.writeFileSync(file, data, "utf-8");
|
|
3075
|
+
}
|
|
3076
|
+
function writeFileSync$1({ fileName, content }) {
|
|
3077
|
+
writeFileWithDirSync(fileName, content);
|
|
3078
|
+
}
|
|
3079
|
+
function writeGenerateFileData(filesData) {
|
|
3080
|
+
filesData.forEach(writeFileSync$1);
|
|
3081
|
+
}
|
|
3082
|
+
|
|
3083
|
+
//#endregion
|
|
3084
|
+
//#region src/generators/generate/generateAcl.ts
|
|
3085
|
+
function generateAcl({ resolver, data, tag }) {
|
|
3086
|
+
const aclData = getAclData({
|
|
3087
|
+
resolver,
|
|
3088
|
+
data,
|
|
3089
|
+
tag
|
|
3090
|
+
});
|
|
3091
|
+
if (!aclData) return;
|
|
3092
|
+
const { hasAdditionalAbilityImports, modelsImports, endpoints } = aclData;
|
|
3093
|
+
const caslAbilityTupleImport = {
|
|
3094
|
+
bindings: [CASL_ABILITY_BINDING.abilityTuple, ...hasAdditionalAbilityImports ? [CASL_ABILITY_BINDING.forcedSubject, CASL_ABILITY_BINDING.subject] : []],
|
|
3095
|
+
from: CASL_ABILITY_IMPORT.from
|
|
3096
|
+
};
|
|
3097
|
+
const lines = [];
|
|
3098
|
+
lines.push(renderImport$5(caslAbilityTupleImport));
|
|
3099
|
+
for (const modelsImport of modelsImports) lines.push(renderImport$5(modelsImport));
|
|
3100
|
+
lines.push("");
|
|
3101
|
+
if (resolver.options.tsNamespaces) lines.push(`export namespace ${getNamespaceName({
|
|
3102
|
+
type: GenerateType.Acl,
|
|
3103
|
+
tag,
|
|
3104
|
+
options: resolver.options
|
|
3105
|
+
})} {`);
|
|
3106
|
+
for (const endpoint of endpoints) {
|
|
3107
|
+
lines.push(renderAbilityFunction(endpoint));
|
|
3108
|
+
lines.push("");
|
|
3109
|
+
}
|
|
3110
|
+
if (resolver.options.tsNamespaces) lines.push("}");
|
|
3111
|
+
return lines.join("\n").trimEnd() + "\n";
|
|
3112
|
+
}
|
|
3113
|
+
function generateAppAcl({ resolver, data }) {
|
|
3114
|
+
const { appAbilitiesType, hasAdditionalAbilityImports, modelsImports } = getAppAbilitiesType({
|
|
3115
|
+
resolver,
|
|
3116
|
+
data
|
|
3117
|
+
});
|
|
3118
|
+
const caslAbilityTupleImport = {
|
|
3119
|
+
bindings: [
|
|
3120
|
+
CASL_ABILITY_BINDING.pureAbility,
|
|
3121
|
+
CASL_ABILITY_BINDING.abilityTuple,
|
|
3122
|
+
...!appAbilitiesType ? [CASL_ABILITY_BINDING.subjectType] : [],
|
|
3123
|
+
...hasAdditionalAbilityImports ? [CASL_ABILITY_BINDING.forcedSubject] : []
|
|
3124
|
+
],
|
|
3125
|
+
from: CASL_ABILITY_IMPORT.from
|
|
3126
|
+
};
|
|
3127
|
+
const lines = [];
|
|
3128
|
+
lines.push(renderImport$5(caslAbilityTupleImport));
|
|
3129
|
+
for (const modelsImport of modelsImports) lines.push(renderImport$5(modelsImport));
|
|
3130
|
+
lines.push("");
|
|
3131
|
+
if (appAbilitiesType) {
|
|
3132
|
+
lines.push(`export type ${ACL_APP_ABILITIES} = `);
|
|
3133
|
+
for (const [action, subjects] of Object.entries(appAbilitiesType)) lines.push(`| ${CASL_ABILITY_BINDING.abilityTuple}<"${action}", ${subjects.join(" | ")}>`);
|
|
3134
|
+
} else lines.push(`export type ${ACL_APP_ABILITIES} = ${CASL_ABILITY_BINDING.abilityTuple}<string, ${CASL_ABILITY_BINDING.subjectType}>;`);
|
|
3135
|
+
lines.push("");
|
|
3136
|
+
lines.push(`export type AppAbility = PureAbility<${ACL_APP_ABILITIES}>;`);
|
|
3137
|
+
return lines.join("\n");
|
|
3138
|
+
}
|
|
3139
|
+
function renderImport$5(importData) {
|
|
3140
|
+
return `import ${[...importData.defaultImport ? [importData.defaultImport] : [], ...importData.bindings ? [`{ ${importData.bindings.join(", ")} }`] : []].join(", ")} from "${importData.from}";`;
|
|
3141
|
+
}
|
|
3142
|
+
function renderAbilityFunction(endpoint) {
|
|
3143
|
+
const abilityConditionsTypes = getAbilityConditionsTypes(endpoint) ?? [];
|
|
3144
|
+
const hasConditions = hasAbilityConditions(endpoint);
|
|
3145
|
+
const lines = [];
|
|
3146
|
+
const abilityQuery = endpoint.method === "get" ? endpoint.mediaDownload ? `\`${getQueryName(endpoint)}\` query or \`${getQueryName(endpoint, true)}\` mutation` : `\`${getQueryName(endpoint)}\` query` : `\`${getQueryName(endpoint)}\` mutation`;
|
|
3147
|
+
lines.push("/**");
|
|
3148
|
+
lines.push(` * Use for ${abilityQuery} ability. ${hasConditions ? "For global ability, omit the object parameter." : ""}${getAbilityDescription(endpoint) ? "" : ""}`);
|
|
3149
|
+
if (getAbilityDescription(endpoint)) lines.push(` * @description ${getAbilityDescription(endpoint)}`);
|
|
3150
|
+
if (hasConditions) for (const propertyType of abilityConditionsTypes) lines.push(` * @param { ${(propertyType.type ?? "") + (propertyType.zodSchemaName ?? "")} } object.${propertyType.name} ${propertyType.name} from ${propertyType.info}`);
|
|
3151
|
+
lines.push(` * @returns { AbilityTuple } An ability tuple indicating the user's ability to use ${abilityQuery}`);
|
|
3152
|
+
lines.push(" */");
|
|
3153
|
+
lines.push(`export const ${getAbilityFunctionName(endpoint)} = (`);
|
|
3154
|
+
if (hasConditions) lines.push(` object?: { ${abilityConditionsTypes.map((propertyType) => `${propertyType.name}${propertyType.required ? "" : "?"}: ${(propertyType.type ?? "") + (propertyType.zodSchemaName ?? "")}, `).join("")} } `);
|
|
3155
|
+
lines.push(") => [");
|
|
3156
|
+
lines.push(` "${getAbilityAction(endpoint)}",`);
|
|
3157
|
+
lines.push(` ${hasConditions ? `object ? subject("${getAbilitySubject(endpoint)}", object) : "${getAbilitySubject(endpoint)}"` : `"${getAbilitySubject(endpoint)}"`}`);
|
|
3158
|
+
lines.push(`] as ${CASL_ABILITY_BINDING.abilityTuple}<"${getAbilityAction(endpoint)}", ${getAbilitySubjectTypes(endpoint).join(" | ")}>;`);
|
|
3159
|
+
return lines.join("\n");
|
|
3160
|
+
}
|
|
3161
|
+
|
|
3162
|
+
//#endregion
|
|
3163
|
+
//#region src/generators/const/buildConfigs.const.ts
|
|
3164
|
+
const BUILD_CONFIG_SUFFIX = "config";
|
|
3165
|
+
|
|
3166
|
+
//#endregion
|
|
3167
|
+
//#region src/generators/utils/generate/generate.configs.utils.ts
|
|
3168
|
+
function getBuilderConfigs({ data, tag, resolver }) {
|
|
3169
|
+
const endpoints = data.get(tag)?.endpoints;
|
|
3170
|
+
if (!endpoints || endpoints.length === 0) return {
|
|
3171
|
+
configs: [],
|
|
3172
|
+
hasZodImport: false,
|
|
3173
|
+
modelsImports: [],
|
|
3174
|
+
queriesImports: [],
|
|
3175
|
+
aclImports: []
|
|
3176
|
+
};
|
|
3177
|
+
const extendedEndpoints = endpoints.map((endpoint) => ({
|
|
3178
|
+
...endpoint,
|
|
3179
|
+
pathSegments: getPathSegments(endpoint.path)
|
|
3180
|
+
}));
|
|
3181
|
+
const namedReadAllEndpoints = resolveBuilderConfigNames(extendedEndpoints.filter((endpoint) => isReadAllEndpoint(endpoint, resolver.options)));
|
|
3182
|
+
let hasZodImport = false;
|
|
3183
|
+
const importedZodSchemas = [];
|
|
3184
|
+
const importedEndpoints = [];
|
|
3185
|
+
const importedInfiniteEndpoints = [];
|
|
3186
|
+
const configs = Object.entries(namedReadAllEndpoints).map(([name, readAllEndpoint]) => {
|
|
3187
|
+
const columnsConfig = getColumnsConfig(resolver, readAllEndpoint);
|
|
3188
|
+
if (!columnsConfig) return;
|
|
3189
|
+
importedEndpoints.push(readAllEndpoint);
|
|
3190
|
+
importedInfiniteEndpoints.push(readAllEndpoint);
|
|
3191
|
+
if (columnsConfig.zodSchema) if (isNamedZodSchema(columnsConfig.zodSchema)) importedZodSchemas.push(columnsConfig.zodSchema);
|
|
3192
|
+
else hasZodImport = true;
|
|
3193
|
+
if (columnsConfig.sortableEnumSchemaName) importedZodSchemas.push(columnsConfig.sortableEnumSchemaName);
|
|
3194
|
+
const filter = readAllEndpoint.parameters.find((param) => param.name === resolver.options.filterParamName);
|
|
3195
|
+
if (filter) importedZodSchemas.push(filter.zodSchema);
|
|
3196
|
+
const config = {
|
|
3197
|
+
name,
|
|
3198
|
+
title: capitalize(camelToSpaceSeparated(name.replace(/config$/i, ""))),
|
|
3199
|
+
readAll: {
|
|
3200
|
+
acl: getAclConfig(readAllEndpoint, resolver.options),
|
|
3201
|
+
paginated: getImportedQueryName(readAllEndpoint, resolver.options),
|
|
3202
|
+
infinite: resolver.options.infiniteQueries ? getImportedInfiniteQueryName(readAllEndpoint, resolver.options) : void 0,
|
|
3203
|
+
filters: getInputsConfig(resolver, filter),
|
|
3204
|
+
columns: columnsConfig.columns
|
|
3205
|
+
}
|
|
3206
|
+
};
|
|
3207
|
+
const readEndpoint = extendedEndpoints.find((endpoint) => isReadEndpoint(endpoint, readAllEndpoint));
|
|
3208
|
+
if (readEndpoint) {
|
|
3209
|
+
importedEndpoints.push(readEndpoint);
|
|
3210
|
+
let responseSchema = readEndpoint.response;
|
|
3211
|
+
if (isNamedZodSchema(responseSchema)) {
|
|
3212
|
+
importedZodSchemas.push(responseSchema);
|
|
3213
|
+
responseSchema = getImportedZodSchemaName(resolver, responseSchema);
|
|
3214
|
+
} else hasZodImport = true;
|
|
3215
|
+
config.read = {
|
|
3216
|
+
acl: getAclConfig(readEndpoint, resolver.options),
|
|
3217
|
+
schema: responseSchema,
|
|
3218
|
+
query: getImportedQueryName(readEndpoint, resolver.options)
|
|
3219
|
+
};
|
|
3220
|
+
}
|
|
3221
|
+
const createEndpoint = extendedEndpoints.find((endpoint) => isCreateEndpoint(endpoint, readAllEndpoint));
|
|
3222
|
+
if (createEndpoint) {
|
|
3223
|
+
importedEndpoints.push(createEndpoint);
|
|
3224
|
+
const body = getEndpointBody$1(createEndpoint);
|
|
3225
|
+
if (body) importedZodSchemas.push(body.zodSchema);
|
|
3226
|
+
config.create = {
|
|
3227
|
+
acl: getAclConfig(createEndpoint, resolver.options),
|
|
3228
|
+
mutation: getImportedQueryName(createEndpoint, resolver.options),
|
|
3229
|
+
inputDefs: getInputsConfig(resolver, body)
|
|
3230
|
+
};
|
|
3231
|
+
}
|
|
3232
|
+
const updateEndpoint = extendedEndpoints.find((endpoint) => isUpdateEndpoint(endpoint, readAllEndpoint));
|
|
3233
|
+
if (updateEndpoint) {
|
|
3234
|
+
importedEndpoints.push(updateEndpoint);
|
|
3235
|
+
const body = getEndpointBody$1(updateEndpoint);
|
|
3236
|
+
if (body) importedZodSchemas.push(body.zodSchema);
|
|
3237
|
+
config.update = {
|
|
3238
|
+
acl: getAclConfig(updateEndpoint, resolver.options),
|
|
3239
|
+
mutation: getImportedQueryName(updateEndpoint, resolver.options),
|
|
3240
|
+
inputDefs: getInputsConfig(resolver, body)
|
|
3241
|
+
};
|
|
3242
|
+
}
|
|
3243
|
+
const deleteEndpoint = extendedEndpoints.find((endpoint) => isDeleteEndpoint(endpoint, readAllEndpoint));
|
|
3244
|
+
if (deleteEndpoint) {
|
|
3245
|
+
importedEndpoints.push(deleteEndpoint);
|
|
3246
|
+
config.delete = {
|
|
3247
|
+
acl: getAclConfig(deleteEndpoint, resolver.options),
|
|
3248
|
+
mutation: getImportedQueryName(deleteEndpoint, resolver.options)
|
|
3249
|
+
};
|
|
3250
|
+
}
|
|
3251
|
+
const bulkDeleteEndpoint = extendedEndpoints.find((endpoint) => isBulkDeleteEndpoint(endpoint, readAllEndpoint));
|
|
3252
|
+
if (bulkDeleteEndpoint) {
|
|
3253
|
+
importedEndpoints.push(bulkDeleteEndpoint);
|
|
3254
|
+
const body = getEndpointBody$1(bulkDeleteEndpoint);
|
|
3255
|
+
if (body) importedZodSchemas.push(body.zodSchema);
|
|
3256
|
+
config.bulkDelete = {
|
|
3257
|
+
acl: getAclConfig(bulkDeleteEndpoint, resolver.options),
|
|
3258
|
+
mutation: getImportedQueryName(bulkDeleteEndpoint, resolver.options),
|
|
3259
|
+
inputDefs: getInputsConfig(resolver, body)
|
|
3260
|
+
};
|
|
3261
|
+
}
|
|
3262
|
+
return config;
|
|
3263
|
+
});
|
|
3264
|
+
const modelsImports = getModelsImports({
|
|
3265
|
+
resolver,
|
|
3266
|
+
tag,
|
|
3267
|
+
zodSchemas: importedZodSchemas
|
|
3268
|
+
});
|
|
3269
|
+
const queriesImports = getQueriesImports({
|
|
3270
|
+
tag,
|
|
3271
|
+
endpoints: importedEndpoints,
|
|
3272
|
+
options: resolver.options
|
|
3273
|
+
});
|
|
3274
|
+
const infiniteQueriesImports = resolver.options.infiniteQueries ? getInfiniteQueriesImports({
|
|
3275
|
+
tag,
|
|
3276
|
+
endpoints: importedInfiniteEndpoints,
|
|
3277
|
+
options: resolver.options
|
|
3278
|
+
}) : [];
|
|
3279
|
+
const aclImports = getAclImports({
|
|
3280
|
+
tag,
|
|
3281
|
+
endpoints: importedEndpoints.filter((endpoint) => endpoint.acl),
|
|
3282
|
+
options: resolver.options
|
|
3283
|
+
});
|
|
3284
|
+
return {
|
|
3285
|
+
configs: configs.filter(Boolean),
|
|
3286
|
+
hasZodImport,
|
|
3287
|
+
modelsImports,
|
|
3288
|
+
queriesImports: mergeImports(resolver.options, queriesImports, infiniteQueriesImports),
|
|
3289
|
+
aclImports
|
|
3290
|
+
};
|
|
3291
|
+
}
|
|
3292
|
+
function resolveBuilderConfigNames(endpoints) {
|
|
3293
|
+
const sortedEndpoints = endpoints.map((endpoint) => ({
|
|
3294
|
+
...endpoint,
|
|
3295
|
+
namePathSegments: endpoint.pathSegments.filter((segment) => !isPathSegmentParam(segment))
|
|
3296
|
+
})).toSorted((a, b) => a.namePathSegments.length - b.namePathSegments.length);
|
|
3297
|
+
const namedEndpoints = {};
|
|
3298
|
+
for (const endpoint of sortedEndpoints) {
|
|
3299
|
+
const namePathSegments = endpoint.namePathSegments;
|
|
3300
|
+
let name = namePathSegments.length > 0 ? `${kebabToCamel(namePathSegments.pop())}${capitalize(BUILD_CONFIG_SUFFIX)}` : BUILD_CONFIG_SUFFIX;
|
|
3301
|
+
while (namedEndpoints[name]) {
|
|
3302
|
+
if (namePathSegments.length === 0) throw new Error(`Can't uniquely resolve builder config name: ${name}`);
|
|
3303
|
+
name = `${kebabToCamel(namePathSegments.pop())}${capitalize(name)}`;
|
|
3304
|
+
}
|
|
3305
|
+
namedEndpoints[name] = endpoint;
|
|
3306
|
+
}
|
|
3307
|
+
return namedEndpoints;
|
|
3308
|
+
}
|
|
3309
|
+
function getAclConfig(endpoint, options) {
|
|
3310
|
+
return options.acl && endpoint.acl ? getImportedAbilityFunctionName(endpoint, options) : void 0;
|
|
3311
|
+
}
|
|
3312
|
+
function getInputsConfig(resolver, endpointParameter) {
|
|
3313
|
+
if (!endpointParameter) return;
|
|
3314
|
+
let schema;
|
|
3315
|
+
if (endpointParameter.type === "Body") schema = endpointParameter.bodyObject?.content?.[JSON_APPLICATION_FORMAT]?.schema;
|
|
3316
|
+
else schema = endpointParameter.parameterObject?.schema;
|
|
3317
|
+
if (!schema) return;
|
|
3318
|
+
const schemaObj = resolver.resolveObject(schema);
|
|
3319
|
+
const inputs = Object.keys(schemaObj?.properties ?? {}).reduce((acc, key) => ({
|
|
3320
|
+
...acc,
|
|
3321
|
+
[key]: true
|
|
3322
|
+
}), {});
|
|
3323
|
+
return {
|
|
3324
|
+
schema: getImportedZodSchemaName(resolver, endpointParameter.zodSchema),
|
|
3325
|
+
options: { inputs }
|
|
3326
|
+
};
|
|
3327
|
+
}
|
|
3328
|
+
function getColumnsConfig(resolver, endpoint) {
|
|
3329
|
+
const endpointResponse = endpoint.responseObject;
|
|
3330
|
+
if (!endpointResponse) return;
|
|
3331
|
+
const schema = endpointResponse.content?.[JSON_APPLICATION_FORMAT]?.schema;
|
|
3332
|
+
if (!schema) return;
|
|
3333
|
+
const properties = getSchemaProperties(resolver, schema);
|
|
3334
|
+
const arrayPropertyKeys = Object.keys(properties).filter((key) => resolver.resolveObject(properties[key]).type === "array");
|
|
3335
|
+
arrayPropertyKeys.sort((a, b) => {
|
|
3336
|
+
const aIndex = resolver.options.dataResponseParamNames.indexOf(a);
|
|
3337
|
+
const bIndex = resolver.options.dataResponseParamNames.indexOf(b);
|
|
3338
|
+
if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex;
|
|
3339
|
+
if (aIndex !== -1) return -1;
|
|
3340
|
+
if (bIndex !== -1) return 1;
|
|
3341
|
+
return a.localeCompare(b);
|
|
3342
|
+
});
|
|
3343
|
+
const propertyKey = arrayPropertyKeys[0];
|
|
3344
|
+
if (!propertyKey) return;
|
|
3345
|
+
const dataSchemaObj = resolver.resolveObject(properties[propertyKey]);
|
|
3346
|
+
if (!dataSchemaObj || dataSchemaObj.type !== "array") return;
|
|
3347
|
+
const itemSchema = dataSchemaObj.items;
|
|
3348
|
+
const itemSchemaObj = resolver.resolveObject(itemSchema);
|
|
3349
|
+
if (!itemSchemaObj) return;
|
|
3350
|
+
const zodSchema = isReferenceObject(itemSchema) ? resolver.getZodSchemaNameByRef(itemSchema.$ref) : ANY_SCHEMA;
|
|
3351
|
+
const columns = Object.keys(itemSchemaObj?.properties ?? {}).reduce((acc, key) => ({
|
|
3352
|
+
...acc,
|
|
3353
|
+
[key]: true
|
|
3354
|
+
}), {});
|
|
3355
|
+
const sortableEnumSchemaName = endpoint.parameters.find((param) => param.parameterObject && isSortingParameterObject(param.parameterObject))?.parameterSortingEnumSchemaName;
|
|
3356
|
+
return {
|
|
3357
|
+
columns: {
|
|
3358
|
+
schema: getImportedZodSchemaName(resolver, zodSchema),
|
|
3359
|
+
options: {
|
|
3360
|
+
columns,
|
|
3361
|
+
sortable: sortableEnumSchemaName ? getImportedZodSchemaName(resolver, sortableEnumSchemaName) : void 0
|
|
3362
|
+
}
|
|
3363
|
+
},
|
|
3364
|
+
zodSchema,
|
|
3365
|
+
sortableEnumSchemaName
|
|
3366
|
+
};
|
|
3367
|
+
}
|
|
3368
|
+
function getSchemaProperties(resolver, schema) {
|
|
3369
|
+
const schemaObj = resolver.resolveObject(schema);
|
|
3370
|
+
if (schemaObj.properties) return schemaObj.properties;
|
|
3371
|
+
else if ("allOf" in schemaObj && schemaObj.allOf) return schemaObj.allOf.reduce((acc, cur) => ({
|
|
3372
|
+
...acc,
|
|
3373
|
+
...getSchemaProperties(resolver, cur)
|
|
3374
|
+
}), {});
|
|
3375
|
+
return {};
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3378
|
+
//#endregion
|
|
3379
|
+
//#region src/generators/generate/generateConfigs.ts
|
|
3380
|
+
function generateConfigs(generateTypeParams) {
|
|
3381
|
+
const { configs, hasZodImport, modelsImports, queriesImports, aclImports } = getBuilderConfigs(generateTypeParams);
|
|
3382
|
+
if (configs.length === 0) return;
|
|
3383
|
+
const { resolver, tag } = generateTypeParams;
|
|
3384
|
+
const hasDynamicInputsImport = configs.some((config) => config.readAll.filters || config.create?.inputDefs || config.update?.inputDefs);
|
|
3385
|
+
const dynamicInputsImport = {
|
|
3386
|
+
bindings: [BUILDERS_UTILS.dynamicInputs],
|
|
3387
|
+
from: resolver.options.dynamicInputsImportPath
|
|
3388
|
+
};
|
|
3389
|
+
const hasDynamicColumnsImport = configs.some((config) => config.readAll.columns);
|
|
3390
|
+
const dynamicColumnsImport = {
|
|
3391
|
+
bindings: [BUILDERS_UTILS.dynamicColumns],
|
|
3392
|
+
from: resolver.options.dynamicColumnsImportPath
|
|
3393
|
+
};
|
|
3394
|
+
const lines = [];
|
|
3395
|
+
if (hasZodImport) lines.push(renderImport$4(ZOD_IMPORT));
|
|
3396
|
+
if (hasDynamicInputsImport) lines.push(renderImport$4(dynamicInputsImport));
|
|
3397
|
+
if (hasDynamicColumnsImport) lines.push(renderImport$4(dynamicColumnsImport));
|
|
3398
|
+
for (const modelsImport of modelsImports) lines.push(renderImport$4(modelsImport));
|
|
3399
|
+
for (const queriesImport of queriesImports) lines.push(renderImport$4(queriesImport));
|
|
3400
|
+
for (const aclImport of aclImports) lines.push(renderImport$4(aclImport));
|
|
3401
|
+
lines.push("");
|
|
3402
|
+
if (resolver.options.tsNamespaces) lines.push(`export namespace ${getNamespaceName({
|
|
3403
|
+
type: GenerateType.Configs,
|
|
3404
|
+
tag,
|
|
3405
|
+
options: resolver.options
|
|
3406
|
+
})} {`);
|
|
3407
|
+
for (const config of configs) {
|
|
3408
|
+
lines.push(renderBuilderConfig(config));
|
|
3409
|
+
lines.push("");
|
|
3410
|
+
}
|
|
3411
|
+
if (resolver.options.tsNamespaces) lines.push("}");
|
|
3412
|
+
return lines.join("\n").trimEnd() + "\n";
|
|
3413
|
+
}
|
|
3414
|
+
function renderImport$4(importData) {
|
|
3415
|
+
return `import ${[...importData.defaultImport ? [importData.defaultImport] : [], ...importData.bindings ? [`{ ${importData.bindings.join(", ")} }`] : []].join(", ")} from "${importData.from}";`;
|
|
3416
|
+
}
|
|
3417
|
+
function renderInputsConfig(inputsConfig) {
|
|
3418
|
+
const lines = [];
|
|
3419
|
+
lines.push("{");
|
|
3420
|
+
lines.push(` schema: ${inputsConfig.schema},`);
|
|
3421
|
+
lines.push(" options: {");
|
|
3422
|
+
lines.push(" inputs: {");
|
|
3423
|
+
for (const key of Object.keys(inputsConfig.options.inputs)) lines.push(` ${key}: true,`);
|
|
3424
|
+
lines.push(" },");
|
|
3425
|
+
lines.push(" },");
|
|
3426
|
+
lines.push("}");
|
|
3427
|
+
return lines.join("\n");
|
|
3428
|
+
}
|
|
3429
|
+
function renderColumnsConfig(columnsConfig) {
|
|
3430
|
+
const lines = [];
|
|
3431
|
+
lines.push("{");
|
|
3432
|
+
lines.push(` schema: ${columnsConfig.schema},`);
|
|
3433
|
+
lines.push(" options: {");
|
|
3434
|
+
lines.push(" columns: {");
|
|
3435
|
+
for (const key of Object.keys(columnsConfig.options.columns)) lines.push(` ${key}: true,`);
|
|
3436
|
+
lines.push(" },");
|
|
3437
|
+
if (columnsConfig.options.sortable) lines.push(` sortable: ${columnsConfig.options.sortable},`);
|
|
3438
|
+
lines.push(" },");
|
|
3439
|
+
lines.push("}");
|
|
3440
|
+
return lines.join("\n");
|
|
3441
|
+
}
|
|
3442
|
+
function renderBuilderConfig(config) {
|
|
3443
|
+
const lines = [];
|
|
3444
|
+
lines.push(`export const ${config.name} = {`);
|
|
3445
|
+
lines.push(" meta: {");
|
|
3446
|
+
lines.push(` title: "${config.title}",`);
|
|
3447
|
+
lines.push(" },");
|
|
3448
|
+
lines.push(" readAll: {");
|
|
3449
|
+
if (config.readAll.acl) lines.push(` acl: ${config.readAll.acl},`);
|
|
3450
|
+
lines.push(` schema: ${config.readAll.columns.schema},`);
|
|
3451
|
+
lines.push(` paginated: ${config.readAll.paginated},`);
|
|
3452
|
+
if (config.readAll.infinite) lines.push(` infinite: ${config.readAll.infinite},`);
|
|
3453
|
+
if (config.readAll.filters) {
|
|
3454
|
+
lines.push(" filters: {");
|
|
3455
|
+
lines.push(` schema: ${config.readAll.filters.schema},`);
|
|
3456
|
+
lines.push(` filterDefs: ${BUILDERS_UTILS.dynamicInputs}(${renderInputsConfig(config.readAll.filters)})`);
|
|
3457
|
+
lines.push(" },");
|
|
3458
|
+
}
|
|
3459
|
+
lines.push(` columns: ${BUILDERS_UTILS.dynamicColumns}(${renderColumnsConfig(config.readAll.columns)}),`);
|
|
3460
|
+
lines.push(" },");
|
|
3461
|
+
if (config.read) {
|
|
3462
|
+
lines.push(" read: {");
|
|
3463
|
+
if (config.read.acl) lines.push(` acl: ${config.read.acl},`);
|
|
3464
|
+
lines.push(` schema: ${config.read.schema},`);
|
|
3465
|
+
lines.push(` query: ${config.read.query},`);
|
|
3466
|
+
lines.push(" },");
|
|
3467
|
+
}
|
|
3468
|
+
if (config.create) {
|
|
3469
|
+
lines.push(" create: {");
|
|
3470
|
+
if (config.create.acl) lines.push(` acl: ${config.create.acl},`);
|
|
3471
|
+
if (config.create.inputDefs) lines.push(` schema: ${config.create.inputDefs.schema},`);
|
|
3472
|
+
lines.push(` mutation: ${config.create.mutation},`);
|
|
3473
|
+
if (config.create.inputDefs) lines.push(` inputDefs: ${BUILDERS_UTILS.dynamicInputs}(${renderInputsConfig(config.create.inputDefs)})`);
|
|
3474
|
+
lines.push(" },");
|
|
3475
|
+
}
|
|
3476
|
+
if (config.update) {
|
|
3477
|
+
lines.push(" update: {");
|
|
3478
|
+
if (config.update.acl) lines.push(` acl: ${config.update.acl},`);
|
|
3479
|
+
if (config.update.inputDefs) lines.push(` schema: ${config.update.inputDefs.schema},`);
|
|
3480
|
+
lines.push(` mutation: ${config.update.mutation},`);
|
|
3481
|
+
if (config.update.inputDefs) lines.push(` inputDefs: ${BUILDERS_UTILS.dynamicInputs}(${renderInputsConfig(config.update.inputDefs)})`);
|
|
3482
|
+
lines.push(" },");
|
|
3483
|
+
}
|
|
3484
|
+
if (config.delete) {
|
|
3485
|
+
lines.push(" delete: {");
|
|
3486
|
+
if (config.delete.acl) lines.push(` acl: ${config.delete.acl},`);
|
|
3487
|
+
lines.push(` mutation: ${config.delete.mutation},`);
|
|
3488
|
+
lines.push(" },");
|
|
3489
|
+
}
|
|
3490
|
+
lines.push("};");
|
|
3491
|
+
return lines.join("\n");
|
|
3492
|
+
}
|
|
3493
|
+
|
|
3494
|
+
//#endregion
|
|
3495
|
+
//#region src/generators/generate/generateEndpoints.ts
|
|
3496
|
+
function generateEndpoints({ resolver, data, tag }) {
|
|
3497
|
+
if (shouldInlineEndpointsForTag(tag, resolver.options)) return;
|
|
3498
|
+
const endpoints = data.get(tag)?.endpoints;
|
|
3499
|
+
if (!endpoints || endpoints.length === 0) return;
|
|
3500
|
+
const appRestClientImport = {
|
|
3501
|
+
bindings: [APP_REST_CLIENT_NAME],
|
|
3502
|
+
from: getAppRestClientImportPath(resolver.options)
|
|
3503
|
+
};
|
|
3504
|
+
const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
|
|
3505
|
+
const hasAxiosImport = hasAxiosRequestConfig;
|
|
3506
|
+
const axiosImport = {
|
|
3507
|
+
bindings: hasAxiosRequestConfig ? [AXIOS_REQUEST_CONFIG_TYPE] : [],
|
|
3508
|
+
from: AXIOS_IMPORT.from
|
|
3509
|
+
};
|
|
3510
|
+
const generateParse = resolver.options.parseRequestParams;
|
|
3511
|
+
const endpointParams = endpoints.flatMap((endpoint) => endpoint.parameters);
|
|
3512
|
+
const endpointParamsParseSchemas = endpointParams.filter((param) => !["Path", "Header"].includes(param.type)).map((param) => param.parameterSortingEnumSchemaName ?? param.zodSchema);
|
|
3513
|
+
const zodSchemas = getUniqueArray([...endpoints.map((endpoint) => endpoint.response), ...generateParse ? endpointParamsParseSchemas : []]);
|
|
3514
|
+
const hasZodImport = zodSchemas.some((schema) => !isNamedZodSchema(schema));
|
|
3515
|
+
const hasZodExtendedImport = resolver.options.parseRequestParams && endpointParamsParseSchemas.length > 0;
|
|
3516
|
+
const zodExtendedImport = {
|
|
3517
|
+
bindings: [ZOD_EXTENDED.namespace],
|
|
3518
|
+
from: getZodExtendedImportPath(resolver.options)
|
|
3519
|
+
};
|
|
3520
|
+
const modelsImports = getModelsImports({
|
|
3521
|
+
resolver,
|
|
3522
|
+
tag,
|
|
3523
|
+
zodSchemas: zodSchemas.filter(isNamedZodSchema),
|
|
3524
|
+
zodSchemasAsTypes: getUniqueArray(endpointParams.map((param) => param.zodSchema).filter(isNamedZodSchema))
|
|
3525
|
+
});
|
|
3526
|
+
const lines = [];
|
|
3527
|
+
lines.push(renderImport$3(appRestClientImport));
|
|
3528
|
+
if (hasAxiosImport) lines.push(renderImport$3(axiosImport));
|
|
3529
|
+
if (hasZodImport) lines.push(renderImport$3(ZOD_IMPORT));
|
|
3530
|
+
if (hasZodExtendedImport) lines.push(renderImport$3(zodExtendedImport));
|
|
3531
|
+
for (const modelsImport of modelsImports) lines.push(renderImport$3(modelsImport));
|
|
3532
|
+
lines.push("");
|
|
3533
|
+
if (resolver.options.tsNamespaces) lines.push(`export namespace ${getNamespaceName({
|
|
3534
|
+
type: GenerateType.Endpoints,
|
|
3535
|
+
tag,
|
|
3536
|
+
options: resolver.options
|
|
3537
|
+
})} {`);
|
|
3538
|
+
for (const endpoint of endpoints) {
|
|
3539
|
+
const endpointParams = renderEndpointParams$1(resolver, endpoint, {});
|
|
3540
|
+
renderEndpointArgs$1(resolver, endpoint, {});
|
|
3541
|
+
const endpointBody = getEndpointBody$1(endpoint);
|
|
3542
|
+
const hasUndefinedEndpointBody = requiresBody(endpoint) && !endpointBody && hasEndpointConfig(endpoint, resolver);
|
|
3543
|
+
const endpointConfig = renderEndpointConfig(resolver, endpoint);
|
|
3544
|
+
lines.push(`export const ${getEndpointName(endpoint)} = (${endpointParams}${hasAxiosRequestConfig ? `${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => {`);
|
|
3545
|
+
lines.push(` return ${APP_REST_CLIENT_NAME}.${endpoint.method}(`);
|
|
3546
|
+
lines.push(` { resSchema: ${getImportedZodSchemaName(resolver, endpoint.response)} },`);
|
|
3547
|
+
lines.push(` \`${getEndpointPath(endpoint)}\`,`);
|
|
3548
|
+
if (endpointBody) lines.push(` ${generateParse ? renderEndpointParamParse(resolver, endpointBody, endpointBody.name) : endpointBody.name},`);
|
|
3549
|
+
else if (hasUndefinedEndpointBody) lines.push(" undefined,");
|
|
3550
|
+
lines.push(` ${endpointConfig}`);
|
|
3551
|
+
lines.push(" )");
|
|
3552
|
+
lines.push("};");
|
|
3553
|
+
}
|
|
3554
|
+
if (resolver.options.tsNamespaces) lines.push("}");
|
|
3555
|
+
return lines.join("\n").trimEnd() + "\n";
|
|
3556
|
+
}
|
|
3557
|
+
function renderImport$3(importData) {
|
|
3558
|
+
return `import ${[...importData.defaultImport ? [importData.defaultImport] : [], ...importData.bindings ? [`{ ${importData.bindings.join(", ")} }`] : []].join(", ")} from "${importData.from}";`;
|
|
3559
|
+
}
|
|
3560
|
+
function renderEndpointParams$1(resolver, endpoint, options) {
|
|
3561
|
+
return mapEndpointParamsToFunctionParams(resolver, endpoint, options).map((param) => `${param.name}${param.required ? "" : "?"}: ${param.type}, `).join("");
|
|
3562
|
+
}
|
|
3563
|
+
function renderEndpointArgs$1(resolver, endpoint, options) {
|
|
3564
|
+
return mapEndpointParamsToFunctionParams(resolver, endpoint, options).map((param) => param.name).join(", ");
|
|
3565
|
+
}
|
|
3566
|
+
function renderEndpointParamParse(resolver, param, paramName) {
|
|
3567
|
+
const addOptional = !(param.parameterObject ?? param.bodyObject)?.required && (Boolean(param.parameterSortingEnumSchemaName) || isNamedZodSchema(param.zodSchema));
|
|
3568
|
+
const schemaValue = param.parameterSortingEnumSchemaName ? `${ZOD_EXTENDED.namespace}.${ZOD_EXTENDED.exports.sortExp}(${getImportedZodSchemaName(resolver, param.parameterSortingEnumSchemaName)})${addOptional ? ".optional()" : ""}` : `${getImportedZodSchemaName(resolver, param.zodSchema)}${addOptional ? ".optional()" : ""}`;
|
|
3569
|
+
const queryArgs = param.type === "Query" ? `, { type: "query", name: "${paramName}" }` : "";
|
|
3570
|
+
return `${ZOD_EXTENDED.namespace}.${ZOD_EXTENDED.exports.parse}(${schemaValue}, ${paramName}${queryArgs})`;
|
|
3571
|
+
}
|
|
3572
|
+
function renderEndpointConfig(resolver, endpoint) {
|
|
3573
|
+
const endpointConfig = getEndpointConfig(endpoint);
|
|
3574
|
+
const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
|
|
3575
|
+
if (Object.keys(endpointConfig).length === 0) return hasAxiosRequestConfig ? AXIOS_REQUEST_CONFIG_NAME : "";
|
|
3576
|
+
const lines = [];
|
|
3577
|
+
lines.push("{");
|
|
3578
|
+
if (hasAxiosRequestConfig) lines.push(` ...${AXIOS_REQUEST_CONFIG_NAME},`);
|
|
3579
|
+
if (endpointConfig.params) {
|
|
3580
|
+
lines.push(" params: {");
|
|
3581
|
+
for (const param of endpointConfig.params) {
|
|
3582
|
+
const value = resolver.options.parseRequestParams ? renderEndpointParamParse(resolver, param, param.value) : param.value;
|
|
3583
|
+
lines.push(` ${param.name}: ${value},`);
|
|
3584
|
+
}
|
|
3585
|
+
lines.push(" },");
|
|
3586
|
+
}
|
|
3587
|
+
if (endpointConfig.headers) {
|
|
3588
|
+
lines.push(" headers: {");
|
|
3589
|
+
for (const [key, value] of Object.entries(endpointConfig.headers)) lines.push(` '${key}': ${value},`);
|
|
3590
|
+
lines.push(" },");
|
|
3591
|
+
}
|
|
3592
|
+
if (endpoint.response === "z.instanceof(Blob)") lines.push(" responseType: \"blob\",");
|
|
3593
|
+
if (endpoint.mediaDownload) lines.push(" rawResponse: true,");
|
|
3594
|
+
lines.push("}");
|
|
3595
|
+
return lines.join("\n ");
|
|
3596
|
+
}
|
|
3597
|
+
|
|
3598
|
+
//#endregion
|
|
3599
|
+
//#region src/generators/generate/generateModels.ts
|
|
3600
|
+
function generateModels({ resolver, data, tag }) {
|
|
3601
|
+
if (resolver.options.modelsInCommon && resolver.options.splitByTags && tag !== resolver.options.defaultTag) return renderModelsProxy({
|
|
3602
|
+
resolver,
|
|
3603
|
+
data,
|
|
3604
|
+
tag
|
|
3605
|
+
});
|
|
3606
|
+
const zodSchemas = data.get(tag)?.zodSchemas;
|
|
3607
|
+
if (!zodSchemas || Object.keys(zodSchemas).length === 0) return;
|
|
3608
|
+
const refZodSchemas = [];
|
|
3609
|
+
for (const zodSchema of Object.keys(zodSchemas)) {
|
|
3610
|
+
const refs = getZodSchemaRefs(resolver, zodSchema);
|
|
3611
|
+
for (const ref of refs) if (!zodSchemas[ref]) refZodSchemas.push(ref);
|
|
3612
|
+
}
|
|
3613
|
+
const modelsImports = getModelsImports({
|
|
3614
|
+
resolver,
|
|
3615
|
+
tag,
|
|
3616
|
+
zodSchemas: refZodSchemas
|
|
3617
|
+
});
|
|
3618
|
+
const zodSchemasData = {};
|
|
3619
|
+
for (const [key, code] of Object.entries(zodSchemas)) {
|
|
3620
|
+
const schemaRef = resolver.getRefByZodSchemaName(key);
|
|
3621
|
+
zodSchemasData[key] = {
|
|
3622
|
+
code,
|
|
3623
|
+
isCiruclar: schemaRef ? resolver.isSchemaCircular(schemaRef) : false,
|
|
3624
|
+
isEnum: isEnumZodSchema(code),
|
|
3625
|
+
schemaObj: resolver.getZodSchemaObj(key)
|
|
3626
|
+
};
|
|
3627
|
+
}
|
|
3628
|
+
const lines = [];
|
|
3629
|
+
lines.push(renderImport$2(ZOD_IMPORT));
|
|
3630
|
+
for (const modelsImport of modelsImports) lines.push(renderImport$2(modelsImport));
|
|
3631
|
+
lines.push("");
|
|
3632
|
+
if (resolver.options.tsNamespaces) lines.push(`export namespace ${getNamespaceName({
|
|
3633
|
+
type: GenerateType.Models,
|
|
3634
|
+
tag,
|
|
3635
|
+
options: resolver.options
|
|
3636
|
+
})} {`);
|
|
3637
|
+
for (const [name, zodSchema] of Object.entries(zodSchemasData)) {
|
|
3638
|
+
lines.push(renderModelJsDocs({
|
|
3639
|
+
name,
|
|
3640
|
+
zodSchema,
|
|
3641
|
+
tag,
|
|
3642
|
+
resolver
|
|
3643
|
+
}));
|
|
3644
|
+
lines.push(`export const ${name} = ${zodSchema.code};`);
|
|
3645
|
+
lines.push(`export type ${getZodSchemaInferedTypeName(name, resolver.options)} = z.infer<typeof ${name}>;`);
|
|
3646
|
+
if (zodSchema.isEnum) lines.push(`export const ${getZodSchemaInferedTypeName(name, resolver.options)} = ${name}.enum;`);
|
|
3647
|
+
lines.push("");
|
|
3648
|
+
}
|
|
3649
|
+
if (resolver.options.tsNamespaces) lines.push("}");
|
|
3650
|
+
return lines.join("\n").trimEnd() + "\n";
|
|
3651
|
+
}
|
|
3652
|
+
function renderModelsProxy({ resolver, data, tag }) {
|
|
3653
|
+
const commonZodSchemas = data.get(resolver.options.defaultTag)?.zodSchemas ?? {};
|
|
3654
|
+
const schemaNames = getUsedSchemaNames({
|
|
3655
|
+
resolver,
|
|
3656
|
+
endpoints: data.get(tag)?.endpoints ?? []
|
|
3657
|
+
}).filter((schemaName) => Boolean(commonZodSchemas[schemaName]));
|
|
3658
|
+
if (schemaNames.length === 0) return;
|
|
3659
|
+
const modelsNamespace = getNamespaceName({
|
|
3660
|
+
type: GenerateType.Models,
|
|
3661
|
+
tag,
|
|
3662
|
+
options: resolver.options
|
|
3663
|
+
});
|
|
3664
|
+
const commonNamespace = getNamespaceName({
|
|
3665
|
+
type: GenerateType.Models,
|
|
3666
|
+
tag: resolver.options.defaultTag,
|
|
3667
|
+
options: resolver.options
|
|
3668
|
+
});
|
|
3669
|
+
const commonModelsPath = `${getImportPath(resolver.options)}${getTagImportPath({
|
|
3670
|
+
type: GenerateType.Models,
|
|
3671
|
+
tag: resolver.options.defaultTag,
|
|
3672
|
+
includeTagDir: true,
|
|
3673
|
+
options: resolver.options
|
|
3674
|
+
})}`;
|
|
3675
|
+
const inferredTypeNames = schemaNames.map((schemaName) => getZodSchemaInferedTypeName(schemaName, resolver.options));
|
|
3676
|
+
const enumInferredTypeNames = schemaNames.filter((schemaName) => isEnumZodSchema(commonZodSchemas[schemaName] ?? "")).map((schemaName) => getZodSchemaInferedTypeName(schemaName, resolver.options));
|
|
3677
|
+
if (resolver.options.tsNamespaces) {
|
|
3678
|
+
const lines = [];
|
|
3679
|
+
lines.push(`import { ${commonNamespace} } from "${commonModelsPath}";`);
|
|
3680
|
+
lines.push("");
|
|
3681
|
+
lines.push(`export namespace ${modelsNamespace} {`);
|
|
3682
|
+
for (const schemaName of schemaNames) lines.push(` export const ${schemaName} = ${commonNamespace}.${schemaName};`);
|
|
3683
|
+
for (const typeName of inferredTypeNames) lines.push(` export type ${typeName} = ${commonNamespace}.${typeName};`);
|
|
3684
|
+
for (const enumName of enumInferredTypeNames) lines.push(` export const ${enumName} = ${commonNamespace}.${enumName};`);
|
|
3685
|
+
lines.push("}");
|
|
3686
|
+
lines.push("");
|
|
3687
|
+
return lines.join("\n");
|
|
3688
|
+
}
|
|
3689
|
+
const valueExports = getUniqueArray([...schemaNames, ...enumInferredTypeNames]);
|
|
3690
|
+
const lines = [];
|
|
3691
|
+
if (valueExports.length > 0) lines.push(`export { ${valueExports.join(", ")} } from "${commonModelsPath}";`);
|
|
3692
|
+
if (inferredTypeNames.length > 0) lines.push(`export type { ${inferredTypeNames.join(", ")} } from "${commonModelsPath}";`);
|
|
3693
|
+
return lines.join("\n") + "\n";
|
|
3694
|
+
}
|
|
3695
|
+
function getUsedSchemaNames({ resolver, endpoints }) {
|
|
3696
|
+
const usedSchemaNames = /* @__PURE__ */ new Set();
|
|
3697
|
+
const queue = [];
|
|
3698
|
+
const enqueue = (schemaName) => {
|
|
3699
|
+
if (!schemaName || !isNamedZodSchema(schemaName) || usedSchemaNames.has(schemaName)) return;
|
|
3700
|
+
usedSchemaNames.add(schemaName);
|
|
3701
|
+
queue.push(schemaName);
|
|
3702
|
+
};
|
|
3703
|
+
for (const endpoint of endpoints) {
|
|
3704
|
+
enqueue(endpoint.response);
|
|
3705
|
+
for (const error of endpoint.errors) enqueue(error.zodSchema);
|
|
3706
|
+
for (const param of endpoint.parameters) {
|
|
3707
|
+
enqueue(param.zodSchema);
|
|
3708
|
+
enqueue(param.parameterSortingEnumSchemaName);
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
while (queue.length > 0) {
|
|
3712
|
+
const schemaName = queue.shift();
|
|
3713
|
+
if (!schemaName) continue;
|
|
3714
|
+
const refs = getZodSchemaRefs(resolver, schemaName);
|
|
3715
|
+
for (const ref of refs) enqueue(ref);
|
|
3716
|
+
}
|
|
3717
|
+
return Array.from(usedSchemaNames);
|
|
3718
|
+
}
|
|
3719
|
+
function renderImport$2(importData) {
|
|
3720
|
+
return `import ${[...importData.defaultImport ? [importData.defaultImport] : [], ...importData.bindings ? [`{ ${importData.bindings.join(", ")} }`] : []].join(", ")} from "${importData.from}";`;
|
|
3721
|
+
}
|
|
3722
|
+
function renderModelJsDocs({ name, zodSchema, tag, resolver }) {
|
|
3723
|
+
const lines = [
|
|
3724
|
+
`/** `,
|
|
3725
|
+
` * ${name} `,
|
|
3726
|
+
` * @type { ${getZodSchemaType(zodSchema)} }`
|
|
3727
|
+
];
|
|
3728
|
+
const description = getZodSchemaDescription(zodSchema);
|
|
3729
|
+
if (description) lines.push(` * @description ${description.replace(/\n/g, "\n *")}`);
|
|
3730
|
+
const propertyDescriptions = getZodSchemaPropertyDescriptions(resolver, zodSchema, tag);
|
|
3731
|
+
if (propertyDescriptions) for (const [property, info] of Object.entries(propertyDescriptions)) lines.push(` * @property { ${info.type} } ${property} ${info.description.replace(/\n/g, "\n *")} `);
|
|
3732
|
+
lines.push(" */");
|
|
3733
|
+
return lines.join("\n");
|
|
3734
|
+
}
|
|
3735
|
+
|
|
3736
|
+
//#endregion
|
|
3737
|
+
//#region src/generators/const/queries.const.ts
|
|
3738
|
+
const QUERY_HOOKS = {
|
|
3739
|
+
query: "useQuery",
|
|
3740
|
+
infiniteQuery: "useInfiniteQuery",
|
|
3741
|
+
mutation: "useMutation"
|
|
3742
|
+
};
|
|
3743
|
+
const QUERY_IMPORT = {
|
|
3744
|
+
bindings: [
|
|
3745
|
+
QUERY_HOOKS.query,
|
|
3746
|
+
QUERY_HOOKS.infiniteQuery,
|
|
3747
|
+
QUERY_HOOKS.mutation
|
|
3748
|
+
],
|
|
3749
|
+
from: "@tanstack/react-query"
|
|
3750
|
+
};
|
|
3751
|
+
const QUERIES_MODULE_NAME = "moduleName";
|
|
3752
|
+
|
|
3753
|
+
//#endregion
|
|
3754
|
+
//#region src/generators/generate/generateQueries.ts
|
|
3755
|
+
const endpointParamMappingCache = /* @__PURE__ */ new WeakMap();
|
|
3756
|
+
function generateQueries(params) {
|
|
3757
|
+
const { resolver, data, tag } = params;
|
|
3758
|
+
const inlineEndpoints = shouldInlineEndpointsForTag(tag, resolver.options);
|
|
3759
|
+
const endpoints = data.get(tag)?.endpoints;
|
|
3760
|
+
if (!endpoints || endpoints.length === 0) return;
|
|
3761
|
+
const endpointGroups = groupEndpoints(endpoints, resolver);
|
|
3762
|
+
const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
|
|
3763
|
+
const hasAxiosDefaultImport = endpoints.some(({ mediaUpload }) => mediaUpload);
|
|
3764
|
+
const hasAxiosImport = hasAxiosRequestConfig || hasAxiosDefaultImport;
|
|
3765
|
+
const axiosImport = {
|
|
3766
|
+
defaultImport: hasAxiosDefaultImport ? AXIOS_DEFAULT_IMPORT_NAME : void 0,
|
|
3767
|
+
bindings: hasAxiosRequestConfig ? [AXIOS_REQUEST_CONFIG_TYPE] : [],
|
|
3768
|
+
from: AXIOS_IMPORT.from
|
|
3769
|
+
};
|
|
3770
|
+
const { queryEndpoints, infiniteQueryEndpoints, mutationEndpoints, aclEndpoints } = endpointGroups;
|
|
3771
|
+
const queryImport = {
|
|
3772
|
+
bindings: [
|
|
3773
|
+
...queryEndpoints.length > 0 ? [QUERY_HOOKS.query] : [],
|
|
3774
|
+
...resolver.options.infiniteQueries && infiniteQueryEndpoints.length > 0 ? [QUERY_HOOKS.infiniteQuery] : [],
|
|
3775
|
+
...mutationEndpoints.length > 0 ? [QUERY_HOOKS.mutation] : []
|
|
3776
|
+
],
|
|
3777
|
+
from: QUERY_IMPORT.from
|
|
3778
|
+
};
|
|
3779
|
+
const hasMutationEffects = resolver.options.mutationEffects;
|
|
3780
|
+
const queryModulesImport = {
|
|
3781
|
+
bindings: [QUERY_MODULE_ENUM],
|
|
3782
|
+
from: getQueryModulesImportPath(resolver.options)
|
|
3783
|
+
};
|
|
3784
|
+
const hasMutationEffectsImport = hasMutationEffects && mutationEndpoints.length > 0;
|
|
3785
|
+
const mutationEffectsImport = {
|
|
3786
|
+
bindings: [...mutationEndpoints.length > 0 ? [MUTATION_EFFECTS.optionsType, MUTATION_EFFECTS.hookName] : []],
|
|
3787
|
+
from: getMutationEffectsImportPath(resolver.options)
|
|
3788
|
+
};
|
|
3789
|
+
const hasAclCheck = resolver.options.checkAcl && aclEndpoints.length > 0;
|
|
3790
|
+
const aclCheckImport = {
|
|
3791
|
+
bindings: [ACL_CHECK_HOOK],
|
|
3792
|
+
from: getAclCheckImportPath(resolver.options)
|
|
3793
|
+
};
|
|
3794
|
+
const queryTypesImport = {
|
|
3795
|
+
bindings: [
|
|
3796
|
+
"OpenApiQueryConfig",
|
|
3797
|
+
...queryEndpoints.length > 0 ? [QUERY_OPTIONS_TYPES.query] : [],
|
|
3798
|
+
...resolver.options.infiniteQueries && infiniteQueryEndpoints.length > 0 ? [QUERY_OPTIONS_TYPES.infiniteQuery] : [],
|
|
3799
|
+
...mutationEndpoints.length > 0 ? [QUERY_OPTIONS_TYPES.mutation] : []
|
|
3800
|
+
],
|
|
3801
|
+
from: getQueryTypesImportPath(resolver.options)
|
|
3802
|
+
};
|
|
3803
|
+
const hasWorkspaceContext = resolver.options.workspaceContext && endpoints.some((endpoint) => getWorkspaceParamNames(resolver, endpoint).length > 0);
|
|
3804
|
+
const workspaceContextImport = {
|
|
3805
|
+
bindings: ["OpenApiWorkspaceContext"],
|
|
3806
|
+
from: PACKAGE_IMPORT_PATH
|
|
3807
|
+
};
|
|
3808
|
+
const endpointParams = endpoints.flatMap((endpoint) => endpoint.parameters);
|
|
3809
|
+
const endpointParamsParseSchemas = endpointParams.filter((param) => !["Path", "Header"].includes(param.type)).map((param) => param.parameterSortingEnumSchemaName ?? param.zodSchema);
|
|
3810
|
+
const endpointRuntimeSchemas = getUniqueArray([...endpoints.map((endpoint) => endpoint.response), ...resolver.options.parseRequestParams ? endpointParamsParseSchemas : []]);
|
|
3811
|
+
const hasZodImport = inlineEndpoints && endpointRuntimeSchemas.some((schema) => !isNamedZodSchema(schema));
|
|
3812
|
+
const hasZodExtendedImport = inlineEndpoints && resolver.options.parseRequestParams && endpointParamsParseSchemas.length > 0;
|
|
3813
|
+
const appRestClientImport = {
|
|
3814
|
+
bindings: [APP_REST_CLIENT_NAME],
|
|
3815
|
+
from: getAppRestClientImportPath(resolver.options)
|
|
3816
|
+
};
|
|
3817
|
+
const zodExtendedImport = {
|
|
3818
|
+
bindings: [ZOD_EXTENDED.namespace],
|
|
3819
|
+
from: getZodExtendedImportPath(resolver.options)
|
|
3820
|
+
};
|
|
3821
|
+
const modelsImports = getModelsImports({
|
|
3822
|
+
resolver,
|
|
3823
|
+
tag,
|
|
3824
|
+
zodSchemas: inlineEndpoints ? endpointRuntimeSchemas.filter(isNamedZodSchema) : [],
|
|
3825
|
+
zodSchemasAsTypes: getUniqueArray(endpointParams.map((param) => param.zodSchema).filter(isNamedZodSchema))
|
|
3826
|
+
});
|
|
3827
|
+
const endpointsImports = inlineEndpoints ? [] : getEndpointsImports({
|
|
3828
|
+
tag,
|
|
3829
|
+
endpoints,
|
|
3830
|
+
options: resolver.options
|
|
3831
|
+
});
|
|
3832
|
+
const aclImports = getAclImports({
|
|
3833
|
+
tag,
|
|
3834
|
+
endpoints: aclEndpoints,
|
|
3835
|
+
options: resolver.options
|
|
3836
|
+
});
|
|
3837
|
+
const namespace = getNamespaceName({
|
|
3838
|
+
type: GenerateType.Queries,
|
|
3839
|
+
tag,
|
|
3840
|
+
options: resolver.options
|
|
3841
|
+
});
|
|
3842
|
+
const lines = [];
|
|
3843
|
+
if (hasAxiosImport) lines.push(renderImport$1(axiosImport));
|
|
3844
|
+
if (inlineEndpoints) {
|
|
3845
|
+
lines.push(renderImport$1(appRestClientImport));
|
|
3846
|
+
if (hasZodImport) lines.push(renderImport$1(ZOD_IMPORT));
|
|
3847
|
+
if (hasZodExtendedImport) lines.push(renderImport$1(zodExtendedImport));
|
|
3848
|
+
}
|
|
3849
|
+
lines.push(renderImport$1(queryImport));
|
|
3850
|
+
if (hasMutationEffects) lines.push(renderImport$1(queryModulesImport));
|
|
3851
|
+
if (hasMutationEffectsImport) lines.push(renderImport$1(mutationEffectsImport));
|
|
3852
|
+
if (hasAclCheck) {
|
|
3853
|
+
lines.push(renderImport$1(aclCheckImport));
|
|
3854
|
+
for (const aclImport of aclImports) lines.push(renderImport$1(aclImport));
|
|
3855
|
+
}
|
|
3856
|
+
lines.push(renderImport$1(queryTypesImport));
|
|
3857
|
+
if (hasWorkspaceContext) lines.push(renderImport$1(workspaceContextImport));
|
|
3858
|
+
for (const modelsImport of modelsImports) lines.push(renderImport$1(modelsImport));
|
|
3859
|
+
for (const endpointsImport of endpointsImports) lines.push(renderImport$1(endpointsImport));
|
|
3860
|
+
lines.push("");
|
|
3861
|
+
if (resolver.options.tsNamespaces) lines.push(`export namespace ${namespace} {`);
|
|
3862
|
+
if (inlineEndpoints) {
|
|
3863
|
+
lines.push(...renderInlineEndpoints({
|
|
3864
|
+
resolver,
|
|
3865
|
+
endpoints
|
|
3866
|
+
}));
|
|
3867
|
+
lines.push("");
|
|
3868
|
+
}
|
|
3869
|
+
lines.push(`export const ${QUERIES_MODULE_NAME} = ${hasMutationEffects ? `${QUERY_MODULE_ENUM}.${tag}` : `"${namespace}"`};`);
|
|
3870
|
+
lines.push("");
|
|
3871
|
+
lines.push(renderQueryKeys({
|
|
3872
|
+
resolver,
|
|
3873
|
+
queryEndpoints
|
|
3874
|
+
}));
|
|
3875
|
+
lines.push("");
|
|
3876
|
+
for (const endpoint of endpoints) {
|
|
3877
|
+
const endpointInfo = endpointGroups.infoByEndpoint.get(endpoint);
|
|
3878
|
+
if (endpointInfo?.query) {
|
|
3879
|
+
lines.push(renderQuery({
|
|
3880
|
+
resolver,
|
|
3881
|
+
endpoint,
|
|
3882
|
+
inlineEndpoints
|
|
3883
|
+
}));
|
|
3884
|
+
lines.push("");
|
|
3885
|
+
}
|
|
3886
|
+
if (endpointInfo?.mutation) {
|
|
3887
|
+
lines.push(renderMutation({
|
|
3888
|
+
resolver,
|
|
3889
|
+
endpoint,
|
|
3890
|
+
inlineEndpoints,
|
|
3891
|
+
precomputed: endpointGroups.mutationDataByEndpoint.get(endpoint)
|
|
3892
|
+
}));
|
|
3893
|
+
lines.push("");
|
|
3894
|
+
}
|
|
3895
|
+
if (endpointInfo?.infiniteQuery) {
|
|
3896
|
+
lines.push(renderInfiniteQuery({
|
|
3897
|
+
resolver,
|
|
3898
|
+
endpoint,
|
|
3899
|
+
inlineEndpoints
|
|
3900
|
+
}));
|
|
3901
|
+
lines.push("");
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3904
|
+
if (resolver.options.tsNamespaces) lines.push("}");
|
|
3905
|
+
return lines.join("\n").trimEnd() + "\n";
|
|
3906
|
+
}
|
|
3907
|
+
function getEndpointParamMapping(resolver, endpoint, options) {
|
|
3908
|
+
let resolverCache = endpointParamMappingCache.get(resolver);
|
|
3909
|
+
if (!resolverCache) {
|
|
3910
|
+
resolverCache = /* @__PURE__ */ new WeakMap();
|
|
3911
|
+
endpointParamMappingCache.set(resolver, resolverCache);
|
|
3912
|
+
}
|
|
3913
|
+
let endpointCache = resolverCache.get(endpoint);
|
|
3914
|
+
if (!endpointCache) {
|
|
3915
|
+
endpointCache = /* @__PURE__ */ new Map();
|
|
3916
|
+
resolverCache.set(endpoint, endpointCache);
|
|
3917
|
+
}
|
|
3918
|
+
const key = JSON.stringify(Object.entries(options ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([optionName, optionValue]) => [optionName, Boolean(optionValue)]));
|
|
3919
|
+
const cached = endpointCache.get(key);
|
|
3920
|
+
if (cached) return cached;
|
|
3921
|
+
const computed = mapEndpointParamsToFunctionParams(resolver, endpoint, options);
|
|
3922
|
+
endpointCache.set(key, computed);
|
|
3923
|
+
return computed;
|
|
3924
|
+
}
|
|
3925
|
+
function renderImport$1(importData) {
|
|
3926
|
+
return `import ${[...importData.defaultImport ? [importData.defaultImport] : [], ...importData.bindings ? [`{ ${importData.bindings.join(", ")} }`] : []].join(", ")} from "${importData.from}";`;
|
|
3927
|
+
}
|
|
3928
|
+
function renderEndpointParams(resolver, endpoint, options) {
|
|
3929
|
+
return getEndpointParamMapping(resolver, endpoint, options).map((param) => `${param.name}${param.required ? "" : "?"}: ${param.type}`).join(", ");
|
|
3930
|
+
}
|
|
3931
|
+
function renderEndpointArgs(resolver, endpoint, options, replacements) {
|
|
3932
|
+
return getEndpointParamMapping(resolver, endpoint, options).map((param) => replacements?.[param.name] ?? param.name).join(", ");
|
|
3933
|
+
}
|
|
3934
|
+
function renderEndpointParamDescription(endpointParam) {
|
|
3935
|
+
const strs = [`${endpointParam.paramType} parameter`];
|
|
3936
|
+
const description = endpointParam.parameterObject?.description || endpointParam.bodyObject?.description;
|
|
3937
|
+
if (description) strs.push(description);
|
|
3938
|
+
let schema = void 0;
|
|
3939
|
+
let mediaTypeObject = void 0;
|
|
3940
|
+
if (endpointParam.parameterObject?.schema && isSchemaObject(endpointParam.parameterObject.schema)) schema = endpointParam.parameterObject?.schema;
|
|
3941
|
+
if (endpointParam.bodyObject?.content) {
|
|
3942
|
+
const matchingMediaType = Object.keys(endpointParam.bodyObject.content ?? {}).find(isParamMediaTypeAllowed);
|
|
3943
|
+
if (matchingMediaType) {
|
|
3944
|
+
mediaTypeObject = endpointParam.bodyObject.content[matchingMediaType];
|
|
3945
|
+
if (mediaTypeObject.schema && isSchemaObject(mediaTypeObject.schema)) schema = mediaTypeObject.schema;
|
|
3946
|
+
}
|
|
3947
|
+
}
|
|
3948
|
+
if (schema) strs.push(...getSchemaDescriptions(schema));
|
|
3949
|
+
if (mediaTypeObject?.example) strs.push(`Example: \`${mediaTypeObject.example}\``);
|
|
3950
|
+
return strs.join(". ");
|
|
3951
|
+
}
|
|
3952
|
+
function getWorkspaceParamNames(resolver, endpoint) {
|
|
3953
|
+
const endpointParams = getEndpointParamMapping(resolver, endpoint, {});
|
|
3954
|
+
const endpointParamNames = new Set(endpointParams.map((param) => param.name));
|
|
3955
|
+
const workspaceParamNames = endpointParams.filter((param) => param.paramType === "Path").map((param) => param.name);
|
|
3956
|
+
const aclParamNames = (getAbilityConditionsTypes(endpoint) ?? []).map((condition) => invalidVariableNameCharactersToCamel(condition.name)).filter((name) => endpointParamNames.has(name));
|
|
3957
|
+
return getUniqueArray([...workspaceParamNames, ...aclParamNames]);
|
|
3958
|
+
}
|
|
3959
|
+
function getWorkspaceParamReplacements(resolver, endpoint) {
|
|
3960
|
+
return Object.fromEntries(getWorkspaceParamNames(resolver, endpoint).map((name) => [name, `${name}FromWorkspace`]));
|
|
3961
|
+
}
|
|
3962
|
+
function renderWorkspaceParamResolutions({ replacements, indent }) {
|
|
3963
|
+
const workspaceParamNames = Object.keys(replacements);
|
|
3964
|
+
if (workspaceParamNames.length === 0) return [];
|
|
3965
|
+
const lines = [`${indent}const workspaceContext = OpenApiWorkspaceContext.useContext();`];
|
|
3966
|
+
for (const paramName of workspaceParamNames) lines.push(`${indent}const ${replacements[paramName]} = OpenApiWorkspaceContext.resolveParam(workspaceContext, "${paramName}", ${paramName});`);
|
|
3967
|
+
return lines;
|
|
3968
|
+
}
|
|
3969
|
+
function renderAclCheckCall(resolver, endpoint, replacements, indent = "") {
|
|
3970
|
+
const checkParams = getAbilityConditionsTypes(endpoint)?.map((condition) => invalidVariableNameCharactersToCamel(condition.name));
|
|
3971
|
+
const paramNames = new Set(endpoint.parameters.map((param) => invalidVariableNameCharactersToCamel(param.name)));
|
|
3972
|
+
const hasAllCheckParams = checkParams?.every((param) => paramNames.has(param));
|
|
3973
|
+
const args = hasAbilityConditions(endpoint) && hasAllCheckParams ? `{ ${(checkParams ?? []).map((param) => {
|
|
3974
|
+
const resolvedParam = replacements?.[param] ?? param;
|
|
3975
|
+
return resolvedParam === param ? param : `${param}: ${resolvedParam}`;
|
|
3976
|
+
}).join(", ")} } ` : "";
|
|
3977
|
+
return `${indent}checkAcl(${getImportedAbilityFunctionName(endpoint, resolver.options)}(${args}));`;
|
|
3978
|
+
}
|
|
3979
|
+
function addAsteriskAfterNewLine(str) {
|
|
3980
|
+
return str.replace(/\n/g, "\n *");
|
|
3981
|
+
}
|
|
3982
|
+
function renderQueryJsDocs({ resolver, endpoint, mode }) {
|
|
3983
|
+
const lines = ["/** "];
|
|
3984
|
+
if (mode === "infiniteQuery") lines.push(` * Infinite query \`${getInfiniteQueryName(endpoint)}${endpoint.summary ? "" : ""}`);
|
|
3985
|
+
else if (mode === "query") lines.push(` * Query \`${getQueryName(endpoint)}\`${endpoint.summary && endpoint.mediaDownload ? " - recommended when file should be cached" : ""}`);
|
|
3986
|
+
else lines.push(` * Mutation \`${getQueryName(endpoint, true)}\`${endpoint.summary && endpoint.mediaDownload ? " - recommended when file should not be cached" : ""}`);
|
|
3987
|
+
if (endpoint.summary) lines.push(` * @summary ${addAsteriskAfterNewLine(endpoint.summary)}`);
|
|
3988
|
+
if (endpoint.description) lines.push(` * @description ${addAsteriskAfterNewLine(endpoint.description)}`);
|
|
3989
|
+
if (endpoint.acl) lines.push(` * @permission Requires \`${getAbilityFunctionName(endpoint)}\` ability `);
|
|
3990
|
+
const params = getEndpointParamMapping(resolver, endpoint, { ...mode !== "infiniteQuery" ? { includeFileParam: true } : {} });
|
|
3991
|
+
for (const endpointParam of params) {
|
|
3992
|
+
const source = mode === "mutation" ? "mutation" : "object";
|
|
3993
|
+
lines.push(` * @param { ${endpointParam.type} } ${source}.${endpointParam.name} ${renderEndpointParamDescription(endpointParam)}`);
|
|
3994
|
+
}
|
|
3995
|
+
if (mode === "query") lines.push(" * @param { AppQueryOptions } options Query options");
|
|
3996
|
+
else if (mode === "mutation") lines.push(` * @param { AppMutationOptions${resolver.options.mutationEffects ? ` & ${MUTATION_EFFECTS.optionsType}` : ""} } options Mutation options`);
|
|
3997
|
+
else lines.push(" * @param { AppInfiniteQueryOptions } options Infinite query options");
|
|
3998
|
+
const withAxiosResponse = endpoint.mediaDownload && mode !== "infiniteQuery";
|
|
3999
|
+
const resultType = `${withAxiosResponse ? "AxiosResponse<" : ""}${getImportedZodSchemaInferedTypeName(resolver, endpoint.response)}${withAxiosResponse ? ">" : ""}`;
|
|
4000
|
+
if (mode === "query") lines.push(` * @returns { UseQueryResult<${resultType}> } ${endpoint.responseDescription ?? ""}`);
|
|
4001
|
+
else if (mode === "mutation") lines.push(` * @returns { UseMutationResult<${resultType}> } ${endpoint.responseDescription ?? ""}`);
|
|
4002
|
+
else lines.push(` * @returns { UseInfiniteQueryResult<${resultType}> } ${endpoint.responseDescription ?? ""}`);
|
|
4003
|
+
lines.push(` * @statusCodes [${endpoint.responseStatusCodes.join(", ")}]`);
|
|
4004
|
+
lines.push(" */");
|
|
4005
|
+
return lines.join("\n");
|
|
4006
|
+
}
|
|
4007
|
+
function renderQueryKeys({ resolver, queryEndpoints }) {
|
|
4008
|
+
if (queryEndpoints.length === 0) return "";
|
|
4009
|
+
const lines = [];
|
|
4010
|
+
lines.push("export const keys = {");
|
|
4011
|
+
lines.push(` all: [${QUERIES_MODULE_NAME}] as const,`);
|
|
4012
|
+
for (const endpoint of queryEndpoints) {
|
|
4013
|
+
lines.push(` ${getEndpointName(endpoint)}: (${renderEndpointParams(resolver, endpoint, { pathParamsRequiredOnly: true })}) => [...keys.all, "${endpoint.path}", ${renderEndpointArgs(resolver, endpoint, {})}] as const,`);
|
|
4014
|
+
if (resolver.options.infiniteQueries && isInfiniteQuery(endpoint, resolver.options)) lines.push(` ${getEndpointName(endpoint)}Infinite: (${renderEndpointParams(resolver, endpoint, {
|
|
4015
|
+
excludePageParam: true,
|
|
4016
|
+
pathParamsRequiredOnly: true
|
|
4017
|
+
})}) => [...keys.all, "${endpoint.path}", "infinite", ${renderEndpointArgs(resolver, endpoint, { excludePageParam: true })}] as const,`);
|
|
4018
|
+
}
|
|
4019
|
+
lines.push("};");
|
|
4020
|
+
return lines.join("\n");
|
|
4021
|
+
}
|
|
4022
|
+
function renderInlineEndpoints({ resolver, endpoints }) {
|
|
4023
|
+
const lines = [];
|
|
4024
|
+
for (const endpoint of endpoints) {
|
|
4025
|
+
const endpointParams = renderEndpointParams(resolver, endpoint, {});
|
|
4026
|
+
const endpointBody = getEndpointBody$1(endpoint);
|
|
4027
|
+
const hasUndefinedEndpointBody = requiresBody(endpoint) && !endpointBody && hasEndpointConfig(endpoint, resolver);
|
|
4028
|
+
const endpointConfig = renderInlineEndpointConfig(resolver, endpoint);
|
|
4029
|
+
lines.push(`const ${getEndpointName(endpoint)} = (${endpointParams}${resolver.options.axiosRequestConfig ? `${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => {`);
|
|
4030
|
+
lines.push(` return ${APP_REST_CLIENT_NAME}.${endpoint.method}(`);
|
|
4031
|
+
lines.push(` { resSchema: ${getImportedZodSchemaName(resolver, endpoint.response)} },`);
|
|
4032
|
+
lines.push(` \`${getEndpointPath(endpoint)}\`,`);
|
|
4033
|
+
if (endpointBody) lines.push(` ${resolver.options.parseRequestParams ? renderInlineEndpointParamParse(resolver, endpointBody, endpointBody.name) : endpointBody.name},`);
|
|
4034
|
+
else if (hasUndefinedEndpointBody) lines.push(" undefined,");
|
|
4035
|
+
lines.push(` ${endpointConfig}`);
|
|
4036
|
+
lines.push(" );");
|
|
4037
|
+
lines.push("};");
|
|
4038
|
+
lines.push("");
|
|
4039
|
+
}
|
|
4040
|
+
return lines;
|
|
4041
|
+
}
|
|
4042
|
+
function renderInlineEndpointParamParse(resolver, param, paramName) {
|
|
4043
|
+
const addOptional = !(param.parameterObject ?? param.bodyObject)?.required && (Boolean(param.parameterSortingEnumSchemaName) || isNamedZodSchema(param.zodSchema));
|
|
4044
|
+
const schemaValue = param.parameterSortingEnumSchemaName ? `${ZOD_EXTENDED.namespace}.${ZOD_EXTENDED.exports.sortExp}(${getImportedZodSchemaName(resolver, param.parameterSortingEnumSchemaName)})${addOptional ? ".optional()" : ""}` : `${getImportedZodSchemaName(resolver, param.zodSchema)}${addOptional ? ".optional()" : ""}`;
|
|
4045
|
+
const queryArgs = param.type === "Query" ? `, { type: "query", name: "${paramName}" }` : "";
|
|
4046
|
+
return `${ZOD_EXTENDED.namespace}.${ZOD_EXTENDED.exports.parse}(${schemaValue}, ${paramName}${queryArgs})`;
|
|
4047
|
+
}
|
|
4048
|
+
function renderInlineEndpointConfig(resolver, endpoint) {
|
|
4049
|
+
const endpointConfig = getEndpointConfig(endpoint);
|
|
4050
|
+
const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
|
|
4051
|
+
if (Object.keys(endpointConfig).length === 0) return hasAxiosRequestConfig ? AXIOS_REQUEST_CONFIG_NAME : "";
|
|
4052
|
+
const lines = [];
|
|
4053
|
+
lines.push("{");
|
|
4054
|
+
if (hasAxiosRequestConfig) lines.push(` ...${AXIOS_REQUEST_CONFIG_NAME},`);
|
|
4055
|
+
if (endpointConfig.params) {
|
|
4056
|
+
lines.push(" params: {");
|
|
4057
|
+
for (const param of endpointConfig.params) {
|
|
4058
|
+
const value = resolver.options.parseRequestParams ? renderInlineEndpointParamParse(resolver, param, param.value) : param.value;
|
|
4059
|
+
lines.push(` ${param.name}: ${value},`);
|
|
4060
|
+
}
|
|
4061
|
+
lines.push(" },");
|
|
4062
|
+
}
|
|
4063
|
+
if (endpointConfig.headers) {
|
|
4064
|
+
lines.push(" headers: {");
|
|
4065
|
+
for (const [key, value] of Object.entries(endpointConfig.headers)) lines.push(` '${key}': ${value},`);
|
|
4066
|
+
lines.push(" },");
|
|
4067
|
+
}
|
|
4068
|
+
if (endpoint.response === "z.instanceof(Blob)") lines.push(" responseType: \"blob\",");
|
|
4069
|
+
if (endpoint.mediaDownload) lines.push(" rawResponse: true,");
|
|
4070
|
+
lines.push(" }");
|
|
4071
|
+
return lines.join("\n");
|
|
4072
|
+
}
|
|
4073
|
+
function renderQuery({ resolver, endpoint, inlineEndpoints }) {
|
|
4074
|
+
const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
|
|
4075
|
+
const hasAclCheck = resolver.options.checkAcl && endpoint.acl;
|
|
4076
|
+
const workspaceParamReplacements = resolver.options.workspaceContext ? getWorkspaceParamReplacements(resolver, endpoint) : {};
|
|
4077
|
+
const endpointArgs = renderEndpointArgs(resolver, endpoint, {});
|
|
4078
|
+
const resolvedEndpointArgs = renderEndpointArgs(resolver, endpoint, {}, workspaceParamReplacements);
|
|
4079
|
+
const endpointParams = renderEndpointParams(resolver, endpoint, { optionalPathParams: resolver.options.workspaceContext });
|
|
4080
|
+
const hasQueryFn = endpointArgs.length > 0 || hasAxiosRequestConfig || hasAclCheck;
|
|
4081
|
+
const hasQueryFnBody = Boolean(hasAclCheck) || Object.keys(workspaceParamReplacements).length > 0;
|
|
4082
|
+
const importedEndpoint = inlineEndpoints ? getEndpointName(endpoint) : getImportedEndpointName(endpoint, resolver.options);
|
|
4083
|
+
const lines = [];
|
|
4084
|
+
lines.push(renderQueryJsDocs({
|
|
4085
|
+
resolver,
|
|
4086
|
+
endpoint,
|
|
4087
|
+
mode: "query"
|
|
4088
|
+
}));
|
|
4089
|
+
lines.push(`export const ${getQueryName(endpoint)} = <TData>(${endpointParams ? `{ ${endpointArgs} }: { ${endpointParams} }, ` : ""}options?: AppQueryOptions<typeof ${importedEndpoint}, TData>${hasAxiosRequestConfig ? `, ${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => {`);
|
|
4090
|
+
lines.push(" const queryConfig = OpenApiQueryConfig.useConfig();");
|
|
4091
|
+
if (hasAclCheck) lines.push(` const { checkAcl } = ${ACL_CHECK_HOOK}();`);
|
|
4092
|
+
lines.push(...renderWorkspaceParamResolutions({
|
|
4093
|
+
replacements: workspaceParamReplacements,
|
|
4094
|
+
indent: " "
|
|
4095
|
+
}));
|
|
4096
|
+
lines.push(" ");
|
|
4097
|
+
lines.push(` return ${QUERY_HOOKS.query}({`);
|
|
4098
|
+
lines.push(` queryKey: keys.${getEndpointName(endpoint)}(${resolvedEndpointArgs}),`);
|
|
4099
|
+
if (hasQueryFn) {
|
|
4100
|
+
lines.push(` queryFn: () => ${hasQueryFnBody ? "{ " : ""}`);
|
|
4101
|
+
if (hasAclCheck) lines.push(renderAclCheckCall(resolver, endpoint, workspaceParamReplacements, " "));
|
|
4102
|
+
lines.push(` ${hasQueryFnBody ? "return " : ""}${importedEndpoint}(${resolvedEndpointArgs}${hasAxiosRequestConfig ? `${resolvedEndpointArgs ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}` : ""})${hasQueryFnBody ? " }" : ""},`);
|
|
4103
|
+
} else lines.push(` queryFn: ${importedEndpoint},`);
|
|
4104
|
+
lines.push(" ...options,");
|
|
4105
|
+
lines.push(" });");
|
|
4106
|
+
lines.push("};");
|
|
4107
|
+
return lines.join("\n");
|
|
4108
|
+
}
|
|
4109
|
+
function renderMutation({ resolver, endpoint, inlineEndpoints, precomputed }) {
|
|
4110
|
+
const hasAclCheck = resolver.options.checkAcl && endpoint.acl;
|
|
4111
|
+
const hasMutationEffects = resolver.options.mutationEffects;
|
|
4112
|
+
const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
|
|
4113
|
+
const workspaceParamReplacements = resolver.options.workspaceContext ? getWorkspaceParamReplacements(resolver, endpoint) : {};
|
|
4114
|
+
const endpointParams = renderEndpointParams(resolver, endpoint, {
|
|
4115
|
+
includeFileParam: true,
|
|
4116
|
+
optionalPathParams: resolver.options.workspaceContext
|
|
4117
|
+
});
|
|
4118
|
+
const resolvedEndpointArgs = renderEndpointArgs(resolver, endpoint, {}, workspaceParamReplacements);
|
|
4119
|
+
const destructuredMutationArgs = renderEndpointArgs(resolver, endpoint, { includeFileParam: true });
|
|
4120
|
+
const endpointFunction = inlineEndpoints ? getEndpointName(endpoint) : getImportedEndpointName(endpoint, resolver.options);
|
|
4121
|
+
const updateQueryEndpoints = precomputed?.updateQueryEndpoints ?? [];
|
|
4122
|
+
const destructuredVariables = precomputed?.destructuredVariables ?? getDestructuredVariables(resolver, endpoint, updateQueryEndpoints);
|
|
4123
|
+
const hasMutationFnBody = endpoint.mediaUpload || hasAclCheck || Object.keys(workspaceParamReplacements).length > 0;
|
|
4124
|
+
const mutationVariablesType = endpoint.mediaUpload ? `${endpointParams}${endpointParams ? "; " : ""}abortController?: AbortController; onUploadProgress?: (progress: { loaded: number; total: number }) => void` : endpointParams;
|
|
4125
|
+
const lines = [];
|
|
4126
|
+
lines.push(renderQueryJsDocs({
|
|
4127
|
+
resolver,
|
|
4128
|
+
endpoint,
|
|
4129
|
+
mode: "mutation"
|
|
4130
|
+
}));
|
|
4131
|
+
lines.push(`export const ${getQueryName(endpoint, true)} = (options?: AppMutationOptions<typeof ${endpointFunction}, { ${mutationVariablesType} }>${hasMutationEffects ? ` & ${MUTATION_EFFECTS.optionsType}` : ""}${hasAxiosRequestConfig ? `, ${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => {`);
|
|
4132
|
+
lines.push(" const queryConfig = OpenApiQueryConfig.useConfig();");
|
|
4133
|
+
if (hasAclCheck) lines.push(` const { checkAcl } = ${ACL_CHECK_HOOK}();`);
|
|
4134
|
+
if (Object.keys(workspaceParamReplacements).length > 0) lines.push(" const workspaceContext = OpenApiWorkspaceContext.useContext();");
|
|
4135
|
+
if (hasMutationEffects) lines.push(` const { runMutationEffects } = useMutationEffects({ currentModule: ${QUERIES_MODULE_NAME} });`);
|
|
4136
|
+
lines.push("");
|
|
4137
|
+
lines.push(` return ${QUERY_HOOKS.mutation}({`);
|
|
4138
|
+
const mutationFnArg = endpointParams ? `{ ${destructuredMutationArgs}${endpoint.mediaUpload ? `${destructuredMutationArgs ? ", " : ""}abortController, onUploadProgress` : ""} }` : "";
|
|
4139
|
+
lines.push(` mutationFn: ${endpoint.mediaUpload ? "async " : ""}(${mutationFnArg}) => ${hasMutationFnBody ? "{ " : ""}`);
|
|
4140
|
+
for (const [paramName, resolvedParamName] of Object.entries(workspaceParamReplacements)) lines.push(` const ${resolvedParamName} = OpenApiWorkspaceContext.resolveParam(workspaceContext, "${paramName}", ${paramName});`);
|
|
4141
|
+
if (hasAclCheck) lines.push(renderAclCheckCall(resolver, endpoint, workspaceParamReplacements, " "));
|
|
4142
|
+
if (endpoint.mediaUpload) {
|
|
4143
|
+
lines.push(` const uploadInstructions = await ${endpointFunction}(${resolvedEndpointArgs}${hasAxiosRequestConfig ? `${resolvedEndpointArgs ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}` : ""});`);
|
|
4144
|
+
lines.push(" ");
|
|
4145
|
+
lines.push(" if (file && uploadInstructions.url) {");
|
|
4146
|
+
lines.push(" const method = (data?.method?.toLowerCase() ?? \"put\") as \"put\" | \"post\";");
|
|
4147
|
+
lines.push(" let dataToSend: File | FormData = file;");
|
|
4148
|
+
lines.push(" if (method === \"post\") {");
|
|
4149
|
+
lines.push(" dataToSend = new FormData();");
|
|
4150
|
+
lines.push(" if (uploadInstructions.fields) {");
|
|
4151
|
+
lines.push(" for (const [key, value] of uploadInstructions.fields) {");
|
|
4152
|
+
lines.push(" dataToSend.append(key, value);");
|
|
4153
|
+
lines.push(" }");
|
|
4154
|
+
lines.push(" }");
|
|
4155
|
+
lines.push(" dataToSend.append(\"file\", file);");
|
|
4156
|
+
lines.push(" }");
|
|
4157
|
+
lines.push(" await axios[method](uploadInstructions.url, dataToSend, {");
|
|
4158
|
+
lines.push(" headers: {");
|
|
4159
|
+
lines.push(" \"Content-Type\": file.type,");
|
|
4160
|
+
lines.push(" },");
|
|
4161
|
+
lines.push(" signal: abortController?.signal,");
|
|
4162
|
+
lines.push(" onUploadProgress: onUploadProgress");
|
|
4163
|
+
lines.push(" ? (progressEvent) => onUploadProgress({ loaded: progressEvent.loaded, total: progressEvent.total ?? 0 })");
|
|
4164
|
+
lines.push(" : undefined,");
|
|
4165
|
+
lines.push(" });");
|
|
4166
|
+
lines.push(" }");
|
|
4167
|
+
lines.push(" ");
|
|
4168
|
+
lines.push(" return uploadInstructions;");
|
|
4169
|
+
} else lines.push(` ${hasMutationFnBody ? "return " : ""}${endpointFunction}(${resolvedEndpointArgs}${hasAxiosRequestConfig ? `${resolvedEndpointArgs ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}` : ""})`);
|
|
4170
|
+
if (hasMutationFnBody) lines.push(" },");
|
|
4171
|
+
else lines.push(",");
|
|
4172
|
+
lines.push(" ...options,");
|
|
4173
|
+
if (hasMutationEffects) {
|
|
4174
|
+
lines.push(" onSuccess: async (resData, variables, onMutateResult, context) => {");
|
|
4175
|
+
if (updateQueryEndpoints.length > 0) {
|
|
4176
|
+
if (destructuredVariables.length > 0) lines.push(` const { ${destructuredVariables.join(", ")} } = variables;`);
|
|
4177
|
+
for (const [paramName, resolvedParamName] of Object.entries(workspaceParamReplacements)) lines.push(` const ${resolvedParamName} = OpenApiWorkspaceContext.resolveParam(workspaceContext, "${paramName}", ${paramName});`);
|
|
4178
|
+
lines.push(` const updateKeys = [${updateQueryEndpoints.map((e) => `keys.${getEndpointName(e)}(${renderEndpointArgs(resolver, e, { includeOnlyRequiredParams: true }, workspaceParamReplacements)})`).join(", ")}];`);
|
|
4179
|
+
lines.push(` await runMutationEffects(resData, variables, options, updateKeys);`);
|
|
4180
|
+
} else lines.push(" await runMutationEffects(resData, variables, options);");
|
|
4181
|
+
lines.push(" options?.onSuccess?.(resData, variables, onMutateResult, context);");
|
|
4182
|
+
lines.push(" },");
|
|
4183
|
+
}
|
|
4184
|
+
lines.push(" });");
|
|
4185
|
+
lines.push("};");
|
|
4186
|
+
return lines.join("\n");
|
|
4187
|
+
}
|
|
4188
|
+
function groupEndpoints(endpoints, resolver) {
|
|
4189
|
+
const queryEndpoints = [];
|
|
4190
|
+
const mutationEndpoints = [];
|
|
4191
|
+
const infiniteQueryEndpoints = [];
|
|
4192
|
+
const aclEndpoints = [];
|
|
4193
|
+
const infoByEndpoint = /* @__PURE__ */ new Map();
|
|
4194
|
+
const mutationDataByEndpoint = /* @__PURE__ */ new Map();
|
|
4195
|
+
for (const endpoint of endpoints) {
|
|
4196
|
+
const query = isQuery(endpoint);
|
|
4197
|
+
const mutation = isMutation(endpoint);
|
|
4198
|
+
const infiniteQuery = Boolean(resolver.options.infiniteQueries && query && isInfiniteQuery(endpoint, resolver.options));
|
|
4199
|
+
if (query) queryEndpoints.push(endpoint);
|
|
4200
|
+
if (mutation) mutationEndpoints.push(endpoint);
|
|
4201
|
+
if (infiniteQuery) infiniteQueryEndpoints.push(endpoint);
|
|
4202
|
+
if (endpoint.acl) aclEndpoints.push(endpoint);
|
|
4203
|
+
infoByEndpoint.set(endpoint, {
|
|
4204
|
+
query,
|
|
4205
|
+
mutation,
|
|
4206
|
+
infiniteQuery
|
|
4207
|
+
});
|
|
4208
|
+
}
|
|
4209
|
+
for (const endpoint of mutationEndpoints) {
|
|
4210
|
+
const updateQueryEndpoints = queryEndpoints.filter((queryEndpoint) => queryEndpoint.parameters.filter((param) => param.parameterObject?.required).every((pathParam) => endpoint.parameters.some((param) => param.name === pathParam.name)) && queryEndpoint.response === endpoint.response);
|
|
4211
|
+
mutationDataByEndpoint.set(endpoint, {
|
|
4212
|
+
updateQueryEndpoints,
|
|
4213
|
+
destructuredVariables: getDestructuredVariables(resolver, endpoint, updateQueryEndpoints)
|
|
4214
|
+
});
|
|
4215
|
+
}
|
|
4216
|
+
return {
|
|
4217
|
+
queryEndpoints,
|
|
4218
|
+
mutationEndpoints,
|
|
4219
|
+
infiniteQueryEndpoints,
|
|
4220
|
+
aclEndpoints,
|
|
4221
|
+
infoByEndpoint,
|
|
4222
|
+
mutationDataByEndpoint
|
|
4223
|
+
};
|
|
4224
|
+
}
|
|
4225
|
+
function renderInfiniteQuery({ resolver, endpoint, inlineEndpoints }) {
|
|
4226
|
+
const hasAclCheck = resolver.options.checkAcl && endpoint.acl;
|
|
4227
|
+
const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
|
|
4228
|
+
const workspaceParamReplacements = resolver.options.workspaceContext ? getWorkspaceParamReplacements(resolver, endpoint) : {};
|
|
4229
|
+
const endpointParams = renderEndpointParams(resolver, endpoint, {
|
|
4230
|
+
excludePageParam: true,
|
|
4231
|
+
optionalPathParams: resolver.options.workspaceContext
|
|
4232
|
+
});
|
|
4233
|
+
const endpointArgsWithoutPage = renderEndpointArgs(resolver, endpoint, { excludePageParam: true });
|
|
4234
|
+
const resolvedEndpointArgsWithoutPage = renderEndpointArgs(resolver, endpoint, { excludePageParam: true }, workspaceParamReplacements);
|
|
4235
|
+
renderEndpointArgs(resolver, endpoint, { replacePageParam: true });
|
|
4236
|
+
const resolvedEndpointArgsWithPage = renderEndpointArgs(resolver, endpoint, { replacePageParam: true }, workspaceParamReplacements);
|
|
4237
|
+
const endpointFunction = inlineEndpoints ? getEndpointName(endpoint) : getImportedEndpointName(endpoint, resolver.options);
|
|
4238
|
+
const hasQueryFnBody = Boolean(hasAclCheck) || Object.keys(workspaceParamReplacements).length > 0;
|
|
4239
|
+
const lines = [];
|
|
4240
|
+
lines.push(renderQueryJsDocs({
|
|
4241
|
+
resolver,
|
|
4242
|
+
endpoint,
|
|
4243
|
+
mode: "infiniteQuery"
|
|
4244
|
+
}));
|
|
4245
|
+
lines.push(`export const ${getInfiniteQueryName(endpoint)} = <TData>(${endpointParams ? `{ ${endpointArgsWithoutPage} }: { ${endpointParams} }, ` : ""}options?: AppInfiniteQueryOptions<typeof ${endpointFunction}, TData>${hasAxiosRequestConfig ? `, ${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => {`);
|
|
4246
|
+
lines.push(" const queryConfig = OpenApiQueryConfig.useConfig();");
|
|
4247
|
+
if (hasAclCheck) lines.push(` const { checkAcl } = ${ACL_CHECK_HOOK}();`);
|
|
4248
|
+
lines.push(...renderWorkspaceParamResolutions({
|
|
4249
|
+
replacements: workspaceParamReplacements,
|
|
4250
|
+
indent: " "
|
|
4251
|
+
}));
|
|
4252
|
+
lines.push("");
|
|
4253
|
+
lines.push(` return ${QUERY_HOOKS.infiniteQuery}({`);
|
|
4254
|
+
lines.push(` queryKey: keys.${getEndpointName(endpoint)}Infinite(${resolvedEndpointArgsWithoutPage}),`);
|
|
4255
|
+
lines.push(` queryFn: ({ pageParam }) => ${hasQueryFnBody ? "{ " : ""}`);
|
|
4256
|
+
if (hasAclCheck) lines.push(renderAclCheckCall(resolver, endpoint, workspaceParamReplacements, " "));
|
|
4257
|
+
lines.push(` ${hasQueryFnBody ? "return " : ""}${endpointFunction}(${resolvedEndpointArgsWithPage}${hasAxiosRequestConfig ? `, ${AXIOS_REQUEST_CONFIG_NAME}` : ""})${hasQueryFnBody ? " }" : ""},`);
|
|
4258
|
+
lines.push(" initialPageParam: 1,");
|
|
4259
|
+
lines.push(` getNextPageParam: ({ ${resolver.options.infiniteQueryResponseParamNames.page}, ${resolver.options.infiniteQueryResponseParamNames.totalItems}, ${resolver.options.infiniteQueryResponseParamNames.limit}: limitParam }) => {`);
|
|
4260
|
+
lines.push(` const pageParam = ${resolver.options.infiniteQueryResponseParamNames.page} ?? 1;`);
|
|
4261
|
+
lines.push(` return pageParam * limitParam < ${resolver.options.infiniteQueryResponseParamNames.totalItems} ? pageParam + 1 : null;`);
|
|
4262
|
+
lines.push(" },");
|
|
4263
|
+
lines.push(" ...options,");
|
|
4264
|
+
lines.push(" });");
|
|
4265
|
+
lines.push("};");
|
|
4266
|
+
return lines.join("\n");
|
|
4267
|
+
}
|
|
4268
|
+
|
|
4269
|
+
//#endregion
|
|
4270
|
+
//#region src/generators/generate/generateAclCheck.ts
|
|
4271
|
+
function generateAclCheck(resolver) {
|
|
4272
|
+
const abilityContextImportPath = resolver.options.abilityContextImportPath ?? ABILITY_CONTEXT_IMPORT.from;
|
|
4273
|
+
const appAbilitiesImportPath = getAppAbilitiesImportPath(resolver.options);
|
|
4274
|
+
const errorHandlingImportPath = resolver.options.errorHandlingImportPath ?? ERROR_HANDLING_IMPORT.from;
|
|
4275
|
+
const genericAppAbilities = resolver.options.abilityContextGenericAppAbilities ? `<${ACL_APP_ABILITIES}>` : "";
|
|
4276
|
+
return `import { ${CASL_ABILITY_BINDING.abilityTuple} } from "@casl/ability";
|
|
4277
|
+
import { type ${ERROR_HANDLERS.ErrorHandler}, ${ERROR_HANDLERS.SharedErrorHandler} } from "${errorHandlingImportPath}";
|
|
4278
|
+
import { ${ABILITY_CONTEXT} } from "${abilityContextImportPath}";
|
|
4279
|
+
import { useCallback } from "react";
|
|
4280
|
+
import { ${ACL_APP_ABILITIES} } from "${appAbilitiesImportPath}";
|
|
4281
|
+
|
|
4282
|
+
interface UseAclCheckProps {
|
|
4283
|
+
errorHandler?: ${ERROR_HANDLERS.ErrorHandler}<never>;
|
|
4284
|
+
}
|
|
4285
|
+
|
|
4286
|
+
export function ${ACL_CHECK_HOOK}({ errorHandler }: UseAclCheckProps = {}) {
|
|
4287
|
+
const ability = ${ABILITY_CONTEXT}.useAbility${genericAppAbilities}();
|
|
4288
|
+
|
|
4289
|
+
const checkAcl = useCallback((appAbility: ${ACL_APP_ABILITIES}) => {
|
|
4290
|
+
if (!ability.can(...(appAbility as ${CASL_ABILITY_BINDING.abilityTuple}))) {
|
|
4291
|
+
(errorHandler ?? ${ERROR_HANDLERS.SharedErrorHandler}).rethrowError(new Error("ACL check failed"));
|
|
4292
|
+
}
|
|
4293
|
+
}, [ability, errorHandler]);
|
|
4294
|
+
|
|
4295
|
+
return { checkAcl };
|
|
4296
|
+
}
|
|
4297
|
+
`;
|
|
4298
|
+
}
|
|
4299
|
+
|
|
4300
|
+
//#endregion
|
|
4301
|
+
//#region src/generators/generate/generateAppRestClient.ts
|
|
4302
|
+
function generateAppRestClient(resolver) {
|
|
4303
|
+
return `import { RestClient } from "${PACKAGE_IMPORT_PATH}";
|
|
4304
|
+
|
|
4305
|
+
export const ${APP_REST_CLIENT_NAME} = new RestClient({
|
|
4306
|
+
config: {
|
|
4307
|
+
baseURL: "${resolver.getBaseUrl()}"
|
|
4308
|
+
},
|
|
4309
|
+
});
|
|
4310
|
+
`;
|
|
4311
|
+
}
|
|
4312
|
+
|
|
4313
|
+
//#endregion
|
|
4314
|
+
//#region src/generators/generate/generateQueryModules.ts
|
|
4315
|
+
function generateQueryModules({ resolver, data }) {
|
|
4316
|
+
const modules = [];
|
|
4317
|
+
data.forEach((_, tag) => {
|
|
4318
|
+
const endpoints = data.get(tag)?.endpoints;
|
|
4319
|
+
if (!endpoints || endpoints.length === 0) return;
|
|
4320
|
+
modules.push({
|
|
4321
|
+
tag,
|
|
4322
|
+
namespace: getNamespaceName({
|
|
4323
|
+
type: GenerateType.Queries,
|
|
4324
|
+
tag,
|
|
4325
|
+
options: resolver.options
|
|
4326
|
+
})
|
|
4327
|
+
});
|
|
4328
|
+
});
|
|
4329
|
+
const lines = [];
|
|
4330
|
+
lines.push("export const enum QueryModule {");
|
|
4331
|
+
for (const module of modules) lines.push(` ${module.tag} = "${module.namespace}",`);
|
|
4332
|
+
lines.push("}");
|
|
4333
|
+
return lines.join("\n");
|
|
4334
|
+
}
|
|
4335
|
+
|
|
4336
|
+
//#endregion
|
|
4337
|
+
//#region src/generators/generate/generateZodExtended.ts
|
|
4338
|
+
function generateZodExtended(resolver) {
|
|
4339
|
+
const errorHandlingImport = {
|
|
4340
|
+
...ERROR_HANDLING_IMPORT,
|
|
4341
|
+
from: resolver.options.errorHandlingImportPath ?? ERROR_HANDLING_IMPORT.from
|
|
4342
|
+
};
|
|
4343
|
+
return `${renderImport(ZOD_IMPORT)}
|
|
4344
|
+
${renderImport(errorHandlingImport)}
|
|
4345
|
+
|
|
4346
|
+
export namespace ZodExtended {
|
|
4347
|
+
interface ParseOptions {
|
|
4348
|
+
type: "body" | "query";
|
|
4349
|
+
name?: string;
|
|
4350
|
+
errorHandler?: ${ERROR_HANDLERS.ErrorHandler}<never>;
|
|
4351
|
+
}
|
|
4352
|
+
|
|
4353
|
+
export function ${ZOD_EXTENDED.exports.parse}<ZOutput, ZInput>(
|
|
4354
|
+
schema: z.ZodType<ZOutput, ZInput>,
|
|
4355
|
+
data: unknown,
|
|
4356
|
+
{ type, name, errorHandler }: ParseOptions = { type: "body" },
|
|
4357
|
+
) {
|
|
4358
|
+
try {
|
|
4359
|
+
return schema.parse(data);
|
|
4360
|
+
} catch (e) {
|
|
4361
|
+
if (e instanceof z.ZodError) {
|
|
4362
|
+
e.name = \`FE Request \${type === "body" ? "body" : "query param"}\${name ? \` ("\${name}")\` : ""} schema mismatch - ZodError\`;
|
|
4363
|
+
}
|
|
4364
|
+
(errorHandler ?? ${ERROR_HANDLERS.SharedErrorHandler}).rethrowError(e);
|
|
4365
|
+
throw e;
|
|
4366
|
+
}
|
|
4367
|
+
}
|
|
4368
|
+
|
|
4369
|
+
function isSortExpValid(enumSchema: z.ZodEnum, data?: string) {
|
|
4370
|
+
if (data === undefined || data === "" || enumSchema.options.length === 0) {
|
|
4371
|
+
return true;
|
|
4372
|
+
}
|
|
4373
|
+
|
|
4374
|
+
const prefixedEnumOptions = \`([+-]?(\${enumSchema.options.join("|")}))\`;
|
|
4375
|
+
const commaSeparatedOptions = \`(\${prefixedEnumOptions})(\\s*,\\s*\${prefixedEnumOptions})*\`;
|
|
4376
|
+
return new RegExp(\`^\${commaSeparatedOptions}$\`).test(data);
|
|
4377
|
+
}
|
|
4378
|
+
|
|
4379
|
+
export const ${ZOD_EXTENDED.exports.sortExp} = (enumSchema: z.ZodEnum) =>
|
|
4380
|
+
z.string().superRefine((arg, ctx) => {
|
|
4381
|
+
if (!isSortExpValid(enumSchema, arg)) {
|
|
4382
|
+
ctx.addIssue({
|
|
4383
|
+
code: "invalid_value",
|
|
4384
|
+
message: "Invalid sorting string.",
|
|
4385
|
+
values: [],
|
|
4386
|
+
});
|
|
4387
|
+
}
|
|
4388
|
+
});
|
|
4389
|
+
}
|
|
4390
|
+
`;
|
|
4391
|
+
}
|
|
4392
|
+
function renderImport(importData) {
|
|
4393
|
+
return `import ${[...importData.defaultImport ? [importData.defaultImport] : [], ...importData.bindings ? [`{ ${importData.bindings.join(", ")} }`] : []].join(", ")} from "${importData.from}";`;
|
|
4394
|
+
}
|
|
4395
|
+
|
|
4396
|
+
//#endregion
|
|
4397
|
+
//#region src/generators/utils/generate-files.utils.ts
|
|
4398
|
+
function getAclFiles(data, resolver) {
|
|
4399
|
+
if (!resolver.options.acl) return [];
|
|
4400
|
+
return [{
|
|
4401
|
+
fileName: getOutputFileName({
|
|
4402
|
+
output: resolver.options.output,
|
|
4403
|
+
fileName: getFileNameWithExtension(ACL_APP_ABILITY_FILE)
|
|
4404
|
+
}),
|
|
4405
|
+
content: generateAppAcl({
|
|
4406
|
+
resolver,
|
|
4407
|
+
data
|
|
4408
|
+
})
|
|
4409
|
+
}, ...resolver.options.checkAcl ? [{
|
|
4410
|
+
fileName: getOutputFileName({
|
|
4411
|
+
output: resolver.options.output,
|
|
4412
|
+
fileName: getFileNameWithExtension(ACL_CHECK_FILE)
|
|
4413
|
+
}),
|
|
4414
|
+
content: generateAclCheck(resolver)
|
|
4415
|
+
}] : []];
|
|
4416
|
+
}
|
|
4417
|
+
function getMutationEffectsFiles(data, resolver) {
|
|
4418
|
+
if (!resolver.options.mutationEffects) return [];
|
|
4419
|
+
return [...getAssetFiles([MUTATION_EFFECTS_FILE, CROSS_TAB_QUERY_INVALIDATION_FILE], resolver), {
|
|
4420
|
+
fileName: getOutputFileName({
|
|
4421
|
+
output: resolver.options.output,
|
|
4422
|
+
fileName: getFileNameWithExtension(QUERY_MODULES_FILE)
|
|
4423
|
+
}),
|
|
4424
|
+
content: generateQueryModules({
|
|
4425
|
+
resolver,
|
|
4426
|
+
data
|
|
4427
|
+
})
|
|
4428
|
+
}];
|
|
4429
|
+
}
|
|
4430
|
+
function getZodExtendedFiles(data, resolver) {
|
|
4431
|
+
if (!resolver.options.parseRequestParams) return [];
|
|
4432
|
+
return [{
|
|
4433
|
+
fileName: getOutputFileName({
|
|
4434
|
+
output: resolver.options.output,
|
|
4435
|
+
fileName: getFileNameWithExtension(ZOD_EXTENDED_FILE)
|
|
4436
|
+
}),
|
|
4437
|
+
content: generateZodExtended(resolver)
|
|
4438
|
+
}];
|
|
4439
|
+
}
|
|
4440
|
+
function getAppRestClientFiles(resolver) {
|
|
4441
|
+
if (resolver.options.restClientImportPath !== DEFAULT_GENERATE_OPTIONS.restClientImportPath) return [];
|
|
4442
|
+
return [{
|
|
4443
|
+
fileName: getOutputFileName({
|
|
4444
|
+
output: resolver.options.output,
|
|
4445
|
+
fileName: getFileNameWithExtension(APP_REST_CLIENT_FILE)
|
|
4446
|
+
}),
|
|
4447
|
+
content: generateAppRestClient(resolver)
|
|
4448
|
+
}];
|
|
4449
|
+
}
|
|
4450
|
+
function getAssetFiles(files, resolver) {
|
|
4451
|
+
return files.map((file) => getAssetFile(file, resolver));
|
|
4452
|
+
}
|
|
4453
|
+
function getAssetFile(file, resolver) {
|
|
4454
|
+
const fileName = getFileNameWithExtension(file);
|
|
4455
|
+
let content = readAssetSync(fileName);
|
|
4456
|
+
if (file.fileName === MUTATION_EFFECTS_FILE.fileName) content = content.replace("import { OpenApiQueryConfig, QueryModule, InvalidationMap } from \"../lib/config/queryConfig.context\";", `import { OpenApiQueryConfig, InvalidationMap } from "${PACKAGE_IMPORT_PATH}";\nimport { QueryModule } from "./${QUERY_MODULES_FILE.fileName}";`);
|
|
4457
|
+
return {
|
|
4458
|
+
fileName: getOutputFileName({
|
|
4459
|
+
output: resolver.options.output,
|
|
4460
|
+
fileName
|
|
4461
|
+
}),
|
|
4462
|
+
content
|
|
4463
|
+
};
|
|
4464
|
+
}
|
|
4465
|
+
|
|
4466
|
+
//#endregion
|
|
4467
|
+
//#region src/generators/generateCodeFromOpenAPIDoc.ts
|
|
4468
|
+
function generateCodeFromOpenAPIDoc(openApiDoc, options, profiler) {
|
|
4469
|
+
const p = profiler ?? new Profiler(false);
|
|
4470
|
+
const importPath = options.standalone && options.importPath === "ts" ? "relative" : options.importPath;
|
|
4471
|
+
const { resolver, data } = p.runSync("data.extract", () => getDataFromOpenAPIDoc(openApiDoc, {
|
|
4472
|
+
...options,
|
|
4473
|
+
importPath
|
|
4474
|
+
}, p));
|
|
4475
|
+
const generateFilesData = [];
|
|
4476
|
+
const appAclTags = [];
|
|
4477
|
+
const modelsOnly = Boolean(resolver.options.modelsOnly);
|
|
4478
|
+
const shouldGenerateEndpoints = !modelsOnly && Array.from(data.keys()).some((tag) => !shouldInlineEndpointsForTag(tag, resolver.options));
|
|
4479
|
+
const generateTypes = modelsOnly ? [GenerateType.Models] : [
|
|
4480
|
+
GenerateType.Models,
|
|
4481
|
+
...shouldGenerateEndpoints ? [GenerateType.Endpoints] : [],
|
|
4482
|
+
GenerateType.Queries,
|
|
4483
|
+
...resolver.options.acl ? [GenerateType.Acl] : [],
|
|
4484
|
+
...resolver.options.builderConfigs ? [GenerateType.Configs] : []
|
|
4485
|
+
];
|
|
4486
|
+
const generateFunctions = {
|
|
4487
|
+
[GenerateType.Models]: generateModels,
|
|
4488
|
+
[GenerateType.Endpoints]: generateEndpoints,
|
|
4489
|
+
[GenerateType.Queries]: generateQueries,
|
|
4490
|
+
[GenerateType.Acl]: generateAcl,
|
|
4491
|
+
[GenerateType.Configs]: generateConfigs
|
|
4492
|
+
};
|
|
4493
|
+
data.forEach((_, tag) => {
|
|
4494
|
+
generateTypes.forEach((type) => {
|
|
4495
|
+
const content = p.runSync(`render.${type}`, () => generateFunctions[type]({
|
|
4496
|
+
resolver,
|
|
4497
|
+
data,
|
|
4498
|
+
tag
|
|
4499
|
+
}));
|
|
4500
|
+
if (content) {
|
|
4501
|
+
const fileName = getOutputFileName({
|
|
4502
|
+
output: options.output,
|
|
4503
|
+
fileName: getTagFileName({
|
|
4504
|
+
tag,
|
|
4505
|
+
type,
|
|
4506
|
+
options
|
|
4507
|
+
})
|
|
4508
|
+
});
|
|
4509
|
+
generateFilesData.push({
|
|
4510
|
+
fileName,
|
|
4511
|
+
content
|
|
4512
|
+
});
|
|
4513
|
+
if (type === GenerateType.Acl) appAclTags.push(tag);
|
|
4514
|
+
}
|
|
4515
|
+
});
|
|
4516
|
+
});
|
|
4517
|
+
if (!modelsOnly) generateFilesData.push(...p.runSync("render.AclShared", () => getAclFiles(data, resolver)), ...p.runSync("render.MutationEffects", () => getMutationEffectsFiles(data, resolver)), ...p.runSync("render.ZodExtended", () => getZodExtendedFiles(data, resolver)), ...p.runSync("render.Standalone", () => getAppRestClientFiles(resolver)));
|
|
4518
|
+
return generateFilesData;
|
|
4519
|
+
}
|
|
4520
|
+
|
|
4521
|
+
//#endregion
|
|
4522
|
+
export { VALIDATION_ERROR_TYPE_TITLE as S, isMediaTypeAllowed as _, deepMerge as a, formatTag as b, getSchemaTsMetaType as c, getTagImportPath as d, getQueryName as f, groupByType as g, GenerateType as h, getDataFromOpenAPIDoc as i, getTsTypeBase as l, getNamespaceName as m, getOutputFileName as n, isMutation as o, DEFAULT_GENERATE_OPTIONS as p, writeGenerateFileData as r, isQuery as s, generateCodeFromOpenAPIDoc as t, getTagFileName as u, isParamMediaTypeAllowed as v, Profiler as x, invalidVariableNameCharactersToCamel as y };
|