@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
@@ -0,0 +1,4 @@
1
+ import { createRequire } from "node:module";
2
+ // \0rolldown/runtime.js
3
+ var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
4
+ export { __require };
@@ -0,0 +1,75 @@
1
+ import { XHandler } from "../core/types.mjs";
2
+ import createDebug from "debug";
3
+ import { ts } from "ts-morph";
4
+ import { JSONSchema4 } from "json-schema";
5
+ import { OpenAPIV3_1 } from "openapi-types";
6
+ import { LiteralUnion } from "vtils/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
+ private resolveCategorySymbols;
49
+ start(): Promise<void>;
50
+ getComment(symbol?: ts.Symbol): Comment;
51
+ getApiDto({ type, keySymbol }: {
52
+ type: ts.Type;
53
+ keySymbol?: ts.Symbol;
54
+ }): ApiDto;
55
+ apiDataToJsonSchema(apiData: ApiDto, jsonSchema?: JSONSchema4): JSONSchema4;
56
+ apiDataToYApiData(handles: ApiData[]): {
57
+ name: string;
58
+ desc: string;
59
+ list: any;
60
+ }[];
61
+ apiDataToOpenAPI31Data(handles: ApiData[]): Omit<Omit<import("openapi-types").OpenAPIV3.Document<{}>, "paths" | "components">, "paths" | "components" | "info" | "servers" | "webhooks" | "jsonSchemaDialect"> & {
62
+ info: OpenAPIV3_1.InfoObject;
63
+ jsonSchemaDialect?: string;
64
+ servers?: OpenAPIV3_1.ServerObject[];
65
+ } & Pick<{
66
+ paths: OpenAPIV3_1.PathsObject<{}, {}>;
67
+ webhooks: Record<string, OpenAPIV3_1.PathItemObject | OpenAPIV3_1.ReferenceObject>;
68
+ components: OpenAPIV3_1.ComponentsObject;
69
+ }, "paths"> & Omit<Partial<{
70
+ paths: OpenAPIV3_1.PathsObject<{}, {}>;
71
+ webhooks: Record<string, OpenAPIV3_1.PathItemObject | OpenAPIV3_1.ReferenceObject>;
72
+ components: OpenAPIV3_1.ComponentsObject;
73
+ }>, "paths">;
74
+ }
75
+ export {};
@@ -0,0 +1,334 @@
1
+ import { HandlerMethodToHttpMethod } from "../core/http_method.mjs";
2
+ import { castArray, ii, pascalCase } from "vtils";
3
+ import path from "node:path";
4
+ import fs from "fs-extra";
5
+ import createDebug from "debug";
6
+ import mo, { ts } from "ts-morph";
7
+ // src/cli/api_generator.ts
8
+ var ApiGenerator = class {
9
+ options;
10
+ cwd;
11
+ constructor(options = {}) {
12
+ this.options = options;
13
+ this.cwd = this.options.cwd || process.cwd();
14
+ }
15
+ debug = createDebug("api");
16
+ categoryUrlRe = /^.+\/src\/handlers\/(?:index\.ts|(.*)\/index\.ts|(.*)\.ts)$/;
17
+ checker;
18
+ resolveCategorySymbols(program, checker, entrySourceFile, sourcePath) {
19
+ const moduleSymbol = checker.getSymbolAtLocation(entrySourceFile);
20
+ const directCategorySymbols = checker.getExportsOfModule(moduleSymbol).filter((categorySymbol) => {
21
+ return checker.getTypeOfSymbol(categorySymbol).getProperties().length > 0;
22
+ });
23
+ if (directCategorySymbols.length > 0) return directCategorySymbols;
24
+ const resolvedSymbols = [];
25
+ for (const statement of entrySourceFile.statements) {
26
+ if (!ts.isExportDeclaration(statement) || !statement.moduleSpecifier || !ts.isStringLiteral(statement.moduleSpecifier)) continue;
27
+ const targetPath = path.resolve(path.dirname(sourcePath), statement.moduleSpecifier.text);
28
+ const resolvedSourceFile = [
29
+ targetPath,
30
+ `${targetPath}.ts`,
31
+ `${targetPath}.tsx`,
32
+ `${targetPath}/index.ts`,
33
+ `${targetPath}/index.tsx`
34
+ ].map((candidatePath) => program.getSourceFile(candidatePath)).find(Boolean);
35
+ if (!resolvedSourceFile) continue;
36
+ const resolvedSymbol = checker.getSymbolAtLocation(resolvedSourceFile);
37
+ if (!resolvedSymbol) continue;
38
+ if (checker.getTypeOfSymbol(resolvedSymbol).getProperties().length > 0) resolvedSymbols.push(resolvedSymbol);
39
+ }
40
+ return resolvedSymbols;
41
+ }
42
+ async start() {
43
+ this.debug("启动项目...");
44
+ const tsConfigPath = path.join(this.cwd, "tsconfig.json");
45
+ const handlersPath = path.join(this.cwd, "node_modules/@a/x/handlers.ts");
46
+ const entryFile = path.join(this.cwd, "src/generated/handlers.ts");
47
+ const moProject = new mo.Project({ tsConfigFilePath: tsConfigPath });
48
+ moProject.createSourceFile(entryFile, await fs.readFile(handlersPath, "utf-8"));
49
+ const program = moProject.getProgram().compilerObject;
50
+ const checker = program.getTypeChecker();
51
+ this.checker = checker;
52
+ const entrySourceFile = program.getSourceFile(entryFile);
53
+ const categorySymbols = this.resolveCategorySymbols(program, checker, entrySourceFile, handlersPath);
54
+ const apiData = [];
55
+ for (const categorySymbol of categorySymbols) {
56
+ const handlerSymbols = checker.getTypeOfSymbol(categorySymbol).getProperties();
57
+ if (!handlerSymbols.length) continue;
58
+ const categorySourceFilePath = handlerSymbols[0].getDeclarations()[0].getSourceFile().fileName;
59
+ if (/@dev[/.]/.test(categorySourceFilePath)) continue;
60
+ if (this.options.include?.length) {
61
+ if (this.options.include.every((item) => !categorySourceFilePath.includes(item))) continue;
62
+ }
63
+ if (this.options.exclude?.length) {
64
+ if (this.options.exclude.some((item) => categorySourceFilePath.includes(item))) continue;
65
+ }
66
+ const categoryUrlMatch = categorySourceFilePath.match(this.categoryUrlRe);
67
+ let categoryUrl = categoryUrlMatch[1] ?? categoryUrlMatch[2] ?? "";
68
+ categoryUrl = categoryUrl === "" ? "/" : `/${categoryUrl}/`;
69
+ for (const handlerSymbol of handlerSymbols) {
70
+ let handlerPath = [handlerSymbol.getName()];
71
+ const handlerNode = handlerSymbol.getDeclarations()[0];
72
+ if (ts.isVariableDeclaration(handlerNode) && handlerNode.initializer && ts.isCallExpression(handlerNode.initializer) && ts.isObjectLiteralExpression(handlerNode.initializer.arguments[0])) {
73
+ const requestPathNode = handlerNode.initializer.arguments[0].properties.find((item) => item.name?.getText() === "requestPath");
74
+ if (requestPathNode && ts.isPropertyAssignment(requestPathNode)) {
75
+ const customHandlerPath = ts.isStringLiteral(requestPathNode.initializer) ? requestPathNode.initializer.text : ts.isArrayLiteralExpression(requestPathNode.initializer) ? requestPathNode.initializer.elements.filter((item) => ts.isStringLiteral(item)).map((item) => item.text) : "";
76
+ if (customHandlerPath.length) handlerPath = castArray(customHandlerPath);
77
+ }
78
+ }
79
+ const handlerUrl = handlerPath.map((path) => `${categoryUrl}${path}`);
80
+ const handlerComment = this.getComment(handlerSymbol);
81
+ if (handlerComment.tags.has("private")) {
82
+ this.debug("跳过生成接口: %s", `${handlerUrl}`);
83
+ continue;
84
+ }
85
+ this.debug("生成接口: %s ...", handlerUrl);
86
+ const handlerType = checker.getTypeAtLocation(handlerNode);
87
+ const [requestType, responseType, methodType] = checker.getTypeArguments(handlerType);
88
+ const handlerCategory = pascalCase(categoryUrl) || "Index";
89
+ const handlerDescription = handlerComment.description || handlerUrl.join(", ");
90
+ const handlerMethod = methodType.value;
91
+ const httpMethod = HandlerMethodToHttpMethod[handlerMethod];
92
+ const requestData = this.getApiDto({ type: requestType });
93
+ const responseData = this.getApiDto({ type: responseType });
94
+ const requestDataJsonSchema = this.apiDataToJsonSchema(requestData);
95
+ const responseDataJsonSchema = this.apiDataToJsonSchema(responseData);
96
+ const handlerDescriptionDividerIndex = handlerDescription.indexOf("\n\n");
97
+ const apiName = handlerDescriptionDividerIndex === -1 ? handlerDescription : handlerDescription.substring(0, handlerDescriptionDividerIndex);
98
+ const apiDesc = handlerDescriptionDividerIndex === -1 ? "" : handlerDescription.substring(handlerDescriptionDividerIndex + 2);
99
+ apiData.push({
100
+ category: handlerCategory,
101
+ name: apiName,
102
+ desc: apiDesc,
103
+ path: handlerUrl,
104
+ handlerMethod,
105
+ method: httpMethod,
106
+ requestData,
107
+ responseData,
108
+ requestDataJsonSchema,
109
+ responseDataJsonSchema
110
+ });
111
+ }
112
+ }
113
+ this.debug("写入文件...");
114
+ const prefix = this.options.name ? `${this.options.name}_` : "";
115
+ await Promise.all([
116
+ fs.outputJSON(path.join(this.cwd, `temp/${prefix}api.json`), apiData, { spaces: 2 }),
117
+ fs.outputJSON(path.join(this.cwd, `temp/${prefix}yapi.json`), this.apiDataToYApiData(apiData), { spaces: 2 }),
118
+ fs.outputJSON(path.join(this.cwd, `temp/${prefix}openapi31.json`), this.apiDataToOpenAPI31Data(apiData), { spaces: 2 })
119
+ ]);
120
+ }
121
+ getComment(symbol) {
122
+ if (!symbol) return {
123
+ existing: false,
124
+ description: "",
125
+ tags: /* @__PURE__ */ new Map()
126
+ };
127
+ const description = ts.displayPartsToString(symbol.getDocumentationComment(this.checker)).trim();
128
+ const tags = symbol.getJsDocTags().map((item) => {
129
+ return {
130
+ label: item.name,
131
+ value: ts.displayPartsToString(item.text).trim()
132
+ };
133
+ });
134
+ return {
135
+ existing: !!description,
136
+ description,
137
+ tags: tags.reduce((res, item) => {
138
+ res.set(item.label, item.value);
139
+ return res;
140
+ }, /* @__PURE__ */ new Map())
141
+ };
142
+ }
143
+ getApiDto({ type, keySymbol = type.symbol || type.aliasSymbol }) {
144
+ const hasTypeFlag = (flag, _type = type) => (_type.flags & flag) === flag;
145
+ let valueSymbol = type.symbol || type.aliasSymbol;
146
+ const keySymbolName = keySymbol?.getName() || "";
147
+ let valueSymbolName = valueSymbol?.getName() || "";
148
+ const comment = this.getComment(keySymbol);
149
+ let isRequired = keySymbol ? !(keySymbol.getFlags() & ts.SymbolFlags.Optional) : false;
150
+ const apiName = keySymbolName || "__type";
151
+ if (valueSymbolName === "Decimal") return {
152
+ name: apiName,
153
+ desc: comment.description,
154
+ required: isRequired,
155
+ type: "number",
156
+ enum: [],
157
+ children: []
158
+ };
159
+ if (valueSymbolName === "SocketStream") return {
160
+ name: "ws",
161
+ desc: comment.description,
162
+ required: isRequired,
163
+ type: "object",
164
+ enum: [],
165
+ children: []
166
+ };
167
+ if (valueSymbolName === "MultipartFile") return {
168
+ name: "file",
169
+ desc: comment.description,
170
+ required: isRequired,
171
+ type: "file",
172
+ enum: [],
173
+ children: []
174
+ };
175
+ if (valueSymbolName === "Buffer") return {
176
+ name: "buffer",
177
+ desc: comment.description,
178
+ required: isRequired,
179
+ type: "object",
180
+ enum: [],
181
+ children: []
182
+ };
183
+ const rawUnionTypes = type.isUnion() && type.types || [];
184
+ const unionTypes = rawUnionTypes.filter((item) => !hasTypeFlag(ts.TypeFlags.Null, item) && !hasTypeFlag(ts.TypeFlags.Undefined, item));
185
+ const isUnion = !!unionTypes.length;
186
+ if (isUnion) {
187
+ if (unionTypes.length !== rawUnionTypes.length) isRequired = false;
188
+ type = unionTypes[0];
189
+ valueSymbol = type.symbol || type.aliasSymbol;
190
+ valueSymbolName = this.checker.getBaseTypeOfLiteralType(type).getSymbol()?.getName() || "";
191
+ }
192
+ const isIntersection = type.isIntersection();
193
+ const intersectionTypes = isIntersection && type.types || [];
194
+ const isDate = valueSymbolName === "Date";
195
+ const isRegExp = valueSymbolName === "RegExp";
196
+ const isBigIntLiteral = hasTypeFlag(ts.TypeFlags.BigIntLiteral);
197
+ const isBigInt = hasTypeFlag(ts.TypeFlags.BigInt) || isBigIntLiteral;
198
+ const isArray = valueSymbolName === "Array" || valueSymbolName === "ReadonlyArray";
199
+ const isStringLiteral = hasTypeFlag(ts.TypeFlags.StringLiteral);
200
+ const isString = hasTypeFlag(ts.TypeFlags.String) || isStringLiteral || isBigInt || isDate || isRegExp;
201
+ const isNumberLiteral = hasTypeFlag(ts.TypeFlags.NumberLiteral);
202
+ const isNumber = hasTypeFlag(ts.TypeFlags.Number) || isNumberLiteral;
203
+ const isBoolean = hasTypeFlag(ts.TypeFlags.Boolean) || hasTypeFlag(ts.TypeFlags.BooleanLiteral);
204
+ const isLiteral = isStringLiteral || isNumberLiteral || isBigIntLiteral;
205
+ const isObject = !isArray && !isString && !isNumber && !isBoolean && hasTypeFlag(ts.TypeFlags.Object) || isIntersection;
206
+ return {
207
+ name: apiName,
208
+ desc: keySymbol && this.getComment(keySymbol).description || "",
209
+ enum: (isUnion ? unionTypes.map((item) => item.value) : isLiteral ? [type.value] : []).filter((v) => v != null),
210
+ type: isArray ? "array" : isString ? "string" : isNumber ? "number" : isBoolean ? "boolean" : "object",
211
+ required: isRequired,
212
+ children: isArray ? [this.getApiDto({ type: this.checker.getTypeArguments(type)[0] })] : isObject ? ii(() => {
213
+ return this.checker.getAllPossiblePropertiesOfTypes(intersectionTypes.length ? intersectionTypes : [type]).map((childSymbol) => {
214
+ const childType = this.checker.getTypeOfSymbol(childSymbol);
215
+ return this.getApiDto({
216
+ type: childType,
217
+ keySymbol: childSymbol
218
+ });
219
+ });
220
+ }) : []
221
+ };
222
+ }
223
+ apiDataToJsonSchema(apiData, jsonSchema = {}) {
224
+ jsonSchema.description = apiData.desc;
225
+ if (apiData.type === "object") {
226
+ jsonSchema.type = "object";
227
+ jsonSchema.properties = apiData.children.reduce((res, item) => {
228
+ res[item.name] = this.apiDataToJsonSchema(item);
229
+ return res;
230
+ }, {});
231
+ jsonSchema.required = apiData.children.filter((item) => item.required).map((item) => item.name);
232
+ } else if (apiData.type === "array") {
233
+ jsonSchema.type = "array";
234
+ jsonSchema.items = apiData.children.map((item) => this.apiDataToJsonSchema(item))[0];
235
+ } else {
236
+ jsonSchema.type = apiData.type;
237
+ if (apiData.enum.length) jsonSchema.enum = apiData.enum;
238
+ }
239
+ return jsonSchema;
240
+ }
241
+ apiDataToYApiData(handles) {
242
+ const data = {};
243
+ for (const handle of handles) for (const path of handle.path) {
244
+ data[handle.category] = data[handle.category] || [];
245
+ data[handle.category].push(handle.handlerMethod === "GET" ? {
246
+ method: handle.method.toUpperCase(),
247
+ title: handle.name,
248
+ markdown: handle.desc,
249
+ path,
250
+ res_body_type: "json",
251
+ req_body_is_json_schema: false,
252
+ res_body_is_json_schema: true,
253
+ req_params: [],
254
+ req_query: handle.requestData.children.map((item) => ({
255
+ required: item.required ? 1 : 0,
256
+ name: item.name,
257
+ desc: item.desc,
258
+ type: "string"
259
+ })),
260
+ req_headers: [],
261
+ req_body_form: [],
262
+ res_body: JSON.stringify(handle.responseDataJsonSchema)
263
+ } : handle.handlerMethod === "FILE" ? {
264
+ method: handle.method.toUpperCase(),
265
+ title: handle.name,
266
+ markdown: handle.desc,
267
+ path,
268
+ req_body_type: "form",
269
+ res_body_type: "json",
270
+ req_body_is_json_schema: false,
271
+ res_body_is_json_schema: true,
272
+ req_params: [],
273
+ req_query: [],
274
+ req_headers: [],
275
+ req_body_form: handle.requestData.children.map((item) => ({
276
+ required: item.required ? 1 : 0,
277
+ name: item.name,
278
+ desc: item.desc,
279
+ type: item.type === "file" ? "file" : "text"
280
+ })),
281
+ res_body: JSON.stringify(handle.responseDataJsonSchema)
282
+ } : {
283
+ method: handle.method.toUpperCase(),
284
+ title: handle.name,
285
+ markdown: handle.desc,
286
+ path,
287
+ req_body_type: "json",
288
+ res_body_type: "json",
289
+ req_body_is_json_schema: true,
290
+ res_body_is_json_schema: true,
291
+ req_params: [],
292
+ req_query: [],
293
+ req_headers: [],
294
+ req_body_form: [],
295
+ req_body_other: JSON.stringify(handle.requestDataJsonSchema),
296
+ res_body: JSON.stringify(handle.responseDataJsonSchema)
297
+ });
298
+ }
299
+ return Object.keys(data).map((cat) => ({
300
+ name: cat,
301
+ desc: cat,
302
+ list: data[cat]
303
+ }));
304
+ }
305
+ apiDataToOpenAPI31Data(handles) {
306
+ const data = {
307
+ openapi: "3.1.0",
308
+ info: {
309
+ title: `${process.env.APP_NAME}`,
310
+ version: "1.0.0"
311
+ },
312
+ paths: {},
313
+ servers: [{
314
+ url: `${process.env.APP_URL}`.replace(/\/+$/, ""),
315
+ description: "生产"
316
+ }, {
317
+ url: `http://127.0.0.1:${process.env.APP_PORT}`,
318
+ description: "本地"
319
+ }]
320
+ };
321
+ for (const handle of handles) for (const path of handle.path) data.paths[path] = { [handle.method.toLowerCase()]: {
322
+ tags: [handle.category],
323
+ summary: handle.name,
324
+ description: handle.desc,
325
+ requestBody: { content: { "application/json": { schema: handle.requestDataJsonSchema } } },
326
+ responses: { "200": {
327
+ description: "success",
328
+ content: { "application/json": { schema: handle.responseDataJsonSchema } }
329
+ } }
330
+ } };
331
+ return data;
332
+ }
333
+ };
334
+ export { ApiGenerator };
@@ -0,0 +1,15 @@
1
+ export interface BuildOptions {
2
+ appId: string;
3
+ cwd: string;
4
+ inlineEnvs?: Record<string, any>;
5
+ minify?: boolean;
6
+ channel?: string;
7
+ excludeFiles?: string[];
8
+ noEmptyDistDir?: boolean;
9
+ pm2MaxMemoryRestart?: string;
10
+ pm2CronRestart?: string;
11
+ pm2NodeArgs?: string | string[];
12
+ }
13
+ export declare class BuildUtil {
14
+ static build(options: BuildOptions): Promise<void>;
15
+ }
@@ -0,0 +1,101 @@
1
+ import { dedent, omitStrict } from "vtils";
2
+ import path from "node:path";
3
+ import fs from "fs-extra";
4
+ import compressing from "compressing";
5
+ import * as esbuild from "esbuild";
6
+ import macrosPlugin from "unplugin-macros/esbuild";
7
+ // src/cli/build_util.ts
8
+ var BuildUtil = class {
9
+ static async build(options) {
10
+ const mainFile = path.join(options.cwd, "src/main.ts");
11
+ const pkgFile = path.join(options.cwd, "package.json");
12
+ const pkgContent = await fs.readJson(pkgFile);
13
+ pkgContent.name = options.appId;
14
+ const distDir = path.join(options.cwd, options.channel ? `dist/${options.channel}` : "dist");
15
+ const tempDir = path.join(options.cwd, options.channel ? `temp/${options.channel}` : "temp");
16
+ const distMainFile = path.join(distDir, "main.js");
17
+ const distPkgFile = path.join(distDir, "package.json");
18
+ const distNvmrcFile = path.join(distDir, ".nvmrc");
19
+ const distNpmrcFile = path.join(distDir, ".npmrc");
20
+ const distPnpmWorkspaceFile = path.join(distDir, "pnpm-workspace.yaml");
21
+ const distPnpmLockFile = path.join(distDir, "pnpm-lock.yaml");
22
+ const distPm2File = path.join(distDir, "pm2.config.js");
23
+ const distBundleFile = path.join(tempDir, `app.${pkgContent.version}.tgz`);
24
+ await fs.ensureDir(distDir);
25
+ await fs.ensureDir(tempDir);
26
+ if (!options.noEmptyDistDir) await fs.emptyDir(distDir);
27
+ await esbuild.build({
28
+ entryPoints: [mainFile],
29
+ bundle: true,
30
+ outfile: distMainFile,
31
+ platform: "node",
32
+ mainFields: ["module", "main"],
33
+ target: `node${process.version.slice(1)}`,
34
+ minify: options.minify ?? false,
35
+ format: "esm",
36
+ sourcemap: false,
37
+ treeShaking: true,
38
+ banner: { js: [...Object.keys(options.inlineEnvs || {}).map((key) => `process.env[${JSON.stringify(key)}]=${JSON.stringify(options.inlineEnvs[key])};`), `process.env["X_SERVER_ENVS"]=${JSON.stringify(JSON.stringify(options.inlineEnvs || {}))};`].join("\n") },
39
+ plugins: [{
40
+ name: "custom",
41
+ async setup(build) {
42
+ build.onLoad({ filter: /@dev[/.]/ }, async () => {
43
+ return {
44
+ contents: "module.exports = {}",
45
+ loader: "js"
46
+ };
47
+ });
48
+ if (options.excludeFiles?.length) {
49
+ const excludeRegExps = options.excludeFiles.map((item) => new RegExp(item));
50
+ build.onLoad({ filter: /\.ts$/ }, async (args) => {
51
+ if (excludeRegExps.some((re) => re.test(args.path))) return {
52
+ contents: "module.exports = {}",
53
+ loader: "js"
54
+ };
55
+ });
56
+ }
57
+ }
58
+ }, macrosPlugin()],
59
+ loader: { ".css": "empty" }
60
+ });
61
+ const prismaSchemaFile = path.join(options.cwd, "src/db/schema.prisma");
62
+ if (await fs.pathExists(prismaSchemaFile)) {
63
+ const distPrismaSchemaFile = path.join(distDir, path.basename(prismaSchemaFile));
64
+ await fs.copyFile(prismaSchemaFile, distPrismaSchemaFile);
65
+ const multipleSchemaDir = path.join(options.cwd, "src/db/schema");
66
+ if (await fs.pathExists(multipleSchemaDir)) {
67
+ const distMultipleSchemaDir = path.join(distDir, path.basename(multipleSchemaDir));
68
+ await fs.copy(multipleSchemaDir, distMultipleSchemaDir);
69
+ }
70
+ }
71
+ await fs.writeJson(distPkgFile, omitStrict(pkgContent, ["devDependencies", "scripts"]), { spaces: 2 });
72
+ const nvmrcFile = path.join(options.cwd, ".nvmrc");
73
+ const hasNvmrc = await fs.pathExists(nvmrcFile);
74
+ await fs.writeFile(distNvmrcFile, hasNvmrc ? await fs.readFile(nvmrcFile) : process.version.slice(1).split(".")[0]);
75
+ const npmrcFile = path.join(options.cwd, ".npmrc");
76
+ if (await fs.pathExists(npmrcFile)) await fs.copyFile(npmrcFile, distNpmrcFile);
77
+ const pnpmWorkspaceFile = path.join(options.cwd, "pnpm-workspace.yaml");
78
+ if (await fs.pathExists(pnpmWorkspaceFile)) await fs.copyFile(pnpmWorkspaceFile, distPnpmWorkspaceFile);
79
+ const pnpmLockFile = path.join(options.cwd, "pnpm-lock.yaml");
80
+ if (await fs.pathExists(pnpmLockFile)) await fs.copyFile(pnpmLockFile, distPnpmLockFile);
81
+ await fs.writeFile(distPm2File, dedent`
82
+ module.exports = {
83
+ apps: [
84
+ {
85
+ name: ${JSON.stringify(pkgContent.name)},
86
+ script: './main.js',
87
+ interpreter: 'node',
88
+ interpreter_args: ${JSON.stringify(options.pm2NodeArgs || [])},
89
+ env: {
90
+ PATH: \`\${require('child_process').execSync('fnm exec which node').toString().trim().replace(/\\/node$/, '')}:\${process.env.PATH}\`,
91
+ },
92
+ ${options.pm2MaxMemoryRestart ? `max_memory_restart: '${options.pm2MaxMemoryRestart}',` : ""}
93
+ ${options.pm2CronRestart ? `cron_restart: '${options.pm2CronRestart}',` : ""}
94
+ },
95
+ ],
96
+ }
97
+ `);
98
+ await compressing.tgz.compressDir(distDir, distBundleFile);
99
+ }
100
+ };
101
+ export { BuildUtil };
@@ -0,0 +1 @@
1
+ export {}