vona-module-a-openapi 5.0.12 → 5.0.14

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.
@@ -1,352 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { OpenApiGeneratorV3, OpenApiGeneratorV31, OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
8
- import * as ModuleInfo from '@cabloy/module-info';
9
- import { isEmptyObject } from '@cabloy/utils';
10
- import { toUpperCaseFirstChar } from '@cabloy/word-utils';
11
- import { appMetadata, appResource, BeanBase, cast, HttpStatus, LocaleModuleNameSeparator, } from 'vona';
12
- import { RequestMethod, Service, SymbolRequestMappingHandler, } from 'vona-module-a-web';
13
- import { z } from 'zod';
14
- import { bodySchemaWrapperDefault } from "../lib/schema/bodySchemaWrapper.js";
15
- import { $schema } from "../lib/schema/schema.js";
16
- import { SymbolOpenApiOptions } from "../types/api.js";
17
- import { SymbolRouteHandlersArgumentsMeta } from "../types/decorator.js";
18
- const __ArgumentTypes = ['param', 'query', 'body', 'headers', 'fields', 'field', 'files', 'file'];
19
- let ServiceOpenapi = class ServiceOpenapi extends BeanBase {
20
- generateJson(version = 'V31') {
21
- const registry = this._collectRegistry();
22
- const generator = version === 'V30' ? new OpenApiGeneratorV3(registry.definitions) : new OpenApiGeneratorV31(registry.definitions);
23
- const apiObj = generator.generateDocument(this.scope.config.generateDocument[version]);
24
- this._translate(apiObj);
25
- return apiObj;
26
- }
27
- generateJsonOfControllerAction(controller, actionKey, version = 'V31') {
28
- const registry = new OpenAPIRegistry();
29
- const beanOptions = appResource.getBean(controller);
30
- if (!beanOptions)
31
- throw new Error('invalid controller');
32
- this._collectController(registry, beanOptions.module, controller, actionKey);
33
- const generator = version === 'V30' ? new OpenApiGeneratorV3(registry.definitions) : new OpenApiGeneratorV31(registry.definitions);
34
- const apiObj = generator.generateDocument(this.scope.config.generateDocument[version]);
35
- this._translate(apiObj);
36
- return apiObj;
37
- }
38
- _translate(apiObj) {
39
- // paths
40
- if (apiObj.paths) {
41
- for (const key in apiObj.paths) {
42
- const pathObj = apiObj.paths[key];
43
- for (const method in pathObj) {
44
- const methodObj = pathObj[method];
45
- this._translateStrings(methodObj, ['description', 'summary']);
46
- // parameters
47
- for (const parameterObj of methodObj.parameters || []) {
48
- this._translateSchema(parameterObj.schema);
49
- }
50
- // requestBody
51
- this._translateSchema(methodObj.requestBody?.content?.['application/json']?.schema);
52
- }
53
- }
54
- }
55
- // components
56
- if (apiObj.components?.schemas) {
57
- for (const key in apiObj.components.schemas) {
58
- const schema = apiObj.components.schemas[key];
59
- this._translateSchema(schema);
60
- }
61
- }
62
- }
63
- _translateSchema(schema) {
64
- if (!schema)
65
- return;
66
- if (schema.type === 'object' && schema.required === undefined)
67
- schema.required = [];
68
- this._translateStrings(schema, ['title', 'description']);
69
- const properties = cast(schema).properties;
70
- if (properties && typeof properties === 'object') {
71
- for (const prop in properties) {
72
- const propObj = properties[prop];
73
- this._translateSchema(propObj);
74
- }
75
- }
76
- }
77
- _translateStrings(obj, keys) {
78
- for (const key of keys) {
79
- this._translateString(obj, key);
80
- }
81
- }
82
- _translateString(obj, key) {
83
- if (!obj)
84
- return;
85
- if (obj[key] && obj[key].includes(LocaleModuleNameSeparator)) {
86
- obj[key] = this.app.meta.text(obj[key]);
87
- }
88
- }
89
- _collectRegistry() {
90
- const registry = new OpenAPIRegistry();
91
- // securitySchemes
92
- const configSecuritySchemes = this.scope.config.securitySchemes;
93
- for (const key in configSecuritySchemes) {
94
- let securityScheme = configSecuritySchemes[key];
95
- if (typeof securityScheme === 'function') {
96
- securityScheme = securityScheme.call(this.app);
97
- }
98
- registry.registerComponent('securitySchemes', key, securityScheme);
99
- }
100
- // schema: independent
101
- for (const sceneName of ['dto', 'entity']) {
102
- const onionSlices = this.bean.onion[sceneName].getOnionsEnabled();
103
- for (const onionSlice of onionSlices) {
104
- if (onionSlice.beanOptions.options?.independent) {
105
- const schema = $schema(onionSlice.beanOptions.beanClass);
106
- registry.register(onionSlice.beanOptions.beanFullName, schema);
107
- }
108
- }
109
- }
110
- // controller
111
- for (const controller of this.bean.onion.controller.getOnionsEnabled()) {
112
- this._collectController(registry, controller.beanOptions.module, controller.beanOptions.beanClass);
113
- }
114
- return registry;
115
- }
116
- _collectController(registry, moduleName, controller, actionKey) {
117
- // info
118
- const info = ModuleInfo.parseInfo(moduleName);
119
- // controller options
120
- const beanOptions = appResource.getBean(controller);
121
- if (!beanOptions)
122
- return;
123
- const controllerBeanFullName = beanOptions.beanFullName;
124
- const controllerOptions = beanOptions.options;
125
- const controllerPath = controllerOptions.path;
126
- const controllerOpenApiOptions = appMetadata.getMetadata(SymbolOpenApiOptions, controller);
127
- if (controllerOpenApiOptions?.exclude)
128
- return;
129
- // descs
130
- const descs = Object.getOwnPropertyDescriptors(controller.prototype);
131
- const actionKeys = actionKey ? [actionKey] : Object.keys(descs);
132
- for (const actionKey of actionKeys) {
133
- const desc = descs[actionKey];
134
- if (['constructor'].includes(actionKey))
135
- continue;
136
- if (!desc.value || typeof desc.value !== 'function')
137
- continue;
138
- this._registerControllerAction(registry, info, controller, beanOptions, controllerBeanFullName, controllerPath, controllerOpenApiOptions, actionKey, desc);
139
- }
140
- }
141
- _registerControllerAction(registry, info, controller, beanOptions, _controllerBeanFullName, controllerPath, controllerOpenApiOptions, actionKey, _desc) {
142
- // app
143
- const app = this.app;
144
- // action options: should not extend controllerOpenApiOptions
145
- const actionOpenApiOptions = appMetadata.getMetadata(SymbolOpenApiOptions, controller.prototype, actionKey);
146
- if (actionOpenApiOptions?.exclude)
147
- return;
148
- // actionPath/actionMethod
149
- if (!appMetadata.hasMetadata(SymbolRequestMappingHandler, controller.prototype, actionKey))
150
- return;
151
- const handlerMetadata = appMetadata.getMetadata(SymbolRequestMappingHandler, controller.prototype, actionKey);
152
- const actionPath = handlerMetadata.path || '';
153
- const actionMethod = handlerMetadata.method || RequestMethod.GET;
154
- // routePath
155
- const routePath = app.util.combineApiPathControllerAndAction(info.relativeName, controllerPath, actionPath, true, true);
156
- // :id -> {id}
157
- const routePath2 = routePath.replace(/:([^/]+)/g, '{$1}');
158
- // tags
159
- let tags = actionOpenApiOptions?.tags ?? controllerOpenApiOptions?.tags;
160
- if (!tags || tags.length === 0) {
161
- tags = [toUpperCaseFirstChar(this.app.util.combineResourceName(beanOptions.name, info.relativeName, true, true))];
162
- }
163
- // operationId
164
- let operationId = actionOpenApiOptions?.operationId ?? actionKey;
165
- operationId = `${tags[0]}_${operationId}`;
166
- // security
167
- const _public = actionOpenApiOptions?.public ?? controllerOpenApiOptions?.public;
168
- let security;
169
- if (!_public) {
170
- security = [
171
- {
172
- bearerAuth: [],
173
- },
174
- ];
175
- }
176
- // registerPath
177
- registry.registerPath({
178
- tags,
179
- method: actionMethod,
180
- path: routePath2,
181
- operationId,
182
- security,
183
- description: actionOpenApiOptions?.description,
184
- summary: actionOpenApiOptions?.summary,
185
- request: this._collectRequest(controller, actionKey, actionOpenApiOptions, controllerOpenApiOptions),
186
- responses: this._collectResponses(controller, actionKey, actionOpenApiOptions),
187
- });
188
- }
189
- _collectRequest(controller, actionKey, actionOpenApiOptions, controllerOpenApiOptions) {
190
- // meta
191
- const argsMeta = this._prepareArgsMeta(controller, actionKey, actionOpenApiOptions, controllerOpenApiOptions);
192
- if (!argsMeta)
193
- return;
194
- // args
195
- const argsMapWithField = {};
196
- const argsMapIsolate = {};
197
- let isUpload;
198
- for (const argMeta of argsMeta) {
199
- if (!__ArgumentTypes.includes(argMeta.type))
200
- continue;
201
- if (['fields', 'field', 'files', 'file'].includes(argMeta.type)) {
202
- isUpload = true;
203
- }
204
- if (argMeta.field) {
205
- if (!argsMapWithField[argMeta.type]) {
206
- argsMapWithField[argMeta.type] = {};
207
- }
208
- argsMapWithField[argMeta.type][argMeta.field] = argMeta.schema;
209
- }
210
- else {
211
- if (!argsMapIsolate[argMeta.type]) {
212
- argsMapIsolate[argMeta.type] = argMeta.schema;
213
- }
214
- }
215
- }
216
- // request
217
- const request = {};
218
- if (isUpload) {
219
- const schemaObj = {};
220
- // not check argsMapIsolate.fields
221
- if (argsMapWithField.fields)
222
- Object.assign(schemaObj, argsMapWithField.fields);
223
- if (argsMapWithField.field)
224
- Object.assign(schemaObj, argsMapWithField.field);
225
- if (argsMapWithField.files)
226
- Object.assign(schemaObj, argsMapWithField.files);
227
- if (argsMapWithField.file)
228
- Object.assign(schemaObj, argsMapWithField.file);
229
- if (argsMapIsolate.files)
230
- schemaObj.blobs = argsMapIsolate.files;
231
- const schema = z.object(schemaObj);
232
- // body
233
- request.body = {
234
- required: true,
235
- content: {
236
- 'multipart/form-data': {
237
- schema,
238
- },
239
- },
240
- };
241
- }
242
- else {
243
- for (const argumentType of __ArgumentTypes) {
244
- let schema = argsMapIsolate[argumentType];
245
- if (argsMapWithField[argumentType]) {
246
- if (!schema) {
247
- schema = z.object(argsMapWithField[argumentType]);
248
- }
249
- else {
250
- schema = schema.extend(argsMapWithField[argumentType]);
251
- }
252
- }
253
- if (!schema)
254
- continue;
255
- // record
256
- if (argumentType === 'body') {
257
- // body
258
- request.body = {
259
- required: !schema.isOptional(),
260
- content: {
261
- 'application/json': {
262
- schema,
263
- },
264
- },
265
- };
266
- }
267
- else {
268
- // others
269
- const name = argumentType === 'param' ? 'params' : argumentType;
270
- request[name] = schema;
271
- }
272
- }
273
- }
274
- return request;
275
- }
276
- _collectResponses(controller, actionKey, actionOpenApiOptions) {
277
- // contentType
278
- const contentType = actionOpenApiOptions?.contentType || 'application/json';
279
- // body schema
280
- const bodySchema = this._parseBodySchema(controller, actionKey, actionOpenApiOptions, contentType);
281
- // response
282
- const response = {
283
- description: '',
284
- content: {
285
- [contentType]: {
286
- schema: bodySchema,
287
- },
288
- },
289
- };
290
- // responses
291
- const responses = { [HttpStatus.OK]: response };
292
- return responses;
293
- }
294
- _parseBodySchema(controller, actionKey, actionOpenApiOptions, contentType) {
295
- // bodySchema
296
- let bodySchema;
297
- if (actionOpenApiOptions?.bodySchema) {
298
- bodySchema = actionOpenApiOptions.bodySchema;
299
- }
300
- else {
301
- const metaType = appMetadata.getDesignReturntype(controller.prototype, actionKey);
302
- bodySchema = $schema(metaType);
303
- }
304
- // wrapper
305
- if (contentType !== 'application/json')
306
- return bodySchema;
307
- if (actionOpenApiOptions?.bodySchemaWrapper === false)
308
- return bodySchema;
309
- const wrapper = actionOpenApiOptions?.bodySchemaWrapper ?? bodySchemaWrapperDefault;
310
- return wrapper(bodySchema);
311
- }
312
- _prepareArgsMeta(controller, actionKey, actionOpenApiOptions, controllerOpenApiOptions) {
313
- // meta
314
- let argsMeta = appMetadata.getMetadata(SymbolRouteHandlersArgumentsMeta, controller.prototype, actionKey);
315
- // headers
316
- const objHeaders = Object.assign({}, this._combineArgHeaders(controllerOpenApiOptions?.headers), this._combineArgHeaders(actionOpenApiOptions?.headers));
317
- // public
318
- const _public = actionOpenApiOptions?.public ?? controllerOpenApiOptions?.public;
319
- if (!_public && !objHeaders.Authorization) {
320
- objHeaders.Authorization = z.string().optional();
321
- }
322
- if (isEmptyObject(objHeaders))
323
- return argsMeta;
324
- // merge
325
- if (!argsMeta)
326
- argsMeta = [];
327
- let argHeaders = argsMeta.find(item => item.type === 'headers' && !item.field);
328
- if (!argHeaders) {
329
- argHeaders = { type: 'headers', field: undefined, schema: z.object(objHeaders) };
330
- argsMeta.push(argHeaders);
331
- }
332
- else {
333
- if (!argHeaders.schema.extend)
334
- throw new Error(`headers schema is not valid: ${actionKey}`);
335
- argHeaders.schema = argHeaders.schema.extend(objHeaders);
336
- }
337
- return argsMeta;
338
- }
339
- _combineArgHeaders(headers) {
340
- if (!headers)
341
- return;
342
- const objHeaders = {};
343
- for (const header of headers) {
344
- objHeaders[header.name] = z.string().openapi({ description: header.description });
345
- }
346
- return objHeaders;
347
- }
348
- };
349
- ServiceOpenapi = __decorate([
350
- Service()
351
- ], ServiceOpenapi);
352
- export { ServiceOpenapi };
@@ -1 +0,0 @@
1
- export {};
package/dist/types/api.js DELETED
@@ -1 +0,0 @@
1
- export const SymbolOpenApiOptions = Symbol('SymbolOpenApiOptions');
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,4 +0,0 @@
1
- export const OrderCoreBase = 100;
2
- export const OrderBusinessBase = 1000;
3
- export const OrderUnknownBase = 10000;
4
- export const OrderMaxBase = 100000;
@@ -1,4 +0,0 @@
1
- export const SymbolDecoratorRule = Symbol('SymbolDecoratorRule');
2
- export const SymbolDecoratorRuleColumn = Symbol('SymbolDecoratorRuleColumn');
3
- export const SymbolRouteHandlersArgumentsMeta = Symbol('SymbolRouteHandlersArgumentsMeta');
4
- export const SymbolRouteHandlersArgumentsValue = Symbol('SymbolRouteHandlersArgumentsValue');
@@ -1,8 +0,0 @@
1
- import '@cabloy/zod-query';
2
- export * from "./actions.js";
3
- export * from "./api.js";
4
- export * from "./behavior.js";
5
- export * from "./component.js";
6
- export * from "./database.js";
7
- export * from "./decorator.js";
8
- export * from "./rest.js";
@@ -1,2 +0,0 @@
1
- import 'openapi3-ts/oas30';
2
- import 'openapi3-ts/oas31';