95 lines
2.7 KiB
Markdown
95 lines
2.7 KiB
Markdown
# Step 03 — Phase 2.2: ESLint 适配器
|
|
|
|
**依赖**: Step 02
|
|
**参考设计**: §3.3
|
|
|
|
## 目标
|
|
|
|
实现 JavaScript / TypeScript 的 ESLint 适配器,用 eslint npm 包直接检查代码。
|
|
|
|
## 前置准备
|
|
|
|
```bash
|
|
npm install --save eslint@^9.39.3
|
|
```
|
|
|
|
## 新建文件
|
|
|
|
| # | 文件 | 说明 |
|
|
|---|------|------|
|
|
| 1 | `src/adapters/eslint.ts` | `ESLintAdapter` |
|
|
|
|
---
|
|
|
|
## `src/adapters/eslint.ts`
|
|
|
|
```typescript
|
|
import * as vscode from 'vscode';
|
|
import { LinterAdapter, LinterDiagnostic, AdapterResult } from '../types';
|
|
|
|
export class ESLintAdapter implements LinterAdapter {
|
|
id = 'eslint';
|
|
supportedLanguages = ['javascript', 'typescript'];
|
|
|
|
async check(document: vscode.TextDocument, workingDir: string): Promise<AdapterResult> {
|
|
try {
|
|
const code = document.getText();
|
|
const { ESLint } = await import('eslint');
|
|
const eslint = new ESLint({ cwd: workingDir });
|
|
const results = await eslint.lintText(code, { filePath: document.uri.fsPath });
|
|
|
|
const diagnostics: LinterDiagnostic[] = [];
|
|
for (const result of results) {
|
|
for (const msg of result.messages) {
|
|
if (!msg.ruleId) { continue; }
|
|
const line = Math.max(0, (msg.line ?? 1) - 1);
|
|
const column = Math.max(0, (msg.column ?? 1) - 1);
|
|
const range = new vscode.Range(line, column, line, column + 1);
|
|
diagnostics.push({
|
|
severity: msg.severity === 2 ? 'error' : msg.severity === 1 ? 'warning' : 'info',
|
|
ruleId: `eslint:${msg.ruleId}`,
|
|
message: msg.message,
|
|
range,
|
|
suggestion: msg.fix ? msg.fix.text : undefined,
|
|
});
|
|
}
|
|
}
|
|
return { diagnostics, status: 'ok' };
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
if (message.includes('Cannot find module')) {
|
|
return { diagnostics: [], status: 'tool-unavailable', errorMessage: 'ESLint 未安装,请执行 npm install eslint' };
|
|
}
|
|
return { diagnostics: [], status: 'execution-failed', errorMessage: message };
|
|
}
|
|
}
|
|
|
|
isAvailable(): boolean {
|
|
try {
|
|
require.resolve('eslint');
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 关键逻辑
|
|
|
|
- `check()`: 使用 `ESLint.lintText(code, { filePath })` 直接检查代码文本,支持虚拟文档
|
|
- 将 ESLint 严重级别映射为 `error(2) → 'error'`, `warning(1) → 'warning'`, `0 → 'info'`
|
|
- ruleId 加前缀 `eslint:`,如 `eslint:no-unused-vars`
|
|
- `isAvailable()`: 通过 `require.resolve` 检测 eslint 是否已安装
|
|
- 错误处理:模块未找到 → `tool-unavailable`,其他错误 → `execution-failed`
|
|
|
|
---
|
|
|
|
## 验收
|
|
|
|
- [ ] 文件创建完成
|
|
- [ ] `npm run compile` 通过
|
|
- [ ] `npm run lint` 通过
|