@jayfong/x-server 2.119.0 → 3.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.
Files changed (290) hide show
  1. package/lib/_virtual/_rolldown/runtime.mjs +4 -0
  2. package/lib/cli/api_generator.d.mts +74 -0
  3. package/lib/cli/api_generator.mjs +310 -0
  4. package/lib/cli/build_util.d.mts +17 -0
  5. package/lib/cli/build_util.mjs +156 -0
  6. package/lib/cli/cli.d.mts +1 -0
  7. package/lib/cli/cli.mjs +355 -0
  8. package/lib/cli/css_register.d.mts +1 -0
  9. package/lib/cli/css_register.mjs +7 -0
  10. package/lib/cli/deploy_util.d.mts +23 -0
  11. package/lib/cli/deploy_util.mjs +70 -0
  12. package/lib/cli/dev_util.d.mts +7 -0
  13. package/lib/cli/dev_util.mjs +25 -0
  14. package/lib/cli/env_util.d.mts +45 -0
  15. package/lib/cli/env_util.mjs +207 -0
  16. package/lib/cli/esbuild_register.d.mts +1 -0
  17. package/lib/cli/esbuild_register.mjs +7 -0
  18. package/lib/cli/template_util.d.mts +18 -0
  19. package/lib/cli/template_util.mjs +85 -0
  20. package/lib/cli/templates/crons.ts +1 -1
  21. package/lib/cli/templates/handlers.ts +1 -1
  22. package/lib/cli/templates/hooks.ts +1 -1
  23. package/lib/cli/templates/models.ts +7 -7
  24. package/lib/cli/templates/package.json +11 -1
  25. package/lib/cli/templates/routes.ts +2 -1
  26. package/lib/core/ctx_storage.d.mts +3 -0
  27. package/lib/core/ctx_storage.mjs +4 -0
  28. package/lib/core/define_bus.d.mts +37 -0
  29. package/lib/core/define_bus.mjs +12 -0
  30. package/lib/core/{define_cron.d.ts → define_cron.d.mts} +2 -2
  31. package/lib/core/define_cron.mjs +11 -0
  32. package/lib/core/{define_handler.d.ts → define_handler.d.mts} +19 -19
  33. package/lib/core/define_handler.mjs +44 -0
  34. package/lib/core/define_hook.d.mts +2 -0
  35. package/lib/core/define_hook.mjs +6 -0
  36. package/lib/core/define_server.d.mts +3 -0
  37. package/lib/core/define_server.mjs +8 -0
  38. package/lib/core/{define_task.d.ts → define_task.d.mts} +2 -2
  39. package/lib/core/define_task.mjs +102 -0
  40. package/lib/core/get_handler_url.d.mts +2 -0
  41. package/lib/core/get_handler_url.mjs +7 -0
  42. package/lib/core/handler.d.mts +16 -0
  43. package/lib/core/handler.mjs +132 -0
  44. package/lib/core/http_error.d.mts +2 -0
  45. package/lib/core/http_error.mjs +1 -0
  46. package/lib/core/http_header.d.mts +856 -0
  47. package/lib/core/http_header.mjs +860 -0
  48. package/lib/core/http_method.d.mts +3 -0
  49. package/lib/core/http_method.mjs +10 -0
  50. package/lib/core/http_redirect.d.mts +5 -0
  51. package/lib/core/http_redirect.mjs +10 -0
  52. package/lib/core/server.d.mts +20 -0
  53. package/lib/core/server.mjs +186 -0
  54. package/lib/core/types.d.mts +256 -0
  55. package/lib/exports.d.mts +46 -0
  56. package/lib/exports.mjs +46 -0
  57. package/lib/index.d.mts +48 -0
  58. package/lib/index.mjs +45 -0
  59. package/lib/plugins/base.d.mts +4 -0
  60. package/lib/plugins/compress.d.mts +12 -0
  61. package/lib/plugins/compress.mjs +15 -0
  62. package/lib/plugins/cookie.d.mts +12 -0
  63. package/lib/plugins/cookie.mjs +15 -0
  64. package/lib/plugins/cors.d.mts +22 -0
  65. package/lib/plugins/cors.mjs +34 -0
  66. package/lib/plugins/file_parser.d.mts +15 -0
  67. package/lib/plugins/file_parser.mjs +24 -0
  68. package/lib/plugins/form_body_parser.d.mts +12 -0
  69. package/lib/plugins/form_body_parser.mjs +15 -0
  70. package/lib/plugins/ws_parser.d.mts +12 -0
  71. package/lib/plugins/ws_parser.mjs +15 -0
  72. package/lib/plugins/xml_parser.d.mts +19 -0
  73. package/lib/plugins/xml_parser.mjs +40 -0
  74. package/lib/services/ai.d.mts +31 -0
  75. package/lib/services/ai.mjs +44 -0
  76. package/lib/services/base.d.mts +4 -0
  77. package/lib/services/base.mjs +1 -0
  78. package/lib/services/cache.d.mts +165 -0
  79. package/lib/services/cache.mjs +323 -0
  80. package/lib/services/captcha.d.mts +65 -0
  81. package/lib/services/captcha.mjs +61 -0
  82. package/lib/services/{crypto.js → crypto.d.mts} +19 -78
  83. package/lib/services/crypto.mjs +141 -0
  84. package/lib/services/db_value.d.mts +60 -0
  85. package/lib/services/db_value.mjs +64 -0
  86. package/lib/services/dingtalk.d.mts +39 -0
  87. package/lib/services/dingtalk.mjs +44 -0
  88. package/lib/services/dispose.d.mts +17 -0
  89. package/lib/services/dispose.mjs +18 -0
  90. package/lib/services/emoji.d.mts +10 -0
  91. package/lib/services/emoji.mjs +2025 -0
  92. package/lib/services/file_store.d.mts +49 -0
  93. package/lib/services/file_store.mjs +58 -0
  94. package/lib/services/html.d.mts +11 -0
  95. package/lib/services/html.mjs +12 -0
  96. package/lib/services/jwt.d.mts +33 -0
  97. package/lib/services/jwt.mjs +42 -0
  98. package/lib/services/log.d.mts +37 -0
  99. package/lib/services/log.mjs +99 -0
  100. package/lib/services/mail.d.mts +22 -0
  101. package/lib/services/mail.mjs +28 -0
  102. package/lib/services/pay.d.mts +123 -0
  103. package/lib/services/pay.mjs +157 -0
  104. package/lib/services/random.d.mts +27 -0
  105. package/lib/services/random.mjs +42 -0
  106. package/lib/services/rate_limit.d.mts +37 -0
  107. package/lib/services/rate_limit.mjs +40 -0
  108. package/lib/services/redis.d.mts +11 -0
  109. package/lib/services/redis.mjs +6 -0
  110. package/lib/services/sensitive_words.d.mts +29 -0
  111. package/lib/services/sensitive_words.mjs +37 -0
  112. package/lib/services/sms.d.mts +40 -0
  113. package/lib/services/sms.mjs +30238 -0
  114. package/lib/types/dto.d.mts +30 -0
  115. package/lib/types/dto.mjs +1 -0
  116. package/lib/x.d.mts +11 -0
  117. package/lib/x.mjs +21 -0
  118. package/lib/x_init.d.mts +1 -0
  119. package/lib/x_init.mjs +10 -0
  120. package/package.json +71 -16
  121. package/lib/_cjs/cli/api_generator.js +0 -458
  122. package/lib/_cjs/cli/build_util.js +0 -243
  123. package/lib/_cjs/cli/cli.js +0 -378
  124. package/lib/_cjs/cli/css_register.js +0 -7
  125. package/lib/_cjs/cli/deploy_util.js +0 -76
  126. package/lib/_cjs/cli/dev_util.js +0 -26
  127. package/lib/_cjs/cli/env_util.js +0 -252
  128. package/lib/_cjs/cli/esbuild_register.js +0 -7
  129. package/lib/_cjs/cli/template_util.js +0 -101
  130. package/lib/_cjs/cli/templates/crons.ts +0 -2
  131. package/lib/_cjs/cli/templates/handlers.ts +0 -3
  132. package/lib/_cjs/cli/templates/hooks.ts +0 -2
  133. package/lib/_cjs/cli/templates/models.ts +0 -123
  134. package/lib/_cjs/cli/templates/package.json +0 -3
  135. package/lib/_cjs/cli/templates/routes.ts +0 -68
  136. package/lib/_cjs/core/ctx_storage.js +0 -6
  137. package/lib/_cjs/core/define_bus.js +0 -31
  138. package/lib/_cjs/core/define_cron.js +0 -13
  139. package/lib/_cjs/core/define_handler.js +0 -56
  140. package/lib/_cjs/core/define_hook.js +0 -8
  141. package/lib/_cjs/core/define_server.js +0 -10
  142. package/lib/_cjs/core/define_task.js +0 -113
  143. package/lib/_cjs/core/get_handler_url.js +0 -11
  144. package/lib/_cjs/core/handler.js +0 -216
  145. package/lib/_cjs/core/http_error.js +0 -6
  146. package/lib/_cjs/core/http_header.js +0 -142
  147. package/lib/_cjs/core/http_method.js +0 -12
  148. package/lib/_cjs/core/http_redirect.js +0 -11
  149. package/lib/_cjs/core/server.js +0 -219
  150. package/lib/_cjs/core/types.js +0 -8
  151. package/lib/_cjs/exports.js +0 -273
  152. package/lib/_cjs/index.js +0 -15
  153. package/lib/_cjs/plugins/base.js +0 -3
  154. package/lib/_cjs/plugins/compress.js +0 -18
  155. package/lib/_cjs/plugins/cookie.js +0 -18
  156. package/lib/_cjs/plugins/cors.js +0 -38
  157. package/lib/_cjs/plugins/file_parser.js +0 -28
  158. package/lib/_cjs/plugins/form_body_parser.js +0 -18
  159. package/lib/_cjs/plugins/ws_parser.js +0 -18
  160. package/lib/_cjs/plugins/xml_parser.js +0 -48
  161. package/lib/_cjs/services/ai.js +0 -48
  162. package/lib/_cjs/services/base.js +0 -3
  163. package/lib/_cjs/services/cache.js +0 -400
  164. package/lib/_cjs/services/captcha.js +0 -78
  165. package/lib/_cjs/services/crypto.js +0 -175
  166. package/lib/_cjs/services/db_value.js +0 -77
  167. package/lib/_cjs/services/dingtalk.js +0 -51
  168. package/lib/_cjs/services/dispose.js +0 -23
  169. package/lib/_cjs/services/emoji.js +0 -2034
  170. package/lib/_cjs/services/file_store.js +0 -67
  171. package/lib/_cjs/services/html.js +0 -17
  172. package/lib/_cjs/services/jwt.js +0 -65
  173. package/lib/_cjs/services/log.js +0 -108
  174. package/lib/_cjs/services/mail.js +0 -31
  175. package/lib/_cjs/services/pay.js +0 -191
  176. package/lib/_cjs/services/random.js +0 -51
  177. package/lib/_cjs/services/rate_limit.js +0 -54
  178. package/lib/_cjs/services/redis.js +0 -12
  179. package/lib/_cjs/services/sensitive_words.js +0 -61
  180. package/lib/_cjs/services/sms.js +0 -84
  181. package/lib/_cjs/types/dto.js +0 -3
  182. package/lib/_cjs/x.js +0 -35
  183. package/lib/cli/api_generator.d.ts +0 -74
  184. package/lib/cli/api_generator.js +0 -452
  185. package/lib/cli/build_util.d.ts +0 -17
  186. package/lib/cli/build_util.js +0 -236
  187. package/lib/cli/cli.d.ts +0 -2
  188. package/lib/cli/cli.js +0 -374
  189. package/lib/cli/css_register.js +0 -5
  190. package/lib/cli/deploy_util.d.ts +0 -23
  191. package/lib/cli/deploy_util.js +0 -70
  192. package/lib/cli/dev_util.d.ts +0 -8
  193. package/lib/cli/dev_util.js +0 -20
  194. package/lib/cli/env_util.d.ts +0 -45
  195. package/lib/cli/env_util.js +0 -246
  196. package/lib/cli/esbuild_register.js +0 -5
  197. package/lib/cli/template_util.d.ts +0 -18
  198. package/lib/cli/template_util.js +0 -95
  199. package/lib/core/ctx_storage.d.ts +0 -3
  200. package/lib/core/ctx_storage.js +0 -2
  201. package/lib/core/define_bus.d.ts +0 -37
  202. package/lib/core/define_bus.js +0 -27
  203. package/lib/core/define_cron.js +0 -9
  204. package/lib/core/define_handler.js +0 -48
  205. package/lib/core/define_hook.d.ts +0 -2
  206. package/lib/core/define_hook.js +0 -4
  207. package/lib/core/define_server.d.ts +0 -3
  208. package/lib/core/define_server.js +0 -6
  209. package/lib/core/define_task.js +0 -107
  210. package/lib/core/get_handler_url.d.ts +0 -2
  211. package/lib/core/get_handler_url.js +0 -7
  212. package/lib/core/handler.d.ts +0 -16
  213. package/lib/core/handler.js +0 -209
  214. package/lib/core/http_error.d.ts +0 -2
  215. package/lib/core/http_error.js +0 -2
  216. package/lib/core/http_header.d.ts +0 -856
  217. package/lib/core/http_header.js +0 -139
  218. package/lib/core/http_method.d.ts +0 -3
  219. package/lib/core/http_method.js +0 -8
  220. package/lib/core/http_redirect.d.ts +0 -5
  221. package/lib/core/http_redirect.js +0 -6
  222. package/lib/core/server.d.ts +0 -20
  223. package/lib/core/server.js +0 -213
  224. package/lib/core/types.d.ts +0 -265
  225. package/lib/core/types.js +0 -4
  226. package/lib/exports.d.ts +0 -45
  227. package/lib/exports.js +0 -47
  228. package/lib/index.d.ts +0 -2
  229. package/lib/index.js +0 -3
  230. package/lib/plugins/base.d.ts +0 -4
  231. package/lib/plugins/base.js +0 -1
  232. package/lib/plugins/compress.d.ts +0 -13
  233. package/lib/plugins/compress.js +0 -12
  234. package/lib/plugins/cookie.d.ts +0 -13
  235. package/lib/plugins/cookie.js +0 -12
  236. package/lib/plugins/cors.d.ts +0 -22
  237. package/lib/plugins/cors.js +0 -32
  238. package/lib/plugins/file_parser.d.ts +0 -16
  239. package/lib/plugins/file_parser.js +0 -22
  240. package/lib/plugins/form_body_parser.d.ts +0 -13
  241. package/lib/plugins/form_body_parser.js +0 -12
  242. package/lib/plugins/ws_parser.d.ts +0 -13
  243. package/lib/plugins/ws_parser.js +0 -12
  244. package/lib/plugins/xml_parser.d.ts +0 -19
  245. package/lib/plugins/xml_parser.js +0 -43
  246. package/lib/services/ai.d.ts +0 -31
  247. package/lib/services/ai.js +0 -43
  248. package/lib/services/base.d.ts +0 -4
  249. package/lib/services/base.js +0 -1
  250. package/lib/services/cache.d.ts +0 -173
  251. package/lib/services/cache.js +0 -394
  252. package/lib/services/captcha.d.ts +0 -65
  253. package/lib/services/captcha.js +0 -72
  254. package/lib/services/crypto.d.ts +0 -110
  255. package/lib/services/db_value.d.ts +0 -60
  256. package/lib/services/db_value.js +0 -72
  257. package/lib/services/dingtalk.d.ts +0 -39
  258. package/lib/services/dingtalk.js +0 -45
  259. package/lib/services/dispose.d.ts +0 -17
  260. package/lib/services/dispose.js +0 -17
  261. package/lib/services/emoji.d.ts +0 -10
  262. package/lib/services/emoji.js +0 -2029
  263. package/lib/services/file_store.d.ts +0 -49
  264. package/lib/services/file_store.js +0 -61
  265. package/lib/services/html.d.ts +0 -11
  266. package/lib/services/html.js +0 -12
  267. package/lib/services/jwt.d.ts +0 -34
  268. package/lib/services/jwt.js +0 -59
  269. package/lib/services/log.d.ts +0 -37
  270. package/lib/services/log.js +0 -102
  271. package/lib/services/mail.d.ts +0 -23
  272. package/lib/services/mail.js +0 -25
  273. package/lib/services/pay.d.ts +0 -123
  274. package/lib/services/pay.js +0 -185
  275. package/lib/services/random.d.ts +0 -27
  276. package/lib/services/random.js +0 -45
  277. package/lib/services/rate_limit.d.ts +0 -37
  278. package/lib/services/rate_limit.js +0 -49
  279. package/lib/services/redis.d.ts +0 -12
  280. package/lib/services/redis.js +0 -7
  281. package/lib/services/sensitive_words.d.ts +0 -29
  282. package/lib/services/sensitive_words.js +0 -56
  283. package/lib/services/sms.d.ts +0 -40
  284. package/lib/services/sms.js +0 -78
  285. package/lib/types/dto.d.ts +0 -86
  286. package/lib/types/dto.js +0 -1
  287. package/lib/x.d.ts +0 -17
  288. package/lib/x.js +0 -30
  289. /package/lib/{cli/css_register.d.ts → core/types.mjs} +0 -0
  290. /package/lib/{cli/esbuild_register.d.ts → plugins/base.mjs} +0 -0
