@dune2/cli 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -1,10 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import cac from "cac";
3
3
  import debug from "debug";
4
-
5
4
  //#region package.json
6
- var version = "1.1.6";
7
-
5
+ var version = "1.2.1";
8
6
  //#endregion
9
7
  //#region src/shared/index.ts
10
8
  const cli = cac("dune");
@@ -17,23 +15,22 @@ const createLogger = (name) => {
17
15
  };
18
16
  };
19
17
  debug.enable(`${cli.name}:*`);
20
-
21
18
  //#endregion
22
19
  //#region src/cli.ts
23
20
  cli.command("generateApi", "生成 api 文件").example("dune generateApi").action(async () => {
24
- const { generateApi } = await import("./generateApi-Dd7TJHu0.mjs");
21
+ const { generateApi } = await import("./generateApi-DwdWYQrF.mjs");
25
22
  await generateApi();
26
23
  });
27
24
  cli.command("init", "初始化配置文件").example("dune init").action(async () => {
28
- const { initConfig } = await import("./initConfig-D8kYF-u1.mjs");
25
+ const { initConfig } = await import("./initConfig-DCOS9II9.mjs");
29
26
  await initConfig();
30
27
  });
31
28
  cli.command("interactive", "交互式操作").example("dune interactive").alias("i").action(async (args) => {
32
- const { interactive } = await import("./interactive-FF1hLdGL.mjs");
29
+ const { interactive } = await import("./interactive-CK8WpuBn.mjs");
33
30
  await interactive(args);
34
31
  });
35
32
  cli.command("").action(async (args) => {
36
- const { interactive } = await import("./interactive-FF1hLdGL.mjs");
33
+ const { interactive } = await import("./interactive-CK8WpuBn.mjs");
37
34
  await interactive(args);
38
35
  });
39
36
  cli.version(version);
@@ -44,7 +41,7 @@ cli.help();
44
41
  await cli.runMatchedCommand();
45
42
  } catch (error) {}
46
43
  })();
47
-
48
44
  //#endregion
49
45
  export { createLogger as n, cli as t };
46
+
50
47
  //# sourceMappingURL=cli.mjs.map
package/dist/cli.mjs.map CHANGED
@@ -1 +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"}
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"}
@@ -1,6 +1,5 @@
1
1
  import { normalizeConfig } from "./normalizeConfig.mjs";
2
2
  import { createJiti } from "jiti";
3
-
4
3
  //#region src/shared/config/index.ts
5
4
  function defineConfig(c) {
6
5
  return c;
@@ -14,7 +13,7 @@ async function getConfig() {
14
13
  return {};
15
14
  }));
16
15
  }
17
-
18
16
  //#endregion
19
17
  export { defineConfig as n, getConfig as r, configName as t };
20
- //# sourceMappingURL=config-9MrZts4R.mjs.map
18
+
19
+ //# sourceMappingURL=config-CF5PxwnQ.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-9MrZts4R.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"}
1
+ {"version":3,"file":"config-CF5PxwnQ.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"}
@@ -1,4 +1,4 @@
1
- import { r as getConfig } from "./config-9MrZts4R.mjs";
1
+ import { r as getConfig } from "./config-CF5PxwnQ.mjs";
2
2
  import { n as createLogger } from "./cli.mjs";
3
3
  import path from "path";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -9,7 +9,6 @@ import { camelCase, isPlainObject, merge } from "es-toolkit";
9
9
  import { compile } from "json-schema-to-typescript";
10
10
  import pMap from "p-map";
11
11
  import enquirer from "enquirer";
12
-
13
12
  //#region src/shared/promptConfigEnable.ts
14
13
  const { prompt } = enquirer;
15
14
  async function promptConfigEnable(opt) {
@@ -50,11 +49,17 @@ function promptApiConfigEnable(configArr) {
50
49
  }
51
50
  });
52
51
  }
53
-
54
52
  //#endregion
55
53
  //#region src/commands/generateApi/index.ts
56
54
  const log = createLogger("generateApi");
57
55
  const asyncLocalStorage = new AsyncLocalStorage();
56
+ function getCompileSchemaContext(parsed) {
57
+ if (!parsed) return {};
58
+ const context = {};
59
+ if ("components" in parsed && parsed.components) context.components = parsed.components;
60
+ if ("definitions" in parsed && parsed.definitions) context.definitions = parsed.definitions;
61
+ return context;
62
+ }
58
63
  async function generateApi() {
59
64
  const selectedConfigs = await promptApiConfigEnable((await getConfig()).api);
60
65
  const apiConfigs = selectedConfigs.filter((apiConfig) => {
@@ -104,7 +109,11 @@ async function generateApi() {
104
109
  const bundleStartedAt = Date.now();
105
110
  let parsed;
106
111
  try {
107
- parsed = await parser.bundle(apiConfig.swaggerJSONPath, dereferenceConfig);
112
+ const bundleInput = /^https?:\/\//.test(apiConfig.swaggerJSONPath) ? await fetch(apiConfig.swaggerJSONPath).then((res) => {
113
+ if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
114
+ return res.json();
115
+ }) : apiConfig.swaggerJSONPath;
116
+ parsed = await parser.bundle(bundleInput, dereferenceConfig);
108
117
  log.info("解析 %s 成功,耗时 %dms", apiConfig.swaggerJSONPath, Date.now() - bundleStartedAt);
109
118
  } catch (error) {
110
119
  totalFailedCount++;
@@ -272,7 +281,7 @@ async function compileRequestParams(operationObject) {
272
281
  };
273
282
  }
274
283
  })();
275
- const finalSchema = isPlainObject(schemaOrRefObject) ? Object.assign({ components: store === null || store === void 0 ? void 0 : store.parsed.components }, "$ref" in schemaOrRefObject ? store === null || store === void 0 ? void 0 : store.parser.$refs.get(schemaOrRefObject.$ref) : schemaOrRefObject) : void 0;
284
+ const finalSchema = isPlainObject(schemaOrRefObject) ? Object.assign(getCompileSchemaContext(store === null || store === void 0 ? void 0 : store.parsed), "$ref" in schemaOrRefObject ? store === null || store === void 0 ? void 0 : store.parser.$refs.get(schemaOrRefObject.$ref) : schemaOrRefObject) : void 0;
276
285
  let code = "";
