@povio/openapi-codegen-cli 2.0.8-rc.9 → 3.0.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 (49) hide show
  1. package/README.md +32 -4
  2. package/dist/acl.d.mts +12 -1
  3. package/dist/acl.mjs +14 -3
  4. package/dist/{config-Cu_GYfai.d.mts → config-C1ME3Ay4.d.mts} +1 -1
  5. package/dist/error-handling-CvW_FecB.d.mts +38 -0
  6. package/dist/error-handling-DkPY7Asf.mjs +187 -0
  7. package/dist/generate.runner-BsNMtOTd.mjs +90 -0
  8. package/dist/{generateCodeFromOpenAPIDoc-BOjk_Ey8.mjs → generateCodeFromOpenAPIDoc-CbBWYEZG.mjs} +2482 -2132
  9. package/dist/generator.d.mts +1 -1
  10. package/dist/generator.mjs +1 -1
  11. package/dist/index.d.mts +45 -60
  12. package/dist/index.mjs +76 -189
  13. package/dist/{options-DBz5YE3s.d.mts → options-BPAjzilp.d.mts} +12 -2
  14. package/dist/sh.mjs +22 -6
  15. package/dist/vite.d.mts +7 -4
  16. package/dist/vite.mjs +9 -6
  17. package/dist/zod.d.mts +20 -0
  18. package/dist/zod.mjs +33 -0
  19. package/package.json +12 -8
  20. package/dist/generate.runner-CSqX4Uw7.mjs +0 -98
  21. package/src/assets/useCrossTabQueryInvalidation.ts +0 -40
  22. package/src/assets/useMutationEffects.ts +0 -94
  23. package/src/generators/templates/acl-check.hbs +0 -29
  24. package/src/generators/templates/acl.hbs +0 -19
  25. package/src/generators/templates/app-acl.hbs +0 -17
  26. package/src/generators/templates/app-rest-client.hbs +0 -7
  27. package/src/generators/templates/configs.hbs +0 -80
  28. package/src/generators/templates/endpoints.hbs +0 -43
  29. package/src/generators/templates/models.hbs +0 -23
  30. package/src/generators/templates/partials/acl-check-call.hbs +0 -1
  31. package/src/generators/templates/partials/casl-ability-function.hbs +0 -12
  32. package/src/generators/templates/partials/casl-ability-query.hbs +0 -1
  33. package/src/generators/templates/partials/casl-ability-type.hbs +0 -1
  34. package/src/generators/templates/partials/columns-config.hbs +0 -11
  35. package/src/generators/templates/partials/endpoint-config.hbs +0 -31
  36. package/src/generators/templates/partials/endpoint-param-parse.hbs +0 -1
  37. package/src/generators/templates/partials/endpoint-params.hbs +0 -1
  38. package/src/generators/templates/partials/import.hbs +0 -1
  39. package/src/generators/templates/partials/inputs-config.hbs +0 -10
  40. package/src/generators/templates/partials/model-js-docs.hbs +0 -6
  41. package/src/generators/templates/partials/query-js-docs.hbs +0 -31
  42. package/src/generators/templates/partials/query-keys.hbs +0 -11
  43. package/src/generators/templates/partials/query-use-infinite-query.hbs +0 -21
  44. package/src/generators/templates/partials/query-use-mutation.hbs +0 -54
  45. package/src/generators/templates/partials/query-use-query.hbs +0 -16
  46. package/src/generators/templates/queries.hbs +0 -54
  47. package/src/generators/templates/query-modules.hbs +0 -5
  48. package/src/generators/templates/zod-extended.hbs +0 -49
  49. /package/dist/{auth.context-DKjzWiaA.mjs → auth.context-Bu5KW2sI.mjs} +0 -0
package/README.md CHANGED
@@ -76,6 +76,7 @@ yarn openapi-codegen generate --config my-config.ts
76
76
  --splitByTags Organize output into separate folders based on OpenAPI operation tags (default: true)
77
77
  --defaultTag (Requires `--splitByTags`) Default tag for shared code across multiple tags (default: 'Common')
