@fjyueke/bify-mcp 1.0.2 → 1.0.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/README.md +68 -5
- package/dist/index.js +278 -86
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,26 +9,89 @@
|
|
|
9
9
|
|
|
10
10
|
Bify 是基于 Taroify 的移动端组件库,基于 Vant 视觉规范,提供一致的 API 接口,助力开发者快速搭建小程序应用。
|
|
11
11
|
|
|
12
|
-
Bify MCP 是一项独立的 MCP(模型上下文协议)服务,旨在将 Bify 与大模型连接起来。它使大模型能够直接从文档中检索组件、API
|
|
12
|
+
Bify MCP 是一项独立的 MCP(模型上下文协议)服务,旨在将 Bify 与大模型连接起来。它使大模型能够直接从文档中检索组件、API 数据,并支持 Arco Mobile → Bify 代码转换。
|
|
13
13
|
|
|
14
14
|
- 直接使用 npx 运行
|
|
15
15
|
- 无需外部依赖,只需要 Node 环境
|
|
16
|
+
- 支持 68+ 个组件文档查询
|
|
17
|
+
- 支持 Arco Mobile 代码转换
|
|
16
18
|
|
|
17
|
-
##
|
|
19
|
+
## 配置方式
|
|
18
20
|
|
|
19
|
-
Cursor
|
|
21
|
+
### Cursor
|
|
20
22
|
|
|
21
|
-
```
|
|
23
|
+
```json
|
|
22
24
|
{
|
|
23
25
|
"mcpServers": {
|
|
24
26
|
"@fjyueke/bify-mcp": {
|
|
25
27
|
"command": "npx",
|
|
26
28
|
"args": [
|
|
27
29
|
"-y",
|
|
28
|
-
"@fjyueke/bify-mcp"
|
|
30
|
+
"@fjyueke/bify-mcp"
|
|
29
31
|
],
|
|
30
32
|
"env": {}
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
```
|
|
37
|
+
|
|
38
|
+
### Trae
|
|
39
|
+
|
|
40
|
+
在 `.trae/skills/` 目录下创建配置文件,或在 Trae 设置中添加 MCP 服务。
|
|
41
|
+
|
|
42
|
+
### 其他支持 MCP 的 IDE
|
|
43
|
+
|
|
44
|
+
参考对应 IDE 的 MCP 配置文档,使用上述配置格式。
|
|
45
|
+
|
|
46
|
+
## 可用工具
|
|
47
|
+
|
|
48
|
+
| 工具名 | 功能 |
|
|
49
|
+
|--------|------|
|
|
50
|
+
| `list-components` | 列出所有可用的 Bify 组件 |
|
|
51
|
+
| `get-component-docs` | 获取指定组件的详细文档 |
|
|
52
|
+
| `get-component-props` | 获取指定组件的属性和 API 文档 |
|
|
53
|
+
| `list-component-example` | 获取指定组件的所有示例代码 |
|
|
54
|
+
| `convert-arco-to-bify` | 将 Arco Mobile React 代码转换为 Bify 代码 |
|
|
55
|
+
| `get-arco-conversion-help` | 获取 Arco Mobile → Bify 转换帮助信息 |
|
|
56
|
+
|
|
57
|
+
## 使用示例
|
|
58
|
+
|
|
59
|
+
### 查询组件文档
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# 列出所有组件
|
|
63
|
+
list-components
|
|
64
|
+
|
|
65
|
+
# 获取 Cell 组件文档
|
|
66
|
+
get-component-docs Cell
|
|
67
|
+
|
|
68
|
+
# 获取 Cell 组件属性
|
|
69
|
+
get-component-props Cell
|
|
70
|
+
|
|
71
|
+
# 获取 Cell 组件示例
|
|
72
|
+
list-component-example Cell
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Arco Mobile 代码转换
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# 获取转换帮助
|
|
79
|
+
get-arco-conversion-help
|
|
80
|
+
|
|
81
|
+
# 转换代码
|
|
82
|
+
convert-arco-to-bify "<Cell label='标题' desc='描述' showArrow>内容</Cell>"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 版本历史
|
|
86
|
+
|
|
87
|
+
| 版本 | 日期 | 说明 |
|
|
88
|
+
|------|------|------|
|
|
89
|
+
| 1.0.3 | 2026-07-13 | 优化代码转换工具,增加 40+ 组件映射、值映射、布尔属性转换 |
|
|
90
|
+
| 1.0.2 | 2026-07-13 | 添加 Arco Mobile → Bify 代码转换功能 |
|
|
91
|
+
| 1.0.1 | 2026-07-13 | 更正包名为 bify-mcp |
|
|
92
|
+
| 1.0.0 | 2026-07-13 | 初始版本,支持 68+ 组件文档查询 |
|
|
93
|
+
|
|
94
|
+
## 相关链接
|
|
95
|
+
|
|
96
|
+
- npm 包地址:https://www.npmjs.com/package/@fjyueke/bify-mcp
|
|
97
|
+
- Bify 组件库:https://github.com/fjyueke/bify
|
package/dist/index.js
CHANGED
|
@@ -172,9 +172,11 @@ var componentMappings = [
|
|
|
172
172
|
{ arcoProp: "label", bifyProp: "title" },
|
|
173
173
|
{ arcoProp: "desc", bifyProp: "brief" },
|
|
174
174
|
{ arcoProp: "text", bifyProp: "children" },
|
|
175
|
-
{ arcoProp: "showArrow", bifyProp: "clickable" },
|
|
175
|
+
{ arcoProp: "showArrow", bifyProp: "clickable", transform: () => "true" },
|
|
176
|
+
{ arcoProp: "arrow", bifyProp: "rightIcon" },
|
|
176
177
|
{ arcoProp: "bordered", bifyProp: "bordered" },
|
|
177
|
-
{ arcoProp: "icon", bifyProp: "icon" }
|
|
178
|
+
{ arcoProp: "icon", bifyProp: "icon" },
|
|
179
|
+
{ arcoProp: "onClick", bifyProp: "onClick" }
|
|
178
180
|
]
|
|
179
181
|
},
|
|
180
182
|
{
|
|
@@ -182,7 +184,10 @@ var componentMappings = [
|
|
|
182
184
|
bifyName: "CellGroup",
|
|
183
185
|
arcoImport: "@arco-design/mobile-react",
|
|
184
186
|
bifyImport: "@fjyueke/bify-core",
|
|
185
|
-
propMappings: [
|
|
187
|
+
propMappings: [
|
|
188
|
+
{ arcoProp: "bordered", bifyProp: "bordered" },
|
|
189
|
+
{ arcoProp: "onClick", bifyProp: "onClick" }
|
|
190
|
+
]
|
|
186
191
|
},
|
|
187
192
|
{
|
|
188
193
|
arcoName: "Button",
|
|
@@ -194,16 +199,25 @@ var componentMappings = [
|
|
|
194
199
|
{ arcoProp: "size", bifyProp: "size" },
|
|
195
200
|
{ arcoProp: "disabled", bifyProp: "disabled" },
|
|
196
201
|
{ arcoProp: "loading", bifyProp: "loading" },
|
|
197
|
-
{ arcoProp: "
|
|
198
|
-
{ arcoProp: "
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
202
|
+
{ arcoProp: "icon", bifyProp: "icon" },
|
|
203
|
+
{ arcoProp: "onClick", bifyProp: "onClick" },
|
|
204
|
+
{ arcoProp: "className", bifyProp: "className" },
|
|
205
|
+
{ arcoProp: "style", bifyProp: "style" }
|
|
206
|
+
],
|
|
207
|
+
valueMappings: {
|
|
208
|
+
type: {
|
|
209
|
+
ghost: "outlined",
|
|
210
|
+
default: "default",
|
|
211
|
+
primary: "primary"
|
|
212
|
+
},
|
|
213
|
+
size: {
|
|
214
|
+
mini: "mini",
|
|
215
|
+
small: "small",
|
|
216
|
+
medium: "medium",
|
|
217
|
+
large: "large",
|
|
218
|
+
huge: "large"
|
|
219
|
+
}
|
|
220
|
+
}
|
|
207
221
|
},
|
|
208
222
|
{
|
|
209
223
|
arcoName: "Avatar",
|
|
@@ -235,8 +249,18 @@ var componentMappings = [
|
|
|
235
249
|
propMappings: [
|
|
236
250
|
{ arcoProp: "type", bifyProp: "type" },
|
|
237
251
|
{ arcoProp: "size", bifyProp: "size" },
|
|
238
|
-
{ arcoProp: "closable", bifyProp: "closable" }
|
|
239
|
-
|
|
252
|
+
{ arcoProp: "closable", bifyProp: "closable" },
|
|
253
|
+
{ arcoProp: "onClose", bifyProp: "onClose" }
|
|
254
|
+
],
|
|
255
|
+
valueMappings: {
|
|
256
|
+
type: {
|
|
257
|
+
default: "default",
|
|
258
|
+
primary: "primary",
|
|
259
|
+
success: "success",
|
|
260
|
+
warning: "warning",
|
|
261
|
+
danger: "danger"
|
|
262
|
+
}
|
|
263
|
+
}
|
|
240
264
|
},
|
|
241
265
|
{
|
|
242
266
|
arcoName: "Switch",
|
|
@@ -257,6 +281,17 @@ var componentMappings = [
|
|
|
257
281
|
propMappings: [
|
|
258
282
|
{ arcoProp: "checked", bifyProp: "checked" },
|
|
259
283
|
{ arcoProp: "disabled", bifyProp: "disabled" },
|
|
284
|
+
{ arcoProp: "onChange", bifyProp: "onChange" },
|
|
285
|
+
{ arcoProp: "label", bifyProp: "children" }
|
|
286
|
+
]
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
arcoName: "CheckboxGroup",
|
|
290
|
+
bifyName: "Checkbox.Group",
|
|
291
|
+
arcoImport: "@arco-design/mobile-react",
|
|
292
|
+
bifyImport: "@fjyueke/bify-core",
|
|
293
|
+
propMappings: [
|
|
294
|
+
{ arcoProp: "value", bifyProp: "modelValue" },
|
|
260
295
|
{ arcoProp: "onChange", bifyProp: "onChange" }
|
|
261
296
|
]
|
|
262
297
|
},
|
|
@@ -268,6 +303,17 @@ var componentMappings = [
|
|
|
268
303
|
propMappings: [
|
|
269
304
|
{ arcoProp: "checked", bifyProp: "checked" },
|
|
270
305
|
{ arcoProp: "disabled", bifyProp: "disabled" },
|
|
306
|
+
{ arcoProp: "onChange", bifyProp: "onChange" },
|
|
307
|
+
{ arcoProp: "label", bifyProp: "children" }
|
|
308
|
+
]
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
arcoName: "RadioGroup",
|
|
312
|
+
bifyName: "Radio.Group",
|
|
313
|
+
arcoImport: "@arco-design/mobile-react",
|
|
314
|
+
bifyImport: "@fjyueke/bify-core",
|
|
315
|
+
propMappings: [
|
|
316
|
+
{ arcoProp: "value", bifyProp: "modelValue" },
|
|
271
317
|
{ arcoProp: "onChange", bifyProp: "onChange" }
|
|
272
318
|
]
|
|
273
319
|
},
|
|
@@ -332,13 +378,6 @@ var componentMappings = [
|
|
|
332
378
|
{ arcoProp: "onClose", bifyProp: "onClose" }
|
|
333
379
|
]
|
|
334
380
|
},
|
|
335
|
-
{
|
|
336
|
-
arcoName: "PickerView",
|
|
337
|
-
bifyName: "Picker",
|
|
338
|
-
arcoImport: "@arco-design/mobile-react",
|
|
339
|
-
bifyImport: "@fjyueke/bify-core",
|
|
340
|
-
propMappings: []
|
|
341
|
-
},
|
|
342
381
|
{
|
|
343
382
|
arcoName: "DatePicker",
|
|
344
383
|
bifyName: "DatePicker",
|
|
@@ -505,6 +544,16 @@ var componentMappings = [
|
|
|
505
544
|
{ arcoProp: "activeKey", bifyProp: "activeNames" }
|
|
506
545
|
]
|
|
507
546
|
},
|
|
547
|
+
{
|
|
548
|
+
arcoName: "CollapseItem",
|
|
549
|
+
bifyName: "Collapse.Item",
|
|
550
|
+
arcoImport: "@arco-design/mobile-react",
|
|
551
|
+
bifyImport: "@fjyueke/bify-core",
|
|
552
|
+
propMappings: [
|
|
553
|
+
{ arcoProp: "title", bifyProp: "title" },
|
|
554
|
+
{ arcoProp: "name", bifyProp: "name" }
|
|
555
|
+
]
|
|
556
|
+
},
|
|
508
557
|
{
|
|
509
558
|
arcoName: "PullRefresh",
|
|
510
559
|
bifyName: "PullRefresh",
|
|
@@ -533,6 +582,29 @@ var componentMappings = [
|
|
|
533
582
|
propMappings: [
|
|
534
583
|
{ arcoProp: "endTime", bifyProp: "endTime" }
|
|
535
584
|
]
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
arcoName: "List",
|
|
588
|
+
bifyName: "List",
|
|
589
|
+
arcoImport: "@arco-design/mobile-react",
|
|
590
|
+
bifyImport: "@fjyueke/bify-core",
|
|
591
|
+
propMappings: []
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
arcoName: "RefreshControl",
|
|
595
|
+
bifyName: "PullRefresh",
|
|
596
|
+
arcoImport: "@arco-design/mobile-react",
|
|
597
|
+
bifyImport: "@fjyueke/bify-core",
|
|
598
|
+
propMappings: [
|
|
599
|
+
{ arcoProp: "onRefresh", bifyProp: "onRefresh" }
|
|
600
|
+
]
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
arcoName: "PickerView",
|
|
604
|
+
bifyName: "PickerView",
|
|
605
|
+
arcoImport: "@arco-design/mobile-react",
|
|
606
|
+
bifyImport: "@fjyueke/bify-core",
|
|
607
|
+
propMappings: []
|
|
536
608
|
}
|
|
537
609
|
];
|
|
538
610
|
function findMappingByArcoName(arcoName) {
|
|
@@ -544,19 +616,36 @@ function findAllArcoComponents() {
|
|
|
544
616
|
|
|
545
617
|
// src/services/arco-converter.ts
|
|
546
618
|
async function convertArcoToBify(arcoCode) {
|
|
619
|
+
const warnings = [];
|
|
620
|
+
const suggestions = [];
|
|
621
|
+
const usedMappings = [];
|
|
547
622
|
let result = arcoCode;
|
|
548
|
-
|
|
549
|
-
result =
|
|
623
|
+
const importsResult = convertImports(result, warnings);
|
|
624
|
+
result = importsResult.code;
|
|
625
|
+
usedMappings.push(...importsResult.mappings);
|
|
626
|
+
const componentsResult = convertComponents(result, warnings, suggestions);
|
|
627
|
+
result = componentsResult.code;
|
|
628
|
+
usedMappings.push(...componentsResult.mappings);
|
|
550
629
|
result = convertIconImports(result);
|
|
551
|
-
|
|
630
|
+
result = fixCodeFormat(result);
|
|
631
|
+
const uniqueMappings = usedMappings.filter(
|
|
632
|
+
(m, index, self) => self.findIndex((t) => t.arcoName === m.arcoName) === index
|
|
633
|
+
);
|
|
634
|
+
return {
|
|
635
|
+
code: result,
|
|
636
|
+
mappings: uniqueMappings,
|
|
637
|
+
warnings,
|
|
638
|
+
suggestions
|
|
639
|
+
};
|
|
552
640
|
}
|
|
553
|
-
function convertImports(code) {
|
|
641
|
+
function convertImports(code, warnings) {
|
|
554
642
|
let result = code;
|
|
643
|
+
const usedMappings = [];
|
|
555
644
|
const arcoImportRegex = /import\s+([\s\S]*?)\s+from\s+['"]@arco-design\/mobile-react['"]/g;
|
|
556
645
|
const matches = [...code.matchAll(arcoImportRegex)];
|
|
557
646
|
const bifyCoreComponents = [];
|
|
558
647
|
const bifyIconComponents = [];
|
|
559
|
-
const
|
|
648
|
+
const unsupportedComponents = [];
|
|
560
649
|
for (const match of matches) {
|
|
561
650
|
const importContent = match[1].trim();
|
|
562
651
|
const namedImportRegex = /\{([\s\S]*?)\}/;
|
|
@@ -566,62 +655,56 @@ function convertImports(code) {
|
|
|
566
655
|
for (const component of components) {
|
|
567
656
|
const mapping = findMappingByArcoName(component);
|
|
568
657
|
if (mapping) {
|
|
658
|
+
usedMappings.push(mapping);
|
|
569
659
|
if (mapping.bifyImport === "@fjyueke/bify-icons") {
|
|
570
660
|
bifyIconComponents.push(component);
|
|
571
661
|
} else {
|
|
572
662
|
bifyCoreComponents.push(mapping.bifyName || component);
|
|
573
663
|
}
|
|
574
664
|
} else {
|
|
575
|
-
|
|
665
|
+
unsupportedComponents.push(component);
|
|
576
666
|
}
|
|
577
667
|
}
|
|
578
|
-
} else {
|
|
579
|
-
remainingComponents.push(importContent);
|
|
580
668
|
}
|
|
581
669
|
result = result.replace(match[0], "");
|
|
582
670
|
}
|
|
583
671
|
result = result.trim();
|
|
584
672
|
if (bifyCoreComponents.length > 0) {
|
|
585
|
-
const
|
|
673
|
+
const uniqueCoreComponents = [...new Set(bifyCoreComponents)];
|
|
674
|
+
const coreImport = `import { ${uniqueCoreComponents.join(", ")} } from "@fjyueke/bify-core"
|
|
586
675
|
`;
|
|
587
676
|
result = coreImport + result;
|
|
588
677
|
}
|
|
589
678
|
if (bifyIconComponents.length > 0) {
|
|
590
|
-
const
|
|
679
|
+
const uniqueIconComponents = [...new Set(bifyIconComponents)];
|
|
680
|
+
const iconImport = `import { ${uniqueIconComponents.join(", ")} } from "@fjyueke/bify-icons"
|
|
591
681
|
`;
|
|
592
682
|
result = iconImport + result;
|
|
593
683
|
}
|
|
594
|
-
|
|
684
|
+
if (unsupportedComponents.length > 0) {
|
|
685
|
+
warnings.push(`\u4EE5\u4E0B\u7EC4\u4EF6\u6682\u4E0D\u652F\u6301\u81EA\u52A8\u8F6C\u6362\uFF1A${unsupportedComponents.join(", ")}`);
|
|
686
|
+
}
|
|
687
|
+
return { code: result, mappings: usedMappings };
|
|
595
688
|
}
|
|
596
|
-
function convertComponents(code) {
|
|
689
|
+
function convertComponents(code, warnings, suggestions) {
|
|
597
690
|
let result = code;
|
|
691
|
+
const usedMappings = [];
|
|
598
692
|
const arcoComponents = findAllArcoComponents();
|
|
599
693
|
for (const arcoComponent of arcoComponents) {
|
|
600
694
|
const mapping = findMappingByArcoName(arcoComponent);
|
|
601
695
|
if (!mapping || !mapping.bifyName) continue;
|
|
696
|
+
const componentPattern = new RegExp(`<${arcoComponent}`, "g");
|
|
697
|
+
if (!componentPattern.test(code)) continue;
|
|
698
|
+
usedMappings.push(mapping);
|
|
602
699
|
const bifyComponent = mapping.bifyName;
|
|
603
|
-
const
|
|
700
|
+
const selfClosingRegex = new RegExp(
|
|
604
701
|
`<${arcoComponent}([^>]*)\\/?>`,
|
|
605
702
|
"g"
|
|
606
703
|
);
|
|
607
|
-
result = result.replace(
|
|
704
|
+
result = result.replace(selfClosingRegex, (match, props) => {
|
|
608
705
|
let newProps = props;
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
`${propMapping.arcoProp}=(["'])(.*?)\\1`,
|
|
612
|
-
"g"
|
|
613
|
-
);
|
|
614
|
-
newProps = newProps.replace(propRegex, `${propMapping.bifyProp}=$1$2$1`);
|
|
615
|
-
}
|
|
616
|
-
if (arcoComponent === "Dialog" || arcoComponent === "Popup") {
|
|
617
|
-
newProps = newProps.replace(/visible=/g, "open=");
|
|
618
|
-
}
|
|
619
|
-
if (arcoComponent === "SearchBar" || arcoComponent === "Field" || arcoComponent === "Textarea") {
|
|
620
|
-
newProps = newProps.replace(/value=/g, "modelValue=");
|
|
621
|
-
}
|
|
622
|
-
if (arcoComponent === "Cell") {
|
|
623
|
-
newProps = newProps.replace(/showArrow/g, "clickable");
|
|
624
|
-
}
|
|
706
|
+
newProps = applyPropMappings(newProps, mapping, warnings);
|
|
707
|
+
newProps = applyValueMappings(newProps, mapping);
|
|
625
708
|
return `<${bifyComponent}${newProps}/>`;
|
|
626
709
|
});
|
|
627
710
|
const closingComponentRegex = new RegExp(
|
|
@@ -630,23 +713,58 @@ function convertComponents(code) {
|
|
|
630
713
|
);
|
|
631
714
|
result = result.replace(closingComponentRegex, (match, props, children) => {
|
|
632
715
|
let newProps = props;
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
716
|
+
newProps = applyPropMappings(newProps, mapping, warnings);
|
|
717
|
+
newProps = applyValueMappings(newProps, mapping);
|
|
718
|
+
return `<${bifyComponent}${newProps}>${children}</${bifyComponent}>`;
|
|
719
|
+
});
|
|
720
|
+
addSuggestions(mapping, suggestions);
|
|
721
|
+
}
|
|
722
|
+
return { code: result, mappings: usedMappings };
|
|
723
|
+
}
|
|
724
|
+
function applyPropMappings(props, mapping, warnings) {
|
|
725
|
+
let result = props;
|
|
726
|
+
const arcoProps = props.match(/\b(\w+)=/g)?.map((p) => p.slice(0, -1)) || [];
|
|
727
|
+
const mappedProps = mapping.propMappings.map((m) => m.arcoProp);
|
|
728
|
+
for (const arcoProp of arcoProps) {
|
|
729
|
+
if (!mappedProps.includes(arcoProp) && !["className", "style", "children"].includes(arcoProp)) {
|
|
730
|
+
warnings.push(`\u7EC4\u4EF6 ${mapping.arcoName} \u7684\u5C5E\u6027 ${arcoProp} \u672A\u627E\u5230\u6620\u5C04\uFF0C\u5DF2\u4FDD\u7559\u539F\u6837`);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
for (const propMapping of mapping.propMappings) {
|
|
734
|
+
const propRegex = new RegExp(
|
|
735
|
+
`${propMapping.arcoProp}=(["'])(.*?)\\1`,
|
|
736
|
+
"g"
|
|
737
|
+
);
|
|
738
|
+
result = result.replace(propRegex, (match, quote, value) => {
|
|
739
|
+
if (propMapping.transform) {
|
|
740
|
+
const transformedValue = propMapping.transform(value);
|
|
741
|
+
return `${propMapping.bifyProp}=${quote}${transformedValue}${quote}`;
|
|
645
742
|
}
|
|
646
|
-
|
|
647
|
-
|
|
743
|
+
return `${propMapping.bifyProp}=${quote}${value}${quote}`;
|
|
744
|
+
});
|
|
745
|
+
const booleanPropRegex = new RegExp(`\\b${propMapping.arcoProp}\\b`, "g");
|
|
746
|
+
if (propMapping.transform) {
|
|
747
|
+
result = result.replace(booleanPropRegex, `${propMapping.bifyProp}=${propMapping.transform("")}`);
|
|
748
|
+
} else {
|
|
749
|
+
result = result.replace(booleanPropRegex, propMapping.bifyProp);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
return result;
|
|
753
|
+
}
|
|
754
|
+
function applyValueMappings(props, mapping) {
|
|
755
|
+
if (!mapping.valueMappings) return props;
|
|
756
|
+
let result = props;
|
|
757
|
+
for (const [propName, valueMap] of Object.entries(mapping.valueMappings)) {
|
|
758
|
+
const propRegex = new RegExp(
|
|
759
|
+
`${propName}=(["'])(.*?)\\1`,
|
|
760
|
+
"g"
|
|
761
|
+
);
|
|
762
|
+
result = result.replace(propRegex, (match, quote, value) => {
|
|
763
|
+
const mappedValue = valueMap[value] || value;
|
|
764
|
+
if (mappedValue !== value) {
|
|
765
|
+
return `${propName}=${quote}${mappedValue}${quote}`;
|
|
648
766
|
}
|
|
649
|
-
return
|
|
767
|
+
return match;
|
|
650
768
|
});
|
|
651
769
|
}
|
|
652
770
|
return result;
|
|
@@ -655,16 +773,51 @@ function convertIconImports(code) {
|
|
|
655
773
|
let result = code;
|
|
656
774
|
const arcoIconRegex = /import\s+Icon(\w+)\s+from\s+['"]@arco-design\/mobile-react\/es\/icon\/Icon(\w+)['"]/g;
|
|
657
775
|
result = result.replace(arcoIconRegex, 'import { Icon$1 } from "@fjyueke/bify-icons"');
|
|
776
|
+
const arcoIconsImportRegex = /import\s+\{([^}]+)\}\s+from\s+['"]@arco-design\/mobile-react\/es\/icon['"]/g;
|
|
777
|
+
result = result.replace(arcoIconsImportRegex, 'import { $1 } from "@fjyueke/bify-icons"');
|
|
658
778
|
return result;
|
|
659
779
|
}
|
|
780
|
+
function fixCodeFormat(code) {
|
|
781
|
+
let result = code;
|
|
782
|
+
result = result.replace(/\n{3,}/g, "\n\n");
|
|
783
|
+
result = result.replace(/import\s+\{\s*\}\s+from/g, "");
|
|
784
|
+
const lines = result.split("\n");
|
|
785
|
+
const nonEmptyLines = lines.filter((line) => line.trim() !== "");
|
|
786
|
+
result = nonEmptyLines.join("\n");
|
|
787
|
+
return result.trim();
|
|
788
|
+
}
|
|
789
|
+
function addSuggestions(mapping, suggestions) {
|
|
790
|
+
const suggestionMap = {
|
|
791
|
+
Cell: "Bify \u7684 Cell \u7EC4\u4EF6\u652F\u6301\u66F4\u591A\u5E03\u5C40\u5C5E\u6027\uFF0C\u5EFA\u8BAE\u67E5\u770B\u6587\u6863\u4E86\u89E3 align\u3001size \u7B49\u5C5E\u6027",
|
|
792
|
+
Button: "Bify \u7684 Button \u7EC4\u4EF6\u652F\u6301\u66F4\u591A\u6837\u5F0F\u53D8\u4F53\uFF0C\u5EFA\u8BAE\u67E5\u770B variant \u5C5E\u6027",
|
|
793
|
+
Dialog: "Bify \u7684 Dialog \u7EC4\u4EF6\u652F\u6301\u66F4\u591A\u4EA4\u4E92\u9009\u9879\uFF0C\u5EFA\u8BAE\u67E5\u770B closeOnClickOverlay \u7B49\u5C5E\u6027",
|
|
794
|
+
Tabs: "Bify \u7684 Tabs \u7EC4\u4EF6\u652F\u6301\u6ED1\u52A8\u5207\u6362\uFF0C\u5EFA\u8BAE\u67E5\u770B swipeable \u5C5E\u6027",
|
|
795
|
+
Field: "Bify \u7684 Field \u7EC4\u4EF6\u652F\u6301\u66F4\u591A\u9A8C\u8BC1\u5C5E\u6027\uFF0C\u5EFA\u8BAE\u67E5\u770B rules \u5C5E\u6027"
|
|
796
|
+
};
|
|
797
|
+
if (suggestionMap[mapping.arcoName]) {
|
|
798
|
+
suggestions.push(suggestionMap[mapping.arcoName]);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
660
801
|
async function getArcoConversionHelp() {
|
|
661
802
|
const availableComponents = componentMappings.filter((m) => m.bifyName).map((m) => `- ${m.arcoName} \u2192 ${m.bifyName}`).join("\n");
|
|
803
|
+
const valueMappingExamples = componentMappings.filter((m) => m.valueMappings).map((m) => {
|
|
804
|
+
const mappings = Object.entries(m.valueMappings).map(([prop, values]) => {
|
|
805
|
+
const valuePairs = Object.entries(values).map(([from, to]) => `${from} \u2192 ${to}`).join(", ");
|
|
806
|
+
return ` - ${prop}: ${valuePairs}`;
|
|
807
|
+
}).join("\n");
|
|
808
|
+
return `**${m.arcoName}**
|
|
809
|
+
${mappings}`;
|
|
810
|
+
}).join("\n\n");
|
|
662
811
|
return `## Arco Mobile \u2192 Bify \u4EE3\u7801\u8F6C\u6362
|
|
663
812
|
|
|
664
|
-
### \u652F\u6301\u7684\u7EC4\u4EF6
|
|
813
|
+
### \u652F\u6301\u7684\u7EC4\u4EF6 (${componentMappings.length} \u4E2A)
|
|
665
814
|
|
|
666
815
|
${availableComponents}
|
|
667
816
|
|
|
817
|
+
### \u503C\u6620\u5C04\u793A\u4F8B
|
|
818
|
+
|
|
819
|
+
${valueMappingExamples || "\u6682\u65E0"}
|
|
820
|
+
|
|
668
821
|
### \u4F7F\u7528\u65B9\u5F0F
|
|
669
822
|
|
|
670
823
|
\`\`\`tsx
|
|
@@ -674,7 +827,7 @@ import { Cell, CellGroup, Button } from '@arco-design/mobile-react';
|
|
|
674
827
|
<CellGroup>
|
|
675
828
|
<Cell label="\u6807\u9898" desc="\u63CF\u8FF0" showArrow>\u5185\u5BB9</Cell>
|
|
676
829
|
</CellGroup>
|
|
677
|
-
<Button type="primary">\u6309\u94AE</Button>
|
|
830
|
+
<Button type="primary" ghost>\u6309\u94AE</Button>
|
|
678
831
|
|
|
679
832
|
// \u8F6C\u6362\u4E3A Bify \u4EE3\u7801
|
|
680
833
|
import { Cell, CellGroup, Button } from '@fjyueke/bify-core';
|
|
@@ -682,23 +835,31 @@ import { Cell, CellGroup, Button } from '@fjyueke/bify-core';
|
|
|
682
835
|
<CellGroup>
|
|
683
836
|
<Cell title="\u6807\u9898" brief="\u63CF\u8FF0" clickable>\u5185\u5BB9</Cell>
|
|
684
837
|
</CellGroup>
|
|
685
|
-
<Button type="primary">\u6309\u94AE</Button>
|
|
838
|
+
<Button type="primary" outlined>\u6309\u94AE</Button>
|
|
686
839
|
\`\`\`
|
|
687
840
|
|
|
688
841
|
### \u5C5E\u6027\u6620\u5C04\u793A\u4F8B
|
|
689
842
|
|
|
690
|
-
| Arco \u5C5E\u6027 | Bify \u5C5E\u6027 |
|
|
691
|
-
|
|
692
|
-
| \`label\` | \`title\` |
|
|
693
|
-
| \`desc\` | \`brief\` |
|
|
694
|
-
| \`showArrow\` | \`clickable\` |
|
|
695
|
-
| \`visible\` | \`open\` |
|
|
696
|
-
| \`value\` | \`modelValue\` |
|
|
697
|
-
| \`ghost\` | \`
|
|
843
|
+
| Arco \u5C5E\u6027 | Bify \u5C5E\u6027 | \u8BF4\u660E |
|
|
844
|
+
|-----------|-----------|------|
|
|
845
|
+
| \`label\` | \`title\` | \u5355\u5143\u683C\u6807\u9898 |
|
|
846
|
+
| \`desc\` | \`brief\` | \u5355\u5143\u683C\u63CF\u8FF0 |
|
|
847
|
+
| \`showArrow\` | \`clickable\` | \u662F\u5426\u663E\u793A\u7BAD\u5934 |
|
|
848
|
+
| \`visible\` | \`open\` | \u5F39\u7A97\u663E\u793A\u72B6\u6001 |
|
|
849
|
+
| \`value\` | \`modelValue\` | \u8868\u5355\u503C\u7ED1\u5B9A |
|
|
850
|
+
| \`ghost\` | \`outlined\` | \u9542\u7A7A\u6309\u94AE\u6837\u5F0F |
|
|
851
|
+
| \`max\` | \`count\` | Rate \u6700\u5927\u6570\u91CF |
|
|
852
|
+
| \`percent\` | \`percentage\` | Progress \u767E\u5206\u6BD4 |
|
|
853
|
+
|
|
854
|
+
### \u6700\u4F73\u5B9E\u8DF5
|
|
855
|
+
|
|
856
|
+
1. **\u4F7F\u7528 AI \u8F85\u52A9\u8F6C\u6362**\uFF1A\u540C\u65F6\u914D\u7F6E Arco Mobile MCP \u548C Bify MCP\uFF0C\u8BA9 AI \u67E5\u8BE2\u53CC\u65B9\u6587\u6863\u540E\u518D\u8FDB\u884C\u8F6C\u6362
|
|
857
|
+
2. **\u624B\u52A8\u68C0\u67E5**\uFF1A\u8F6C\u6362\u540E\u8BF7\u68C0\u67E5\u8B66\u544A\u4FE1\u606F\uFF0C\u5904\u7406\u672A\u6620\u5C04\u7684\u5C5E\u6027
|
|
858
|
+
3. **\u53C2\u8003\u6587\u6863**\uFF1A\u4F7F\u7528 \`get-component-docs\` \u548C \`get-component-props\` \u67E5\u770B Bify \u7EC4\u4EF6\u7684\u8BE6\u7EC6\u7528\u6CD5
|
|
698
859
|
|
|
699
860
|
### \u8C03\u7528\u65B9\u5F0F
|
|
700
861
|
|
|
701
|
-
\u4F7F\u7528 \`convert-arco-to-bify\` \u5DE5\u5177\uFF0C\u4F20\u5165 Arco Mobile \u4EE3\u7801\u5373\u53EF\u83B7\u5F97\u8F6C\u6362\u540E\u7684 Bify \u4EE3\u7801\u3002`;
|
|
862
|
+
\u4F7F\u7528 \`convert-arco-to-bify\` \u5DE5\u5177\uFF0C\u4F20\u5165 Arco Mobile \u4EE3\u7801\u5373\u53EF\u83B7\u5F97\u8F6C\u6362\u540E\u7684 Bify \u4EE3\u7801\u53CA\u8BE6\u7EC6\u62A5\u544A\u3002`;
|
|
702
863
|
}
|
|
703
864
|
|
|
704
865
|
// src/tools/components.ts
|
|
@@ -770,19 +931,50 @@ function registerTifyTools(server) {
|
|
|
770
931
|
);
|
|
771
932
|
server.tool(
|
|
772
933
|
"convert-arco-to-bify",
|
|
773
|
-
"Converts Arco Mobile React code to Bify code",
|
|
934
|
+
"Converts Arco Mobile React code to Bify code with detailed report including warnings and suggestions",
|
|
774
935
|
{ arcoCode: z.string() },
|
|
775
936
|
async (args) => {
|
|
776
|
-
const
|
|
937
|
+
const result = await convertArcoToBify(args.arcoCode);
|
|
938
|
+
let report = `## \u8F6C\u6362\u7ED3\u679C
|
|
939
|
+
|
|
940
|
+
### \u8F6C\u6362\u540E\u7684\u4EE3\u7801
|
|
941
|
+
|
|
942
|
+
\`\`\`tsx
|
|
943
|
+
${result.code}
|
|
944
|
+
\`\`\``;
|
|
945
|
+
if (result.mappings.length > 0) {
|
|
946
|
+
report += `
|
|
947
|
+
|
|
948
|
+
### \u4F7F\u7528\u7684\u6620\u5C04
|
|
949
|
+
|
|
950
|
+
| Arco \u7EC4\u4EF6 | Bify \u7EC4\u4EF6 |
|
|
951
|
+
|-----------|-----------|
|
|
952
|
+
${result.mappings.map((m) => `| ${m.arcoName} | ${m.bifyName} |`).join("\n")}`;
|
|
953
|
+
}
|
|
954
|
+
if (result.warnings.length > 0) {
|
|
955
|
+
report += `
|
|
956
|
+
|
|
957
|
+
### \u26A0\uFE0F \u8B66\u544A
|
|
958
|
+
|
|
959
|
+
- ${result.warnings.join("\n- ")}`;
|
|
960
|
+
}
|
|
961
|
+
if (result.suggestions.length > 0) {
|
|
962
|
+
report += `
|
|
963
|
+
|
|
964
|
+
### \u{1F4A1} \u5EFA\u8BAE
|
|
965
|
+
|
|
966
|
+
- ${result.suggestions.join("\n- ")}`;
|
|
967
|
+
}
|
|
968
|
+
report += `
|
|
969
|
+
|
|
970
|
+
### \u8F6C\u6362\u8BF4\u660E
|
|
971
|
+
|
|
972
|
+
\u5982\u9700\u66F4\u7CBE\u786E\u7684\u8F6C\u6362\uFF0C\u5EFA\u8BAE\u540C\u65F6\u4F7F\u7528 Arco Mobile MCP \u548C Bify MCP \u67E5\u8BE2\u53CC\u65B9\u7EC4\u4EF6\u6587\u6863\u540E\u8FDB\u884C\u624B\u52A8\u8C03\u6574\u3002`;
|
|
777
973
|
return {
|
|
778
974
|
content: [
|
|
779
975
|
{
|
|
780
976
|
type: "text",
|
|
781
|
-
text:
|
|
782
|
-
|
|
783
|
-
\`\`\`tsx
|
|
784
|
-
${convertedCode}
|
|
785
|
-
\`\`\``
|
|
977
|
+
text: report
|
|
786
978
|
}
|
|
787
979
|
]
|
|
788
980
|
};
|