@povio/openapi-codegen-cli 3.1.1-rc.1 → 3.2.0-rc.10
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 -15
- package/dist/AuthGuard-GbtTDXs0.d.mts +32 -0
- package/dist/AuthGuard-qpAtHaBz.mjs +24 -0
- package/dist/acl.d.mts +6 -20
- package/dist/acl.mjs +8 -13
- package/dist/{auth.context-Bu5KW2sI.mjs → auth.context-COWO6ssl.mjs} +1 -21
- package/dist/auth.d.mts +2 -0
- package/dist/auth.mjs +3 -0
- package/dist/axios.d.mts +2 -0
- package/dist/axios.mjs +2 -0
- package/dist/{config-BU7wVf7U.d.mts → config-DgrOddSC.d.mts} +1 -2
- package/dist/config.d.mts +4 -0
- package/dist/config.mjs +5 -0
- package/dist/{error-handling-DSI86D3u.mjs → error-handling-BeydPL7s.mjs} +21 -51
- package/dist/{error-handling-D-mHJ60d.d.mts → error-handling-LPEPQV1V.d.mts} +3 -42
- package/dist/errors.d.mts +3 -0
- package/dist/errors.mjs +2 -0
- package/dist/generate.runner-CD7mlcJ4.mjs +184 -0
- package/dist/generate.utils-CT-LA-gX.cjs +2267 -0
- package/dist/generateCodeFromOpenAPIDoc-D9W5BtAt.mjs +2097 -0
- package/dist/{generateCodeFromOpenAPIDoc-DseBECa-.mjs → generateCodeFromOpenAPIDoc-DhI7CHeh.cjs} +1349 -2344
- package/dist/generator.d.mts +3 -10
- package/dist/generator.mjs +9 -9
- package/dist/getDataFromOpenAPIDoc-D8w0QElH.mjs +2011 -0
- package/dist/i18n-B_brQh4X.d.mts +38 -0
- package/dist/i18n-D-FesqFb.mjs +36 -0
- package/dist/index.d.mts +12 -200
- package/dist/index.mjs +12 -264
- package/dist/metro.cjs +114 -4959
- package/dist/metro.d.mts +3 -4
- package/dist/metro.mjs +4 -9
- package/dist/native-bindings-BTQGSGhU.mjs +1480 -0
- package/dist/native-rest-interceptor-CAWR8H5Y.mjs +208 -0
- package/dist/native-rest-interceptor-Cz6saoq5.d.mts +46 -0
- package/dist/native.d.mts +3 -0
- package/dist/native.mjs +3 -0
- package/dist/openapi-codegen-native-darwin-arm64.node +0 -0
- package/dist/openapi-codegen-native-linux-x64.node +0 -0
- package/dist/openapi-codegen-native-win32-x64.node +0 -0
- package/dist/{openapi-codegen.runner-Co_bG00_.mjs → openapi-codegen.runner-C4TIXQNx.mjs} +4 -5
- package/dist/{openapi-source.runner-wLs5vqw6.mjs → openapi-source.runner-BZ6ZLgRO.mjs} +19 -10
- package/dist/{openapi-source.runner-BSIrB6ny.d.mts → openapi-source.runner-ykstqlPC.d.mts} +2 -8
- package/dist/{options-CE4Koxof.d.mts → options-KPf-Fti5.d.mts} +6 -1
- package/dist/query.d.mts +3 -0
- package/dist/query.mjs +3 -0
- package/dist/queryConfig.context-CRJOgf19.d.mts +22 -0
- package/dist/queryConfig.context-CldQ5YL9.mjs +34 -0
- package/dist/rest-client-CQyFvqYC.d.mts +55 -0
- package/dist/rest-interceptor-D5NCNTm1.mjs +115 -0
- package/dist/rest-transport.types-DM5-qyOJ.d.mts +66 -0
- package/dist/rest-transport.types-DxitRtsB.mjs +11 -0
- package/dist/rest.d.mts +2 -0
- package/dist/rest.mjs +2 -0
- package/dist/rest.utils-rezWAIYL.d.mts +10 -0
- package/dist/router.context-EPlMBk3G.mjs +21 -0
- package/dist/sh.d.mts +1 -1
- package/dist/sh.mjs +41 -71
- package/dist/tiny.d.mts +1 -3
- package/dist/tiny.mjs +2 -3
- package/dist/useMutationEffects-DIdL8tlx.d.mts +29 -0
- package/dist/useMutationEffects-PB1fvKWM.mjs +68 -0
- package/dist/vite.d.mts +3 -4
- package/dist/vite.mjs +6 -10
- package/dist/workspace.context-XWvQ_7Hg.mjs +26 -0
- package/dist/workspace.context-isVY9ves.d.mts +23 -0
- package/dist/zod.d.mts +2 -7
- package/dist/zod.mjs +2 -4
- package/package.json +73 -26
- package/dist/generate.runner-C1HrS_9G.mjs +0 -90
|
@@ -0,0 +1,1480 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { OpenAPIV3 } from "openapi-types";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import path$1 from "node:path";
|
|
8
|
+
//#region src/helpers/profile.helper.ts
|
|
9
|
+
function nowMs() {
|
|
10
|
+
return Number(process.hrtime.bigint()) / 1e6;
|
|
11
|
+
}
|
|
12
|
+
var Profiler = class {
|
|
13
|
+
enabled;
|
|
14
|
+
entries = /* @__PURE__ */ new Map();
|
|
15
|
+
constructor(enabled) {
|
|
16
|
+
this.enabled = enabled;
|
|
17
|
+
}
|
|
18
|
+
add(label, elapsedMs) {
|
|
19
|
+
if (!this.enabled) return;
|
|
20
|
+
const prev = this.entries.get(label);
|
|
21
|
+
if (prev) {
|
|
22
|
+
prev.totalMs += elapsedMs;
|
|
23
|
+
prev.count += 1;
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
this.entries.set(label, {
|
|
27
|
+
totalMs: elapsedMs,
|
|
28
|
+
count: 1
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
runSync(label, fn) {
|
|
32
|
+
if (!this.enabled) return fn();
|
|
33
|
+
const startMs = nowMs();
|
|
34
|
+
try {
|
|
35
|
+
return fn();
|
|
36
|
+
} finally {
|
|
37
|
+
this.add(label, nowMs() - startMs);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async runAsync(label, fn) {
|
|
41
|
+
if (!this.enabled) return await fn();
|
|
42
|
+
const startMs = nowMs();
|
|
43
|
+
try {
|
|
44
|
+
return await fn();
|
|
45
|
+
} finally {
|
|
46
|
+
this.add(label, nowMs() - startMs);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
formatLines() {
|
|
50
|
+
if (!this.enabled) return [];
|
|
51
|
+
return Array.from(this.entries.entries()).sort((a, b) => b[1].totalMs - a[1].totalMs).map(([label, entry]) => {
|
|
52
|
+
const avgMs = entry.totalMs / entry.count;
|
|
53
|
+
return `${label}: ${entry.totalMs.toFixed(1)}ms (count: ${entry.count}, avg: ${avgMs.toFixed(2)}ms)`;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/generators/utils/string.utils.ts
|
|
59
|
+
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
60
|
+
const decapitalize = (str) => str.charAt(0).toLowerCase() + str.slice(1);
|
|
61
|
+
const kebabToCamel = (str) => str.replace(/(-\w)/g, (group) => group[1].toUpperCase());
|
|
62
|
+
const snakeToCamel = (str) => str.replace(/(_\w)/g, (group) => group[1].toUpperCase());
|
|
63
|
+
const nonWordCharactersToCamel = (str) => str.replace(/[\W_]+(\w)?/g, (_, char) => char?.toUpperCase() ?? "");
|
|
64
|
+
const suffixIfNeeded = (text, suffix = "") => text.endsWith(suffix) ? text : `${text}${suffix}`;
|
|
65
|
+
const removeSuffix = (text, suffix) => text.replace(new RegExp(`${suffix}$`), "");
|
|
66
|
+
const getLongestMostCommon = (strs) => {
|
|
67
|
+
const counter = strs.reduce((acc, str) => ({
|
|
68
|
+
...acc,
|
|
69
|
+
[str]: (acc[str] ?? 0) + 1
|
|
70
|
+
}), {});
|
|
71
|
+
return Object.entries(counter).toSorted((a, b) => {
|
|
72
|
+
if (a[1] === b[1]) return b[0].length - a[0].length;
|
|
73
|
+
return b[1] - a[1];
|
|
74
|
+
})[0]?.[0];
|
|
75
|
+
};
|
|
76
|
+
const getMostCommonAdjacentCombinationSplit = (strs) => {
|
|
77
|
+
const splits = strs.flatMap((str) => getAdjacentStringCombinations(splitByUppercase(capitalize(str))));
|
|
78
|
+
return getLongestMostCommon(splits);
|
|
79
|
+
};
|
|
80
|
+
const splitByUppercase = (str) => {
|
|
81
|
+
return str.split(/(?<![A-Z])(?=[A-Z])/).filter(Boolean);
|
|
82
|
+
};
|
|
83
|
+
const camelToSpaceSeparated = (text) => splitByUppercase(text).join(" ");
|
|
84
|
+
const getAdjacentStringCombinations = (strs, ignoreStrs = [
|
|
85
|
+
"dto",
|
|
86
|
+
"by",
|
|
87
|
+
"for",
|
|
88
|
+
"of",
|
|
89
|
+
"in",
|
|
90
|
+
"to",
|
|
91
|
+
"and",
|
|
92
|
+
"with"
|
|
93
|
+
]) => {
|
|
94
|
+
const combinations = [];
|
|
95
|
+
for (let i = 0; i < strs.length; i++) {
|
|
96
|
+
if (ignoreStrs.includes(strs[i].toLowerCase())) continue;
|
|
97
|
+
for (let j = i + 1; j <= strs.length; j++) {
|
|
98
|
+
if (ignoreStrs.includes(strs[j - 1]?.toLowerCase())) continue;
|
|
99
|
+
combinations.push(strs.slice(i, j).join(""));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return combinations;
|
|
103
|
+
};
|
|
104
|
+
const removeWord = (source, wordToRemove) => {
|
|
105
|
+
const singularWordToRemove = wordToRemove.replace(/es$|s$/g, "");
|
|
106
|
+
const pattern = new RegExp(`(${decapitalize(singularWordToRemove)}|${capitalize(singularWordToRemove)})[a-z]*(?=$|[A-Z])`, "g");
|
|
107
|
+
return source.replace(pattern, "");
|
|
108
|
+
};
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/generators/utils/tag.utils.ts
|
|
111
|
+
const formattedTagCache = /* @__PURE__ */ new Map();
|
|
112
|
+
const tagFilterCache = /* @__PURE__ */ new WeakMap();
|
|
113
|
+
function formatTag(tag) {
|
|
114
|
+
let formattedTag = formattedTagCache.get(tag);
|
|
115
|
+
if (formattedTag === void 0) {
|
|
116
|
+
formattedTag = nonWordCharactersToCamel(tag);
|
|
117
|
+
formattedTagCache.set(tag, formattedTag);
|
|
118
|
+
}
|
|
119
|
+
return formattedTag;
|
|
120
|
+
}
|
|
121
|
+
function getOperationTag(operation, options) {
|
|
122
|
+
const tag = operation.tags?.[0];
|
|
123
|
+
return formatTag(tag ?? options.defaultTag);
|
|
124
|
+
}
|
|
125
|
+
function getEndpointTag(endpoint, options) {
|
|
126
|
+
return formatTag((options.splitByTags ? endpoint.tags?.[0] : options.defaultTag) ?? options.defaultTag);
|
|
127
|
+
}
|
|
128
|
+
function isTagIncluded(tag, options) {
|
|
129
|
+
const normalizedTag = formatTag(tag).toLowerCase();
|
|
130
|
+
let filters = tagFilterCache.get(options);
|
|
131
|
+
if (!filters) {
|
|
132
|
+
filters = {
|
|
133
|
+
include: new Set(options.includeTags.map((includeTag) => formatTag(includeTag).toLowerCase())),
|
|
134
|
+
exclude: new Set(options.excludeTags.map((excludeTag) => formatTag(excludeTag).toLowerCase()))
|
|
135
|
+
};
|
|
136
|
+
tagFilterCache.set(options, filters);
|
|
137
|
+
}
|
|
138
|
+
if (filters.include.has(normalizedTag)) return true;
|
|
139
|
+
if (filters.exclude.has(normalizedTag)) return false;
|
|
140
|
+
return options.includeTags.length === 0;
|
|
141
|
+
}
|
|
142
|
+
function shouldInlineEndpointsForTag(tag, options) {
|
|
143
|
+
if (!options.inlineEndpoints) return false;
|
|
144
|
+
return !(options.inlineEndpointsExcludeModules ?? []).some((moduleName) => formatTag(moduleName).toLowerCase() === tag.toLowerCase());
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/generators/const/endpoints.const.ts
|
|
148
|
+
const JSON_APPLICATION_FORMAT = "application/json";
|
|
149
|
+
const DEFAULT_HEADERS = {
|
|
150
|
+
"Content-Type": JSON_APPLICATION_FORMAT,
|
|
151
|
+
Accept: JSON_APPLICATION_FORMAT
|
|
152
|
+
};
|
|
153
|
+
const BODY_PARAMETER_NAME = "data";
|
|
154
|
+
const AXIOS_DEFAULT_IMPORT_NAME = "axios";
|
|
155
|
+
const AXIOS_REQUEST_CONFIG_NAME = "config";
|
|
156
|
+
const AXIOS_REQUEST_CONFIG_TYPE = "AxiosRequestConfig";
|
|
157
|
+
const NATIVE_REQUEST_CONFIG_TYPE = "TransportRequestConfig";
|
|
158
|
+
const NATIVE_RESPONSE_TYPE = "TransportResponse";
|
|
159
|
+
const AXIOS_IMPORT = {
|
|
160
|
+
defaultImport: AXIOS_DEFAULT_IMPORT_NAME,
|
|
161
|
+
bindings: [],
|
|
162
|
+
typeBindings: [AXIOS_REQUEST_CONFIG_TYPE],
|
|
163
|
+
from: "axios"
|
|
164
|
+
};
|
|
165
|
+
function getRequestConfigTypeName(restClient) {
|
|
166
|
+
return restClient === "native" ? NATIVE_REQUEST_CONFIG_TYPE : AXIOS_REQUEST_CONFIG_TYPE;
|
|
167
|
+
}
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/generators/const/zod.const.ts
|
|
170
|
+
const SCHEMA_SUFFIX = "Schema";
|
|
171
|
+
const ENUM_SUFFIX = "Enum";
|
|
172
|
+
const BODY_SCHEMA_SUFFIX = "Body";
|
|
173
|
+
const PARAM_SCHEMA_SUFFIX = "Param";
|
|
174
|
+
const RESPONSE_SCHEMA_SUFFIX = "Response";
|
|
175
|
+
const ERROR_RESPONSE_SCHEMA_SUFFIX = "ErrorResponse";
|
|
176
|
+
const VOID_SCHEMA = "z.void()";
|
|
177
|
+
const ANY_SCHEMA = "z.any()";
|
|
178
|
+
const BLOB_SCHEMA = "z.instanceof(Blob)";
|
|
179
|
+
const ENUM_SCHEMA = "z.enum";
|
|
180
|
+
const INT_SCHEMA = "z.int()";
|
|
181
|
+
const NUMBER_SCHEMA = "z.number()";
|
|
182
|
+
const STRING_SCHEMA = "z.string()";
|
|
183
|
+
const EMAIL_SCHEMA = "z.email()";
|
|
184
|
+
const URL_SCHEMA = "z.url()";
|
|
185
|
+
const UUID_SCHEMA = "z.uuid()";
|
|
186
|
+
const DATETIME_SCHEMA = "z.iso.datetime({ offset: true })";
|
|
187
|
+
const ZOD_IMPORT = {
|
|
188
|
+
bindings: ["z"],
|
|
189
|
+
from: "zod"
|
|
190
|
+
};
|
|
191
|
+
//#endregion
|
|
192
|
+
//#region src/generators/const/openapi.const.ts
|
|
193
|
+
const ALLOWED_PARAM_MEDIA_TYPES = [
|
|
194
|
+
"application/octet-stream",
|
|
195
|
+
"multipart/form-data",
|
|
196
|
+
"application/x-www-form-urlencoded",
|
|
197
|
+
"*/*"
|
|
198
|
+
];
|
|
199
|
+
const ALLOWED_PATH_IN = [
|
|
200
|
+
"query",
|
|
201
|
+
"header",
|
|
202
|
+
"path"
|
|
203
|
+
];
|
|
204
|
+
const ALLOWED_METHODS = [
|
|
205
|
+
OpenAPIV3.HttpMethods.GET,
|
|
206
|
+
OpenAPIV3.HttpMethods.PUT,
|
|
207
|
+
OpenAPIV3.HttpMethods.POST,
|
|
208
|
+
OpenAPIV3.HttpMethods.DELETE,
|
|
209
|
+
OpenAPIV3.HttpMethods.OPTIONS,
|
|
210
|
+
OpenAPIV3.HttpMethods.HEAD,
|
|
211
|
+
OpenAPIV3.HttpMethods.PATCH,
|
|
212
|
+
OpenAPIV3.HttpMethods.TRACE
|
|
213
|
+
];
|
|
214
|
+
const PRIMITIVE_TYPE_LIST = [
|
|
215
|
+
"string",
|
|
216
|
+
"number",
|
|
217
|
+
"integer",
|
|
218
|
+
"boolean"
|
|
219
|
+
];
|
|
220
|
+
const COMPOSITE_KEYWORDS = [
|
|
221
|
+
"allOf",
|
|
222
|
+
"anyOf",
|
|
223
|
+
"oneOf"
|
|
224
|
+
];
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/generators/utils/openapi-schema.utils.ts
|
|
227
|
+
function isReferenceObject(obj) {
|
|
228
|
+
return obj != null && Object.prototype.hasOwnProperty.call(obj, "$ref");
|
|
229
|
+
}
|
|
230
|
+
function isSchemaObject(schema) {
|
|
231
|
+
return !isReferenceObject(schema);
|
|
232
|
+
}
|
|
233
|
+
function isArraySchemaObject(schema) {
|
|
234
|
+
return schema.type === "array";
|
|
235
|
+
}
|
|
236
|
+
function inferRequiredSchema(schema) {
|
|
237
|
+
if (!schema.allOf) throw new Error("Function inferRequiredSchema is specialized to handle item with required only in an allOf array.");
|
|
238
|
+
const [standaloneRequisites, noRequiredOnlyAllof] = schema.allOf.reduce((acc, cur) => {
|
|
239
|
+
if (isBrokenAllOfItem(cur)) {
|
|
240
|
+
const required = cur.required;
|
|
241
|
+
acc[0].push(...required ?? []);
|
|
242
|
+
} else acc[1].push(cur);
|
|
243
|
+
return acc;
|
|
244
|
+
}, [[], []]);
|
|
245
|
+
const composedRequiredSchema = {
|
|
246
|
+
properties: standaloneRequisites.reduce((acc, cur) => {
|
|
247
|
+
acc[cur] = {};
|
|
248
|
+
return acc;
|
|
249
|
+
}, {}),
|
|
250
|
+
type: "object",
|
|
251
|
+
required: standaloneRequisites
|
|
252
|
+
};
|
|
253
|
+
return {
|
|
254
|
+
noRequiredOnlyAllof,
|
|
255
|
+
composedRequiredSchema,
|
|
256
|
+
patchRequiredSchemaInLoop: (prop, getSchemaByRef) => {
|
|
257
|
+
if (isReferenceObject(prop)) {
|
|
258
|
+
const refType = getSchemaByRef(prop.$ref);
|
|
259
|
+
if (refType) composedRequiredSchema.required.forEach((required) => {
|
|
260
|
+
composedRequiredSchema.properties[required] = refType?.properties?.[required] ?? {};
|
|
261
|
+
});
|
|
262
|
+
} else {
|
|
263
|
+
const properties = prop["properties"] ?? {};
|
|
264
|
+
composedRequiredSchema.required.forEach((required) => {
|
|
265
|
+
if (properties[required]) composedRequiredSchema.properties[required] = properties[required] ?? {};
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
const isBrokenAllOfItem = (item) => {
|
|
272
|
+
return !isReferenceObject(item) && !!item.required && !item.type && !item.properties && !item?.allOf && !item?.anyOf && !item.oneOf;
|
|
273
|
+
};
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/generators/utils/openapi.utils.ts
|
|
276
|
+
const getSchemaRef = (schemaName) => `#/components/schemas/${schemaName}`;
|
|
277
|
+
const autocorrectRef = (ref) => ref[1] === "/" ? ref : "#/" + ref.slice(1);
|
|
278
|
+
const getSchemaNameByRef = (ref) => autocorrectRef(ref).split("/").at(-1);
|
|
279
|
+
function normalizeString(text) {
|
|
280
|
+
const formatted = prefixStringStartingWithNumberIfNeeded(text).normalize("NFKD").trim().replace(/\s+/g, "_").replace(/--+/g, "-").replace(/-+/g, "_").replace(/[^\w-]+/g, "_");
|
|
281
|
+
return snakeToCamel(formatted);
|
|
282
|
+
}
|
|
283
|
+
function wrapWithQuotesIfNeeded(str) {
|
|
284
|
+
if (/^[a-zA-Z]\w*$/.test(str)) return str;
|
|
285
|
+
return `"${str}"`;
|
|
286
|
+
}
|
|
287
|
+
function unwrapQuotesIfNeeded(value) {
|
|
288
|
+
if (typeof value === "string" && value.startsWith("\"") && value.endsWith("\"")) return value.slice(1, -1);
|
|
289
|
+
return value;
|
|
290
|
+
}
|
|
291
|
+
function prefixStringStartingWithNumberIfNeeded(str) {
|
|
292
|
+
const firstAsNumber = Number(str[0]);
|
|
293
|
+
if (typeof firstAsNumber === "number" && !Number.isNaN(firstAsNumber)) return "_" + str;
|
|
294
|
+
return str;
|
|
295
|
+
}
|
|
296
|
+
function pathParamToVariableName(name) {
|
|
297
|
+
const preserveUnderscore = name.replaceAll("_", "#");
|
|
298
|
+
return snakeToCamel(preserveUnderscore.replaceAll("-", "_")).replaceAll("#", "_");
|
|
299
|
+
}
|
|
300
|
+
const isPrimitiveType = (type) => PRIMITIVE_TYPE_LIST.includes(type);
|
|
301
|
+
function escapeControlCharacters(str) {
|
|
302
|
+
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) => {
|
|
303
|
+
const dec = p1.codePointAt();
|
|
304
|
+
const hex = dec.toString(16);
|
|
305
|
+
if (dec <= 255) return `\\x${`00${hex}`.slice(-2)}`;
|
|
306
|
+
return `\\u${`0000${hex}`.slice(-4)}`;
|
|
307
|
+
}).replace(/\//g, "\\/");
|
|
308
|
+
}
|
|
309
|
+
function isParamMediaTypeAllowed(mediaType) {
|
|
310
|
+
return mediaType.includes("application/") && mediaType.includes("json") || ALLOWED_PARAM_MEDIA_TYPES.includes(mediaType) || mediaType.includes("text/");
|
|
311
|
+
}
|
|
312
|
+
function isMainResponseStatus(status) {
|
|
313
|
+
return status >= 200 && status < 300;
|
|
314
|
+
}
|
|
315
|
+
function isErrorStatus(status) {
|
|
316
|
+
return !(status >= 200 && status < 300);
|
|
317
|
+
}
|
|
318
|
+
function isMediaTypeAllowed(mediaType) {
|
|
319
|
+
return mediaType.startsWith("application/");
|
|
320
|
+
}
|
|
321
|
+
const PATH_PARAM_WITH_BRACKETS_REGEX = /({\w+})/g;
|
|
322
|
+
const WORD_PRECEDED_BY_NON_WORD_CHARACTER = /[^\w\-]+/g;
|
|
323
|
+
/** @example turns `/media-objects/{id}` into `MediaObjectsById` */
|
|
324
|
+
function pathToVariableName(path) {
|
|
325
|
+
path = capitalize(kebabToCamel(path.replaceAll("/", "-")).replaceAll("-", ""));
|
|
326
|
+
const pathParams = [...path.matchAll(PATH_PARAM_WITH_BRACKETS_REGEX)];
|
|
327
|
+
if (pathParams.length > 0) {
|
|
328
|
+
const lastPathParam = pathParams.toSorted((a, b) => a.index - b.index)[pathParams.length - 1][0];
|
|
329
|
+
path = `${path.replace(PATH_PARAM_WITH_BRACKETS_REGEX, "")}By${capitalize(lastPathParam.slice(1, -1))}`;
|
|
330
|
+
}
|
|
331
|
+
return path.replace(WORD_PRECEDED_BY_NON_WORD_CHARACTER, "_");
|
|
332
|
+
}
|
|
333
|
+
const MATCHER_REGEX = /{(\b\w+(?:-\w+)*\b)}/g;
|
|
334
|
+
function replaceHyphenatedPath(path) {
|
|
335
|
+
const matches = path.match(MATCHER_REGEX);
|
|
336
|
+
if (matches === null) return path.replaceAll(MATCHER_REGEX, ":$1");
|
|
337
|
+
matches.forEach((match) => {
|
|
338
|
+
const replacement = pathParamToVariableName(match.replaceAll(MATCHER_REGEX, ":$1"));
|
|
339
|
+
path = path.replaceAll(match, replacement);
|
|
340
|
+
});
|
|
341
|
+
return path;
|
|
342
|
+
}
|
|
343
|
+
const isSortingParameterObject = (param, schema = param.schema, resolver) => {
|
|
344
|
+
const enumNames = getParameterEnumNames(param, schema);
|
|
345
|
+
return Array.isArray(enumNames) && enumNames.length > 0 && isStringLikeParameterSchema(schema, resolver);
|
|
346
|
+
};
|
|
347
|
+
function getParameterEnumNames(param, schema = param.schema) {
|
|
348
|
+
return param["x-enumNames"] ?? (schema && isSchemaObject(schema) ? schema["x-enumNames"] : void 0);
|
|
349
|
+
}
|
|
350
|
+
function isStringLikeParameterSchema(schema, resolver) {
|
|
351
|
+
if (!schema) return false;
|
|
352
|
+
if (isReferenceObject(schema)) return resolver ? isStringLikeParameterSchema(resolver.resolveObject(schema), resolver) : true;
|
|
353
|
+
if (schema.type === "string" || Array.isArray(schema.type) && schema.type.includes("string")) return true;
|
|
354
|
+
return [
|
|
355
|
+
...schema.allOf ?? [],
|
|
356
|
+
...schema.oneOf ?? [],
|
|
357
|
+
...schema.anyOf ?? []
|
|
358
|
+
].some((compositeSchema) => isStringLikeParameterSchema(compositeSchema, resolver));
|
|
359
|
+
}
|
|
360
|
+
const isPathExcluded = (path, options) => {
|
|
361
|
+
if (!options.excludePathRegex) return false;
|
|
362
|
+
return new RegExp(options.excludePathRegex).test(path);
|
|
363
|
+
};
|
|
364
|
+
//#endregion
|
|
365
|
+
//#region src/generators/utils/namespace.utils.ts
|
|
366
|
+
const getNamespaceName = ({ type, tag, options }) => `${capitalize(tag)}${options.configs[type].namespaceSuffix}`;
|
|
367
|
+
//#endregion
|
|
368
|
+
//#region src/generators/const/package.const.ts
|
|
369
|
+
const PACKAGE_IMPORT_PATH = "@povio/openapi-codegen-cli";
|
|
370
|
+
const NATIVE_PACKAGE_IMPORT_PATH = `${PACKAGE_IMPORT_PATH}/native`;
|
|
371
|
+
const REST_PACKAGE_IMPORT_PATH = `${PACKAGE_IMPORT_PATH}/rest`;
|
|
372
|
+
const QUERY_PACKAGE_IMPORT_PATH = `${PACKAGE_IMPORT_PATH}/query`;
|
|
373
|
+
const CONFIG_PACKAGE_IMPORT_PATH = `${PACKAGE_IMPORT_PATH}/config`;
|
|
374
|
+
//#endregion
|
|
375
|
+
//#region src/generators/const/deps.const.ts
|
|
376
|
+
const APP_REST_CLIENT_NAME = "AppRestClient";
|
|
377
|
+
const APP_REST_CLIENT_FILE = {
|
|
378
|
+
fileName: "app-rest-client",
|
|
379
|
+
extension: "ts"
|
|
380
|
+
};
|
|
381
|
+
const DOMAIN_ERRORS_FILE = {
|
|
382
|
+
fileName: "domain-errors",
|
|
383
|
+
extension: "ts"
|
|
384
|
+
};
|
|
385
|
+
const QUERY_OPTIONS_TYPES = {
|
|
386
|
+
query: "AppQueryOptions",
|
|
387
|
+
infiniteQuery: "AppInfiniteQueryOptions",
|
|
388
|
+
mutation: "AppMutationOptions"
|
|
389
|
+
};
|
|
390
|
+
const TEMPLATE_DATA_FILE_PATH = "src/data";
|
|
391
|
+
const ERROR_HANDLERS = {
|
|
392
|
+
ErrorHandler: "ErrorHandler",
|
|
393
|
+
SharedErrorHandler: "SharedErrorHandler"
|
|
394
|
+
};
|
|
395
|
+
ERROR_HANDLERS.ErrorHandler, ERROR_HANDLERS.SharedErrorHandler;
|
|
396
|
+
const BUILDERS_UTILS = {
|
|
397
|
+
dynamicInputs: "dynamicInputs",
|
|
398
|
+
dynamicColumns: "dynamicColumns"
|
|
399
|
+
};
|
|
400
|
+
const QUERY_MODULE_ENUM = "QueryModule";
|
|
401
|
+
const QUERY_MODULES_FILE = {
|
|
402
|
+
fileName: "queryModules",
|
|
403
|
+
extension: "ts"
|
|
404
|
+
};
|
|
405
|
+
const MUTATION_EFFECTS = {
|
|
406
|
+
optionsType: "MutationEffectsOptions",
|
|
407
|
+
hookName: "useMutationEffects",
|
|
408
|
+
runFunctionName: "runMutationEffects"
|
|
409
|
+
};
|
|
410
|
+
const ZOD_EXTENDED = {
|
|
411
|
+
namespace: "ZodExtended",
|
|
412
|
+
exports: {
|
|
413
|
+
parse: "parse",
|
|
414
|
+
sortExp: "sortExp"
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
//#endregion
|
|
418
|
+
//#region src/generators/utils/zod-schema.utils.ts
|
|
419
|
+
const getZodSchemaName = (name, schemaSuffix) => suffixIfNeeded(capitalize(normalizeString(name)), schemaSuffix);
|
|
420
|
+
const getEnumZodSchemaName = (name, enumSuffix, schemaSuffix) => suffixIfNeeded(capitalize(normalizeString(name)), `${enumSuffix}${schemaSuffix}`);
|
|
421
|
+
const isNamedZodSchema = (schema) => ["z.", `${ZOD_EXTENDED.namespace}.`].every((searchString) => !schema.startsWith(searchString));
|
|
422
|
+
const isEnumZodSchema = (schema) => schema.startsWith(ENUM_SCHEMA);
|
|
423
|
+
const getZodSchemaOperationName = (operationName, isUniqueOperationName, tag) => isUniqueOperationName ? operationName : `${tag}_${operationName}`;
|
|
424
|
+
const getBodyZodSchemaName = (operationName) => snakeToCamel(`${operationName}_${BODY_SCHEMA_SUFFIX}`);
|
|
425
|
+
const getParamZodSchemaName = (operationName, paramName) => snakeToCamel(`${operationName}_${paramName}${PARAM_SCHEMA_SUFFIX}`);
|
|
426
|
+
const getMainResponseZodSchemaName = (operationName) => snakeToCamel(`${operationName}${RESPONSE_SCHEMA_SUFFIX}`);
|
|
427
|
+
const getErrorResponseZodSchemaName = (operationName, statusCode) => snakeToCamel(`${operationName}_${statusCode}_${ERROR_RESPONSE_SCHEMA_SUFFIX}`);
|
|
428
|
+
function getResponseZodSchemaName({ statusCode, operationName, isUniqueOperationName, tag }) {
|
|
429
|
+
const status = Number(statusCode);
|
|
430
|
+
const zodSchemaOperationName = getZodSchemaOperationName(operationName, isUniqueOperationName, tag);
|
|
431
|
+
if (!isMainResponseStatus(status) && statusCode !== "default" && isErrorStatus(status)) return getErrorResponseZodSchemaName(zodSchemaOperationName, statusCode);
|
|
432
|
+
return getMainResponseZodSchemaName(zodSchemaOperationName);
|
|
433
|
+
}
|
|
434
|
+
//#endregion
|
|
435
|
+
//#region src/generators/utils/js.utils.ts
|
|
436
|
+
const isValidPropertyName = (str) => /^(?:[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+)$/.test(str);
|
|
437
|
+
const invalidVariableNameCharactersToCamel = (str) => str.replace(/^[^a-zA-Z_$]*/g, "").replace(/[^a-zA-Z0-9_$]+(\w)?/g, (_, char) => char?.toUpperCase() ?? "");
|
|
438
|
+
//#endregion
|
|
439
|
+
//#region src/generators/utils/endpoint.utils.ts
|
|
440
|
+
const isGetEndpoint = (endpoint) => endpoint.method === OpenAPIV3.HttpMethods.GET;
|
|
441
|
+
const isPaginatedGetEndpoint = (endpoint, options) => isGetEndpoint(endpoint) && Object.values(options.infiniteQueryParamNames).every((infiniteQueryParam) => endpoint.parameters.some((param) => param.name === infiniteQueryParam && param.type === "Query"));
|
|
442
|
+
const isReadAllEndpoint = (endpoint, options) => endpoint.method === OpenAPIV3.HttpMethods.GET && !isPathSegmentParam(endpoint.pathSegments.at(-1)) && isPaginatedGetEndpoint(endpoint, options);
|
|
443
|
+
const isReadEndpoint = (endpoint, readAllEndpoint) => endpoint.method === OpenAPIV3.HttpMethods.GET && hasMatchingPathWithTrailingParam(endpoint, readAllEndpoint);
|
|
444
|
+
const isCreateEndpoint = (endpoint, readAllEndpoint) => endpoint.method === OpenAPIV3.HttpMethods.POST && hasMatchingPathWithoutTrailingParam(endpoint, readAllEndpoint);
|
|
445
|
+
const isUpdateEndpoint = (endpoint, readAllEndpoint) => [OpenAPIV3.HttpMethods.PUT, OpenAPIV3.HttpMethods.PATCH].includes(endpoint.method) && hasMatchingPathWithTrailingParam(endpoint, readAllEndpoint);
|
|
446
|
+
const isDeleteEndpoint = (endpoint, readAllEndpoint) => endpoint.method === OpenAPIV3.HttpMethods.DELETE && hasMatchingPathWithTrailingParam(endpoint, readAllEndpoint);
|
|
447
|
+
const isBulkDeleteEndpoint = (endpoint, readAllEndpoint) => endpoint.method === OpenAPIV3.HttpMethods.DELETE && hasMatchingPathWithoutTrailingParam(endpoint, readAllEndpoint);
|
|
448
|
+
const getPathSegments = (path) => path.split("/").filter(Boolean);
|
|
449
|
+
const isPathSegmentParam = (pathSegment) => pathSegment?.startsWith(":");
|
|
450
|
+
const hasMatchingPath = (endpoint, readAllEndpoint) => readAllEndpoint.pathSegments.every((segment, index) => isPathSegmentParam(segment) && isPathSegmentParam(endpoint.pathSegments[index]) || segment === endpoint.pathSegments[index]);
|
|
451
|
+
const hasMatchingPathWithoutTrailingParam = (endpoint, readAllEndpoint) => endpoint.pathSegments.length === readAllEndpoint.pathSegments.length && hasMatchingPath(endpoint, readAllEndpoint);
|
|
452
|
+
const hasMatchingPathWithTrailingParam = (endpoint, readAllEndpoint) => endpoint.pathSegments.length - 1 === readAllEndpoint.pathSegments.length && isPathSegmentParam(endpoint.pathSegments.at(-1)) && hasMatchingPath(endpoint, readAllEndpoint);
|
|
453
|
+
//#endregion
|
|
454
|
+
//#region src/generators/const/options.const.ts
|
|
455
|
+
const DEFAULT_GENERATE_OPTIONS = {
|
|
456
|
+
input: "http://localhost:4000/docs-json/",
|
|
457
|
+
output: "output",
|
|
458
|
+
clearOutput: false,
|
|
459
|
+
incremental: true,
|
|
460
|
+
splitByTags: true,
|
|
461
|
+
defaultTag: "Common",
|
|
462
|
+
includeTags: [],
|
|
463
|
+
excludeTags: [],
|
|
464
|
+
excludePathRegex: "",
|
|
465
|
+
excludeRedundantZodSchemas: true,
|
|
466
|
+
tsNamespaces: true,
|
|
467
|
+
treeShakeableNamespaces: false,
|
|
468
|
+
tsPath: "@/data",
|
|
469
|
+
importPath: "ts",
|
|
470
|
+
configs: {
|
|
471
|
+
["models"]: {
|
|
472
|
+
outputFileNameSuffix: "models",
|
|
473
|
+
namespaceSuffix: "Models"
|
|
474
|
+
},
|
|
475
|
+
["endpoints"]: {
|
|
476
|
+
outputFileNameSuffix: "api",
|
|
477
|
+
namespaceSuffix: "Api"
|
|
478
|
+
},
|
|
479
|
+
["queries"]: {
|
|
480
|
+
outputFileNameSuffix: "queries",
|
|
481
|
+
namespaceSuffix: "Queries"
|
|
482
|
+
},
|
|
483
|
+
["acl"]: {
|
|
484
|
+
outputFileNameSuffix: "acl",
|
|
485
|
+
namespaceSuffix: "Acl"
|
|
486
|
+
},
|
|
487
|
+
["configs"]: {
|
|
488
|
+
outputFileNameSuffix: "configs",
|
|
489
|
+
namespaceSuffix: "Configs"
|
|
490
|
+
}
|
|
491
|
+
},
|
|
492
|
+
baseUrl: "",
|
|
493
|
+
modelsOnly: false,
|
|
494
|
+
standalone: false,
|
|
495
|
+
schemaSuffix: SCHEMA_SUFFIX,
|
|
496
|
+
enumSuffix: ENUM_SUFFIX,
|
|
497
|
+
modelsInCommon: false,
|
|
498
|
+
modelsInModules: false,
|
|
499
|
+
withDefaultValues: true,
|
|
500
|
+
extractEnums: true,
|
|
501
|
+
replaceOptionalWithNullish: false,
|
|
502
|
+
restClient: "axios",
|
|
503
|
+
restClientImportPath: "",
|
|
504
|
+
zodImportPath: "@povio/openapi-codegen-cli/zod",
|
|
505
|
+
errorHandlingImportPath: "",
|
|
506
|
+
removeOperationPrefixEndingWith: "Controller_",
|
|
507
|
+
parseRequestParams: true,
|
|
508
|
+
inlineEndpoints: false,
|
|
509
|
+
inlineEndpointsExcludeModules: [],
|
|
510
|
+
queryTypesImportPath: QUERY_PACKAGE_IMPORT_PATH,
|
|
511
|
+
mutationEffectsImportPath: QUERY_PACKAGE_IMPORT_PATH,
|
|
512
|
+
axiosRequestConfig: false,
|
|
513
|
+
mutationEffects: true,
|
|
514
|
+
mutationDefaultOnError: false,
|
|
515
|
+
workspaceContext: [],
|
|
516
|
+
prefetchQueries: true,
|
|
517
|
+
mutationScope: false,
|
|
518
|
+
infiniteQueries: false,
|
|
519
|
+
infiniteQueryParamNames: { page: "page" },
|
|
520
|
+
infiniteQueryResponseParamNames: {
|
|
521
|
+
page: "page",
|
|
522
|
+
totalItems: "totalItems",
|
|
523
|
+
limit: "limit"
|
|
524
|
+
},
|
|
525
|
+
acl: true,
|
|
526
|
+
checkAcl: true,
|
|
527
|
+
abilityContextGenericAppAbilities: false,
|
|
528
|
+
abilityContextImportPath: "",
|
|
529
|
+
aclCheckImportPath: "@povio/openapi-codegen-cli/acl",
|
|
530
|
+
builderConfigs: false,
|
|
531
|
+
filterParamName: "filter",
|
|
532
|
+
dataResponseParamNames: ["data", "items"],
|
|
533
|
+
dynamicInputsImportPath: "@povio/ui",
|
|
534
|
+
dynamicColumnsImportPath: "@povio/ui"
|
|
535
|
+
};
|
|
536
|
+
//#endregion
|
|
537
|
+
//#region src/generators/utils/array.utils.ts
|
|
538
|
+
const getUniqueArray = (...arrs) => [...new Set(arrs.flat())];
|
|
539
|
+
//#endregion
|
|
540
|
+
//#region src/generators/core/openapi/iterateSchema.ts
|
|
541
|
+
function iterateSchema(schema, options) {
|
|
542
|
+
if (!schema) return;
|
|
543
|
+
const { data, onSchema } = options;
|
|
544
|
+
if (isReferenceObject(schema) && onSchema({
|
|
545
|
+
type: "reference",
|
|
546
|
+
schema,
|
|
547
|
+
data
|
|
548
|
+
}) === true) return;
|
|
549
|
+
const schemaObj = schema;
|
|
550
|
+
if (COMPOSITE_KEYWORDS.some((prop) => prop in schemaObj && schemaObj[prop])) {
|
|
551
|
+
const schemaObjs = schemaObj.allOf ?? schemaObj.anyOf ?? schemaObj.oneOf ?? [];
|
|
552
|
+
for (const compositeObj of schemaObjs) {
|
|
553
|
+
if (onSchema?.({
|
|
554
|
+
type: "composite",
|
|
555
|
+
parentSchema: schema,
|
|
556
|
+
schema: compositeObj,
|
|
557
|
+
data
|
|
558
|
+
}) === true) continue;
|
|
559
|
+
iterateSchema(compositeObj, {
|
|
560
|
+
data,
|
|
561
|
+
onSchema
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
if (schemaObj.properties) for (const [propertyName, propertyObj] of Object.entries(schemaObj.properties)) {
|
|
566
|
+
if (onSchema({
|
|
567
|
+
type: "property",
|
|
568
|
+
parentSchema: schema,
|
|
569
|
+
schema: propertyObj,
|
|
570
|
+
data,
|
|
571
|
+
propertyName
|
|
572
|
+
}) === true) continue;
|
|
573
|
+
iterateSchema(propertyObj, options);
|
|
574
|
+
}
|
|
575
|
+
if (schemaObj.additionalProperties && typeof schemaObj.additionalProperties === "object") {
|
|
576
|
+
if (onSchema({
|
|
577
|
+
type: "additionalProperties",
|
|
578
|
+
parentSchema: schema,
|
|
579
|
+
schema: schemaObj.additionalProperties,
|
|
580
|
+
data
|
|
581
|
+
}) === true) return;
|
|
582
|
+
iterateSchema(schemaObj.additionalProperties, options);
|
|
583
|
+
}
|
|
584
|
+
if (schemaObj.type === "array") {
|
|
585
|
+
const arrayObj = schema.items;
|
|
586
|
+
if (onSchema({
|
|
587
|
+
type: "array",
|
|
588
|
+
parentSchema: schema,
|
|
589
|
+
schema: arrayObj,
|
|
590
|
+
data
|
|
591
|
+
}) === true) return;
|
|
592
|
+
iterateSchema(arrayObj, options);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
//#endregion
|
|
596
|
+
//#region src/generators/utils/generate/generate.openapi.utils.ts
|
|
597
|
+
const schemaDescriptionsCache = /* @__PURE__ */ new WeakMap();
|
|
598
|
+
function getSchemaDescriptions(schemaObj) {
|
|
599
|
+
const cachedSchemaDescriptions = schemaDescriptionsCache.get(schemaObj);
|
|
600
|
+
if (cachedSchemaDescriptions) return cachedSchemaDescriptions;
|
|
601
|
+
const schemaDescriptions = [
|
|
602
|
+
"minimum",
|
|
603
|
+
"exclusiveMinimum",
|
|
604
|
+
"maximum",
|
|
605
|
+
"exclusiveMaximum",
|
|
606
|
+
"minItems",
|
|
607
|
+
"minLength",
|
|
608
|
+
"minProperties",
|
|
609
|
+
"maxItems",
|
|
610
|
+
"maxLength",
|
|
611
|
+
"maxProperties",
|
|
612
|
+
"default",
|
|
613
|
+
"example"
|
|
614
|
+
].filter((key) => schemaObj[key] !== void 0).reduce((acc, key) => [...acc, `${capitalize(camelToSpaceSeparated(key))}: \`${schemaObj[key]}\``], []);
|
|
615
|
+
schemaDescriptionsCache.set(schemaObj, schemaDescriptions);
|
|
616
|
+
return schemaDescriptions;
|
|
617
|
+
}
|
|
618
|
+
//#endregion
|
|
619
|
+
//#region src/generators/utils/generate/generate.zod.utils.ts
|
|
620
|
+
const getZodSchemaInferedTypeName = (zodSchemaName, options) => removeSuffix(zodSchemaName, options.schemaSuffix);
|
|
621
|
+
const getImportedZodSchemaName = (resolver, zodSchemaName, namespaceTag) => {
|
|
622
|
+
if (!isNamedZodSchema(zodSchemaName)) return zodSchemaName;
|
|
623
|
+
const tag = getOwningOrLocalProxyTag(resolver, zodSchemaName, namespaceTag);
|
|
624
|
+
return `${resolver.options.tsNamespaces ? `${getNamespaceName({
|
|
625
|
+
type: "models",
|
|
626
|
+
tag,
|
|
627
|
+
options: resolver.options
|
|
628
|
+
})}.` : ""}${zodSchemaName}`;
|
|
629
|
+
};
|
|
630
|
+
function getOwningOrLocalProxyTag(resolver, zodSchemaName, namespaceTag) {
|
|
631
|
+
if (namespaceTag && (resolver.options.modelsInCommon || resolver.options.modelsInModules) && resolver.options.splitByTags) return namespaceTag;
|
|
632
|
+
return resolver.getTagByZodSchemaName(zodSchemaName) ?? namespaceTag;
|
|
633
|
+
}
|
|
634
|
+
const getImportedZodSchemaInferedTypeName = (resolver, zodSchemaName, currentTag, namespaceTag) => {
|
|
635
|
+
if (!isNamedZodSchema(zodSchemaName)) return zodSchemaName === "z.void()" ? "void" : zodSchemaName;
|
|
636
|
+
const tag = getOwningOrLocalProxyTag(resolver, zodSchemaName, namespaceTag);
|
|
637
|
+
return `${resolver.options.tsNamespaces && (Boolean(namespaceTag) || tag !== currentTag) ? `${getNamespaceName({
|
|
638
|
+
type: "models",
|
|
639
|
+
tag,
|
|
640
|
+
options: resolver.options
|
|
641
|
+
})}.` : ""}${getZodSchemaInferedTypeName(zodSchemaName, resolver.options)}`;
|
|
642
|
+
};
|
|
643
|
+
function getZodSchemaType(data) {
|
|
644
|
+
return data.isEnum ? "enum" : data.schemaObj?.type ?? "object";
|
|
645
|
+
}
|
|
646
|
+
function getZodSchemaDescription(data) {
|
|
647
|
+
if (!data.schemaObj) return;
|
|
648
|
+
return [data.schemaObj.description, ...getSchemaDescriptions(data.schemaObj)].filter(Boolean).join(". ");
|
|
649
|
+
}
|
|
650
|
+
function getType(resolver, schemaObj, tag) {
|
|
651
|
+
if (isReferenceObject(schemaObj)) {
|
|
652
|
+
const zodSchemaName = resolver.getZodSchemaNameByRef(schemaObj.$ref);
|
|
653
|
+
return zodSchemaName ? getImportedZodSchemaInferedTypeName(resolver, zodSchemaName, tag) : void 0;
|
|
654
|
+
}
|
|
655
|
+
if (isArraySchemaObject(schemaObj)) {
|
|
656
|
+
if (!isReferenceObject(schemaObj.items)) return `${schemaObj.items?.type ?? "unknown"}[]`;
|
|
657
|
+
const zodSchemaName = resolver.getZodSchemaNameByRef(schemaObj.items.$ref);
|
|
658
|
+
return zodSchemaName ? `${getImportedZodSchemaInferedTypeName(resolver, zodSchemaName, tag)}[]` : void 0;
|
|
659
|
+
}
|
|
660
|
+
if (COMPOSITE_KEYWORDS.some((prop) => prop in schemaObj && schemaObj[prop])) {
|
|
661
|
+
const schemaObjs = schemaObj.allOf ?? schemaObj.anyOf ?? schemaObj.oneOf ?? [];
|
|
662
|
+
if (schemaObjs.length > 0) return getType(resolver, schemaObjs[0], tag);
|
|
663
|
+
}
|
|
664
|
+
return schemaObj.type;
|
|
665
|
+
}
|
|
666
|
+
function getZodSchemaPropertyDescriptions(resolver, data, tag) {
|
|
667
|
+
if (!data.schemaObj) return [];
|
|
668
|
+
const ARRAY_INDEX = "[0]";
|
|
669
|
+
const ADDITIONAL_PROPERTIES_KEY = "[key]";
|
|
670
|
+
const properties = {};
|
|
671
|
+
const onSchema = (schemaData) => {
|
|
672
|
+
if (schemaData.type === "reference") return true;
|
|
673
|
+
if (schemaData.type === "composite") return;
|
|
674
|
+
const segments = [...schemaData.data?.pathSegments ?? []];
|
|
675
|
+
if (schemaData.type === "array") segments.push(ARRAY_INDEX);
|
|
676
|
+
else if (schemaData.type === "property") segments.push(schemaData.propertyName);
|
|
677
|
+
else if (schemaData.type === "additionalProperties") segments.push(ADDITIONAL_PROPERTIES_KEY);
|
|
678
|
+
if (schemaData.schema && segments[segments.length - 1] !== ARRAY_INDEX) {
|
|
679
|
+
const resolvedSchema = resolver.resolveObject(schemaData.schema);
|
|
680
|
+
const schemaDescriptions = [resolvedSchema?.description, ...getSchemaDescriptions(resolvedSchema)].filter(Boolean);
|
|
681
|
+
const propertyKey = segments.join(".");
|
|
682
|
+
if (!(properties[propertyKey] && "type" in schemaData.schema && schemaData.schema.type === "object")) {
|
|
683
|
+
delete properties[propertyKey];
|
|
684
|
+
properties[propertyKey] = {
|
|
685
|
+
type: getType(resolver, schemaData.schema, tag) ?? "unknown",
|
|
686
|
+
description: schemaDescriptions.join(". ")
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
iterateSchema(schemaData.schema, {
|
|
691
|
+
data: { pathSegments: [...segments] },
|
|
692
|
+
onSchema
|
|
693
|
+
});
|
|
694
|
+
return true;
|
|
695
|
+
};
|
|
696
|
+
if ("allOf" in data.schemaObj && data.schemaObj.allOf) data.schemaObj.allOf.forEach((schemaObj) => {
|
|
697
|
+
if (isReferenceObject(schemaObj)) iterateSchema(resolver.resolveObject(schemaObj), {
|
|
698
|
+
data: { pathSegments: [] },
|
|
699
|
+
onSchema
|
|
700
|
+
});
|
|
701
|
+
});
|
|
702
|
+
iterateSchema(data.schemaObj, {
|
|
703
|
+
data: { pathSegments: [] },
|
|
704
|
+
onSchema
|
|
705
|
+
});
|
|
706
|
+
return properties;
|
|
707
|
+
}
|
|
708
|
+
//#endregion
|
|
709
|
+
//#region src/generators/utils/generate/generate.acl.utils.ts
|
|
710
|
+
const getAbilityFunctionName = (endpoint) => `canUse${capitalize(snakeToCamel(endpoint.operationName))}`;
|
|
711
|
+
const getImportedAbilityFunctionName = (endpoint, options) => {
|
|
712
|
+
return `${options.tsNamespaces ? `${getNamespaceName({
|
|
713
|
+
type: "acl",
|
|
714
|
+
tag: getEndpointTag(endpoint, options),
|
|
715
|
+
options
|
|
716
|
+
})}.` : ""}${getAbilityFunctionName(endpoint)}`;
|
|
717
|
+
};
|
|
718
|
+
const getAbilityAction = (endpoint) => endpoint.acl?.[0].action;
|
|
719
|
+
const getAbilitySubject = (endpoint) => endpoint.acl?.[0].subject;
|
|
720
|
+
const hasAbilityConditions = (endpoint) => !!getAbilityConditionsTypes(endpoint)?.length;
|
|
721
|
+
const getAbilityConditionsTypes = (endpoint) => endpoint.acl?.[0].conditionsTypes?.sort((a, b) => a.name.localeCompare(b.name));
|
|
722
|
+
const getAbilityDescription = (endpoint) => endpoint.acl?.[0]?.description;
|
|
723
|
+
const getAbilitySubjectTypes = (endpoint, resolver, tag) => {
|
|
724
|
+
const abilitySubject = getAbilitySubject(endpoint);
|
|
725
|
+
const types = [`"${abilitySubject ?? ""}"`];
|
|
726
|
+
if (hasAbilityConditions(endpoint)) types.push(`ForcedSubject<"${abilitySubject}"> & { ${getAbilityConditionsTypes(endpoint)?.map((conditionType) => `${conditionType.name}${conditionType.required ? "" : "?"}: ${getAbilityConditionType(conditionType, resolver, tag)},`).join(" ")} }`);
|
|
727
|
+
return types;
|
|
728
|
+
};
|
|
729
|
+
function getAbilityConditionType(conditionType, resolver, tag) {
|
|
730
|
+
if (!conditionType.zodSchemaName) return conditionType.type ?? "";
|
|
731
|
+
if (!resolver) return `${conditionType.type ?? ""}${conditionType.zodSchemaName}`;
|
|
732
|
+
return getImportedZodSchemaInferedTypeName(resolver, conditionType.zodSchemaName, tag, tag);
|
|
733
|
+
}
|
|
734
|
+
function getAclData({ resolver, data, tag }) {
|
|
735
|
+
const endpoints = data.get(tag)?.endpoints.filter(({ acl }) => acl && acl.length > 0);
|
|
736
|
+
if (!endpoints || endpoints.length === 0) return;
|
|
737
|
+
const hasAdditionalAbilityImports = endpoints.some(({ acl }) => acl?.[0].conditions && Object.keys(acl[0].conditions).length > 0);
|
|
738
|
+
const aclZodSchemas = endpoints.reduce((acc, endpoint) => {
|
|
739
|
+
const zodSchemas = endpoint.acl?.[0].conditionsTypes?.reduce((acc, propertyType) => [...acc, ...propertyType?.zodSchemaName ? [propertyType.zodSchemaName] : []], []);
|
|
740
|
+
return [...acc, ...zodSchemas ?? []];
|
|
741
|
+
}, []);
|
|
742
|
+
return {
|
|
743
|
+
endpoints,
|
|
744
|
+
hasAdditionalAbilityImports,
|
|
745
|
+
modelsImports: getModelsImports({
|
|
746
|
+
resolver,
|
|
747
|
+
tag,
|
|
748
|
+
zodSchemasAsTypes: getUniqueArray(aclZodSchemas)
|
|
749
|
+
})
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
const getAppAbilitiesType = ({ resolver, data }) => {
|
|
753
|
+
const appAbilitiesTypeMap = /* @__PURE__ */ new Map();
|
|
754
|
+
const modelsImportsArr = [];
|
|
755
|
+
let hasAdditionalAbilityImports = false;
|
|
756
|
+
data.forEach((_, tag) => {
|
|
757
|
+
const aclData = getAclData({
|
|
758
|
+
resolver,
|
|
759
|
+
data,
|
|
760
|
+
tag
|
|
761
|
+
});
|
|
762
|
+
if (!aclData) return;
|
|
763
|
+
const { modelsImports: tagModelsImports, hasAdditionalAbilityImports: tagHasAdditionalAbilityImports, endpoints } = aclData;
|
|
764
|
+
modelsImportsArr.push(tagModelsImports);
|
|
765
|
+
hasAdditionalAbilityImports = hasAdditionalAbilityImports || tagHasAdditionalAbilityImports;
|
|
766
|
+
endpoints.forEach((endpoint) => {
|
|
767
|
+
const abilityAction = getAbilityAction(endpoint);
|
|
768
|
+
if (abilityAction) appAbilitiesTypeMap.set(abilityAction, /* @__PURE__ */ new Set([...appAbilitiesTypeMap.get(abilityAction) ?? [], ...getAbilitySubjectTypes(endpoint, resolver, tag)]));
|
|
769
|
+
});
|
|
770
|
+
});
|
|
771
|
+
const modelsImports = mergeImports(resolver.options, ...modelsImportsArr);
|
|
772
|
+
return {
|
|
773
|
+
appAbilitiesType: appAbilitiesTypeMap.size > 0 ? Object.fromEntries(Array.from(appAbilitiesTypeMap.entries()).map(([key, valueSet]) => [key, Array.from(valueSet)])) : void 0,
|
|
774
|
+
modelsImports,
|
|
775
|
+
hasAdditionalAbilityImports
|
|
776
|
+
};
|
|
777
|
+
};
|
|
778
|
+
/** Renders a `checkAcl(...)` call, passing the ability's conditions object only when the
|
|
779
|
+
* ability function actually expects one (i.e. the endpoint declares matching conditions). */
|
|
780
|
+
function renderAclCheckCall(resolver, endpoint, replacements, indent = "") {
|
|
781
|
+
const checkParams = getAbilityConditionsTypes(endpoint)?.map((condition) => invalidVariableNameCharactersToCamel(condition.name));
|
|
782
|
+
const paramNames = new Set(endpoint.parameters.map((param) => invalidVariableNameCharactersToCamel(param.name)));
|
|
783
|
+
const hasAllCheckParams = checkParams?.every((param) => paramNames.has(param));
|
|
784
|
+
const args = hasAbilityConditions(endpoint) && hasAllCheckParams ? `{ ${(checkParams ?? []).map((param) => {
|
|
785
|
+
const resolvedParam = replacements?.[param] ?? param;
|
|
786
|
+
return resolvedParam === param ? param : `${param}: ${resolvedParam}`;
|
|
787
|
+
}).join(", ")} } ` : "";
|
|
788
|
+
return `${indent}checkAcl(${getImportedAbilityFunctionName(endpoint, resolver.options)}(${args}));`;
|
|
789
|
+
}
|
|
790
|
+
//#endregion
|
|
791
|
+
//#region src/generators/utils/generate/generate.query.utils.ts
|
|
792
|
+
const operationNameByEndpoint = /* @__PURE__ */ new WeakMap();
|
|
793
|
+
const capitalizedOperationNameByEndpoint = /* @__PURE__ */ new WeakMap();
|
|
794
|
+
function getOperationName(endpoint) {
|
|
795
|
+
let name = operationNameByEndpoint.get(endpoint);
|
|
796
|
+
if (name === void 0) {
|
|
797
|
+
name = snakeToCamel(endpoint.operationName);
|
|
798
|
+
operationNameByEndpoint.set(endpoint, name);
|
|
799
|
+
}
|
|
800
|
+
return name;
|
|
801
|
+
}
|
|
802
|
+
function getCapitalizedOperationName(endpoint) {
|
|
803
|
+
let name = capitalizedOperationNameByEndpoint.get(endpoint);
|
|
804
|
+
if (name === void 0) {
|
|
805
|
+
name = capitalize(getOperationName(endpoint));
|
|
806
|
+
capitalizedOperationNameByEndpoint.set(endpoint, name);
|
|
807
|
+
}
|
|
808
|
+
return name;
|
|
809
|
+
}
|
|
810
|
+
const getQueryName = (endpoint, mutation) => {
|
|
811
|
+
const addMutationSuffix = isQuery(endpoint) && isMutation(endpoint) && mutation;
|
|
812
|
+
return `use${getCapitalizedOperationName(endpoint)}${addMutationSuffix ? "Mutation" : ""}`;
|
|
813
|
+
};
|
|
814
|
+
const getInfiniteQueryName = (endpoint) => `use${getCapitalizedOperationName(endpoint)}Infinite`;
|
|
815
|
+
const getQueryOptionsName = (endpoint) => `${getOperationName(endpoint)}QueryOptions`;
|
|
816
|
+
const getInfiniteQueryOptionsName = (endpoint) => `${getOperationName(endpoint)}InfiniteQueryOptions`;
|
|
817
|
+
const getPrefetchQueryName = (endpoint) => `prefetch${getCapitalizedOperationName(endpoint)}`;
|
|
818
|
+
const getPrefetchInfiniteQueryName = (endpoint) => `prefetch${getCapitalizedOperationName(endpoint)}Infinite`;
|
|
819
|
+
const getImportedQueryName = (endpoint, options) => {
|
|
820
|
+
return `${options.tsNamespaces ? `${getNamespaceName({
|
|
821
|
+
type: "queries",
|
|
822
|
+
tag: getEndpointTag(endpoint, options),
|
|
823
|
+
options
|
|
824
|
+
})}.` : ""}${getQueryName(endpoint)}`;
|
|
825
|
+
};
|
|
826
|
+
const getImportedInfiniteQueryName = (endpoint, options) => {
|
|
827
|
+
return `${options.tsNamespaces ? `${getNamespaceName({
|
|
828
|
+
type: "queries",
|
|
829
|
+
tag: getEndpointTag(endpoint, options),
|
|
830
|
+
options
|
|
831
|
+
})}.` : ""}${getInfiniteQueryName(endpoint)}`;
|
|
832
|
+
};
|
|
833
|
+
//#endregion
|
|
834
|
+
//#region src/generators/utils/generate/generate.imports.utils.ts
|
|
835
|
+
function getModelsImports({ resolver, tag, zodSchemas = [], zodSchemasAsTypes = [] }) {
|
|
836
|
+
const type = "models";
|
|
837
|
+
const getTag = (zodSchemaName) => resolver.getTagByZodSchemaName(zodSchemaName);
|
|
838
|
+
const zodSchemaImports = getImports({
|
|
839
|
+
type,
|
|
840
|
+
tag,
|
|
841
|
+
entities: zodSchemas,
|
|
842
|
+
getTag,
|
|
843
|
+
getEntityName: (zodSchema) => zodSchema,
|
|
844
|
+
options: resolver.options
|
|
845
|
+
});
|
|
846
|
+
const zodSchemaTypeImports = getImports({
|
|
847
|
+
type,
|
|
848
|
+
tag,
|
|
849
|
+
entities: zodSchemasAsTypes,
|
|
850
|
+
getTag,
|
|
851
|
+
getEntityName: (zodSchema) => getZodSchemaInferedTypeName(zodSchema, resolver.options),
|
|
852
|
+
options: resolver.options
|
|
853
|
+
}).map((importData) => ({
|
|
854
|
+
...importData,
|
|
855
|
+
...resolver.options.tsNamespaces ? {} : { typeOnly: true }
|
|
856
|
+
}));
|
|
857
|
+
return mergeImports(resolver.options, zodSchemaImports, zodSchemaTypeImports);
|
|
858
|
+
}
|
|
859
|
+
function getEndpointsImports({ tag, endpoints, options }) {
|
|
860
|
+
return getImports({
|
|
861
|
+
type: "endpoints",
|
|
862
|
+
tag,
|
|
863
|
+
entities: endpoints,
|
|
864
|
+
getTag: (endpoint) => getEndpointTag(endpoint, options),
|
|
865
|
+
getEntityName: getEndpointName,
|
|
866
|
+
options
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
function getQueriesImports({ tag, endpoints, options }) {
|
|
870
|
+
return getImports({
|
|
871
|
+
type: "queries",
|
|
872
|
+
tag,
|
|
873
|
+
entities: endpoints,
|
|
874
|
+
getTag: (endpoint) => getEndpointTag(endpoint, options),
|
|
875
|
+
getEntityName: getQueryName,
|
|
876
|
+
options
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
function getInfiniteQueriesImports({ tag, endpoints, options }) {
|
|
880
|
+
return getImports({
|
|
881
|
+
type: "queries",
|
|
882
|
+
tag,
|
|
883
|
+
entities: endpoints,
|
|
884
|
+
getTag: (endpoint) => getEndpointTag(endpoint, options),
|
|
885
|
+
getEntityName: getInfiniteQueryName,
|
|
886
|
+
options
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
function getAclImports({ tag, endpoints, options }) {
|
|
890
|
+
return getImports({
|
|
891
|
+
type: "acl",
|
|
892
|
+
tag,
|
|
893
|
+
entities: endpoints,
|
|
894
|
+
getTag: (endpoint) => getEndpointTag(endpoint, options),
|
|
895
|
+
getEntityName: getAbilityFunctionName,
|
|
896
|
+
options
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
function getImportPath(options, fromRoot = false) {
|
|
900
|
+
let importPath = options.tsPath;
|
|
901
|
+
if (options.importPath === "relative") importPath = fromRoot ? "./" : "../";
|
|
902
|
+
else if (options.importPath === "absolute") importPath = options.output;
|
|
903
|
+
else if (new RegExp(`src/data`, "g").test(options.output)) importPath = options.output.replace(new RegExp(`.*${TEMPLATE_DATA_FILE_PATH}`, "g"), options.tsPath);
|
|
904
|
+
return `${importPath}/`.replace(/\/\//g, "/");
|
|
905
|
+
}
|
|
906
|
+
function getImports({ type = "models", tag: currentTag, entities, getTag, getEntityName, options }) {
|
|
907
|
+
const imports = /* @__PURE__ */ new Map();
|
|
908
|
+
entities.forEach((entity) => {
|
|
909
|
+
const tag = type === "models" && (options.modelsInCommon || options.modelsInModules) && options.splitByTags ? currentTag : getTag(entity);
|
|
910
|
+
if (!imports.has(tag)) {
|
|
911
|
+
const sameTagDir = currentTag === tag;
|
|
912
|
+
imports.set(tag, {
|
|
913
|
+
bindings: [options.tsNamespaces ? getNamespaceName({
|
|
914
|
+
type,
|
|
915
|
+
tag,
|
|
916
|
+
options
|
|
917
|
+
}) : getEntityName(entity)],
|
|
918
|
+
from: `${sameTagDir ? "./" : getImportPath(options)}${getTagImportPath({
|
|
919
|
+
type,
|
|
920
|
+
tag,
|
|
921
|
+
includeTagDir: !sameTagDir,
|
|
922
|
+
options
|
|
923
|
+
})}`
|
|
924
|
+
});
|
|
925
|
+
} else if (!options.tsNamespaces) imports.get(tag).bindings.push(getEntityName(entity));
|
|
926
|
+
});
|
|
927
|
+
return Array.from(imports.values());
|
|
928
|
+
}
|
|
929
|
+
function mergeImports(options, ...importArrs) {
|
|
930
|
+
const merged = /* @__PURE__ */ new Map();
|
|
931
|
+
importArrs.forEach((imports) => {
|
|
932
|
+
imports.forEach((importItem) => {
|
|
933
|
+
if (!merged.has(importItem.from)) merged.set(importItem.from, {
|
|
934
|
+
...importItem,
|
|
935
|
+
bindings: importItem.typeOnly ? [] : [...importItem.bindings],
|
|
936
|
+
typeBindings: [...importItem.typeBindings ?? [], ...importItem.typeOnly ? importItem.bindings : []]
|
|
937
|
+
});
|
|
938
|
+
else {
|
|
939
|
+
const existing = merged.get(importItem.from);
|
|
940
|
+
if (!options.tsNamespaces && !importItem.typeOnly) existing.bindings.push(...importItem.bindings);
|
|
941
|
+
existing.typeBindings = [
|
|
942
|
+
...existing.typeBindings ?? [],
|
|
943
|
+
...importItem.typeBindings ?? [],
|
|
944
|
+
...importItem.typeOnly ? importItem.bindings : []
|
|
945
|
+
];
|
|
946
|
+
existing.typeOnly = false;
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
});
|
|
950
|
+
return Array.from(merged.values()).map((importItem) => ({
|
|
951
|
+
...importItem,
|
|
952
|
+
bindings: getUniqueArray(importItem.bindings),
|
|
953
|
+
typeBindings: getUniqueArray(importItem.typeBindings ?? []).filter((binding) => !importItem.bindings.includes(binding)),
|
|
954
|
+
typeOnly: Boolean(importItem.typeOnly && importItem.bindings.length === 0 && (importItem.typeBindings?.length ?? 0) > 0)
|
|
955
|
+
}));
|
|
956
|
+
}
|
|
957
|
+
//#endregion
|
|
958
|
+
//#region src/generators/utils/generate/generate.utils.ts
|
|
959
|
+
function getFileNameWithExtension({ fileName, extension }) {
|
|
960
|
+
return `${fileName}.${extension}`;
|
|
961
|
+
}
|
|
962
|
+
function getTagFileNameWithoutExtension({ type, tag, options, includeTagDir = true }) {
|
|
963
|
+
const outputFileNameSuffix = options.configs[type].outputFileNameSuffix;
|
|
964
|
+
if (!tag) return outputFileNameSuffix;
|
|
965
|
+
return `${includeTagDir ? `${decapitalize(tag)}/` : ""}${decapitalize(tag)}.${outputFileNameSuffix}`;
|
|
966
|
+
}
|
|
967
|
+
function getTagImportPath(...args) {
|
|
968
|
+
return getTagFileNameWithoutExtension(...args);
|
|
969
|
+
}
|
|
970
|
+
function getTagFileName(...args) {
|
|
971
|
+
return `${getTagFileNameWithoutExtension(...args)}.ts`;
|
|
972
|
+
}
|
|
973
|
+
function getAppRestClientImportPath(options) {
|
|
974
|
+
if (options.restClientImportPath === DEFAULT_GENERATE_OPTIONS.restClientImportPath) return `${getImportPath(options)}${APP_REST_CLIENT_FILE.fileName}`;
|
|
975
|
+
return options.restClientImportPath;
|
|
976
|
+
}
|
|
977
|
+
function getQueryModulesImportPath(options) {
|
|
978
|
+
return `${getImportPath(options)}${QUERY_MODULES_FILE.fileName}`;
|
|
979
|
+
}
|
|
980
|
+
function getQueryTypesImportPath(options) {
|
|
981
|
+
return options.queryTypesImportPath;
|
|
982
|
+
}
|
|
983
|
+
//#endregion
|
|
984
|
+
//#region src/generators/utils/ts.utils.ts
|
|
985
|
+
function primitiveTypeToTsType(type) {
|
|
986
|
+
switch (type) {
|
|
987
|
+
case "string": return "string";
|
|
988
|
+
case "number":
|
|
989
|
+
case "integer": return "number";
|
|
990
|
+
case "boolean": return "boolean";
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
function getTsTypeBase({ zodSchemaName, schema, resolver }) {
|
|
994
|
+
let type = "void";
|
|
995
|
+
let tag;
|
|
996
|
+
if (zodSchemaName && isNamedZodSchema(zodSchemaName)) {
|
|
997
|
+
type = getImportedZodSchemaInferedTypeName(resolver, zodSchemaName);
|
|
998
|
+
tag = resolver.getTagByZodSchemaName(zodSchemaName);
|
|
999
|
+
} else if (schema?.type && isPrimitiveType(schema?.type)) type = primitiveTypeToTsType(schema?.type);
|
|
1000
|
+
const splitType = type.split(".");
|
|
1001
|
+
return {
|
|
1002
|
+
type: splitType[splitType.length - 1],
|
|
1003
|
+
...splitType.length > 1 ? { namespace: splitType[0] } : {},
|
|
1004
|
+
...tag ? { importPath: getTagImportPath({
|
|
1005
|
+
type: "models",
|
|
1006
|
+
tag,
|
|
1007
|
+
includeTagDir: true,
|
|
1008
|
+
options: resolver.options
|
|
1009
|
+
}) } : {}
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
function getSchemaTsMetaType({ schema, isCircular, parentTypes, resolver }) {
|
|
1013
|
+
if (!schema) return { metaType: "primitive" };
|
|
1014
|
+
for (const compositeKeyword of COMPOSITE_KEYWORDS) {
|
|
1015
|
+
const compositeObjs = schema[compositeKeyword];
|
|
1016
|
+
if (!compositeObjs) continue;
|
|
1017
|
+
if (compositeObjs.length > 1) {
|
|
1018
|
+
const metaTypes = compositeObjs.map((compositeObj) => {
|
|
1019
|
+
return getSchemaTsMetaType({
|
|
1020
|
+
schema: resolver.resolveObject(compositeObj),
|
|
1021
|
+
parentTypes,
|
|
1022
|
+
resolver
|
|
1023
|
+
});
|
|
1024
|
+
});
|
|
1025
|
+
if (metaTypes.every(({ metaType }) => metaType === "object")) return {
|
|
1026
|
+
metaType: "object",
|
|
1027
|
+
objectProperties: metaTypes.reduce((acc, { objectProperties }) => {
|
|
1028
|
+
const objectPropertyNames = new Set(objectProperties.map(({ name }) => name));
|
|
1029
|
+
return [...acc.filter(({ name }) => !objectPropertyNames.has(name)), ...objectProperties];
|
|
1030
|
+
}, [])
|
|
1031
|
+
};
|
|
1032
|
+
else return {
|
|
1033
|
+
metaType: "composite",
|
|
1034
|
+
[compositeKeyword]: metaTypes
|
|
1035
|
+
};
|
|
1036
|
+
} else schema = resolver.resolveObject(compositeObjs[0]);
|
|
1037
|
+
}
|
|
1038
|
+
if (schema.type === "array") return {
|
|
1039
|
+
metaType: "array",
|
|
1040
|
+
arrayType: getArraySchemaTsType({
|
|
1041
|
+
arraySchema: schema,
|
|
1042
|
+
resolver,
|
|
1043
|
+
parentTypes
|
|
1044
|
+
})
|
|
1045
|
+
};
|
|
1046
|
+
else if ((schema.type === "object" || schema.properties) && isCircular) return {
|
|
1047
|
+
metaType: "object",
|
|
1048
|
+
objectProperties: [],
|
|
1049
|
+
isCircular: true
|
|
1050
|
+
};
|
|
1051
|
+
else if (schema.type === "object" || schema.properties) return {
|
|
1052
|
+
metaType: "object",
|
|
1053
|
+
objectProperties: getSchemaTsProperties({
|
|
1054
|
+
schema,
|
|
1055
|
+
parentTypes,
|
|
1056
|
+
resolver
|
|
1057
|
+
})
|
|
1058
|
+
};
|
|
1059
|
+
return { metaType: "primitive" };
|
|
1060
|
+
}
|
|
1061
|
+
function getArraySchemaTsType({ arraySchema, parentTypes, resolver }) {
|
|
1062
|
+
let zodSchemaName;
|
|
1063
|
+
let schema;
|
|
1064
|
+
if (isReferenceObject(arraySchema.items)) {
|
|
1065
|
+
const ref = arraySchema.items.$ref;
|
|
1066
|
+
zodSchemaName = resolver.getZodSchemaNameByRef(ref);
|
|
1067
|
+
schema = resolver.getSchemaByRef(ref);
|
|
1068
|
+
} else schema = arraySchema.items;
|
|
1069
|
+
const tsType = getTsTypeBase({
|
|
1070
|
+
zodSchemaName,
|
|
1071
|
+
schema,
|
|
1072
|
+
resolver
|
|
1073
|
+
});
|
|
1074
|
+
const isCircular = getIsCircular(tsType, parentTypes);
|
|
1075
|
+
const tsMetaType = getSchemaTsMetaType({
|
|
1076
|
+
schema,
|
|
1077
|
+
isCircular,
|
|
1078
|
+
parentTypes: [...parentTypes, tsType],
|
|
1079
|
+
resolver
|
|
1080
|
+
});
|
|
1081
|
+
return {
|
|
1082
|
+
...tsType,
|
|
1083
|
+
...tsMetaType
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
function getSchemaTsProperties({ schema, parentTypes, resolver }) {
|
|
1087
|
+
return Object.entries(schema?.properties ?? {}).map(([name, property]) => {
|
|
1088
|
+
const isRequired = schema?.required?.includes(name) ?? false;
|
|
1089
|
+
if (isReferenceObject(property)) {
|
|
1090
|
+
const zodSchemaName = resolver.getZodSchemaNameByRef(property.$ref);
|
|
1091
|
+
const schema = resolver.getSchemaByRef(property.$ref);
|
|
1092
|
+
const tsType = getTsTypeBase({
|
|
1093
|
+
zodSchemaName,
|
|
1094
|
+
schema,
|
|
1095
|
+
resolver
|
|
1096
|
+
});
|
|
1097
|
+
const tsMetaType = getSchemaTsMetaType({
|
|
1098
|
+
schema,
|
|
1099
|
+
isCircular: getIsCircular(tsType, parentTypes),
|
|
1100
|
+
parentTypes: [...parentTypes, tsType],
|
|
1101
|
+
resolver
|
|
1102
|
+
});
|
|
1103
|
+
return {
|
|
1104
|
+
name,
|
|
1105
|
+
isRequired,
|
|
1106
|
+
...tsType,
|
|
1107
|
+
...tsMetaType
|
|
1108
|
+
};
|
|
1109
|
+
} else if (property.type === "array") return {
|
|
1110
|
+
name,
|
|
1111
|
+
isRequired,
|
|
1112
|
+
type: "array",
|
|
1113
|
+
metaType: "array",
|
|
1114
|
+
arrayType: getArraySchemaTsType({
|
|
1115
|
+
arraySchema: property,
|
|
1116
|
+
parentTypes,
|
|
1117
|
+
resolver
|
|
1118
|
+
})
|
|
1119
|
+
};
|
|
1120
|
+
else if (isPrimitiveType(property.type)) return {
|
|
1121
|
+
name,
|
|
1122
|
+
isRequired,
|
|
1123
|
+
type: primitiveTypeToTsType(property.type),
|
|
1124
|
+
metaType: "primitive"
|
|
1125
|
+
};
|
|
1126
|
+
return {
|
|
1127
|
+
name,
|
|
1128
|
+
isRequired,
|
|
1129
|
+
type: "void",
|
|
1130
|
+
metaType: "primitive"
|
|
1131
|
+
};
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
function getIsCircular(tsType, parentTypes) {
|
|
1135
|
+
return parentTypes.findIndex(({ type, namespace }) => type === tsType.type && namespace === tsType.namespace) > -1;
|
|
1136
|
+
}
|
|
1137
|
+
//#endregion
|
|
1138
|
+
//#region src/generators/utils/generate/generate.endpoints.utils.ts
|
|
1139
|
+
const endpointNameCache = /* @__PURE__ */ new WeakMap();
|
|
1140
|
+
const endpointPathCache = /* @__PURE__ */ new WeakMap();
|
|
1141
|
+
const endpointBodyCache = /* @__PURE__ */ new WeakMap();
|
|
1142
|
+
const endpointConfigCache = /* @__PURE__ */ new WeakMap();
|
|
1143
|
+
const getEndpointName = (endpoint) => {
|
|
1144
|
+
let name = endpointNameCache.get(endpoint);
|
|
1145
|
+
if (name === void 0) {
|
|
1146
|
+
name = decapitalize(snakeToCamel(endpoint.operationName));
|
|
1147
|
+
endpointNameCache.set(endpoint, name);
|
|
1148
|
+
}
|
|
1149
|
+
return name;
|
|
1150
|
+
};
|
|
1151
|
+
function getImportedEndpointName(endpoint, options) {
|
|
1152
|
+
return `${options.tsNamespaces ? `${getNamespaceName({
|
|
1153
|
+
type: "endpoints",
|
|
1154
|
+
tag: getEndpointTag(endpoint, options),
|
|
1155
|
+
options
|
|
1156
|
+
})}.` : ""}${getEndpointName(endpoint)}`;
|
|
1157
|
+
}
|
|
1158
|
+
const requiresBody = (endpoint) => endpoint.method !== OpenAPIV3.HttpMethods.GET;
|
|
1159
|
+
const findEndpointBody = (endpoint) => endpoint.parameters.find((param) => param.type === "Body");
|
|
1160
|
+
const getEndpointBody = (endpoint) => {
|
|
1161
|
+
if (!endpointBodyCache.has(endpoint)) endpointBodyCache.set(endpoint, findEndpointBody(endpoint));
|
|
1162
|
+
return endpointBodyCache.get(endpoint);
|
|
1163
|
+
};
|
|
1164
|
+
const hasEndpointConfig = (endpoint, resolver) => {
|
|
1165
|
+
const endpointConfig = getEndpointConfig(endpoint);
|
|
1166
|
+
const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
|
|
1167
|
+
const needsBlobConfig = endpoint.mediaDownload || endpoint.response === "z.instanceof(Blob)";
|
|
1168
|
+
return Object.keys(endpointConfig).length > 0 || hasAxiosRequestConfig || needsBlobConfig;
|
|
1169
|
+
};
|
|
1170
|
+
const getEndpointPath = (endpoint) => {
|
|
1171
|
+
let endpointPath = endpointPathCache.get(endpoint);
|
|
1172
|
+
if (endpointPath === void 0) {
|
|
1173
|
+
endpointPath = endpoint.path.replace(/:([a-zA-Z0-9_]+)/g, "${$1}");
|
|
1174
|
+
endpointPathCache.set(endpoint, endpointPath);
|
|
1175
|
+
}
|
|
1176
|
+
return endpointPath;
|
|
1177
|
+
};
|
|
1178
|
+
function mapEndpointParamsToFunctionParams(resolver, endpoint, options) {
|
|
1179
|
+
const optionalPathParams = options?.optionalPathParams ? new Set(options.optionalPathParams) : void 0;
|
|
1180
|
+
const params = endpoint.parameters.map((param) => {
|
|
1181
|
+
let type = "string";
|
|
1182
|
+
if (isNamedZodSchema(param.zodSchema)) type = getImportedZodSchemaInferedTypeName(resolver, param.zodSchema, void 0, options?.modelNamespaceTag);
|
|
1183
|
+
else if (param.parameterObject?.schema && isSchemaObject(param.parameterObject.schema)) {
|
|
1184
|
+
const openApiSchemaType = (param.parameterObject?.schema)?.type;
|
|
1185
|
+
if (openApiSchemaType && isPrimitiveType(openApiSchemaType)) type = primitiveTypeToTsType(openApiSchemaType);
|
|
1186
|
+
}
|
|
1187
|
+
return {
|
|
1188
|
+
name: invalidVariableNameCharactersToCamel(param.name),
|
|
1189
|
+
type,
|
|
1190
|
+
paramType: param.type,
|
|
1191
|
+
required: param.parameterObject?.required ?? true,
|
|
1192
|
+
parameterObject: param.parameterObject,
|
|
1193
|
+
bodyObject: param.bodyObject
|
|
1194
|
+
};
|
|
1195
|
+
});
|
|
1196
|
+
if (options?.includeFileParam && endpoint.mediaUpload) params.push({
|
|
1197
|
+
name: "file",
|
|
1198
|
+
type: "File",
|
|
1199
|
+
paramType: "Body",
|
|
1200
|
+
required: false,
|
|
1201
|
+
parameterObject: void 0,
|
|
1202
|
+
bodyObject: void 0
|
|
1203
|
+
});
|
|
1204
|
+
return params.toSorted((a, b) => {
|
|
1205
|
+
if (a.required === b.required) {
|
|
1206
|
+
const sortedParamTypes = [
|
|
1207
|
+
"Path",
|
|
1208
|
+
"Body",
|
|
1209
|
+
"Query",
|
|
1210
|
+
"Header"
|
|
1211
|
+
];
|
|
1212
|
+
return sortedParamTypes.indexOf(a.paramType) - sortedParamTypes.indexOf(b.paramType);
|
|
1213
|
+
}
|
|
1214
|
+
return a.required ? -1 : 1;
|
|
1215
|
+
}).filter((param) => (!options?.excludeBodyParam || param.name !== "data") && (!options?.excludePageParam || param.name !== resolver.options.infiniteQueryParamNames.page) && (!options?.includeOnlyRequiredParams || param.required) && (!options?.excludePathParams || param.paramType !== "Path")).map((param) => ({
|
|
1216
|
+
...param,
|
|
1217
|
+
name: options?.replacePageParam && param.name === resolver.options.infiniteQueryParamNames.page ? "pageParam" : param.name,
|
|
1218
|
+
required: param.paramType === "Path" && optionalPathParams?.has(param.name) ? false : param.required && (param.paramType === "Path" || !options?.pathParamsRequiredOnly)
|
|
1219
|
+
}));
|
|
1220
|
+
}
|
|
1221
|
+
function getEndpointConfig(endpoint) {
|
|
1222
|
+
let config = endpointConfigCache.get(endpoint);
|
|
1223
|
+
if (!config) {
|
|
1224
|
+
config = createEndpointConfig(endpoint);
|
|
1225
|
+
endpointConfigCache.set(endpoint, config);
|
|
1226
|
+
}
|
|
1227
|
+
return config;
|
|
1228
|
+
}
|
|
1229
|
+
function createEndpointConfig(endpoint) {
|
|
1230
|
+
const params = endpoint.parameters.filter((param) => param.type === "Query").map((param) => {
|
|
1231
|
+
const paramPropertyName = isValidPropertyName(param.name) ? param.name : `"${param.name}"`;
|
|
1232
|
+
const paramVariableName = invalidVariableNameCharactersToCamel(param.name);
|
|
1233
|
+
return {
|
|
1234
|
+
...param,
|
|
1235
|
+
name: paramPropertyName,
|
|
1236
|
+
value: paramVariableName
|
|
1237
|
+
};
|
|
1238
|
+
});
|
|
1239
|
+
const headers = {};
|
|
1240
|
+
if (endpoint.requestFormat !== DEFAULT_HEADERS["Content-Type"]) headers["Content-Type"] = `'${endpoint.requestFormat}'`;
|
|
1241
|
+
if (endpoint.responseFormat && endpoint.responseFormat !== DEFAULT_HEADERS.Accept) headers.Accept = `'${endpoint.responseFormat}'`;
|
|
1242
|
+
endpoint.parameters.filter((param) => param.type === "Header").forEach((param) => {
|
|
1243
|
+
headers[param.name] = invalidVariableNameCharactersToCamel(param.name);
|
|
1244
|
+
});
|
|
1245
|
+
return {
|
|
1246
|
+
...params.length > 0 ? { params } : {},
|
|
1247
|
+
...Object.keys(headers).length ? { headers } : {}
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
/** Renders the body of a media-upload mutationFn: call the endpoint (without the file arg) to
|
|
1251
|
+
* get upload instructions, then upload the file itself to the returned URL. Shared between
|
|
1252
|
+
* renderMutation (*.queries.ts) and renderMutationContent (*.configs.ts / builderConfigs) so
|
|
1253
|
+
* both mutation paths stay in sync. Lines are relative to the caller's own indent. */
|
|
1254
|
+
function renderMediaUploadMutationBody({ resolver, endpointFunction, resolvedEndpointArgs }) {
|
|
1255
|
+
return [
|
|
1256
|
+
`const uploadInstructions = await ${endpointFunction}(${resolvedEndpointArgs}${resolver.options.axiosRequestConfig ? `${resolvedEndpointArgs ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}` : ""});`,
|
|
1257
|
+
"",
|
|
1258
|
+
"if (file && uploadInstructions.url) {",
|
|
1259
|
+
` const method = (uploadInstructions.method?.toLowerCase() ?? "put") as "put" | "post";`,
|
|
1260
|
+
" let dataToSend: File | FormData = file;",
|
|
1261
|
+
" if (method === \"post\") {",
|
|
1262
|
+
" dataToSend = new FormData();",
|
|
1263
|
+
" if (uploadInstructions.fields) {",
|
|
1264
|
+
" for (const [key, value] of uploadInstructions.fields) {",
|
|
1265
|
+
" dataToSend.append(key, value);",
|
|
1266
|
+
" }",
|
|
1267
|
+
" }",
|
|
1268
|
+
" dataToSend.append(\"file\", file);",
|
|
1269
|
+
" }",
|
|
1270
|
+
resolver.options.restClient === "native" ? " await AppRestClient.upload(uploadInstructions.url, dataToSend, {" : " await axios[method](uploadInstructions.url, dataToSend, {",
|
|
1271
|
+
resolver.options.restClient === "native" ? " headers: method === \"put\" ? { \"Content-Type\": file.type } : undefined," : " headers: {",
|
|
1272
|
+
...resolver.options.restClient === "native" ? [] : [" \"Content-Type\": file.type,", " },"],
|
|
1273
|
+
" signal: abortController?.signal,",
|
|
1274
|
+
" onUploadProgress: onUploadProgress",
|
|
1275
|
+
" ? (progressEvent) => onUploadProgress({ loaded: progressEvent.loaded, total: progressEvent.total ?? 0 })",
|
|
1276
|
+
" : undefined,",
|
|
1277
|
+
resolver.options.restClient === "native" ? " }, method);" : " });",
|
|
1278
|
+
"}",
|
|
1279
|
+
"",
|
|
1280
|
+
"return uploadInstructions;"
|
|
1281
|
+
];
|
|
1282
|
+
}
|
|
1283
|
+
//#endregion
|
|
1284
|
+
//#region src/generators/utils/query.utils.ts
|
|
1285
|
+
const isQuery = (endpoint) => isGetEndpoint(endpoint);
|
|
1286
|
+
const isMutation = (endpoint) => !isGetEndpoint(endpoint) || !!endpoint.mediaDownload;
|
|
1287
|
+
const isInfiniteQuery = (endpoint, options) => isPaginatedGetEndpoint(endpoint, options);
|
|
1288
|
+
const getDestructuredVariables = (resolver, endpoint, updateQueryEndpoints) => {
|
|
1289
|
+
const requiredUpdateQueryParams = updateQueryEndpoints.reduce((acc, updateEndpoint) => [...acc, ...mapEndpointParamsToFunctionParams(resolver, updateEndpoint, { includeOnlyRequiredParams: true }).map((param) => param.name)], []);
|
|
1290
|
+
return mapEndpointParamsToFunctionParams(resolver, endpoint, {
|
|
1291
|
+
includeOnlyRequiredParams: true,
|
|
1292
|
+
excludeBodyParam: true
|
|
1293
|
+
}).filter((param) => requiredUpdateQueryParams.includes(param.name)).map((param) => param.name);
|
|
1294
|
+
};
|
|
1295
|
+
//#endregion
|
|
1296
|
+
//#region src/generators/utils/object.utils.ts
|
|
1297
|
+
/** Pick given properties in object */
|
|
1298
|
+
function pick(obj, paths) {
|
|
1299
|
+
const result = {};
|
|
1300
|
+
Object.keys(obj).forEach((key) => {
|
|
1301
|
+
if (!paths.includes(key)) return;
|
|
1302
|
+
result[key] = obj[key];
|
|
1303
|
+
});
|
|
1304
|
+
return result;
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* Deep merge two or more objects/arrays recursively.
|
|
1308
|
+
* Arrays are concatenated, objects are merged recursively.
|
|
1309
|
+
* Later arguments take precedence over earlier ones.
|
|
1310
|
+
* Returns a new object/array without mutating the originals.
|
|
1311
|
+
*/
|
|
1312
|
+
function deepMerge(source, ...sources) {
|
|
1313
|
+
if (sources.length === 0) return source;
|
|
1314
|
+
let result = source;
|
|
1315
|
+
for (const source of sources) result = mergeTwoValues(result, source);
|
|
1316
|
+
return result;
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Merge two values recursively
|
|
1320
|
+
*/
|
|
1321
|
+
function mergeTwoValues(target, source) {
|
|
1322
|
+
if (source === null || source === void 0) return target;
|
|
1323
|
+
if (target === null || target === void 0) return deepClone(source);
|
|
1324
|
+
if (Array.isArray(target) && Array.isArray(source)) return [...target, ...source];
|
|
1325
|
+
if (isPlainObject(target) && isPlainObject(source)) {
|
|
1326
|
+
const result = {};
|
|
1327
|
+
for (const [key, targetValue] of Object.entries(target)) result[key] = deepClone(targetValue);
|
|
1328
|
+
for (const [key, sourceValue] of Object.entries(source)) {
|
|
1329
|
+
const targetValue = result[key];
|
|
1330
|
+
if (sourceValue === void 0) continue;
|
|
1331
|
+
else if (sourceValue === null) result[key] = sourceValue;
|
|
1332
|
+
else if (isPlainObject(targetValue) && isPlainObject(sourceValue)) result[key] = mergeTwoValues(targetValue, sourceValue);
|
|
1333
|
+
else if (Array.isArray(targetValue) && Array.isArray(sourceValue)) result[key] = [...targetValue, ...sourceValue];
|
|
1334
|
+
else result[key] = deepClone(sourceValue);
|
|
1335
|
+
}
|
|
1336
|
+
return result;
|
|
1337
|
+
}
|
|
1338
|
+
return deepClone(source);
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* Deep clone an object or array to avoid reference sharing.
|
|
1342
|
+
* Helper function for deepMerge.
|
|
1343
|
+
*/
|
|
1344
|
+
function deepClone(obj) {
|
|
1345
|
+
if (obj === null || obj === void 0 || typeof obj !== "object") return obj;
|
|
1346
|
+
if (Array.isArray(obj)) return obj.map((item) => deepClone(item));
|
|
1347
|
+
if (isPlainObject(obj)) {
|
|
1348
|
+
const result = {};
|
|
1349
|
+
for (const [key, value] of Object.entries(obj)) result[key] = deepClone(value);
|
|
1350
|
+
return result;
|
|
1351
|
+
}
|
|
1352
|
+
return obj;
|
|
1353
|
+
}
|
|
1354
|
+
/**
|
|
1355
|
+
* Check if a value is a plain object (not an array, Date, etc.)
|
|
1356
|
+
*/
|
|
1357
|
+
function isPlainObject(obj) {
|
|
1358
|
+
return obj !== null && typeof obj === "object" && !Array.isArray(obj) && Object.prototype.toString.call(obj) === "[object Object]";
|
|
1359
|
+
}
|
|
1360
|
+
//#endregion
|
|
1361
|
+
//#region src/generators/utils/file.utils.ts
|
|
1362
|
+
function getOutputFileName({ output, fileName }) {
|
|
1363
|
+
return `${output}/${fileName}`;
|
|
1364
|
+
}
|
|
1365
|
+
async function writeFileIfChanged(file, data, skipExistingCheck = false) {
|
|
1366
|
+
if (skipExistingCheck) {
|
|
1367
|
+
await fs.promises.writeFile(file, data, "utf-8");
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
try {
|
|
1371
|
+
if (await fs.promises.readFile(file, "utf-8") === data) return;
|
|
1372
|
+
} catch (error) {
|
|
1373
|
+
if (error.code !== "ENOENT") throw error;
|
|
1374
|
+
}
|
|
1375
|
+
await fs.promises.writeFile(file, data, "utf-8");
|
|
1376
|
+
}
|
|
1377
|
+
async function writeFile({ fileName, content }, options) {
|
|
1378
|
+
const formattedContent = options?.formatGeneratedFile ? await options.formatGeneratedFile({
|
|
1379
|
+
fileName,
|
|
1380
|
+
content
|
|
1381
|
+
}) : content;
|
|
1382
|
+
await fs.promises.mkdir(path.dirname(fileName), { recursive: true });
|
|
1383
|
+
await writeFileIfChanged(fileName, formattedContent, options?.skipExistingCheck);
|
|
1384
|
+
}
|
|
1385
|
+
async function writeGenerateFileData(filesData, options) {
|
|
1386
|
+
if (!options?.formatGeneratedFile) {
|
|
1387
|
+
const directories = new Set(filesData.map(({ fileName }) => path.dirname(fileName)));
|
|
1388
|
+
for (const directory of directories) fs.mkdirSync(directory, { recursive: true });
|
|
1389
|
+
await Promise.all(filesData.map(({ fileName, content }) => writeFileIfChanged(fileName, content, options?.skipExistingCheck)));
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1392
|
+
for (const file of filesData) await writeFile(file, options);
|
|
1393
|
+
}
|
|
1394
|
+
function removeStaleGeneratedFiles({ output, filesData, options }) {
|
|
1395
|
+
if (!fs.existsSync(output)) return;
|
|
1396
|
+
const expectedFiles = new Set(filesData.map((file) => path.resolve(file.fileName)));
|
|
1397
|
+
const generatedSuffixes = new Set(Object.values(options.configs).map((config) => config.outputFileNameSuffix));
|
|
1398
|
+
const staleFiles = [];
|
|
1399
|
+
const visit = (dirPath) => {
|
|
1400
|
+
for (const dirent of fs.readdirSync(dirPath, { withFileTypes: true })) {
|
|
1401
|
+
const entryPath = path.join(dirPath, dirent.name);
|
|
1402
|
+
if (dirent.isDirectory()) {
|
|
1403
|
+
visit(entryPath);
|
|
1404
|
+
continue;
|
|
1405
|
+
}
|
|
1406
|
+
if (isGeneratedFile(entryPath, output, generatedSuffixes) && !expectedFiles.has(path.resolve(entryPath))) staleFiles.push(entryPath);
|
|
1407
|
+
}
|
|
1408
|
+
};
|
|
1409
|
+
visit(output);
|
|
1410
|
+
staleFiles.forEach((filePath) => fs.rmSync(filePath, { force: true }));
|
|
1411
|
+
removeEmptyDirectories(output);
|
|
1412
|
+
}
|
|
1413
|
+
function isGeneratedFile(filePath, output, generatedSuffixes) {
|
|
1414
|
+
const relativePath = path.relative(output, filePath);
|
|
1415
|
+
if (relativePath === ".openapi-codegen-cache.json") return true;
|
|
1416
|
+
const normalizedRelativePath = relativePath.split(path.sep).join("/");
|
|
1417
|
+
if ([
|
|
1418
|
+
"app-rest-client.ts",
|
|
1419
|
+
"queryModules.ts",
|
|
1420
|
+
"acl/app.ability.ts"
|
|
1421
|
+
].includes(normalizedRelativePath)) return true;
|
|
1422
|
+
if (path.parse(filePath).ext !== ".ts") return false;
|
|
1423
|
+
const segments = relativePath.split(path.sep).filter(Boolean);
|
|
1424
|
+
if (segments.length < 2) return false;
|
|
1425
|
+
const moduleName = segments[0];
|
|
1426
|
+
const fileName = segments[segments.length - 1];
|
|
1427
|
+
if (!fileName.startsWith(`${moduleName}.`)) return false;
|
|
1428
|
+
const suffix = fileName.slice(moduleName.length + 1).replace(/\.tsx?$/, "");
|
|
1429
|
+
return generatedSuffixes.has(suffix);
|
|
1430
|
+
}
|
|
1431
|
+
function removeEmptyDirectories(root) {
|
|
1432
|
+
if (!fs.existsSync(root)) return;
|
|
1433
|
+
const removeIfEmpty = (dirPath) => {
|
|
1434
|
+
for (const dirent of fs.readdirSync(dirPath, { withFileTypes: true })) if (dirent.isDirectory()) removeIfEmpty(path.join(dirPath, dirent.name));
|
|
1435
|
+
if (dirPath !== root && fs.readdirSync(dirPath).length === 0) fs.rmdirSync(dirPath);
|
|
1436
|
+
};
|
|
1437
|
+
removeIfEmpty(root);
|
|
1438
|
+
}
|
|
1439
|
+
//#endregion
|
|
1440
|
+
//#region src/native/native-bindings.ts
|
|
1441
|
+
let bindings;
|
|
1442
|
+
let nativePath;
|
|
1443
|
+
function getNativePath() {
|
|
1444
|
+
if (nativePath) return nativePath;
|
|
1445
|
+
const moduleDir = path$1.dirname(fileURLToPath(import.meta.url));
|
|
1446
|
+
const binaryName = `openapi-codegen-native-${process.platform}-${process.arch}.node`;
|
|
1447
|
+
nativePath = [path$1.join(moduleDir, binaryName), path$1.resolve(moduleDir, "../../dist", binaryName)].find(existsSync);
|
|
1448
|
+
if (!nativePath) throw new Error("Native OpenAPI codegen module is not built. Run `bun run build:native`.");
|
|
1449
|
+
return nativePath;
|
|
1450
|
+
}
|
|
1451
|
+
function hasNativeBindings() {
|
|
1452
|
+
try {
|
|
1453
|
+
getNativeBindings();
|
|
1454
|
+
return true;
|
|
1455
|
+
} catch {
|
|
1456
|
+
return false;
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
function shouldUseNativeCodegen() {
|
|
1460
|
+
if (process.env.OPENAPI_CODEGEN_NATIVE === "0") return false;
|
|
1461
|
+
if (process.env.OPENAPI_CODEGEN_NATIVE === "1") return true;
|
|
1462
|
+
return hasNativeBindings();
|
|
1463
|
+
}
|
|
1464
|
+
function getNativeBindings() {
|
|
1465
|
+
if (!bindings) {
|
|
1466
|
+
const require = createRequire(import.meta.url);
|
|
1467
|
+
const resolvedNativePath = getNativePath();
|
|
1468
|
+
if (typeof process.dlopen === "function") {
|
|
1469
|
+
const nativeModule = { exports: {} };
|
|
1470
|
+
process.dlopen(nativeModule, resolvedNativePath);
|
|
1471
|
+
bindings = nativeModule.exports;
|
|
1472
|
+
} else bindings = require(resolvedNativePath);
|
|
1473
|
+
}
|
|
1474
|
+
return bindings;
|
|
1475
|
+
}
|
|
1476
|
+
function compileNativeData(source, yaml, optionsJson) {
|
|
1477
|
+
return getNativeBindings().compileData(source, yaml, optionsJson);
|
|
1478
|
+
}
|
|
1479
|
+
//#endregion
|
|
1480
|
+
export { getImportedAbilityFunctionName as $, isPrimitiveType as $t, getEndpointsImports as A, NATIVE_RESPONSE_TYPE as An, APP_REST_CLIENT_NAME as At, getPrefetchInfiniteQueryName as B, getMostCommonAdjacentCombinationSplit as Bn, PACKAGE_IMPORT_PATH as Bt, getAppRestClientImportPath as C, ZOD_IMPORT as Cn, getParamZodSchemaName as Ct, getTagFileName as D, AXIOS_REQUEST_CONFIG_TYPE as Dn, isEnumZodSchema as Dt, getQueryTypesImportPath as E, AXIOS_REQUEST_CONFIG_NAME as En, getZodSchemaOperationName as Et, mergeImports as F, isTagIncluded as Fn, QUERY_MODULE_ENUM as Ft, getAbilityConditionType as G, getParameterEnumNames as Gt, getQueryName as H, removeWord as Hn, getNamespaceName as Ht, getImportedInfiniteQueryName as I, shouldInlineEndpointsForTag as In, QUERY_OPTIONS_TYPES as It, getAbilityFunctionName as J, isErrorStatus as Jt, getAbilityConditionsTypes as K, getSchemaNameByRef as Kt, getImportedQueryName as L, camelToSpaceSeparated as Ln, ZOD_EXTENDED as Lt, getInfiniteQueriesImports as M, formatTag as Mn, DOMAIN_ERRORS_FILE as Mt, getModelsImports as N, getEndpointTag as Nn, MUTATION_EFFECTS as Nt, getTagImportPath as O, BODY_PARAMETER_NAME as On, isNamedZodSchema as Ot, getQueriesImports as P, getOperationTag as Pn, QUERY_MODULES_FILE as Pt, getAppAbilitiesType as Q, isPathExcluded as Qt, getInfiniteQueryName as R, capitalize as Rn, CONFIG_PACKAGE_IMPORT_PATH as Rt, getTsTypeBase as S, VOID_SCHEMA as Sn, getEnumZodSchemaName as St, getQueryModulesImportPath as T, AXIOS_IMPORT as Tn, getZodSchemaName as Tt, getQueryOptionsName as U, snakeToCamel as Un, autocorrectRef as Ut, getPrefetchQueryName as V, kebabToCamel as Vn, REST_PACKAGE_IMPORT_PATH as Vt, getAbilityAction as W, Profiler as Wn, escapeControlCharacters as Wt, getAbilitySubjectTypes as X, isMediaTypeAllowed as Xt, getAbilitySubject as Y, isMainResponseStatus as Yt, getAclData as Z, isParamMediaTypeAllowed as Zt, hasEndpointConfig as _, INT_SCHEMA as _n, isReadAllEndpoint as _t, writeGenerateFileData as a, wrapWithQuotesIfNeeded as an, getZodSchemaInferedTypeName as at, requiresBody as b, URL_SCHEMA as bn, invalidVariableNameCharactersToCamel as bt, getDestructuredVariables as c, isReferenceObject as cn, getSchemaDescriptions as ct, isQuery as d, ALLOWED_PATH_IN as dn, DEFAULT_GENERATE_OPTIONS as dt, isSortingParameterObject as en, hasAbilityConditions as et, getEndpointBody as f, ANY_SCHEMA as fn, getPathSegments as ft, getImportedEndpointName as g, ENUM_SCHEMA as gn, isPathSegmentParam as gt, getEndpointPath as h, EMAIL_SCHEMA as hn, isDeleteEndpoint as ht, removeStaleGeneratedFiles as i, unwrapQuotesIfNeeded as in, getZodSchemaDescription as it, getImportPath as j, getRequestConfigTypeName as jn, BUILDERS_UTILS as jt, getAclImports as k, JSON_APPLICATION_FORMAT as kn, APP_REST_CLIENT_FILE as kt, isInfiniteQuery as l, isSchemaObject as ln, iterateSchema as lt, getEndpointName as m, DATETIME_SCHEMA as mn, isCreateEndpoint as mt, shouldUseNativeCodegen as n, pathToVariableName as nn, getImportedZodSchemaInferedTypeName as nt, deepMerge as o, inferRequiredSchema as on, getZodSchemaPropertyDescriptions as ot, getEndpointConfig as p, BLOB_SCHEMA as pn, isBulkDeleteEndpoint as pt, getAbilityDescription as q, getSchemaRef as qt, getOutputFileName as r, replaceHyphenatedPath as rn, getImportedZodSchemaName as rt, pick as s, isArraySchemaObject as sn, getZodSchemaType as st, compileNativeData as t, pathParamToVariableName as tn, renderAclCheckCall as tt, isMutation as u, ALLOWED_METHODS as un, getUniqueArray as ut, mapEndpointParamsToFunctionParams as v, NUMBER_SCHEMA as vn, isReadEndpoint as vt, getFileNameWithExtension as w, AXIOS_DEFAULT_IMPORT_NAME as wn, getResponseZodSchemaName as wt, getSchemaTsMetaType as x, UUID_SCHEMA as xn, getBodyZodSchemaName as xt, renderMediaUploadMutationBody as y, STRING_SCHEMA as yn, isUpdateEndpoint as yt, getInfiniteQueryOptionsName as z, decapitalize as zn, NATIVE_PACKAGE_IMPORT_PATH as zt };
|