78
78
 
79
+ --includeTags Comma-separated list of tags to include in generation
79
80
  --excludeTags Comma-separated list of tags to exclude from generation
80
81
  --excludePathRegex Exclude operations whose paths match the given regular expression
81
82
  --excludeRedundantZodSchemas Exclude any redundant Zod schemas (default: true)
@@ -91,7 +92,12 @@ yarn openapi-codegen generate --config my-config.ts
91
92
  --axiosRequestConfig Include Axios request config parameters in query hooks (default: false)
92
93
  --infiniteQueries Generate infinite queries for paginated API endpoints (default: false)
93
94
  --mutationEffects Add mutation effects options to mutation hooks (default: true)
94
- --workspaceContext Allow generated hooks to resolve path/ACL params from OpenApiWorkspaceContext (default: false)
95
+ --mutationScope Serialize mutations for the same path-param resource via TanStack scope.id (default: false).
96
+ In config files also accepts { include: string[] } or { exclude: string[] } to opt specific
97
+ operations in/out of scoping. Use "Tag/operationId" format for precision (e.g. "EmployeeSettings/update")
98
+ or just "operationId" to match across all tags. Cannot specify both include and exclude.
99
+ --mutationDefaultOnError Use OpenApiQueryConfig.onError as the default onError for mutation hooks (default: false)
100
+ --workspaceContext Comma-separated list of path/ACL params that generated hooks may resolve from OpenApiWorkspaceContext
95
101
  --inlineEndpoints Inline endpoint implementations into generated query files (default: false)
96
102
  --inlineEndpointsExcludeModules Comma-separated modules/tags to keep as separate API files while inlineEndpoints=true
97
103
  --modelsOnly Generate only model files (default: false)
@@ -115,6 +121,7 @@ yarn openapi-codegen generate --config my-config.ts
115
121
  --splitByTags Organize output into separate folders based on OpenAPI operation tags (default: true)
116
122
  --defaultTag (Requires `--splitByTags`) Default tag for shared code across multiple tags (default: 'Common')
117
123
 
124
+ --includeTags Comma-separated list of tags to include in generation
118
125
  --excludeTags Comma-separated list of tags to exclude from generation
119
126
  --excludePathRegex Exclude operations whose paths match the given regular expression
120
127
  --excludeRedundantZodSchemas Exclude any redundant Zod schemas (default: true)
