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