@dune2/cli 1.1.5 → 1.1.6

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
@@ -3,7 +3,7 @@ import cac from "cac";
3
3
  import debug from "debug";
4
4
 
5
5
  //#region package.json
6
- var version = "1.1.4";
6
+ var version = "1.1.5";
7
7
 
8
8
  //#endregion
9
9
  //#region src/shared/index.ts
@@ -21,7 +21,7 @@ debug.enable(`${cli.name}:*`);
21
21
  //#endregion
22
22
  //#region src/cli.ts
23
23
  cli.command("generateApi", "生成 api 文件").example("dune generateApi").action(async () => {
24
- const { generateApi } = await import("./generateApi-CxXqgeuk.mjs");
24
+ const { generateApi } = await import("./generateApi-BMRAxjkM.mjs");
25
25
  await generateApi();
26
26
  });
27
27
  cli.command("init", "初始化配置文件").example("dune init").action(async () => {
@@ -56,28 +56,84 @@ function promptApiConfigEnable(configArr) {
56
56
  const log = createLogger("generateApi");
57
57
  const asyncLocalStorage = new AsyncLocalStorage();
58
58
  async function generateApi() {
59
- const apiConfigs = await promptApiConfigEnable((await getConfig()).api);
60
- for (const apiConfig of apiConfigs) {
61
- log.info(`清除旧的 api 文件:${apiConfig.output}`);
62
- await fs.rm(apiConfig.output, {
63
- recursive: true,
64
- force: true
65
- });
66
- await fs.mkdir(apiConfig.output, { recursive: true });
59
+ const selectedConfigs = await promptApiConfigEnable((await getConfig()).api);
60
+ const apiConfigs = selectedConfigs.filter((apiConfig) => {
61
+ if (!apiConfig.output) {
62
+ log.error("配置 %s 缺少 output,已跳过", apiConfig.swaggerJSONPath);
63
+ return false;
64
+ }
65
+ return true;
66
+ });
67
+ const skippedConfigCount = selectedConfigs.length - apiConfigs.length;
68
+ if (skippedConfigCount > 0) log.info("由于缺少 output,跳过 %d 个配置", skippedConfigCount);
69
+ if (!apiConfigs.length) {
70
+ log.info("没有需要生成的 API 配置,生成流程结束");
71
+ return;
67
72
  }
73
+ log.info("本次将生成 %d 个 API 配置", apiConfigs.length);
74
+ let totalSuccessCount = 0;
75
+ let totalFailedCount = 0;
76
+ const startedAt = Date.now();
77
+ const preparedConfigs = [];
68
78
  for (const apiConfig of apiConfigs) {
79
+ log.info("开始初始化输出目录 %s", apiConfig.output);
80
+ const prepareStartedAt = Date.now();
81
+ try {
82
+ await fs.rm(apiConfig.output, {
83
+ recursive: true,
84
+ force: true
85
+ });
86
+ await fs.mkdir(apiConfig.output, { recursive: true });
87
+ preparedConfigs.push(apiConfig);
88
+ log.info("输出目录 %s 初始化完成,耗时 %dms", apiConfig.output, Date.now() - prepareStartedAt);
89
+ } catch (error) {
90
+ totalFailedCount++;
91
+ const message = error instanceof Error ? error.message : String(error);
92
+ log.error("初始化输出目录 %s 失败:%s", apiConfig.output, message);
93
+ }
94
+ }
95
+ if (!preparedConfigs.length) {
96
+ log.error("所有配置都初始化失败,生成流程结束");
97
+ log.info("generateApi Done,成功 %d 个,失败 %d 个,总耗时 %dms", totalSuccessCount, totalFailedCount, Date.now() - startedAt);
98
+ return;
99
+ }
100
+ for (const apiConfig of preparedConfigs) {
69
101
  log.info("开始解析 %s", apiConfig.swaggerJSONPath);
70
102
  const dereferenceConfig = merge({ resolve: { http: { timeout: 30 * 1e3 } } }, apiConfig.dereferenceSwaggerConfig || {});
71
103
  const parser = new SwaggerParser();
72
- const parsed = await parser.bundle(apiConfig.swaggerJSONPath, dereferenceConfig);
104
+ const bundleStartedAt = Date.now();
105
+ let parsed;
106
+ try {
107
+ parsed = await parser.bundle(apiConfig.swaggerJSONPath, dereferenceConfig);
108
+ log.info("解析 %s 成功,耗时 %dms", apiConfig.swaggerJSONPath, Date.now() - bundleStartedAt);
109
+ } catch (error) {
110
+ totalFailedCount++;
111
+ const message = error instanceof Error ? error.message : String(error);
112
+ log.error("解析 %s 失败:%s", apiConfig.swaggerJSONPath, message);
113
+ continue;
114
+ }
73
115
  const state = {
74
116
  parsed,
75
117
  parser
76
118
  };
119
+ let generatedCount = 0;
120
+ let skippedCount = 0;
121
+ const pathEntries = Object.entries(parsed.paths ?? {});
122
+ if (!pathEntries.length) {
123
+ log.error("%s 中没有可用的 paths,已跳过", apiConfig.swaggerJSONPath);
124
+ totalFailedCount++;
125
+ continue;
126
+ }
77
127
  await asyncLocalStorage.run(state, async () => {
78
- await pMap(Object.entries(parsed.paths), async ([url, pathItemObject]) => {
128
+ await pMap(pathEntries, async ([url, pathItemObject]) => {
129
+ if (!pathItemObject) {
130
+ log.error("路径 %s 未定义 pathItemObject,已跳过", url);
131
+ skippedCount++;
132
+ return;
133
+ }
79
134
  log.info("开始生成 %s", url);
80
- if (pathItemObject) await pMap([
135
+ let generatedForUrl = 0;
136
+ await pMap([
81
137
  "get",
82
138
  "put",
83
139
  "post",
@@ -85,7 +141,8 @@ async function generateApi() {
85
141
  "patch"
86
142
  ], async (method) => {
87
143
  const operationObject = pathItemObject[method];
88
- if (operationObject) {
144
+ if (!operationObject) return;
145
+ try {
89
146
  const code = await generateApiRequestCode({
90
147
  url,
91
148
  method,
@@ -95,22 +152,38 @@ async function generateApi() {
95
152
  const outputPath = path.join(apiConfig.output, url, apiConfig.enableTs ? `${method}.ts` : `${method}.js`).replace(/:/g, "_");
96
153
  await fs.mkdir(path.dirname(outputPath), { recursive: true });
97
154
  await fs.writeFile(outputPath, code);
155
+ generatedCount++;
156
+ generatedForUrl++;
157
+ } catch (error) {
158
+ skippedCount++;
159
+ const message = error instanceof Error ? error.message : String(error);
160
+ log.error("%s %s 生成失败:%s", method.toUpperCase(), url, message);
98
161
  }
99
162
  });
163
+ if (generatedForUrl === 0) log.info("路径 %s 未生成任何方法", url);
100
164
  });
101
165
  });
166
+ if (!generatedCount) {
167
+ log.error("%s 未生成任何请求,已标记失败", apiConfig.swaggerJSONPath);
168
+ totalFailedCount++;
169
+ continue;
170
+ }
102
171
  if (apiConfig.codeFormatterCmd) {
103
172
  const { exec } = await import("child_process");
104
173
  await new Promise((resolve) => {
105
174
  exec(`${apiConfig.codeFormatterCmd} "${apiConfig.output}"`, (error) => {
106
- if (error) log.error(`Code formatting failed: ${error.message}`);
107
- else log.info(`Code formatting success`);
175
+ if (error) {
176
+ skippedCount++;
177
+ log.error(`Code formatting failed: ${error.message}`);
178
+ } else log.info(`Code formatting success`);
108
179
  resolve();
109
180
  });
110
181
  });
111
182
  }
183
+ log.info("%s 生成完成,共生成 %d 个请求,跳过 %d 个", apiConfig.swaggerJSONPath, generatedCount, skippedCount);
184
+ totalSuccessCount++;
112
185
  }
113
- log.info("generateApi Done");
186
+ log.info("generateApi Done,成功 %d 个,失败 %d 个,总耗时 %dms", totalSuccessCount, totalFailedCount, Date.now() - startedAt);
114
187
  }
115
188
  /**
116
189
  * 根据请求方法,生成请求代码
@@ -253,4 +326,4 @@ async function compileResponseParams(operationObject, apiConfig) {
253
326
 
254
327
  //#endregion
255
328
  export { generateApi };
256
- //# sourceMappingURL=generateApi-CxXqgeuk.mjs.map
329
+ //# sourceMappingURL=generateApi-BMRAxjkM.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateApi-BMRAxjkM.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 SwaggerParser from \"@apidevtools/swagger-parser\";\nimport { camelCase, isPlainObject, merge } from \"es-toolkit\";\nimport { compile } from \"json-schema-to-typescript\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport fs from \"node:fs/promises\";\nimport { OpenAPIV3 } from \"openapi-types\";\nimport * as os from \"os\";\nimport pMap from \"p-map\";\nimport path from \"path\";\nimport { createLogger } from \"../../shared\";\nimport { ApiConfig, getConfig } from \"../../shared/config\";\nimport { promptApiConfigEnable } from \"../../shared/promptConfigEnable\";\n\nconst log = createLogger(\"generateApi\");\n\nexport const asyncLocalStorage = new AsyncLocalStorage<{\n parsed: 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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dune2/cli",
3
- "version": "1.1.5",
3
+ "version": "1.1.6",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/liaoyinglong/next-tools.git",
@@ -1 +0,0 @@
1
- {"version":3,"file":"generateApi-CxXqgeuk.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 SwaggerParser from \"@apidevtools/swagger-parser\";\nimport { camelCase, isPlainObject, merge } from \"es-toolkit\";\nimport { compile } from \"json-schema-to-typescript\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport fs from \"node:fs/promises\";\nimport { OpenAPIV3, type OpenAPI } from \"openapi-types\";\nimport * as os from \"os\";\nimport pMap from \"p-map\";\nimport path from \"path\";\nimport { createLogger } from \"../../shared\";\nimport { ApiConfig, getConfig } from \"../../shared/config\";\nimport { promptApiConfigEnable } from \"../../shared/promptConfigEnable\";\n\nconst log = createLogger(\"generateApi\");\n\nexport const asyncLocalStorage = new AsyncLocalStorage<{\n parsed: OpenAPIV3.Document;\n parser: SwaggerParser;\n}>();\n\nfunction isV3(doc: OpenAPI.Document | undefined): doc is OpenAPIV3.Document {\n if (doc) {\n return \"components\" in doc;\n }\n return false;\n}\n\nexport async function generateApi() {\n const config = await getConfig();\n const apiConfigs = await promptApiConfigEnable(config.api);\n\n for (const apiConfig of apiConfigs) {\n log.info(`清除旧的 api 文件:${apiConfig.output}`);\n await fs.rm(apiConfig.output!, { recursive: true, force: true });\n await fs.mkdir(apiConfig.output!, { recursive: true });\n }\n\n for (const apiConfig of apiConfigs) {\n log.info(\"开始解析 %s\", apiConfig.swaggerJSONPath);\n const dereferenceConfig = merge(\n {\n resolve: {\n http: {\n timeout: 30 * 1000,\n },\n },\n },\n apiConfig.dereferenceSwaggerConfig || {},\n );\n const parser = new SwaggerParser();\n\n const parsed = await parser.bundle(\n apiConfig.swaggerJSONPath,\n dereferenceConfig,\n );\n\n const state = {\n // only support v3\n parsed: parsed as OpenAPIV3.Document,\n parser,\n };\n await asyncLocalStorage.run(state, async () => {\n await pMap(\n Object.entries(parsed.paths!),\n async ([url, pathItemObject]) => {\n log.info(\"开始生成 %s\", url);\n if (pathItemObject) {\n await pMap(\n [\"get\", \"put\", \"post\", \"delete\", \"patch\"],\n async (method) => {\n const operationObject = pathItemObject[method];\n if (operationObject) {\n const code = await generateApiRequestCode({\n url: url,\n method: method,\n operationObject: operationObject,\n apiConfig,\n });\n const outputPath = path\n .join(\n apiConfig.output!,\n url,\n apiConfig.enableTs ? `${method}.ts` : `${method}.js`,\n )\n .replace(/:/g, \"_\");\n await fs.mkdir(path.dirname(outputPath), {\n recursive: true,\n });\n await fs.writeFile(outputPath, code);\n }\n },\n );\n }\n },\n );\n });\n if (apiConfig.codeFormatterCmd) {\n const { exec } = await import(\"child_process\");\n await new Promise<void>((resolve) => {\n exec(\n `${apiConfig.codeFormatterCmd} \"${apiConfig.output!}\"`,\n (error) => {\n if (error) {\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\n log.info(\"generateApi Done\");\n}\n\n/**\n * 根据请求方法,生成请求代码\n */\nexport async function generateApiRequestCode(options: {\n url: string;\n method: string;\n operationObject: OpenAPIV3.OperationObject;\n apiConfig: ApiConfig;\n}): Promise<string> {\n const { method, operationObject, apiConfig } = options;\n\n const url = (() => {\n if (typeof apiConfig.urlTransformer === \"string\") {\n return `${apiConfig.urlTransformer}${options.url}`;\n }\n if (typeof apiConfig.urlTransformer === \"function\") {\n return apiConfig.urlTransformer(options.url);\n }\n return options.url;\n })();\n\n const seeUrl = apiConfig.swaggerUiUrl\n ? `${apiConfig.swaggerUiUrl}#/${encodeURIComponent(\n `${operationObject.tags?.join(\"/\") ?? \"\"}/${\n operationObject.operationId\n }`,\n )}`\n : \"\";\n\n // 生成的请求构造器的名称,需要使用原始 url\n let requestBuilderName = camelCase(`${options.url}_${method}_api`);\n\n // 判断是否有效的 js 变量\n if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(requestBuilderName)) {\n // 不是有效的 js 变量,使用 _ + 数字\n requestBuilderName = `_${requestBuilderName}`;\n }\n\n //#region url 上参数 例如 /api/v1/users/{userId}\n const urlPathParams = getUrlPathParams(\n (operationObject.parameters as never) ?? [],\n );\n const urlPathParamsCode = urlPathParams.length\n ? `urlPathParams: ${JSON.stringify(urlPathParams)},`\n : \"\";\n //#endregion\n\n let code: string[] = [\n \"// do not edit this file manually, it will be overwritten by @dune2/cli\",\n apiConfig.RequestBuilderImportPath!,\n apiConfig.queryClientImportPath!,\n\n \"/**\",\n ` * ${operationObject.summary}`,\n ` * @tags ${operationObject.tags?.join(\",\")}`,\n seeUrl && ` * @see ${seeUrl}`,\n ` */`,\n ].filter(Boolean);\n\n // builder 代码\n let builderCode = `\\\nexport const ${requestBuilderName} = new RequestBuilder({\n url: '${url}',\n method: '${method}',\n ${urlPathParamsCode}\n ${apiConfig.queryClientImportPath ? \"queryClient,\" : \"\"}\n});`\n // 移除空行\n .replace(/,\\n\\s*}/, \",\" + os.EOL + \"}\");\n if (apiConfig.enableTs) {\n builderCode = builderCode.replace(\n \"new RequestBuilder(\",\n `new RequestBuilder<${requestBuilderName}.Req, ${requestBuilderName}.Res>(`,\n );\n }\n code.push(builderCode);\n\n if (apiConfig.enableTs) {\n const [requestParamsTypeCode, responseParamsTypeCode] = await Promise.all([\n // 请求参数类型\n compileRequestParams(operationObject),\n // 响应参数类型\n compileResponseParams(operationObject, apiConfig),\n ]);\n\n code.push(`\nexport namespace ${requestBuilderName} {\n ${requestParamsTypeCode.code}\n \n ${responseParamsTypeCode}\n};`);\n }\n\n return code.join(os.EOL);\n}\n\nfunction getUrlPathParams(parameters: OpenAPIV3.ParameterObject[]) {\n return parameters\n .filter((item) => item.in === \"path\")\n .map((item) => item.name);\n}\n\n/**\n * 这个方法还不完善,只能处理简单的请求参数\n */\nasync function compileRequestParams(\n operationObject: OpenAPIV3.OperationObject,\n) {\n 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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"}