news 2026/9/25 4:14:32

anti-slop开发者教程:如何从零编写第一条基于ESTree的Oxlint自定义Lint规则

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
anti-slop开发者教程:如何从零编写第一条基于ESTree的Oxlint自定义Lint规则

anti-slop开发者教程:如何从零编写第一条基于ESTree的Oxlint自定义Lint规则

【免费下载链接】anti-slopOpinionated Oxlint rules for rejecting low-evidence TypeScript and JavaScript patterns项目地址: https://gitcode.com/gh_mirrors/ant/anti-slop

anti-slop 是一组有主见的 Oxlint 规则集,专门拒绝低证据、低信号的 TypeScript 与 JavaScript 模式。本教程带你从零编写第一条基于 ESTree 的 Oxlint 自定义 Lint 规则:理解 AST 节点、用defineRule定义检查逻辑、写测试验证,最终注册进插件。全文以仓库内真实规则为样例,代码量精简,新手也能跟上。🧭

anti-slop 是什么:为什么需要自定义 Lint 规则

大多数团队遇到as unknown as User、type X = unknown这类"看起来能编译、实则掩盖证据"的写法时,通用 Lint 工具并不会拦截。anti-slop 的做法很直接:把团队标准写成规则,交给 Linter 自动执法。

它内置了 15 条规则(如 no-unknown-type-aliases.ts、no-reflect-get.ts),全部基于 Oxlint 的 ESTree API 实现,不引入额外解析器(见 AGENTS.md 的约定)。

这个项目特意设计为"可搬运"(vendored):把 src/ 整个复制到你的仓库、读懂它、改成团队自己的标准——这也是为什么理解"如何写一条规则"如此重要。

一条自定义 Lint 规则由什么构成

先建立心智模型。Oxlint 的 JS 插件 API 兼容 ESLint 的规则写法,一条规则就两样东西:

  • meta:规则的"身份说明"——类型(problem)、描述、以及报错文案模板(messages,支持{{占位符}})。
  • createOnce(context):规则的"大脑"——返回一组AST 访问器。ESTree 是 JS/TS 代码的抽象语法树(AST)标准表示,每个语法结构都有节点类型,比如Program(整个文件)、CallExpression(函数调用)、Identifier(标识符)。访问器按节点类型注册,每当解析器走到这类节点就被触发。

用仓库里最简单的规则 no-shape-in-symbol-names.ts 感受一下骨架:

export const noForbiddenTermInSymbolNamesRule = defineRule({ meta: { type: "problem", docs: { description: "Disallow the substring \"shape\" in symbol names." }, messages: { forbiddenSymbolName: 'Rename symbol "{{name}}" for its domain role.', }, }, createOnce(context) { return { Identifier(node) { if (!node.name.toLowerCase().includes("shape")) return; context.report({ node, messageId: "forbiddenSymbolName", data: { name: node.name } }); }, }; }, });

逻辑拆开看只有三步:① 监听Identifier节点;② 判断名字是否含违禁词;③ 命中就context.report上报,并填充messages里的占位符。这就是全部核心机制——换一种节点类型、换一个判断条件,就是另一条规则。

三步写出你的第一条 Oxlint 自定义 Lint 规则

第 1 步:选场景,找对 AST 节点

写规则前先问自己:这条模式在语法树里长什么样?

以"禁止把类型别名直接定义为unknown"(type Alias = unknown;)为例。它出现在类型别名声明节点TSTypeAliasDeclaration上,而顶层文件结构由Program节点承载。仓库实现见 no-unknown-type-aliases.ts:它选择监听Program,在文件级一次遍历完成收集与检查,这比在每次类型引用处反复查找更省事。

第 2 步:实现检查逻辑并上报

no-unknown-type-aliases.ts 的Program访问器做了两件事:

  1. 收集:遍历node.body(顶层语句),把每个TSTypeAliasDeclaration按别名名存进Map;
  2. 检查:对每个别名递归解引用——遇到TSUnknownKeyword就命中,递归还带visited集合防止type A = B; type B = A;这类循环引用死循环。

注意它如何区分导出写法:export type X = unknown在 AST 里是ExportNamedDeclaration包着TSTypeAliasDeclaration,所以代码里先剥一层声明再判断(第 52-56 行)。这种"剥包装"的防御性写法是 ESTree 规则里的常见模式。

第 3 步:用 RuleTester 写测试

每条语义规则都要配一份聚焦测试。仓库的测试风格非常轻量,看 no-unknown-type-aliases.test.ts:

import { RuleTester } from "oxlint/plugins-dev"; import { noUnknownTypeAliasesRule } from "./no-unknown-type-aliases.ts"; const tester = new RuleTester({ languageOptions: { parserOptions: { lang: "ts" } } }); tester.run("anti-slop/no-unknown-type-aliases", noUnknownTypeAliasesRule, { valid: ["type User = { readonly id: string };"], invalid: [{ code: "type Alias = unknown;", errors: [{ messageId: "unknownAlias" }] }], });

valid是不该报警的合法代码,invalid是必须报警的违规代码(按messageId精确断言)。新规则按src/rules/<规则名>.test.ts命名,再把它加进 package.json 的test脚本即可纳入检查流程。

