@cnbcool/cnb-api-generate 2.1.0 → 2.2.0

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.
@@ -24,10 +24,8 @@ export function getToolParamDefs(moduleName: string, toolName: string) {
24
24
  export function formatParams(
25
25
  params: Record<string, string | string[] | boolean | undefined>,
26
26
  ): Record<string, any> {
27
- console.log(JSON.stringify(params))
28
27
  // 先将 CLI 带 '-' 的参数名还原为原始 '_'/'@' 参数名
29
28
  params = restoreOriginalKeys(params);
30
- console.log(params)
31
29
  const formatted: Record<string, any> = {
32
30
  module: params.module,
33
31
  tool: params.tool,
@@ -111,7 +109,15 @@ export function formatParams(
111
109
  } else if (bodyProps[key]) {
112
110
  // body 字段(无冲突,直接用原 key)
113
111
  if (!formatted.data) formatted.data = {};
114
- formatted.data[key] = Array.isArray(value) ? value : tryParseJSON(value as string);
112
+ if (Array.isArray(value)) {
113
+ formatted.data[key] = value;
114
+ } else if (bodyProps[key].type === 'string') {
115
+ // schema 定义为 string 类型时,保持原始字符串,不做 JSON 解析
116
+ // 避免纯数字字符串(如 "123")被转为 number
117
+ formatted.data[key] = value;
118
+ } else {
119
+ formatted.data[key] = tryParseJSON(value as string);
120
+ }
115
121
  } else {
116
122
  // 处理 d- 前缀(冲突时 CLI 以 d- 前缀传入)
117
123
  const stripped = (key.startsWith('d-') || key.startsWith('d_'))
@@ -1,3 +1,4 @@
1
+ import { encode } from '@toon-format/toon'
1
2
  /**
2
3
  * 将数据转换为格式化的 JSON 字符串
3
4
  * @param data 要序列化的数据(可以是任意类型)缩进)
@@ -8,5 +9,13 @@ export function printJSON(
8
9
  data: Record<string, any> | Array<any>,
9
10
  verbose: boolean = false
10
11
  ): string {
11
- return verbose ? JSON.stringify(data, null, 2) : JSON.stringify(data);
12
+ if (verbose) {
13
+ return JSON.stringify(data, null, 2);
14
+ } else {
15
+ try {
16
+ return encode(data);
17
+ } catch (e) {
18
+ return JSON.stringify(data);
19
+ }
20
+ }
12
21
  }
@@ -3,7 +3,7 @@ import { trimSummary } from './trim-summary';
3
3
  import { helpData } from './help-data';
4
4
  import { flatOptionsData } from './flat-options-data';
5
5
  import { executeAction } from './execute-action';
6
- import { resolveShortcut } from '../shortcuts';
6
+ import { ISSUE_SHORTCUTS, PR_SHORTCUTS, type ShortcutDefinition } from '../shortcuts';
7
7
 
8
8
  interface FlatOption {
9
9
  optKey: string;
@@ -22,19 +22,22 @@ interface FlatOption {
22
22
  * 为单个 tool 子命令注册 Commander options
23
23
  * 直接读取预生成的 flat-options.json 中已扁平化的参数定义,无需运行时计算
24
24
  */
25
- function registerToolOptions(toolCmd: Command, moduleName: string, toolName: string): void {
25
+ function registerToolOptions(toolCmd: Command, moduleName: string, toolName: string, skipPathMandatory?: boolean): void {
26
26
  const moduleOptions = flatOptionsData[moduleName];
27
27
  if (!moduleOptions) return;
28
28
  const toolOptions: Record<string, FlatOption> = moduleOptions[toolName];
29
29
  if (!toolOptions) return;
30
30
 
31
31
  for (const [, opt] of Object.entries(toolOptions) as [string, FlatOption][]) {
32
+ // 快捷命令跳过 path 参数(由环境变量自动注入)
33
+ if (skipPathMandatory && opt.source === 'path') continue;
34
+
32
35
  const option = new Option(
33
36
  `--${opt.optKey} ${opt.valuePlaceholder}`.trim(),
34
37
  opt.description,
35
38
  );
36
39
 
37
- if (opt.required && opt.source === 'path') {
40
+ if (opt.required && opt.source === 'path' && !skipPathMandatory) {
38
41
  option.makeOptionMandatory();
39
42
  }
40
43
 
@@ -61,6 +64,15 @@ function registerToolOptions(toolCmd: Command, moduleName: string, toolName: str
61
64
  }
62
65
  }
63
66
 
67
+ /**
68
+ * 获取指定模块的快捷命令列表
69
+ */
70
+ function getShortcutsForModule(moduleName: string): ShortcutDefinition[] {
71
+ if (moduleName === 'issues') return ISSUE_SHORTCUTS;
72
+ if (moduleName === 'pulls') return PR_SHORTCUTS;
73
+ return [];
74
+ }
75
+
64
76
  /**
65
77
  * 为每个模块注册子命令,使 cnb <module> -h 显示模块帮助
66
78
  * 每个 tool 的参数通过 Commander 的 option 系统注册,--help 自动展示参数说明
@@ -75,6 +87,9 @@ export function registerModuleCommands(program: Command): void {
75
87
  .description(`${moduleName} 模块 (${toolEntries.length} tools)`)
76
88
  .helpOption('-h, --help', '显示帮助文档');
77
89
 
90
+ // 收集已注册的子命令名,避免快捷命令与真实 tool 名冲突
91
+ const registeredNames = new Set<string>();
92
+
78
93
  // 为每个 tool 注册子命令
79
94
  for (const [toolName, toolInfo] of Object.entries(tools) as [string, any][]) {
80
95
  const summary = trimSummary(toolInfo.summary || '');
@@ -95,6 +110,30 @@ export function registerModuleCommands(program: Command): void {
95
110
 
96
111
  // 根据 flat-options.json 注册参数选项
97
112
  registerToolOptions(toolCmd, moduleName, toolName);
113
+ registeredNames.add(toolName);
114
+ }
115
+
116
+ // 为快捷命令注册 Commander 子命令(别名)
117
+ // 复用对应真实 tool 的选项定义,但跳过 path 参数(由环境变量自动注入)
118
+ const shortcuts = getShortcutsForModule(moduleName);
119
+ for (const shortcut of shortcuts) {
120
+ // 如果快捷命令名与真实 tool 名重复,跳过(真实 tool 优先)
121
+ if (registeredNames.has(shortcut.shortName)) continue;
122
+
123
+ const shortcutCmd = sub
124
+ .command(shortcut.shortName)
125
+ .description(`[快捷] ${shortcut.description}`)
126
+ .option('-v, --verbose', '输出完整原始响应')
127
+ .helpOption('-h, --help', '显示帮助文档')
128
+ .showHelpAfterError(true)
129
+ .action(async (opts: Record<string, any>) => {
130
+ // 传入快捷命令名,executeAction 内部会通过 resolveShortcut 转换
131
+ await executeAction(moduleName, shortcut.shortName, opts, sub);
132
+ });
133
+
134
+ // 复用真实 tool 的选项,跳过 path 参数
135
+ registerToolOptions(shortcutCmd, moduleName, shortcut.realTool, true);
136
+ registeredNames.add(shortcut.shortName);
98
137
  }
99
138
 
100
139
  // 允许未匹配到子命令时也能正常执行(不报错)
@@ -102,18 +141,13 @@ export function registerModuleCommands(program: Command): void {
102
141
  sub.allowExcessArguments();
103
142
 
104
143
  // 模块级 action:处理未匹配到子命令的情况
105
- // 如果输入了快捷命令名(如 cnb issues get),Commander 匹配不到真实 tool 子命令,
106
- // 会走到这里,此时尝试 resolveShortcut 将其转换为真实 tool
107
144
  sub
108
145
  .argument('[tool]', '工具名称(支持快捷命令)')
109
- .action(async (toolArg: string | undefined, opts: Record<string, any>) => {
146
+ .action(async (toolArg: string | undefined, _opts: Record<string, any>) => {
110
147
  if (toolArg) {
111
- const shortcut = resolveShortcut(moduleName, toolArg);
112
- if (shortcut) {
113
- // 快捷命令匹配成功,走 executeAction 流程
114
- await executeAction(moduleName, toolArg, opts, sub);
115
- return;
116
- }
148
+ // 此处已不会再命中快捷命令(因为已注册为子命令),仅作兜底
149
+ sub.help();
150
+ return;
117
151
  }
118
152
  sub.help();
119
153
  });
@@ -67,7 +67,7 @@ function getPRNumber(): string {
67
67
  // 快捷命令定义
68
68
  // ============================================================
69
69
 
70
- const ISSUE_SHORTCUTS: ShortcutDefinition[] = [
70
+ export const ISSUE_SHORTCUTS: ShortcutDefinition[] = [
71
71
  { shortName: 'get', realTool: 'get-issue', description: '获取详情' },
72
72
  { shortName: 'list-comments', realTool: 'list-issue-comments', description: '获取评论列表' },
73
73
  { shortName: 'comment', realTool: 'post-issue-comment', description: '评论', dataTip: "--body 内容" },
@@ -81,7 +81,7 @@ const ISSUE_SHORTCUTS: ShortcutDefinition[] = [
81
81
  { shortName: 'upload-image', realTool: 'post-issue-image-asset-upload-url', description: '上传图片', upload: true, dataTip: "--file 图片路径" },
82
82
  ];
83
83
 
84
- const PR_SHORTCUTS: ShortcutDefinition[] = [
84
+ export const PR_SHORTCUTS: ShortcutDefinition[] = [
85
85
  { shortName: 'get', realTool: 'get-pull', description: '获取详情' },
86
86
  { shortName: 'list-files', realTool: 'list-pull-files', description: '获取文件变更' },
87
87
  { shortName: 'list-commits', realTool: 'list-pull-commits', description: '获取提交记录' },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cnbcool/cnb-api-generate",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "main": "./built/index.js",
5
5
  "module": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -33,6 +33,7 @@
33
33
  "@babel/preset-env": "^7.29.0",
34
34
  "@babel/preset-typescript": "^7.28.5",
35
35
  "@babel/traverse": "^7.29.0",
36
+ "@toon-format/toon": "^2.1.0",
36
37
  "@types/cli-progress": "^3.11.6",
37
38
  "@types/lodash": "4.17.20",
38
39
  "babel-plugin-transform-define": "^2.1.4",