build(lint): 引入 ESLint 工具链与 flat config 最小规则集

- devDependencies: eslint 10 / typescript-eslint 8 / eslint-plugin-react-hooks 7 / globals / @eslint/js(ESLint 10 起 @eslint/js 不再随 eslint 自带,需显式安装)
- eslint.config.js:@eslint/js recommended + typescript-eslint recommended(非 type-checked)+ react-hooks recommended(v7 的 React Compiler 语义规则档整体关闭——57 处存量误报,保留经典 rules-of-hooks / exhaustive-deps 双规则)
- globals 分域:src/client → browser;src 根 / scripts / 根级 config → node;tests → node+browser
- reportUnusedDisableDirectives: error 揪孤儿豁免;no-unused-vars 对齐仓库既有 _ 前缀占位约定
- package.json 增加 lint script(eslint .)
This commit is contained in:
Menghuan1918
2026-09-03 20:00:07 +08:00
parent 9e1a034527
commit f418692ad0
3 changed files with 1413 additions and 2 deletions
+88
View File
@@ -0,0 +1,88 @@
// ESLint flat config(最小规则集):
// - 基础:@eslint/js recommended + typescript-eslint recommended(非 type-checked 档,
// 全量 type-checked 需要项目服务且更慢,当前收益不足以引入);
// - react-hooks recommended:client 侧是 React 重镇,依赖数组豁免注释
// (react-hooks/exhaustive-deps)由此规则消费;
// - globals 按运行域分治:client bundle → browser,host/脚本 → node,tests → 混合。
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import tseslint from 'typescript-eslint'
export default tseslint.config(
// 构建产物 / 工具目录不参与 lint(node_modules 与点开头目录默认也不进)。
{
ignores: [
'lib/',
'dist/',
'coverage/',
'registry/',
'playwright-report/',
'test-results/',
'node_modules/',
'.worktrees/',
],
},
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs.flat.recommended,
// react-hooks v7 的 recommended 捆绑了 React Compiler 语义规则(purity /
// immutability / refs / set-state-in-effect 等):本仓库对 CodeMirror / xterm
// 等命令式集成大量依赖 render 期读 ref、effect 内同步 setState 的既有模式,
// 57 处存量报错均为噪音级误报,先整体关闭该档,只保留经典双规则
// (rules-of-hooks / exhaustive-deps——后者消费代码里带理由的豁免注释)。
{
rules: Object.fromEntries(
[
'config',
'error-boundaries',
'gating',
'globals',
'immutability',
'incompatible-library',
'preserve-manual-memoization',
'purity',
'refs',
'set-state-in-effect',
'static-components',
'unsupported-syntax',
'use-memo',
].map(rule => [`react-hooks/${rule}`, 'off']),
),
},
// 孤儿 eslint-disable 注释(规则未实际触发)直接报错,防止豁免残留。
{ linterOptions: { reportUnusedDisableDirectives: 'error' } },
// no-unused-vars 对齐仓库既有约定:下划线前缀 = 刻意不用的占位(mock 桩等)。
{
rules: {
'@typescript-eslint/no-unused-vars': ['error', {
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
}],
},
},
// client bundle 运行在浏览器(portal 侧边栏 / 各视图 / 拦截层)。
{
files: ['src/client/**/*.{js,mjs,cjs,ts,tsx,jsx}'],
languageOptions: { globals: globals.browser },
},
// host 侧插件入口与构建/运维脚本跑在 Node。eslint.config.js 自身不 ignore:
// 它就是一个普通 ESM 脚本,走 js recommended + node globals 正常通过。
{
files: ['src/*.{js,mjs,cjs,ts}', 'scripts/**/*.{js,mjs,cjs,ts}', '*.config.ts', 'eslint.config.js'],
languageOptions: { globals: globals.node },
},
// tests:Node 里跑(vitest / fs fixtures),jsdom 组件测试又摸浏览器全局。
{
files: ['tests/**/*.{js,mjs,cjs,ts,tsx,jsx}'],
languageOptions: { globals: { ...globals.node, ...globals.browser } },
},
)
+8 -2
View File
@@ -82,7 +82,8 @@
"test:mount": "bash scripts/e2e-mount.sh",
"test:mount:aggregate": "bash scripts/e2e-aggregate-mount.sh",
"clean": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\"",
"check:consumer-types": "bash scripts/check-consumer-types.sh"
"check:consumer-types": "bash scripts/check-consumer-types.sh",
"lint": "eslint ."
},
"license": "MIT",
"peerDependencies": {
@@ -179,6 +180,11 @@
"tsdown": "^0.22.2",
"typescript": "^5.6.0",
"unrun": "^0.2.39",
"vitest": "^4.1.8"
"vitest": "^4.1.8",
"@eslint/js": "^10.0.1",
"eslint": "^10.9.1",
"eslint-plugin-react-hooks": "^7.1.1",
"globals": "^17.12.0",
"typescript-eslint": "^8.69.0"
}
}
+1317
View File
File diff suppressed because it is too large Load Diff