crabatool 1.0.444 → 1.0.445
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/lib/server.js +0 -6
- package/package.json +1 -1
- package/res/client.js +112 -23
- package/tool/openFileWatcher.js +69 -16
package/lib/server.js
CHANGED
|
@@ -156,12 +156,6 @@ function createServer(app, options) {
|
|
|
156
156
|
utils.log('文件监听功能已禁用');
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
// 统一拦截login.html
|
|
160
|
-
if (config.modName && !config.localLogin) {
|
|
161
|
-
app.use(utils.rewriteLoginHTML);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
159
|
app.webPath = webPath; // handler.js里面动态获取当前app的网站路径(多个server实例的时候需要)
|
|
166
160
|
|
|
167
161
|
app.use(express.static(webPath, {
|
package/package.json
CHANGED
package/res/client.js
CHANGED
|
@@ -146,6 +146,11 @@
|
|
|
146
146
|
existingOverlay.remove();
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
// 兼容旧版本数据格式(单文件错误)
|
|
150
|
+
var allErrorFiles = errorData.allErrorFiles || [errorData];
|
|
151
|
+
var currentFile = errorData.currentFile || errorData;
|
|
152
|
+
var totalErrorFiles = errorData.totalErrorFiles || 1;
|
|
153
|
+
|
|
149
154
|
// 创建错误覆盖层
|
|
150
155
|
var overlay = document.createElement('div');
|
|
151
156
|
overlay.id = 'syntax-error-overlay';
|
|
@@ -164,19 +169,56 @@
|
|
|
164
169
|
var container = document.createElement('div');
|
|
165
170
|
container.style.cssText = `
|
|
166
171
|
background: #fff;
|
|
167
|
-
margin:
|
|
168
|
-
padding:
|
|
169
|
-
max-width:
|
|
170
|
-
max-height:
|
|
171
|
-
overflow-y: auto;
|
|
172
|
+
margin: 30px auto;
|
|
173
|
+
padding: 0;
|
|
174
|
+
max-width: 1000px;
|
|
175
|
+
max-height: 85vh;
|
|
172
176
|
border-radius: 8px;
|
|
173
177
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
|
178
|
+
display: flex;
|
|
179
|
+
overflow: hidden;
|
|
174
180
|
`;
|
|
175
181
|
|
|
176
|
-
//
|
|
182
|
+
// 构建文件列表HTML(如果有多个文件)
|
|
183
|
+
var fileListHtml = '';
|
|
184
|
+
if (totalErrorFiles > 1) {
|
|
185
|
+
fileListHtml = `
|
|
186
|
+
<div style="width: 300px; background: #f8f9fa; border-right: 1px solid #dee2e6; overflow-y: auto;">
|
|
187
|
+
<div style="padding: 20px; border-bottom: 1px solid #dee2e6; background: #e9ecef;">
|
|
188
|
+
<h3 style="margin: 0; color: #495057; font-size: 16px;">错误文件列表 (${totalErrorFiles})</h3>
|
|
189
|
+
</div>
|
|
190
|
+
<div style="padding: 10px;">
|
|
191
|
+
${allErrorFiles.map(function(file, index) {
|
|
192
|
+
var isActive = file.filePath === currentFile.filePath;
|
|
193
|
+
var fileId = 'error-file-' + index;
|
|
194
|
+
return `
|
|
195
|
+
<div id="${fileId}" onclick="switchErrorFile('${file.filePath}')"
|
|
196
|
+
class="${isActive ? 'active-file' : 'inactive-file'}"
|
|
197
|
+
data-filepath="${file.filePath}"
|
|
198
|
+
style="
|
|
199
|
+
padding: 12px;
|
|
200
|
+
margin-bottom: 8px;
|
|
201
|
+
border-radius: 4px;
|
|
202
|
+
cursor: pointer;
|
|
203
|
+
background: ${isActive ? '#007bff !important' : '#fff'};
|
|
204
|
+
color: ${isActive ? '#fff' : '#333'};
|
|
205
|
+
border: 1px solid ${isActive ? '#007bff' : '#dee2e6'};
|
|
206
|
+
transition: all 0.2s;
|
|
207
|
+
" onmouseover="handleFileHover(this, true)" onmouseout="handleFileHover(this, false)">
|
|
208
|
+
<div style="font-weight: bold; font-size: 12px; margin-bottom: 4px;">${file.filePath.split('/').pop()}</div>
|
|
209
|
+
<div style="font-size: 11px; opacity: 0.8; word-break: break-all;">${file.filePath}</div>
|
|
210
|
+
<div style="font-size: 11px; margin-top: 4px;">${file.errors.length} 个错误</div>
|
|
211
|
+
</div>
|
|
212
|
+
`;
|
|
213
|
+
}).join('')}
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
`;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 构建当前文件错误信息HTML
|
|
177
220
|
var errorsHtml = '';
|
|
178
|
-
|
|
179
|
-
var errorClass = error.severity === 'error' ? 'error' : 'warning';
|
|
221
|
+
currentFile.errors.forEach(function(error, index) {
|
|
180
222
|
errorsHtml += `
|
|
181
223
|
<div style="margin-bottom: 15px; padding: 15px; background: ${error.severity === 'error' ? '#ffebee' : '#fff3e0'}; border-left: 4px solid ${error.severity === 'error' ? '#e74c3c' : '#ff9800'}; border-radius: 4px;">
|
|
182
224
|
<div style="font-weight: bold; color: ${error.severity === 'error' ? '#e74c3c' : '#ff9800'}; margin-bottom: 8px;">
|
|
@@ -188,34 +230,81 @@
|
|
|
188
230
|
`;
|
|
189
231
|
});
|
|
190
232
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
233
|
+
// 主内容区域
|
|
234
|
+
var mainContentHtml = `
|
|
235
|
+
<div style="flex: 1; display: flex; flex-direction: column;">
|
|
236
|
+
<div style="padding: 20px; border-bottom: 2px solid #e74c3c; background: #fff;">
|
|
237
|
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
238
|
+
<h2 style="margin: 0; color: #e74c3c; font-size: 20px;">JavaScript 兼容性语法错误</h2>
|
|
239
|
+
${totalErrorFiles > 1 ? '<span style="background: #e74c3c; color: white; padding: 4px 8px; border-radius: 12px; font-size: 12px;">' + totalErrorFiles + ' 个文件</span>' : ''}
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
<div style="flex: 1; overflow-y: auto; padding: 20px;">
|
|
243
|
+
<div style="margin-bottom: 20px;">
|
|
244
|
+
<div style="font-weight: bold; color: #333; margin-bottom: 8px;">当前文件:</div>
|
|
245
|
+
<div style="background: #f8f9fa; padding: 10px; border-radius: 4px; font-family: monospace; color: #666; word-break: break-all;">${currentFile.filePath}</div>
|
|
246
|
+
</div>
|
|
247
|
+
<div style="margin-bottom: 20px;">
|
|
248
|
+
<div style="font-weight: bold; color: #333; margin-bottom: 12px;">错误详情 (${currentFile.errors.length} 个):</div>
|
|
249
|
+
${errorsHtml}
|
|
250
|
+
</div>
|
|
251
|
+
<div style="text-align: center; color: #666; font-size: 12px; border-top: 1px solid #dee2e6; padding-top: 15px;">
|
|
252
|
+
检测时间:${currentFile.timestamp}
|
|
253
|
+
</div>
|
|
254
|
+
</div>
|
|
206
255
|
</div>
|
|
207
256
|
`;
|
|
208
257
|
|
|
258
|
+
container.innerHTML = fileListHtml + mainContentHtml;
|
|
209
259
|
overlay.appendChild(container);
|
|
210
260
|
document.body.appendChild(overlay);
|
|
261
|
+
|
|
262
|
+
// 存储当前错误数据供切换使用
|
|
263
|
+
window.currentErrorData = errorData;
|
|
211
264
|
}
|
|
212
265
|
|
|
266
|
+
// 处理文件项的鼠标悬停效果
|
|
267
|
+
window.handleFileHover = function(element, isHover) {
|
|
268
|
+
// 如果是激活状态的文件,不改变样式
|
|
269
|
+
if (element.classList.contains('active-file')) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (isHover) {
|
|
274
|
+
element.style.background = '#f8f9fa';
|
|
275
|
+
} else {
|
|
276
|
+
element.style.background = '#fff';
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// 切换错误文件显示
|
|
281
|
+
window.switchErrorFile = function(filePath) {
|
|
282
|
+
if (!window.currentErrorData || !window.currentErrorData.allErrorFiles) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// 找到对应的文件数据
|
|
287
|
+
var targetFile = window.currentErrorData.allErrorFiles.find(function(file) {
|
|
288
|
+
return file.filePath === filePath;
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
if (targetFile) {
|
|
292
|
+
// 更新当前文件并重新显示
|
|
293
|
+
var newErrorData = Object.assign({}, window.currentErrorData, {
|
|
294
|
+
currentFile: targetFile
|
|
295
|
+
});
|
|
296
|
+
showSyntaxErrorOverlay(newErrorData);
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
213
300
|
// 关闭语法错误覆盖层
|
|
214
301
|
window.closeSyntaxErrorOverlay = function() {
|
|
215
302
|
var overlay = document.getElementById('syntax-error-overlay');
|
|
216
303
|
if (overlay) {
|
|
217
304
|
overlay.remove();
|
|
218
305
|
}
|
|
306
|
+
// 清理存储的错误数据
|
|
307
|
+
window.currentErrorData = null;
|
|
219
308
|
};
|
|
220
309
|
|
|
221
310
|
waitCraba();
|
package/tool/openFileWatcher.js
CHANGED
|
@@ -46,7 +46,9 @@ class OpenFileWatcher {
|
|
|
46
46
|
this.openFiles = new Set(); // 当前打开的文件
|
|
47
47
|
this.changeQueue = new Map(); // 变化队列
|
|
48
48
|
this.debounceTimers = new Map(); // 防抖定时器
|
|
49
|
-
|
|
49
|
+
// 错误文件缓存,存储所有有异常语法的文件信息
|
|
50
|
+
this.errorFilesCache = new Map();
|
|
51
|
+
|
|
50
52
|
// 绑定方法
|
|
51
53
|
this.handleFileChange = this.handleFileChange.bind(this);
|
|
52
54
|
this.processFileChange = this.processFileChange.bind(this);
|
|
@@ -116,11 +118,14 @@ class OpenFileWatcher {
|
|
|
116
118
|
this.isWatching = false;
|
|
117
119
|
this.openFiles.clear();
|
|
118
120
|
this.changeQueue.clear();
|
|
119
|
-
|
|
121
|
+
|
|
120
122
|
// 清理所有防抖定时器
|
|
121
123
|
this.debounceTimers.forEach(timer => clearTimeout(timer));
|
|
122
124
|
this.debounceTimers.clear();
|
|
123
|
-
|
|
125
|
+
|
|
126
|
+
// 清空错误文件缓存
|
|
127
|
+
this.clearErrorFilesCache();
|
|
128
|
+
|
|
124
129
|
utils.log('文件监听器已停止');
|
|
125
130
|
}
|
|
126
131
|
return this;
|
|
@@ -583,28 +588,42 @@ class OpenFileWatcher {
|
|
|
583
588
|
});
|
|
584
589
|
}
|
|
585
590
|
|
|
586
|
-
//
|
|
591
|
+
// 处理错误文件缓存
|
|
587
592
|
if (errors.length > 0) {
|
|
593
|
+
// 有错误:将文件信息添加到缓存中
|
|
588
594
|
const errorData = {
|
|
589
|
-
mode: 'syntaxError',
|
|
590
595
|
filePath: relativePath,
|
|
591
596
|
fullPath: path.resolve(this.watchPath, relativePath),
|
|
592
597
|
errors: errors.slice(0, 5), // 最多显示5个错误
|
|
593
598
|
timestamp: new Date().toLocaleString()
|
|
594
599
|
};
|
|
595
600
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
//
|
|
600
|
-
|
|
601
|
-
mode: 'clearSyntaxError',
|
|
602
|
-
filePath: relativePath,
|
|
603
|
-
timestamp: new Date().toLocaleString()
|
|
604
|
-
};
|
|
601
|
+
this.errorFilesCache.set(relativePath, errorData);
|
|
602
|
+
console.log(chalk.blue(`文件有${errors.length}个语法错误,已缓存: ${relativePath}`));
|
|
603
|
+
|
|
604
|
+
// 发送包含所有错误文件的信息到前端
|
|
605
|
+
this.sendAllErrorsToFrontend();
|
|
605
606
|
|
|
606
|
-
|
|
607
|
-
|
|
607
|
+
} else {
|
|
608
|
+
// 没有错误:从缓存中移除该文件
|
|
609
|
+
if (this.errorFilesCache.has(relativePath)) {
|
|
610
|
+
this.errorFilesCache.delete(relativePath);
|
|
611
|
+
console.log(chalk.green(`文件已修复,从错误缓存中移除: ${relativePath}`));
|
|
612
|
+
|
|
613
|
+
// 检查是否还有其他错误文件
|
|
614
|
+
if (this.errorFilesCache.size === 0) {
|
|
615
|
+
// 所有文件都修复了,发送清除错误覆盖层的消息
|
|
616
|
+
const clearData = {
|
|
617
|
+
mode: 'clearSyntaxError',
|
|
618
|
+
timestamp: new Date().toLocaleString()
|
|
619
|
+
};
|
|
620
|
+
console.log(chalk.green('所有错误文件都已修复,发送清除错误覆盖层消息'));
|
|
621
|
+
this.emit('clearSyntaxError', clearData);
|
|
622
|
+
} else {
|
|
623
|
+
// 还有其他错误文件,更新前端显示
|
|
624
|
+
this.sendAllErrorsToFrontend();
|
|
625
|
+
}
|
|
626
|
+
}
|
|
608
627
|
}
|
|
609
628
|
}
|
|
610
629
|
|
|
@@ -718,6 +737,40 @@ class OpenFileWatcher {
|
|
|
718
737
|
return 'ES6+语法';
|
|
719
738
|
}
|
|
720
739
|
|
|
740
|
+
/**
|
|
741
|
+
* 发送所有错误文件信息到前端
|
|
742
|
+
*/
|
|
743
|
+
sendAllErrorsToFrontend() {
|
|
744
|
+
if (this.errorFilesCache.size === 0) {
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// 将Map转换为数组,按时间戳排序(最新的在前)
|
|
749
|
+
const allErrorFiles = Array.from(this.errorFilesCache.values()).sort((a, b) => {
|
|
750
|
+
return new Date(b.timestamp) - new Date(a.timestamp);
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
// 构造发送给前端的数据
|
|
754
|
+
const errorData = {
|
|
755
|
+
mode: 'syntaxError',
|
|
756
|
+
allErrorFiles: allErrorFiles,
|
|
757
|
+
totalErrorFiles: allErrorFiles.length,
|
|
758
|
+
currentFile: allErrorFiles[0], // 默认显示最新的错误文件
|
|
759
|
+
timestamp: new Date().toLocaleString()
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
console.log(chalk.blue(`发送${allErrorFiles.length}个错误文件信息到前端`));
|
|
763
|
+
this.emit('syntaxError', errorData);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* 清空错误文件缓存
|
|
768
|
+
*/
|
|
769
|
+
clearErrorFilesCache() {
|
|
770
|
+
this.errorFilesCache.clear();
|
|
771
|
+
console.log(chalk.yellow('已清空错误文件缓存'));
|
|
772
|
+
}
|
|
773
|
+
|
|
721
774
|
/**
|
|
722
775
|
* 获取指定行的内容
|
|
723
776
|
* @param {string} content - 文件内容
|