vona-module-a-openapi 5.0.12 → 5.0.13
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/dist/index.js +779 -3
- package/package.json +2 -2
- package/dist/.metadata/index.js +0 -39
- package/dist/.metadata/this.js +0 -2
- package/dist/config/config.js +0 -30
- package/dist/config/locale/en-us.js +0 -2
- package/dist/config/locale/zh-cn.js +0 -2
- package/dist/lib/decorator/api.js +0 -71
- package/dist/lib/decorator/arguments.js +0 -39
- package/dist/lib/decorator/field.js +0 -15
- package/dist/lib/decorator/index.js +0 -3
- package/dist/lib/decorator/pipesArgument.js +0 -35
- package/dist/lib/index.js +0 -4
- package/dist/lib/schema/bodySchemaWrapper.js +0 -8
- package/dist/lib/schema/index.js +0 -4
- package/dist/lib/schema/makeSchemaLikes.js +0 -29
- package/dist/lib/schema/schema.js +0 -40
- package/dist/lib/schema/v/helpers.js +0 -36
- package/dist/lib/schema/v/openapi.js +0 -20
- package/dist/lib/schema/v/system.js +0 -34
- package/dist/lib/schema/v.js +0 -22
- package/dist/lib/utils.js +0 -43
- package/dist/lib/zod/errorUtil.js +0 -1
- package/dist/lib/zod/errorsAdapter.js +0 -9
- package/dist/lib/zod/index.js +0 -2
- package/dist/main.js +0 -9
- package/dist/service/openapi.js +0 -352
- package/dist/types/actions.js +0 -1
- package/dist/types/api.js +0 -1
- package/dist/types/behavior.js +0 -1
- package/dist/types/component.js +0 -1
- package/dist/types/database.js +0 -4
- package/dist/types/decorator.js +0 -4
- package/dist/types/index.js +0 -8
- package/dist/types/rest.js +0 -2
package/dist/index.js
CHANGED
|
@@ -1,3 +1,779 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { BeanSimple, appMetadata, appResource, cast, BeanInfo, BeanBase, LocaleModuleNameSeparator, HttpStatus, BeanScopeBase, isClassStrict, registerMappedClassMetadataKey, deepExtend } from 'vona';
|
|
2
|
+
import { Scope } from 'vona-module-a-bean';
|
|
3
|
+
import { locales as locales$1, setErrorMapDefault, setErrorMapSchema } from '@cabloy/zod-errors-custom';
|
|
4
|
+
import { OpenApiGeneratorV3, OpenApiGeneratorV31, OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
|
|
5
|
+
import * as ModuleInfo from '@cabloy/module-info';
|
|
6
|
+
import { isEmptyObject, isNil } from '@cabloy/utils';
|
|
7
|
+
import { toUpperCaseFirstChar } from '@cabloy/word-utils';
|
|
8
|
+
import { Service, SymbolRequestMappingHandler, RequestMethod } from 'vona-module-a-web';
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { coerceWithNil } from '@cabloy/zod-query';
|
|
11
|
+
import 'openapi3-ts/oas30';
|
|
12
|
+
import 'openapi3-ts/oas31';
|
|
13
|
+
|
|
14
|
+
var locale_en_us = locales$1['en-us'];
|
|
15
|
+
|
|
16
|
+
var locale_zh_cn = locales$1['zh-cn'];
|
|
17
|
+
|
|
18
|
+
function config(_app) {
|
|
19
|
+
return {
|
|
20
|
+
defaultVersion: 'V31',
|
|
21
|
+
generateDocument: {
|
|
22
|
+
V30: {
|
|
23
|
+
openapi: '3.0.0',
|
|
24
|
+
info: {
|
|
25
|
+
version: '5.0.0',
|
|
26
|
+
title: 'Vona',
|
|
27
|
+
description: 'Vona API'
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
V31: {
|
|
31
|
+
openapi: '3.1.0',
|
|
32
|
+
info: {
|
|
33
|
+
version: '5.0.0',
|
|
34
|
+
title: 'Vona',
|
|
35
|
+
description: 'Vona API'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
securitySchemes: {
|
|
40
|
+
bearerAuth: {
|
|
41
|
+
type: 'http',
|
|
42
|
+
scheme: 'bearer',
|
|
43
|
+
bearerFormat: 'JWT'
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function errorsAdapter(app) {
|
|
50
|
+
setErrorMapDefault((text, ...args) => {
|
|
51
|
+
return app.meta.text(text, ...args);
|
|
52
|
+
});
|
|
53
|
+
setErrorMapSchema((text, ...args) => {
|
|
54
|
+
return app.meta.text(text, ...args);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class Main extends BeanSimple {
|
|
59
|
+
async moduleLoading() {}
|
|
60
|
+
async moduleLoaded() {
|
|
61
|
+
errorsAdapter(this.app);
|
|
62
|
+
}
|
|
63
|
+
async configLoaded(_config) {}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function bodySchemaWrapperDefault(bodySchema) {
|
|
67
|
+
return z.object({
|
|
68
|
+
code: z.string(),
|
|
69
|
+
message: z.string(),
|
|
70
|
+
data: bodySchema
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const SymbolDecoratorRule = Symbol('SymbolDecoratorRule');
|
|
75
|
+
const SymbolDecoratorRuleColumn = Symbol('SymbolDecoratorRuleColumn');
|
|
76
|
+
|
|
77
|
+
// not use z.ZodSchema
|
|
78
|
+
|
|
79
|
+
const SymbolRouteHandlersArgumentsMeta = Symbol('SymbolRouteHandlersArgumentsMeta');
|
|
80
|
+
const SymbolRouteHandlersArgumentsValue = Symbol('SymbolRouteHandlersArgumentsValue');
|
|
81
|
+
|
|
82
|
+
function $schema(classType, options) {
|
|
83
|
+
if (!classType) return z.any();
|
|
84
|
+
if (classType.parseAsync) return classType;
|
|
85
|
+
if (classType.name === 'String') return z.string();
|
|
86
|
+
if (classType.name === 'Number') return z.number();
|
|
87
|
+
if (classType.name === 'Boolean') return z.boolean();
|
|
88
|
+
if (classType.name === 'Date') return z.date();
|
|
89
|
+
if (classType.name === 'BigInt') return z.bigint();
|
|
90
|
+
if (classType.name === 'Array') return z.array(z.any());
|
|
91
|
+
// check if object
|
|
92
|
+
const rules = classType.prototype ? appMetadata.getMetadata(SymbolDecoratorRule, classType.prototype) : undefined;
|
|
93
|
+
if (!rules) {
|
|
94
|
+
// not object
|
|
95
|
+
return z.any();
|
|
96
|
+
}
|
|
97
|
+
// object
|
|
98
|
+
let schema = z.object(rules);
|
|
99
|
+
if (options?.passthrough) schema = schema.passthrough();
|
|
100
|
+
if (options?.strict) schema = schema.strict();
|
|
101
|
+
// refId
|
|
102
|
+
const beanOptions = appResource.getBean(classType);
|
|
103
|
+
if (beanOptions) {
|
|
104
|
+
const openapi = cast(beanOptions.options)?.openapi;
|
|
105
|
+
schema = schema.openapi(beanOptions.beanFullName, openapi);
|
|
106
|
+
}
|
|
107
|
+
return schema;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const SymbolOpenApiOptions = Symbol('SymbolOpenApiOptions');
|
|
111
|
+
|
|
112
|
+
var _dec$1, _dec2$1, _class$1;
|
|
113
|
+
const __ArgumentTypes = ['param', 'query', 'body', 'headers', 'fields', 'field', 'files', 'file'];
|
|
114
|
+
let ServiceOpenapi = (_dec$1 = Service(), _dec2$1 = BeanInfo({
|
|
115
|
+
module: "a-openapi"
|
|
116
|
+
}), _dec$1(_class$1 = _dec2$1(_class$1 = class ServiceOpenapi extends BeanBase {
|
|
117
|
+
generateJson(version = 'V31') {
|
|
118
|
+
const registry = this._collectRegistry();
|
|
119
|
+
const generator = version === 'V30' ? new OpenApiGeneratorV3(registry.definitions) : new OpenApiGeneratorV31(registry.definitions);
|
|
120
|
+
const apiObj = generator.generateDocument(this.scope.config.generateDocument[version]);
|
|
121
|
+
this._translate(apiObj);
|
|
122
|
+
return apiObj;
|
|
123
|
+
}
|
|
124
|
+
generateJsonOfControllerAction(controller, actionKey, version = 'V31') {
|
|
125
|
+
const registry = new OpenAPIRegistry();
|
|
126
|
+
const beanOptions = appResource.getBean(controller);
|
|
127
|
+
if (!beanOptions) throw new Error('invalid controller');
|
|
128
|
+
this._collectController(registry, beanOptions.module, controller, actionKey);
|
|
129
|
+
const generator = version === 'V30' ? new OpenApiGeneratorV3(registry.definitions) : new OpenApiGeneratorV31(registry.definitions);
|
|
130
|
+
const apiObj = generator.generateDocument(this.scope.config.generateDocument[version]);
|
|
131
|
+
this._translate(apiObj);
|
|
132
|
+
return apiObj;
|
|
133
|
+
}
|
|
134
|
+
_translate(apiObj) {
|
|
135
|
+
// paths
|
|
136
|
+
if (apiObj.paths) {
|
|
137
|
+
for (const key in apiObj.paths) {
|
|
138
|
+
const pathObj = apiObj.paths[key];
|
|
139
|
+
for (const method in pathObj) {
|
|
140
|
+
const methodObj = pathObj[method];
|
|
141
|
+
this._translateStrings(methodObj, ['description', 'summary']);
|
|
142
|
+
// parameters
|
|
143
|
+
for (const parameterObj of methodObj.parameters || []) {
|
|
144
|
+
this._translateSchema(parameterObj.schema);
|
|
145
|
+
}
|
|
146
|
+
// requestBody
|
|
147
|
+
this._translateSchema(methodObj.requestBody?.content?.['application/json']?.schema);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// components
|
|
152
|
+
if (apiObj.components?.schemas) {
|
|
153
|
+
for (const key in apiObj.components.schemas) {
|
|
154
|
+
const schema = apiObj.components.schemas[key];
|
|
155
|
+
this._translateSchema(schema);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
_translateSchema(schema) {
|
|
160
|
+
if (!schema) return;
|
|
161
|
+
if (schema.type === 'object' && schema.required === undefined) schema.required = [];
|
|
162
|
+
this._translateStrings(schema, ['title', 'description']);
|
|
163
|
+
const properties = cast(schema).properties;
|
|
164
|
+
if (properties && typeof properties === 'object') {
|
|
165
|
+
for (const prop in properties) {
|
|
166
|
+
const propObj = properties[prop];
|
|
167
|
+
this._translateSchema(propObj);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
_translateStrings(obj, keys) {
|
|
172
|
+
for (const key of keys) {
|
|
173
|
+
this._translateString(obj, key);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
_translateString(obj, key) {
|
|
177
|
+
if (!obj) return;
|
|
178
|
+
if (obj[key] && obj[key].includes(LocaleModuleNameSeparator)) {
|
|
179
|
+
obj[key] = this.app.meta.text(obj[key]);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
_collectRegistry() {
|
|
183
|
+
const registry = new OpenAPIRegistry();
|
|
184
|
+
// securitySchemes
|
|
185
|
+
const configSecuritySchemes = this.scope.config.securitySchemes;
|
|
186
|
+
for (const key in configSecuritySchemes) {
|
|
187
|
+
let securityScheme = configSecuritySchemes[key];
|
|
188
|
+
if (typeof securityScheme === 'function') {
|
|
189
|
+
securityScheme = securityScheme.call(this.app);
|
|
190
|
+
}
|
|
191
|
+
registry.registerComponent('securitySchemes', key, securityScheme);
|
|
192
|
+
}
|
|
193
|
+
// schema: independent
|
|
194
|
+
for (const sceneName of ['dto', 'entity']) {
|
|
195
|
+
const onionSlices = this.bean.onion[sceneName].getOnionsEnabled();
|
|
196
|
+
for (const onionSlice of onionSlices) {
|
|
197
|
+
if (onionSlice.beanOptions.options?.independent) {
|
|
198
|
+
const schema = $schema(onionSlice.beanOptions.beanClass);
|
|
199
|
+
registry.register(onionSlice.beanOptions.beanFullName, schema);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// controller
|
|
204
|
+
for (const controller of this.bean.onion.controller.getOnionsEnabled()) {
|
|
205
|
+
this._collectController(registry, controller.beanOptions.module, controller.beanOptions.beanClass);
|
|
206
|
+
}
|
|
207
|
+
return registry;
|
|
208
|
+
}
|
|
209
|
+
_collectController(registry, moduleName, controller, actionKey) {
|
|
210
|
+
// info
|
|
211
|
+
const info = ModuleInfo.parseInfo(moduleName);
|
|
212
|
+
// controller options
|
|
213
|
+
const beanOptions = appResource.getBean(controller);
|
|
214
|
+
if (!beanOptions) return;
|
|
215
|
+
const controllerBeanFullName = beanOptions.beanFullName;
|
|
216
|
+
const controllerOptions = beanOptions.options;
|
|
217
|
+
const controllerPath = controllerOptions.path;
|
|
218
|
+
const controllerOpenApiOptions = appMetadata.getMetadata(SymbolOpenApiOptions, controller);
|
|
219
|
+
if (controllerOpenApiOptions?.exclude) return;
|
|
220
|
+
// descs
|
|
221
|
+
const descs = Object.getOwnPropertyDescriptors(controller.prototype);
|
|
222
|
+
const actionKeys = actionKey ? [actionKey] : Object.keys(descs);
|
|
223
|
+
for (const actionKey of actionKeys) {
|
|
224
|
+
const desc = descs[actionKey];
|
|
225
|
+
if (['constructor'].includes(actionKey)) continue;
|
|
226
|
+
if (!desc.value || typeof desc.value !== 'function') continue;
|
|
227
|
+
this._registerControllerAction(registry, info, controller, beanOptions, controllerBeanFullName, controllerPath, controllerOpenApiOptions, actionKey, desc);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
_registerControllerAction(registry, info, controller, beanOptions, _controllerBeanFullName, controllerPath, controllerOpenApiOptions, actionKey, _desc) {
|
|
231
|
+
// app
|
|
232
|
+
const app = this.app;
|
|
233
|
+
|
|
234
|
+
// action options: should not extend controllerOpenApiOptions
|
|
235
|
+
const actionOpenApiOptions = appMetadata.getMetadata(SymbolOpenApiOptions, controller.prototype, actionKey);
|
|
236
|
+
if (actionOpenApiOptions?.exclude) return;
|
|
237
|
+
|
|
238
|
+
// actionPath/actionMethod
|
|
239
|
+
if (!appMetadata.hasMetadata(SymbolRequestMappingHandler, controller.prototype, actionKey)) return;
|
|
240
|
+
const handlerMetadata = appMetadata.getMetadata(SymbolRequestMappingHandler, controller.prototype, actionKey);
|
|
241
|
+
const actionPath = handlerMetadata.path || '';
|
|
242
|
+
const actionMethod = handlerMetadata.method || RequestMethod.GET;
|
|
243
|
+
|
|
244
|
+
// routePath
|
|
245
|
+
const routePath = app.util.combineApiPathControllerAndAction(info.relativeName, controllerPath, actionPath, true, true);
|
|
246
|
+
// :id -> {id}
|
|
247
|
+
const routePath2 = routePath.replace(/:([^/]+)/g, '{$1}');
|
|
248
|
+
|
|
249
|
+
// tags
|
|
250
|
+
let tags = actionOpenApiOptions?.tags ?? controllerOpenApiOptions?.tags;
|
|
251
|
+
if (!tags || tags.length === 0) {
|
|
252
|
+
tags = [toUpperCaseFirstChar(this.app.util.combineResourceName(beanOptions.name, info.relativeName, true, true))];
|
|
253
|
+
}
|
|
254
|
+
// operationId
|
|
255
|
+
let operationId = actionOpenApiOptions?.operationId ?? actionKey;
|
|
256
|
+
operationId = `${tags[0]}_${operationId}`;
|
|
257
|
+
// security
|
|
258
|
+
const _public = actionOpenApiOptions?.public ?? controllerOpenApiOptions?.public;
|
|
259
|
+
let security;
|
|
260
|
+
if (!_public) {
|
|
261
|
+
security = [{
|
|
262
|
+
bearerAuth: []
|
|
263
|
+
}];
|
|
264
|
+
}
|
|
265
|
+
// registerPath
|
|
266
|
+
registry.registerPath({
|
|
267
|
+
tags,
|
|
268
|
+
method: actionMethod,
|
|
269
|
+
path: routePath2,
|
|
270
|
+
operationId,
|
|
271
|
+
security,
|
|
272
|
+
description: actionOpenApiOptions?.description,
|
|
273
|
+
summary: actionOpenApiOptions?.summary,
|
|
274
|
+
request: this._collectRequest(controller, actionKey, actionOpenApiOptions, controllerOpenApiOptions),
|
|
275
|
+
responses: this._collectResponses(controller, actionKey, actionOpenApiOptions)
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
_collectRequest(controller, actionKey, actionOpenApiOptions, controllerOpenApiOptions) {
|
|
279
|
+
// meta
|
|
280
|
+
const argsMeta = this._prepareArgsMeta(controller, actionKey, actionOpenApiOptions, controllerOpenApiOptions);
|
|
281
|
+
if (!argsMeta) return;
|
|
282
|
+
// args
|
|
283
|
+
const argsMapWithField = {};
|
|
284
|
+
const argsMapIsolate = {};
|
|
285
|
+
let isUpload;
|
|
286
|
+
for (const argMeta of argsMeta) {
|
|
287
|
+
if (!__ArgumentTypes.includes(argMeta.type)) continue;
|
|
288
|
+
if (['fields', 'field', 'files', 'file'].includes(argMeta.type)) {
|
|
289
|
+
isUpload = true;
|
|
290
|
+
}
|
|
291
|
+
if (argMeta.field) {
|
|
292
|
+
if (!argsMapWithField[argMeta.type]) {
|
|
293
|
+
argsMapWithField[argMeta.type] = {};
|
|
294
|
+
}
|
|
295
|
+
argsMapWithField[argMeta.type][argMeta.field] = argMeta.schema;
|
|
296
|
+
} else {
|
|
297
|
+
if (!argsMapIsolate[argMeta.type]) {
|
|
298
|
+
argsMapIsolate[argMeta.type] = argMeta.schema;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// request
|
|
303
|
+
const request = {};
|
|
304
|
+
if (isUpload) {
|
|
305
|
+
const schemaObj = {};
|
|
306
|
+
// not check argsMapIsolate.fields
|
|
307
|
+
if (argsMapWithField.fields) Object.assign(schemaObj, argsMapWithField.fields);
|
|
308
|
+
if (argsMapWithField.field) Object.assign(schemaObj, argsMapWithField.field);
|
|
309
|
+
if (argsMapWithField.files) Object.assign(schemaObj, argsMapWithField.files);
|
|
310
|
+
if (argsMapWithField.file) Object.assign(schemaObj, argsMapWithField.file);
|
|
311
|
+
if (argsMapIsolate.files) schemaObj.blobs = argsMapIsolate.files;
|
|
312
|
+
const schema = z.object(schemaObj);
|
|
313
|
+
// body
|
|
314
|
+
request.body = {
|
|
315
|
+
required: true,
|
|
316
|
+
content: {
|
|
317
|
+
'multipart/form-data': {
|
|
318
|
+
schema
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
} else {
|
|
323
|
+
for (const argumentType of __ArgumentTypes) {
|
|
324
|
+
let schema = argsMapIsolate[argumentType];
|
|
325
|
+
if (argsMapWithField[argumentType]) {
|
|
326
|
+
if (!schema) {
|
|
327
|
+
schema = z.object(argsMapWithField[argumentType]);
|
|
328
|
+
} else {
|
|
329
|
+
schema = schema.extend(argsMapWithField[argumentType]);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (!schema) continue;
|
|
333
|
+
// record
|
|
334
|
+
if (argumentType === 'body') {
|
|
335
|
+
// body
|
|
336
|
+
request.body = {
|
|
337
|
+
required: !schema.isOptional(),
|
|
338
|
+
content: {
|
|
339
|
+
'application/json': {
|
|
340
|
+
schema
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
} else {
|
|
345
|
+
// others
|
|
346
|
+
const name = argumentType === 'param' ? 'params' : argumentType;
|
|
347
|
+
request[name] = schema;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return request;
|
|
352
|
+
}
|
|
353
|
+
_collectResponses(controller, actionKey, actionOpenApiOptions) {
|
|
354
|
+
// contentType
|
|
355
|
+
const contentType = actionOpenApiOptions?.contentType || 'application/json';
|
|
356
|
+
// body schema
|
|
357
|
+
const bodySchema = this._parseBodySchema(controller, actionKey, actionOpenApiOptions, contentType);
|
|
358
|
+
// response
|
|
359
|
+
const response = {
|
|
360
|
+
description: '',
|
|
361
|
+
content: {
|
|
362
|
+
[contentType]: {
|
|
363
|
+
schema: bodySchema
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
// responses
|
|
368
|
+
const responses = {
|
|
369
|
+
[HttpStatus.OK]: response
|
|
370
|
+
};
|
|
371
|
+
return responses;
|
|
372
|
+
}
|
|
373
|
+
_parseBodySchema(controller, actionKey, actionOpenApiOptions, contentType) {
|
|
374
|
+
// bodySchema
|
|
375
|
+
let bodySchema;
|
|
376
|
+
if (actionOpenApiOptions?.bodySchema) {
|
|
377
|
+
bodySchema = actionOpenApiOptions.bodySchema;
|
|
378
|
+
} else {
|
|
379
|
+
const metaType = appMetadata.getDesignReturntype(controller.prototype, actionKey);
|
|
380
|
+
bodySchema = $schema(metaType);
|
|
381
|
+
}
|
|
382
|
+
// wrapper
|
|
383
|
+
if (contentType !== 'application/json') return bodySchema;
|
|
384
|
+
if (actionOpenApiOptions?.bodySchemaWrapper === false) return bodySchema;
|
|
385
|
+
const wrapper = actionOpenApiOptions?.bodySchemaWrapper ?? bodySchemaWrapperDefault;
|
|
386
|
+
return wrapper(bodySchema);
|
|
387
|
+
}
|
|
388
|
+
_prepareArgsMeta(controller, actionKey, actionOpenApiOptions, controllerOpenApiOptions) {
|
|
389
|
+
// meta
|
|
390
|
+
let argsMeta = appMetadata.getMetadata(SymbolRouteHandlersArgumentsMeta, controller.prototype, actionKey);
|
|
391
|
+
// headers
|
|
392
|
+
const objHeaders = Object.assign({}, this._combineArgHeaders(controllerOpenApiOptions?.headers), this._combineArgHeaders(actionOpenApiOptions?.headers));
|
|
393
|
+
// public
|
|
394
|
+
const _public = actionOpenApiOptions?.public ?? controllerOpenApiOptions?.public;
|
|
395
|
+
if (!_public && !objHeaders.Authorization) {
|
|
396
|
+
objHeaders.Authorization = z.string().optional();
|
|
397
|
+
}
|
|
398
|
+
if (isEmptyObject(objHeaders)) return argsMeta;
|
|
399
|
+
// merge
|
|
400
|
+
if (!argsMeta) argsMeta = [];
|
|
401
|
+
let argHeaders = argsMeta.find(item => item.type === 'headers' && !item.field);
|
|
402
|
+
if (!argHeaders) {
|
|
403
|
+
argHeaders = {
|
|
404
|
+
type: 'headers',
|
|
405
|
+
field: undefined,
|
|
406
|
+
schema: z.object(objHeaders)
|
|
407
|
+
};
|
|
408
|
+
argsMeta.push(argHeaders);
|
|
409
|
+
} else {
|
|
410
|
+
if (!argHeaders.schema.extend) throw new Error(`headers schema is not valid: ${actionKey}`);
|
|
411
|
+
argHeaders.schema = argHeaders.schema.extend(objHeaders);
|
|
412
|
+
}
|
|
413
|
+
return argsMeta;
|
|
414
|
+
}
|
|
415
|
+
_combineArgHeaders(headers) {
|
|
416
|
+
if (!headers) return;
|
|
417
|
+
const objHeaders = {};
|
|
418
|
+
for (const header of headers) {
|
|
419
|
+
objHeaders[header.name] = z.string().openapi({
|
|
420
|
+
description: header.description
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
return objHeaders;
|
|
424
|
+
}
|
|
425
|
+
}) || _class$1) || _class$1);
|
|
426
|
+
|
|
427
|
+
var _dec, _dec2, _class;
|
|
428
|
+
const locales = {
|
|
429
|
+
'en-us': locale_en_us,
|
|
430
|
+
'zh-cn': locale_zh_cn
|
|
431
|
+
};
|
|
432
|
+
let ScopeModuleAOpenapi = (_dec = Scope(), _dec2 = BeanInfo({
|
|
433
|
+
module: "a-openapi"
|
|
434
|
+
}), _dec(_class = _dec2(_class = class ScopeModuleAOpenapi extends BeanScopeBase {}) || _class) || _class);
|
|
435
|
+
function $locale(key) {
|
|
436
|
+
return `a-openapi::${key}`;
|
|
437
|
+
}
|
|
438
|
+
/** scope: end */
|
|
439
|
+
|
|
440
|
+
function makeSchemaLikes(schemaLikes, typeInit) {
|
|
441
|
+
// default schema
|
|
442
|
+
let argSchema = $schema(typeInit);
|
|
443
|
+
// loop
|
|
444
|
+
for (let index = schemaLikes.length - 1; index >= 0; index--) {
|
|
445
|
+
const schemaLike = schemaLikes[index];
|
|
446
|
+
argSchema = makeSchemaLike(schemaLike, argSchema);
|
|
447
|
+
}
|
|
448
|
+
return argSchema;
|
|
449
|
+
}
|
|
450
|
+
function makeSchemaLike(schemaLike, schemaPrevious) {
|
|
451
|
+
if (!schemaLike) return schemaPrevious;
|
|
452
|
+
if (Object.prototype.hasOwnProperty.call(schemaLike, 'parseAsync')) {
|
|
453
|
+
// schema
|
|
454
|
+
return schemaLike;
|
|
455
|
+
} else if (isClassStrict(schemaLike) || ['String', 'Number', 'Boolean', 'Date', 'BigInt', 'Array'].includes(cast(schemaLike).name)) {
|
|
456
|
+
// class
|
|
457
|
+
return $schema(cast(schemaLike));
|
|
458
|
+
} else {
|
|
459
|
+
// function
|
|
460
|
+
return cast(schemaLike)(schemaPrevious);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function getTargetDecoratorRules(target) {
|
|
465
|
+
registerMappedClassMetadataKey(target, SymbolDecoratorRule, {
|
|
466
|
+
partialClass: meta => {
|
|
467
|
+
return meta.optional();
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
return appMetadata.getOwnMetadataMap(true, SymbolDecoratorRule, target);
|
|
471
|
+
}
|
|
472
|
+
function getTargetDecoratorRuleColumns(target) {
|
|
473
|
+
registerMappedClassMetadataKey(target, SymbolDecoratorRuleColumn);
|
|
474
|
+
return appMetadata.getOwnMetadataMap(true, SymbolDecoratorRuleColumn, target);
|
|
475
|
+
}
|
|
476
|
+
function mergeFieldsOpenAPIMetadata(target) {
|
|
477
|
+
// rules
|
|
478
|
+
const rules = getTargetDecoratorRules(target.prototype);
|
|
479
|
+
// beanOptions
|
|
480
|
+
const beanOptions = appResource.getBean(target);
|
|
481
|
+
const fields = cast(beanOptions?.options)?.fields;
|
|
482
|
+
if (!fields) return;
|
|
483
|
+
for (const key in fields) {
|
|
484
|
+
const field = fields[key];
|
|
485
|
+
if (!field) continue;
|
|
486
|
+
const schemaCurrent = rules[key];
|
|
487
|
+
if (Object.prototype.hasOwnProperty.call(field, 'parseAsync')) {
|
|
488
|
+
const schema = field;
|
|
489
|
+
rules[key] = schema.openapi(deepExtend({}, schemaCurrent?._def.openapi?.metadata, schema._def.openapi?.metadata));
|
|
490
|
+
} else {
|
|
491
|
+
// use deepExtend for sure strict
|
|
492
|
+
if (schemaCurrent) {
|
|
493
|
+
rules[key] = schemaCurrent.openapi(deepExtend({}, schemaCurrent._def.openapi?.metadata, field));
|
|
494
|
+
} else {
|
|
495
|
+
rules[key] = z.any().openapi(deepExtend({}, field));
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function Field$1(...schemaLikes) {
|
|
502
|
+
return function (target, prop) {
|
|
503
|
+
// rules
|
|
504
|
+
const rules = getTargetDecoratorRules(target);
|
|
505
|
+
// rule
|
|
506
|
+
const metaType = appMetadata.getDesignType(target, prop);
|
|
507
|
+
rules[prop] = makeSchemaLikes(schemaLikes, metaType);
|
|
508
|
+
//
|
|
509
|
+
const columns = getTargetDecoratorRuleColumns(target);
|
|
510
|
+
columns[prop] = prop;
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function setPublic(target, prop, _descriptor, value) {
|
|
515
|
+
const options = appMetadata.getOwnMetadataMap(false, SymbolOpenApiOptions, target, prop);
|
|
516
|
+
options.public = value;
|
|
517
|
+
}
|
|
518
|
+
function contentType(contentType) {
|
|
519
|
+
return function (target, prop, descriptor) {
|
|
520
|
+
const options = appMetadata.getOwnMetadataMap(false, SymbolOpenApiOptions, target, prop);
|
|
521
|
+
options.contentType = contentType;
|
|
522
|
+
return descriptor;
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
function body(...schemaLikes) {
|
|
526
|
+
return function (target, prop, descriptor) {
|
|
527
|
+
// schema
|
|
528
|
+
const metaType = appMetadata.getDesignReturntype(target, prop);
|
|
529
|
+
const schema = makeSchemaLikes(schemaLikes, metaType);
|
|
530
|
+
// options
|
|
531
|
+
const options = appMetadata.getOwnMetadataMap(false, SymbolOpenApiOptions, target, prop);
|
|
532
|
+
options.bodySchema = schema;
|
|
533
|
+
return descriptor;
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
function bodyCustom(bodySchemaWrapper, ...schemaLikes) {
|
|
537
|
+
return function (target, prop, descriptor) {
|
|
538
|
+
// schema
|
|
539
|
+
const metaType = appMetadata.getDesignReturntype(target, prop);
|
|
540
|
+
const schema = makeSchemaLikes(schemaLikes, metaType);
|
|
541
|
+
// options
|
|
542
|
+
const options = appMetadata.getOwnMetadataMap(false, SymbolOpenApiOptions, target, prop);
|
|
543
|
+
options.bodySchema = schema;
|
|
544
|
+
options.bodySchemaWrapper = bodySchemaWrapper;
|
|
545
|
+
return descriptor;
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
function exclude() {
|
|
549
|
+
return function (target, prop, descriptor) {
|
|
550
|
+
const options = appMetadata.getOwnMetadataMap(false, SymbolOpenApiOptions, target, prop);
|
|
551
|
+
options.exclude = true;
|
|
552
|
+
return descriptor;
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function tags(tags) {
|
|
556
|
+
return function (target, prop, descriptor) {
|
|
557
|
+
const options = appMetadata.getOwnMetadataMap(false, SymbolOpenApiOptions, target, prop);
|
|
558
|
+
options.tags = tags;
|
|
559
|
+
return descriptor;
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
function header(header) {
|
|
563
|
+
return function (target, prop, descriptor) {
|
|
564
|
+
const options = appMetadata.getOwnMetadataMap(false, SymbolOpenApiOptions, target, prop);
|
|
565
|
+
if (!options.headers) options.headers = [];
|
|
566
|
+
options.headers.push(header);
|
|
567
|
+
return descriptor;
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
function headers(headers) {
|
|
571
|
+
return function (target, prop, descriptor) {
|
|
572
|
+
const options = appMetadata.getOwnMetadataMap(false, SymbolOpenApiOptions, target, prop);
|
|
573
|
+
if (!options.headers) options.headers = [];
|
|
574
|
+
options.headers.push(...headers);
|
|
575
|
+
return descriptor;
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
const Api = {
|
|
579
|
+
field: Field$1,
|
|
580
|
+
contentType,
|
|
581
|
+
body,
|
|
582
|
+
bodyCustom,
|
|
583
|
+
exclude,
|
|
584
|
+
tags,
|
|
585
|
+
header,
|
|
586
|
+
headers
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
function createPipesArgumentDecorator(paramType, extractValue) {
|
|
590
|
+
return function (field, ...schemaLikes) {
|
|
591
|
+
return function (target, prop, index) {
|
|
592
|
+
// not inherit
|
|
593
|
+
const argsMeta = appMetadata.getOwnMetadataArray(false, SymbolRouteHandlersArgumentsMeta, target, prop);
|
|
594
|
+
const hasParamField = typeof field === 'string';
|
|
595
|
+
const paramField = hasParamField ? field : undefined;
|
|
596
|
+
const paramSchemaLikes = hasParamField ? schemaLikes : [field, ...schemaLikes].filter(item => !!item);
|
|
597
|
+
const paramtypes = appMetadata.getMetadata('design:paramtypes', target, prop);
|
|
598
|
+
let metaType;
|
|
599
|
+
if (paramType === 'file') {
|
|
600
|
+
metaType = z.string().openapi({
|
|
601
|
+
format: 'binary'
|
|
602
|
+
});
|
|
603
|
+
} else if (paramType === 'files') {
|
|
604
|
+
metaType = z.array(z.string().openapi({
|
|
605
|
+
format: 'binary'
|
|
606
|
+
}));
|
|
607
|
+
} else {
|
|
608
|
+
metaType = paramtypes[index];
|
|
609
|
+
}
|
|
610
|
+
const argSchema = makeSchemaLikes(paramSchemaLikes, metaType);
|
|
611
|
+
argsMeta.push({
|
|
612
|
+
index,
|
|
613
|
+
type: paramType,
|
|
614
|
+
field: paramField,
|
|
615
|
+
pipes: [argSchema],
|
|
616
|
+
schema: argSchema,
|
|
617
|
+
extractValue
|
|
618
|
+
});
|
|
619
|
+
};
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function Param(property, ...schemaLikes) {
|
|
624
|
+
return createPipesArgumentDecorator('param')(property, ...schemaLikes);
|
|
625
|
+
}
|
|
626
|
+
function Query(property, ...schemaLikes) {
|
|
627
|
+
return createPipesArgumentDecorator('query')(property, ...schemaLikes);
|
|
628
|
+
}
|
|
629
|
+
function Body(property, ...schemaLikes) {
|
|
630
|
+
return createPipesArgumentDecorator('body')(property, ...schemaLikes);
|
|
631
|
+
}
|
|
632
|
+
function Headers(property, ...schemaLikes) {
|
|
633
|
+
return createPipesArgumentDecorator('headers')(property, ...schemaLikes);
|
|
634
|
+
}
|
|
635
|
+
function Fields(property, ...schemaLikes) {
|
|
636
|
+
return createPipesArgumentDecorator('fields')(property, ...schemaLikes);
|
|
637
|
+
}
|
|
638
|
+
function Field(property, ...schemaLikes) {
|
|
639
|
+
return createPipesArgumentDecorator('field')(property, ...schemaLikes);
|
|
640
|
+
}
|
|
641
|
+
function Files(property, ...schemaLikes) {
|
|
642
|
+
return createPipesArgumentDecorator('files')(property, ...schemaLikes);
|
|
643
|
+
}
|
|
644
|
+
function File(property, ...schemaLikes) {
|
|
645
|
+
return createPipesArgumentDecorator('file')(property, ...schemaLikes);
|
|
646
|
+
}
|
|
647
|
+
function User(...schemaLikes) {
|
|
648
|
+
return createPipesArgumentDecorator('user')(undefined, ...schemaLikes);
|
|
649
|
+
}
|
|
650
|
+
const Arg = {
|
|
651
|
+
param: Param,
|
|
652
|
+
query: Query,
|
|
653
|
+
body: Body,
|
|
654
|
+
headers: Headers,
|
|
655
|
+
fields: Fields,
|
|
656
|
+
field: Field,
|
|
657
|
+
files: Files,
|
|
658
|
+
file: File,
|
|
659
|
+
user: User
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
function schemaEmail(message) {
|
|
663
|
+
return function (schema) {
|
|
664
|
+
return schema.email(message);
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
function schemaUrl(message) {
|
|
668
|
+
return function (schema) {
|
|
669
|
+
return schema.url(message);
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
function schemaUuid(message) {
|
|
673
|
+
return function (schema) {
|
|
674
|
+
return schema.uuid(message);
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
function schemaIp(options) {
|
|
678
|
+
return function (schema) {
|
|
679
|
+
return schema.ip(options);
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
function schemaMin(min, message) {
|
|
683
|
+
return function (schema) {
|
|
684
|
+
return schema.min(min, message);
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
function schemaMax(max, message) {
|
|
688
|
+
return function (schema) {
|
|
689
|
+
return schema.max(max, message);
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
function schemaTableIdentity() {
|
|
693
|
+
return function (_schema) {
|
|
694
|
+
return z.union([z.string(), z.number()]);
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
function schemaOpenapi(refId, metadata) {
|
|
699
|
+
return function (schema) {
|
|
700
|
+
return schema.openapi(refId, metadata);
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
function schemaTitle(title) {
|
|
704
|
+
return function (schema) {
|
|
705
|
+
return schema.openapi({
|
|
706
|
+
title
|
|
707
|
+
});
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
function schemaDescription(description) {
|
|
711
|
+
return function (schema) {
|
|
712
|
+
return schema.openapi({
|
|
713
|
+
description
|
|
714
|
+
});
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
function schemaExample(example) {
|
|
718
|
+
return function (schema) {
|
|
719
|
+
return schema.openapi({
|
|
720
|
+
example
|
|
721
|
+
});
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
function schemaDefault(defaultValue) {
|
|
726
|
+
return function (schema) {
|
|
727
|
+
return schema.default(defaultValue);
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
function schemaOptional() {
|
|
731
|
+
return function (schema) {
|
|
732
|
+
return schema.optional();
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
function schemaObject(classType, options) {
|
|
736
|
+
return function (_schema) {
|
|
737
|
+
return $schema(classType, options);
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
function schemaArray(schemaLike, params) {
|
|
741
|
+
return function (schema) {
|
|
742
|
+
return z.preprocess(val => {
|
|
743
|
+
val = coerceWithNil(val);
|
|
744
|
+
if (isNil(val)) return val;
|
|
745
|
+
if (typeof val !== 'string') return val;
|
|
746
|
+
if (isNil(params?.separator) && val[0] === '[') return JSON.parse(val);
|
|
747
|
+
return val.split(params?.separator ?? ',');
|
|
748
|
+
}, z.array(makeSchemaLike(schemaLike ?? schema, z.any()), params)
|
|
749
|
+
// z.array(makeSchemaLike(schemaLike, schema), params),
|
|
750
|
+
);
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
const v = {
|
|
755
|
+
array: schemaArray,
|
|
756
|
+
default: schemaDefault,
|
|
757
|
+
object: schemaObject,
|
|
758
|
+
optional: schemaOptional,
|
|
759
|
+
// helpers
|
|
760
|
+
email: schemaEmail,
|
|
761
|
+
url: schemaUrl,
|
|
762
|
+
uuid: schemaUuid,
|
|
763
|
+
ip: schemaIp,
|
|
764
|
+
min: schemaMin,
|
|
765
|
+
max: schemaMax,
|
|
766
|
+
tableIdentity: schemaTableIdentity,
|
|
767
|
+
// openapi
|
|
768
|
+
openapi: schemaOpenapi,
|
|
769
|
+
title: schemaTitle,
|
|
770
|
+
description: schemaDescription,
|
|
771
|
+
example: schemaExample
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
const OrderCoreBase = 100;
|
|
775
|
+
const OrderBusinessBase = 1000;
|
|
776
|
+
const OrderUnknownBase = 10000;
|
|
777
|
+
const OrderMaxBase = 100000;
|
|
778
|
+
|
|
779
|
+
export { $locale, $schema, Api, Arg, Main, OrderBusinessBase, OrderCoreBase, OrderMaxBase, OrderUnknownBase, ScopeModuleAOpenapi, ServiceOpenapi, SymbolDecoratorRule, SymbolDecoratorRuleColumn, SymbolOpenApiOptions, SymbolRouteHandlersArgumentsMeta, SymbolRouteHandlersArgumentsValue, bodySchemaWrapperDefault, config, createPipesArgumentDecorator, errorsAdapter, getTargetDecoratorRuleColumns, getTargetDecoratorRules, locales, makeSchemaLike, makeSchemaLikes, mergeFieldsOpenAPIMetadata, setPublic, v };
|