@jayfong/x-server 2.119.0 → 3.1.1

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