You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何仅对暂存JS/TS文件中已变更代码行修复可修复的ESLint错误

如何仅对暂存JS/TS文件中已变更代码行修复可修复的ESLint错误

嘿,这个需求我之前在团队协作里刚好落地过,完全懂你想最小化修复范围、避免改动未修改代码的诉求。下面给你分享一套纯本地可实现的实操方案,核心思路就是先定位Git暂存区的目标文件和具体变更行,再让ESLint只针对这些行做修复,最后确保只保留变更行的修复结果并重新暂存:

一、基础准备

首先确保项目已经安装了eslint(这个肯定是必备的),我们会用到Node.js内置模块和Git原生命令,不需要额外安装第三方依赖,轻量又可靠。

二、编写核心Node.js脚本

在项目根目录新建scripts/fix-staged-lines.js文件,把下面的代码复制进去:

const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');

// 筛选出暂存区中的JS/TS文件
const getStagedFiles = () => {
  try {
    const output = execSync(
      'git diff --name-only --cached -- "*.js" "*.jsx" "*.ts" "*.tsx"',
      { encoding: 'utf-8' }
    );
    return output.trim().split('\n').filter(file => file);
  } catch (err) {
    console.error('获取暂存文件失败:', err.message);
    return [];
  }
};

// 解析单个文件的变更行范围(返回新文件中的行号数组)
const getChangedLines = (filePath) => {
  try {
    // 用--unified=0参数只输出变更行的核心信息,减少解析复杂度
    const diffOutput = execSync(
      `git diff --cached --unified=0 "${filePath}"`,
      { encoding: 'utf-8' }
    );
    const changedLineNumbers = [];
    // 匹配diff中的行范围标记,比如@@ -123,0 +124,5 @@ 代表新文件中124-128行是变更内容
    const rangeRegex = /@@ -\d+,\d+ \+(\d+),(\d+) @@/g;
    let matchResult;
    while ((matchResult = rangeRegex.exec(diffOutput)) !== null) {
      const startLine = parseInt(matchResult[1], 10);
      const lineCount = parseInt(matchResult[2], 10);
      // 把范围内的每一行号都存入数组
      for (let i = startLine; i < startLine + lineCount; i++) {
        changedLineNumbers.push(i);
      }
    }
    return changedLineNumbers;
  } catch (err) {
    console.error(`解析${filePath}的变更行失败:`, err.message);
    return [];
  }
};

// 仅对指定行执行ESLint自动修复
const fixTargetLines = (filePath, targetLines) => {
  if (targetLines.length === 0) return;

  // 1. 备份原文件内容,防止意外改动
  const originalContent = fs.readFileSync(filePath, 'utf-8');
  const originalLineList = originalContent.split('\n');

  // 2. 创建临时文件,对整个文件执行ESLint修复(先拿到全量修复结果)
  const tempFile = path.join(path.dirname(filePath), `.temp-${path.basename(filePath)}`);
  fs.writeFileSync(tempFile, originalContent);
  try {
    // 忽略ESLint的非致命错误输出,只关注修复结果
    execSync(`npx eslint --fix "${tempFile}"`, { stdio: 'ignore' });
  } catch (err) {
    // 无法自动修复的规则会抛出错误,这里直接跳过不影响流程
  }

  // 3. 读取修复后的临时文件内容
  const fixedContent = fs.readFileSync(tempFile, 'utf-8');
  const fixedLineList = fixedContent.split('\n');

  // 4. 只保留变更行的修复结果,其他行还原成原内容
  const finalLineList = [...originalLineList];
  targetLines.forEach(lineNum => {
    // 注意:行号是从1开始计数,数组索引要减1
    const lineIndex = lineNum - 1;
    if (fixedLineList[lineIndex] !== undefined && fixedLineList[lineIndex] !== originalLineList[lineIndex]) {
      finalLineList[lineIndex] = fixedLineList[lineIndex];
    }
  });

  // 5. 将筛选后的结果写回原文件
  fs.writeFileSync(filePath, finalLineList.join('\n'));

  // 6. 清理临时文件
  fs.unlinkSync(tempFile);
};

// 主执行流程
const main = () => {
  const stagedFileList = getStagedFiles();
  stagedFileList.forEach(file => {
    const absolutePath = path.resolve(file);
    const targetLineNumbers = getChangedLines(absolutePath);
    console.log(`处理文件: ${file},目标修复行: ${targetLineNumbers.join(', ')}`);
    fixTargetLines(absolutePath, targetLineNumbers);
    // 把修复后的文件重新暂存,确保提交的是修复后的版本
    execSync(`git add "${absolutePath}"`);
  });
  console.log('所有暂存文件的变更行修复完成!');
};

main();

三、配置自动触发(可选)

如果你想在每次提交代码前自动执行这个修复脚本,可以配置Git的pre-commit钩子:

  1. 到项目根目录的.git/hooks文件夹下,新建pre-commit文件(不要加任何后缀),内容如下:
#!/bin/sh
# 执行自定义的修复脚本
node scripts/fix-staged-lines.js
# 继续执行后续的提交流程
exit 0
  1. 给这个钩子文件添加执行权限:
chmod +x .git/hooks/pre-commit

之后你每次运行git commit时,脚本都会自动处理暂存文件的变更行修复,不用手动触发。

一些小提醒

  • 这个方案只处理ESLint标记为可自动修复的错误,对于无法自动修复的规则(比如部分no-unused-vars场景),还是需要手动调整。
  • 如果你的ESLint需要指定特殊配置文件(比如不在根目录的tsconfig.json),可以在脚本的ESLint命令里加上--config参数指定路径。
  • 首次使用建议先手动运行node scripts/fix-staged-lines.js测试效果,确认符合预期后再配置自动钩子。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 12:39:37