Files
claudia/src/lib/eslint-integration.ts

219 lines
6.3 KiB
TypeScript

import * as monaco from 'monaco-editor';
import type { Linter } from 'eslint';
// 将 ESLint 诊断转换为 Monaco 标记
export function convertESLintToMonacoMarkers(
eslintMessages: Linter.LintMessage[],
_model: monaco.editor.ITextModel
): monaco.editor.IMarkerData[] {
return eslintMessages.map(message => {
return {
severity: message.severity === 2
? monaco.MarkerSeverity.Error
: monaco.MarkerSeverity.Warning,
startLineNumber: message.line || 1,
startColumn: message.column || 1,
endLineNumber: message.endLine || message.line || 1,
endColumn: message.endColumn || (message.column ? message.column + 1 : 1),
message: message.message,
source: message.ruleId || 'eslint',
};
});
}
// 实时语法检查配置
export interface RealtimeLintOptions {
enabled: boolean;
delay: number; // 延迟时间(毫秒)
showInlineErrors: boolean;
showErrorsInScrollbar: boolean;
showErrorsInMinimap: boolean;
}
export const defaultLintOptions: RealtimeLintOptions = {
enabled: true,
delay: 500,
showInlineErrors: true,
showErrorsInScrollbar: true,
showErrorsInMinimap: true,
};
// 配置实时语法检查
export function setupRealtimeLinting(
editor: monaco.editor.IStandaloneCodeEditor,
options: RealtimeLintOptions = defaultLintOptions
) {
if (!options.enabled) return;
let lintTimer: NodeJS.Timeout | null = null;
const performLinting = () => {
const model = editor.getModel();
if (!model) return;
const language = model.getLanguageId();
if (language !== 'typescript' && language !== 'javascript' &&
language !== 'typescriptreact' && language !== 'javascriptreact') {
return;
}
// 根据选项配置显示
if (options.showErrorsInScrollbar) {
editor.updateOptions({
overviewRulerLanes: 3,
});
}
if (options.showErrorsInMinimap) {
editor.updateOptions({
minimap: {
showSlider: 'always',
renderCharacters: false,
},
});
}
};
// 监听内容变化
editor.onDidChangeModelContent(() => {
if (lintTimer) {
clearTimeout(lintTimer);
}
lintTimer = setTimeout(() => {
performLinting();
}, options.delay);
});
// 初始检查
performLinting();
}
// 代码快速修复建议
export interface QuickFix {
title: string;
kind: string;
edit: monaco.languages.WorkspaceEdit;
}
// 注册代码操作提供器(快速修复)
export function registerCodeActionProvider() {
monaco.languages.registerCodeActionProvider(['typescript', 'javascript', 'typescriptreact', 'javascriptreact'], {
provideCodeActions: (model, _range, context, _token) => {
const actions: monaco.languages.CodeAction[] = [];
// 检查是否有错误标记
const markers = context.markers.filter(marker => marker.severity === monaco.MarkerSeverity.Error);
for (const marker of markers) {
// 未使用变量的快速修复
if (marker.code === '6133' || marker.message.includes('is declared but')) {
actions.push({
title: `Remove unused declaration`,
kind: 'quickfix',
diagnostics: [marker],
edit: {
edits: [{
resource: model.uri,
textEdit: {
range: {
startLineNumber: marker.startLineNumber,
startColumn: 1,
endLineNumber: marker.endLineNumber,
endColumn: model.getLineLength(marker.endLineNumber) + 1,
},
text: '',
},
versionId: undefined,
}],
},
isPreferred: true,
});
}
// 缺少导入的快速修复
if (marker.message.includes('Cannot find name')) {
const variableName = marker.message.match(/Cannot find name '([^']+)'/)?.[1];
if (variableName) {
actions.push({
title: `Import '${variableName}'`,
kind: 'quickfix',
diagnostics: [marker],
edit: {
edits: [{
resource: model.uri,
textEdit: {
range: {
startLineNumber: 1,
startColumn: 1,
endLineNumber: 1,
endColumn: 1,
},
text: `import { ${variableName} } from './${variableName.toLowerCase()}';\n`,
},
versionId: undefined,
}],
},
isPreferred: false,
});
}
}
// 类型错误的快速修复
if (marker.message.includes('Type') && marker.message.includes('is not assignable')) {
actions.push({
title: 'Add type assertion',
kind: 'quickfix',
diagnostics: [marker],
edit: {
edits: [{
resource: model.uri,
textEdit: {
range: {
startLineNumber: marker.startLineNumber,
startColumn: marker.startColumn,
endLineNumber: marker.endLineNumber,
endColumn: marker.endColumn,
},
text: `(${model.getValueInRange({
startLineNumber: marker.startLineNumber,
startColumn: marker.startColumn,
endLineNumber: marker.endLineNumber,
endColumn: marker.endColumn,
})} as any)`,
},
versionId: undefined,
}],
},
isPreferred: false,
});
}
}
// 添加格式化操作
actions.push({
title: 'Format Document',
kind: 'source.formatAll',
command: {
id: 'editor.action.formatDocument',
title: 'Format Document',
},
});
// 添加组织导入操作
actions.push({
title: 'Organize Imports',
kind: 'source.organizeImports',
command: {
id: 'editor.action.organizeImports',
title: 'Organize Imports',
},
});
return {
actions,
dispose: () => {},
};
},
});
}