mofox-plugin-dev-toolkit 0.3.3__py3-none-any.whl
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.
- mofox_plugin_dev_toolkit-0.3.3.dist-info/METADATA +730 -0
- mofox_plugin_dev_toolkit-0.3.3.dist-info/RECORD +46 -0
- mofox_plugin_dev_toolkit-0.3.3.dist-info/WHEEL +5 -0
- mofox_plugin_dev_toolkit-0.3.3.dist-info/entry_points.txt +2 -0
- mofox_plugin_dev_toolkit-0.3.3.dist-info/licenses/LICENSE +674 -0
- mofox_plugin_dev_toolkit-0.3.3.dist-info/top_level.txt +1 -0
- mpdt/__init__.py +15 -0
- mpdt/__main__.py +8 -0
- mpdt/cli.py +316 -0
- mpdt/commands/__init__.py +9 -0
- mpdt/commands/check.py +498 -0
- mpdt/commands/dev.py +318 -0
- mpdt/commands/generate.py +448 -0
- mpdt/commands/init.py +686 -0
- mpdt/dev/bridge_plugin/__init__.py +17 -0
- mpdt/dev/bridge_plugin/cleanup_handler.py +65 -0
- mpdt/dev/bridge_plugin/dev_config.py +24 -0
- mpdt/dev/bridge_plugin/file_watcher.py +169 -0
- mpdt/dev/bridge_plugin/plugin.py +219 -0
- mpdt/templates/__init__.py +165 -0
- mpdt/templates/action_template.py +102 -0
- mpdt/templates/adapter_template.py +129 -0
- mpdt/templates/chatter_template.py +103 -0
- mpdt/templates/event_template.py +116 -0
- mpdt/templates/plus_command_template.py +150 -0
- mpdt/templates/prompt_template.py +92 -0
- mpdt/templates/router_template.py +175 -0
- mpdt/templates/tool_template.py +98 -0
- mpdt/utils/__init__.py +10 -0
- mpdt/utils/code_parser.py +401 -0
- mpdt/utils/color_printer.py +99 -0
- mpdt/utils/config_loader.py +171 -0
- mpdt/utils/config_manager.py +297 -0
- mpdt/utils/file_ops.py +207 -0
- mpdt/utils/license_generator.py +980 -0
- mpdt/utils/plugin_parser.py +195 -0
- mpdt/utils/template_engine.py +112 -0
- mpdt/validators/__init__.py +26 -0
- mpdt/validators/auto_fix_validator.py +990 -0
- mpdt/validators/base.py +129 -0
- mpdt/validators/component_validator.py +842 -0
- mpdt/validators/config_validator.py +119 -0
- mpdt/validators/metadata_validator.py +107 -0
- mpdt/validators/structure_validator.py +72 -0
- mpdt/validators/style_validator.py +117 -0
- mpdt/validators/type_validator.py +206 -0
mpdt/commands/check.py
ADDED
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
"""
|
|
2
|
+
静态检查命令实现
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from rich.panel import Panel
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
|
|
10
|
+
from mpdt.utils.color_printer import console, print_error, print_info, print_success, print_warning
|
|
11
|
+
from mpdt.validators import (
|
|
12
|
+
AutoFixValidator,
|
|
13
|
+
ComponentValidator,
|
|
14
|
+
ConfigValidator,
|
|
15
|
+
MetadataValidator,
|
|
16
|
+
StructureValidator,
|
|
17
|
+
StyleValidator,
|
|
18
|
+
TypeValidator,
|
|
19
|
+
ValidationLevel,
|
|
20
|
+
ValidationResult,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def check_plugin(
|
|
25
|
+
plugin_path: str,
|
|
26
|
+
level: str = "warning",
|
|
27
|
+
auto_fix: bool = False,
|
|
28
|
+
report_format: str = "console",
|
|
29
|
+
output_path: str | None = None,
|
|
30
|
+
skip_structure: bool = False,
|
|
31
|
+
skip_metadata: bool = False,
|
|
32
|
+
skip_component: bool = False,
|
|
33
|
+
skip_type: bool = False,
|
|
34
|
+
skip_style: bool = False,
|
|
35
|
+
verbose: bool = False,
|
|
36
|
+
) -> None:
|
|
37
|
+
"""
|
|
38
|
+
检查插件
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
plugin_path: 插件路径
|
|
42
|
+
level: 显示级别 (error, warning, info)
|
|
43
|
+
auto_fix: 自动修复
|
|
44
|
+
report_format: 报告格式 (console, markdown)
|
|
45
|
+
output_path: 输出路径
|
|
46
|
+
skip_structure: 跳过结构检查
|
|
47
|
+
skip_metadata: 跳过元数据检查
|
|
48
|
+
skip_component: 跳过组件检查
|
|
49
|
+
skip_type: 跳过类型检查
|
|
50
|
+
skip_style: 跳过代码风格检查
|
|
51
|
+
skip_security: 跳过安全检查
|
|
52
|
+
verbose: 详细输出
|
|
53
|
+
"""
|
|
54
|
+
path = Path(plugin_path).resolve()
|
|
55
|
+
|
|
56
|
+
if not path.exists():
|
|
57
|
+
print_error(f"插件路径不存在: {plugin_path}")
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
if not path.is_dir():
|
|
61
|
+
print_error(f"插件路径不是目录: {plugin_path}")
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
console.print(Panel.fit(f"🔍 检查插件: [cyan]{path.name}[/cyan]", border_style="blue"))
|
|
65
|
+
|
|
66
|
+
# 收集所有验证结果
|
|
67
|
+
all_results: list[ValidationResult] = []
|
|
68
|
+
|
|
69
|
+
# 结构验证
|
|
70
|
+
if not skip_structure:
|
|
71
|
+
print_info("正在检查插件结构...")
|
|
72
|
+
validator = StructureValidator(path)
|
|
73
|
+
result = validator.validate()
|
|
74
|
+
all_results.append(result)
|
|
75
|
+
_print_validation_summary(result, verbose)
|
|
76
|
+
|
|
77
|
+
# 元数据验证
|
|
78
|
+
if not skip_metadata:
|
|
79
|
+
print_info("正在检查插件元数据...")
|
|
80
|
+
validator = MetadataValidator(path)
|
|
81
|
+
result = validator.validate()
|
|
82
|
+
all_results.append(result)
|
|
83
|
+
_print_validation_summary(result, verbose)
|
|
84
|
+
|
|
85
|
+
# 组件验证
|
|
86
|
+
if not skip_component:
|
|
87
|
+
print_info("正在检查组件元数据...")
|
|
88
|
+
validator = ComponentValidator(path)
|
|
89
|
+
result = validator.validate()
|
|
90
|
+
all_results.append(result)
|
|
91
|
+
_print_validation_summary(result, verbose)
|
|
92
|
+
|
|
93
|
+
# 配置验证
|
|
94
|
+
print_info("正在检查配置文件...")
|
|
95
|
+
validator = ConfigValidator(path)
|
|
96
|
+
result = validator.validate()
|
|
97
|
+
all_results.append(result)
|
|
98
|
+
_print_validation_summary(result, verbose)
|
|
99
|
+
|
|
100
|
+
# 类型检查
|
|
101
|
+
if not skip_type:
|
|
102
|
+
print_info("正在进行类型检查...")
|
|
103
|
+
validator = TypeValidator(path)
|
|
104
|
+
result = validator.validate()
|
|
105
|
+
all_results.append(result)
|
|
106
|
+
_print_validation_summary(result, verbose)
|
|
107
|
+
|
|
108
|
+
# 代码风格检查
|
|
109
|
+
if not skip_style:
|
|
110
|
+
print_info("正在检查代码风格...")
|
|
111
|
+
validator = StyleValidator(path)
|
|
112
|
+
result = validator.validate()
|
|
113
|
+
all_results.append(result)
|
|
114
|
+
_print_validation_summary(result, verbose)
|
|
115
|
+
|
|
116
|
+
# 自动修复(如果启用)
|
|
117
|
+
auto_fixer = None
|
|
118
|
+
if auto_fix:
|
|
119
|
+
print_info("正在应用自动修复...")
|
|
120
|
+
auto_fixer = AutoFixValidator(path)
|
|
121
|
+
fix_result = auto_fixer.fix_issues(all_results)
|
|
122
|
+
|
|
123
|
+
# 从原始结果中移除已修复的问题(使用对象 id 比较)
|
|
124
|
+
fixed_issue_ids = {id(issue) for issue in auto_fixer.fixed_issues}
|
|
125
|
+
for result in all_results:
|
|
126
|
+
result.issues = [issue for issue in result.issues if id(issue) not in fixed_issue_ids]
|
|
127
|
+
# 更新计数
|
|
128
|
+
result._update_counts()
|
|
129
|
+
|
|
130
|
+
# 如果应用了 ruff 修复,移除所有可以被 ruff 修复的问题
|
|
131
|
+
if any("ruff" in fix for fix in auto_fixer.fixes_applied):
|
|
132
|
+
import re
|
|
133
|
+
ruff_fixed_count = 0
|
|
134
|
+
for result in all_results:
|
|
135
|
+
original_count = len(result.issues)
|
|
136
|
+
# 移除所有 ruff 错误格式的问题(如果建议包含"可自动修复"或问题本身就是 ruff 格式)
|
|
137
|
+
result.issues = [
|
|
138
|
+
issue for issue in result.issues
|
|
139
|
+
if not (
|
|
140
|
+
re.match(r'^[A-Z]\d+:', issue.message) and
|
|
141
|
+
(issue.suggestion is None or "可自动修复" in issue.suggestion or "--fix" in issue.suggestion)
|
|
142
|
+
)
|
|
143
|
+
]
|
|
144
|
+
ruff_fixed_count += original_count - len(result.issues)
|
|
145
|
+
# 更新计数
|
|
146
|
+
result._update_counts()
|
|
147
|
+
|
|
148
|
+
# 显示修复摘要
|
|
149
|
+
if auto_fixer.fixes_applied:
|
|
150
|
+
print_success(f" ✓ 成功修复 {len(auto_fixer.fixes_applied)} 个问题")
|
|
151
|
+
if verbose:
|
|
152
|
+
for fix in auto_fixer.fixes_applied:
|
|
153
|
+
console.print(f" [green]✓[/green] {fix}")
|
|
154
|
+
|
|
155
|
+
if auto_fixer.fixes_failed:
|
|
156
|
+
print_warning(f" ⚠ {len(auto_fixer.fixes_failed)} 个问题修复失败")
|
|
157
|
+
if verbose:
|
|
158
|
+
for fail in auto_fixer.fixes_failed:
|
|
159
|
+
console.print(f" [yellow]✗[/yellow] {fail}")
|
|
160
|
+
|
|
161
|
+
if not auto_fixer.fixes_applied and not auto_fixer.fixes_failed:
|
|
162
|
+
print_info(" ℹ 未发现可自动修复的问题")
|
|
163
|
+
|
|
164
|
+
# 生成总体报告
|
|
165
|
+
_print_overall_report(all_results, level, auto_fixer)
|
|
166
|
+
|
|
167
|
+
# 保存报告(如果需要)
|
|
168
|
+
if output_path:
|
|
169
|
+
_save_report(all_results, output_path, report_format, auto_fixer)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _print_validation_summary(result: ValidationResult, verbose: bool = False) -> None:
|
|
173
|
+
"""打印验证摘要
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
result: 验证结果
|
|
177
|
+
verbose: 是否详细输出
|
|
178
|
+
"""
|
|
179
|
+
if result.success:
|
|
180
|
+
print_success(f" ✓ {result.validator_name}: 通过")
|
|
181
|
+
else:
|
|
182
|
+
print_error(f" ✗ {result.validator_name}: 发现 {result.error_count} 个错误")
|
|
183
|
+
|
|
184
|
+
if verbose and result.issues:
|
|
185
|
+
for issue in result.issues:
|
|
186
|
+
_print_issue(issue)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _print_issue(issue) -> None:
|
|
190
|
+
"""打印单个问题
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
issue: 验证问题
|
|
194
|
+
"""
|
|
195
|
+
level_colors = {
|
|
196
|
+
ValidationLevel.ERROR: "red",
|
|
197
|
+
ValidationLevel.WARNING: "yellow",
|
|
198
|
+
ValidationLevel.INFO: "blue",
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
level_icons = {
|
|
202
|
+
ValidationLevel.ERROR: "✗",
|
|
203
|
+
ValidationLevel.WARNING: "⚠",
|
|
204
|
+
ValidationLevel.INFO: "ℹ",
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
color = level_colors.get(issue.level, "white")
|
|
208
|
+
icon = level_icons.get(issue.level, "•")
|
|
209
|
+
|
|
210
|
+
message = f" [{color}]{icon}[/{color}] {issue.message}"
|
|
211
|
+
|
|
212
|
+
if issue.file_path:
|
|
213
|
+
message += f" ([dim]{issue.file_path}"
|
|
214
|
+
if issue.line_number:
|
|
215
|
+
message += f":{issue.line_number}"
|
|
216
|
+
message += "[/dim])"
|
|
217
|
+
|
|
218
|
+
console.print(message)
|
|
219
|
+
|
|
220
|
+
if issue.suggestion:
|
|
221
|
+
console.print(f" [dim]💡 {issue.suggestion}[/dim]")
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _print_overall_report(
|
|
225
|
+
results: list[ValidationResult], level: str, auto_fixer: AutoFixValidator | None = None
|
|
226
|
+
) -> None:
|
|
227
|
+
"""打印总体报告
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
results: 所有验证结果
|
|
231
|
+
level: 显示级别
|
|
232
|
+
auto_fixer: 自动修复器对象(如果启用了自动修复)
|
|
233
|
+
"""
|
|
234
|
+
console.print()
|
|
235
|
+
console.print("=" * 60)
|
|
236
|
+
console.print()
|
|
237
|
+
|
|
238
|
+
# 统计总数
|
|
239
|
+
total_errors = sum(r.error_count for r in results)
|
|
240
|
+
total_warnings = sum(r.warning_count for r in results)
|
|
241
|
+
|
|
242
|
+
# 创建统计表格
|
|
243
|
+
table = Table(title="检查结果汇总", show_header=True, header_style="bold")
|
|
244
|
+
table.add_column("验证器", style="cyan")
|
|
245
|
+
table.add_column("错误", style="red")
|
|
246
|
+
table.add_column("警告", style="yellow")
|
|
247
|
+
table.add_column("信息", style="blue")
|
|
248
|
+
table.add_column("状态", style="green")
|
|
249
|
+
|
|
250
|
+
for result in results:
|
|
251
|
+
status = "✓ 通过" if result.success else "✗ 失败"
|
|
252
|
+
status_style = "green" if result.success else "red"
|
|
253
|
+
table.add_row(
|
|
254
|
+
result.validator_name,
|
|
255
|
+
str(result.error_count),
|
|
256
|
+
str(result.warning_count),
|
|
257
|
+
str(result.info_count),
|
|
258
|
+
f"[{status_style}]{status}[/{status_style}]",
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
console.print(table)
|
|
262
|
+
console.print()
|
|
263
|
+
|
|
264
|
+
# 打印详细问题列表
|
|
265
|
+
level_filter = ValidationLevel(level)
|
|
266
|
+
for result in results:
|
|
267
|
+
filtered_issues = [
|
|
268
|
+
issue
|
|
269
|
+
for issue in result.issues
|
|
270
|
+
if (issue.level == ValidationLevel.ERROR)
|
|
271
|
+
or (
|
|
272
|
+
issue.level == ValidationLevel.WARNING
|
|
273
|
+
and level_filter in [ValidationLevel.WARNING, ValidationLevel.INFO]
|
|
274
|
+
)
|
|
275
|
+
or (issue.level == ValidationLevel.INFO and level_filter == ValidationLevel.INFO)
|
|
276
|
+
]
|
|
277
|
+
|
|
278
|
+
if filtered_issues:
|
|
279
|
+
console.print(f"\n[bold]{result.validator_name}:[/bold]")
|
|
280
|
+
for issue in filtered_issues:
|
|
281
|
+
_print_issue(issue)
|
|
282
|
+
|
|
283
|
+
# 总结
|
|
284
|
+
console.print()
|
|
285
|
+
if auto_fixer:
|
|
286
|
+
console.print("[bold cyan]═══ 修复统计 ═══[/bold cyan]")
|
|
287
|
+
console.print()
|
|
288
|
+
|
|
289
|
+
if auto_fixer.fixes_applied:
|
|
290
|
+
console.print(f"[green]✓ 成功修复: {len(auto_fixer.fixes_applied)} 个[/green]")
|
|
291
|
+
for fix in auto_fixer.fixes_applied:
|
|
292
|
+
console.print(f" [green]•[/green] {fix}")
|
|
293
|
+
console.print()
|
|
294
|
+
|
|
295
|
+
if auto_fixer.fixes_failed:
|
|
296
|
+
console.print(f"[yellow]✗ 修复失败: {len(auto_fixer.fixes_failed)} 个[/yellow]")
|
|
297
|
+
for fail in auto_fixer.fixes_failed:
|
|
298
|
+
console.print(f" [yellow]•[/yellow] {fail}")
|
|
299
|
+
console.print()
|
|
300
|
+
|
|
301
|
+
if not auto_fixer.fixes_applied and not auto_fixer.fixes_failed:
|
|
302
|
+
console.print("[blue]ℹ 未发现可自动修复的问题[/blue]")
|
|
303
|
+
console.print()
|
|
304
|
+
|
|
305
|
+
console.print("[bold cyan]═══ 最终结果 ═══[/bold cyan]")
|
|
306
|
+
console.print()
|
|
307
|
+
if total_errors > 0:
|
|
308
|
+
print_error(f"剩余 {total_errors} 个错误,{total_warnings} 个警告")
|
|
309
|
+
elif total_warnings > 0:
|
|
310
|
+
print_warning(f"剩余 {total_warnings} 个警告")
|
|
311
|
+
else:
|
|
312
|
+
print_success("所有检查通过!")
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def _save_report(
|
|
316
|
+
results: list[ValidationResult], output_path: str, report_format: str, auto_fixer: AutoFixValidator | None = None
|
|
317
|
+
) -> None:
|
|
318
|
+
"""保存检查报告
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
results: 验证结果列表
|
|
322
|
+
output_path: 输出路径
|
|
323
|
+
report_format: 报告格式
|
|
324
|
+
auto_fixer: 自动修复器对象(如果启用了自动修复)
|
|
325
|
+
"""
|
|
326
|
+
if report_format == "markdown":
|
|
327
|
+
_save_markdown_report(results, output_path, auto_fixer)
|
|
328
|
+
elif report_format == "json":
|
|
329
|
+
_save_json_report(results, output_path, auto_fixer)
|
|
330
|
+
else:
|
|
331
|
+
print_warning(f"不支持的报告格式: {report_format}")
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def _save_markdown_report(
|
|
335
|
+
results: list[ValidationResult], output_path: str, auto_fixer: AutoFixValidator | None = None
|
|
336
|
+
) -> None:
|
|
337
|
+
"""保存 Markdown 格式的报告
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
results: 验证结果列表
|
|
341
|
+
output_path: 输出路径
|
|
342
|
+
auto_fixer: 自动修复器对象(如果启用了自动修复)
|
|
343
|
+
"""
|
|
344
|
+
lines = ["# 插件检查报告\n\n"]
|
|
345
|
+
|
|
346
|
+
# 统计
|
|
347
|
+
total_errors = sum(r.error_count for r in results)
|
|
348
|
+
total_warnings = sum(r.warning_count for r in results)
|
|
349
|
+
total_info = sum(r.info_count for r in results)
|
|
350
|
+
|
|
351
|
+
lines.append("## 摘要\n\n")
|
|
352
|
+
lines.append(f"- 错误: {total_errors}\n")
|
|
353
|
+
lines.append(f"- 警告: {total_warnings}\n")
|
|
354
|
+
lines.append(f"- 信息: {total_info}\n")
|
|
355
|
+
|
|
356
|
+
# 修复统计
|
|
357
|
+
if auto_fixer:
|
|
358
|
+
lines.append("\n### 自动修复统计\n\n")
|
|
359
|
+
if auto_fixer.fixes_applied:
|
|
360
|
+
lines.append(f"- ✅ 成功修复: {len(auto_fixer.fixes_applied)} 个\n")
|
|
361
|
+
for fix in auto_fixer.fixes_applied:
|
|
362
|
+
lines.append(f" - {fix}\n")
|
|
363
|
+
if auto_fixer.fixes_failed:
|
|
364
|
+
lines.append(f"- ❌ 修复失败: {len(auto_fixer.fixes_failed)} 个\n")
|
|
365
|
+
for fail in auto_fixer.fixes_failed:
|
|
366
|
+
lines.append(f" - {fail}\n")
|
|
367
|
+
if not auto_fixer.fixes_applied and not auto_fixer.fixes_failed:
|
|
368
|
+
lines.append("- ℹ️ 未发现可自动修复的问题\n")
|
|
369
|
+
|
|
370
|
+
lines.append("\n")
|
|
371
|
+
|
|
372
|
+
# 详细结果
|
|
373
|
+
for result in results:
|
|
374
|
+
lines.append(f"## {result.validator_name}\n")
|
|
375
|
+
|
|
376
|
+
if result.success:
|
|
377
|
+
lines.append("✓ 通过\n\n")
|
|
378
|
+
else:
|
|
379
|
+
lines.append(f"✗ 发现 {result.error_count} 个错误\n\n")
|
|
380
|
+
|
|
381
|
+
if result.issues:
|
|
382
|
+
lines.append("### 问题列表\n\n")
|
|
383
|
+
for issue in result.issues:
|
|
384
|
+
level_icons = {
|
|
385
|
+
ValidationLevel.ERROR: "❌",
|
|
386
|
+
ValidationLevel.WARNING: "⚠️",
|
|
387
|
+
ValidationLevel.INFO: "ℹ️",
|
|
388
|
+
}
|
|
389
|
+
icon = level_icons.get(issue.level, "•")
|
|
390
|
+
lines.append(f"- {icon} **{issue.level.value.upper()}**: {issue.message}\n")
|
|
391
|
+
|
|
392
|
+
if issue.file_path:
|
|
393
|
+
lines.append(f" - 文件: `{issue.file_path}`")
|
|
394
|
+
if issue.line_number:
|
|
395
|
+
lines.append(f":{issue.line_number}")
|
|
396
|
+
lines.append("\n")
|
|
397
|
+
|
|
398
|
+
if issue.suggestion:
|
|
399
|
+
lines.append(f" - 建议: {issue.suggestion}\n")
|
|
400
|
+
|
|
401
|
+
lines.append("\n")
|
|
402
|
+
|
|
403
|
+
# 总结
|
|
404
|
+
lines.append("## 总结\n\n")
|
|
405
|
+
if auto_fixer and auto_fixer.fixes_applied:
|
|
406
|
+
lines.append(f"✅ 成功修复 {len(auto_fixer.fixes_applied)} 个问题\n\n")
|
|
407
|
+
if auto_fixer.fixes_failed:
|
|
408
|
+
lines.append(f"⚠️ {len(auto_fixer.fixes_failed)} 个问题修复失败\n\n")
|
|
409
|
+
|
|
410
|
+
if total_errors > 0:
|
|
411
|
+
lines.append(f"❌ 剩余 {total_errors} 个错误,{total_warnings} 个警告\n")
|
|
412
|
+
elif total_warnings > 0:
|
|
413
|
+
lines.append(f"⚠️ 剩余 {total_warnings} 个警告\n")
|
|
414
|
+
else:
|
|
415
|
+
lines.append("✅ 所有检查通过!\n")
|
|
416
|
+
|
|
417
|
+
# 写入文件
|
|
418
|
+
try:
|
|
419
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
420
|
+
f.writelines(lines)
|
|
421
|
+
print_success(f"报告已保存到: {output_path}")
|
|
422
|
+
except Exception as e:
|
|
423
|
+
print_error(f"保存报告失败: {e}")
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def _save_json_report(
|
|
427
|
+
results: list[ValidationResult], output_path: str, auto_fixer: AutoFixValidator | None = None
|
|
428
|
+
) -> None:
|
|
429
|
+
"""保存 JSON 格式的报告
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
results: 验证结果列表
|
|
433
|
+
output_path: 输出路径
|
|
434
|
+
auto_fixer: 自动修复器对象(如果启用了自动修复)
|
|
435
|
+
"""
|
|
436
|
+
import json
|
|
437
|
+
from datetime import datetime
|
|
438
|
+
|
|
439
|
+
# 统计总数
|
|
440
|
+
total_errors = sum(r.error_count for r in results)
|
|
441
|
+
total_warnings = sum(r.warning_count for r in results)
|
|
442
|
+
total_info = sum(r.info_count for r in results)
|
|
443
|
+
|
|
444
|
+
# 构建报告数据结构
|
|
445
|
+
report = {
|
|
446
|
+
"timestamp": datetime.now().isoformat(),
|
|
447
|
+
"summary": {
|
|
448
|
+
"total_errors": total_errors,
|
|
449
|
+
"total_warnings": total_warnings,
|
|
450
|
+
"total_info": total_info,
|
|
451
|
+
"success": total_errors == 0,
|
|
452
|
+
},
|
|
453
|
+
"validators": [],
|
|
454
|
+
"issues": [],
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
# 添加自动修复统计
|
|
458
|
+
if auto_fixer:
|
|
459
|
+
report["auto_fix"] = {
|
|
460
|
+
"enabled": True,
|
|
461
|
+
"fixes_applied": len(auto_fixer.fixes_applied),
|
|
462
|
+
"fixes_failed": len(auto_fixer.fixes_failed),
|
|
463
|
+
"applied_fixes": auto_fixer.fixes_applied,
|
|
464
|
+
"failed_fixes": auto_fixer.fixes_failed,
|
|
465
|
+
}
|
|
466
|
+
else:
|
|
467
|
+
report["auto_fix"] = {"enabled": False}
|
|
468
|
+
|
|
469
|
+
# 添加每个验证器的结果
|
|
470
|
+
for result in results:
|
|
471
|
+
validator_data = {
|
|
472
|
+
"name": result.validator_name,
|
|
473
|
+
"success": result.success,
|
|
474
|
+
"error_count": result.error_count,
|
|
475
|
+
"warning_count": result.warning_count,
|
|
476
|
+
"info_count": result.info_count,
|
|
477
|
+
}
|
|
478
|
+
report["validators"].append(validator_data)
|
|
479
|
+
|
|
480
|
+
# 添加问题详情
|
|
481
|
+
for issue in result.issues:
|
|
482
|
+
issue_data = {
|
|
483
|
+
"validator": result.validator_name,
|
|
484
|
+
"level": issue.level.value,
|
|
485
|
+
"message": issue.message,
|
|
486
|
+
"file_path": issue.file_path,
|
|
487
|
+
"line_number": issue.line_number,
|
|
488
|
+
"suggestion": issue.suggestion,
|
|
489
|
+
}
|
|
490
|
+
report["issues"].append(issue_data)
|
|
491
|
+
|
|
492
|
+
# 写入文件
|
|
493
|
+
try:
|
|
494
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
495
|
+
json.dump(report, f, ensure_ascii=False, indent=2)
|
|
496
|
+
print_success(f"报告已保存到: {output_path}")
|
|
497
|
+
except Exception as e:
|
|
498
|
+
print_error(f"保存报告失败: {e}")
|