277
286
  if (finalSchema) try {
278
287
  code = await compile(finalSchema, "Req", {
@@ -299,12 +308,13 @@ async function compileResponseParams(operationObject, apiConfig) {
299
308
  const temp = ((_arg$content = arg.content) === null || _arg$content === void 0 ? void 0 : _arg$content["application/json"]) || ((_arg$content2 = arg.content) === null || _arg$content2 === void 0 ? void 0 : _arg$content2["*/*"]);
300
309
  return resolveSchema(temp === null || temp === void 0 ? void 0 : temp.schema);
301
310
  }
311
+ if ("schema" in arg && arg.schema) return resolveSchema(arg.schema);
302
312
  let schema = apiConfig.responseSchemaTransformer(arg);
303
313
  if ("$ref" in schema) return resolveSchema(store === null || store === void 0 ? void 0 : store.parser.$refs.get(schema.$ref));
304
314
  return schema;
305
315
  }
306
316
  const schemaObject = resolveSchema(operationObject.responses["200"]);
307
- const finalSchema = schemaObject ? Object.assign({ components: store === null || store === void 0 ? void 0 : store.parsed.components }, schemaObject) : void 0;
317
+ const finalSchema = schemaObject ? Object.assign(getCompileSchemaContext(store === null || store === void 0 ? void 0 : store.parsed), schemaObject) : void 0;
308
318
  let code = "";
309
319
  if (finalSchema) try {
310
320
  code = await compile(finalSchema, "Res", {
@@ -323,7 +333,7 @@ async function compileResponseParams(operationObject, apiConfig) {
323
333
  else log.error("responseSchemaTransformer 返回值为空,请检查");
324
334
  return code ? code : "export type Res = any;";
325
335
  }
326
-
327
336
  //#endregion
328
337
  export { generateApi };
329
- //# sourceMappingURL=generateApi-Dd7TJHu0.mjs.map
338
+
339
+ //# sourceMappingURL=generateApi-DwdWYQrF.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateApi-DwdWYQrF.mjs","names":[],"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 { AsyncLocalStorage } from 'node:async_hooks';\nimport fs from 'node:fs/promises';\nimport * as os from 'os';\nimport path from 'path';\nimport SwaggerParser from '@apidevtools/swagger-parser';\nimport { camelCase, isPlainObject, merge } from 'es-toolkit';\nimport { compile } from 'json-schema-to-typescript';\nimport type { OpenAPIV2, OpenAPIV3 } from 'openapi-types';\nimport pMap from 'p-map';\nimport { createLogger } from '../../shared';\nimport { ApiConfig, getConfig } from '../../shared/config';\nimport { promptApiConfigEnable } from '../../shared/promptConfigEnable';\n\nconst log = createLogger('generateApi');\n\ntype ParsedDocument = OpenAPIV2.Document | OpenAPIV3.Document;\n\nexport const asyncLocalStorage = new AsyncLocalStorage<{\n parsed: ParsedDocument;\n parser: SwaggerParser;\n}>();\n\nfunction getCompileSchemaContext(parsed: ParsedDocument | undefined) {\n if (!parsed) return {};\n const context: Record<string, unknown> = {};\n if ('components' in parsed && parsed.components) {\n context.components = parsed.components;\n }\n if ('definitions' in parsed && parsed.definitions) {\n context.definitions = parsed.definitions;\n }\n return context;\n}\n\nexport async function generateApi() {\n const config = await getConfig();\n const selectedConfigs = await promptApiConfigEnable(config.api);\n const apiConfigs = selectedConfigs.filter((apiConfig) => {\n if (!apiConfig.output) {\n log.error('配置 %s 缺少 output,已跳过', apiConfig.swaggerJSONPath);\n return false;\n }\n return true;\n });\n const skippedConfigCount = selectedConfigs.length - apiConfigs.length;\n\n if (skippedConfigCount > 0) {\n log.info('由于缺少 output,跳过 %d 个配置', skippedConfigCount);\n }\n\n if (!apiConfigs.length) {\n log.info('没有需要生成的 API 配置,生成流程结束');\n return;\n }\n\n log.info('本次将生成 %d 个 API 配置', apiConfigs.length);\n\n let totalSuccessCount = 0;\n let totalFailedCount = 0;\n const startedAt = Date.now();\n\n const preparedConfigs: ApiConfig[] = [];\n\n for (const apiConfig of apiConfigs) {\n log.info('开始初始化输出目录 %s', apiConfig.output);\n const prepareStartedAt = Date.now();\n try {\n await fs.rm(apiConfig.output!, { recursive: true, force: true });\n await fs.mkdir(apiConfig.output!, { recursive: true });\n preparedConfigs.push(apiConfig);\n log.info(\n '输出目录 %s 初始化完成,耗时 %dms',\n apiConfig.output,\n Date.now() - prepareStartedAt,\n );\n } catch (error) {\n totalFailedCount++;\n const message = error instanceof Error ? error.message : String(error);\n log.error('初始化输出目录 %s 失败:%s', apiConfig.output, message);\n }\n }\n\n if (!preparedConfigs.length) {\n log.error('所有配置都初始化失败,生成流程结束');\n log.info(\n 'generateApi Done,成功 %d 个,失败 %d 个,总耗时 %dms',\n totalSuccessCount,\n totalFailedCount,\n Date.now() - startedAt,\n );\n return;\n }\n\n for (const apiConfig of preparedConfigs) {\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 const bundleStartedAt = Date.now();\n\n let parsed: unknown;\n try {\n // swagger-parser's built-in HTTP resolver fails on remote URLs,\n // so we fetch the JSON ourselves and pass the parsed object instead.\n const isRemoteUrl = /^https?:\\/\\//.test(apiConfig.swaggerJSONPath);\n const bundleInput = isRemoteUrl\n ? await fetch(apiConfig.swaggerJSONPath).then((res) => {\n if (!res.ok)\n throw new Error(`HTTP ${res.status} ${res.statusText}`);\n return res.json();\n })\n : apiConfig.swaggerJSONPath;\n parsed = await parser.bundle(bundleInput, dereferenceConfig);\n log.info(\n '解析 %s 成功,耗时 %dms',\n apiConfig.swaggerJSONPath,\n Date.now() - bundleStartedAt,\n );\n } catch (error) {\n totalFailedCount++;\n const message = error instanceof Error ? error.message : String(error);\n log.error('解析 %s 失败:%s', apiConfig.swaggerJSONPath, message);\n continue;\n }\n\n const state = {\n // only support v3\n parsed: parsed as OpenAPIV3.Document,\n parser,\n };\n\n let generatedCount = 0;\n let skippedCount = 0;\n const pathEntries = Object.entries(\n (parsed as OpenAPIV3.Document).paths ?? {},\n );\n if (!pathEntries.length) {\n log.error('%s 中没有可用的 paths,已跳过', apiConfig.swaggerJSONPath);\n totalFailedCount++;\n continue;\n }\n\n await asyncLocalStorage.run(state, async () => {\n await pMap(pathEntries, async ([url, pathItemObject]) => {\n if (!pathItemObject) {\n log.error('路径 %s 未定义 pathItemObject,已跳过', url);\n skippedCount++;\n return;\n }\n\n log.info('开始生成 %s', url);\n let generatedForUrl = 0;\n await pMap(\n ['get', 'put', 'post', 'delete', 'patch'],\n async (method) => {\n const operationObject = pathItemObject[method];\n if (!operationObject) {\n return;\n }\n\n try {\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), {\n recursive: true,\n });\n await fs.writeFile(outputPath, code);\n generatedCount++;\n generatedForUrl++;\n } catch (error) {\n skippedCount++;\n const message =\n error instanceof Error ? error.message : String(error);\n log.error(\n '%s %s 生成失败:%s',\n method.toUpperCase(),\n url,\n message,\n );\n }\n },\n );\n if (generatedForUrl === 0) {\n log.info('路径 %s 未生成任何方法', url);\n }\n });\n });\n\n if (!generatedCount) {\n log.error('%s 未生成任何请求,已标记失败', apiConfig.swaggerJSONPath);\n totalFailedCount++;\n continue;\n }\n\n if (apiConfig.codeFormatterCmd) {\n const { exec } = await import('child_process');\n await new Promise<void>((resolve) => {\n exec(\n `${apiConfig.codeFormatterCmd} \"${apiConfig.output!}\"`,\n (error) => {\n if (error) {\n skippedCount++;\n log.error(`Code formatting failed: ${error.message}`);\n } else {\n log.info(`Code formatting success`);\n }\n resolve();\n },\n );\n });\n }\n\n log.info(\n '%s 生成完成,共生成 %d 个请求,跳过 %d 个',\n apiConfig.swaggerJSONPath,\n generatedCount,\n skippedCount,\n );\n totalSuccessCount++;\n }\n\n log.info(\n 'generateApi Done,成功 %d 个,失败 %d 个,总耗时 %dms',\n totalSuccessCount,\n totalFailedCount,\n Date.now() - startedAt,\n );\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 const store = asyncLocalStorage.getStore();\n const schemaOrRefObject = (() => {\n if (operationObject.requestBody) {\n if ('$ref' in operationObject.requestBody) {\n return operationObject.requestBody;\n }\n return operationObject.requestBody.content['application/json'].schema;\n }\n 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 const required = parameters\n .filter(\n (p) =>\n 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 const schema = p.schema;\n return [\n p.name,\n {\n ...schema,\n description: p.description,\n // enum: schema.enum ?? [],\n },\n ];\n }),\n );\n return {\n required,\n type: 'object',\n properties: { ...properties, ...extraProperties },\n };\n }\n })();\n\n const finalSchema = isPlainObject(schemaOrRefObject)\n ? Object.assign(\n getCompileSchemaContext(store?.parsed),\n '$ref' in schemaOrRefObject\n ? store?.parser.$refs.get(schemaOrRefObject.$ref)\n : schemaOrRefObject,\n )\n : void 0;\n\n let code = '';\n if (finalSchema) {\n try {\n code = await compile(finalSchema as never, '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 store = asyncLocalStorage.getStore();\n\n function resolveSchema(\n arg:\n | OpenAPIV3.ReferenceObject\n | OpenAPIV3.ResponseObject\n | OpenAPIV3.MediaTypeObject\n | undefined,\n ) {\n if (!arg) return;\n\n if ('content' in arg) {\n const temp = arg.content?.['application/json'] || arg.content?.['*/*'];\n return resolveSchema(temp?.schema);\n }\n // 兼容 swagger v2 的 response.schema\n if ('schema' in arg && arg.schema) {\n return resolveSchema(arg.schema as never);\n }\n\n let schema = apiConfig.responseSchemaTransformer!(arg as never) as\n | OpenAPIV3.ReferenceObject\n | OpenAPIV3.SchemaObject;\n if ('$ref' in schema) {\n return resolveSchema(store?.parser.$refs.get(schema.$ref) as never);\n }\n return schema;\n }\n const schemaObject = resolveSchema(operationObject.responses['200']);\n const finalSchema = schemaObject\n ? Object.assign(getCompileSchemaContext(store?.parsed), schemaObject)\n : void 0;\n\n let code = '';\n if (finalSchema) {\n try {\n code = await compile(finalSchema, 'Res', {\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 error: e.message,\n operationId: operationObject.operationId,\n });\n }\n } else {\n log.error('responseSchemaTransformer 返回值为空,请检查');\n }\n\n return code ? code : 'export type Res = any;';\n}\n"],"mappings":";;;;;;;;;;;;AAEA,MAAM,EAAE,WAAW;AAanB,eAAsB,mBAAsB,KAAa;CACvD,MAAM,EAAE,WAAW,kBAAkB;AAErC,KAAI,UAAU,UAAU,EACtB,QAAO;CAYT,MAAM,MAAM,MAAM,OAA8B;EAC9C,MAAM;EACN,SAAS;EAET,MAAM;EACN,MAAM;EACN,SAAS,OAAO;AACd,UAAO,MAAM,WAAW,IAAI,WAAW;;EAEzC,SAlBc,CACd;GACE,MAAM;GACN,SAAS;GACT,SAAS,UAAU,KAAK,SAAS;AAC/B,WAAO,cAAc,KAAK;KAC1B;GACH,CACF;EAWA,CAAC;AAEF,WAAU,SAAS,SAAS;AAC1B,OAAK,UAAU,IAAI,eAAe,IAAI,SAAS,KAAK;GACpD;AAEF,QAAO,UAAU,QAAQ,MAAM,EAAE,QAAQ;;AAG3C,SAAgB,sBAAsB,WAAoC;AACxE,QAAO,mBAAmB;EACxB,WAAW,aAAa,EAAE;EAC1B,gBAAgB,SAAS;AACvB,UAAO;IACL,MAAM,KAAK;IACX,MAAM,oBAAoB,KAAK;IAChC;;EAEH,iBAAiB,YAAY,SAAS;AACpC,UAAO,WAAW,SAAS,KAAK,OAAQ;;EAE3C,CAAC;;;;ACjDJ,MAAM,MAAM,aAAa,cAAc;AAIvC,MAAa,oBAAoB,IAAI,mBAGjC;AAEJ,SAAS,wBAAwB,QAAoC;AACnE,KAAI,CAAC,OAAQ,QAAO,EAAE;CACtB,MAAM,UAAmC,EAAE;AAC3C,KAAI,gBAAgB,UAAU,OAAO,WACnC,SAAQ,aAAa,OAAO;AAE9B,KAAI,iBAAiB,UAAU,OAAO,YACpC,SAAQ,cAAc,OAAO;AAE/B,QAAO;;AAGT,eAAsB,cAAc;CAElC,MAAM,kBAAkB,MAAM,uBADf,MAAM,WAAW,EAC2B,IAAI;CAC/D,MAAM,aAAa,gBAAgB,QAAQ,cAAc;AACvD,MAAI,CAAC,UAAU,QAAQ;AACrB,OAAI,MAAM,uBAAuB,UAAU,gBAAgB;AAC3D,UAAO;;AAET,SAAO;GACP;CACF,MAAM,qBAAqB,gBAAgB,SAAS,WAAW;AAE/D,KAAI,qBAAqB,EACvB,KAAI,KAAK,yBAAyB,mBAAmB;AAGvD,KAAI,CAAC,WAAW,QAAQ;AACtB,MAAI,KAAK,wBAAwB;AACjC;;AAGF,KAAI,KAAK,qBAAqB,WAAW,OAAO;CAEhD,IAAI,oBAAoB;CACxB,IAAI,mBAAmB;CACvB,MAAM,YAAY,KAAK,KAAK;CAE5B,MAAM,kBAA+B,EAAE;AAEvC,MAAK,MAAM,aAAa,YAAY;AAClC,MAAI,KAAK,gBAAgB,UAAU,OAAO;EAC1C,MAAM,mBAAmB,KAAK,KAAK;AACnC,MAAI;AACF,SAAM,GAAG,GAAG,UAAU,QAAS;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;AAChE,SAAM,GAAG,MAAM,UAAU,QAAS,EAAE,WAAW,MAAM,CAAC;AACtD,mBAAgB,KAAK,UAAU;AAC/B,OAAI,KACF,yBACA,UAAU,QACV,KAAK,KAAK,GAAG,iBACd;WACM,OAAO;AACd;GACA,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,OAAI,MAAM,oBAAoB,UAAU,QAAQ,QAAQ;;;AAI5D,KAAI,CAAC,gBAAgB,QAAQ;AAC3B,MAAI,MAAM,oBAAoB;AAC9B,MAAI,KACF,6CACA,mBACA,kBACA,KAAK,KAAK,GAAG,UACd;AACD;;AAGF,MAAK,MAAM,aAAa,iBAAiB;AACvC,MAAI,KAAK,WAAW,UAAU,gBAAgB;EAC9C,MAAM,oBAAoB,MACxB,EACE,SAAS,EACP,MAAM,EACJ,SAAS,KAAK,KACf,EACF,EACF,EACD,UAAU,4BAA4B,EAAE,CACzC;EACD,MAAM,SAAS,IAAI,eAAe;EAClC,MAAM,kBAAkB,KAAK,KAAK;EAElC,IAAI;AACJ,MAAI;GAIF,MAAM,cADc,eAAe,KAAK,UAAU,gBAAgB,GAE9D,MAAM,MAAM,UAAU,gBAAgB,CAAC,MAAM,QAAQ;AACnD,QAAI,CAAC,IAAI,GACP,OAAM,IAAI,MAAM,QAAQ,IAAI,OAAO,GAAG,IAAI,aAAa;AACzD,WAAO,IAAI,MAAM;KACjB,GACF,UAAU;AACd,YAAS,MAAM,OAAO,OAAO,aAAa,kBAAkB;AAC5D,OAAI,KACF,oBACA,UAAU,iBACV,KAAK,KAAK,GAAG,gBACd;WACM,OAAO;AACd;GACA,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,OAAI,MAAM,eAAe,UAAU,iBAAiB,QAAQ;AAC5D;;EAGF,MAAM,QAAQ;GAEJ;GACR;GACD;EAED,IAAI,iBAAiB;EACrB,IAAI,eAAe;EACnB,MAAM,cAAc,OAAO,QACxB,OAA8B,SAAS,EAAE,CAC3C;AACD,MAAI,CAAC,YAAY,QAAQ;AACvB,OAAI,MAAM,uBAAuB,UAAU,gBAAgB;AAC3D;AACA;;AAGF,QAAM,kBAAkB,IAAI,OAAO,YAAY;AAC7C,SAAM,KAAK,aAAa,OAAO,CAAC,KAAK,oBAAoB;AACvD,QAAI,CAAC,gBAAgB;AACnB,SAAI,MAAM,gCAAgC,IAAI;AAC9C;AACA;;AAGF,QAAI,KAAK,WAAW,IAAI;IACxB,IAAI,kBAAkB;AACtB,UAAM,KACJ;KAAC;KAAO;KAAO;KAAQ;KAAU;KAAQ,EACzC,OAAO,WAAW;KAChB,MAAM,kBAAkB,eAAe;AACvC,SAAI,CAAC,gBACH;AAGF,SAAI;MACF,MAAM,OAAO,MAAM,uBAAuB;OACnC;OACG;OACS;OACjB;OACD,CAAC;MACF,MAAM,aAAa,KAChB,KACC,UAAU,QACV,KACA,UAAU,WAAW,GAAG,OAAO,OAAO,GAAG,OAAO,KACjD,CACA,QAAQ,MAAM,IAAI;AACrB,YAAM,GAAG,MAAM,KAAK,QAAQ,WAAW,EAAE,EACvC,WAAW,MACZ,CAAC;AACF,YAAM,GAAG,UAAU,YAAY,KAAK;AACpC;AACA;cACO,OAAO;AACd;MACA,MAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACxD,UAAI,MACF,iBACA,OAAO,aAAa,EACpB,KACA,QACD;;MAGN;AACD,QAAI,oBAAoB,EACtB,KAAI,KAAK,iBAAiB,IAAI;KAEhC;IACF;AAEF,MAAI,CAAC,gBAAgB;AACnB,OAAI,MAAM,oBAAoB,UAAU,gBAAgB;AACxD;AACA;;AAGF,MAAI,UAAU,kBAAkB;GAC9B,MAAM,EAAE,SAAS,MAAM,OAAO;AAC9B,SAAM,IAAI,SAAe,YAAY;AACnC,SACE,GAAG,UAAU,iBAAiB,IAAI,UAAU,OAAQ,KACnD,UAAU;AACT,SAAI,OAAO;AACT;AACA,UAAI,MAAM,2BAA2B,MAAM,UAAU;WAErD,KAAI,KAAK,0BAA0B;AAErC,cAAS;MAEZ;KACD;;AAGJ,MAAI,KACF,8BACA,UAAU,iBACV,gBACA,aACD;AACD;;AAGF,KAAI,KACF,6CACA,mBACA,kBACA,KAAK,KAAK,GAAG,UACd;;;;;AAMH,eAAsB,uBAAuB,SAKzB;;CAClB,MAAM,EAAE,QAAQ,iBAAiB,cAAc;CAE/C,MAAM,aAAa;AACjB,MAAI,OAAO,UAAU,mBAAmB,SACtC,QAAO,GAAG,UAAU,iBAAiB,QAAQ;AAE/C,MAAI,OAAO,UAAU,mBAAmB,WACtC,QAAO,UAAU,eAAe,QAAQ,IAAI;AAE9C,SAAO,QAAQ;KACb;CAEJ,MAAM,SAAS,UAAU,eACrB,GAAG,UAAU,aAAa,IAAI,mBAC5B,KAAA,wBAAG,gBAAgB,UAAA,QAAA,0BAAA,KAAA,IAAA,KAAA,IAAA,sBAAM,KAAK,IAAI,KAAI,GAAG,GACvC,gBAAgB,cAEnB,KACD;CAGJ,IAAI,qBAAqB,UAAU,GAAG,QAAQ,IAAI,GAAG,OAAO,MAAM;AAGlE,KAAI,CAAC,6BAA6B,KAAK,mBAAmB,CAExD,sBAAqB,IAAI;CAI3B,MAAM,gBAAgB,iBACnB,gBAAgB,cAAwB,EAAE,CAC5C;CACD,MAAM,oBAAoB,cAAc,SACpC,kBAAkB,KAAK,UAAU,cAAc,CAAC,KAChD;CAGJ,IAAI,OAAiB;EACnB;EACA,UAAU;EACV,UAAU;EAEV;EACA,OAAO,gBAAgB;EACvB,cAAA,yBAAa,gBAAgB,UAAA,QAAA,2BAAA,KAAA,IAAA,KAAA,IAAA,uBAAM,KAAK,IAAI;EAC5C,UAAU,YAAY;EACtB;EACD,CAAC,OAAO,QAAQ;CAGjB,IAAI,cAAc;eACL,mBAAmB;UACxB,IAAI;aACD,OAAO;IAChB,kBAAkB;IAClB,UAAU,wBAAwB,iBAAiB,GAAG;KAGrD,QAAQ,WAAW,MAAM,GAAG,MAAM,IAAI;AACzC,KAAI,UAAU,SACZ,eAAc,YAAY,QACxB,uBACA,sBAAsB,mBAAmB,QAAQ,mBAAmB,QACrE;AAEH,MAAK,KAAK,YAAY;AAEtB,KAAI,UAAU,UAAU;EACtB,MAAM,CAAC,uBAAuB,0BAA0B,MAAM,QAAQ,IAAI,CAExE,qBAAqB,gBAAgB,EAErC,sBAAsB,iBAAiB,UAAU,CAClD,CAAC;AAEF,OAAK,KAAK;mBACK,mBAAmB;GACnC,sBAAsB,KAAK;;GAE3B,uBAAuB;IACtB;;AAGF,QAAO,KAAK,KAAK,GAAG,IAAI;;AAG1B,SAAS,iBAAiB,YAAyC;AACjE,QAAO,WACJ,QAAQ,SAAS,KAAK,OAAO,OAAO,CACpC,KAAK,SAAS,KAAK,KAAK;;;;;AAM7B,eAAe,qBACb,iBACA;CACA,MAAM,QAAQ,kBAAkB,UAAU;CAC1C,MAAM,2BAA2B;AAC/B,MAAI,gBAAgB,aAAa;AAC/B,OAAI,UAAU,gBAAgB,YAC5B,QAAO,gBAAgB;AAEzB,UAAO,gBAAgB,YAAY,QAAQ,oBAAoB;;AAEjE,MAAI,gBAAgB,YAAY;GAC9B,MAAM,kBAAkB,EAAE;GAC1B,MAAM,aAA0C,EAAE;AACjD,mBAAgB,WAA2C,SACzD,SAAS;AACR,QAAI,CAAC,CAAC,SAAS,OAAO,CAAC,SAAS,KAAK,GAAG,CACtC;AAEF,QACE,KAAK,UACL,UAAU,KAAK,UACf,KAAK,OAAO,SAAS,SAGrB,QAAO,OACL,iBACC,KAAK,OAAkC,cAAc,EAAE,CACzD;QAED,YAAW,KAAK,KAAK;KAG1B;AAwBD,UAAO;IACL,UAvBe,WACd,QACE,MACC,EAAE,YAAY,CAAC;KAAC;KAAW;KAAY;KAAQ,CAAC,SAAS,EAAE,KAAK,CACnE,CACA,KAAK,MAAM,EAAE,KAAK;IAmBnB,MAAM;IACN,YAAY;KAAE,GAnBG,OAAO,YACxB,WAEG,QAAQ,MAAM,CAAC,CAAC,EAAE,OAAO,CACzB,KAAK,MAAM;MACV,MAAM,SAAS,EAAE;AACjB,aAAO,CACL,EAAE,MACF;OACE,GAAG;OACH,aAAa,EAAE;OAEhB,CACF;OACD,CACL;KAI8B,GAAG;KAAiB;IAClD;;KAED;CAEJ,MAAM,cAAc,cAAc,kBAAkB,GAChD,OAAO,OACL,wBAAA,UAAA,QAAA,UAAA,KAAA,IAAA,KAAA,IAAwB,MAAO,OAAO,EACtC,UAAU,oBAAA,UAAA,QAAA,UAAA,KAAA,IAAA,KAAA,IACN,MAAO,OAAO,MAAM,IAAI,kBAAkB,KAAK,GAC/C,kBACL,GACD,KAAK;CAET,IAAI,OAAO;AACX,KAAI,YACF,KAAI;AACF,SAAO,MAAM,QAAQ,aAAsB,OAAO;GAChD,eAAe;GACf,sBAAsB;GACtB,sBAAsB;GACtB,YAAY;GAEb,CAAC;UACK,GAAG;AACV,MAAI,MAAM,qBAAqB;GAC7B,SAAS,gBAAgB;GACzB,SAAS,EAAE;GACX,aAAa,gBAAgB;GAC9B,CAAC;;AAIN,QAAO,EACL,MAAM,QAAQ,0BACf;;AAGH,eAAe,sBACb,iBACA,WACA;CACA,MAAM,QAAQ,kBAAkB,UAAU;CAE1C,SAAS,cACP,KAKA;AACA,MAAI,CAAC,IAAK;AAEV,MAAI,aAAa,KAAK;;GACpB,MAAM,SAAA,eAAO,IAAI,aAAA,QAAA,iBAAA,KAAA,IAAA,KAAA,IAAA,aAAU,0BAAA,gBAAuB,IAAI,aAAA,QAAA,kBAAA,KAAA,IAAA,KAAA,IAAA,cAAU;AAChE,UAAO,cAAA,SAAA,QAAA,SAAA,KAAA,IAAA,KAAA,IAAc,KAAM,OAAO;;AAGpC,MAAI,YAAY,OAAO,IAAI,OACzB,QAAO,cAAc,IAAI,OAAgB;EAG3C,IAAI,SAAS,UAAU,0BAA2B,IAAa;AAG/D,MAAI,UAAU,OACZ,QAAO,cAAA,UAAA,QAAA,UAAA,KAAA,IAAA,KAAA,IAAc,MAAO,OAAO,MAAM,IAAI,OAAO,KAAK,CAAU;AAErE,SAAO;;CAET,MAAM,eAAe,cAAc,gBAAgB,UAAU,OAAO;CACpE,MAAM,cAAc,eAChB,OAAO,OAAO,wBAAA,UAAA,QAAA,UAAA,KAAA,IAAA,KAAA,IAAwB,MAAO,OAAO,EAAE,aAAa,GACnE,KAAK;CAET,IAAI,OAAO;AACX,KAAI,YACF,KAAI;AACF,SAAO,MAAM,QAAQ,aAAa,OAAO;GACvC,eAAe;GACf,sBAAsB;GACtB,sBAAsB;GACtB,YAAY;GAEb,CAAC;UACK,GAAG;AACV,MAAI,MAAM,qBAAqB;GAC7B,SAAS,gBAAgB;GACzB,OAAO,EAAE;GACT,aAAa,gBAAgB;GAC9B,CAAC;;KAGJ,KAAI,MAAM,sCAAsC;AAGlD,QAAO,OAAO,OAAO"}
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as Config, t as ApiConfig } from "./types-BRp2czbi.mjs";
1
+ import { n as Config, t as ApiConfig } from "./types-PHOcXvPc.mjs";
2
2
 
3
3
  //#region src/shared/config/index.d.ts
4
4
  declare function defineConfig<T extends Config = Config>(c: T): T;
package/dist/index.mjs CHANGED
@@ -1,5 +1,4 @@
1
- import { n as defineConfig, r as getConfig, t as configName } from "./config-9MrZts4R.mjs";
2
-
1
+ import { n as defineConfig, r as getConfig, t as configName } from "./config-CF5PxwnQ.mjs";
3
2
  //#region src/shared/defaultJsonSorter.ts
4
3
  /**
5
4
  * 对 JSON 对象的键进行排序
@@ -12,7 +11,6 @@ function defaultJsonSorter(obj) {
12
11
  return acc;
13
12
  }, {});
14
13
  }
15
-
16
14
  //#endregion
17
15
  //#region src/shared/letters.ts
18
16
  /**
@@ -59,7 +57,7 @@ function numberToLetter(n) {
59
57
  while (digits.length) chars.push(alphabet[digits.pop()]);
60
58
  return chars.join("");
61
59
  }
62
-
63
60
  //#endregion
64
61
  export { configName, defaultJsonSorter, defineConfig, getConfig, letterToNumber, numberToLetter };
62
+
65
63
  //# sourceMappingURL=index.mjs.map
@@ -1 +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"}
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"}
@@ -1,8 +1,7 @@
1
- import { t as configName } from "./config-9MrZts4R.mjs";
1
+ import { t as configName } from "./config-CF5PxwnQ.mjs";
2
2
  import { n as createLogger } from "./cli.mjs";
3
3
  import path from "path";
4
4
  import fs from "node:fs/promises";
5
-
6
5
  //#region src/commands/initConfig.ts
7
6
  const log = createLogger("initConfig");
8
7
  const tpl = `\
@@ -22,7 +21,7 @@ const initConfig = async () => {
22
21
  await fs.writeFile(configPath, tpl);
23
22
  log.info(`config file created`);
24
23
  };
25
-
26
24
  //#endregion
27
25
  export { initConfig };
28
- //# sourceMappingURL=initConfig-D8kYF-u1.mjs.map
26
+
27
+ //# sourceMappingURL=initConfig-DCOS9II9.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"initConfig-D8kYF-u1.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"}
1
+ {"version":3,"file":"initConfig-DCOS9II9.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"}
@@ -1,6 +1,5 @@
1
1
  import { n as createLogger, t as cli } from "./cli.mjs";
2
2
  import enquirer from "enquirer";
3
-
4
3
  //#region src/commands/interactive.ts
5
4
  const { prompt } = enquirer;
6
5
  const log = createLogger("interactive");
@@ -32,7 +31,7 @@ const interactive = async (args) => {
32
31
  }
33
32
  (_command$commandActio = command.commandAction) === null || _command$commandActio === void 0 || _command$commandActio.apply(cli, args);
34
33
  };
35
-
36
34
  //#endregion
37
35
  export { interactive };
38
- //# sourceMappingURL=interactive-FF1hLdGL.mjs.map
36
+
37
+ //# sourceMappingURL=interactive-CK8WpuBn.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"interactive-FF1hLdGL.mjs","names":[],"sources":["../src/commands/interactive.ts"],"sourcesContent":["import enquirer from 'enquirer';\nimport { cli, createLogger } from '../shared';\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,YAAY;AAChD,MAAI,QAAQ,KACV,QAAO,CAAC,QAAQ,KAAK,WAAW,KAAK,IAAI,QAAQ,SAAS;AAE5D,SAAO;GACP;CAEF,MAAM,6BAAa,IAAI,KAAwC;CAC/D,MAAM,MAAM,MAAM,OAA4B;EAC5C,MAAM;EACN,MAAM;EACN,SAAS;EACT,SAAS,SAAS,KAAK,YAAY;AACjC,cAAW,IAAI,QAAQ,MAAM,QAAQ;AACrC,UAAO;IACL,MAAM,QAAQ;IACd,OAAO,QAAQ;IACf,SAAS,QAAQ;IACjB,MAAM,QAAQ,IAAI,KAAK,GAAG,QAAQ;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"}
1
+ {"version":3,"file":"interactive-CK8WpuBn.mjs","names":[],"sources":["../src/commands/interactive.ts"],"sourcesContent":["import enquirer from 'enquirer';\nimport { cli, createLogger } from '../shared';\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,YAAY;AAChD,MAAI,QAAQ,KACV,QAAO,CAAC,QAAQ,KAAK,WAAW,KAAK,IAAI,QAAQ,SAAS;AAE5D,SAAO;GACP;CAEF,MAAM,6BAAa,IAAI,KAAwC;CAC/D,MAAM,MAAM,MAAM,OAA4B;EAC5C,MAAM;EACN,MAAM;EACN,SAAS;EACT,SAAS,SAAS,KAAK,YAAY;AACjC,cAAW,IAAI,QAAQ,MAAM,QAAQ;AACrC,UAAO;IACL,MAAM,QAAQ;IACd,OAAO,QAAQ;IACf,SAAS,QAAQ;IACjB,MAAM,QAAQ,IAAI,KAAK,GAAG,QAAQ;IACnC;IACD;EACH,CAAC;CACF,MAAM,UAAU,WAAW,IAAI,IAAI,QAAQ;AAC3C,KAAI,CAAC,SAAS;AACZ,MAAI,MAAM,YAAY,IAAI,QAAQ;AAClC;;AAEF,EAAA,wBAAA,QAAQ,mBAAA,QAAA,0BAAA,KAAA,KAAA,sBAAe,MAAM,KAAK,KAAK"}
@@ -1,4 +1,4 @@
1
- import { n as Config, t as ApiConfig } from "./types-BRp2czbi.mjs";
1
+ import { n as Config, t as ApiConfig } from "./types-PHOcXvPc.mjs";
2
2
 
3
3
  //#region src/shared/config/normalizeConfig.d.ts
4
4
  declare function normalizeConfig(config: Config): Config;
@@ -1,5 +1,4 @@
1
1
  import path from "path";
2
-
3
2
  //#region src/shared/config/normalizeConfig.ts
4
3
  function normalizeConfig(config) {
5
4
  config.cwd ??= process.cwd();
@@ -20,7 +19,7 @@ function apiConfigNormalizer(item) {
20
19
  };
21
20
  return item;
22
21
  }
23
-
24
22
  //#endregion
25
23
  export { apiConfigNormalizer, normalizeConfig };
24
+
26
25
  //# sourceMappingURL=normalizeConfig.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalizeConfig.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 ??= 'oxfmt';\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"}
1
+ {"version":3,"file":"normalizeConfig.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 ??= 'oxfmt';\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,gBAAA,QAAA,uBAAA,KAAA,IAAA,KAAA,IAAA,mBAAY,SAAQ;;AAC7B,QAAO"}
@@ -386,4 +386,4 @@ interface Config {
386
386
  }
387
387
  //#endregion
388
388
  export { Config as n, ApiConfig as t };
389
- //# sourceMappingURL=types-BRp2czbi.d.mts.map
389
+ //# sourceMappingURL=types-PHOcXvPc.d.mts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dune2/cli",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/liaoyinglong/next-tools.git",
@@ -40,10 +40,10 @@
40
40
  "p-map": "^7.0.4"
41
41
  },
42
42
  "devDependencies": {
43
- "@types/debug": "^4.1.12",
43
+ "@types/debug": "^4.1.7",
44
44
  "openapi-types": "^12.0.2",
45
45
  "prettier": "^3.8.1",
46
- "tsdown": "^0.20.3"
46
+ "tsdown": "^0.21.0"
47
47
  },
48
48
  "scripts": {
49
49
  "build": "tsdown --splitting --clean",
@@ -1 +0,0 @@
1
- {"version":3,"file":"generateApi-Dd7TJHu0.mjs","names":[],"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 { AsyncLocalStorage } from 'node:async_hooks';\nimport fs from 'node:fs/promises';\nimport * as os from 'os';\nimport path from 'path';\nimport SwaggerParser from '@apidevtools/swagger-parser';\nimport { camelCase, isPlainObject, merge } from 'es-toolkit';\nimport { compile } from 'json-schema-to-typescript';\nimport type { OpenAPIV3 } from 'openapi-types';\nimport pMap from 'p-map';\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: OpenAPIV3.Document;\n parser: SwaggerParser;\n}>();\n\nexport async function generateApi() {\n const config = await getConfig();\n const selectedConfigs = await promptApiConfigEnable(config.api);\n const apiConfigs = selectedConfigs.filter((apiConfig) => {\n if (!apiConfig.output) {\n log.error('配置 %s 缺少 output,已跳过', apiConfig.swaggerJSONPath);\n return false;\n }\n return true;\n });\n const skippedConfigCount = selectedConfigs.length - apiConfigs.length;\n\n if (skippedConfigCount > 0) {\n log.info('由于缺少 output,跳过 %d 个配置', skippedConfigCount);\n }\n\n if (!apiConfigs.length) {\n log.info('没有需要生成的 API 配置,生成流程结束');\n return;\n }\n\n log.info('本次将生成 %d 个 API 配置', apiConfigs.length);\n\n let totalSuccessCount = 0;\n let totalFailedCount = 0;\n const startedAt = Date.now();\n\n const preparedConfigs: ApiConfig[] = [];\n\n for (const apiConfig of apiConfigs) {\n log.info('开始初始化输出目录 %s', apiConfig.output);\n const prepareStartedAt = Date.now();\n try {\n await fs.rm(apiConfig.output!, { recursive: true, force: true });\n await fs.mkdir(apiConfig.output!, { recursive: true });\n preparedConfigs.push(apiConfig);\n log.info(\n '输出目录 %s 初始化完成,耗时 %dms',\n apiConfig.output,\n Date.now() - prepareStartedAt,\n );\n } catch (error) {\n totalFailedCount++;\n const message = error instanceof Error ? error.message : String(error);\n log.error('初始化输出目录 %s 失败:%s', apiConfig.output, message);\n }\n }\n\n if (!preparedConfigs.length) {\n log.error('所有配置都初始化失败,生成流程结束');\n log.info(\n 'generateApi Done,成功 %d 个,失败 %d 个,总耗时 %dms',\n totalSuccessCount,\n totalFailedCount,\n Date.now() - startedAt,\n );\n return;\n }\n\n for (const apiConfig of preparedConfigs) {\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 const bundleStartedAt = Date.now();\n\n let parsed: unknown;\n try {\n parsed = await parser.bundle(\n apiConfig.swaggerJSONPath,\n dereferenceConfig,\n );\n log.info(\n '解析 %s 成功,耗时 %dms',\n apiConfig.swaggerJSONPath,\n Date.now() - bundleStartedAt,\n );\n } catch (error) {\n totalFailedCount++;\n const message = error instanceof Error ? error.message : String(error);\n log.error('解析 %s 失败:%s', apiConfig.swaggerJSONPath, message);\n continue;\n }\n\n const state = {\n // only support v3\n parsed: parsed as OpenAPIV3.Document,\n parser,\n };\n\n let generatedCount = 0;\n let skippedCount = 0;\n const pathEntries = Object.entries(\n (parsed as OpenAPIV3.Document).paths ?? {},\n );\n if (!pathEntries.length) {\n log.error('%s 中没有可用的 paths,已跳过', apiConfig.swaggerJSONPath);\n totalFailedCount++;\n continue;\n }\n\n await asyncLocalStorage.run(state, async () => {\n await pMap(pathEntries, async ([url, pathItemObject]) => {\n if (!pathItemObject) {\n log.error('路径 %s 未定义 pathItemObject,已跳过', url);\n skippedCount++;\n return;\n }\n\n log.info('开始生成 %s', url);\n let generatedForUrl = 0;\n await pMap(\n ['get', 'put', 'post', 'delete', 'patch'],\n async (method) => {\n const operationObject = pathItemObject[method];\n if (!operationObject) {\n return;\n }\n\n try {\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), {\n recursive: true,\n });\n await fs.writeFile(outputPath, code);\n generatedCount++;\n generatedForUrl++;\n } catch (error) {\n skippedCount++;\n const message =\n error instanceof Error ? error.message : String(error);\n log.error(\n '%s %s 生成失败:%s',\n method.toUpperCase(),\n url,\n message,\n );\n }\n },\n );\n if (generatedForUrl === 0) {\n log.info('路径 %s 未生成任何方法', url);\n }\n });\n });\n\n if (!generatedCount) {\n log.error('%s 未生成任何请求,已标记失败', apiConfig.swaggerJSONPath);\n totalFailedCount++;\n continue;\n }\n\n if (apiConfig.codeFormatterCmd) {\n const { exec } = await import('child_process');\n await new Promise<void>((resolve) => {\n exec(\n `${apiConfig.codeFormatterCmd} \"${apiConfig.output!}\"`,\n (error) => {\n if (error) {\n skippedCount++;\n log.error(`Code formatting failed: ${error.message}`);\n } else {\n log.info(`Code formatting success`);\n }\n resolve();\n },\n );\n });\n }\n\n log.info(\n '%s 生成完成,共生成 %d 个请求,跳过 %d 个',\n apiConfig.swaggerJSONPath,\n generatedCount,\n skippedCount,\n );\n totalSuccessCount++;\n }\n\n log.info(\n 'generateApi Done,成功 %d 个,失败 %d 个,总耗时 %dms',\n totalSuccessCount,\n totalFailedCount,\n Date.now() - startedAt,\n );\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 const store = asyncLocalStorage.getStore();\n const schemaOrRefObject = (() => {\n if (operationObject.requestBody) {\n if ('$ref' in operationObject.requestBody) {\n return operationObject.requestBody;\n }\n return operationObject.requestBody.content['application/json'].schema;\n }\n 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 const required = parameters\n .filter(\n (p) =>\n 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 const schema = p.schema;\n return [\n p.name,\n {\n ...schema,\n description: p.description,\n // enum: schema.enum ?? [],\n },\n ];\n }),\n );\n return {\n required,\n type: 'object',\n properties: { ...properties, ...extraProperties },\n };\n }\n })();\n\n const finalSchema = isPlainObject(schemaOrRefObject)\n ? Object.assign(\n {\n components: store?.parsed.components,\n },\n '$ref' in schemaOrRefObject\n ? store?.parser.$refs.get(schemaOrRefObject.$ref)\n : schemaOrRefObject,\n )\n : void 0;\n\n let code = '';\n if (finalSchema) {\n try {\n code = await compile(finalSchema as never, '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 store = asyncLocalStorage.getStore();\n\n function resolveSchema(\n arg:\n | OpenAPIV3.ReferenceObject\n | OpenAPIV3.ResponseObject\n | OpenAPIV3.MediaTypeObject\n | undefined,\n ) {\n if (!arg) return;\n\n if ('content' in arg) {\n const temp = arg.content?.['application/json'] || arg.content?.['*/*'];\n return resolveSchema(temp?.schema);\n }\n\n let schema = apiConfig.responseSchemaTransformer!(arg as never) as\n | OpenAPIV3.ReferenceObject\n | OpenAPIV3.SchemaObject;\n if ('$ref' in schema) {\n return resolveSchema(store?.parser.$refs.get(schema.$ref) as never);\n }\n return schema;\n }\n const schemaObject = resolveSchema(operationObject.responses['200']);\n const finalSchema = schemaObject\n ? Object.assign(\n {\n components: store?.parsed.components,\n },\n schemaObject,\n )\n : void 0;\n\n let code = '';\n if (finalSchema) {\n try {\n code = await compile(finalSchema, 'Res', {\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 error: e.message,\n operationId: operationObject.operationId,\n });\n }\n } else {\n log.error('responseSchemaTransformer 返回值为空,请检查');\n }\n\n return code ? code : 'export type Res = any;';\n}\n"],"mappings":"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"}