Ctrl K
ComunidadGuías…

eslint.config.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Copyright (c) 2026 开发者猫叔 (DeveloperCatUncle) · 商业使用需授权:COMMERCIAL-LICENSE.md
"use strict";
/**
 * ESLint 配置:只开「报了就一定是 bug」的那十二条。
 *
 *   npm run lint         (= node test/lint.js,只对新增的违规报红)
 *   npx eslint server.js (看某个文件的原始结果)
 *
 * 为什么只开这么几条:
 *   - 这道闸门的价值全靠「红了就得修」。开一条会误报的规则,头一个星期就会被人加进忽略名单,
 *     再过一个月就没人看了。下面每一条都满足:代码能跑、但写出来的意思和实际跑的不一样
 *     (同一个键写两遍后一个悄悄盖掉前一个、typeof 拼错成永远为假、return 后面的代码永远不跑……)。
 *   - 不开 no-undef:public/js 下是经典 <script>,十来个文件共享一个全局作用域,
 *     A 文件定义的函数 B 文件直接调,ESLint 一个文件一个文件看,会报成片的「未定义」。
 *     这件事交给 tsc 的 TS2304(test/typecheck.js),它是把整页的脚本放在一起看的。
 *   - 不开格式类规则:实测对全仓跑一次 Prettier,58 个套件里有 15 个变红——
 *     很多测试按正则读源码,换行、引号一动,正则就切空了。格式统一不值这个险。
 *
 * 忽略的目录:用户数据(workspace/ projects/ data/)、构建产物、依赖、任务_* 临时目录,
 * 以及 .gitignore 里挡掉的那些目录(本机私货:别人 clone 下来没有,本机红了 CI 却是绿的,
 * 这种「只在我这儿红」的闸门没人会信)。
 */
const fs = require("fs");
const path = require("path");

/**
 * .gitignore 里「以 / 结尾」的目录行,翻成 ESLint 的 ignores 写法。
 * 名单从 .gitignore 现读,不在这儿抄一份——抄了就会和真源分叉。
 * 只认目录行:*.log、config.json 这些跟 .js 无关,认了也白认。
 */
function gitignoredDirs() {
  let text = "";
  try { text = fs.readFileSync(path.join(__dirname, ".gitignore"), "utf8"); } catch { return []; }
  const out = [];
  for (const raw of text.split("\n")) {
    const line = raw.trim();
    if (!line || line.startsWith("#") || line.startsWith("!") || !line.endsWith("/")) continue;
    const dir = line.replace(/^\/+/, "").replace(/\/+$/, "");
    if (!dir) continue;
    // 中间带斜杠的(skills/ppt-master/)只认仓库根下那一处;不带的(node_modules/)哪一层都算
    out.push(dir.includes("/") ? dir + "/**" : "**/" + dir + "/**");
  }
  return out;
}

// 这十二条的共同点:命中即 bug,没有「风格不同」一说。
const RULES = {
  "no-dupe-keys": "error", // 对象字面量里同一个键写两遍,后一个悄悄盖掉前一个
  "no-unreachable": "error", // return / throw 后面的代码永远不会跑
  "no-unsafe-finally": "error", // finally 里 return 会吞掉 try 里抛的错
  "no-func-assign": "error", // 给函数声明重新赋值
  "no-redeclare": "error", // 同一作用域 var / function 声明两次
  "no-self-assign": "error", // a = a
  "no-dupe-else-if": "error", // else if 的条件和前面某一支一模一样,这一支永远进不来
  "no-const-assign": "error", // 给 const 赋值,运行到那一行直接抛
  "valid-typeof": "error", // typeof x === "strnig" 永远为假
  "use-isnan": "error", // x === NaN 永远为假
  "getter-return": "error", // getter 忘了 return
  "no-dupe-class-members": "error", // class 里同名方法写两遍
};

module.exports = [
  {
    ignores: [
      "workspace/**",
      "projects/**",
      "dist/**",
      "build/**",
      "**/node_modules/**",
      "任务_*/**",
      "public/vendor/**",
      // 技能包是装给 agent 在用户工作区里用的素材,不少是第三方的,不归这道闸门管
      "skills/**",
      // VS Code 本地历史插件存的旧副本:一份文件的几十个老版本,查它们只会报过去的错
      ".history/**",
      ...gitignoredDirs(),
    ],
  },
  {
    files: ["**/*.js", "**/*.cjs"],
    languageOptions: { ecmaVersion: "latest", sourceType: "commonjs" },
    // 我们只开了十二条,代码里给别的规则留的 disable 注释是正当的说明,不算「多余」
    linterOptions: { reportUnusedDisableDirectives: "off" },
    rules: RULES,
  },
  {
    files: ["**/*.mjs"],
    languageOptions: { ecmaVersion: "latest", sourceType: "module" },
    linterOptions: { reportUnusedDisableDirectives: "off" },
    rules: RULES,
  },
  {
    // 前端是经典 <script>,不是 CommonJS 也不是 ES module:顶层声明就是全局
    files: ["public/**/*.js"],
    languageOptions: { sourceType: "script" },
  },
];