@jayfong/x-server 2.12.14 → 2.12.16
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/lib/_cjs/cli/api_generator.js +20 -54
- package/lib/_cjs/cli/build_util.js +16 -45
- package/lib/_cjs/cli/cli.js +17 -29
- package/lib/_cjs/cli/deploy_util.js +0 -12
- package/lib/_cjs/cli/dev_util.js +18 -0
- package/lib/_cjs/cli/env_util.js +16 -49
- package/lib/_cjs/cli/{register.js → esbuild_register.js} +0 -1
- package/lib/_cjs/cli/template_util.js +26 -29
- package/lib/_cjs/core/define_bus.js +9 -6
- package/lib/_cjs/core/define_cron.js +0 -2
- package/lib/_cjs/core/define_handler.js +10 -12
- package/lib/_cjs/core/define_hook.js +0 -2
- package/lib/_cjs/core/define_server.js +0 -2
- package/lib/_cjs/core/define_task.js +7 -13
- package/lib/_cjs/core/get_handler_url.js +1 -2
- package/lib/_cjs/core/handler.js +8 -29
- package/lib/_cjs/core/http_error.js +0 -3
- package/lib/_cjs/core/http_header.js +8 -12
- package/lib/_cjs/core/server.js +8 -41
- package/lib/_cjs/core/types.js +0 -7
- package/lib/_cjs/index.js +0 -72
- package/lib/_cjs/plugins/cors.js +0 -7
- package/lib/_cjs/plugins/file_parser.js +2 -9
- package/lib/_cjs/plugins/form_body_parser.js +0 -6
- package/lib/_cjs/plugins/ws_parser.js +0 -6
- package/lib/_cjs/plugins/xml_parser.js +0 -12
- package/lib/_cjs/services/cache.js +18 -58
- package/lib/_cjs/services/captcha.js +0 -14
- package/lib/_cjs/services/dingtalk.js +0 -14
- package/lib/_cjs/services/dispose.js +0 -9
- package/lib/_cjs/services/emoji.js +2 -5
- package/lib/_cjs/services/jwt.js +0 -21
- package/lib/_cjs/services/log.js +0 -17
- package/lib/_cjs/services/mail.js +0 -9
- package/lib/_cjs/services/pay.js +9 -40
- package/lib/_cjs/services/rate_limit.js +0 -12
- package/lib/_cjs/services/redis.js +0 -4
- package/lib/_cjs/services/request.js +0 -5
- package/lib/_cjs/services/sensitive_words.js +13 -19
- package/lib/_cjs/x.js +0 -11
- package/lib/cli/api_generator.js +20 -42
- package/lib/cli/build_util.js +16 -19
- package/lib/cli/cli.js +17 -14
- package/lib/cli/deploy_util.js +0 -4
- package/lib/cli/dev_util.d.ts +8 -0
- package/lib/cli/dev_util.js +12 -0
- package/lib/cli/env_util.js +16 -37
- package/lib/cli/template_util.d.ts +1 -0
- package/lib/cli/template_util.js +26 -14
- package/lib/core/define_bus.js +7 -5
- package/lib/core/define_handler.js +10 -9
- package/lib/core/define_task.js +7 -6
- package/lib/core/get_handler_url.js +2 -1
- package/lib/core/handler.js +9 -22
- package/lib/core/http_header.js +6 -9
- package/lib/core/server.js +8 -31
- package/lib/core/types.js +0 -7
- package/lib/index.js +4 -3
- package/lib/plugins/cors.js +0 -3
- package/lib/plugins/file_parser.js +2 -5
- package/lib/plugins/form_body_parser.js +0 -3
- package/lib/plugins/ws_parser.js +0 -3
- package/lib/plugins/xml_parser.js +0 -10
- package/lib/services/cache.js +18 -52
- package/lib/services/captcha.js +0 -7
- package/lib/services/dingtalk.js +0 -7
- package/lib/services/dispose.js +0 -5
- package/lib/services/emoji.js +2 -3
- package/lib/services/jwt.js +0 -13
- package/lib/services/log.js +0 -8
- package/lib/services/mail.js +0 -3
- package/lib/services/pay.js +9 -30
- package/lib/services/rate_limit.js +0 -8
- package/lib/services/redis.js +0 -1
- package/lib/services/request.js +0 -1
- package/lib/services/sensitive_words.js +13 -15
- package/package.json +3 -3
- /package/lib/cli/{register.d.ts → esbuild_register.d.ts} +0 -0
- /package/lib/cli/{register.js → esbuild_register.js} +0 -0
package/lib/_cjs/services/pay.js
CHANGED
|
@@ -1,27 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
-
|
|
5
4
|
exports.__esModule = true;
|
|
6
5
|
exports.PayService = void 0;
|
|
7
|
-
|
|
8
6
|
var _form = _interopRequireDefault(require("alipay-sdk/lib/form"));
|
|
9
|
-
|
|
10
7
|
var _alipaySdk = _interopRequireDefault(require("alipay-sdk"));
|
|
11
|
-
|
|
12
8
|
var _crypto = _interopRequireDefault(require("crypto"));
|
|
13
|
-
|
|
14
9
|
var _got = _interopRequireDefault(require("got"));
|
|
15
|
-
|
|
16
10
|
var _http_error = require("../core/http_error");
|
|
17
|
-
|
|
18
11
|
class PayService {
|
|
19
12
|
constructor(options) {
|
|
20
13
|
this.options = options;
|
|
21
14
|
this.serviceName = 'pay';
|
|
22
15
|
this.alipaySdk = void 0;
|
|
23
16
|
}
|
|
24
|
-
|
|
25
17
|
async prepareAlipay(options) {
|
|
26
18
|
if (!this.alipaySdk) {
|
|
27
19
|
this.alipaySdk = new _alipaySdk.default({
|
|
@@ -30,15 +22,12 @@ class PayService {
|
|
|
30
22
|
alipayPublicKey: this.options.alipay.publicKey
|
|
31
23
|
});
|
|
32
24
|
}
|
|
33
|
-
|
|
34
25
|
const formData = new _form.default();
|
|
35
26
|
formData.setMethod('get');
|
|
36
27
|
formData.addField('notifyUrl', options.notifyUrl);
|
|
37
|
-
|
|
38
28
|
if (options.returnUrl) {
|
|
39
29
|
formData.addField('returnUrl', options.returnUrl);
|
|
40
30
|
}
|
|
41
|
-
|
|
42
31
|
formData.addField('bizContent', {
|
|
43
32
|
outTradeNo: options.tradeNumber,
|
|
44
33
|
productCode: 'FAST_INSTANT_TRADE_PAY',
|
|
@@ -54,7 +43,6 @@ class PayService {
|
|
|
54
43
|
payUrl: payUrl
|
|
55
44
|
};
|
|
56
45
|
}
|
|
57
|
-
|
|
58
46
|
async prepareWepay(options) {
|
|
59
47
|
const appId = options.appId || this.options.wepay.appId;
|
|
60
48
|
const res = await this.wepayRequest('https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi', {
|
|
@@ -72,12 +60,10 @@ class PayService {
|
|
|
72
60
|
openid: options.openid
|
|
73
61
|
}
|
|
74
62
|
});
|
|
75
|
-
|
|
76
63
|
if (!res || !res.prepay_id) {
|
|
77
64
|
const error = res && res.message || '支付错误';
|
|
78
65
|
throw new Error(error);
|
|
79
66
|
}
|
|
80
|
-
|
|
81
67
|
const params = {
|
|
82
68
|
appId: appId,
|
|
83
69
|
timestamp: String(Math.round(Date.now() / 1000)),
|
|
@@ -91,57 +77,47 @@ class PayService {
|
|
|
91
77
|
payParams: params
|
|
92
78
|
};
|
|
93
79
|
}
|
|
94
|
-
|
|
95
80
|
verifyNotifyData(data) {
|
|
96
81
|
try {
|
|
97
82
|
if (!data || typeof data !== 'object') {
|
|
98
83
|
return false;
|
|
99
|
-
}
|
|
100
|
-
// https://opendocs.alipay.com/open/270/105902
|
|
101
|
-
|
|
84
|
+
}
|
|
102
85
|
|
|
86
|
+
// 支付宝
|
|
87
|
+
// https://opendocs.alipay.com/open/270/105902
|
|
103
88
|
if (data.passback_params === 'alipay') {
|
|
104
89
|
var _this$alipaySdk;
|
|
105
|
-
|
|
106
90
|
if (!((_this$alipaySdk = this.alipaySdk) != null && _this$alipaySdk.checkNotifySign(data))) {
|
|
107
91
|
return false;
|
|
108
92
|
}
|
|
109
|
-
|
|
110
93
|
return {
|
|
111
94
|
channelOrderNo: data.trade_no
|
|
112
95
|
};
|
|
113
|
-
}
|
|
114
|
-
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml
|
|
115
|
-
|
|
96
|
+
}
|
|
116
97
|
|
|
98
|
+
// 微信支付
|
|
99
|
+
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml
|
|
117
100
|
if (data.resource) {
|
|
118
101
|
const params = JSON.parse(this.wepayDecrypt(data.resource));
|
|
119
|
-
|
|
120
102
|
if (params.attach === 'wepay') {
|
|
121
103
|
return {
|
|
122
104
|
channelOrderNo: params.transaction_id
|
|
123
105
|
};
|
|
124
106
|
}
|
|
125
|
-
|
|
126
107
|
return false;
|
|
127
108
|
}
|
|
128
|
-
|
|
129
109
|
return false;
|
|
130
110
|
} catch {
|
|
131
111
|
return false;
|
|
132
112
|
}
|
|
133
113
|
}
|
|
134
|
-
|
|
135
114
|
verifyNotifyDataOrFail(data, message) {
|
|
136
115
|
const res = this.verifyNotifyData(data);
|
|
137
|
-
|
|
138
116
|
if (!res) {
|
|
139
117
|
throw new _http_error.HttpError.BadRequest(message);
|
|
140
118
|
}
|
|
141
|
-
|
|
142
119
|
return res;
|
|
143
120
|
}
|
|
144
|
-
|
|
145
121
|
async getOrderInfo(payload) {
|
|
146
122
|
// 微信支付
|
|
147
123
|
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_2.shtml
|
|
@@ -152,10 +128,10 @@ class PayService {
|
|
|
152
128
|
orderNo: res.out_trade_no,
|
|
153
129
|
status: res.trade_state === 'SUCCESS' ? 'success' : 'fail'
|
|
154
130
|
};
|
|
155
|
-
}
|
|
156
|
-
// https://opendocs.alipay.com/open/028woa?scene=common&pathHash=dbf247eb
|
|
157
|
-
|
|
131
|
+
}
|
|
158
132
|
|
|
133
|
+
// 支付宝
|
|
134
|
+
// https://opendocs.alipay.com/open/028woa?scene=common&pathHash=dbf247eb
|
|
159
135
|
const res = await this.alipaySdk.exec('alipay.trade.query', {
|
|
160
136
|
biz_content: payload.orderNo ? {
|
|
161
137
|
out_trade_no: payload.orderNo
|
|
@@ -169,25 +145,20 @@ class PayService {
|
|
|
169
145
|
status: res.trade_status === 'TRADE_SUCCESS' || res.trade_status === 'TRADE_FINISHED' ? 'success' : 'fail'
|
|
170
146
|
};
|
|
171
147
|
}
|
|
172
|
-
|
|
173
148
|
wepaySign(data) {
|
|
174
149
|
return _crypto.default.createSign('RSA-SHA256').update(data.map(v => `${v}\n`).join('')).sign(this.options.wepay.privateKey, 'base64');
|
|
175
150
|
}
|
|
176
|
-
|
|
177
151
|
wepayDecrypt(payload) {
|
|
178
152
|
const ciphertextBuffer = Buffer.from(payload.ciphertext, 'base64');
|
|
179
153
|
const authTag = ciphertextBuffer.slice(ciphertextBuffer.length - 16);
|
|
180
154
|
const data = ciphertextBuffer.slice(0, ciphertextBuffer.length - 16);
|
|
181
|
-
|
|
182
155
|
const decipherIv = _crypto.default.createDecipheriv('aes-256-gcm', this.options.wepay.secretKey, payload.nonce);
|
|
183
|
-
|
|
184
156
|
decipherIv.setAuthTag(Buffer.from(authTag));
|
|
185
157
|
decipherIv.setAAD(Buffer.from(payload.associated_data));
|
|
186
158
|
const decryptStr = decipherIv.update(data, undefined, 'utf8');
|
|
187
159
|
decipherIv.final();
|
|
188
160
|
return decryptStr;
|
|
189
161
|
}
|
|
190
|
-
|
|
191
162
|
async wepayRequest(url, data) {
|
|
192
163
|
const path = url.replace(/^https?:\/\/[^/]+/, '');
|
|
193
164
|
const method = data == null ? 'GET' : 'POST';
|
|
@@ -218,7 +189,5 @@ class PayService {
|
|
|
218
189
|
});
|
|
219
190
|
return res;
|
|
220
191
|
}
|
|
221
|
-
|
|
222
192
|
}
|
|
223
|
-
|
|
224
193
|
exports.PayService = PayService;
|
|
@@ -2,43 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
4
|
exports.RateLimitService = void 0;
|
|
5
|
-
|
|
6
5
|
var _http_error = require("../core/http_error");
|
|
7
|
-
|
|
8
6
|
var _x = require("../x");
|
|
9
|
-
|
|
10
7
|
class RateLimitService {
|
|
11
8
|
constructor() {
|
|
12
9
|
this.serviceName = 'rateLimit';
|
|
13
10
|
}
|
|
14
|
-
|
|
15
11
|
async limitByCount(options) {
|
|
16
12
|
const cacheKey = `rateLimit_${options.key}`;
|
|
17
13
|
const remainingCount = await _x.x.cache.get(cacheKey);
|
|
18
|
-
|
|
19
14
|
if (remainingCount == null) {
|
|
20
15
|
await _x.x.cache.set(cacheKey, options.count, options.ttl);
|
|
21
16
|
return options.count;
|
|
22
17
|
}
|
|
23
|
-
|
|
24
18
|
if (remainingCount === 0) {
|
|
25
19
|
return 0;
|
|
26
20
|
}
|
|
27
|
-
|
|
28
21
|
await _x.x.cache.decrease(cacheKey);
|
|
29
22
|
return remainingCount - 1;
|
|
30
23
|
}
|
|
31
|
-
|
|
32
24
|
async limitByCountOrFail(options) {
|
|
33
25
|
const count = await this.limitByCount(options);
|
|
34
|
-
|
|
35
26
|
if (count === 0) {
|
|
36
27
|
throw new _http_error.HttpError.Forbidden(options.message);
|
|
37
28
|
}
|
|
38
|
-
|
|
39
29
|
return count;
|
|
40
30
|
}
|
|
41
|
-
|
|
42
31
|
}
|
|
43
|
-
|
|
44
32
|
exports.RateLimitService = RateLimitService;
|
|
@@ -2,15 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
4
|
exports.RedisService = void 0;
|
|
5
|
-
|
|
6
5
|
var _ioredis = require("ioredis");
|
|
7
|
-
|
|
8
6
|
class RedisService extends _ioredis.Redis {
|
|
9
7
|
constructor(...args) {
|
|
10
8
|
super(...args);
|
|
11
9
|
this.serviceName = 'redis';
|
|
12
10
|
}
|
|
13
|
-
|
|
14
11
|
}
|
|
15
|
-
|
|
16
12
|
exports.RedisService = RedisService;
|
|
@@ -5,22 +5,17 @@ var _exportNames = {
|
|
|
5
5
|
RequestService: true
|
|
6
6
|
};
|
|
7
7
|
exports.RequestService = void 0;
|
|
8
|
-
|
|
9
8
|
var _xRequest = require("@jayfong/x-request");
|
|
10
|
-
|
|
11
9
|
Object.keys(_xRequest).forEach(function (key) {
|
|
12
10
|
if (key === "default" || key === "__esModule") return;
|
|
13
11
|
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
14
12
|
if (key in exports && exports[key] === _xRequest[key]) return;
|
|
15
13
|
exports[key] = _xRequest[key];
|
|
16
14
|
});
|
|
17
|
-
|
|
18
15
|
class RequestService extends _xRequest.XRequest {
|
|
19
16
|
constructor(...args) {
|
|
20
17
|
super(...args);
|
|
21
18
|
this.serviceName = 'request';
|
|
22
19
|
}
|
|
23
|
-
|
|
24
20
|
}
|
|
25
|
-
|
|
26
21
|
exports.RequestService = RequestService;
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
-
|
|
5
4
|
exports.__esModule = true;
|
|
6
5
|
exports.SensitiveWordsService = void 0;
|
|
7
|
-
|
|
8
6
|
var _mintFilter = _interopRequireDefault(require("mint-filter"));
|
|
9
|
-
|
|
10
7
|
var _vtils = require("vtils");
|
|
11
|
-
|
|
12
8
|
/**
|
|
13
9
|
* 敏感词服务。
|
|
14
10
|
*/
|
|
@@ -18,30 +14,32 @@ class SensitiveWordsService {
|
|
|
18
14
|
this.serviceName = 'sensitiveWords';
|
|
19
15
|
this.mint = void 0;
|
|
20
16
|
}
|
|
17
|
+
|
|
21
18
|
/**
|
|
22
19
|
* 文本转换。
|
|
23
20
|
*/
|
|
24
|
-
|
|
25
|
-
|
|
26
21
|
transform(text) {
|
|
27
|
-
return (
|
|
28
|
-
|
|
29
|
-
(0, _vtils.
|
|
30
|
-
|
|
31
|
-
.
|
|
22
|
+
return (
|
|
23
|
+
// 移除空白字符
|
|
24
|
+
(0, _vtils.removeBlankChars)(
|
|
25
|
+
// 移除非单词字符
|
|
26
|
+
(0, _vtils.removeNonWordChars)(
|
|
27
|
+
// 全角转半角
|
|
28
|
+
(0, _vtils.toHalfWidthString)(text)))
|
|
29
|
+
// 转小写
|
|
30
|
+
.toLowerCase()
|
|
31
|
+
// 叠词归一
|
|
32
32
|
.replace(/(.)\1+/g, '$1')
|
|
33
33
|
);
|
|
34
34
|
}
|
|
35
|
+
|
|
35
36
|
/**
|
|
36
37
|
* 处理文本,敏感词将被替换为 * 号。
|
|
37
38
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
39
|
async process(text) {
|
|
41
40
|
if (!this.mint) {
|
|
42
41
|
this.mint = new _mintFilter.default(this.options.words);
|
|
43
42
|
}
|
|
44
|
-
|
|
45
43
|
const res = await this.mint.filter(this.transform(text), {
|
|
46
44
|
every: true,
|
|
47
45
|
replace: true,
|
|
@@ -49,16 +47,14 @@ class SensitiveWordsService {
|
|
|
49
47
|
});
|
|
50
48
|
return res.text;
|
|
51
49
|
}
|
|
50
|
+
|
|
52
51
|
/**
|
|
53
52
|
* 验证文本是否包含敏感词。
|
|
54
53
|
*/
|
|
55
|
-
|
|
56
|
-
|
|
57
54
|
async validate(text, every) {
|
|
58
55
|
if (!this.mint) {
|
|
59
56
|
this.mint = new _mintFilter.default(this.options.words);
|
|
60
57
|
}
|
|
61
|
-
|
|
62
58
|
const res = await this.mint.filter(this.transform(text), {
|
|
63
59
|
replace: false,
|
|
64
60
|
every: !!every,
|
|
@@ -69,7 +65,5 @@ class SensitiveWordsService {
|
|
|
69
65
|
words: res.words
|
|
70
66
|
};
|
|
71
67
|
}
|
|
72
|
-
|
|
73
68
|
}
|
|
74
|
-
|
|
75
69
|
exports.SensitiveWordsService = SensitiveWordsService;
|
package/lib/_cjs/x.js
CHANGED
|
@@ -1,24 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
-
|
|
5
4
|
exports.__esModule = true;
|
|
6
5
|
exports.x = void 0;
|
|
7
|
-
|
|
8
6
|
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
9
|
-
|
|
10
7
|
var _os = _interopRequireDefault(require("os"));
|
|
11
|
-
|
|
12
8
|
var _path = _interopRequireDefault(require("path"));
|
|
13
|
-
|
|
14
9
|
var _dispose = require("./services/dispose");
|
|
15
|
-
|
|
16
10
|
var _emoji = require("./services/emoji");
|
|
17
|
-
|
|
18
11
|
var _log = require("./services/log");
|
|
19
|
-
|
|
20
12
|
var _request = require("./services/request");
|
|
21
|
-
|
|
22
13
|
const env = JSON.parse(process.env.X_SERVER_ENVS || '{}');
|
|
23
14
|
const x = {
|
|
24
15
|
appId: env.APP_ID,
|
|
@@ -32,9 +23,7 @@ const x = {
|
|
|
32
23
|
}
|
|
33
24
|
};
|
|
34
25
|
exports.x = x;
|
|
35
|
-
|
|
36
26
|
_fsExtra.default.ensureDirSync(x.dataDir);
|
|
37
|
-
|
|
38
27
|
x.register(new _dispose.DisposeService({
|
|
39
28
|
disposeOnExit: true
|
|
40
29
|
}), new _log.LogService(), new _emoji.EmojiService(), new _request.RequestService());
|
package/lib/cli/api_generator.js
CHANGED
|
@@ -9,17 +9,15 @@ export class ApiGenerator {
|
|
|
9
9
|
constructor() {
|
|
10
10
|
this.debug = createDebug('api');
|
|
11
11
|
this.cwd = process.cwd();
|
|
12
|
+
// cwd = '/Users/admin/Documents/jfWorks/x-server-test'
|
|
12
13
|
this.project = void 0;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
15
|
getTypeBySymbol(symbol) {
|
|
16
16
|
return symbol.getTypeAtLocation(symbol.getDeclarations()[0] || symbol.getValueDeclarationOrThrow());
|
|
17
17
|
}
|
|
18
|
-
|
|
19
18
|
getComment(declaration) {
|
|
20
19
|
var _declaration$getLeadi;
|
|
21
|
-
|
|
22
|
-
const text = ((declaration == null ? void 0 : (_declaration$getLeadi = declaration.getLeadingCommentRanges()[0]) == null ? void 0 : _declaration$getLeadi.getText()) || '').trim();
|
|
20
|
+
const text = ((declaration == null || (_declaration$getLeadi = declaration.getLeadingCommentRanges()[0]) == null ? void 0 : _declaration$getLeadi.getText()) || '').trim();
|
|
23
21
|
const comment = parseComment.parse(text)[0];
|
|
24
22
|
const description = (comment == null ? void 0 : comment.description) || '';
|
|
25
23
|
const tags = new Map();
|
|
@@ -32,16 +30,12 @@ export class ApiGenerator {
|
|
|
32
30
|
tags: tags
|
|
33
31
|
};
|
|
34
32
|
}
|
|
35
|
-
|
|
36
33
|
getCommentBySymbol(symbol) {
|
|
37
34
|
var _this$getComment;
|
|
38
|
-
|
|
39
35
|
return ((_this$getComment = this.getComment(symbol.getDeclarations()[0])) == null ? void 0 : _this$getComment.description) || '';
|
|
40
36
|
}
|
|
41
|
-
|
|
42
37
|
typeToApiData(type, _symbol) {
|
|
43
38
|
var _type$getSymbol, _type$getSymbol2, _type$getSymbol3;
|
|
44
|
-
|
|
45
39
|
// ws
|
|
46
40
|
if (((_type$getSymbol = type.getSymbol()) == null ? void 0 : _type$getSymbol.getName()) === 'SocketStream') {
|
|
47
41
|
return {
|
|
@@ -52,12 +46,11 @@ export class ApiGenerator {
|
|
|
52
46
|
children: [],
|
|
53
47
|
enum: []
|
|
54
48
|
};
|
|
55
|
-
}
|
|
56
|
-
|
|
49
|
+
}
|
|
57
50
|
|
|
51
|
+
// XFile
|
|
58
52
|
if (((_type$getSymbol2 = type.getSymbol()) == null ? void 0 : _type$getSymbol2.getName()) === 'MultipartFile') {
|
|
59
53
|
const symbol = _symbol || type.getSymbol();
|
|
60
|
-
|
|
61
54
|
return {
|
|
62
55
|
name: 'file',
|
|
63
56
|
desc: symbol && this.getCommentBySymbol(symbol) || '',
|
|
@@ -67,25 +60,22 @@ export class ApiGenerator {
|
|
|
67
60
|
enum: []
|
|
68
61
|
};
|
|
69
62
|
}
|
|
70
|
-
|
|
71
63
|
let isRequired = true;
|
|
72
64
|
let isUnion = type.isUnion();
|
|
73
65
|
const unionTypes = isUnion ? type.getUnionTypes().filter(item => !item.isBooleanLiteral() && !item.isNull() && !item.isUndefined()) : [];
|
|
74
66
|
isUnion = !!unionTypes.length;
|
|
75
|
-
|
|
76
67
|
if (isUnion) {
|
|
77
68
|
if (unionTypes.length === 1 && !unionTypes[0].isLiteral()) {
|
|
78
69
|
isUnion = false;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
70
|
+
}
|
|
71
|
+
// 兼容 prisma 生成的类型用 null 表示可选
|
|
72
|
+
isRequired = unionTypes.length === type.getUnionTypes().length;
|
|
73
|
+
// 必须用 getBaseTypeOfLiteralType 获取枚举字面量的原始类型
|
|
84
74
|
type = unionTypes[0].getBaseTypeOfLiteralType();
|
|
85
75
|
}
|
|
86
|
-
|
|
87
76
|
const isEnum = type.isEnum();
|
|
88
|
-
const enumData = isEnum ?
|
|
77
|
+
const enumData = isEnum ?
|
|
78
|
+
// @ts-ignore
|
|
89
79
|
type.compilerType.types.reduce((res, item) => {
|
|
90
80
|
res[item.getSymbol().getName()] = item.value;
|
|
91
81
|
return res;
|
|
@@ -98,11 +88,10 @@ export class ApiGenerator {
|
|
|
98
88
|
const isString = isEnum ? typeof enumValues[0] === 'string' : type.isString() || ['Date'].includes(((_type$getSymbol3 = type.getSymbol()) == null ? void 0 : _type$getSymbol3.getName()) || '');
|
|
99
89
|
const isNumber = isEnum ? typeof enumValues[0] === 'number' : type.isNumber();
|
|
100
90
|
const isBoolean = type.isBoolean() || type.isUnion() && type.getUnionTypes().some(item => item.isBooleanLiteral()) && type.getUnionTypes().every(item => item.isBooleanLiteral() || item.isNull() || item.isUndefined());
|
|
101
|
-
const isObject = !isArray && !isString && !isNumber && !isBoolean && type.isObject() ||
|
|
91
|
+
const isObject = !isArray && !isString && !isNumber && !isBoolean && type.isObject() ||
|
|
92
|
+
// 将交集类型视为对象
|
|
102
93
|
isIntersection;
|
|
103
|
-
|
|
104
94
|
const symbol = _symbol || type.getSymbol();
|
|
105
|
-
|
|
106
95
|
const apiName = (symbol == null ? void 0 : symbol.getName()) || '__type';
|
|
107
96
|
const apiDesc = [symbol && this.getCommentBySymbol(symbol), isEnum && `枚举:${enumKeys.map((key, index) => `${key}->${enumValues[index]}`).join('; ')}`].filter(Boolean).join('\n');
|
|
108
97
|
const apiEnum = isUnion ? unionTypes.map(t => t.getLiteralValue()) : isEnum ? enumValues : [];
|
|
@@ -113,20 +102,21 @@ export class ApiGenerator {
|
|
|
113
102
|
const compilerFactory = context.compilerFactory;
|
|
114
103
|
const rawChecker = type.compilerType.checker;
|
|
115
104
|
let symbols = [];
|
|
116
|
-
|
|
117
105
|
if (intersectionTypes) {
|
|
118
106
|
// https://github.com/microsoft/TypeScript/issues/38184
|
|
119
|
-
symbols = rawChecker.getAllPossiblePropertiesOfTypes(intersectionTypes.map(item => item.compilerType))
|
|
107
|
+
symbols = rawChecker.getAllPossiblePropertiesOfTypes(intersectionTypes.map(item => item.compilerType))
|
|
108
|
+
// https://github.com/dsherret/ts-morph/blob/a7072fcf6f9babb784b40f0326c80dea4563a4aa/packages/ts-morph/src/compiler/types/Type.ts#L296
|
|
120
109
|
.map(symbol => compilerFactory.getSymbol(symbol));
|
|
121
110
|
} else {
|
|
122
111
|
// symbols = type.getApparentProperties()
|
|
123
112
|
// https://github.com/microsoft/TypeScript/issues/38184
|
|
124
|
-
symbols = rawChecker.getAllPossiblePropertiesOfTypes([type.compilerType])
|
|
113
|
+
symbols = rawChecker.getAllPossiblePropertiesOfTypes([type.compilerType])
|
|
114
|
+
// https://github.com/dsherret/ts-morph/blob/a7072fcf6f9babb784b40f0326c80dea4563a4aa/packages/ts-morph/src/compiler/types/Type.ts#L296
|
|
125
115
|
.map(symbol => compilerFactory.getSymbol(symbol));
|
|
126
116
|
}
|
|
127
|
-
|
|
128
117
|
return symbols.map(symbol => {
|
|
129
|
-
return this.typeToApiData(!symbol.compilerSymbol.declarations ?
|
|
118
|
+
return this.typeToApiData(!symbol.compilerSymbol.declarations ?
|
|
119
|
+
// 对于复杂对象,没有定义的,通过 type 直接获取(在前面通过 getText 预处理得到)
|
|
130
120
|
compilerFactory.getType(symbol.compilerSymbol.type) : this.getTypeBySymbol(symbol), symbol);
|
|
131
121
|
});
|
|
132
122
|
}) : [];
|
|
@@ -139,10 +129,8 @@ export class ApiGenerator {
|
|
|
139
129
|
children: apiChildren
|
|
140
130
|
};
|
|
141
131
|
}
|
|
142
|
-
|
|
143
132
|
apiDataToJsonSchema(apiData, jsonSchema = {}) {
|
|
144
133
|
jsonSchema.description = apiData.desc;
|
|
145
|
-
|
|
146
134
|
if (apiData.type === 'object') {
|
|
147
135
|
jsonSchema.type = 'object';
|
|
148
136
|
jsonSchema.properties = apiData.children.reduce((res, item) => {
|
|
@@ -156,18 +144,14 @@ export class ApiGenerator {
|
|
|
156
144
|
jsonSchema.items = apiData.children.map(item => this.apiDataToJsonSchema(item))[0];
|
|
157
145
|
} else {
|
|
158
146
|
jsonSchema.type = apiData.type;
|
|
159
|
-
|
|
160
147
|
if (apiData.enum.length) {
|
|
161
148
|
jsonSchema.enum = apiData.enum;
|
|
162
149
|
}
|
|
163
150
|
}
|
|
164
|
-
|
|
165
151
|
return jsonSchema;
|
|
166
152
|
}
|
|
167
|
-
|
|
168
153
|
genYApiData(handles) {
|
|
169
154
|
const data = {};
|
|
170
|
-
|
|
171
155
|
for (const handle of handles) {
|
|
172
156
|
data[handle.category] = data[handle.category] || [];
|
|
173
157
|
data[handle.category].push(handle.handlerMethod === 'GET' ? {
|
|
@@ -221,14 +205,12 @@ export class ApiGenerator {
|
|
|
221
205
|
res_body: JSON.stringify(handle.responseDataJsonSchema)
|
|
222
206
|
});
|
|
223
207
|
}
|
|
224
|
-
|
|
225
208
|
return Object.keys(data).map(cat => ({
|
|
226
209
|
name: cat,
|
|
227
210
|
desc: cat,
|
|
228
211
|
list: data[cat]
|
|
229
212
|
}));
|
|
230
213
|
}
|
|
231
|
-
|
|
232
214
|
async generate() {
|
|
233
215
|
this.debug('启动项目...');
|
|
234
216
|
this.project = new ts.Project({
|
|
@@ -240,11 +222,9 @@ export class ApiGenerator {
|
|
|
240
222
|
const handlerGroup = sourceFile.getExportSymbols();
|
|
241
223
|
const handles = [];
|
|
242
224
|
this.debug('生成API文档...');
|
|
243
|
-
|
|
244
225
|
for (const handlerList of handlerGroup) {
|
|
245
226
|
const handlerListSourceFile = this.getTypeBySymbol(handlerList).getProperties()[0].getDeclarations()[0].getSourceFile();
|
|
246
227
|
const basePath = `/${handlerListSourceFile.getFilePath().replace('.ts', '').split('/src/handlers/')[1].replace(/(^|\/)index$/, '/').split('/').map(v => snakeCase(v)).join('/')}/`.replace(/\/{2,}/g, '/');
|
|
247
|
-
|
|
248
228
|
for (const handler of handlerListSourceFile.getVariableStatements().filter(item => item.isExported())) {
|
|
249
229
|
// 重要:这一步必须,先调一遍 getText 获取看到的对象,后续对于复杂定义才不会报错
|
|
250
230
|
handler.getDeclarations().forEach(exp => {
|
|
@@ -255,12 +235,10 @@ export class ApiGenerator {
|
|
|
255
235
|
this.debug('生成接口: %s ...', handlerPath);
|
|
256
236
|
const [requestType, responseType, methodType] = handlerExp.getType().getTypeArguments();
|
|
257
237
|
const handlerComment = this.getComment(handlerExp.getParent().getParent());
|
|
258
|
-
|
|
259
238
|
if (handlerComment.tags.has('private')) {
|
|
260
239
|
this.debug('跳过生成接口: %s', `${handlerPath}`);
|
|
261
240
|
continue;
|
|
262
241
|
}
|
|
263
|
-
|
|
264
242
|
const handlerCategory = pascalCase(basePath) || 'Index';
|
|
265
243
|
const handlerName = handlerComment.description || handlerPath;
|
|
266
244
|
const handlerMethod = methodType.getLiteralValueOrThrow();
|
|
@@ -282,7 +260,6 @@ export class ApiGenerator {
|
|
|
282
260
|
});
|
|
283
261
|
}
|
|
284
262
|
}
|
|
285
|
-
|
|
286
263
|
this.debug('写入文件...');
|
|
287
264
|
await Promise.all([fs.outputJSON(path.join(this.cwd, 'temp/api.json'), handles, {
|
|
288
265
|
spaces: 2
|
|
@@ -290,5 +267,6 @@ export class ApiGenerator {
|
|
|
290
267
|
spaces: 2
|
|
291
268
|
})]);
|
|
292
269
|
}
|
|
270
|
+
}
|
|
293
271
|
|
|
294
|
-
|
|
272
|
+
// new ApiGenerator().generate()
|