@dune2/cli 1.2.3 → 1.2.5

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
@@ -2,7 +2,7 @@
2
2
  import cac from "cac";
3
3
  import debug from "debug";
4
4
  //#region package.json
5
- var version = "1.2.2";
5
+ var version = "1.2.4";
6
6
  //#endregion
7
7
  //#region src/shared/index.ts
8
8
  const cli = cac("dune");
@@ -18,7 +18,7 @@ debug.enable(`${cli.name}:*`);
18
18
  //#endregion
19
19
  //#region src/cli.ts
20
20
  cli.command("generateApi", "生成 api 文件").example("dune generateApi").action(async () => {
21
- const { generateApi } = await import("./generateApi-th-P08qy.mjs");
21
+ const { generateApi } = await import("./generateApi-MKVHBsOV.mjs");
22
22
  await generateApi();
23
23
  });
24
24
  cli.command("init", "初始化配置文件").example("dune init").action(async () => {
@@ -26,11 +26,11 @@ cli.command("init", "初始化配置文件").example("dune init").action(async (
26
26
  await initConfig();
27
27
  });
28
28
  cli.command("interactive", "交互式操作").example("dune interactive").alias("i").action(async (args) => {
29
- const { interactive } = await import("./interactive-CK8WpuBn.mjs");
29
+ const { interactive } = await import("./interactive-OXXqccQf.mjs");
30
30
  await interactive(args);
31
31
  });
32
32
  cli.command("").action(async (args) => {
33
- const { interactive } = await import("./interactive-CK8WpuBn.mjs");
33
+ const { interactive } = await import("./interactive-OXXqccQf.mjs");
34
34
  await interactive(args);
35
35
  });
36
36
  cli.version(version);
@@ -53,13 +53,73 @@ function promptApiConfigEnable(configArr) {
53
53
  //#region src/commands/generateApi/index.ts
54
54
  const log = createLogger("generateApi");
55
55
  const asyncLocalStorage = new AsyncLocalStorage();
56
- function getCompileSchemaContext(parsed) {
57
- if (!parsed) return {};
56
+ /**
57
+ * 只收集 rootSchema 里真正引用到的 `$ref`(含传递依赖),
58
+ * 构造一个最小化的定义上下文。
59
+ *
60
+ * 之前是把整个 components/definitions 直接挂到每个待编译的 schema 上,
61
+ * 导致 json-schema-to-typescript 每次 compile 都要遍历整份 API 的类型图,
62
+ * 261 个接口 × 2(Req/Res)= 522 次全量遍历,非常慢。
63
+ * 这里改为按需收集可达定义,输出结果不变,但速度大幅提升。
64
+ */
65
+ function buildRefContext(rootSchema, parsed) {
58
66
  const context = {};
59
- if ("components" in parsed && parsed.components) context.components = parsed.components;
60
- if ("definitions" in parsed && parsed.definitions) context.definitions = parsed.definitions;
67
+ if (!parsed || !rootSchema || typeof rootSchema !== "object") return context;
68
+ const seen = /* @__PURE__ */ new Set();
69
+ const queue = [];
70
+ const collectRefs = (obj) => {
71
+ if (!obj || typeof obj !== "object") return;
72
+ if (Array.isArray(obj)) {
73
+ obj.forEach(collectRefs);
74
+ return;
75
+ }
76
+ for (const [key, value] of Object.entries(obj)) if (key === "$ref" && typeof value === "string" && value.startsWith("#/")) queue.push(value);
77
+ else collectRefs(value);
78
+ };
79
+ const decodeSegment = (segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~");
80
+ const resolvePointer = (ref) => {
81
+ const parts = ref.slice(2).split("/").map(decodeSegment);
82
+ let cur = parsed;
83
+ for (const part of parts) {
84
+ if (!cur || typeof cur !== "object") return void 0;
85
+ cur = cur[part];
86
+ }
87
+ return cur === void 0 ? void 0 : {
88
+ parts,
89
+ value: cur
90
+ };
91
+ };
92
+ const setPointer = (parts, value) => {
93
+ let cur = context;
94
+ for (let i = 0; i < parts.length - 1; i++) {
95
+ const part = parts[i];
96
+ if (!cur[part] || typeof cur[part] !== "object") cur[part] = {};
97
+ cur = cur[part];
98
+ }
99
+ cur[parts[parts.length - 1]] = value;
100
+ };
101
+ collectRefs(rootSchema);
102
+ while (queue.length) {
103
+ const ref = queue.shift();
104
+ if (seen.has(ref)) continue;
105
+ seen.add(ref);
106
+ const resolved = resolvePointer(ref);
107
+ if (!resolved) continue;
108
+ setPointer(resolved.parts, resolved.value);
109
+ collectRefs(resolved.value);
110
+ }
61
111
  return context;
62
112
  }
113
+ function stripDefaultKeywordDeep(value) {
114
+ if (!value || typeof value !== "object") return;
115
+ if (Array.isArray(value)) {
116
+ value.forEach((item) => stripDefaultKeywordDeep(item));
117
+ return;
118
+ }
119
+ const record = value;
120
+ if ("default" in record) delete record.default;
121
+ Object.values(record).forEach((item) => stripDefaultKeywordDeep(item));
122
+ }
63
123
  async function generateApi() {
64
124
  const selectedConfigs = await promptApiConfigEnable((await getConfig()).api);
65
125
  const apiConfigs = selectedConfigs.filter((apiConfig) => {
@@ -114,6 +174,7 @@ async function generateApi() {
114
174
  return res.json();
115
175
  }) : apiConfig.swaggerJSONPath;
116
176
  parsed = await parser.bundle(bundleInput, dereferenceConfig);
177
+ stripDefaultKeywordDeep(parsed);
117
178
  log.info("解析 %s 成功,耗时 %dms", apiConfig.swaggerJSONPath, Date.now() - bundleStartedAt);
118
179
  } catch (error) {
119
180
  totalFailedCount++;
@@ -198,14 +259,13 @@ async function generateApi() {
198
259
  * 根据请求方法,生成请求代码
199
260
  */
200
261
  async function generateApiRequestCode(options) {
201
- var _operationObject$tags, _operationObject$tags2;
202
262
  const { method, operationObject, apiConfig } = options;
203
263
  const url = (() => {
204
264
  if (typeof apiConfig.urlTransformer === "string") return `${apiConfig.urlTransformer}${options.url}`;
205
265
  if (typeof apiConfig.urlTransformer === "function") return apiConfig.urlTransformer(options.url);
206
266
  return options.url;
207
267
  })();
208
- const seeUrl = apiConfig.swaggerUiUrl ? `${apiConfig.swaggerUiUrl}#/${encodeURIComponent(`${((_operationObject$tags = operationObject.tags) === null || _operationObject$tags === void 0 ? void 0 : _operationObject$tags.join("/")) ?? ""}/${operationObject.operationId}`)}` : "";
268
+ const seeUrl = apiConfig.swaggerUiUrl ? `${apiConfig.swaggerUiUrl}#/${encodeURIComponent(`${operationObject.tags?.join("/") ?? ""}/${operationObject.operationId}`)}` : "";
209
269
  let requestBuilderName = camelCase(`${options.url}_${method}_api`);
210
270
  if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(requestBuilderName)) requestBuilderName = `_${requestBuilderName}`;
211
271
  const urlPathParams = getUrlPathParams(operationObject.parameters ?? []);
@@ -216,7 +276,7 @@ async function generateApiRequestCode(options) {
216
276
  apiConfig.queryClientImportPath,
217
277
  "/**",
218
278
  ` * ${operationObject.summary}`,
219
- ` * @tags ${(_operationObject$tags2 = operationObject.tags) === null || _operationObject$tags2 === void 0 ? void 0 : _operationObject$tags2.join(",")}`,
279
+ ` * @tags ${operationObject.tags?.join(",")}`,
220
280
  seeUrl && ` * @see ${seeUrl}`,
221
281
  ` */`
222
282
  ].filter(Boolean);
@@ -281,7 +341,7 @@ async function compileRequestParams(operationObject) {
281
341
  }
282
342
  };
283
343
  })();
284
- const requestBodySchema = isPlainObject(requestBodySchemaOrRef) ? "$ref" in requestBodySchemaOrRef ? store === null || store === void 0 ? void 0 : store.parser.$refs.get(requestBodySchemaOrRef.$ref) : requestBodySchemaOrRef : void 0;
344
+ const requestBodySchema = isPlainObject(requestBodySchemaOrRef) ? "$ref" in requestBodySchemaOrRef ? store?.parser.$refs.get(requestBodySchemaOrRef.$ref) : requestBodySchemaOrRef : void 0;
285
345
  const schemaObject = requestBodySchema && parameterSchema ? {
286
346
  ...requestBodySchema,
287
347
  type: "object",
@@ -291,14 +351,16 @@ async function compileRequestParams(operationObject) {
291
351
  ...parameterSchema.properties || {}
292
352
  }
293
353
  } : requestBodySchema || parameterSchema;
294
- const finalSchema = schemaObject ? Object.assign(getCompileSchemaContext(store === null || store === void 0 ? void 0 : store.parsed), schemaObject) : void 0;
354
+ if (schemaObject) stripDefaultKeywordDeep(schemaObject);
355
+ const finalSchema = schemaObject ? Object.assign(buildRefContext(schemaObject, store?.parsed), schemaObject) : void 0;
295
356
  let code = "";
296
357
  if (finalSchema) try {
297
358
  code = await compile(finalSchema, "Req", {
298
359
  bannerComment: "",
299
360
  ignoreMinAndMaxItems: true,
300
361
  additionalProperties: false,
301
- unknownAny: false
362
+ unknownAny: false,
363
+ format: false
302
364
  });
303
365
  } catch (e) {
304
366
  log.error("生成请求参数类型失败,请检查 %o", {
@@ -313,25 +375,23 @@ async function compileResponseParams(operationObject, apiConfig) {
313
375
  const store = asyncLocalStorage.getStore();
314
376
  function resolveSchema(arg) {
315
377
  if (!arg) return;
316
- if ("content" in arg) {
317
- var _arg$content, _arg$content2;
318
- 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["*/*"]);
319
- return resolveSchema(temp === null || temp === void 0 ? void 0 : temp.schema);
320
- }
378
+ if ("content" in arg) return resolveSchema((arg.content?.["application/json"] || arg.content?.["*/*"])?.schema);
321
379
  if ("schema" in arg && arg.schema) return resolveSchema(arg.schema);
322
380
  let schema = apiConfig.responseSchemaTransformer(arg);
323
- if ("$ref" in schema) return resolveSchema(store === null || store === void 0 ? void 0 : store.parser.$refs.get(schema.$ref));
381
+ if ("$ref" in schema) return resolveSchema(store?.parser.$refs.get(schema.$ref));
324
382
  return schema;
325
383
  }
326
384
  const schemaObject = resolveSchema(operationObject.responses["200"]);
327
- const finalSchema = schemaObject ? Object.assign(getCompileSchemaContext(store === null || store === void 0 ? void 0 : store.parsed), schemaObject) : void 0;
385
+ if (schemaObject) stripDefaultKeywordDeep(schemaObject);
386
+ const finalSchema = schemaObject ? Object.assign(buildRefContext(schemaObject, store?.parsed), schemaObject) : void 0;
328
387
  let code = "";
329
388
  if (finalSchema) try {
330
389
  code = await compile(finalSchema, "Res", {
331
390
  bannerComment: "",
332
391
  ignoreMinAndMaxItems: true,
333
392
  additionalProperties: false,
334
- unknownAny: false
393
+ unknownAny: false,
394
+ format: false
335
395
  });
336
396
  } catch (e) {
337
397
  log.error("转换响应参数类型失败,请检查 %o", {
@@ -346,4 +406,4 @@ async function compileResponseParams(operationObject, apiConfig) {
346
406
  //#endregion
347
407
  export { generateApi };
348
408
 
349
- //# sourceMappingURL=generateApi-th-P08qy.mjs.map
409
+ //# sourceMappingURL=generateApi-MKVHBsOV.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateApi-MKVHBsOV.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\n/**\n * 只收集 rootSchema 里真正引用到的 `$ref`(含传递依赖),\n * 构造一个最小化的定义上下文。\n *\n * 之前是把整个 components/definitions 直接挂到每个待编译的 schema 上,\n * 导致 json-schema-to-typescript 每次 compile 都要遍历整份 API 的类型图,\n * 261 个接口 × 2(Req/Res)= 522 次全量遍历,非常慢。\n * 这里改为按需收集可达定义,输出结果不变,但速度大幅提升。\n */\nfunction buildRefContext(\n rootSchema: unknown,\n parsed: ParsedDocument | undefined,\n): Record<string, unknown> {\n const context: Record<string, unknown> = {};\n if (!parsed || !rootSchema || typeof rootSchema !== 'object') {\n return context;\n }\n\n const seen = new Set<string>();\n const queue: string[] = [];\n\n const collectRefs = (obj: unknown) => {\n if (!obj || typeof obj !== 'object') return;\n if (Array.isArray(obj)) {\n obj.forEach(collectRefs);\n return;\n }\n for (const [key, value] of Object.entries(obj)) {\n if (\n key === '$ref' &&\n typeof value === 'string' &&\n value.startsWith('#/')\n ) {\n queue.push(value);\n } else {\n collectRefs(value);\n }\n }\n };\n\n const decodeSegment = (segment: string) =>\n segment.replace(/~1/g, '/').replace(/~0/g, '~');\n\n const resolvePointer = (ref: string) => {\n const parts = ref.slice(2).split('/').map(decodeSegment);\n let cur: unknown = parsed;\n for (const part of parts) {\n if (!cur || typeof cur !== 'object') return undefined;\n cur = (cur as Record<string, unknown>)[part];\n }\n return cur === undefined ? undefined : { parts, value: cur };\n };\n\n const setPointer = (parts: string[], value: unknown) => {\n let cur = context;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (!cur[part] || typeof cur[part] !== 'object') {\n cur[part] = {};\n }\n cur = cur[part] as Record<string, unknown>;\n }\n cur[parts[parts.length - 1]] = value;\n };\n\n collectRefs(rootSchema);\n while (queue.length) {\n const ref = queue.shift()!;\n if (seen.has(ref)) continue;\n seen.add(ref);\n const resolved = resolvePointer(ref);\n if (!resolved) continue;\n setPointer(resolved.parts, resolved.value);\n collectRefs(resolved.value);\n }\n\n return context;\n}\n\nfunction stripDefaultKeywordDeep(value: unknown) {\n if (!value || typeof value !== 'object') {\n return;\n }\n\n if (Array.isArray(value)) {\n value.forEach((item) => stripDefaultKeywordDeep(item));\n return;\n }\n\n const record = value as Record<string, unknown>;\n if ('default' in record) {\n delete record.default;\n }\n\n Object.values(record).forEach((item) => stripDefaultKeywordDeep(item));\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 // default 值经常和 type 不一致(例如 integer + \"\"),\n // 会被 json-schema-to-typescript 推断成交叉类型(number & string)。\n // 生成前统一移除 default,避免污染类型。\n stripDefaultKeywordDeep(parsed);\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 requestBodySchemaOrRef = (() => {\n if (!operationObject.requestBody) {\n return;\n }\n if ('$ref' in operationObject.requestBody) {\n return operationObject.requestBody;\n }\n return operationObject.requestBody.content['application/json'].schema;\n })();\n\n const parameterSchema = (() => {\n if (!operationObject.parameters) {\n return;\n }\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) => 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 } satisfies OpenAPIV3.SchemaObject;\n })();\n\n const requestBodySchema = isPlainObject(requestBodySchemaOrRef)\n ? '$ref' in requestBodySchemaOrRef\n ? (store?.parser.$refs.get(\n requestBodySchemaOrRef.$ref,\n ) as OpenAPIV3.SchemaObject)\n : requestBodySchemaOrRef\n : void 0;\n\n const schemaObject =\n requestBodySchema && parameterSchema\n ? ({\n ...requestBodySchema,\n type: 'object',\n required: [\n ...new Set([\n ...(requestBodySchema.required || []),\n ...(parameterSchema.required || []),\n ]),\n ],\n properties: {\n ...(requestBodySchema.properties || {}),\n ...(parameterSchema.properties || {}),\n },\n } satisfies OpenAPIV3.SchemaObject)\n : requestBodySchema || parameterSchema;\n\n if (schemaObject) {\n stripDefaultKeywordDeep(schemaObject);\n }\n\n const finalSchema = schemaObject\n ? Object.assign(buildRefContext(schemaObject, store?.parsed), schemaObject)\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 // 生成完成后会统一用 codeFormatterCmd 格式化,\n // 这里关闭内置 prettier,避免每个类型都跑一次格式化拖慢速度。\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 if (schemaObject) {\n stripDefaultKeywordDeep(schemaObject);\n }\n\n const finalSchema = schemaObject\n ? Object.assign(buildRefContext(schemaObject, 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 // 生成完成后会统一用 codeFormatterCmd 格式化,\n // 这里关闭内置 prettier,避免每个类型都跑一次格式化拖慢速度。\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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"}
@@ -4,7 +4,6 @@ import enquirer from "enquirer";
4
4
  const { prompt } = enquirer;
5
5
  const log = createLogger("interactive");
6
6
  const interactive = async (args) => {
7
- var _command$commandActio;
8
7
  const commands = cli.commands.filter((command) => {
9
8
  if (command.name) return !command.name.startsWith("@@") && command.name !== "interactive";
10
9
  return false;
@@ -29,9 +28,9 @@ const interactive = async (args) => {
29
28
  log.error("未找到命令 %s", res.command);
30
29
  return;
31
30
  }
32
- (_command$commandActio = command.commandAction) === null || _command$commandActio === void 0 || _command$commandActio.apply(cli, args);
31
+ command.commandAction?.apply(cli, args);
33
32
  };
34
33
  //#endregion
35
34
  export { interactive };
36
35
 
37
- //# sourceMappingURL=interactive-CK8WpuBn.mjs.map
36
+ //# sourceMappingURL=interactive-OXXqccQf.mjs.map
@@ -1 +1 @@
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
+ {"version":3,"file":"interactive-OXXqccQf.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,SAAQ,eAAe,MAAM,KAAK,KAAK"}
@@ -13,10 +13,7 @@ function apiConfigNormalizer(item) {
13
13
  item.enableTs ??= true;
14
14
  item.enabled ??= true;
15
15
  item.codeFormatterCmd ??= "oxfmt";
16
- item.responseSchemaTransformer ??= (schema) => {
17
- var _schema$properties;
18
- return ((_schema$properties = schema.properties) === null || _schema$properties === void 0 ? void 0 : _schema$properties.data) ?? schema;
19
- };
16
+ item.responseSchemaTransformer ??= (schema) => schema.properties?.data ?? schema;
20
17
  return item;
21
18
  }
22
19
  //#endregion
@@ -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,gBAAA,QAAA,uBAAA,KAAA,IAAA,KAAA,IAAA,mBAAY,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,OAAO,YAAY,QAAQ;AAC7B,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dune2/cli",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/liaoyinglong/next-tools.git",
@@ -42,7 +42,6 @@
42
42
  "devDependencies": {
43
43
  "@types/debug": "^4.1.7",
44
44
  "openapi-types": "^12.0.2",
45
- "prettier": "^3.8.1",
46
45
  "tsdown": "^0.21.0"
47
46
  },
48
47
  "scripts": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"generateApi-th-P08qy.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 requestBodySchemaOrRef = (() => {\n if (!operationObject.requestBody) {\n return;\n }\n if ('$ref' in operationObject.requestBody) {\n return operationObject.requestBody;\n }\n return operationObject.requestBody.content['application/json'].schema;\n })();\n\n const parameterSchema = (() => {\n if (!operationObject.parameters) {\n return;\n }\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) => 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 } satisfies OpenAPIV3.SchemaObject;\n })();\n\n const requestBodySchema = isPlainObject(requestBodySchemaOrRef)\n ? '$ref' in requestBodySchemaOrRef\n ? (store?.parser.$refs.get(\n requestBodySchemaOrRef.$ref,\n ) as OpenAPIV3.SchemaObject)\n : requestBodySchemaOrRef\n : void 0;\n\n const schemaObject =\n requestBodySchema && parameterSchema\n ? ({\n ...requestBodySchema,\n type: 'object',\n required: [\n ...new Set([\n ...(requestBodySchema.required || []),\n ...(parameterSchema.required || []),\n ]),\n ],\n properties: {\n ...(requestBodySchema.properties || {}),\n ...(parameterSchema.properties || {}),\n },\n } satisfies OpenAPIV3.SchemaObject)\n : requestBodySchema || parameterSchema;\n\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 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":"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"}