@@ -192,20 +199,36 @@ const config: OpenAPICodegenConfig = {
192
199
  export default config;
193
200
  ```
194
201
 
202
+ ### Default mutation errors
203
+
204
+ Set `mutationDefaultOnError: true` in codegen config (or pass `--mutationDefaultOnError`) to let generated mutation hooks fall back to `OpenApiQueryConfig.Provider` when a mutation call does not define its own `onError`.
205
+
206
+ ```tsx
207
+ import { ErrorHandler, OpenApiQueryConfig } from "@povio/openapi-codegen-cli";
208
+
209
+ <OpenApiQueryConfig.Provider
210
+ onError={(error) => {
211
+ errorToast({ text: ErrorHandler.getErrorMessage(error) });
212
+ }}
213
+ >
214
+ <App />
215
+ </OpenApiQueryConfig.Provider>;
216
+ ```
217
+
195
218
  ### OpenApiWorkspaceContext (Path + ACL defaults)
196
219
 
197
- Enable `workspaceContext: true` in codegen config (or pass `--workspaceContext`) and wrap your app subtree with `OpenApiWorkspaceContext.Provider` if generated hooks frequently repeat workspace-scoped params (for example `officeId`).
220
+ Set `workspaceContext` to a list of param names in codegen config (or pass `--workspaceContext officeId,projectId`) and wrap your app subtree with `OpenApiWorkspaceContext.Provider` if generated hooks frequently repeat workspace-scoped params.
198
221
 
199
222
  ```tsx
200
223
  import { OpenApiWorkspaceContext } from "@povio/openapi-codegen-cli";
201
- // openapi-codegen.config.ts -> { workspaceContext: true }
224
+ // openapi-codegen.config.ts -> { workspaceContext: ["officeId", "projectId"] }
202
225
 
203
226
  <OpenApiWorkspaceContext.Provider values={{ officeId: "office_123" }}>
204
227
  <MyWorkspacePages />
205
228
  </OpenApiWorkspaceContext.Provider>;
206
229
  ```
207
230
 
208
- Generated query/mutation hooks can then omit matching path/ACL params and resolve them from `OpenApiWorkspaceContext`.
231
+ Generated query/mutation hooks can then omit only those matching path/ACL params and resolve them from `OpenApiWorkspaceContext`. Params not listed in `workspaceContext` remain explicit and required.
209
232
 
210
233
  ### Generation Modes
211
234
 
@@ -242,12 +265,17 @@ export default defineConfig({
242
265
  output: "./src/data",
243
266
  inlineEndpoints: true,
244
267
  incremental: true,
268
+ formatGeneratedFile: async ({ fileName, content }) => {
269
+ void fileName;
270
+ return content;
271
+ },
245
272
  }),
246
273
  ],
247
274
  });
248
275
  ```
249
276
 
250
277
  The plugin runs on both `vite serve` and `vite build`, and watches local OpenAPI files in dev mode.
278
+ If you provide `formatGeneratedFile`, the plugin formats each generated file in memory before comparing and writing it, which helps avoid unnecessary HMR when the formatted output is unchanged.
251
279
 
252
280
  ### Enums
253
281
 
package/dist/acl.d.mts CHANGED
@@ -1,3 +1,4 @@
1
+ import { r as ErrorHandler } from "./error-handling-CvW_FecB.mjs";
1
2
  import * as react from "react";
2
3
  import { PropsWithChildren } from "react";
3
4
  import * as react_jsx_runtime0 from "react/jsx-runtime";
@@ -45,4 +46,14 @@ declare const Can: <TAppAbilities extends AppAbilities = AppAbilities>({
45
46
  ...props
46
47
  }: CanProps<TAppAbilities>) => react_jsx_runtime0.JSX.Element;
47
48
  //#endregion
48
- export { AbilityContext, type AppAbilities, type AppAbility, Can, createAclGuard };
49
+ //#region src/lib/acl/useAclCheck.d.ts
50
+ interface UseAclCheckProps {
51
+ errorHandler?: ErrorHandler<never>;
52
+ }
53
+ declare function useAclCheck<TAppAbilities extends AppAbilities = AppAbilities>({
54
+ errorHandler
55
+ }?: UseAclCheckProps): {
56
+ checkAcl: (appAbility: TAppAbilities) => void;
57
+ };
58
+ //#endregion
59
+ export { AbilityContext, type AppAbilities, type AppAbility, Can, createAclGuard, useAclCheck };
package/dist/acl.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import { n as OpenApiRouter, t as AuthContext } from "./auth.context-DKjzWiaA.mjs";
2
- import { createContext, useEffect, useState } from "react";
1
+ import { r as SharedErrorHandler } from "./error-handling-DkPY7Asf.mjs";
2
+ import { n as OpenApiRouter, t as AuthContext } from "./auth.context-Bu5KW2sI.mjs";
3
+ import { createContext, useCallback, useEffect, useState } from "react";
3
4
  import { jsx } from "react/jsx-runtime";
4
5
  import { AbilityBuilder, createMongoAbility } from "@casl/ability";
5
6
  import { unpackRules } from "@casl/ability/extra";
@@ -60,4 +61,14 @@ const Can = ({ use, ...props }) => {
60
61
  };
61
62
 
62
63
  //#endregion
63
- export { AbilityContext, Can, createAclGuard };
64
+ //#region src/lib/acl/useAclCheck.ts
65
+ function useAclCheck({ errorHandler } = {}) {
66
+ const ability = AbilityContext.useAbility();
67
+ return { checkAcl: useCallback((appAbility) => {
68
+ const [action, subject] = appAbility;
69
+ if (!ability.can(action, subject)) (errorHandler ?? SharedErrorHandler).rethrowError(/* @__PURE__ */ new Error("ACL check failed"));
70
+ }, [ability, errorHandler]) };
71
+ }
72
+
73
+ //#endregion
74
+ export { AbilityContext, Can, createAclGuard, useAclCheck };
@@ -1,4 +1,4 @@
1
- import { t as GenerateOptions } from "./options-DBz5YE3s.mjs";
1
+ import { t as GenerateOptions } from "./options-BPAjzilp.mjs";
2
2
 
3
3
  //#region src/generators/types/config.d.ts
4
4
  type OpenAPICodegenConfig = Partial<GenerateOptions>;
@@ -0,0 +1,38 @@
1
+ import { TFunction } from "i18next";
2
+
3
+ //#region src/lib/rest/error-handling.d.ts
4
+ type GeneralErrorCodes = "DATA_VALIDATION_ERROR" | "NETWORK_ERROR" | "CANCELED_ERROR" | "INTERNAL_ERROR" | "UNKNOWN_ERROR";
5
+ declare class ApplicationException<CodeT> extends Error {
6
+ code: CodeT;
7
+ serverMessage: string | null;
8
+ constructor(message: string, code: CodeT, serverMessage: string | null);
9
+ }
10
+ interface ErrorEntry<CodeT> {
11
+ code: CodeT;
12
+ condition?: (error: unknown) => boolean;
13
+ getMessage: (t: TFunction<string, undefined>, error: unknown) => string;
14
+ }
15
+ interface ErrorHandlerOptions<CodeT extends string> {
16
+ entries: ErrorEntry<CodeT>[];
17
+ t?: TFunction<string, undefined>;
18
+ onRethrowError?: (error: unknown, exception: ApplicationException<CodeT | GeneralErrorCodes>) => void;
19
+ }
20
+ declare class ErrorHandler<CodeT extends string> {
21
+ entries: ErrorEntry<CodeT | GeneralErrorCodes>[];
22
+ private t;
23
+ private onRethrowError?;
24
+ constructor({
25
+ entries,
26
+ t,
27
+ onRethrowError
28
+ }: ErrorHandlerOptions<CodeT>);
29
+ private matchesEntry;
30
+ setTranslateFunction(t: TFunction<string, undefined>): void;
31
+ rethrowError(error: unknown): ApplicationException<CodeT | GeneralErrorCodes>;
32
+ getError(error: unknown): ApplicationException<CodeT | GeneralErrorCodes> | null;
33
+ getErrorCode(error: unknown): CodeT | GeneralErrorCodes | null;
34
+ static getErrorMessage(error: unknown, fallbackToUnknown?: boolean): string | null;
35
+ }
36
+ declare const SharedErrorHandler: ErrorHandler<never>;
37
+ //#endregion
38
+ export { GeneralErrorCodes as a, ErrorHandlerOptions as i, ErrorEntry as n, SharedErrorHandler as o, ErrorHandler as r, ApplicationException as t };
@@ -0,0 +1,187 @@
1
+ import { isAxiosError, isCancel } from "axios";
2
+ import { z } from "zod";
3
+ import i18next from "i18next";
4
+
5
+ //#region src/lib/assets/locales/en/translation.json
6
+ var translation_default$1 = { openapi: { "sharedErrors": {
7
+ "dataValidation": "An error occurred while validating the data",
8
+ "internalError": "An internal error occurred. This is most likely a bug on our end. Please try again later.",
9
+ "networkError": "A network error occurred. Are you connected to the internet?",
10
+ "canceledError": "The request was canceled.",
11
+ "unknownError": "An unknown error occurred. Please try again later.",
12
+ "unknownErrorWithCode": "An unknown error occurred. Error code: \"{{code}}\""
13
+ } } };
14
+
15
+ //#endregion
16
+ //#region src/lib/assets/locales/sl/translation.json
17
+ var translation_default = { openapi: { "sharedErrors": {
18
+ "dataValidation": "Pri preverjanju podatkov je prišlo do napake",
19
+ "internalError": "Prišlo je do notranje napake.",
20
+ "networkError": "Prišlo je do napake v omrežju.",
21
+ "canceledError": "Zahteva je bila preklicana.",
22
+ "unknownError": "Prišlo je do neznane napake.",
23
+ "unknownErrorWithCode": "Prišlo je do neznane napake. Koda napake: \"{{code}}\""
24
+ } } };
25
+
26
+ //#endregion
27
+ //#region src/lib/config/i18n.ts
28
+ const ns = "openapi";
29
+ const resources = {
30
+ en: { [ns]: translation_default$1 },
31
+ sl: { [ns]: translation_default }
32
+ };
33
+ const defaultLanguage = "en";
34
+ const i18n = i18next.createInstance();
35
+ i18n.init({
36
+ compatibilityJSON: "v4",
37
+ lng: defaultLanguage,
38
+ fallbackLng: defaultLanguage,
39
+ resources,
40
+ ns: Object.keys(resources.en),
41
+ defaultNS: ns,
42
+ interpolation: { escapeValue: false }
43
+ });
44
+ const defaultT = i18n.t.bind(i18n);
45
+
46
+ //#endregion
47
+ //#region src/lib/rest/rest.utils.ts
48
+ let RestUtils;
49
+ (function(_RestUtils) {
50
+ _RestUtils.extractServerResponseCode = (e) => {
51
+ if (e instanceof z.ZodError) return "validation-exception";
52
+ if (!isAxiosError(e)) return null;
53
+ if (!e.response) return null;
54
+ const data = e.response.data;
55
+ if (typeof data?.code === "string") return data.code;
56
+ return null;
57
+ };
58
+ _RestUtils.doesServerErrorMessageContain = (e, text) => {
59
+ const message = extractServerErrorMessage(e);
60
+ if (message === null || message === void 0) return false;
61
+ return message.toLowerCase().includes(text.toLowerCase());
62
+ };
63
+ const extractServerErrorMessage = _RestUtils.extractServerErrorMessage = (e) => {
64
+ if (e instanceof z.ZodError) return e.message;
65
+ if (!isAxiosError(e)) return null;
66
+ if (!e.response) return null;
67
+ const data = e.response.data;
68
+ if (typeof data?.message === "string") return data.message;
69
+ return null;
70
+ };
71
+ _RestUtils.extractContentDispositionFilename = (headers) => {
72
+ const contentDisposition = headers["content-disposition"];
73
+ return contentDisposition ? /filename=["']?([^"';]+)/i.exec(contentDisposition)?.[1] : void 0;
74
+ };
75
+ })(RestUtils || (RestUtils = {}));
76
+
77
+ //#endregion
78
+ //#region src/lib/rest/error-handling.ts
79
+ var ApplicationException = class extends Error {
80
+ code;
81
+ serverMessage = null;
82
+ constructor(message, code, serverMessage) {
83
+ super(message);
84
+ this.code = code;
85
+ this.serverMessage = serverMessage;
86
+ }
87
+ };
88
+ var ErrorHandler = class {
89
+ entries = [];
90
+ t;
91
+ onRethrowError;
92
+ constructor({ entries, t = defaultT, onRethrowError }) {
93
+ this.t = t;
94
+ this.onRethrowError = onRethrowError;
95
+ const dataValidationError = {
96
+ code: "DATA_VALIDATION_ERROR",
97
+ condition: (e) => {
98
+ return e instanceof z.ZodError;
99
+ },
100
+ getMessage: () => this.t("openapi.sharedErrors.dataValidation")
101
+ };
102
+ const internalError = {
103
+ code: "INTERNAL_ERROR",
104
+ condition: (e) => {
105
+ if (isAxiosError(e)) return e.response?.status != null && e.response.status >= 500 && e.response.status < 600;
106
+ return false;
107
+ },
108
+ getMessage: () => this.t("openapi.sharedErrors.internalError")
109
+ };
110
+ const networkError = {
111
+ code: "NETWORK_ERROR",
112
+ condition: (e) => {
113
+ if (isAxiosError(e)) return e.code === "ERR_NETWORK";
114
+ return false;
115
+ },
116
+ getMessage: () => this.t("openapi.sharedErrors.networkError")
117
+ };
118
+ const canceledError = {
119
+ code: "CANCELED_ERROR",
120
+ condition: (e) => {
121
+ if (isCancel(e)) return true;
122
+ if (isAxiosError(e) && e.code === "ECONNABORTED") return true;
123
+ return false;
124
+ },
125
+ getMessage: () => this.t("openapi.sharedErrors.canceledError")
126
+ };
127
+ const unknownError = {
128
+ code: "UNKNOWN_ERROR",
129
+ condition: () => true,
130
+ getMessage: (_, e) => {
131
+ const code = RestUtils.extractServerResponseCode(e);
132
+ const serverMessage = RestUtils.extractServerErrorMessage(e);
133
+ if (code) {
134
+ let message = `Unknown error, message from server: ${code}`;
135
+ if (serverMessage) message += ` ${serverMessage}`;
136
+ return message;
137
+ }
138
+ return this.t("openapi.sharedErrors.unknownError");
139
+ }
140
+ };
141
+ this.entries = [
142
+ ...entries,
143
+ dataValidationError,
144
+ internalError,
145
+ networkError,
146
+ canceledError,
147
+ unknownError
148
+ ];
149
+ }
150
+ matchesEntry(error, entry, code) {
151
+ if (entry.condition) return entry.condition(error);
152
+ return code === entry.code;
153
+ }
154
+ setTranslateFunction(t) {
155
+ this.t = t;
156
+ }
157
+ rethrowError(error) {
158
+ const code = RestUtils.extractServerResponseCode(error);
159
+ const errorEntry = this.entries.find((entry) => this.matchesEntry(error, entry, code));
160
+ const serverMessage = RestUtils.extractServerErrorMessage(error);
161
+ const exception = new ApplicationException(errorEntry.getMessage(this.t, error), errorEntry.code, serverMessage);
162
+ this.onRethrowError?.(error, exception);
163
+ throw exception;
164
+ }
165
+ getError(error) {
166
+ if (error instanceof ApplicationException) return error;
167
+ return null;
168
+ }
169
+ getErrorCode(error) {
170
+ if (error instanceof ApplicationException) return error.code;
171
+ return null;
172
+ }
173
+ static getErrorMessage(error, fallbackToUnknown = true) {
174
+ if (typeof error === "string") return error;
175
+ if (error instanceof Error) return error.message;
176
+ if (error instanceof ApplicationException) {
177
+ if (error.serverMessage != null) return error.serverMessage;
178
+ return error.message;
179
+ }
180
+ if (fallbackToUnknown) return defaultT("openapi.sharedErrors.unknownError");
181
+ return null;
182
+ }
183
+ };
184
+ const SharedErrorHandler = new ErrorHandler({ entries: [] });
185
+
186
+ //#endregion
187
+ export { ns as a, RestUtils as i, ErrorHandler as n, resources as o, SharedErrorHandler as r, ApplicationException as t };
@@ -0,0 +1,90 @@
1
+ import { S as Profiler, h as deepMerge, i as writeGenerateFileData, p as DEFAULT_GENERATE_OPTIONS, r as removeStaleGeneratedFiles, t as generateCodeFromOpenAPIDoc } from "./generateCodeFromOpenAPIDoc-CbBWYEZG.mjs";
2
+ import path from "path";
3
+ import SwaggerParser from "@apidevtools/swagger-parser";
4
+
5
+ //#region src/generators/core/resolveConfig.ts
6
+ function resolveConfig({ fileConfig = {}, params: { includeTags, excludeTags, inlineEndpointsExcludeModules, workspaceContext, ...options } }) {
7
+ const resolvedConfig = deepMerge(DEFAULT_GENERATE_OPTIONS, fileConfig ?? {}, {
8
+ ...options,
9
+ includeTags: includeTags?.split(","),
10
+ excludeTags: excludeTags?.split(","),
11
+ inlineEndpointsExcludeModules: inlineEndpointsExcludeModules?.split(","),
12
+ workspaceContext: workspaceContext?.split(",")
13
+ });
14
+ resolvedConfig.checkAcl = resolvedConfig.acl && resolvedConfig.checkAcl;
15
+ resolvedConfig.workspaceContext = Array.from(new Set((resolvedConfig.workspaceContext ?? []).map((value) => value.trim()).filter(Boolean)));
16
+ return resolvedConfig;
17
+ }
18
+
19
+ //#endregion
20
+ //#region src/generators/run/generate.runner.ts
21
+ async function runGenerate({ fileConfig, params, formatGeneratedFile, profiler = new Profiler(process.env.OPENAPI_CODEGEN_PROFILE === "1") }) {
22
+ const config = profiler.runSync("config.resolve", () => resolveConfig({
23
+ fileConfig,
24
+ params: params ?? {}
25
+ }));
26
+ const openApiDoc = await getOpenApiDoc(config.input, profiler);
27
+ const filesData = profiler.runSync("generate.total", () => generateCodeFromOpenAPIDoc(openApiDoc, config, profiler));
28
+ if (config.clearOutput) profiler.runSync("files.removeStaleGenerated", () => {
29
+ removeStaleGeneratedFiles({
30
+ output: config.output,
31
+ filesData,
32
+ options: config
33
+ });
34
+ });
35
+ await profiler.runAsync("files.write", async () => {
36
+ await writeGenerateFileData(filesData, { formatGeneratedFile });
37
+ });
38
+ return {
39
+ skipped: false,
40
+ config,
41
+ stats: getGenerateStats(filesData, config)
42
+ };
43
+ }
44
+ async function getOpenApiDoc(input, profiler) {
45
+ const parsedDoc = await profiler.runAsync("openapi.parse", async () => await SwaggerParser.parse(input));
46
+ if (!profiler.runSync("openapi.detectExternalRefs", () => hasExternalRef(parsedDoc))) return parsedDoc;
47
+ return await profiler.runAsync("openapi.bundle", async () => await SwaggerParser.bundle(input));
48
+ }
49
+ function hasExternalRef(value) {
50
+ const stack = [value];
51
+ const visited = /* @__PURE__ */ new Set();
52
+ while (stack.length > 0) {
53
+ const current = stack.pop();
54
+ if (!current || typeof current !== "object") continue;
55
+ if (visited.has(current)) continue;
56
+ visited.add(current);
57
+ if ("$ref" in current && typeof current.$ref === "string" && !current.$ref.startsWith("#/")) return true;
58
+ for (const nested of Object.values(current)) if (nested && typeof nested === "object") stack.push(nested);
59
+ }
60
+ return false;
61
+ }
62
+ function getGenerateStats(filesData, config) {
63
+ const generatedFilesCount = filesData.length;
64
+ if (generatedFilesCount === 0) return {
65
+ generatedFilesCount,
66
+ generatedModulesCount: 0
67
+ };
68
+ if (!config.splitByTags) return {
69
+ generatedFilesCount,
70
+ generatedModulesCount: 1
71
+ };
72
+ const moduleSuffixes = new Set(Object.values(config.configs).map((generateConfig) => generateConfig.outputFileNameSuffix).filter(Boolean));
73
+ const modules = /* @__PURE__ */ new Set();
74
+ for (const file of filesData) {
75
+ const segments = path.relative(config.output, file.fileName).split(path.sep).filter(Boolean);
76
+ if (segments.length < 2) continue;
77
+ const moduleName = segments[0];
78
+ const fileName = segments[segments.length - 1];
79
+ if (!fileName.startsWith(`${moduleName}.`)) continue;
80
+ const suffix = fileName.slice(moduleName.length + 1).replace(/\.tsx?$/, "");
81
+ if (moduleSuffixes.has(suffix)) modules.add(moduleName);
82
+ }
83
+ return {
84
+ generatedFilesCount,
85
+ generatedModulesCount: modules.size
86
+ };
87
+ }
88
+
89
+ //#endregion
90
+ export { resolveConfig as n, runGenerate as t };