@povio/openapi-codegen-cli 2.0.8-rc.8 → 3.0.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.
- package/README.md +29 -4
- package/dist/acl.d.mts +12 -1
- package/dist/acl.mjs +14 -3
- package/dist/{config-Cu_GYfai.d.mts → config-CKmoJbQB.d.mts} +1 -1
- package/dist/error-handling-CvW_FecB.d.mts +38 -0
- package/dist/error-handling-DkPY7Asf.mjs +187 -0
- package/dist/generate.runner-B0iop_CE.mjs +90 -0
- package/dist/{generateCodeFromOpenAPIDoc-B5lnFNGB.mjs → generateCodeFromOpenAPIDoc-BKIXvJIW.mjs} +2383 -2070
- package/dist/generator.d.mts +1 -1
- package/dist/generator.mjs +1 -1
- package/dist/index.d.mts +45 -60
- package/dist/index.mjs +76 -189
- package/dist/{options-DBz5YE3s.d.mts → options-C6CNQ6tq.d.mts} +8 -2
- package/dist/sh.mjs +22 -6
- package/dist/vite.d.mts +7 -4
- package/dist/vite.mjs +9 -6
- package/dist/zod.d.mts +20 -0
- package/dist/zod.mjs +33 -0
- package/package.json +12 -8
- package/dist/generate.runner-DNldmk0f.mjs +0 -98
- package/src/assets/useCrossTabQueryInvalidation.ts +0 -40
- package/src/assets/useMutationEffects.ts +0 -94
- package/src/generators/templates/acl-check.hbs +0 -29
- package/src/generators/templates/acl.hbs +0 -19
- package/src/generators/templates/app-acl.hbs +0 -17
- package/src/generators/templates/app-rest-client.hbs +0 -7
- package/src/generators/templates/configs.hbs +0 -80
- package/src/generators/templates/endpoints.hbs +0 -43
- package/src/generators/templates/models.hbs +0 -23
- package/src/generators/templates/partials/acl-check-call.hbs +0 -1
- package/src/generators/templates/partials/casl-ability-function.hbs +0 -12
- package/src/generators/templates/partials/casl-ability-query.hbs +0 -1
- package/src/generators/templates/partials/casl-ability-type.hbs +0 -1
- package/src/generators/templates/partials/columns-config.hbs +0 -11
- package/src/generators/templates/partials/endpoint-config.hbs +0 -31
- package/src/generators/templates/partials/endpoint-param-parse.hbs +0 -1
- package/src/generators/templates/partials/endpoint-params.hbs +0 -1
- package/src/generators/templates/partials/import.hbs +0 -1
- package/src/generators/templates/partials/inputs-config.hbs +0 -10
- package/src/generators/templates/partials/model-js-docs.hbs +0 -6
- package/src/generators/templates/partials/query-js-docs.hbs +0 -31
- package/src/generators/templates/partials/query-keys.hbs +0 -11
- package/src/generators/templates/partials/query-use-infinite-query.hbs +0 -21
- package/src/generators/templates/partials/query-use-mutation.hbs +0 -54
- package/src/generators/templates/partials/query-use-query.hbs +0 -16
- package/src/generators/templates/queries.hbs +0 -54
- package/src/generators/templates/query-modules.hbs +0 -5
- package/src/generators/templates/zod-extended.hbs +0 -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,9 @@ 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
|
-
--
|
|
95
|
+
--mutationScope Serialize mutations for the same path-param resource via TanStack scope.id (default: false)
|
|
96
|
+
--mutationDefaultOnError Use OpenApiQueryConfig.onError as the default onError for mutation hooks (default: false)
|
|
97
|
+
--workspaceContext Comma-separated list of path/ACL params that generated hooks may resolve from OpenApiWorkspaceContext
|
|
95
98
|
--inlineEndpoints Inline endpoint implementations into generated query files (default: false)
|
|
96
99
|
--inlineEndpointsExcludeModules Comma-separated modules/tags to keep as separate API files while inlineEndpoints=true
|
|
97
100
|
--modelsOnly Generate only model files (default: false)
|
|
@@ -115,6 +118,7 @@ yarn openapi-codegen generate --config my-config.ts
|
|
|
115
118
|
--splitByTags Organize output into separate folders based on OpenAPI operation tags (default: true)
|
|
116
119
|
--defaultTag (Requires `--splitByTags`) Default tag for shared code across multiple tags (default: 'Common')
|
|
117
120
|
|
|
121
|
+
--includeTags Comma-separated list of tags to include in generation
|
|
118
122
|
--excludeTags Comma-separated list of tags to exclude from generation
|
|
119
123
|
--excludePathRegex Exclude operations whose paths match the given regular expression
|
|
120
124
|
--excludeRedundantZodSchemas Exclude any redundant Zod schemas (default: true)
|
|
@@ -192,20 +196,36 @@ const config: OpenAPICodegenConfig = {
|
|
|
192
196
|
export default config;
|
|
193
197
|
```
|
|
194
198
|
|
|
199
|
+
### Default mutation errors
|
|
200
|
+
|
|
201
|
+
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`.
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
import { ErrorHandler, OpenApiQueryConfig } from "@povio/openapi-codegen-cli";
|
|
205
|
+
|
|
206
|
+
<OpenApiQueryConfig.Provider
|
|
207
|
+
onError={(error) => {
|
|
208
|
+
errorToast({ text: ErrorHandler.getErrorMessage(error) });
|
|
209
|
+
}}
|
|
210
|
+
>
|
|
211
|
+
<App />
|
|
212
|
+
</OpenApiQueryConfig.Provider>;
|
|
213
|
+
```
|
|
214
|
+
|
|
195
215
|
### OpenApiWorkspaceContext (Path + ACL defaults)
|
|
196
216
|
|
|
197
|
-
|
|
217
|
+
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
218
|
|
|
199
219
|
```tsx
|
|
200
220
|
import { OpenApiWorkspaceContext } from "@povio/openapi-codegen-cli";
|
|
201
|
-
// openapi-codegen.config.ts -> { workspaceContext:
|
|
221
|
+
// openapi-codegen.config.ts -> { workspaceContext: ["officeId", "projectId"] }
|
|
202
222
|
|
|
203
223
|
<OpenApiWorkspaceContext.Provider values={{ officeId: "office_123" }}>
|
|
204
224
|
<MyWorkspacePages />
|
|
205
225
|
</OpenApiWorkspaceContext.Provider>;
|
|
206
226
|
```
|
|
207
227
|
|
|
208
|
-
Generated query/mutation hooks can then omit matching path/ACL params and resolve them from `OpenApiWorkspaceContext`.
|
|
228
|
+
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
229
|
|
|
210
230
|
### Generation Modes
|
|
211
231
|
|
|
@@ -242,12 +262,17 @@ export default defineConfig({
|
|
|
242
262
|
output: "./src/data",
|
|
243
263
|
inlineEndpoints: true,
|
|
244
264
|
incremental: true,
|
|
265
|
+
formatGeneratedFile: async ({ fileName, content }) => {
|
|
266
|
+
void fileName;
|
|
267
|
+
return content;
|
|
268
|
+
},
|
|
245
269
|
}),
|
|
246
270
|
],
|
|
247
271
|
});
|
|
248
272
|
```
|
|
249
273
|
|
|
250
274
|
The plugin runs on both `vite serve` and `vite build`, and watches local OpenAPI files in dev mode.
|
|
275
|
+
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
276
|
|
|
252
277
|
### Enums
|
|
253
278
|
|
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
|
-
|
|
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 {
|
|
2
|
-
import {
|
|
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
|
-
|
|
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 };
|
|
@@ -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-BKIXvJIW.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 };
|