@@ -1,458 +0,0 @@
1
- "use strict";
2
-
3
- var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
4
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
5
- exports.__esModule = true;
6
- exports.ApiGenerator = void 0;
7
- var _nodePath = _interopRequireDefault(require("node:path"));
8
- var _debug = _interopRequireDefault(require("debug"));
9
- var _fsExtra = _interopRequireDefault(require("fs-extra"));
10
- var _tsMorph = _interopRequireWildcard(require("ts-morph"));
11
- var _vtils = require("vtils");
12
- var _http_method = require("../core/http_method");
13
- /** 注释 */
14
-
15
- /** 接口传输数据 */
16
-
17
- /** 接口数据 */
18
-
19
- class ApiGenerator {
20
- constructor(options = {}) {
21
- this.options = options;
22
- this.cwd = void 0;
23
- this.debug = (0, _debug.default)('api');
24
- // 几种情况:
25
- // /index.ts
26
- // /user/index.ts
27
- // /post.ts
28
- // /user/list.ts
29
- // category 必须从 handlers 目录结构中推导,后续会直接拼接到 URL 前缀
30
- this.categoryUrlRe = /^.+\/src\/handlers\/(?:index\.ts|(.*)\/index\.ts|(.*)\.ts)$/;
31
- this.checker = void 0;
32
- this.cwd = this.options.cwd || process.cwd();
33
- }
34
- async start() {
35
- this.debug('启动项目...');
36
- const tsConfigPath = _nodePath.default.join(this.cwd, 'tsconfig.json');
37
- const handlersPath = _nodePath.default.join(this.cwd, 'node_modules/.x/handlers.ts');
38
- const entryFile = _nodePath.default.join(this.cwd, 'src/generated/handlers.ts');
39
-
40
- // 仅使用 ts-morph 初始化项目,并把运行时生成的 handlers 聚合文件注入到 Program 中
41
- const moProject = new _tsMorph.default.Project({
42
- tsConfigFilePath: tsConfigPath
43
- });
44
- moProject.createSourceFile(entryFile, await _fsExtra.default.readFile(handlersPath, 'utf-8'));
45
- const program = moProject.getProgram().compilerObject;
46
- const checker = program.getTypeChecker();
47
- this.checker = checker;
48
- const entrySourceFile = program.getSourceFile(entryFile);
49
- // handlers.ts 的每个 export 对应一个分类(如 user、post)
50
- const moduleSymbol = checker.getSymbolAtLocation(entrySourceFile);
51
- const categorySymbols = checker.getExportsOfModule(moduleSymbol);
52
- const apiData = [];
53
- for (const categorySymbol of categorySymbols) {
54
- // 分类的类型:形如 { list: defineHandler<...>, detail: defineHandler<...> }
55
- const categoryType = checker.getTypeOfSymbol(categorySymbol);
56
-
57
- // 处理器列表
58
- const handlerSymbols = categoryType.getProperties();
59
-
60
- // 分类源文件
61
- const categorySourceFile = handlerSymbols[0].getDeclarations()[0].getSourceFile();
62
-
63
- // 分类源文件路径
64
- const categorySourceFilePath = categorySourceFile.fileName;
65
-
66
- // 忽略仅开发时生效的路由
67
- if (/@dev[/.]/.test(categorySourceFilePath)) continue;
68
-
69
- // 支持 include, exclude
70
- if (this.options.include?.length) {
71
- if (this.options.include.every(item => !categorySourceFilePath.includes(item))) continue;
72
- }
73
- if (this.options.exclude?.length) {
74
- if (this.options.exclude.some(item => categorySourceFilePath.includes(item))) continue;
75
- }
76
-
77
- // 分类 URL
78
- const categoryUrlMatch = categorySourceFilePath.match(this.categoryUrlRe);
79
- let categoryUrl = categoryUrlMatch[1] ?? categoryUrlMatch[2] ?? '';
80
- categoryUrl = categoryUrl === '' ? '/' : `/${categoryUrl}/`;
81
- for (const handlerSymbol of handlerSymbols) {
82
- // 处理器路径
83
- let handlerPath = [handlerSymbol.getName()];
84
- const handlerNode = handlerSymbol.getDeclarations()[0];
85
-
86
- // 支持自定义 requestPath,仅识别字符串字面量或字符串数组字面量
87
- // 这里不会执行表达式(例如变量、模板字符串、函数调用)
88
- if (
89
- // const xx = defineHandler
90
- _tsMorph.ts.isVariableDeclaration(handlerNode) && handlerNode.initializer &&
91
- // defineHandler()
92
- _tsMorph.ts.isCallExpression(handlerNode.initializer) &&
93
- // defineHandler({})
94
- _tsMorph.ts.isObjectLiteralExpression(handlerNode.initializer.arguments[0])) {
95
- const props = handlerNode.initializer.arguments[0].properties;
96
- const requestPathNode = props.find(item => item.name?.getText() === 'requestPath');
97
- if (requestPathNode &&
98
- // requestPath: ''
99
- _tsMorph.ts.isPropertyAssignment(requestPathNode)) {
100
- const customHandlerPath =
101
- // requestPath: 'xx'
102
- _tsMorph.ts.isStringLiteral(requestPathNode.initializer) ? requestPathNode.initializer.text :
103
- // requestPath: ['xx']
104
- _tsMorph.ts.isArrayLiteralExpression(requestPathNode.initializer) ? requestPathNode.initializer.elements.filter(item => _tsMorph.ts.isStringLiteral(item)).map(item => item.text) : '';
105
- if (customHandlerPath.length) {
106
- handlerPath = (0, _vtils.castArray)(customHandlerPath);
107
- }
108
- }
109
- }
110
-
111
- // 处理器 URL
112
- const handlerUrl = handlerPath.map(path => `${categoryUrl}${path}`);
113
-
114
- // 处理器注释
115
- const handlerComment = this.getComment(handlerSymbol);
116
- if (handlerComment.tags.has('private')) {
117
- this.debug('跳过生成接口: %s', `${handlerUrl}`);
118
- continue;
119
- }
120
- this.debug('生成接口: %s ...', handlerUrl);
121
- const handlerType = checker.getTypeAtLocation(handlerNode);
122
-
123
- // 约定 defineHandler 的泛型顺序固定为 <Request, Response, Method>
124
- // 若上游定义顺序变更,这里会静默解析错误
125
- const [requestType, responseType, methodType] = checker.getTypeArguments(handlerType);
126
- const handlerCategory = (0, _vtils.pascalCase)(categoryUrl) || 'Index';
127
- const handlerDescription = handlerComment.description || handlerUrl.join(', ');
128
- const handlerMethod = methodType.value;
129
- const httpMethod = _http_method.HandlerMethodToHttpMethod[handlerMethod];
130
- const requestData = this.getApiDto({
131
- type: requestType
132
- });
133
- const responseData = this.getApiDto({
134
- type: responseType
135
- });
136
- const requestDataJsonSchema = this.apiDataToJsonSchema(requestData);
137
- const responseDataJsonSchema = this.apiDataToJsonSchema(responseData);
138
-
139
- // 说明文档按“首段标题 + 空行 + 详情”拆分
140
- const handlerDescriptionDividerIndex = handlerDescription.indexOf('\n\n');
141
- const apiName = handlerDescriptionDividerIndex === -1 ? handlerDescription : handlerDescription.substring(0, handlerDescriptionDividerIndex);
142
- const apiDesc = handlerDescriptionDividerIndex === -1 ? '' : handlerDescription.substring(handlerDescriptionDividerIndex + 2);
143
- apiData.push({
144
- category: handlerCategory,
145
- name: apiName,
146
- desc: apiDesc,
147
- path: handlerUrl,
148
- handlerMethod: handlerMethod,
149
- method: httpMethod,
150
- requestData: requestData,
151
- responseData: responseData,
152
- requestDataJsonSchema: requestDataJsonSchema,
153
- responseDataJsonSchema: responseDataJsonSchema
154
- });
155
- }
156
- }
157
- this.debug('写入文件...');
158
- const prefix = this.options.name ? `${this.options.name}_` : '';
159
- await Promise.all([_fsExtra.default.outputJSON(_nodePath.default.join(this.cwd, `temp/${prefix}api.json`), apiData, {
160
- spaces: 2
161
- }), _fsExtra.default.outputJSON(_nodePath.default.join(this.cwd, `temp/${prefix}yapi.json`), this.apiDataToYApiData(apiData), {
162
- spaces: 2
163
- }), _fsExtra.default.outputJSON(_nodePath.default.join(this.cwd, `temp/${prefix}openapi31.json`), this.apiDataToOpenAPI31Data(apiData), {
164
- spaces: 2
165
- })]);
166
- }
167
-
168
- // ref: https://github.com/styleguidist/react-docgen-typescript/blob/master/src/parser.ts#L777
169
- getComment(symbol) {
170
- if (!symbol) {
171
- return {
172
- existing: false,
173
- description: '',
174
- tags: new Map()
175
- };
176
- }
177
- const description = _tsMorph.ts.displayPartsToString(symbol.getDocumentationComment(this.checker)).trim();
178
- // JSDoc tag 统一收敛到 Map,方便按 @private 这类标签做开关
179
- const tags = symbol.getJsDocTags().map(item => {
180
- return {
181
- label: item.name,
182
- value: _tsMorph.ts.displayPartsToString(item.text).trim()
183
- };
184
- });
185
- return {
186
- existing: !!description,
187
- description: description,
188
- tags: tags.reduce((res, item) => {
189
- res.set(item.label, item.value);
190
- return res;
191
- }, new Map())
192
- };
193
- }
194
- getApiDto({
195
- type,
196
- keySymbol = type.symbol || type.aliasSymbol
197
- }) {
198
- const hasTypeFlag = (flag, _type = type) => (_type.flags & flag) === flag;
199
-
200
- // valueSymbol 用于识别“实际值类型”,keySymbol 用于保留字段名和字段注释
201
- let valueSymbol = type.symbol || type.aliasSymbol;
202
- const keySymbolName = keySymbol?.getName() || '';
203
- let valueSymbolName = valueSymbol?.getName() || '';
204
- const comment = this.getComment(keySymbol);
205
- let isRequired = keySymbol ? !(keySymbol.getFlags() & _tsMorph.ts.SymbolFlags.Optional) : false;
206
- const apiName = keySymbolName || '__type';
207
-
208
- // Decimal, Prisma 生成的
209
- if (valueSymbolName === 'Decimal') {
210
- return {
211
- name: apiName,
212
- desc: comment.description,
213
- required: isRequired,
214
- type: 'number',
215
- enum: [],
216
- children: []
217
- };
218
- }
219
-
220
- // WS
221
- if (valueSymbolName === 'SocketStream') {
222
- return {
223
- name: 'ws',
224
- desc: comment.description,
225
- required: isRequired,
226
- type: 'object',
227
- enum: [],
228
- children: []
229
- };
230
- }
231
-
232
- // 文件
233
- if (valueSymbolName === 'MultipartFile') {
234
- return {
235
- name: 'file',
236
- desc: comment.description,
237
- required: isRequired,
238
- type: 'file',
239
- enum: [],
240
- children: []
241
- };
242
- }
243
-
244
- // Buffer
245
- if (valueSymbolName === 'Buffer') {
246
- return {
247
- name: 'buffer',
248
- desc: comment.description,
249
- required: isRequired,
250
- type: 'object',
251
- enum: [],
252
- children: []
253
- };
254
- }
255
-
256
- // 联合类型:布尔字面量、枚举字面量都会走到这里
257
- // 处理策略:忽略 null/undefined,用第一个成员推断基础类型,同时把所有字面量收集到 enum
258
- const rawUnionTypes = type.isUnion() && type.types || [];
259
- const unionTypes = rawUnionTypes.filter(item => !hasTypeFlag(_tsMorph.ts.TypeFlags.Null, item) && !hasTypeFlag(_tsMorph.ts.TypeFlags.Undefined, item));
260
- const isUnion = !!unionTypes.length;
261
- if (isUnion) {
262
- if (unionTypes.length !== rawUnionTypes.length) {
263
- isRequired = false;
264
- }
265
- type = unionTypes[0];
266
- valueSymbol = type.symbol || type.aliasSymbol;
267
- valueSymbolName = this.checker.getBaseTypeOfLiteralType(type).getSymbol()?.getName() || '';
268
- }
269
- const isIntersection = type.isIntersection();
270
- const intersectionTypes = isIntersection && type.types || [];
271
- const isDate = valueSymbolName === 'Date';
272
- const isRegExp = valueSymbolName === 'RegExp';
273
- const isBigIntLiteral = hasTypeFlag(_tsMorph.ts.TypeFlags.BigIntLiteral);
274
- const isBigInt = hasTypeFlag(_tsMorph.ts.TypeFlags.BigInt) || isBigIntLiteral;
275
- const isArray = valueSymbolName === 'Array' || valueSymbolName === 'ReadonlyArray';
276
- const isStringLiteral = hasTypeFlag(_tsMorph.ts.TypeFlags.StringLiteral);
277
- const isString = hasTypeFlag(_tsMorph.ts.TypeFlags.String) || isStringLiteral ||
278
- // BigInt 类型视为字符串
279
- isBigInt ||
280
- // Date 类型视为字符串
281
- isDate ||
282
- // RegExp 类型视为字符串
283
- isRegExp;
284
- const isNumberLiteral = hasTypeFlag(_tsMorph.ts.TypeFlags.NumberLiteral);
285
- const isNumber = hasTypeFlag(_tsMorph.ts.TypeFlags.Number) || isNumberLiteral;
286
- const isBoolean = hasTypeFlag(_tsMorph.ts.TypeFlags.Boolean) || hasTypeFlag(_tsMorph.ts.TypeFlags.BooleanLiteral);
287
- const isLiteral = isStringLiteral || isNumberLiteral || isBigIntLiteral;
288
-
289
- // object 兜底:只要不是数组/基础类型,且 TypeScript 视为 Object,就按对象递归
290
- const isObject = !isArray && !isString && !isNumber && !isBoolean && hasTypeFlag(_tsMorph.ts.TypeFlags.Object) ||
291
- // 交集类型视为对象
292
- isIntersection;
293
- const apiDesc = keySymbol && this.getComment(keySymbol).description || '';
294
- const apiEnum = (isUnion ? unionTypes.map(item => item.value) : isLiteral ? [type.value] : []).filter(v => v != null);
295
- const apiType = isArray ? 'array' : isString ? 'string' : isNumber ? 'number' : isBoolean ? 'boolean' : 'object';
296
- const apiRequired = isRequired;
297
- const apiChildren = isArray ? [this.getApiDto({
298
- type: this.checker.getTypeArguments(type)[0]
299
- })] : isObject ? (0, _vtils.ii)(() => {
300
- // 这里使用了 TypeChecker 的内部能力来合并交集类型字段
301
- // 若 TypeScript 内部 API 变化,这里是高风险点
302
- const childSymbols = this.checker.getAllPossiblePropertiesOfTypes(intersectionTypes.length ? intersectionTypes : [type]);
303
- return childSymbols.map(childSymbol => {
304
- const childType = this.checker.getTypeOfSymbol(childSymbol);
305
- return this.getApiDto({
306
- type: childType,
307
- keySymbol: childSymbol
308
- });
309
- });
310
- }) : [];
311
- return {
312
- name: apiName,
313
- desc: apiDesc,
314
- enum: apiEnum,
315
- type: apiType,
316
- required: apiRequired,
317
- children: apiChildren
318
- };
319
- }
320
- apiDataToJsonSchema(apiData, jsonSchema = {}) {
321
- // 递归把内部 DTO 结构映射到 JSON Schema(以 object/array/primitive 三类分支处理)
322
- jsonSchema.description = apiData.desc;
323
- if (apiData.type === 'object') {
324
- jsonSchema.type = 'object';
325
- jsonSchema.properties = apiData.children.reduce((res, item) => {
326
- res[item.name] = this.apiDataToJsonSchema(item);
327
- return res;
328
- }, {});
329
- jsonSchema.required = apiData.children.filter(item => item.required).map(item => item.name);
330
- } else if (apiData.type === 'array') {
331
- jsonSchema.type = 'array';
332
- jsonSchema.items = apiData.children.map(item => this.apiDataToJsonSchema(item))[0];
333
- } else {
334
- jsonSchema.type = apiData.type;
335
- if (apiData.enum.length) {
336
- jsonSchema.enum = apiData.enum;
337
- }
338
- }
339
- return jsonSchema;
340
- }
341
- apiDataToYApiData(handles) {
342
- const data = {};
343
- for (const handle of handles) {
344
- for (const path of handle.path) {
345
- data[handle.category] = data[handle.category] || [];
346
- data[handle.category].push(
347
- // GET -> query;FILE -> form-data;其余 -> json body
348
- // 此处是与 YApi 结构的协议转换层
349
- handle.handlerMethod === 'GET' ? {
350
- method: handle.method.toUpperCase(),
351
- title: handle.name,
352
- markdown: handle.desc,
353
- path: path,
354
- res_body_type: 'json',
355
- req_body_is_json_schema: false,
356
- res_body_is_json_schema: true,
357
- req_params: [],
358
- req_query: handle.requestData.children.map(item => ({
359
- required: item.required ? 1 : 0,
360
- name: item.name,
361
- desc: item.desc,
362
- type: 'string'
363
- })),
364
- req_headers: [],
365
- req_body_form: [],
366
- res_body: JSON.stringify(handle.responseDataJsonSchema)
367
- } : handle.handlerMethod === 'FILE' ? {
368
- method: handle.method.toUpperCase(),
369
- title: handle.name,
370
- markdown: handle.desc,
371
- path: path,
372
- req_body_type: 'form',
373
- res_body_type: 'json',
374
- req_body_is_json_schema: false,
375
- res_body_is_json_schema: true,
376
- req_params: [],
377
- req_query: [],
378
- req_headers: [],
379
- req_body_form: handle.requestData.children.map(item => ({
380
- required: item.required ? 1 : 0,
381
- name: item.name,
382
- desc: item.desc,
383
- type: item.type === 'file' ? 'file' : 'text'
384
- })),
385
- res_body: JSON.stringify(handle.responseDataJsonSchema)
386
- } : {
387
- method: handle.method.toUpperCase(),
388
- title: handle.name,
389
- markdown: handle.desc,
390
- path: path,
391
- req_body_type: 'json',
392
- res_body_type: 'json',
393
- req_body_is_json_schema: true,
394
- res_body_is_json_schema: true,
395
- req_params: [],
396
- req_query: [],
397
- req_headers: [],
398
- req_body_form: [],
399
- req_body_other: JSON.stringify(handle.requestDataJsonSchema),
400
- res_body: JSON.stringify(handle.responseDataJsonSchema)
401
- });
402
- }
403
- }
404
- return Object.keys(data).map(cat => ({
405
- name: cat,
406
- desc: cat,
407
- list: data[cat]
408
- }));
409
- }
410
- apiDataToOpenAPI31Data(handles) {
411
- const data = {
412
- openapi: '3.1.0',
413
- info: {
414
- title: `${process.env.APP_NAME}`,
415
- version: '1.0.0'
416
- },
417
- paths: {},
418
- servers: [{
419
- url: `${process.env.APP_URL}`.replace(/\/+$/, ''),
420
- description: '生产'
421
- }, {
422
- url: `http://127.0.0.1:${process.env.APP_PORT}`,
423
- description: '本地'
424
- }]
425
- };
426
- for (const handle of handles) {
427
- for (const path of handle.path) {
428
- data.paths[path] = {
429
- [handle.method.toLowerCase()]: {
430
- tags: [handle.category],
431
- summary: handle.name,
432
- description: handle.desc,
433
- // 目前统一按 application/json 输出;上传类接口未转为 multipart/form-data
434
- requestBody: {
435
- content: {
436
- 'application/json': {
437
- schema: handle.requestDataJsonSchema
438
- }
439
- }
440
- },
441
- responses: {
442
- '200': {
443
- description: 'success',
444
- content: {
445
- 'application/json': {
446
- schema: handle.responseDataJsonSchema
447
- }
448
- }
449
- }
450
- }
451
- }
452
- };
453
- }
454
- }
455
- return data;
456
- }
457
- }
458
- exports.ApiGenerator = ApiGenerator;