
React Doctor 规则编写指南从一句话 Bug 定义到 OSS 验证的 AST 规则【免费下载链接】react-doctorYour agent writes bad React. This catches it项目地址: https://gitcode.com/GitHub_Trending/re/react-doctorReact Doctor 通过一族确定性静态分析规则在扫描时抓住agent 爱写、人容易漏的 React 问题覆盖 state/effects、性能、架构、安全与无障碍等面。仓库随附的规则编写手册 HOW_TO_WRITE_A_RULE.md 以 PR #491no-mutating-reducer-state规则为贯穿案例给出了从 Bug 定义、精度分级、对抗性测试设计到 OSS 大规模评估RDE的完整工程流程。本文继承手册的完整骨架并结合本仓库真实源码规则实现、defineRule、scanByPattern、runRule测试框架等补证每个环节的实际落地形态读完即可掌握编写一条高置信、低噪声规则的全套方法。规则质量门槛手册开宗明义一条好规则必须同时满足七个标准Specific具体只抓一个有明确命名的问题Grounded有据问题经过官方文档、真实代码、issue、PR 或 evals 验证Precise精确检测器匹配诊断所描述的行为Low-noise低噪声误报被视为正确性 bug而不是可接受的代价Tested adversarially对抗性测试测试覆盖合法边界情形而不只是明显违规的样例Scoped有边界v1 不试图顺手解决相邻规则想法Readable可读辅助函数名精确描述其语义。这七条标准直接对应了 PR 描述、测试套件与 Review Triage 的要求是后文所有检查清单的源头。端到端工作流手册把一条规则从想法到合并拆成 16 步分为实现前研究 → 实现与测试 → 评估与合并三段用一句话定义 bug。解释使其成为 bug 的运行时行为。检查现有规则文件与工具函数。用 RDEReact Doctor Evals与 OSS 代码验证想法。确定 v1 范围与检测器精度。编写对抗性测试。实现检测器。仅在必要时新增或复用工具函数。运行定向测试与 typecheck。用 RDE 对大量 OSS 仓库跑评估。把 eval 输出过滤到目标规则。人工逐条检查诊断。写一份带 before/after 示例的清晰 PR 描述。分诊 bot 与人工 review 评论。为真实问题修复补充回归测试。格式化、提交、推送并在修复落地后解决已处理的 review 线程。值得注意的是验证出现在两处第 4 步在实现前用 OSS 验证规则该不该存在、该多窄第 10 步在实现后用 OSS 验证规则够不够精确。这两步都依赖仓库自带的评估框架 packages/evals其语料清单见 repositories.json核心入口是 run-corpus-evaluation.ts。定义规则规则定义必须使用如下句式This rule catches code pattern that causes specific problem.PR #491 的实例This rule catches React useReducer reducers that mutate the current state object and return that same object.要避免含糊定义This rule catches bad reducer state updates.每条规则还必须给出运行时理由React compares reducer state by reference. If a reducer mutates the old state object and returns it, React can treat the update as unchanged.定义阶段要回答五个必答题哪个框架/库的行为使它成为 bug什么代码形状触发 bug什么代码形状修复它哪些相似代码是合法的v1 故意跳过什么一个可以对照的成品事实no-mutating-reducer-state的用户可见消息是This reducer changes state in place, so your update is silently skipped.见 no-mutating-reducer-state.ts。它描述的是用户后果更新被静默跳过而不是实现细节——这正符合手册对 PR 文案不要先讲内部实现的要求。调研现有规则模式与真实证据动手前先调研仓库内的既有模式。oxlint 插件规则的调研路径rules/ /各分类目录state-and-effects/、performance/、security/等 30 余个分类utils/ 工具函数目录rule-registry.ts 规则注册表同目录下的*.test.ts测试文件。先复用、后新增。手册点名的现有 helper 在仓库中均有实体文件可直接参考其签名与注释Helper文件位置defineRuledefine-rule.tsrunRule测试框架run-rule.tswalkAstwalk-ast.tsisNodeOfTypeis-node-of-type.tsfindVariableInitializerfind-variable-initializer.tsstripParenExpressionstrip-paren-expression.ts同时收集真实世界证据官方文档中对该问题的说明、真实应用示例、被认可的调试回答、相似生态中已有的规则实现以及看起来可疑但不应上报的 OSS 代码。PR #491 收集的证据面包括React 官方文档中直接修改后return state的说法、React 内部讨论中reducer bailout 依赖同一性identity的结论、StackOverflow 上const next state这类别名修改示例RocketChat 的嵌套修改但顶层换新对象、Sentry 的state 内Map修改但顶层换新对象、PostHog 的先克隆new Map(state)再修改等合法写法以及 Grafana 的合法 no-opreturn state与 ToolJet 中导入的 reducer 传入useReducer的情形。这些合法反例直接决定了 v1 的边界。用 OSS 验证想法RDE 工作流一在实现之前用 RDE 测试规则想法是否与真实开源代码吻合。目标用大量开源仓库验证理论找到目标 bug 的真实样例找到误报陷阱学习常见库的惯用法决定这条规则是否该存在决定 v1 应该多窄。输入规则想法、一句话 bug 定义、正例、已知合法例、RDE 仓库缓存或清单。输出精确正例候选、模式相邻候选、误报样例、推荐检测器形状、推荐 v1 非目标、测试 fixture 列表。适用时机规则仍是提案阶段、预期 bug 形状不清、对库/框架惯用法不熟悉、有捕获合法模式的风险、需要对抗性测试素材时。手册给了一个可直接套用的 prompt 形状Find real-world evidence for a React Doctor rule: Rule: rule-name Goal: Find examples where exact bug definition. Return: - Strong positive examples - Pattern-adjacent examples - False-positive traps - Detector implications - Suggested adversarial tests Prefer examples tied to real framework/library usage. Do not treat similar-looking valid code as a positive.PR #491 工作流一的结论精确的 reducer bug 真实存在且被 React 文档记载扫描语料中应用级精确正例稀疏误报陷阱却很常见因此检测器必须要求真实的 ReactuseReducer调用、不应上报 no-op 的return state分支、嵌套修改后顶层克隆应留作另一条规则想法。确定范围与检测器精度实现前必须先给规则分类。精度由低到高有四档仅语法Syntax-Onlybug 是局部的、不需要绑定或路径分析时使用dangerouslySetInnerHTML{{ __html: value }}感知作用域Scope-Aware名字必须解析到特定 import/变量/绑定时使用。PR #491 的例子import { useReducer } from react; useReducer(reducer, initialState);标识符useReducer必须是 React 的导入不能是本地函数。源码中对应的做法是逐一识别import { useReducer } from react、别名形式如import { useReducer as useReactReducer } from react、以及通过命名空间/默认导入得到的React.useReducer见 no-mutating-reducer-state.ts 中对ImportSpecifier的判定。感知路径Path-Aware执行顺序与分支影响结论时使用。PR #491 的例子function reducer(state, action) { if (action.type add) { state.items.push(action.item); return { ...state }; } return state; }这段代码不应上报修改所在路径返回了新对象return state所在路径是 no-op。手册同时声明该规则应要求同一路径上先有修改、后返回原引用。扫描规则Scan Rules项目级多数规则是逐文件的 AST 规则但当信号存在于文件系统而非源码语法时应写 scan 规则。适用条件目标文件永远不会被 lint发布的 bundle、.env与配置文件、SQL、Firebase rules、仓库中的 secret 文件路径上下文public/、构建产物、仓库布局比代码形状更重要对整棵目录树做文件内容扫描才是正确的精度。如果 bug 是 lintable 源码中的 JS/TS 代码形状就写普通 AST 规则。Scan 规则位于 rules/security-scan/ 目录在defineRule调用中声明scan而不是create。真实例子firebase-permissive-rules.tsexport 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., }), });扫描契约与源码逐字段吻合见 file-scan.tsscan(file: ScannedFile): ScanFinding[]取代 AST visitorsScannedFile携带absolutePath、relativePath、content、isGeneratedBundle四个只读字段每个ScanFinding有message、line、column以及可选的severity/title/help字段——它们按单条发现覆盖规则的注册表元数据例如public-debug-artifact在产物含 secret 值时升级为error省略则继承规则的severity/title/recommendation。手册的示例只用了scanByPattern的三个参数实际实现scan-by-pattern.ts还支持一组抗误报机制值得在写扫描规则时了解pattern可以是单个正则也可以是按序尝试的析取数组第一个命中的模式定位发现位置requireAll合取门每个模式都必须在文件中命中如用一个 MCP import 证明被匹配的工具面确实是 MCP 面suppressWhen否决模式任意位置命中即抑制整条发现如签名校验调用回应了规则的担忧ignoreStringLiterals匹配前把字符串字面量内部清空避免把description: ...fetch...这类散文误认为真实调用点默认关闭——多数扫描规则合法地需要扫描字符串内容如 URL、secret、安装命令对 JS/TS 与 Firebase.rules文件匹配前会先按保持偏移的方式剥离注释保证报告的行/列仍然准确。注册、标签与严重度流程与普通规则一致Codegen 像对待任何其他规则一样拾取它security-scan桶自动套用Security分类与security-scan标签id:与severity:必须保持为规则文件中的字面量字段——generate-rule-registry.mjs 用正则解析它们能力门控capability gating、disabledBy、用户严重度覆盖、内联 disable、ignore.tags对 scan 规则与 AST 规则同样适用。执行方式不同scan 规则永远不会出现在生成的 oxlint 配置或 ESLint preset 中。react-doctor/core的check-security-scan环境检查check-security-scan.ts在一次有界的整树遍历中运行所有已注册scandiff/staged 扫描会像其他整项目检查一样跳过它。测试方式单规则测试用 test-utils 下的内存 harness 构造ScannedFile、断言 findings写在同目录测试文件中AST 规则对应的是runRule见 run-rule.ts端到端覆盖走 check-security-scan.test.ts配合packages/core/tests/fixtures/check-security-scan/下的 fixture 目录树。V1 范围不要把相邻规则想法混进 v1。PR #491 把 v1 限定为真实 ReactuseReducer调用、同文件 reducer 函数、对原 state 或其别名的修改、同路径返回原顶层 state 引用。明确跳过或留文档说明导入的 reducer 函数体、mutate(state)这类辅助调用、const { items } state这类解构别名、复杂循环与 try/catch 控制流、嵌套引用修改后浅克隆、Immer 与 Redux Toolkit draft reducer。被显式拆出去的独立规则想法state.user.name Ada; return { ...state };它修改的是嵌套 state但返回了新顶层对象不应纳入no-mutating-reducer-state需要单独措辞与单独的误报处理。从当前源码看手册之后实现又有若干演进均见于 规则头部注释相对导入的跨文件 reducer 解析已通过resolveReducerFunction支持非相对路径别名、node_modules、大于 2 MB 的生成文件显式排除单层级解构别名已被跟踪??/||/逻辑赋值按修改处理而 TODO(v2) 明确留下三项缺口——嵌套同一性上述state.user.name情形、更宽的修改 APImutate(state)、lodashset等、以及循环/try-catch/带标签跳转的精确 CFG 路径分析。此外规则通过analyzedReducersWeakSet 去重保证同一 reducer 被多个组件接线时只报一次并用REDUCER_PATH_STATE_LIMIT阈值约束路径状态数量——这些都是低噪声标准在实现层的落实。设计测试套件测试套件应覆盖九类情形直接违规、别名违规、import 别名、命名空间导入、相似但合法的写法、作用域遮蔽、导入/未解析情形、框架/库逃生门、以及来自 review 评论的回归测试。手册特别强调测试要多样化不要复制同一种形状。违规测试样例直接修改加同引用返回import { useReducer } from react; function reducer(state, action) { state.count; return state; } useReducer(reducer, { count: 0 });别名修改加别名返回import { useReducer } from react; function reducer(state, action) { const next state; next.name action.name; return next; } useReducer(reducer, { name: });原地数组方法直接作为返回值sort原地排序并返回同一数组引用import { useReducer } from react; useReducer((state, action) { return state.sort((left, right) left.id - right.id); }, []);Switch 穿透fallthroughimport { useReducer } from react; function reducer(state, action) { switch (action.type) { case mutate: state.count; case done: return state; default: return { ...state }; } } useReducer(reducer, { count: 0 });透明包装as类型断言不改变同一性import { useReducer } from react; function reducer(state: State, action) { state.items!.push(action.item); return state as State; } useReducer(reducer, { items: [] });源码侧的佐证规则把copyWithin、fill、reverse、sort维护为一个同引用数组返回方法集合no-mutating-reducer-state.ts正是为了让第三类样例这类返回state.sort(...)结果的写法被识别为同引用返回。合法测试样例No-op 返回React 官方认可 reducer 对无操作 action 返回原 stateimport { useReducer } from react; function reducer(state, action) { if (action.type noop) { return state; } return { ...state, count: state.count 1 }; } useReducer(reducer, { count: 0 });先克隆再修改import { useReducer } from react; function reducer(state, action) { const next { ...state }; next.count; return next; } useReducer(reducer, { count: 0 });修改路径返回新对象前文 Path-Aware 同例此处作为合法用例import { useReducer } from react; function reducer(state, action) { if (action.type add) { state.items.push(action.item); return { ...state, changed: true }; } return state; } useReducer(reducer, { items: [] });非 React 的Array.prototype.reduce名字撞车作用域解析必须排除items.reduce((state, item) { state.push(item); return state; }, []);本地遮蔽的useReducer用户自定义的同名函数不是 React 导入function useReducer(reducer, initialState) { return [initialState, reducer]; } function reducer(state, action) { state.count; return state; } useReducer(reducer, { count: 0 });导入的 reducerv1 跳过函数体分析import { useReducer } from react; import { reducer } from ./reducer; useReducer(reducer, {});动态计算属性不应被当作静态方法名import { useReducer } from react; function reducer(state, action) { const push action.method; state.itemspush; return state; } useReducer(reducer, { items: [] });实现检测器实现前先写伪代码。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实际实现中path analysis 落地为ReducerPathState恰好持有三个字段originalStateReferenceNames指向原 state 对象的变量名集合返回其中任一个即等价于return state、mutableStateSourceNames指向原 state 或其中可达数据的变量名集合、mutations当前路径上已记录的修改每个分支通过克隆该状态向后传播——与伪代码逐行对应。实现要求检测器必须与一句话规则定义严格匹配在信任标识符名字之前先解析 import把被遮蔽的绑定视为不同的名字不要把嵌套函数当成会立即执行来走只建模规则结论所需的控制流除非规则显式支持否则跳过未知或导入的代码为已知的 v2 缺口加 TODO。手册还总结了一组资源启发的实现规则来自主流 AST 工具生态的经验来自 ESTree检查节点字段而不是从源码文本猜测来自 Babel区分裸节点与 pathpath 式包装器携带 parent、container、scope 与遍历状态来自 Babel同一性问题用 bindings 回答当 import 或遮蔽起作用时不要信任标识符文本来自 Babel避免不必要的遍历浅层结构用直接子节点查找来自 Babel嵌套结构很常见显式剪枝或建模嵌套函数、类与块来自 OXC/Babex预期 Babel 兼容词汇表但针对 TypeScript、JSX、可选链、计算成员要逐一验证解析器特定的节点形状来自 React Compiler对不支持的 JavaScript/控制流写明不支持而不是假装每个模式都被健全建模用置信度分层思考强诊断只给高置信发现。AST 词汇表常用 ESTree/Babel 节点词汇词汇说明示例Program文件级语句列表import React from react;ImportDeclarationES 模块导入语句import { useReducer } from react;ImportSpecifier具名导入绑定import { useReducer } from react中的useReducerIdentifier命名绑定或引用stateVariableDeclarator声明中的一个变量绑定const next state中的next stateMemberExpression对象属性访问state.itemsCallExpression函数或方法调用state.items.push(item)AssignmentExpression对目标的赋值state.count 1UpdateExpression自增/自减表达式state.countUnaryExpression一元运算符表达式delete state.countReturnStatement函数返回语句return stateIfStatement带 consequent 与可选 alternate 两条路径的条件分支if (action.type add) { ... }ConditionalExpression带 consequent 与 alternate 值的三目表达式condition ? next : stateLogicalExpression短路逻辑表达式value \|\| stateSwitchStatement可穿透的 case 分支switch (action.type) { ... }SwitchCase一个 switch case 及其语句case add: state.count;BlockStatement带作用域的语句列表{ const next state; }FunctionDeclaration提升的函数声明function reducer() {}FunctionExpression函数表达式值const reducer function () {};ArrowFunctionExpression箭头函数表达式值const reducer () {};ParenthesizedExpression透明表达式包装(state)TSAsExpressionTypeScriptas包装state as StateChainExpressionESTree 风格 AST 中的可选链包装state.items?.push(item)计算成员的处理state.items.push(item); // 静态属性push state.itemspush; // 静态字符串属性push state.itemspush; // 动态属性未知只有静态属性名才应匹配已知的修改方法——动态属性必须返回未知null把它当静态名处理是最常见的误报来源之一。命名、工具函数与注释命名名字应描述精确行为。避免const isStateReference ... const getName ... const checkMutation ...推荐const isOriginalReducerStateReference ... const getStaticMemberPropertyName ... const collectReducerStateMutationsInExpressionOrStatement ... const canExpressionReturnOriginalReducerStateReference ...相关 helper 使用一致后缀isOriginalReducerStateReference; isMutableReducerStateSource; isReactUseReducerCall;工具函数在以下情形创建工具函数两个及以上调用点需要同一行为行为带有微妙的 AST 语义review 评论指出了重复逻辑。在以下情形不要创建它只是藏起一行简单代码它让名字变得不清晰它仅仅因为实现太长而存在。PR #491 的工具函数范例getStaticMemberPropertyName(node)必需行为对state.items.push返回push对state.items[push]返回push对state.items[push]返回null。注释注释只用于非显然的控制流或 AST 取舍。好注释// An if statement cannot use the generic statement path: the consequent and // alternate are separate possible paths. Therefore, each branch is evaluated // from the state after the condition runs.坏注释// Check if this is an if statement.注释三要求解释为什么这个分支存在解释有损行为或 v1 边界不要给显而易见的代码配叙述性注释。本地验证优先通过antfu/ni命令使用仓库脚本nr test nr lint nr typecheck nr format nr smoke:json-reportPR #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如果宽命令因无关的仓库状态失败要记录四件事运行的命令、失败位置、为何无关、以及通过的定向命令。用 Evals 测试新规则RDE 工作流二实现之后用 RDE 观察新规则在大量开源仓库上的表现。目标避免误报检查真实诊断度量噪声水平抓住单元测试遗漏的实现假设理解这条规则在生产项目里跑起来的体感。输入包含新规则的 React Doctor checkout、RDE 评估框架 checkout、仓库清单、仓库缓存、目标规则名。输出JSONL 扫描输出、过滤到目标规则的输出、按仓库/rootDir 的汇总、人工检查过的命中、后续修复或测试。适用时机规则实现已存在、定向测试通过、检测器可能噪声、规则使用了作用域/路径/启发式逻辑、规则影响常见 React 模式。必备处理方式扫描不同仓库而不仅是清单条目rootDir 扫描数与仓库数分开记录先过滤输出到目标规则再下结论命中数低时逐条人工检查命中数高时抽样人工检查为 eval 发现的误报补回归测试。PR #491 工作流二的事实记录目标规则no-mutating-reducer-state范围repos.json中 100 个不同仓库671 行 rootDir 扫描过滤后 100 个唯一仓库共 1 条诊断结论低噪声命中被人工检查。手册特别警告不要把清单条目数当成不同仓库数。评估记录应包含React Doctor checkout 路径、评估框架路径、仓库清单路径、不同仓库数、清单条目/rootDir 数、目标规则名、过滤输出路径、总诊断数、人工检查的命中数。编写 PR 描述结构要求Why捕获什么具体问题用 1–3 句解释运行时原因附坏的 before 示例附好的 after 示例What changed新增rule-name检测主要检测面在精确条件时报告允许重要合法模式为边界情形增加测试Eval results跑过 RDE 时附表格给出足以证明规则有效且不噪的数字有用时附上过滤输出产物的链接或名字Test plan定向测试命令、typecheck 命令、lint 命令。描述要求以 Catches X 开头必含 before/after 示例对经过 OSS 测试的规则附 eval 结果表只有当能澄清行为时才提及非目标不要以实现细节开头。Eval 结果表模板检查项结果扫描仓库数不同仓库数RootDir 扫描数清单/rootDir 条目数目标规则rule-name诊断数目标规则诊断总数发现的误报人工检查后计数输出产物过滤后的 JSONL / 汇总路径或链接Review 分诊对每条 review 评论做四类分诊。立即修真实误报对已声明行为的真实漏报错误的 AST 语义作用域解析 bug有合理测试用例的控制流 bug。通常修重复的 helper误导性的名字不必要的抽象令人困惑的注释。记录或推迟v1 范围外的漏报覆盖病态代码下的路径爆炸当前行为保守时的复杂循环/try-catch 建模跨导入文件分析。拒绝把规则扩到其消息描述之外的评论会增加误报的建议与仓库约定冲突的风格偏好。从 review 中修复的每个真实 bug 都要补回归测试只在修复或解释落地后才解决 PR 线程。检查清单实现前清单Bug 已用一句话定义运行时原因已记录已检查现有规则模式已审阅 OSS 样例想法需要验证时使用了 RDE 工作流一误报陷阱已列出已选定检测器精度v1 非目标已显式化。提 PR 前清单测试包含违规与合法的对抗性用例helper 名字匹配精确语义共享工具已复用如需要已更新生成式注册表对应 generate-rule-registry.mjs定向测试通过被触及包的 typecheck 通过PR 描述含 before/after 示例。合并前清单已运行 RDE 工作流二或已记录跳过原因eval 输出已过滤到目标规则命中已人工检查bot review 评论已分诊人工 review 评论已分诊真实问题已有回归测试修复落地后已解决 PR 线程已应用格式化提交中不含无关文件。常见失败模式在需要 import 解析时用了字符串/名字启发式在没有证明同路径先前修改的情况下上报return state把导入的函数当作本地实现把嵌套函数当作立即执行来遍历漏掉别名的重新赋值漏掉分支特定路径忽略 switch 穿透把动态计算属性当静态名处理把相关的 v2 规则混进 v1写镜像实现形状的测试而不是真实代码形状的测试;PR 文案解释内部实现却不解释用户可见的 bug。标准产出一条完成态的规则 PR 应包含规则实现、同目录测试如 no-mutating-reducer-state.test.ts、生成式注册表更新、被多个调用点需要的共享工具、带 before/after 示例的 PR 描述、测试计划、宽泛或启发式规则的 evals 汇总、以及带回归测试的 review 修复。一次性学习资源这是学习 AST 规则编写的 onboarding 材料在建立对 React Doctor 规则的品味时花 1–2 小时做一次而不是每个 PR 都做。用这段时间做 agent Q/A建立 AST 词汇表、理解解析器差异、学习生产级分析器如何处理作用域、置信度与误报。资源应提取什么ESTree 规范节点词汇表、标准节点形状、节点无上下文、避免重复信息的设计哲学Babel HandbookAST、visitor、path、scope、binding、遍历状态、嵌套结构、插件测试模式Babel Plugin Handbook实用插件编写指导visitor、path API、scope/binding 查找、遍历性能、单元测试OXCOxlint/parser 上下文、高性能 AST 工具链、可与 React Doctor 规则对照的实现模式React CompilerReact 规则语义、保守建模、控制流需求、React 规则验证方法、以及为什么不支持的 JS 特性应显式列为非目标React Doctor 本仓库产品语境覆盖 state/effects、性能、架构、安全、无障碍的确定性 React 扫描BabexOXC 底座的 Babel 兼容 API理解解析/遍历兼容性与快速 AST 工具链的形状针对这些资源做定向提问这条规则涉及哪些 AST 节点哪些名字必须经 binding 解析哪些语法创建新作用域哪些语法应停止遍历哪些嵌套结构可能制造误报TypeScript、JSX、可选链、计算属性上哪些解析器差异重要哪些情形该给高置信诊断、哪些只给 review 提示资源要点提炼ESTree 节点无上下文除非本地工具挂了 parent 指针不要假设节点知道自己的父节点本仓库为此提供attach-parent-references一类工具Babel path 在裸节点外包上 parent、scope、container 与遍历元数据React Doctor 的工具可能暴露不同包装器使用前先查本地 API只要规则依赖 import、别名或遮蔽变量scope 与 binding 解析就重要遍历昂贵够用就用单个 visitor 或直接子节点查找walkAst即此类工具嵌套结构极易处理错除非规则有意检查它们否则显式跳过嵌套函数React Compiler 对不支持或难以建模的 JavaScript 保守处理React Doctor 规则也应写明 v1 不支持的情形如 no-mutating-reducer-state 头部的 TODO(v2) 注释置信度分层是好用的心智模型只有高置信发现才应阻断或产生强诊断Babex 展示了兼容目标Babel 风格的 parse/traverse API 可以架在 OXC 之上因此规则作者应同时理解 Babel 词汇与 OXC 驱动的解析。小结React Doctor 的规则编写方法论可以浓缩为一条主线先用一句话与运行时理由把 bug 钉死再用 OSS 证据决定 v1 边界然后按仅语法 → 作用域 → 路径的精度阶梯选检测器形态用九类对抗性测试和两阶段 RDE 评估守住低噪声底线最后用标准 PR 结构与回归测试闭环。仓库中的no-mutating-reducer-state规则完整实现与 scan-by-pattern.ts 等文件是这套方法的最佳对照样本读手册时对照源码读源码时对照手册是上手编写 React Doctor 规则最快的路径。【免费下载链接】react-doctorYour agent writes bad React. This catches it项目地址: https://gitcode.com/GitHub_Trending/re/react-doctor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考