vite-plugin-ai-diagnostic 1.0.6 → 1.0.7
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/index.js +511 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +511 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import fs2 from "fs";
|
|
3
|
+
import path2 from "path";
|
|
3
4
|
|
|
4
5
|
// src/langgraph.ts
|
|
5
6
|
import { StateGraph, END, START } from "@langchain/langgraph";
|
|
@@ -617,9 +618,388 @@ ${report.fixed ? `✅ **已自动修复**
|
|
|
617
618
|
fs.writeFileSync(reportPath, JSON.stringify(jsonReport, null, 2), "utf-8");
|
|
618
619
|
console.log(`📄 JSON 报告已生成: ${reportPath}`);
|
|
619
620
|
}
|
|
621
|
+
/**
|
|
622
|
+
* 生成多错误合并报告
|
|
623
|
+
*/
|
|
624
|
+
static async generateMultiReport(reports, options = {}) {
|
|
625
|
+
const multiReport = {
|
|
626
|
+
timestamp: (/* @__PURE__ */ new Date()).toLocaleString("zh-CN"),
|
|
627
|
+
totalErrors: reports.length,
|
|
628
|
+
errors: reports
|
|
629
|
+
};
|
|
630
|
+
if (options.html) {
|
|
631
|
+
await this.generateMultiHTMLReport(multiReport);
|
|
632
|
+
}
|
|
633
|
+
if (options.markdown) {
|
|
634
|
+
await this.generateMultiMarkdownReport(multiReport);
|
|
635
|
+
}
|
|
636
|
+
if (options.json) {
|
|
637
|
+
await this.generateMultiJSONReport(multiReport);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* 生成多错误 HTML 报告
|
|
642
|
+
*/
|
|
643
|
+
static async generateMultiHTMLReport(report) {
|
|
644
|
+
const errorsHtml = report.errors.map(
|
|
645
|
+
(error, index) => `
|
|
646
|
+
<div class="error-item">
|
|
647
|
+
<div class="error-number">错误 ${index + 1} / ${report.totalErrors}</div>
|
|
648
|
+
<div class="error-box">
|
|
649
|
+
<span class="error-type">${error.error.type}</span>
|
|
650
|
+
<div class="error-message">${this.escapeHtml(
|
|
651
|
+
error.error.message
|
|
652
|
+
)}</div>
|
|
653
|
+
<div class="error-file">📂 ${error.error.file}</div>
|
|
654
|
+
${error.error.stack ? `<div class="stack-trace">${this.escapeHtml(
|
|
655
|
+
error.error.stack
|
|
656
|
+
)}</div>` : ""}
|
|
657
|
+
</div>
|
|
658
|
+
|
|
659
|
+
<div class="section">
|
|
660
|
+
<div class="section-title">🔍 AI 分析</div>
|
|
661
|
+
<div class="analysis-box">
|
|
662
|
+
${this.formatText(error.analysis)}
|
|
663
|
+
</div>
|
|
664
|
+
</div>
|
|
665
|
+
|
|
666
|
+
<div class="section">
|
|
667
|
+
<div class="section-title">💡 修复建议</div>
|
|
668
|
+
<div class="suggestion-box">
|
|
669
|
+
${this.formatText(error.suggestion)}
|
|
670
|
+
</div>
|
|
671
|
+
</div>
|
|
672
|
+
|
|
673
|
+
<div class="section">
|
|
674
|
+
<div class="section-title">🔧 修复状态</div>
|
|
675
|
+
${error.fixed ? `<div class="fixed-badge">✅ 已自动修复</div>
|
|
676
|
+
<div style="margin-top: 10px; color: #666;">修复文件: <code>${error.fixedFilePath}</code></div>` : `<div class="not-fixed-badge">⚠️ 未自动修复</div>
|
|
677
|
+
<div style="margin-top: 10px; color: #666;">请根据上述建议手动修复</div>`}
|
|
678
|
+
</div>
|
|
679
|
+
</div>
|
|
680
|
+
`
|
|
681
|
+
).join("");
|
|
682
|
+
const html = `
|
|
683
|
+
<!DOCTYPE html>
|
|
684
|
+
<html lang="zh-CN">
|
|
685
|
+
<head>
|
|
686
|
+
<meta charset="UTF-8">
|
|
687
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
688
|
+
<title>AI 诊断报告 - ${report.totalErrors} 个错误</title>
|
|
689
|
+
<style>
|
|
690
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
691
|
+
body {
|
|
692
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
693
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
694
|
+
padding: 20px;
|
|
695
|
+
min-height: 100vh;
|
|
696
|
+
}
|
|
697
|
+
.container {
|
|
698
|
+
max-width: 1000px;
|
|
699
|
+
margin: 0 auto;
|
|
700
|
+
background: white;
|
|
701
|
+
border-radius: 12px;
|
|
702
|
+
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
|
|
703
|
+
overflow: hidden;
|
|
704
|
+
}
|
|
705
|
+
.header {
|
|
706
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
707
|
+
color: white;
|
|
708
|
+
padding: 30px;
|
|
709
|
+
text-align: center;
|
|
710
|
+
}
|
|
711
|
+
.header h1 {
|
|
712
|
+
font-size: 32px;
|
|
713
|
+
margin-bottom: 10px;
|
|
714
|
+
display: flex;
|
|
715
|
+
align-items: center;
|
|
716
|
+
justify-content: center;
|
|
717
|
+
gap: 10px;
|
|
718
|
+
}
|
|
719
|
+
.header .time {
|
|
720
|
+
font-size: 14px;
|
|
721
|
+
opacity: 0.9;
|
|
722
|
+
}
|
|
723
|
+
.header .error-count {
|
|
724
|
+
font-size: 18px;
|
|
725
|
+
margin-top: 10px;
|
|
726
|
+
background: rgba(255,255,255,0.2);
|
|
727
|
+
padding: 8px 16px;
|
|
728
|
+
border-radius: 20px;
|
|
729
|
+
display: inline-block;
|
|
730
|
+
}
|
|
731
|
+
.content {
|
|
732
|
+
padding: 30px;
|
|
733
|
+
}
|
|
734
|
+
.error-item {
|
|
735
|
+
margin-bottom: 40px;
|
|
736
|
+
padding-bottom: 40px;
|
|
737
|
+
border-bottom: 2px dashed #e2e8f0;
|
|
738
|
+
}
|
|
739
|
+
.error-item:last-child {
|
|
740
|
+
border-bottom: none;
|
|
741
|
+
margin-bottom: 0;
|
|
742
|
+
padding-bottom: 0;
|
|
743
|
+
}
|
|
744
|
+
.error-number {
|
|
745
|
+
font-size: 16px;
|
|
746
|
+
font-weight: bold;
|
|
747
|
+
color: #667eea;
|
|
748
|
+
margin-bottom: 15px;
|
|
749
|
+
padding: 8px 16px;
|
|
750
|
+
background: #f0f9ff;
|
|
751
|
+
border-radius: 8px;
|
|
752
|
+
display: inline-block;
|
|
753
|
+
}
|
|
754
|
+
.section {
|
|
755
|
+
margin-bottom: 20px;
|
|
756
|
+
}
|
|
757
|
+
.section-title {
|
|
758
|
+
font-size: 18px;
|
|
759
|
+
font-weight: bold;
|
|
760
|
+
color: #333;
|
|
761
|
+
margin-bottom: 12px;
|
|
762
|
+
padding-bottom: 8px;
|
|
763
|
+
border-bottom: 2px solid #667eea;
|
|
764
|
+
display: flex;
|
|
765
|
+
align-items: center;
|
|
766
|
+
gap: 8px;
|
|
767
|
+
}
|
|
768
|
+
.error-box {
|
|
769
|
+
background: #fff5f5;
|
|
770
|
+
border-left: 4px solid #f56565;
|
|
771
|
+
padding: 20px;
|
|
772
|
+
border-radius: 8px;
|
|
773
|
+
margin-bottom: 20px;
|
|
774
|
+
}
|
|
775
|
+
.error-type {
|
|
776
|
+
display: inline-block;
|
|
777
|
+
background: #f56565;
|
|
778
|
+
color: white;
|
|
779
|
+
padding: 4px 12px;
|
|
780
|
+
border-radius: 12px;
|
|
781
|
+
font-size: 12px;
|
|
782
|
+
font-weight: bold;
|
|
783
|
+
margin-bottom: 10px;
|
|
784
|
+
}
|
|
785
|
+
.error-message {
|
|
786
|
+
font-size: 16px;
|
|
787
|
+
color: #c53030;
|
|
788
|
+
font-weight: 500;
|
|
789
|
+
margin-bottom: 10px;
|
|
790
|
+
line-height: 1.6;
|
|
791
|
+
}
|
|
792
|
+
.error-file {
|
|
793
|
+
font-size: 14px;
|
|
794
|
+
color: #666;
|
|
795
|
+
font-family: 'Courier New', monospace;
|
|
796
|
+
background: #f7fafc;
|
|
797
|
+
padding: 8px 12px;
|
|
798
|
+
border-radius: 4px;
|
|
799
|
+
display: inline-block;
|
|
800
|
+
}
|
|
801
|
+
.analysis-box {
|
|
802
|
+
background: #f0f9ff;
|
|
803
|
+
border-left: 4px solid #3b82f6;
|
|
804
|
+
padding: 20px;
|
|
805
|
+
border-radius: 8px;
|
|
806
|
+
line-height: 1.8;
|
|
807
|
+
color: #1e40af;
|
|
808
|
+
}
|
|
809
|
+
.suggestion-box {
|
|
810
|
+
background: #f0fdf4;
|
|
811
|
+
border-left: 4px solid #10b981;
|
|
812
|
+
padding: 20px;
|
|
813
|
+
border-radius: 8px;
|
|
814
|
+
line-height: 1.8;
|
|
815
|
+
color: #065f46;
|
|
816
|
+
}
|
|
817
|
+
.suggestion-box pre {
|
|
818
|
+
background: #1e293b;
|
|
819
|
+
color: #e2e8f0;
|
|
820
|
+
padding: 15px;
|
|
821
|
+
border-radius: 6px;
|
|
822
|
+
overflow-x: auto;
|
|
823
|
+
margin: 10px 0;
|
|
824
|
+
font-size: 14px;
|
|
825
|
+
line-height: 1.5;
|
|
826
|
+
}
|
|
827
|
+
.fixed-badge {
|
|
828
|
+
display: inline-flex;
|
|
829
|
+
align-items: center;
|
|
830
|
+
gap: 6px;
|
|
831
|
+
background: #10b981;
|
|
832
|
+
color: white;
|
|
833
|
+
padding: 8px 16px;
|
|
834
|
+
border-radius: 20px;
|
|
835
|
+
font-size: 14px;
|
|
836
|
+
font-weight: bold;
|
|
837
|
+
}
|
|
838
|
+
.not-fixed-badge {
|
|
839
|
+
display: inline-flex;
|
|
840
|
+
align-items: center;
|
|
841
|
+
gap: 6px;
|
|
842
|
+
background: #f59e0b;
|
|
843
|
+
color: white;
|
|
844
|
+
padding: 8px 16px;
|
|
845
|
+
border-radius: 20px;
|
|
846
|
+
font-size: 14px;
|
|
847
|
+
font-weight: bold;
|
|
848
|
+
}
|
|
849
|
+
.footer {
|
|
850
|
+
background: #f7fafc;
|
|
851
|
+
padding: 20px;
|
|
852
|
+
text-align: center;
|
|
853
|
+
color: #718096;
|
|
854
|
+
font-size: 14px;
|
|
855
|
+
border-top: 1px solid #e2e8f0;
|
|
856
|
+
}
|
|
857
|
+
.stack-trace {
|
|
858
|
+
background: #1e293b;
|
|
859
|
+
color: #e2e8f0;
|
|
860
|
+
padding: 15px;
|
|
861
|
+
border-radius: 6px;
|
|
862
|
+
overflow-x: auto;
|
|
863
|
+
font-family: 'Courier New', monospace;
|
|
864
|
+
font-size: 12px;
|
|
865
|
+
line-height: 1.5;
|
|
866
|
+
margin-top: 10px;
|
|
867
|
+
max-height: 300px;
|
|
868
|
+
overflow-y: auto;
|
|
869
|
+
}
|
|
870
|
+
</style>
|
|
871
|
+
</head>
|
|
872
|
+
<body>
|
|
873
|
+
<div class="container">
|
|
874
|
+
<div class="header">
|
|
875
|
+
<h1>🤖 AI 诊断报告</h1>
|
|
876
|
+
<div class="time">生成时间: ${report.timestamp}</div>
|
|
877
|
+
<div class="error-count">共发现 ${report.totalErrors} 个错误</div>
|
|
878
|
+
</div>
|
|
879
|
+
|
|
880
|
+
<div class="content">
|
|
881
|
+
${errorsHtml}
|
|
882
|
+
</div>
|
|
883
|
+
|
|
884
|
+
<div class="footer">
|
|
885
|
+
<p>AI Diagnostic Plugin v1.0.7</p>
|
|
886
|
+
<p>Powered by LangGraph & OpenAI</p>
|
|
887
|
+
</div>
|
|
888
|
+
</div>
|
|
889
|
+
</body>
|
|
890
|
+
</html>
|
|
891
|
+
`.trim();
|
|
892
|
+
const reportsDir = path.resolve(process.cwd(), "ai-reports");
|
|
893
|
+
if (!fs.existsSync(reportsDir)) {
|
|
894
|
+
fs.mkdirSync(reportsDir, { recursive: true });
|
|
895
|
+
}
|
|
896
|
+
const reportPath = path.resolve(reportsDir, "diagnostic-report.html");
|
|
897
|
+
fs.writeFileSync(reportPath, html, "utf-8");
|
|
898
|
+
console.log(
|
|
899
|
+
`
|
|
900
|
+
📄 诊断报告已生成: ${reportPath} (${report.totalErrors} 个错误)
|
|
901
|
+
`
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* 生成多错误 Markdown 报告
|
|
906
|
+
*/
|
|
907
|
+
static async generateMultiMarkdownReport(report) {
|
|
908
|
+
const errorsMarkdown = report.errors.map(
|
|
909
|
+
(error, index) => `
|
|
910
|
+
## 错误 ${index + 1} / ${report.totalErrors}
|
|
911
|
+
|
|
912
|
+
### ❌ 错误信息
|
|
913
|
+
|
|
914
|
+
**类型**: \`${error.error.type}\`
|
|
915
|
+
**文件**: \`${error.error.file}\`
|
|
916
|
+
**消息**:
|
|
917
|
+
\`\`\`
|
|
918
|
+
${error.error.message}
|
|
919
|
+
\`\`\`
|
|
920
|
+
|
|
921
|
+
${error.error.stack ? `**堆栈跟踪**:
|
|
922
|
+
\`\`\`
|
|
923
|
+
${error.error.stack}
|
|
924
|
+
\`\`\`
|
|
925
|
+
` : ""}
|
|
926
|
+
|
|
927
|
+
### 🔍 AI 分析
|
|
928
|
+
|
|
929
|
+
${error.analysis}
|
|
930
|
+
|
|
931
|
+
### 💡 修复建议
|
|
932
|
+
|
|
933
|
+
${error.suggestion}
|
|
934
|
+
|
|
935
|
+
### 🔧 修复状态
|
|
936
|
+
|
|
937
|
+
${error.fixed ? `✅ **已自动修复**
|
|
938
|
+
|
|
939
|
+
修复文件: \`${error.fixedFilePath}\`` : `⚠️ **未自动修复**
|
|
940
|
+
|
|
941
|
+
请根据上述建议手动修复`}
|
|
942
|
+
|
|
943
|
+
---
|
|
944
|
+
`
|
|
945
|
+
).join("\n");
|
|
946
|
+
const markdown = `# 🤖 AI 诊断报告
|
|
947
|
+
|
|
948
|
+
**生成时间**: ${report.timestamp}
|
|
949
|
+
**错误总数**: ${report.totalErrors}
|
|
950
|
+
|
|
951
|
+
---
|
|
952
|
+
|
|
953
|
+
${errorsMarkdown}
|
|
954
|
+
|
|
955
|
+
*AI Diagnostic Plugin v1.0.7*
|
|
956
|
+
*Powered by LangGraph & OpenAI*
|
|
957
|
+
`;
|
|
958
|
+
const reportsDir = path.resolve(process.cwd(), "ai-reports");
|
|
959
|
+
if (!fs.existsSync(reportsDir)) {
|
|
960
|
+
fs.mkdirSync(reportsDir, { recursive: true });
|
|
961
|
+
}
|
|
962
|
+
const reportPath = path.resolve(reportsDir, "diagnostic-report.md");
|
|
963
|
+
fs.writeFileSync(reportPath, markdown, "utf-8");
|
|
964
|
+
console.log(`📄 Markdown 报告已生成: ${reportPath}`);
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* 生成多错误 JSON 报告
|
|
968
|
+
*/
|
|
969
|
+
static async generateMultiJSONReport(report) {
|
|
970
|
+
const jsonReport = {
|
|
971
|
+
version: "1.0.7",
|
|
972
|
+
timestamp: report.timestamp,
|
|
973
|
+
totalErrors: report.totalErrors,
|
|
974
|
+
errors: report.errors.map((error) => ({
|
|
975
|
+
error: {
|
|
976
|
+
type: error.error.type,
|
|
977
|
+
message: error.error.message,
|
|
978
|
+
file: error.error.file,
|
|
979
|
+
stack: error.error.stack || null
|
|
980
|
+
},
|
|
981
|
+
diagnosis: {
|
|
982
|
+
analysis: error.analysis,
|
|
983
|
+
suggestion: error.suggestion
|
|
984
|
+
},
|
|
985
|
+
fix: {
|
|
986
|
+
applied: error.fixed,
|
|
987
|
+
filePath: error.fixedFilePath || null
|
|
988
|
+
}
|
|
989
|
+
}))
|
|
990
|
+
};
|
|
991
|
+
const reportsDir = path.resolve(process.cwd(), "ai-reports");
|
|
992
|
+
if (!fs.existsSync(reportsDir)) {
|
|
993
|
+
fs.mkdirSync(reportsDir, { recursive: true });
|
|
994
|
+
}
|
|
995
|
+
const reportPath = path.resolve(reportsDir, "diagnostic-report.json");
|
|
996
|
+
fs.writeFileSync(reportPath, JSON.stringify(jsonReport, null, 2), "utf-8");
|
|
997
|
+
console.log(`📄 JSON 报告已生成: ${reportPath}`);
|
|
998
|
+
}
|
|
620
999
|
};
|
|
621
1000
|
|
|
622
1001
|
// src/index.ts
|
|
1002
|
+
import { glob } from "glob";
|
|
623
1003
|
function vitePluginAIDiagnostic(options = {}) {
|
|
624
1004
|
const {
|
|
625
1005
|
apiKey = process.env.OPENAI_API_KEY || "",
|
|
@@ -643,6 +1023,8 @@ function vitePluginAIDiagnostic(options = {}) {
|
|
|
643
1023
|
let buildErrors = [];
|
|
644
1024
|
let lastTransformFile = null;
|
|
645
1025
|
let processedErrors = /* @__PURE__ */ new Set();
|
|
1026
|
+
let config;
|
|
1027
|
+
let diagnosticResults = [];
|
|
646
1028
|
async function processError(error) {
|
|
647
1029
|
const errorKey = `${error.file}:${error.message}`;
|
|
648
1030
|
if (processedErrors.has(errorKey)) {
|
|
@@ -692,7 +1074,7 @@ function vitePluginAIDiagnostic(options = {}) {
|
|
|
692
1074
|
fixed: !!(result.fixedCode && result.filePath),
|
|
693
1075
|
fixedFilePath: result.filePath
|
|
694
1076
|
};
|
|
695
|
-
|
|
1077
|
+
diagnosticResults.push(report);
|
|
696
1078
|
} catch (err) {
|
|
697
1079
|
console.error("❌ AI 诊断失败:", err.message);
|
|
698
1080
|
}
|
|
@@ -701,7 +1083,8 @@ function vitePluginAIDiagnostic(options = {}) {
|
|
|
701
1083
|
name: "vite-plugin-ai-diagnostic",
|
|
702
1084
|
// 确保插件在其他插件之后执行,以捕获更多错误
|
|
703
1085
|
enforce: "post",
|
|
704
|
-
configResolved(
|
|
1086
|
+
configResolved(resolvedConfig) {
|
|
1087
|
+
config = resolvedConfig;
|
|
705
1088
|
console.log("\n🤖 AI 诊断助手已启动...");
|
|
706
1089
|
console.log(`⚙️ 自动修复: ${autoFix ? "✅ 已启用" : "❌ 未启用"}`);
|
|
707
1090
|
console.log(`📝 根目录: ${config.root}`);
|
|
@@ -710,10 +1093,123 @@ function vitePluginAIDiagnostic(options = {}) {
|
|
|
710
1093
|
`
|
|
711
1094
|
);
|
|
712
1095
|
},
|
|
713
|
-
buildStart() {
|
|
1096
|
+
async buildStart() {
|
|
714
1097
|
buildErrors = [];
|
|
715
1098
|
processedErrors.clear();
|
|
716
|
-
|
|
1099
|
+
diagnosticResults = [];
|
|
1100
|
+
console.log("🔍 开始扫描源文件...");
|
|
1101
|
+
const srcDir = path2.join(config.root, "src");
|
|
1102
|
+
if (!fs2.existsSync(srcDir)) {
|
|
1103
|
+
console.log("⚠️ src 目录不存在,跳过文件扫描");
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1106
|
+
try {
|
|
1107
|
+
const files = await glob("**/*.{vue,ts,tsx,js,jsx}", {
|
|
1108
|
+
cwd: srcDir,
|
|
1109
|
+
absolute: true,
|
|
1110
|
+
ignore: ["**/node_modules/**", "**/*.d.ts"]
|
|
1111
|
+
});
|
|
1112
|
+
console.log(`📂 找到 ${files.length} 个源文件`);
|
|
1113
|
+
for (const file of files) {
|
|
1114
|
+
try {
|
|
1115
|
+
const code = fs2.readFileSync(file, "utf-8");
|
|
1116
|
+
if (file.endsWith(".vue")) {
|
|
1117
|
+
if (!code.includes("<template>") && !code.includes("<script>")) {
|
|
1118
|
+
buildErrors.push({
|
|
1119
|
+
type: "syntax",
|
|
1120
|
+
message: "Vue 文件缺少 <template> 或 <script> 标签",
|
|
1121
|
+
file,
|
|
1122
|
+
code
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
const templateMatch = code.match(/<template[^>]*>/);
|
|
1126
|
+
if (templateMatch && !code.includes("</template>")) {
|
|
1127
|
+
buildErrors.push({
|
|
1128
|
+
type: "syntax",
|
|
1129
|
+
message: "Vue 文件中 <template> 标签未闭合",
|
|
1130
|
+
file,
|
|
1131
|
+
code
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
const scriptMatch = code.match(/<script[^>]*>/);
|
|
1135
|
+
if (scriptMatch && !code.includes("</script>")) {
|
|
1136
|
+
buildErrors.push({
|
|
1137
|
+
type: "syntax",
|
|
1138
|
+
message: "Vue 文件中 <script> 标签未闭合",
|
|
1139
|
+
file,
|
|
1140
|
+
code
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
if (file.endsWith(".ts") || file.endsWith(".tsx") || file.endsWith(".js") || file.endsWith(".jsx")) {
|
|
1145
|
+
const openBraces = (code.match(/\{/g) || []).length;
|
|
1146
|
+
const closeBraces = (code.match(/\}/g) || []).length;
|
|
1147
|
+
if (openBraces !== closeBraces) {
|
|
1148
|
+
buildErrors.push({
|
|
1149
|
+
type: "syntax",
|
|
1150
|
+
message: `括号不匹配:{ 有 ${openBraces} 个,} 有 ${closeBraces} 个`,
|
|
1151
|
+
file,
|
|
1152
|
+
code
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
const openParens = (code.match(/\(/g) || []).length;
|
|
1156
|
+
const closeParens = (code.match(/\)/g) || []).length;
|
|
1157
|
+
if (openParens !== closeParens) {
|
|
1158
|
+
buildErrors.push({
|
|
1159
|
+
type: "syntax",
|
|
1160
|
+
message: `圆括号不匹配:( 有 ${openParens} 个,) 有 ${closeParens} 个`,
|
|
1161
|
+
file,
|
|
1162
|
+
code
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
const importRegex = /import\s+.*?\s+from\s+['"](.+?)['"]/g;
|
|
1167
|
+
let match;
|
|
1168
|
+
while ((match = importRegex.exec(code)) !== null) {
|
|
1169
|
+
const importPath = match[1];
|
|
1170
|
+
if (importPath.startsWith(".") || importPath.startsWith("/")) {
|
|
1171
|
+
const resolvedPath = path2.resolve(
|
|
1172
|
+
path2.dirname(file),
|
|
1173
|
+
importPath
|
|
1174
|
+
);
|
|
1175
|
+
const extensions = [".ts", ".tsx", ".js", ".jsx", ".vue", ""];
|
|
1176
|
+
let exists = false;
|
|
1177
|
+
for (const ext of extensions) {
|
|
1178
|
+
const fullPath = resolvedPath + ext;
|
|
1179
|
+
if (fs2.existsSync(fullPath)) {
|
|
1180
|
+
exists = true;
|
|
1181
|
+
break;
|
|
1182
|
+
}
|
|
1183
|
+
if (fs2.existsSync(resolvedPath) && fs2.statSync(resolvedPath).isDirectory()) {
|
|
1184
|
+
const indexPath = path2.join(resolvedPath, "index" + ext);
|
|
1185
|
+
if (fs2.existsSync(indexPath)) {
|
|
1186
|
+
exists = true;
|
|
1187
|
+
break;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
if (!exists) {
|
|
1192
|
+
buildErrors.push({
|
|
1193
|
+
type: "module",
|
|
1194
|
+
message: `找不到模块: ${importPath}`,
|
|
1195
|
+
file,
|
|
1196
|
+
code
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
} catch (err) {
|
|
1202
|
+
console.warn(`⚠️ 无法读取文件 ${file}: ${err.message}`);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
if (buildErrors.length > 0) {
|
|
1206
|
+
console.log(`⚠️ 扫描发现 ${buildErrors.length} 个潜在问题`);
|
|
1207
|
+
} else {
|
|
1208
|
+
console.log("✅ 文件扫描完成,未发现明显问题");
|
|
1209
|
+
}
|
|
1210
|
+
} catch (err) {
|
|
1211
|
+
console.error(`❌ 文件扫描失败: ${err.message}`);
|
|
1212
|
+
}
|
|
717
1213
|
},
|
|
718
1214
|
// 解析模块时捕获错误
|
|
719
1215
|
async resolveId(source, importer, options2) {
|
|
@@ -808,6 +1304,17 @@ function vitePluginAIDiagnostic(options = {}) {
|
|
|
808
1304
|
for (const error of buildErrors) {
|
|
809
1305
|
await processError(error);
|
|
810
1306
|
}
|
|
1307
|
+
if (diagnosticResults.length > 0) {
|
|
1308
|
+
console.log(
|
|
1309
|
+
`
|
|
1310
|
+
📊 正在生成合并诊断报告 (${diagnosticResults.length} 个错误)...
|
|
1311
|
+
`
|
|
1312
|
+
);
|
|
1313
|
+
await DiagnosticReporter.generateMultiReport(
|
|
1314
|
+
diagnosticResults,
|
|
1315
|
+
output
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
811
1318
|
} else {
|
|
812
1319
|
console.log("✨ 构建完成,未检测到错误\n");
|
|
813
1320
|
}
|