@povio/openapi-codegen-cli 3.1.0-rc.7 → 3.2.0-rc.2

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