@povio/openapi-codegen-cli 3.2.0-rc.8 → 3.3.0-rc.1

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