注册规则:让 Oxlint 加载你的插件

写好的规则本身还不生效,需要两处"登记":

  1. 插件入口:src/index.ts 用@oxlint/plugins的eslintCompatPlugin把全部规则收进一个rules映射表,键名就是规则短名。你的新规则在这里 import 并挂上即可。

  2. 项目配置:目标仓库在oxlint.config.ts里声明插件入口并开启规则(完整示例见 README.md):

export default defineConfig({ jsPlugins: [ { name: "anti-slop", specifier: "./tools/oxlint/anti-slop/index.ts" }, ], rules: { "anti-slop/no-unknown-type-aliases": "error" }, });

配置细节、Vite+ 环境下的等价写法,都可以参考 skills/install-anti-slop/SKILL.md。

项目约定与避坑清单

  • src/是唯一权威源:改完生产代码后运行pnpm sync:skill-assets,把 src/ 同步到技能打包目录;scripts/sync-skill-assets.mjs 会排除测试文件,--check模式则用于 CI 校验两边一致。
  • 公共逻辑下沉到 shared:当规则开始"解类型"时(别名递归、泛型展开、内置工具类型识别),别在规则里复制粘贴——参考 src/shared/dictionary-types.ts 的createTypeEnvironment与classifyWideningTarget,以及 src/shared/reflect-method.ts 中"识别全局Reflect方法调用"的作用域解析技巧。
  • 规则保持通用:不加入应用专属的名字、路径或例外(AGENTS.md 明确要求),保证可跨仓库复用。
  • 提交前跑全量检查:pnpm check会串联 lint、test、typecheck 和技能资产一致性校验(package.json)。
  • 别为了过 Lint 而加断言:技能文档特别警告,不要通过as unknown as、降级规则等级来"洗白"类型(SKILL.md 第 65 行)。

总结:你的 Oxlint 自定义 Lint 规则路线图 🎯

  1. 定位节点:想清楚目标模式对应哪个 ESTree 节点类型(Program/CallExpression/Identifier…);
  2. defineRule两步走:meta写好描述与报错文案,createOnce里注册访问器并context.report;
  3. RuleTester 兜底:valid/invalid各覆盖几个典型场景,按messageId断言;
  4. 注册生效:挂进 src/index.ts 的映射表,在配置文件中声明插件并设为error;
  5. 同步与检查:pnpm sync:skill-assets+pnpm check,保证src/与打包资产一致。

从一条十几行的no-shape-in-symbol-names起步,到递归解析类型别名的no-unknown-type-aliases进阶,这条路径就是 anti-slop 全部 15 条规则的共同生长方式。把规则搬进你的仓库、按团队口味改造,让"低证据代码"无处遁形。

【免费下载链接】anti-slopOpinionated Oxlint rules for rejecting low-evidence TypeScript and JavaScript patterns项目地址: https://gitcode.com/gh_mirrors/ant/anti-slop

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 4:14:13

Cortex-M内存映射与STM32存储器组织:从HardFault到Memory-Mapped I/O实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:14:03

马兰戈尼学院2026年深圳校区周末兴趣班行情汇总:价格区间、授课语言与适合人群对比

时尚教育周末兴趣班行业基础科普时尚产业是兼具创意性与商业性的复合型产业&#xff0c;随着全球时尚消费市场的不断升级&#xff0c;行业对人才的需求也从单一的设计技能&#xff0c;转向兼具创意能力、商业思维与跨界整合能力的复合型人才。对于希望进入时尚行业的从业者、兴…

作者头像 李华
网站建设 2026/9/25 4:12:30

SpringBoot2.6.13+MySQL8+Flowable6.8.1工作流项目搭建与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:12:10

AI落地真相:六成项目使用率不足,幻觉、部署与Agent三大坑

上周末和一个做AI落地交付的朋友通了将近两个小时的语音。他这三年从大厂出来自己接项目&#xff0c;经手的行业覆盖金融、制造、客服&#xff0c;全是正经的企业级合同。电话挂掉之后我在书桌前坐了很久&#xff0c;脑子里只有一个念头反复打转&#xff1a;他说的每一句话&…

作者头像 李华
网站建设 2026/9/25 4:10:41

Java反序列化攻防本质:从CC1到CC7的机制演进

1. 这不是“漏洞合集”&#xff0c;而是一张Java反序列化攻防地图你可能在面试时被问过&#xff1a;“CC1和CC7有什么区别&#xff1f;”也可能在渗透测试报告里看到“检测到Apache Commons Collections反序列化链”&#xff0c;但真正能说清楚CC1为什么能绕过早期JDK黑名单、C…

作者头像 李华
网站建设 2026/9/25 4:09:00

Qwen3.5-9B长上下文实战:上下文工程与KV Cache优化要点

1. 先聊聊 9B 模型里的“上下文”到底指什么Qwen3.5-9B 这个型号&#xff0c;核心卖点其实是参数量只有 9B&#xff0c;却把上下文窗口做到了百万级别。很多人第一反应是“窗口大了能塞更多话”&#xff0c;这个理解没错&#xff0c;但真到了上手才发现&#xff0c;1m 上下文已…

作者头像 李华