@dune2/cli 1.1.2 → 1.1.4

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 (49) hide show
  1. package/dist/cli.d.mts +1 -0
  2. package/dist/cli.mjs +50 -0
  3. package/dist/cli.mjs.map +1 -0
  4. package/dist/config-CxSOgXuG.mjs +20 -0
  5. package/dist/config-CxSOgXuG.mjs.map +1 -0
  6. package/dist/generateApi-NvvdY6gQ.mjs +272 -0
  7. package/dist/generateApi-NvvdY6gQ.mjs.map +1 -0
  8. package/dist/{index.d.ts → index.d.mts} +9 -8
  9. package/dist/index.mjs +65 -0
  10. package/dist/index.mjs.map +1 -0
  11. package/dist/initConfig-Cu0d5qZ8.mjs +28 -0
  12. package/dist/initConfig-Cu0d5qZ8.mjs.map +1 -0
  13. package/dist/interactive-CG86IvnG.mjs +38 -0
  14. package/dist/interactive-CG86IvnG.mjs.map +1 -0
  15. package/dist/normalizeConfig-Dx193DW8.mjs +26 -0
  16. package/dist/normalizeConfig-Dx193DW8.mjs.map +1 -0
  17. package/dist/normalizeConfig.d.mts +8 -0
  18. package/dist/normalizeConfig.mjs +3 -0
  19. package/dist/prettier.cjs +9946 -42
  20. package/dist/prettier.cjs.map +1 -1
  21. package/dist/prettier.d.cts +14 -0
  22. package/dist/prettier.d.mts +14 -0
  23. package/dist/prettier.mjs +9952 -0
  24. package/dist/prettier.mjs.map +1 -0
  25. package/dist/types-lEW0KXAS.d.mts +70 -0
  26. package/package.json +9 -9
  27. package/dist/chunk-ENF3KHSQ.js +0 -19
  28. package/dist/chunk-ENF3KHSQ.js.map +0 -1
  29. package/dist/chunk-OZFFB6QC.js +0 -27
  30. package/dist/chunk-OZFFB6QC.js.map +0 -1
  31. package/dist/chunk-RWPDDW5T.js +0 -29
  32. package/dist/chunk-RWPDDW5T.js.map +0 -1
  33. package/dist/cli.d.ts +0 -1
  34. package/dist/cli.js +0 -35
  35. package/dist/cli.js.map +0 -1
  36. package/dist/generateApi-CCO7OH35.js +0 -330
  37. package/dist/generateApi-CCO7OH35.js.map +0 -1
  38. package/dist/index.js +0 -54
  39. package/dist/index.js.map +0 -1
  40. package/dist/initConfig-CJT7LP2T.js +0 -32
  41. package/dist/initConfig-CJT7LP2T.js.map +0 -1
  42. package/dist/interactive-VUY3CMIF.js +0 -43
  43. package/dist/interactive-VUY3CMIF.js.map +0 -1
  44. package/dist/normalizeConfig.d.ts +0 -8
  45. package/dist/normalizeConfig.js +0 -9
  46. package/dist/normalizeConfig.js.map +0 -1
  47. package/dist/prettier.js +0 -50
  48. package/dist/prettier.js.map +0 -1
  49. package/dist/types-B1PjA6gT.d.ts +0 -68
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/dist/cli.mjs ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ import cac from "cac";
3
+ import debug from "debug";
4
+
5
+ //#region package.json
6
+ var version = "1.1.3";
7
+
8
+ //#endregion
9
+ //#region src/shared/index.ts
10
+ const cli = cac("dune");
11
+ const createLogger = (name) => {
12
+ const info = debug(`${cli.name}:${name}`);
13
+ return {
14
+ ...info,
15
+ info,
16
+ error: info.extend("error")
17
+ };
18
+ };
19
+ debug.enable(`${cli.name}:*`);
20
+
21
+ //#endregion
22
+ //#region src/cli.ts
23
+ cli.command("generateApi", "生成 api 文件").example("dune generateApi").action(async () => {
24
+ const { generateApi } = await import("./generateApi-NvvdY6gQ.mjs");
25
+ await generateApi();
26
+ });
27
+ cli.command("init", "初始化配置文件").example("dune init").action(async () => {
28
+ const { initConfig } = await import("./initConfig-Cu0d5qZ8.mjs");
29
+ await initConfig();
30
+ });
31
+ cli.command("interactive", "交互式操作").example("dune interactive").alias("i").action(async (args) => {
32
+ const { interactive } = await import("./interactive-CG86IvnG.mjs");
33
+ await interactive(args);
34
+ });
35
+ cli.command("").action(async (args) => {
36
+ const { interactive } = await import("./interactive-CG86IvnG.mjs");
37
+ await interactive(args);
38
+ });
39
+ cli.version(version);
40
+ cli.help();
41
+ (async () => {
42
+ try {
43
+ cli.parse(process.argv, { run: false });
44
+ await cli.runMatchedCommand();
45
+ } catch (error) {}
46
+ })();
47
+
48
+ //#endregion
49
+ export { createLogger as n, cli as t };
50
+ //# sourceMappingURL=cli.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.mjs","names":[],"sources":["../package.json","../src/shared/index.ts","../src/cli.ts"],"sourcesContent":["","import cac from \"cac\";\nimport debug from \"debug\";\n\nexport const cli = cac(\"dune\");\n\nexport const createLogger = (name: string) => {\n const info = debug(`${cli.name}:${name}`);\n return {\n ...info,\n info,\n error: info.extend(\"error\"),\n };\n};\n\ndebug.enable(`${cli.name}:*`);\n","#!/usr/bin/env node\nimport { version } from \"../package.json\";\nimport { cli } from \"./shared\";\n\n//#region api 相关\ncli\n .command(\"generateApi\", \"生成 api 文件\")\n .example(\"dune generateApi\")\n .action(async () => {\n const { generateApi } = await import(\"./commands/generateApi\");\n await generateApi();\n });\n//#endregion\n\ncli\n .command(\"init\", \"初始化配置文件\")\n .example(\"dune init\")\n .action(async () => {\n const { initConfig } = await import(\"./commands/initConfig\");\n await initConfig();\n });\n\ncli\n .command(\"interactive\", \"交互式操作\")\n .example(\"dune interactive\")\n .alias(\"i\")\n .action(async (args) => {\n const { interactive } = await import(\"./commands/interactive\");\n await interactive(args);\n });\n\n// make default command run interactive\ncli.command(\"\").action(async (args) => {\n const { interactive } = await import(\"./commands/interactive\");\n await interactive(args);\n});\n\ncli.version(version);\ncli.help();\n\n(async () => {\n try {\n // Parse CLI args without running the command\n cli.parse(process.argv, { run: false });\n // Run the command yourself\n // You only need `await` when your command action returns a Promise\n await cli.runMatchedCommand();\n } catch (error) {\n // Handle error here..\n // e.g.\n // console.error(error.stack)\n // process.exit(1)\n }\n})();\n"],"mappings":";;;;;;;;;ACGA,MAAa,MAAM,IAAI,OAAO;AAE9B,MAAa,gBAAgB,SAAiB;CAC5C,MAAM,OAAO,MAAM,GAAG,IAAI,KAAK,GAAG,OAAO;AACzC,QAAO;EACL,GAAG;EACH;EACA,OAAO,KAAK,OAAO,QAAQ;EAC5B;;AAGH,MAAM,OAAO,GAAG,IAAI,KAAK,IAAI;;;;ACT7B,IACG,QAAQ,eAAe,YAAY,CACnC,QAAQ,mBAAmB,CAC3B,OAAO,YAAY;CAClB,MAAM,EAAE,gBAAgB,MAAM,OAAO;AACrC,OAAM,aAAa;EACnB;AAGJ,IACG,QAAQ,QAAQ,UAAU,CAC1B,QAAQ,YAAY,CACpB,OAAO,YAAY;CAClB,MAAM,EAAE,eAAe,MAAM,OAAO;AACpC,OAAM,YAAY;EAClB;AAEJ,IACG,QAAQ,eAAe,QAAQ,CAC/B,QAAQ,mBAAmB,CAC3B,MAAM,IAAI,CACV,OAAO,OAAO,SAAS;CACtB,MAAM,EAAE,gBAAgB,MAAM,OAAO;AACrC,OAAM,YAAY,KAAK;EACvB;AAGJ,IAAI,QAAQ,GAAG,CAAC,OAAO,OAAO,SAAS;CACrC,MAAM,EAAE,gBAAgB,MAAM,OAAO;AACrC,OAAM,YAAY,KAAK;EACvB;AAEF,IAAI,QAAQ,QAAQ;AACpB,IAAI,MAAM;CAET,YAAY;AACX,KAAI;AAEF,MAAI,MAAM,QAAQ,MAAM,EAAE,KAAK,OAAO,CAAC;AAGvC,QAAM,IAAI,mBAAmB;UACtB,OAAO;IAMd"}
@@ -0,0 +1,20 @@
1
+ import { n as normalizeConfig } from "./normalizeConfig-Dx193DW8.mjs";
2
+ import { createJiti } from "jiti";
3
+
4
+ //#region src/shared/config/index.ts
5
+ function defineConfig(c) {
6
+ return c;
7
+ }
8
+ const configName = "dune.config.ts";
9
+ async function getConfig() {
10
+ const cwd = process.cwd();
11
+ return normalizeConfig(await createJiti(cwd).import(`./${configName}`, { default: true }).catch((err) => {
12
+ console.warn(`can not find config file: ${configName} in ${cwd}`);
13
+ console.warn(`please run "dune init" to create config file`);
14
+ return {};
15
+ }));
16
+ }
17
+
18
+ //#endregion
19
+ export { defineConfig as n, getConfig as r, configName as t };
20
+ //# sourceMappingURL=config-CxSOgXuG.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-CxSOgXuG.mjs","names":[],"sources":["../src/shared/config/index.ts"],"sourcesContent":["import { createJiti } from \"jiti\";\nimport { normalizeConfig } from \"./normalizeConfig\";\nimport { Config } from \"./types\";\n\nexport * from \"./types\";\n\nexport function defineConfig<T extends Config = Config>(c: T) {\n return c;\n}\n\nexport const configName = \"dune.config.ts\";\n\nexport async function getConfig(): Promise<Config> {\n const cwd = process.cwd();\n const jiti = createJiti(cwd);\n\n const res = await jiti\n .import<Config>(`./${configName}`, {\n default: true,\n })\n .catch((err) => {\n console.warn(`can not find config file: ${configName} in ${cwd}`);\n console.warn(`please run \"dune init\" to create config file`);\n return {};\n });\n\n return normalizeConfig(res);\n}\n"],"mappings":";;;;AAMA,SAAgB,aAAwC,GAAM;AAC5D,QAAO;;AAGT,MAAa,aAAa;AAE1B,eAAsB,YAA6B;CACjD,MAAM,MAAM,QAAQ,KAAK;AAazB,QAAO,gBAVK,MAFC,WAAW,IAAI,CAGzB,OAAe,KAAK,cAAc,EACjC,SAAS,MACV,CAAC,CACD,OAAO,QAAQ;AACd,UAAQ,KAAK,6BAA6B,WAAW,MAAM,MAAM;AACjE,UAAQ,KAAK,+CAA+C;AAC5D,SAAO,EAAE;GACT,CAEuB"}
@@ -0,0 +1,272 @@
1
+ import { r as getConfig } from "./config-CxSOgXuG.mjs";
2
+ import { n as createLogger } from "./cli.mjs";
3
+ import path from "path";
4
+ import SwaggerParser from "@apidevtools/swagger-parser";
5
+ import { camelCase, isPlainObject, merge } from "es-toolkit";
6
+ import { compile } from "json-schema-to-typescript";
7
+ import { AsyncLocalStorage } from "node:async_hooks";
8
+ import fs from "node:fs/promises";
9
+ import * as os from "os";
10
+ import pMap from "p-map";
11
+ import enquirer from "enquirer";
12
+
13
+ //#region src/shared/promptConfigEnable.ts
14
+ const { prompt } = enquirer;
15
+ async function promptConfigEnable(opt) {
16
+ const { configArr, getChoiceItem } = opt;
17
+ if (configArr.length <= 1) return configArr;
18
+ const res = await prompt({
19
+ type: "multiselect",
20
+ message: "选择要生效的配置项",
21
+ hint: "(空格选中,回车确认)",
22
+ name: "enabled",
23
+ validate(value) {
24
+ return value.length === 0 ? `至少选择一项` : true;
25
+ },
26
+ choices: [{
27
+ name: "全部",
28
+ message: "全部",
29
+ choices: configArr.map((item) => {
30
+ return getChoiceItem(item);
31
+ })
32
+ }]
33
+ });
34
+ configArr.forEach((item) => {
35
+ item.enabled = opt.checkIsEnabled(res.enabled, item);
36
+ });
37
+ return configArr.filter((c) => c.enabled);
38
+ }
39
+ function promptApiConfigEnable(configArr) {
40
+ return promptConfigEnable({
41
+ configArr: configArr ?? [],
42
+ getChoiceItem: (item) => {
43
+ return {
44
+ name: item.output,
45
+ hint: `swaggerJSONPath: ${item.swaggerJSONPath}`
46
+ };
47
+ },
48
+ checkIsEnabled: (enabledArr, item) => {
49
+ return enabledArr.includes(item.output);
50
+ }
51
+ });
52
+ }
53
+
54
+ //#endregion
55
+ //#region src/commands/generateApi/index.ts
56
+ const log = createLogger("generateApi");
57
+ const asyncLocalStorage = new AsyncLocalStorage();
58
+ function isV3(doc) {
59
+ if (doc) return "components" in doc;
60
+ return false;
61
+ }
62
+ async function generateApi() {
63
+ const apiConfigs = await promptApiConfigEnable((await getConfig()).api);
64
+ for (const apiConfig of apiConfigs) {
65
+ log.info(`清除旧的 api 文件:${apiConfig.output}`);
66
+ await fs.rm(apiConfig.output, {
67
+ recursive: true,
68
+ force: true
69
+ });
70
+ await fs.mkdir(apiConfig.output, { recursive: true });
71
+ }
72
+ for (const apiConfig of apiConfigs) {
73
+ log.info("开始解析 %s", apiConfig.swaggerJSONPath);
74
+ const dereferenceConfig = merge({ resolve: { http: { timeout: 30 * 1e3 } } }, apiConfig.dereferenceSwaggerConfig || {});
75
+ const parser = new SwaggerParser();
76
+ const parsed = await parser.bundle(apiConfig.swaggerJSONPath, dereferenceConfig);
77
+ asyncLocalStorage.run({
78
+ parsed,
79
+ parser
80
+ }, async () => {
81
+ await pMap(Object.entries(parsed.paths), async ([url, pathItemObject]) => {
82
+ log.info("开始生成 %s", url);
83
+ if (pathItemObject) await pMap([
84
+ "get",
85
+ "put",
86
+ "post",
87
+ "delete",
88
+ "patch"
89
+ ], async (method) => {
90
+ const operationObject = pathItemObject[method];
91
+ if (operationObject) {
92
+ const code = await generateApiRequestCode({
93
+ url,
94
+ method,
95
+ operationObject,
96
+ apiConfig
97
+ });
98
+ const outputPath = path.join(apiConfig.output, url, apiConfig.enableTs ? `${method}.ts` : `${method}.js`).replace(/:/g, "_");
99
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
100
+ await fs.writeFile(outputPath, code);
101
+ }
102
+ });
103
+ });
104
+ });
105
+ if (apiConfig.codeFormatterCmd) {
106
+ const { exec } = await import("child_process");
107
+ await new Promise((resolve, reject) => {
108
+ exec(`${apiConfig.codeFormatterCmd} ${apiConfig.output}/**`, (error) => {
109
+ if (error) console.warn(`Code formatting failed: ${error.message}`);
110
+ resolve();
111
+ });
112
+ });
113
+ }
114
+ }
115
+ log.info("generateApi Done");
116
+ }
117
+ /**
118
+ * 根据请求方法,生成请求代码
119
+ */
120
+ async function generateApiRequestCode(options) {
121
+ var _operationObject$tags, _operationObject$tags2;
122
+ const { method, operationObject, apiConfig } = options;
123
+ const url = (() => {
124
+ if (typeof apiConfig.urlTransformer === "string") return `${apiConfig.urlTransformer}${options.url}`;
125
+ if (typeof apiConfig.urlTransformer === "function") return apiConfig.urlTransformer(options.url);
126
+ return options.url;
127
+ })();
128
+ const seeUrl = apiConfig.swaggerUiUrl ? `${apiConfig.swaggerUiUrl}#/${encodeURIComponent(`${((_operationObject$tags = operationObject.tags) === null || _operationObject$tags === void 0 ? void 0 : _operationObject$tags.join("/")) ?? ""}/${operationObject.operationId}`)}` : "";
129
+ let requestBuilderName = camelCase(`${options.url}_${method}_api`);
130
+ if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(requestBuilderName)) requestBuilderName = `_${requestBuilderName}`;
131
+ const urlPathParams = getUrlPathParams(operationObject.parameters ?? []);
132
+ const urlPathParamsCode = urlPathParams.length ? `urlPathParams: ${JSON.stringify(urlPathParams)},` : "";
133
+ let code = [
134
+ "// do not edit this file manually, it will be overwritten by @dune2/cli",
135
+ apiConfig.RequestBuilderImportPath,
136
+ apiConfig.queryClientImportPath,
137
+ "/**",
138
+ ` * ${operationObject.summary}`,
139
+ ` * @tags ${(_operationObject$tags2 = operationObject.tags) === null || _operationObject$tags2 === void 0 ? void 0 : _operationObject$tags2.join(",")}`,
140
+ seeUrl && ` * @see ${seeUrl}`,
141
+ ` */`
142
+ ].filter(Boolean);
143
+ let builderCode = `\
144
+ export const ${requestBuilderName} = new RequestBuilder({
145
+ url: '${url}',
146
+ method: '${method}',
147
+ ${urlPathParamsCode}
148
+ ${apiConfig.queryClientImportPath ? "queryClient," : ""}
149
+ });`.replace(/,\n\s*}/, "," + os.EOL + "}");
150
+ if (apiConfig.enableTs) builderCode = builderCode.replace("new RequestBuilder(", `new RequestBuilder<${requestBuilderName}.Req, ${requestBuilderName}.Res>(`);
151
+ code.push(builderCode);
152
+ if (apiConfig.enableTs) {
153
+ const [requestParamsTypeCode, responseParamsTypeCode] = await Promise.all([compileRequestParams(operationObject), compileResponseParams(operationObject, apiConfig)]);
154
+ code.push(`
155
+ export namespace ${requestBuilderName} {
156
+ ${requestParamsTypeCode.code}
157
+
158
+ ${responseParamsTypeCode}
159
+ };`);
160
+ }
161
+ return code.join(os.EOL);
162
+ }
163
+ function getUrlPathParams(parameters) {
164
+ return parameters.filter((item) => item.in === "path").map((item) => item.name);
165
+ }
166
+ /**
167
+ * 这个方法还不完善,只能处理简单的请求参数
168
+ */
169
+ async function compileRequestParams(operationObject) {
170
+ let schema;
171
+ if (operationObject.requestBody) schema = operationObject.requestBody.content["application/json"].schema;
172
+ else if (operationObject.parameters) {
173
+ const extraProperties = {};
174
+ const parameters = [];
175
+ operationObject.parameters.forEach((item) => {
176
+ if (!["query", "path"].includes(item.in)) return;
177
+ if (item.schema && "type" in item.schema && item.schema.type === "object") Object.assign(extraProperties, item.schema.properties || {});
178
+ else parameters.push(item);
179
+ });
180
+ schema = {
181
+ required: parameters.filter((p) => p.required && ![
182
+ "pageNum",
183
+ "pageSize",
184
+ "count"
185
+ ].includes(p.name)).map((p) => p.name),
186
+ type: "object",
187
+ properties: {
188
+ ...Object.fromEntries(parameters.filter((p) => !!p.schema).map((p) => {
189
+ const schema$1 = p.schema;
190
+ return [p.name, {
191
+ ...schema$1,
192
+ description: p.description
193
+ }];
194
+ })),
195
+ ...extraProperties
196
+ }
197
+ };
198
+ }
199
+ let code = "";
200
+ if (schema) {
201
+ const store = asyncLocalStorage.getStore();
202
+ if ((store === null || store === void 0 ? void 0 : store.parser) && schema.$ref) schema = store === null || store === void 0 ? void 0 : store.parser.$refs.get(schema.$ref);
203
+ if (isV3(store === null || store === void 0 ? void 0 : store.parsed)) schema.components = store === null || store === void 0 ? void 0 : store.parsed.components;
204
+ try {
205
+ code = await compile(schema, "Req", {
206
+ bannerComment: "",
207
+ ignoreMinAndMaxItems: true,
208
+ additionalProperties: false,
209
+ unknownAny: false
210
+ });
211
+ } catch (e) {
212
+ log.error("生成请求参数类型失败,请检查 %o", {
213
+ summary: operationObject.summary,
214
+ message: e.message,
215
+ operationId: operationObject.operationId
216
+ });
217
+ }
218
+ }
219
+ return { code: code || "export type Req = any;" };
220
+ }
221
+ async function compileResponseParams(operationObject, apiConfig) {
222
+ const temp = operationObject.responses["200"];
223
+ let code = "";
224
+ if (temp === null || temp === void 0 ? void 0 : temp.content) {
225
+ const temp2 = temp.content["application/json"] || temp.content["*/*"];
226
+ let schema = apiConfig.responseSchemaTransformer(temp2.schema);
227
+ if (schema) {
228
+ const store = asyncLocalStorage.getStore();
229
+ const schema2 = (() => {
230
+ if ("$ref" in schema && (store === null || store === void 0 ? void 0 : store.parser) && isV3(store.parsed)) {
231
+ let r = store === null || store === void 0 ? void 0 : store.parser.$refs.get(schema.$ref);
232
+ r = apiConfig.responseSchemaTransformer(r);
233
+ if (isPlainObject(r)) {
234
+ if ("$ref" in r) r = store === null || store === void 0 ? void 0 : store.parser.$refs.get(r.$ref);
235
+ if (isPlainObject(r)) return {
236
+ ...r,
237
+ components: store === null || store === void 0 ? void 0 : store.parsed.components
238
+ };
239
+ }
240
+ log.error(`unknown other types`);
241
+ return;
242
+ }
243
+ return schema;
244
+ })();
245
+ if (!schema2) log.error(`can not found schema to generate response code`);
246
+ try {
247
+ code = await compile(schema2, "Res", {
248
+ bannerComment: "",
249
+ ignoreMinAndMaxItems: true,
250
+ additionalProperties: false,
251
+ unknownAny: false
252
+ });
253
+ const isPageSearchResponse = (data) => {
254
+ var _data$properties;
255
+ return data.type === "object" && ((_data$properties = data.properties) === null || _data$properties === void 0 || (_data$properties = _data$properties.result) === null || _data$properties === void 0 ? void 0 : _data$properties.type) === "array";
256
+ };
257
+ if (isPageSearchResponse(schema)) code += `${os.EOL}export type ResultItem = Res['result'][0]`;
258
+ } catch (e) {
259
+ log.error("转换响应参数类型失败,请检查 %o", {
260
+ summary: operationObject.summary,
261
+ error: e.message,
262
+ operationId: operationObject.operationId
263
+ });
264
+ }
265
+ } else log.error("responseSchemaTransformer 返回值为空,请检查");
266
+ }
267
+ return code ? code : "export type Res = any;";
268
+ }
269
+
270
+ //#endregion
271
+ export { generateApi };
272
+ //# sourceMappingURL=generateApi-NvvdY6gQ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateApi-NvvdY6gQ.mjs","names":["schema"],"sources":["../src/shared/promptConfigEnable.ts","../src/commands/generateApi/index.ts"],"sourcesContent":["import enquirer from \"enquirer\";\nimport { ApiConfig } from \"./config\";\nconst { prompt } = enquirer;\n\ninterface Opt<T> {\n configArr: (T & { enabled?: boolean })[];\n getChoiceItem: (item: T) => {\n name: string;\n message?: string;\n value?: string;\n hint?: string;\n };\n checkIsEnabled: (enabledArr: string[], item: T) => boolean;\n}\n\nexport async function promptConfigEnable<T>(opt: Opt<T>) {\n const { configArr, getChoiceItem } = opt;\n // 只有一条配置的时候不用选择\n if (configArr.length <= 1) {\n return configArr;\n }\n\n const choices = [\n {\n name: \"全部\",\n message: \"全部\",\n choices: configArr.map((item) => {\n return getChoiceItem(item);\n }),\n },\n ];\n const res = await prompt<{ enabled: string[] }>({\n type: \"multiselect\",\n message: \"选择要生效的配置项\",\n // @ts-ignore\n hint: \"(空格选中,回车确认)\",\n name: \"enabled\",\n validate(value) {\n return value.length === 0 ? `至少选择一项` : true;\n },\n choices,\n });\n\n configArr.forEach((item) => {\n item.enabled = opt.checkIsEnabled(res.enabled, item);\n });\n\n return configArr.filter((c) => c.enabled);\n}\n\nexport function promptApiConfigEnable(configArr: ApiConfig[] | undefined) {\n return promptConfigEnable({\n configArr: configArr ?? [],\n getChoiceItem: (item) => {\n return {\n name: item.output!,\n hint: `swaggerJSONPath: ${item.swaggerJSONPath}`,\n };\n },\n checkIsEnabled: (enabledArr, item) => {\n return enabledArr.includes(item.output!);\n },\n });\n}\n","import SwaggerParser from \"@apidevtools/swagger-parser\";\nimport { camelCase, isPlainObject, merge } from \"es-toolkit\";\nimport { compile } from \"json-schema-to-typescript\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport fs from \"node:fs/promises\";\nimport { OpenAPIV3, type OpenAPI } from \"openapi-types\";\nimport * as os from \"os\";\nimport pMap from \"p-map\";\nimport path from \"path\";\nimport { createLogger } from \"../../shared\";\nimport { ApiConfig, getConfig } from \"../../shared/config\";\nimport { promptApiConfigEnable } from \"../../shared/promptConfigEnable\";\n\nconst log = createLogger(\"generateApi\");\n\nexport const asyncLocalStorage = new AsyncLocalStorage<{\n parsed: OpenAPI.Document;\n parser: SwaggerParser;\n}>();\n\nfunction isV3(doc: OpenAPI.Document | undefined): doc is OpenAPIV3.Document {\n if (doc) {\n return \"components\" in doc;\n }\n return false;\n}\n\nexport async function generateApi() {\n const config = await getConfig();\n const apiConfigs = await promptApiConfigEnable(config.api);\n\n for (const apiConfig of apiConfigs) {\n log.info(`清除旧的 api 文件:${apiConfig.output}`);\n await fs.rm(apiConfig.output!, { recursive: true, force: true });\n await fs.mkdir(apiConfig.output!, { recursive: true });\n }\n\n for (const apiConfig of apiConfigs) {\n log.info(\"开始解析 %s\", apiConfig.swaggerJSONPath);\n const dereferenceConfig = merge(\n {\n resolve: {\n http: {\n timeout: 30 * 1000,\n },\n },\n },\n apiConfig.dereferenceSwaggerConfig || {},\n );\n const parser = new SwaggerParser();\n\n const parsed = await parser.bundle(\n apiConfig.swaggerJSONPath,\n dereferenceConfig,\n );\n\n asyncLocalStorage.run({ parsed, parser }, async () => {\n await pMap(\n Object.entries(parsed.paths!),\n async ([url, pathItemObject]) => {\n log.info(\"开始生成 %s\", url);\n if (pathItemObject) {\n await pMap(\n [\"get\", \"put\", \"post\", \"delete\", \"patch\"],\n async (method) => {\n const operationObject = pathItemObject[method];\n if (operationObject) {\n const code = await generateApiRequestCode({\n url: url,\n method: method,\n operationObject: operationObject,\n apiConfig,\n });\n const outputPath = path\n .join(\n apiConfig.output!,\n url,\n apiConfig.enableTs ? `${method}.ts` : `${method}.js`,\n )\n .replace(/:/g, \"_\");\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, code);\n }\n },\n );\n }\n },\n );\n });\n if (apiConfig.codeFormatterCmd) {\n const { exec } = await import(\"child_process\");\n await new Promise<void>((resolve, reject) => {\n exec(\n `${apiConfig.codeFormatterCmd} ${apiConfig.output!}/**`,\n (error) => {\n if (error) {\n console.warn(`Code formatting failed: ${error.message}`);\n }\n resolve();\n },\n );\n });\n }\n }\n\n log.info(\"generateApi Done\");\n}\n\n/**\n * 根据请求方法,生成请求代码\n */\nexport async function generateApiRequestCode(options: {\n url: string;\n method: string;\n operationObject: OpenAPIV3.OperationObject;\n apiConfig: ApiConfig;\n}): Promise<string> {\n const { method, operationObject, apiConfig } = options;\n\n const url = (() => {\n if (typeof apiConfig.urlTransformer === \"string\") {\n return `${apiConfig.urlTransformer}${options.url}`;\n }\n if (typeof apiConfig.urlTransformer === \"function\") {\n return apiConfig.urlTransformer(options.url);\n }\n return options.url;\n })();\n\n const seeUrl = apiConfig.swaggerUiUrl\n ? `${apiConfig.swaggerUiUrl}#/${encodeURIComponent(\n `${operationObject.tags?.join(\"/\") ?? \"\"}/${\n operationObject.operationId\n }`,\n )}`\n : \"\";\n\n // 生成的请求构造器的名称,需要使用原始 url\n let requestBuilderName = camelCase(`${options.url}_${method}_api`);\n\n // 判断是否有效的 js 变量\n if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(requestBuilderName)) {\n // 不是有效的 js 变量,使用 _ + 数字\n requestBuilderName = `_${requestBuilderName}`;\n }\n\n //#region url 上参数 例如 /api/v1/users/{userId}\n const urlPathParams = getUrlPathParams(\n (operationObject.parameters as never) ?? [],\n );\n const urlPathParamsCode = urlPathParams.length\n ? `urlPathParams: ${JSON.stringify(urlPathParams)},`\n : \"\";\n //#endregion\n\n let code: string[] = [\n \"// do not edit this file manually, it will be overwritten by @dune2/cli\",\n apiConfig.RequestBuilderImportPath!,\n apiConfig.queryClientImportPath!,\n\n \"/**\",\n ` * ${operationObject.summary}`,\n ` * @tags ${operationObject.tags?.join(\",\")}`,\n seeUrl && ` * @see ${seeUrl}`,\n ` */`,\n ].filter(Boolean);\n\n // builder 代码\n let builderCode = `\\\nexport const ${requestBuilderName} = new RequestBuilder({\n url: '${url}',\n method: '${method}',\n ${urlPathParamsCode}\n ${apiConfig.queryClientImportPath ? \"queryClient,\" : \"\"}\n});`\n // 移除空行\n .replace(/,\\n\\s*}/, \",\" + os.EOL + \"}\");\n if (apiConfig.enableTs) {\n builderCode = builderCode.replace(\n \"new RequestBuilder(\",\n `new RequestBuilder<${requestBuilderName}.Req, ${requestBuilderName}.Res>(`,\n );\n }\n code.push(builderCode);\n\n if (apiConfig.enableTs) {\n const [requestParamsTypeCode, responseParamsTypeCode] = await Promise.all([\n // 请求参数类型\n compileRequestParams(operationObject),\n // 响应参数类型\n compileResponseParams(operationObject, apiConfig),\n ]);\n\n code.push(`\nexport namespace ${requestBuilderName} {\n ${requestParamsTypeCode.code}\n \n ${responseParamsTypeCode}\n};`);\n }\n\n return code.join(os.EOL);\n}\n\nfunction getUrlPathParams(parameters: OpenAPIV3.ParameterObject[]) {\n return parameters\n .filter((item) => item.in === \"path\")\n .map((item) => item.name);\n}\n\n/**\n * 这个方法还不完善,只能处理简单的请求参数\n */\nasync function compileRequestParams(\n operationObject: OpenAPIV3.OperationObject,\n) {\n let schema;\n if (operationObject.requestBody) {\n //TODO: 这里也需要处理其他类型\n schema = (operationObject.requestBody as OpenAPIV3.RequestBodyObject)\n .content[\"application/json\"].schema;\n } else if (operationObject.parameters) {\n const extraProperties = {};\n const parameters: OpenAPIV3.ParameterObject[] = [];\n (operationObject.parameters as OpenAPIV3.ParameterObject[]).forEach(\n (item) => {\n if (![\"query\", \"path\"].includes(item.in)) {\n return;\n }\n if (\n item.schema &&\n \"type\" in item.schema &&\n item.schema.type === \"object\"\n ) {\n // swagger get 请求上 有些参数是 object 类型 应该拍平\n Object.assign(\n extraProperties,\n (item.schema as OpenAPIV3.SchemaObject).properties || {},\n );\n } else {\n parameters.push(item);\n }\n },\n );\n\n // 必填参数中忽略 分页相关的参数\n const required = parameters\n .filter(\n (p) => p.required && ![\"pageNum\", \"pageSize\", \"count\"].includes(p.name),\n )\n .map((p) => p.name);\n const properties = Object.fromEntries(\n parameters\n // 后端 swagger 可能出现没有 schema 的情况,这里过滤掉\n .filter((p) => !!p.schema)\n .map((p) => {\n //TODO: 这里也要处理 ref 类型\n const schema = p.schema as OpenAPIV3.SchemaObject;\n return [\n p.name,\n {\n ...schema,\n description: p.description,\n // enum: schema.enum ?? [],\n },\n ];\n }),\n );\n schema = {\n required,\n type: \"object\",\n properties: { ...properties, ...extraProperties },\n };\n }\n\n let code = \"\";\n if (schema) {\n const store = asyncLocalStorage.getStore();\n if (store?.parser && schema.$ref) {\n schema = store?.parser.$refs.get(schema.$ref);\n }\n if (isV3(store?.parsed)) {\n schema.components = store?.parsed.components;\n }\n\n try {\n code = await compile(schema, \"Req\", {\n bannerComment: \"\",\n ignoreMinAndMaxItems: !!1,\n additionalProperties: false,\n unknownAny: false,\n // format: false,\n });\n } catch (e) {\n log.error(\"生成请求参数类型失败,请检查 %o\", {\n summary: operationObject.summary,\n message: e.message,\n operationId: operationObject.operationId,\n });\n }\n }\n\n return {\n code: code || \"export type Req = any;\",\n };\n}\n\nasync function compileResponseParams(\n operationObject: OpenAPIV3.OperationObject,\n apiConfig: ApiConfig,\n) {\n const temp = operationObject.responses[\"200\"] as OpenAPIV3.ResponseObject;\n let code = \"\";\n if (temp?.content) {\n // FIXME: 可能需要处理其他的 content 类型\n const temp2 = temp.content[\"application/json\"] || temp.content[\"*/*\"];\n //let schema = temp2.schema;\n //@ts-expect-error TODO: 待修复类型\n let schema = apiConfig.responseSchemaTransformer!(temp2.schema);\n if (schema) {\n const store = asyncLocalStorage.getStore();\n\n const schema2 = (() => {\n if (\"$ref\" in schema && store?.parser && isV3(store.parsed)) {\n let r = store?.parser.$refs.get(schema.$ref);\n // @ts-expect-error TODO: 待修复类型\n r = apiConfig.responseSchemaTransformer!(r);\n if (isPlainObject(r)) {\n if (\"$ref\" in r) {\n r = store?.parser.$refs.get(r.$ref as string);\n }\n\n if (isPlainObject(r)) {\n return {\n ...r,\n components: store?.parsed.components,\n };\n }\n }\n log.error(`unknown other types`);\n return;\n }\n return schema;\n })();\n\n if (!schema2) {\n log.error(`can not found schema to generate response code`);\n }\n\n try {\n code = await compile(schema2, \"Res\", {\n bannerComment: \"\",\n ignoreMinAndMaxItems: !!1,\n additionalProperties: false,\n unknownAny: false,\n // format: false,\n });\n\n // 通过响应数据判断是否是分页查询接口\n const isPageSearchResponse = (data: any) => {\n // 有 result 字段且为数组,就认为是分页查询接口\n return (\n data.type === \"object\" && data.properties?.result?.type === \"array\"\n );\n };\n\n // 新增后端分页查询返回的数据类型\n if (isPageSearchResponse(schema)) {\n code += `${os.EOL}export type ResultItem = Res['result'][0]`;\n }\n } catch (e) {\n log.error(\"转换响应参数类型失败,请检查 %o\", {\n summary: operationObject.summary,\n error: e.message,\n operationId: operationObject.operationId,\n });\n }\n } else {\n log.error(\"responseSchemaTransformer 返回值为空,请检查\");\n }\n }\n\n return code ? code : \"export type Res = any;\";\n}\n"],"mappings":"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"}
@@ -1,19 +1,19 @@
1
- import { C as Config } from './types-B1PjA6gT.js';
2
- export { A as ApiConfig } from './types-B1PjA6gT.js';
3
- import '@apidevtools/swagger-parser';
4
- import 'openapi-types';
1
+ import { n as Config, t as ApiConfig } from "./types-lEW0KXAS.mjs";
5
2
 
