尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

如何为 react-doctor 贡献一条新 lint 规则?

如何为 react-doctor 贡献一条新 lint 规则? 如何为 react-doctor 贡献一条新 lint 规则【免费下载链接】react-doctorYour agent writes bad React. This catches it项目地址: https://gitcode.com/GitHub_Trending/re/react-doctorreact-doctor 的规则集合持续扩张贡献新规则的任务路径在仓库文档中是完整定义的你先用一句话定义规则要抓的代码模式再对照现有规则和工具函数实现检测器写对抗性测试更新生成的注册表用 OSS 仓库做 eval 验证噪声水平最后带着 eval 结果提 PR。本文的操作路径来自 docs/HOW_TO_WRITE_A_RULE.md 与 rule-research、rule-writing、rule-validate 三个 skill 文档参考实现是 PR #491 的no-mutating-reducer-state规则其源文件与测试都在仓库内可以直接阅读。开始前的环境要求来自根 package.jsonNode^20.19.0 || 22.13.0、pnpm 8仓库使用 pnpm workspace turbo规则代码位于packages/oxlint-plugin-react-doctor包。第一步用一句话定义规则在动手写代码之前先把规则定义成这种格式This rule catches code pattern that causes specific problem.文档中的正例This rule catches React useReducer reducers that mutate the current state object and return that same object.反例是模糊的定义catches bad reducer state updates——这类定义会让检测器边界失控。定义之外还必须写清运行时原因例如React 按引用比较 reducer statereducer 原地修改旧对象并返回同一引用时React 可能把这次更新当作无变化。定义阶段需要回答五个问题它们直接决定 v1 的范围哪个框架/库行为让这段代码成为 bug什么代码形态触发 bug什么代码形态是修复后的正确写法哪些长得像但合法的代码必须保持安静v1 有意不覆盖什么rule-research skill 要求把以上内容整理成一份规则契约Rule definition / Runtime reason / Detector precision / Evidence / Strong positives / False-positive traps / In scope / Out of scope / Test seeds / Open questions实现阶段只能按契约写行为不能临场扩大范围。核心纪律是把误报当作正确性 bug 处理诊断信息的范围不能宽于检测器实际证明的行为相邻的规则想法要拆成独立规则。第二步检查现有规则模式与工具实现前先看仓库里已有的代码结构避免重复造轮子。需要检查的位置packages/oxlint-plugin-react-doctor/src/plugin/rules/ 下按类别组织的规则目录a11y、architecture、correctness、state-and-effects、security-scan等utils/ 工具函数目录rule-registry.ts与规则同目录放置的*.test.ts测试文件文档明确要求先复用现有 helper再新增列出的常用工具包括defineRule、runRule、walkAst、isNodeOfType、findVariableInitializer、stripParenExpression。新增 helper 之前先用 truffler 搜索仓库里是否已有同行为实现bunx rayhanadev/truffler symbol-or-behavior \ packages/oxlint-plugin-react-doctor/src/plugin \ --kind function,interface,type,constant --limit 20创建 utility 的条件也有明确标准两个以上调用点需要同行为、行为涉及微妙的 AST 语义、或 review 指出重复逻辑如果只是隐藏一行简单代码或让名字更含糊就不要抽。如果想直接学习 AST 词汇与边界处理参考实现是 no-mutating-reducer-state.ts 及其同目录测试它对应文档中反复引用的 PR #491。第三步选择检测精度与 v1 范围实现前先给规则分类文档给出四种精度Syntax-Only纯语法bug 是局部的不需要绑定或路径分析。典型如dangerouslySetInnerHTML{{ __html: value }}。Scope-Aware作用域感知名字必须解析到特定 import 或绑定。例如useReducer必须是 React 的 import 而不是本地函数本地 shadow 的同名函数必须保持安静。Path-Aware路径感知顺序和分支都重要。文档给出的例子reducer 的某个分支原地修改后return { ...state }返回新对象另一个分支是无副作用的return state——这种组合不应报告因为修改路径返回的是新对象。Scan Rules项目级扫描规则当信号在文件系统里而不是源码语法里时使用——目标文件根本不会被 lintshipped bundle、.env、配置文件、SQL、Firebase rules、仓库 secret 文件且路径上下文比代码形态更重要。如果 bug 是被 lint 的 JS/TS 源码形态就写普通 AST 规则。Scan 规则放在packages/oxlint-plugin-react-doctor/src/plugin/rules/security-scan/defineRule调用里声明scan而不是createexport const firebasePermissiveRules defineRule({ id: firebase-permissive-rules, title: Permissive Firebase security rule, severity: error, recommendation: Bind every read/write to request.auth.uid, immutable ownership, and tenant membership instead of treating sign-in as authorization., scan: scanByPattern({ shouldScan: (file) isFirebaseRulesPath(file.relativePath), pattern: /allow\s(?:read|write|...)\s*:\s*if\s(?:true|request\.auth\s*!\s*null)/i, message: Firebase rules grant broad access to everyone or to any signed-in user., }), });scan 的契约scan(file: ScannedFile): ScanFinding[]替代 AST visitorScannedFile携带absolutePath、relativePath、content、isGeneratedBundle每个ScanFinding有message、line、column可选severity/title/help按 finding 覆盖注册表元数据省略则继承规则的severity/title/recommendation。两点执行差异要注意scan 规则不会出现在生成的 oxlint 配置或 ESLint preset 里而是由react-doctor/core的check-security-scan环境检查在整树扫描时运行id:与severity:必须保持为规则文件里的字面量字段因为scripts/generate-rule-registry.mjs用正则解析它们。v1 范围纪律不要把相邻规则想法混进 v1。PR #491 的 v1 只覆盖真实的 ReactuseReducer调用、同文件 reducer 函数、对原始 state 或其别名alias的修改、同路径返回原始顶层 state 引用。它明确跳过import 进来的 reducer 函数体、mutate(state)这类 helper 调用、解构别名、复杂循环与 try/catch、嵌套引用修改后浅拷贝、Immer/Redux Toolkit draft reducer。像修改state.user.name后return { ...state }这类相邻想法需要单独的措辞和误报处理不能塞进同一条规则。第四步先写对抗性测试测试套件必须覆盖这些类别文档清单直接无效用例、别名无效用例、import 别名下达、命名空间 import、长得像的合法用例、作用域 shadow、import 了但解析不到的情况、框架/库逃生口、review 意见产生的回归测试。文档强调测试要多样化不要反复复制同一种形态。以no-mutating-reducer-state为例文档给出的无效用例包括直接修改加同引用返回state.count; return state;、别名修改加别名返回const next state; ...; return next;、原地数组方法返回return state.sort(...)、switch fallthrough 后落到return state、以及透明包裹层return state as State;。合法用例包括 no-op 的return state分支、clone-first 更新const next { ...state }; next.count; return next;、修改路径返回新对象、非 React 的Array.prototype.reduce、本地 shadow 的useReducer函数、v1 不覆盖的 imported reducer以及动态计算属性state.itemspush不能当静态方法名匹配。测试文件与规则同目录放置命名如no-mutating-reducer-state.test.ts。scan 规则则用内存测试工具 run-scan-rule.ts构造ScannedFile、断言 findings写在同目录测试里端到端覆盖由 packages/core/tests/check-security-scan.test.ts 对着packages/core/tests/fixtures/check-security-scan/下的 fixture 树运行。第五步实现检测器先写伪代码再写实现。PR #491 的伪代码骨架for each file: collect React useReducer imports collect React namespace/default imports for each CallExpression: if callee is not React useReducer: continue reducerFunction resolve first argument if reducerFunction is not same-file: continue stateName first reducer parameter analyze reducer body by path path analysis: track original state reference names track mutable state source names track mutations seen on current path when statement mutates original state source: remember mutation when statement returns original state reference: report remembered mutations实现要求文档原列检测器必须匹配一句话规则定义信任标识符名字之前先解析 importshadowed binding 当作不同名字处理不要把嵌套函数当作立即执行来遍历只建模规则声明需要的控制流未知或 import 来的代码跳过除非规则明确支持已知的 v2 缺口用 TODO 标出。文档还要求对不确定情况保持安静keep uncertain cases quiet诊断信息与检测器证明的条件一致。命名上helper 名必须描述精确行为避免isStateReference、getName、checkMutation偏好isOriginalReducerStateReference、getStaticMemberPropertyName、collectReducerStateMutationsInExpressionOrStatement相关 helper 用一致后缀isOriginalReducerStateReference/isMutableReducerStateSource/isReactUseReducerCall。注释只用于非显然的控制流或 AST 取舍解释分支为什么存在、v1 边界在哪不叙述显而易见的代码。第六步更新生成的注册表规则文件写好后注册表是生成物。packages/oxlint-plugin-react-doctor的 package.json 里定义了生成脚本底层是 scripts/generate-rule-registry.mjspnpm --filter oxlint-plugin-react-doctor gen pnpm --filter oxlint-plugin-react-doctor gen:checkgen重新生成规则注册表gen:check生成后用git diff --exit-code检查 core-rule-registry-data.json、rule-registry.ts 与 security-scan-rule-registry.ts 是否与规则文件一致。Pre-PR checklist 里有一条Generated registry is updated if required——提交前注册表必须与规则文件同步。scan 规则的注册、tag 与 severity 流程与普通规则相同security-scanbucket 会自动应用Security类别和security-scantag。第七步本地验证仓库脚本通过antfu/ni的nr命令执行文档 Verify Locally 一节nr test nr lint nr typecheck nr format nr smoke:json-report迭代期间用聚焦命令。PR #491 实际使用的一组pnpm exec vp test run packages/oxlint-plugin-react-doctor/src/plugin/rules/state-and-effects/no-mutating-reducer-state.test.ts pnpm --filter oxlint-plugin-react-doctor typecheck pnpm lint注意该包的typecheck与test脚本本身会先跑pnpm gen见 plugin package.json所以包级命令会顺带校验注册表生成物。如果宽范围命令因无关的仓库状态失败文档要求记录四件事跑了什么命令、失败位置、为什么与本次改动无关、以及通过的聚焦命令是什么。第八步用 Evals 在 OSS 仓库上验证实现完成、聚焦测试通过后用 RDEeval harness把新规则放到大量开源仓库上跑目标是避免误报、查看真实诊断、测量噪声、发现单元测试漏掉的实现假设。输入包含新规则的 react-doctor checkout、RDE eval harness checkout、repo manifest、repo 缓存、目标规则名。输出JSONL 扫描输出、过滤到目标规则的结果、按 repo/rootDir 的汇总、人工检查过的命中、后续修复或测试。文档列出的硬性处理要求扫描的是不同的仓库不只是 manifest 条目——manifest 条目数rootDir 数与 distinct repo 数要分开记录不要混淆判断结果前先把输出过滤到目标规则命中数低时人工检查每一个命中命中数高时抽样检查eval 发现的每个误报都要补回归测试并按 rule-validate 的要求加入fuzzcorpus。PR #491 的 eval 记录作为格式参考目标规则no-mutating-reducer-state范围是repos.json中 100 个 distinct repos671 个 rootDir 扫描行过滤后 1 条诊断结论是低噪声、该命中经人工检查。第九步写 PR 并准备合并PR 描述用固定结构## Why Catches specific issue。 运行时原因 1-3 句 一个 bad before 示例 一个 good after 示例。 ## What changed - Added rule-name。 - Detects main detection surface。 - Reports exact condition。 - Allows important valid patterns。 - Adds tests for edge cases。 ## Eval results | Check | Result | | ----------------- | ------------------------------------------ | | Repos scanned | distinct repos 数量 | | RootDir scans | manifest/rootDir 条目数 | | Target rule | rule-name | | Diagnostics | 目标规则诊断总数 | | False positives found | 人工检查后的数量 | | Output artifact | 过滤后的 JSONL / 汇总路径 | ## Test plan - 聚焦测试命令 - Typecheck 命令 - Lint 命令对发布包的用户可见改动还要跑nr changeset产生 changeset规则新增、bug 修复、误报修复默认用 patch changeset只有私有/文档/测试/工具类改动可以跳过且必须说明原因。rule-validate 还要求PR head 推送后对每条新规则跑run-parity两个 Daytona run 都完成才算有 parityrepository 数与 project-root 数分开比较先看目标规则的 delta 再下分类结论parity 跑不起来时PR 里报告具体阻塞原因并省略 eval 表格。一条规则 PR 的最终产物清单Standard Output 一节规则实现、同目录测试、注册表生成物更新、被多个调用点共享的 utility、带 before/after 示例的 PR 描述、test plan、宽泛或启发式规则的 evals 汇总、带回归测试的 review 修复。常见失败模式与限制文档的 Common Failure Modes 一节列出的坑基本都是检测器比定义走得更远导致的需要 import 解析时用了字符串/名字启发式没有证明同路径先有修改就报告return state把 import 来的函数当本地实现把嵌套函数当立即执行遍历漏掉别名重赋值、分支路径、switch fallthrough把动态计算属性当静态名把相邻 v2 规则混进 v1测试照抄实现形态而不是真实代码PR 描述只讲内部实现不讲用户可见的 bug。Review 分诊也有明确标准真误报、声明行为的漏报、错误的 AST 语义、scope 解析 bug——立即修重复 helper、误导性命名——通常修v1 范围外的漏报覆盖、病态代码的路径爆炸——文档化或延后扩大规则范围、增加误报的建议——拒绝。每个从 review 修出的真实 bug 都要有回归测试。至此一条新规则从一句话定义到 PR 合并的完整路径是定义契约 → 检查现有模式与工具 → 定精度与 v1 范围 → 先写对抗性测试 → 实现检测器 → 生成注册表 → 本地验证 → OSS eval → 带 eval 表格的 PR。所有命令与检查点都以上述文档为准规则质量的标准始终是特定、有据、精确、低噪声、经过对抗性测试、范围克制、可读。【免费下载链接】react-doctorYour agent writes bad React. This catches it项目地址: https://gitcode.com/GitHub_Trending/re/react-doctor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表