evaengine 1.0.14 → 2.0.0
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 +15 -1
- package/bin/engine +2 -31
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +40 -0
- package/dist/bin.js.map +1 -0
- package/{src/commands/index.js → dist/commands/index.d.ts} +1 -8
- package/dist/commands/index.js +6 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/interface.d.ts +18 -0
- package/dist/commands/interface.js +40 -0
- package/dist/commands/interface.js.map +1 -0
- package/dist/commands/make_entity.d.ts +47 -0
- package/dist/commands/make_entity.js +410 -0
- package/dist/commands/make_entity.js.map +1 -0
- package/dist/commands/tramp.d.ts +7 -0
- package/dist/commands/tramp.js +29 -0
- package/dist/commands/tramp.js.map +1 -0
- package/dist/config/index.d.ts +92 -0
- package/dist/config/index.js +96 -0
- package/dist/config/index.js.map +1 -0
- package/dist/di.d.ts +73 -0
- package/dist/di.js +76 -0
- package/dist/di.js.map +1 -0
- package/dist/engine.d.ts +85 -0
- package/dist/engine.js +404 -0
- package/dist/engine.js.map +1 -0
- package/dist/entities/index.d.ts +54 -0
- package/dist/entities/index.js +228 -0
- package/dist/entities/index.js.map +1 -0
- package/dist/exceptions/index.d.ts +153 -0
- package/dist/exceptions/index.js +439 -0
- package/dist/exceptions/index.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/middlewares/auth.d.ts +5 -0
- package/dist/middlewares/auth.js +63 -0
- package/dist/middlewares/auth.js.map +1 -0
- package/dist/middlewares/auth_kong.d.ts +2 -0
- package/dist/middlewares/auth_kong.js +24 -0
- package/dist/middlewares/auth_kong.js.map +1 -0
- package/dist/middlewares/debug.d.ts +3 -0
- package/dist/middlewares/debug.js +50 -0
- package/dist/middlewares/debug.js.map +1 -0
- package/{src/middlewares/index.js → dist/middlewares/index.d.ts} +1 -11
- package/dist/middlewares/index.js +9 -0
- package/dist/middlewares/index.js.map +1 -0
- package/dist/middlewares/providers.d.ts +25 -0
- package/dist/middlewares/providers.js +63 -0
- package/dist/middlewares/providers.js.map +1 -0
- package/dist/middlewares/session.d.ts +6 -0
- package/dist/middlewares/session.js +51 -0
- package/dist/middlewares/session.js.map +1 -0
- package/dist/middlewares/trace.d.ts +52 -0
- package/dist/middlewares/trace.js +225 -0
- package/dist/middlewares/trace.js.map +1 -0
- package/dist/middlewares/validator.d.ts +10 -0
- package/dist/middlewares/validator.js +43 -0
- package/dist/middlewares/validator.js.map +1 -0
- package/dist/middlewares/view_cache.d.ts +14 -0
- package/dist/middlewares/view_cache.js +102 -0
- package/dist/middlewares/view_cache.js.map +1 -0
- package/dist/services/cache.d.ts +66 -0
- package/dist/services/cache.js +207 -0
- package/dist/services/cache.js.map +1 -0
- package/dist/services/config.d.ts +25 -0
- package/dist/services/config.js +88 -0
- package/dist/services/config.js.map +1 -0
- package/dist/services/env.d.ts +12 -0
- package/dist/services/env.js +24 -0
- package/dist/services/env.js.map +1 -0
- package/dist/services/event_manager.d.ts +29 -0
- package/dist/services/event_manager.js +75 -0
- package/dist/services/event_manager.js.map +1 -0
- package/dist/services/http_client.d.ts +66 -0
- package/dist/services/http_client.js +62 -0
- package/dist/services/http_client.js.map +1 -0
- package/{src/services/index.js → dist/services/index.d.ts} +1 -15
- package/dist/services/index.js +14 -0
- package/dist/services/index.js.map +1 -0
- package/{src/services/interface.js → dist/services/interface.d.ts} +1 -3
- package/dist/services/interface.js +6 -0
- package/dist/services/interface.js.map +1 -0
- package/{src/services/joi.js → dist/services/joi.d.ts} +2 -9
- package/dist/services/joi.js +11 -0
- package/dist/services/joi.js.map +1 -0
- package/dist/services/jwt_token.d.ts +24 -0
- package/dist/services/jwt_token.js +77 -0
- package/dist/services/jwt_token.js.map +1 -0
- package/dist/services/jwt_token_kong.d.ts +25 -0
- package/dist/services/jwt_token_kong.js +65 -0
- package/dist/services/jwt_token_kong.js.map +1 -0
- package/dist/services/logger.d.ts +30 -0
- package/dist/services/logger.js +126 -0
- package/dist/services/logger.js.map +1 -0
- package/dist/services/namespace.d.ts +55 -0
- package/dist/services/namespace.js +157 -0
- package/dist/services/namespace.js.map +1 -0
- package/dist/services/now.d.ts +14 -0
- package/dist/services/now.js +43 -0
- package/dist/services/now.js.map +1 -0
- package/dist/services/providers.d.ts +55 -0
- package/dist/services/providers.js +134 -0
- package/dist/services/providers.js.map +1 -0
- package/dist/services/redis.d.ts +18 -0
- package/dist/services/redis.js +53 -0
- package/dist/services/redis.js.map +1 -0
- package/dist/services/rest_client.d.ts +48 -0
- package/dist/services/rest_client.js +96 -0
- package/dist/services/rest_client.js.map +1 -0
- package/dist/swagger/index.d.ts +223 -0
- package/dist/swagger/index.js +564 -0
- package/dist/swagger/index.js.map +1 -0
- package/dist/types/express.d.ts +14 -0
- package/dist/types/vendor.d.ts +102 -0
- package/dist/utils/api_scaffold.d.ts +74 -0
- package/dist/utils/api_scaffold.js +220 -0
- package/dist/utils/api_scaffold.js.map +1 -0
- package/dist/utils/case_converter.d.ts +7 -0
- package/dist/utils/case_converter.js +29 -0
- package/dist/utils/case_converter.js.map +1 -0
- package/dist/utils/crc32.d.ts +2 -0
- package/dist/utils/crc32.js +43 -0
- package/dist/utils/crc32.js.map +1 -0
- package/dist/utils/cron.d.ts +27 -0
- package/dist/utils/cron.js +186 -0
- package/dist/utils/cron.js.map +1 -0
- package/dist/utils/datetime.d.ts +4 -0
- package/dist/utils/datetime.js +6 -0
- package/dist/utils/datetime.js.map +1 -0
- package/dist/utils/host.d.ts +18 -0
- package/dist/utils/host.js +33 -0
- package/dist/utils/host.js.map +1 -0
- package/{src/utils/index.js → dist/utils/index.d.ts} +2 -26
- package/dist/utils/index.js +12 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/pagination.d.ts +150 -0
- package/dist/utils/pagination.js +242 -0
- package/dist/utils/pagination.js.map +1 -0
- package/dist/utils/random.d.ts +3 -0
- package/dist/utils/random.js +18 -0
- package/dist/utils/random.js.map +1 -0
- package/dist/utils/request_client.d.ts +33 -0
- package/dist/utils/request_client.js +153 -0
- package/dist/utils/request_client.js.map +1 -0
- package/dist/utils/smart_query.d.ts +144 -0
- package/dist/utils/smart_query.js +310 -0
- package/dist/utils/smart_query.js.map +1 -0
- package/dist/utils/test.d.ts +14 -0
- package/dist/utils/test.js +37 -0
- package/dist/utils/test.js.map +1 -0
- package/dist/utils/wrapper.d.ts +3 -0
- package/dist/utils/wrapper.js +5 -0
- package/dist/utils/wrapper.js.map +1 -0
- package/package.json +24 -10
- package/index.js +0 -2
- package/src/commands/interface.js +0 -45
- package/src/commands/make_entity.js +0 -490
- package/src/commands/tramp.js +0 -34
- package/src/config/index.js +0 -95
- package/src/di.js +0 -96
- package/src/engine.js +0 -556
- package/src/entities/index.js +0 -272
- package/src/exceptions/index.js +0 -501
- package/src/index.js +0 -55
- package/src/middlewares/auth.js +0 -67
- package/src/middlewares/auth_kong.js +0 -28
- package/src/middlewares/debug.js +0 -88
- package/src/middlewares/providers.js +0 -73
- package/src/middlewares/session.js +0 -63
- package/src/middlewares/trace.js +0 -254
- package/src/middlewares/validator.js +0 -50
- package/src/middlewares/view_cache.js +0 -127
- package/src/services/cache.js +0 -223
- package/src/services/config.js +0 -115
- package/src/services/env.js +0 -28
- package/src/services/event_manager.js +0 -84
- package/src/services/http_client.js +0 -69
- package/src/services/jwt_token.js +0 -89
- package/src/services/jwt_token_kong.js +0 -75
- package/src/services/logger.js +0 -150
- package/src/services/namespace.js +0 -176
- package/src/services/now.js +0 -49
- package/src/services/providers.js +0 -158
- package/src/services/redis.js +0 -63
- package/src/services/rest_client.js +0 -112
- package/src/swagger/index.js +0 -665
- package/src/utils/api_scaffold.js +0 -240
- package/src/utils/case_converter.js +0 -33
- package/src/utils/crc32.js +0 -44
- package/src/utils/cron.js +0 -208
- package/src/utils/datetime.js +0 -13
- package/src/utils/host.js +0 -39
- package/src/utils/pagination.js +0 -260
- package/src/utils/random.js +0 -23
- package/src/utils/request_client.js +0 -179
- package/src/utils/smart_query.js +0 -352
- package/src/utils/test.js +0 -48
- package/src/utils/wrapper.js +0 -8
package/src/swagger/index.js
DELETED
|
@@ -1,665 +0,0 @@
|
|
|
1
|
-
/*eslint new-cap: [1]*/
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import { createRequire } from 'module';
|
|
4
|
-
import { format } from 'util';
|
|
5
|
-
import assert from 'assert';
|
|
6
|
-
import merge from 'lodash/merge.js';
|
|
7
|
-
import * as doctrine from 'doctrine';
|
|
8
|
-
import * as acorn from 'acorn';
|
|
9
|
-
import * as yaml from 'js-yaml';
|
|
10
|
-
import Entitles from '../entities/index.js';
|
|
11
|
-
import { RuntimeException, StandardException } from '../exceptions/index.js';
|
|
12
|
-
|
|
13
|
-
const require = createRequire(import.meta.url);
|
|
14
|
-
|
|
15
|
-
export class AcornParsingException extends StandardException {
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export class YamlParsingException extends StandardException {
|
|
19
|
-
/**
|
|
20
|
-
* @param {Annotation} annotation
|
|
21
|
-
* @returns {YamlParsingException}
|
|
22
|
-
*/
|
|
23
|
-
setAnnotation(annotation) {
|
|
24
|
-
this.annotation = annotation || {};
|
|
25
|
-
return this;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @returns {Annotation}
|
|
30
|
-
*/
|
|
31
|
-
getAnnotation() {
|
|
32
|
-
return this.annotation || {};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
toString() {
|
|
36
|
-
const {
|
|
37
|
-
file, start, end, value
|
|
38
|
-
} = this.getAnnotation();
|
|
39
|
-
return format(
|
|
40
|
-
'Yaml parsing error happened in %s Line[%s - %s]\n Yaml error: %s \nOriginal Yaml Text:',
|
|
41
|
-
file, start, end,
|
|
42
|
-
this.getPrevError() ? this.getPrevError().message : '',
|
|
43
|
-
value ? value.split('\n').map((v, i) => `${(i - 1).toString().padStart(5)} ${v}`) : []
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
constructor(...args) {
|
|
48
|
-
super(...args);
|
|
49
|
-
this.annotation = {};
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
//Mapping sequelize data types to swagger data types
|
|
55
|
-
//Sequelize types: http://docs.sequelizejs.com/en/latest/api/datatypes/
|
|
56
|
-
//Swagger Data Types: http://swagger.io/specification/
|
|
57
|
-
export const MODEL_TO_FRAGMENT_TYPES_MAPPING = {
|
|
58
|
-
BIGINT: 'integer',
|
|
59
|
-
ENUM: 'string',
|
|
60
|
-
INTEGER: 'integer',
|
|
61
|
-
FLOAT: 'number',
|
|
62
|
-
DOUBLE: 'number',
|
|
63
|
-
DECIMAL: 'number',
|
|
64
|
-
BOOLEAN: 'boolean',
|
|
65
|
-
CHAR: 'string',
|
|
66
|
-
STRING: 'string',
|
|
67
|
-
TEXT: 'string',
|
|
68
|
-
REAL: 'string',
|
|
69
|
-
TIME: 'string',
|
|
70
|
-
DATE: 'string',
|
|
71
|
-
DATEONLY: 'string',
|
|
72
|
-
HSTORE: 'string',
|
|
73
|
-
JSON: 'string',
|
|
74
|
-
JSONB: 'string',
|
|
75
|
-
NOW: 'string',
|
|
76
|
-
BLOB: 'string',
|
|
77
|
-
UUID: 'string',
|
|
78
|
-
UUIDV1: 'string',
|
|
79
|
-
UUIDV4: 'string',
|
|
80
|
-
VIRTUAL: 'string'
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const modelDefaultValueHandlers = {
|
|
84
|
-
integer: v => parseInt(v, 10),
|
|
85
|
-
boolean: v => Boolean(parseInt(v, 10)),
|
|
86
|
-
number: v => parseFloat(v),
|
|
87
|
-
default: v => v
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const FRAGMENT_TYPE_PATH = 'path';
|
|
91
|
-
const FRAGMENT_TYPE_DEFINITION = 'definition';
|
|
92
|
-
const FRAGMENT_TYPE_EXCEPTION = 'exception';
|
|
93
|
-
const FRAGMENT_TYPE_UNKNOWN = 'unknown';
|
|
94
|
-
|
|
95
|
-
export class Fragment {
|
|
96
|
-
/**
|
|
97
|
-
* @returns {[*,*,*,*]}
|
|
98
|
-
*/
|
|
99
|
-
getTypes() {
|
|
100
|
-
return [FRAGMENT_TYPE_PATH, FRAGMENT_TYPE_DEFINITION,
|
|
101
|
-
FRAGMENT_TYPE_EXCEPTION, FRAGMENT_TYPE_UNKNOWN];
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
isPath() {
|
|
105
|
-
return this.type === FRAGMENT_TYPE_PATH;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
isDefinition() {
|
|
109
|
-
return this.type === FRAGMENT_TYPE_DEFINITION;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
isUnknown() {
|
|
113
|
-
return this.type === FRAGMENT_TYPE_UNKNOWN;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
isException() {
|
|
117
|
-
return this.type === FRAGMENT_TYPE_EXCEPTION;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* @param {Fragment} fragment
|
|
122
|
-
* @returns {Fragment}
|
|
123
|
-
*/
|
|
124
|
-
setParentFragment(fragment) {
|
|
125
|
-
assert(fragment && fragment instanceof Fragment, 'Parent fragment must be instance of Fragment');
|
|
126
|
-
this.parent = fragment;
|
|
127
|
-
return this;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* @returns {null|Fragment}
|
|
132
|
-
*/
|
|
133
|
-
getParentFragment() {
|
|
134
|
-
return this.parent;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
correctSwaggerPath(swaggerDoc = {}) {
|
|
138
|
-
return swaggerDoc;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
toSwaggerDoc(exceptions = {}) {
|
|
142
|
-
if (this.isPath()) {
|
|
143
|
-
const path = Object.keys(this.value)[0];
|
|
144
|
-
const method = Object.keys(this.value[path])[0];
|
|
145
|
-
return {
|
|
146
|
-
paths: {
|
|
147
|
-
[path]: {
|
|
148
|
-
[method]: this.correctSwaggerPath(this.value[path][method])
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (this.isDefinition()) {
|
|
155
|
-
const key = Object.keys(this.value)[0];
|
|
156
|
-
return {
|
|
157
|
-
definitions: {
|
|
158
|
-
[key]: this.value[key]
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (this.isException()) {
|
|
164
|
-
if (!this.getParentFragment()) {
|
|
165
|
-
return {};
|
|
166
|
-
}
|
|
167
|
-
const key = this.value;
|
|
168
|
-
const exception = exceptions[key];
|
|
169
|
-
if (!exception) {
|
|
170
|
-
return {};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const path = Object.keys(this.getParentFragment().value)[0];
|
|
174
|
-
const method = Object.keys(this.getParentFragment().value[path])[0];
|
|
175
|
-
return {
|
|
176
|
-
definitions: {
|
|
177
|
-
[key]: Fragment.exceptionMapping(exception)
|
|
178
|
-
},
|
|
179
|
-
paths: {
|
|
180
|
-
[path]: {
|
|
181
|
-
[method]: {
|
|
182
|
-
responses: {
|
|
183
|
-
[exception.getStatusCode()]: {
|
|
184
|
-
description: this.description,
|
|
185
|
-
schema: {
|
|
186
|
-
$ref: `#/definitions/${key}`
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return {};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
static exceptionMapping(exception) {
|
|
200
|
-
return {
|
|
201
|
-
properties: {
|
|
202
|
-
code: {
|
|
203
|
-
type: 'integer',
|
|
204
|
-
format: 'int64'
|
|
205
|
-
},
|
|
206
|
-
message: {
|
|
207
|
-
type: 'string'
|
|
208
|
-
}
|
|
209
|
-
},
|
|
210
|
-
required: [
|
|
211
|
-
'code',
|
|
212
|
-
'message'
|
|
213
|
-
],
|
|
214
|
-
example: {
|
|
215
|
-
code: exception.getCode(),
|
|
216
|
-
message: exception.message
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* @param jsdoc
|
|
223
|
-
* @param {Annotation} annotation
|
|
224
|
-
* @returns {Fragment}
|
|
225
|
-
*/
|
|
226
|
-
static factory(jsdoc, annotation) {
|
|
227
|
-
const { title, description, type } = jsdoc;
|
|
228
|
-
if (title === 'throws') {
|
|
229
|
-
return new Fragment({
|
|
230
|
-
type: FRAGMENT_TYPE_EXCEPTION,
|
|
231
|
-
description,
|
|
232
|
-
value: type ? type.name : FRAGMENT_TYPE_UNKNOWN,
|
|
233
|
-
file: annotation.file,
|
|
234
|
-
start: annotation.start,
|
|
235
|
-
end: annotation.end
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
let elementType = FRAGMENT_TYPE_UNKNOWN;
|
|
240
|
-
const value = yaml.load(description);
|
|
241
|
-
const key = Object.keys(value)[0];
|
|
242
|
-
if (title === 'swagger') {
|
|
243
|
-
elementType = key.startsWith('/') ? FRAGMENT_TYPE_PATH : FRAGMENT_TYPE_DEFINITION;
|
|
244
|
-
}
|
|
245
|
-
return new Fragment({
|
|
246
|
-
type: elementType,
|
|
247
|
-
description,
|
|
248
|
-
value,
|
|
249
|
-
file: annotation.file,
|
|
250
|
-
start: annotation.start,
|
|
251
|
-
end: annotation.end
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
constructor({
|
|
256
|
-
type, description, value, file, start, end
|
|
257
|
-
}) {
|
|
258
|
-
assert(type && description && value && file && start && end, 'Fragment require type && description && value && file && start && end');
|
|
259
|
-
assert(this.getTypes().includes(type), 'Fragment types not match input');
|
|
260
|
-
this.type = type;
|
|
261
|
-
this.description = description;
|
|
262
|
-
this.value = value;
|
|
263
|
-
this.file = file;
|
|
264
|
-
this.start = start;
|
|
265
|
-
this.end = end;
|
|
266
|
-
this.parent = null;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export class Annotation {
|
|
271
|
-
/**
|
|
272
|
-
* @returns {Array<Fragment>}
|
|
273
|
-
*/
|
|
274
|
-
getFragments() {
|
|
275
|
-
if (this.fragments) {
|
|
276
|
-
return this.fragments;
|
|
277
|
-
}
|
|
278
|
-
//支持两种注解:
|
|
279
|
-
//1. 所有行首必定为 space*
|
|
280
|
-
//2. 所有行首必定不为 space*
|
|
281
|
-
const unwrap = this.value.startsWith('*\n *');
|
|
282
|
-
const { tags: jsDocs = [] } = doctrine.parse(this.value, { unwrap });
|
|
283
|
-
if (jsDocs.length < 1) {
|
|
284
|
-
return [];
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* @type {Array<Fragment>}
|
|
289
|
-
*/
|
|
290
|
-
const fragments = [];
|
|
291
|
-
jsDocs.filter(jsDoc =>
|
|
292
|
-
jsDoc.title
|
|
293
|
-
&& (jsDoc.title === 'swagger' || jsDoc.title === 'throws')
|
|
294
|
-
&& jsDoc.description)
|
|
295
|
-
.forEach((jsDoc) => {
|
|
296
|
-
try {
|
|
297
|
-
fragments.push(Fragment.factory(jsDoc, this));
|
|
298
|
-
} catch (e) {
|
|
299
|
-
this.yamlErrors.push((new YamlParsingException(e)).setAnnotation(this));
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
fragments.forEach((fragment) => {
|
|
304
|
-
if (fragment.isException()) {
|
|
305
|
-
fragment.setParentFragment(fragments.filter(f => f.isPath())[0]);
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
this.fragments = fragments;
|
|
310
|
-
return fragments;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
toString() {
|
|
314
|
-
return format('Annotation %s [%s - %s]: %s', this.file, this.start, this.end, this.value);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
getYamlErrors() {
|
|
318
|
-
return this.yamlErrors;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
constructor({
|
|
322
|
-
type, //Block
|
|
323
|
-
value, //Long string
|
|
324
|
-
file, //String
|
|
325
|
-
start,
|
|
326
|
-
end
|
|
327
|
-
}) {
|
|
328
|
-
assert(type && type === 'Block', 'Annotation type must be Block');
|
|
329
|
-
assert(value && typeof value === 'string', 'Annotation value must be Block');
|
|
330
|
-
assert(file, 'Annotation must have file');
|
|
331
|
-
this.value = value;
|
|
332
|
-
this.file = file;
|
|
333
|
-
this.start = start;
|
|
334
|
-
this.end = end;
|
|
335
|
-
this.yamlErrors = [];
|
|
336
|
-
this.fragments = null;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
export class AnnotationsContainer {
|
|
341
|
-
/**
|
|
342
|
-
* @returns {string}
|
|
343
|
-
*/
|
|
344
|
-
getFile() {
|
|
345
|
-
return this.file;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* @returns {boolean}
|
|
350
|
-
*/
|
|
351
|
-
hasAnnotations() {
|
|
352
|
-
return this.annotations.length > 0;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* @returns {Array<Annotation>}
|
|
357
|
-
*/
|
|
358
|
-
getAnnotations() {
|
|
359
|
-
return this.annotations;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* @returns {Array.<Fragment>}
|
|
364
|
-
*/
|
|
365
|
-
collectFragments() {
|
|
366
|
-
if (this.fragments.length > 0) {
|
|
367
|
-
return this.fragments;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
for (const annotation of this.getAnnotations()) {
|
|
371
|
-
this.fragments = this.fragments.concat(annotation.getFragments());
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
return this.fragments;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* @returns {Array}
|
|
379
|
-
*/
|
|
380
|
-
collectYamlErrors() {
|
|
381
|
-
let errors = [];
|
|
382
|
-
for (const annotation of this.getAnnotations()) {
|
|
383
|
-
errors = errors.concat(annotation.getYamlErrors());
|
|
384
|
-
}
|
|
385
|
-
return errors;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
constructor(file, acornComments) {
|
|
389
|
-
assert(file && typeof file === 'string', 'Annotations require a file input');
|
|
390
|
-
assert(acornComments && Array.isArray(acornComments), `Annotations for ${file} require an array of Acorn comments input`);
|
|
391
|
-
this.file = file;
|
|
392
|
-
//Annotations MUST start with double stars
|
|
393
|
-
this.annotations = acornComments
|
|
394
|
-
.filter(v => v.type === 'Block' && v.value.startsWith('*\n'))
|
|
395
|
-
.map(c => new Annotation(Object.assign(c, { file })));
|
|
396
|
-
this.fragments = [];
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* A Swagger Json document generator
|
|
402
|
-
* Generate document from
|
|
403
|
-
* - JS source code annotations (Parser is Doctrine)
|
|
404
|
-
* - ORM entities (Based on Sequelize)
|
|
405
|
-
* - EvaEngine Exceptions
|
|
406
|
-
*/
|
|
407
|
-
export class ExSwagger {
|
|
408
|
-
/**
|
|
409
|
-
* Get file path array by glob
|
|
410
|
-
* @param path
|
|
411
|
-
* @param options
|
|
412
|
-
* @returns {Promise|Array.<string>}
|
|
413
|
-
*/
|
|
414
|
-
static async scanFiles(path, options = {}) {
|
|
415
|
-
return fs.globSync(path, options);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* Get annotations from comments
|
|
420
|
-
* An annotation MUST start with double stars
|
|
421
|
-
* @param files {Array.<string>}
|
|
422
|
-
* @returns {Array.<AnnotationsContainer>}
|
|
423
|
-
*/
|
|
424
|
-
static async filesToAnnotationsContainers(files) {
|
|
425
|
-
const results = [];
|
|
426
|
-
for (const file of files) {
|
|
427
|
-
const comments = [];
|
|
428
|
-
const source = await fs.readFileSync(file);
|
|
429
|
-
try {
|
|
430
|
-
acorn.parse(source, {
|
|
431
|
-
ecmaVersion: 'latest',
|
|
432
|
-
sourceType: 'module',
|
|
433
|
-
allowImportExportEverywhere: true,
|
|
434
|
-
onComment: comments
|
|
435
|
-
});
|
|
436
|
-
} catch (e) {
|
|
437
|
-
throw (new AcornParsingException(`Acorn parsing file ${file} failed`)).setPrevError(e);
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
results.push(new AnnotationsContainer(file, comments));
|
|
441
|
-
}
|
|
442
|
-
return results;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
static modelToSwaggerDefinition(model) {
|
|
446
|
-
const definition = {
|
|
447
|
-
type: 'object',
|
|
448
|
-
properties: {}
|
|
449
|
-
};
|
|
450
|
-
const requires = [];
|
|
451
|
-
Object.keys(model).forEach((columnName) => {
|
|
452
|
-
const column = model[columnName];
|
|
453
|
-
const swaggerType = MODEL_TO_FRAGMENT_TYPES_MAPPING[column.type.key];
|
|
454
|
-
const property = {
|
|
455
|
-
type: swaggerType,
|
|
456
|
-
description: column.comment
|
|
457
|
-
};
|
|
458
|
-
if (column.defaultValue) {
|
|
459
|
-
const defaultValueHandler = modelDefaultValueHandlers[swaggerType] ?
|
|
460
|
-
modelDefaultValueHandlers[swaggerType] : modelDefaultValueHandlers.default;
|
|
461
|
-
property.default = defaultValueHandler(column.defaultValue);
|
|
462
|
-
}
|
|
463
|
-
if (column.allowNull === false) {
|
|
464
|
-
requires.push(columnName);
|
|
465
|
-
}
|
|
466
|
-
definition.properties[columnName] = property;
|
|
467
|
-
});
|
|
468
|
-
definition.required = requires;
|
|
469
|
-
return definition;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
static modelsToSwaggerDefinitions(models, blacklist = []) {
|
|
473
|
-
const definitions = new Map();
|
|
474
|
-
Object.keys(models).forEach((modelName) => {
|
|
475
|
-
if (blacklist.includes(modelName)) {
|
|
476
|
-
return true;
|
|
477
|
-
}
|
|
478
|
-
const model = models[modelName];
|
|
479
|
-
const attributes = model.attributes || model.rawAttributes;
|
|
480
|
-
const definition = ExSwagger.modelToSwaggerDefinition(attributes);
|
|
481
|
-
definitions.set(modelName, definition);
|
|
482
|
-
return true;
|
|
483
|
-
});
|
|
484
|
-
return definitions;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
static async scanExceptions(path, exceptionInterface = Error) {
|
|
488
|
-
const exceptions = {};
|
|
489
|
-
const files = await ExSwagger.scanFiles(path);
|
|
490
|
-
if (files.length < 1) {
|
|
491
|
-
return exceptions;
|
|
492
|
-
}
|
|
493
|
-
for (const file of files) {
|
|
494
|
-
const exceptionsInFile = require(file);
|
|
495
|
-
Object.keys(exceptionsInFile).forEach((exceptionName) => {
|
|
496
|
-
const exceptionClass = exceptionsInFile[exceptionName];
|
|
497
|
-
const exception = new exceptionClass(exceptionName); //eslint-disable-line new-cap
|
|
498
|
-
if (exception instanceof exceptionInterface) {
|
|
499
|
-
exceptions[exceptionName] = exception;
|
|
500
|
-
}
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
return exceptions;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
async exportJson(dist = this.swaggerDocsPath) {
|
|
508
|
-
this.logger.debug('Start export swagger docs by meta %j', this.getStates());
|
|
509
|
-
const fileGroups = await Promise
|
|
510
|
-
.all(this.sourceFilesPath.map(path => ExSwagger.scanFiles(path)));
|
|
511
|
-
let files = [];
|
|
512
|
-
fileGroups.forEach((fileGroup) => {
|
|
513
|
-
files = files.concat(fileGroup);
|
|
514
|
-
});
|
|
515
|
-
if (!files || files.length < 1) {
|
|
516
|
-
throw new RuntimeException('No swagger source files found');
|
|
517
|
-
}
|
|
518
|
-
this.logger.debug('Scanner will scan %s files under %j:', files.length, this.sourceFilesPath);
|
|
519
|
-
|
|
520
|
-
const annotationsContainers = await ExSwagger.filesToAnnotationsContainers(files);
|
|
521
|
-
let fragments = [];
|
|
522
|
-
annotationsContainers.forEach((annotationsContainer) => {
|
|
523
|
-
if (!annotationsContainer.hasAnnotations()) {
|
|
524
|
-
return false;
|
|
525
|
-
}
|
|
526
|
-
const annotationFragments = annotationsContainer.collectFragments();
|
|
527
|
-
fragments = fragments.concat(annotationFragments);
|
|
528
|
-
this.logger.debug(
|
|
529
|
-
'Scanner found %s annotations and collected %s fragments in file %s',
|
|
530
|
-
annotationsContainer.getAnnotations().length.toString().padStart(3),
|
|
531
|
-
annotationFragments.length.toString().padStart(3),
|
|
532
|
-
annotationsContainer.getFile()
|
|
533
|
-
);
|
|
534
|
-
|
|
535
|
-
const yamlErrors = annotationsContainer.collectYamlErrors();
|
|
536
|
-
yamlErrors.forEach(yamlError => this.logger.error(yamlError));
|
|
537
|
-
return true;
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
this.logger.debug('Scanner collected %s fragments in total', fragments.length);
|
|
541
|
-
|
|
542
|
-
const template = this.swaggerDocsTemplate;
|
|
543
|
-
const exceptions = {};
|
|
544
|
-
for (const exceptionPath of this.exceptionPaths) {
|
|
545
|
-
this.logger.debug('Search exception in %s', exceptionPath);
|
|
546
|
-
const exceptionsInFile = await ExSwagger.scanExceptions(
|
|
547
|
-
exceptionPath,
|
|
548
|
-
this.exceptionInterface
|
|
549
|
-
);
|
|
550
|
-
Object.assign(exceptions, exceptionsInFile);
|
|
551
|
-
this.logger.debug(
|
|
552
|
-
'Scanner found %s exceptions: %j',
|
|
553
|
-
Object.keys(exceptions).length,
|
|
554
|
-
Object.keys(exceptions)
|
|
555
|
-
);
|
|
556
|
-
}
|
|
557
|
-
const modelDefinitions = this.models ?
|
|
558
|
-
ExSwagger.modelsToSwaggerDefinitions(this.models, this.modelBlacklist) : new Map();
|
|
559
|
-
const swaggerDocs = ExSwagger.mergeAll(template, fragments, exceptions, modelDefinitions);
|
|
560
|
-
this.logger.debug('Export to %s', dist);
|
|
561
|
-
await fs.writeFileSync(dist, JSON.stringify(swaggerDocs));
|
|
562
|
-
return swaggerDocs;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
/**
|
|
566
|
-
* @param _template
|
|
567
|
-
* @param {Array<Fragment>} fragments
|
|
568
|
-
* @param exceptions
|
|
569
|
-
* @param modelDefinitions
|
|
570
|
-
* @returns {*}
|
|
571
|
-
*/
|
|
572
|
-
static mergeAll(_template, fragments, exceptions, modelDefinitions) {
|
|
573
|
-
const template = _template;
|
|
574
|
-
fragments.forEach(fragment => merge(template, fragment.toSwaggerDoc(exceptions)));
|
|
575
|
-
if (modelDefinitions) {
|
|
576
|
-
modelDefinitions.forEach((definition, modelName) => {
|
|
577
|
-
template.definitions[modelName] = definition;
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
return template;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
getStates() {
|
|
584
|
-
return {
|
|
585
|
-
swaggerTemplate: this.swaggerDocsTemplate,
|
|
586
|
-
modelBlacklist: this.modelBlacklist,
|
|
587
|
-
sourceFilesPath: this.sourceFilesPath,
|
|
588
|
-
exceptionPaths: this.exceptionPaths,
|
|
589
|
-
compileDistPath: this.compileDistPath,
|
|
590
|
-
swaggerUIPath: this.swaggerUIPath,
|
|
591
|
-
swaggerDocsPath: this.swaggerDocsPath
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
getSwaggerUIPath() {
|
|
596
|
-
return this.swaggerUIPath;
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
async getSwaggerIndexHtml() {
|
|
600
|
-
const uiPath = this.getSwaggerUIPath();
|
|
601
|
-
const content = await fs.readFileSync(`${uiPath}/index.html`);
|
|
602
|
-
return content.toString().replace(
|
|
603
|
-
'https://petstore.swagger.io/v2/swagger/index.json',
|
|
604
|
-
this.swaggerDocsPath.replace(this.compileDistPath, '')
|
|
605
|
-
);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
getCompileDistPath() {
|
|
609
|
-
return this.compileDistPath;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
constructor({
|
|
613
|
-
sourceRootPath,
|
|
614
|
-
compileDistPath,
|
|
615
|
-
models,
|
|
616
|
-
modelBlacklist = [],
|
|
617
|
-
swaggerDocsTemplate,
|
|
618
|
-
logger,
|
|
619
|
-
swaggerUIPath,
|
|
620
|
-
swaggerDocsPath = `${compileDistPath}/docs.json`,
|
|
621
|
-
sourceFilesPath = `${sourceRootPath}/**/*.js`,
|
|
622
|
-
exceptionInterface = StandardException,
|
|
623
|
-
extraSourcePaths = [`${import.meta.dirname}/../utils/**/*.js`],
|
|
624
|
-
exceptionPaths
|
|
625
|
-
}) {
|
|
626
|
-
this.logger = logger ||
|
|
627
|
-
{
|
|
628
|
-
debug: () => {
|
|
629
|
-
},
|
|
630
|
-
warn: () => {
|
|
631
|
-
},
|
|
632
|
-
error: () => {
|
|
633
|
-
}
|
|
634
|
-
};
|
|
635
|
-
|
|
636
|
-
if (!swaggerDocsTemplate) {
|
|
637
|
-
throw new RuntimeException('No swagger docs template input');
|
|
638
|
-
}
|
|
639
|
-
this.swaggerDocsTemplate = swaggerDocsTemplate;
|
|
640
|
-
if (models && !(models instanceof Entitles)) {
|
|
641
|
-
throw new RuntimeException('Input models must instance of engine.Entities');
|
|
642
|
-
}
|
|
643
|
-
this.models = models ? models.getAll() : null;
|
|
644
|
-
this.modelBlacklist = modelBlacklist;
|
|
645
|
-
|
|
646
|
-
this.sourceFilesPath = Array.isArray(sourceFilesPath)
|
|
647
|
-
? extraSourcePaths.concat(sourceFilesPath) :
|
|
648
|
-
extraSourcePaths.concat([sourceFilesPath]);
|
|
649
|
-
this.exceptionPaths = exceptionPaths ?
|
|
650
|
-
[`${import.meta.dirname}/../exceptions`].concat(exceptionPaths) : [`${import.meta.dirname}/../exceptions`];
|
|
651
|
-
this.exceptionInterface = exceptionInterface;
|
|
652
|
-
this.compileDistPath = compileDistPath;
|
|
653
|
-
if (swaggerUIPath) {
|
|
654
|
-
this.swaggerUIPath = swaggerUIPath;
|
|
655
|
-
} else {
|
|
656
|
-
this.swaggerUIPath = `${import.meta.dirname}/../../node_modules/swagger-ui-dist`;
|
|
657
|
-
try {
|
|
658
|
-
fs.accessSync(this.swaggerUIPath, fs.F_OK);
|
|
659
|
-
} catch {
|
|
660
|
-
this.swaggerUIPath = `${import.meta.dirname}/../../../swagger-ui-dist`; //For NPM v3.x
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
this.swaggerDocsPath = swaggerDocsPath;
|
|
664
|
-
}
|
|
665
|
-
}
|