3
+ //#region src/shared/config/index.d.ts
6
4
  declare function defineConfig<T extends Config = Config>(c: T): T;
7
5
  declare const configName = "dune.config.ts";
8
6
  declare function getConfig(): Promise<Config>;
9
-
7
+ //#endregion
8
+ //#region src/shared/defaultJsonSorter.d.ts
10
9
  /**
11
10
  * 对 JSON 对象的键进行排序
12
11
  * @param obj 要排序的 JSON 对象
13
12
  * @returns 排序后的 JSON 对象
14
13
  */
15
14
  declare function defaultJsonSorter<T extends Record<string, any>>(obj: T): T;
16
-
15
+ //#endregion
16
+ //#region src/shared/letters.d.ts
17
17
  /**
18
18
  *
19
19
  * - input : A
@@ -37,5 +37,6 @@ declare function letterToNumber(letters: string | number): number;
37
37
  * numberToLetter(702) // AAA
38
38
  */
39
39
  declare function numberToLetter(n: number): string;
40
-
41
- export { Config, configName, defaultJsonSorter, defineConfig, getConfig, letterToNumber, numberToLetter };
40
+ //#endregion
41
+ export { ApiConfig, Config, configName, defaultJsonSorter, defineConfig, getConfig, letterToNumber, numberToLetter };
42
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,65 @@
1
+ import { n as defineConfig, r as getConfig, t as configName } from "./config-CxSOgXuG.mjs";
2
+
3
+ //#region src/shared/defaultJsonSorter.ts
4
+ /**
5
+ * 对 JSON 对象的键进行排序
6
+ * @param obj 要排序的 JSON 对象
7
+ * @returns 排序后的 JSON 对象
8
+ */
9
+ function defaultJsonSorter(obj) {
10
+ return Object.keys(obj).sort().reduce((acc, key) => {
11
+ acc[key] = obj[key];
12
+ return acc;
13
+ }, {});
14
+ }
15
+
16
+ //#endregion
17
+ //#region src/shared/letters.ts
18
+ /**
19
+ *
20
+ * - input : A
21
+ * output : 0
22
+ * - input : Z
23
+ * output : 25
24
+ * - input : AA
25
+ * output : 26
26
+ * - input : a
27
+ * output : 0
28
+ */
29
+ function letterToNumber(letters) {
30
+ if (typeof letters === "number" || !Number.isNaN(+letters)) return +letters;
31
+ let n = 0;
32
+ letters = letters.toUpperCase();
33
+ for (let p = 0; p < letters.length; p++) n = letters[p].charCodeAt(0) - 64 + n * 26;
34
+ return Math.max(0, n - 1);
35
+ }
36
+ /**
37
+ * fork from https://github.com/matthewmueller/number-to-letter
38
+ */
39
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
40
+ const base = 26;
41
+ /**
42
+ * numberToLetter(0) // A
43
+ * numberToLetter(25) // Z
44
+ * numberToLetter(26) // AA
45
+ * numberToLetter(51) // AZ
46
+ * numberToLetter(52) // BA
47
+ * numberToLetter(676) // ZA
48
+ * numberToLetter(701) // ZZ
49
+ * numberToLetter(702) // AAA
50
+ */
51
+ function numberToLetter(n) {
52
+ const digits = [];
53
+ do {
54
+ const v = n % base;
55
+ digits.push(v);
56
+ n = Math.floor(n / base);
57
+ } while (n-- > 0);
58
+ const chars = [];
59
+ while (digits.length) chars.push(alphabet[digits.pop()]);
60
+ return chars.join("");
61
+ }
62
+
63
+ //#endregion
64
+ export { configName, defaultJsonSorter, defineConfig, getConfig, letterToNumber, numberToLetter };
65
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/shared/defaultJsonSorter.ts","../src/shared/letters.ts"],"sourcesContent":["/**\n * 对 JSON 对象的键进行排序\n * @param obj 要排序的 JSON 对象\n * @returns 排序后的 JSON 对象\n */\nexport function defaultJsonSorter<T extends Record<string, any>>(obj: T) {\n const keys = Object.keys(obj);\n const sortedKeys = keys.sort(); // 使用原生 sort 方法对键进行排序\n const sortedObj = sortedKeys.reduce((acc, key) => {\n acc[key as keyof T] = obj[key];\n return acc;\n }, {} as T);\n\n return sortedObj as T;\n}\n","/**\n *\n * - input : A\n * output : 0\n * - input : Z\n * output : 25\n * - input : AA\n * output : 26\n * - input : a\n * output : 0\n */\nexport function letterToNumber(letters: string | number) {\n if (typeof letters === \"number\" || !Number.isNaN(+letters)) {\n return +letters;\n }\n\n let n = 0;\n letters = letters.toUpperCase();\n for (let p = 0; p < letters.length; p++) {\n n = letters[p].charCodeAt(0) - 64 + n * 26;\n }\n\n return Math.max(0, n - 1);\n}\n\n/**\n * fork from https://github.com/matthewmueller/number-to-letter\n */\nconst alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\nconst base = alphabet.length;\n/**\n * numberToLetter(0) // A\n * numberToLetter(25) // Z\n * numberToLetter(26) // AA\n * numberToLetter(51) // AZ\n * numberToLetter(52) // BA\n * numberToLetter(676) // ZA\n * numberToLetter(701) // ZZ\n * numberToLetter(702) // AAA\n */\nexport function numberToLetter(n: number) {\n const digits: number[] = [];\n\n do {\n const v = n % base;\n digits.push(v);\n n = Math.floor(n / base);\n } while (n-- > 0);\n\n const chars: string[] = [];\n while (digits.length) {\n chars.push(alphabet[digits.pop()!]);\n }\n\n return chars.join(\"\");\n}\n"],"mappings":";;;;;;;;AAKA,SAAgB,kBAAiD,KAAQ;AAQvE,QAPa,OAAO,KAAK,IAAI,CACL,MAAM,CACD,QAAQ,KAAK,QAAQ;AAChD,MAAI,OAAkB,IAAI;AAC1B,SAAO;IACN,EAAE,CAAM;;;;;;;;;;;;;;;;ACAb,SAAgB,eAAe,SAA0B;AACvD,KAAI,OAAO,YAAY,YAAY,CAAC,OAAO,MAAM,CAAC,QAAQ,CACxD,QAAO,CAAC;CAGV,IAAI,IAAI;AACR,WAAU,QAAQ,aAAa;AAC/B,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAClC,KAAI,QAAQ,GAAG,WAAW,EAAE,GAAG,KAAK,IAAI;AAG1C,QAAO,KAAK,IAAI,GAAG,IAAI,EAAE;;;;;AAM3B,MAAM,WAAW;AACjB,MAAM,OAAO;;;;;;;;;;;AAWb,SAAgB,eAAe,GAAW;CACxC,MAAM,SAAmB,EAAE;AAE3B,IAAG;EACD,MAAM,IAAI,IAAI;AACd,SAAO,KAAK,EAAE;AACd,MAAI,KAAK,MAAM,IAAI,KAAK;UACjB,MAAM;CAEf,MAAM,QAAkB,EAAE;AAC1B,QAAO,OAAO,OACZ,OAAM,KAAK,SAAS,OAAO,KAAK,EAAG;AAGrC,QAAO,MAAM,KAAK,GAAG"}
@@ -0,0 +1,28 @@
1
+ import { t as configName } from "./config-CxSOgXuG.mjs";
2
+ import { n as createLogger } from "./cli.mjs";
3
+ import path from "path";
4
+ import fs from "node:fs/promises";
5
+
6
+ //#region src/commands/initConfig.ts
7
+ const log = createLogger("initConfig");
8
+ const tpl = `\
9
+ import { defineConfig } from "@dune2/cli";
10
+
11
+ export default defineConfig({
12
+ i18n: [],
13
+ api: [],
14
+ });`;
15
+ const initConfig = async () => {
16
+ const configPath = path.join(process.cwd(), configName);
17
+ log.info(`config file path: ${configPath}`);
18
+ if (await fs.access(configPath).then(() => true).catch(() => false)) {
19
+ log.info(`config file already exists, skip`);
20
+ return;
21
+ }
22
+ await fs.writeFile(configPath, tpl);
23
+ log.info(`config file created`);
24
+ };
25
+
26
+ //#endregion
27
+ export { initConfig };
28
+ //# sourceMappingURL=initConfig-Cu0d5qZ8.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initConfig-Cu0d5qZ8.mjs","names":[],"sources":["../src/commands/initConfig.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"path\";\nimport { createLogger } from \"../shared\";\nimport { configName } from \"../shared/config\";\n\nconst log = createLogger(\"initConfig\");\n\nconst tpl = `\\\nimport { defineConfig } from \"@dune2/cli\";\n\nexport default defineConfig({\n i18n: [],\n api: [],\n});`;\n\nexport const initConfig = async () => {\n const configPath = path.join(process.cwd(), configName);\n log.info(`config file path: ${configPath}`);\n if (\n await fs\n .access(configPath)\n .then(() => true)\n .catch(() => false)\n ) {\n log.info(`config file already exists, skip`);\n return;\n }\n await fs.writeFile(configPath, tpl);\n log.info(`config file created`);\n};\n"],"mappings":";;;;;;AAKA,MAAM,MAAM,aAAa,aAAa;AAEtC,MAAM,MAAM;;;;;;;AAQZ,MAAa,aAAa,YAAY;CACpC,MAAM,aAAa,KAAK,KAAK,QAAQ,KAAK,EAAE,WAAW;AACvD,KAAI,KAAK,qBAAqB,aAAa;AAC3C,KACE,MAAM,GACH,OAAO,WAAW,CAClB,WAAW,KAAK,CAChB,YAAY,MAAM,EACrB;AACA,MAAI,KAAK,mCAAmC;AAC5C;;AAEF,OAAM,GAAG,UAAU,YAAY,IAAI;AACnC,KAAI,KAAK,sBAAsB"}
@@ -0,0 +1,38 @@
1
+ import { n as createLogger, t as cli } from "./cli.mjs";
2
+ import enquirer from "enquirer";
3
+
4
+ //#region src/commands/interactive.ts
5
+ const { prompt } = enquirer;
6
+ const log = createLogger("interactive");
7
+ const interactive = async (args) => {
8
+ var _command$commandActio;
9
+ const commands = cli.commands.filter((command$1) => {
10
+ if (command$1.name) return !command$1.name.startsWith("@@") && command$1.name !== "interactive";
11
+ return false;
12
+ });
13
+ const commandMap = /* @__PURE__ */ new Map();
14
+ const res = await prompt({
15
+ type: "autocomplete",
16
+ name: "command",
17
+ message: "选择要执行的命令:",
18
+ choices: commands.map((command$1) => {
19
+ commandMap.set(command$1.name, command$1);
20
+ return {
21
+ name: command$1.name,
22
+ value: command$1.name,
23
+ message: command$1.description,
24
+ hint: `等同命令 ${cli.name} ${command$1.name}`
25
+ };
26
+ })
27
+ });
28
+ const command = commandMap.get(res.command);
29
+ if (!command) {
30
+ log.error("未找到命令 %s", res.command);
31
+ return;
32
+ }
33
+ (_command$commandActio = command.commandAction) === null || _command$commandActio === void 0 || _command$commandActio.apply(cli, args);
34
+ };
35
+
36
+ //#endregion
37
+ export { interactive };
38
+ //# sourceMappingURL=interactive-CG86IvnG.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive-CG86IvnG.mjs","names":["command"],"sources":["../src/commands/interactive.ts"],"sourcesContent":["import { cli, createLogger } from \"../shared\";\nimport enquirer from \"enquirer\";\nconst { prompt } = enquirer;\n\nconst log = createLogger(\"interactive\");\n\nexport const interactive = async (args: any) => {\n const commands = cli.commands.filter((command) => {\n if (command.name) {\n return !command.name.startsWith(\"@@\") && command.name !== \"interactive\";\n }\n return false;\n });\n\n const commandMap = new Map<string, typeof commands[number]>();\n const res = await prompt<{ command: string }>({\n type: \"autocomplete\",\n name: \"command\",\n message: \"选择要执行的命令:\",\n choices: commands.map((command) => {\n commandMap.set(command.name, command);\n return {\n name: command.name,\n value: command.name,\n message: command.description,\n hint: `等同命令 ${cli.name} ${command.name}`,\n };\n }),\n });\n const command = commandMap.get(res.command);\n if (!command) {\n log.error(\"未找到命令 %s\", res.command);\n return;\n }\n command.commandAction?.apply(cli, args);\n};\n"],"mappings":";;;;AAEA,MAAM,EAAE,WAAW;AAEnB,MAAM,MAAM,aAAa,cAAc;AAEvC,MAAa,cAAc,OAAO,SAAc;;CAC9C,MAAM,WAAW,IAAI,SAAS,QAAQ,cAAY;AAChD,MAAIA,UAAQ,KACV,QAAO,CAACA,UAAQ,KAAK,WAAW,KAAK,IAAIA,UAAQ,SAAS;AAE5D,SAAO;GACP;CAEF,MAAM,6BAAa,IAAI,KAAsC;CAC7D,MAAM,MAAM,MAAM,OAA4B;EAC5C,MAAM;EACN,MAAM;EACN,SAAS;EACT,SAAS,SAAS,KAAK,cAAY;AACjC,cAAW,IAAIA,UAAQ,MAAMA,UAAQ;AACrC,UAAO;IACL,MAAMA,UAAQ;IACd,OAAOA,UAAQ;IACf,SAASA,UAAQ;IACjB,MAAM,QAAQ,IAAI,KAAK,GAAGA,UAAQ;IACnC;IACD;EACH,CAAC;CACF,MAAM,UAAU,WAAW,IAAI,IAAI,QAAQ;AAC3C,KAAI,CAAC,SAAS;AACZ,MAAI,MAAM,YAAY,IAAI,QAAQ;AAClC;;AAEF,kCAAQ,qFAAe,MAAM,KAAK,KAAK"}
@@ -0,0 +1,26 @@
1
+ import path from "path";
2
+
3
+ //#region src/shared/config/normalizeConfig.ts
4
+ function normalizeConfig(config) {
5
+ config.cwd ??= process.cwd();
6
+ config.cacheDir ??= path.join(config.cwd, "node_modules/.cache/dune-cli");
7
+ config.api ??= [];
8
+ config.api = config.api.map(apiConfigNormalizer);
9
+ return config;
10
+ }
11
+ function apiConfigNormalizer(item) {
12
+ item.output ??= "./src/apis";
13
+ item.RequestBuilderImportPath ??= `import { RequestBuilder } from '@dune2/tools/rq';`;
14
+ item.enableTs ??= true;
15
+ item.enabled ??= true;
16
+ item.codeFormatterCmd ??= "prettier --write";
17
+ item.responseSchemaTransformer ??= (schema) => {
18
+ var _schema$properties;
19
+ return ((_schema$properties = schema.properties) === null || _schema$properties === void 0 ? void 0 : _schema$properties.data) ?? schema;
20
+ };
21
+ return item;
22
+ }
23
+
24
+ //#endregion
25
+ export { normalizeConfig as n, apiConfigNormalizer as t };
26
+ //# sourceMappingURL=normalizeConfig-Dx193DW8.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalizeConfig-Dx193DW8.mjs","names":[],"sources":["../src/shared/config/normalizeConfig.ts"],"sourcesContent":["import path from \"path\";\nimport { ApiConfig, Config } from \"./types\";\nexport function normalizeConfig(config: Config): Config {\n config.cwd ??= process.cwd();\n config.cacheDir ??= path.join(config.cwd, \"node_modules/.cache/dune-cli\");\n\n //#region api 配置标准化\n config.api ??= [];\n config.api = config.api.map(apiConfigNormalizer);\n //#endregion\n return config;\n}\nexport function apiConfigNormalizer(item: ApiConfig) {\n item.output ??= \"./src/apis\";\n item.RequestBuilderImportPath ??= `import { RequestBuilder } from '@dune2/tools/rq';`;\n item.enableTs ??= true;\n item.enabled ??= true;\n item.codeFormatterCmd ??= \"prettier --write\";\n item.responseSchemaTransformer ??= (schema) =>\n schema.properties?.data ?? schema;\n return item;\n}\n"],"mappings":";;;AAEA,SAAgB,gBAAgB,QAAwB;AACtD,QAAO,QAAQ,QAAQ,KAAK;AAC5B,QAAO,aAAa,KAAK,KAAK,OAAO,KAAK,+BAA+B;AAGzE,QAAO,QAAQ,EAAE;AACjB,QAAO,MAAM,OAAO,IAAI,IAAI,oBAAoB;AAEhD,QAAO;;AAET,SAAgB,oBAAoB,MAAiB;AACnD,MAAK,WAAW;AAChB,MAAK,6BAA6B;AAClC,MAAK,aAAa;AAClB,MAAK,YAAY;AACjB,MAAK,qBAAqB;AAC1B,MAAK,+BAA+B,WAClC;;uCAAO,oFAAY,SAAQ;;AAC7B,QAAO"}
@@ -0,0 +1,8 @@
1
+ import { n as Config, t as ApiConfig } from "./types-lEW0KXAS.mjs";
2
+
3
+ //#region src/shared/config/normalizeConfig.d.ts
4
+ declare function normalizeConfig(config: Config): Config;
5
+ declare function apiConfigNormalizer(item: ApiConfig): ApiConfig;
6
+ //#endregion
7
+ export { apiConfigNormalizer, normalizeConfig };
8
+ //# sourceMappingURL=normalizeConfig.d.mts.map
@@ -0,0 +1,3 @@
1
+ import { n as normalizeConfig, t as apiConfigNormalizer } from "./normalizeConfig-Dx193DW8.mjs";
2
+
3
+ export { apiConfigNormalizer, normalizeConfig };