eslint-plugin-drizzle 0.2.2 解析:修复嵌套对象中 drizzleObjectName 检测问题的技术细节
2026/9/19 13:20:08 网站建设 项目流程

eslint-plugin-drizzle 0.2.2 解析:修复嵌套对象中 drizzleObjectName 检测问题的技术细节

【免费下载链接】drizzle-ormORM项目地址: https://gitcode.com/gh_mirrors/dr/drizzle-orm

导读

本文围绕 eslint-plugin-drizzle 0.2.2 版本的核心修复——「当drizzleObjectName指向嵌套对象时,规则检测不再失效」——展开,结合仓库源码与测试用例,深入剖析enforce-delete-with-whereenforce-update-with-where两条规则的工作机制、drizzleObjectName选项的三种取值形态,以及嵌套对象(如this.dataSource.db.delete())场景下的成员表达式解析原理。读完本文,你将能够准确理解该插件在 0.2.2 版本中解决了什么问题、修复如何落地,以及在自己的项目中如何正确配置这两条防止危险 SQL 的规则。

一、0.2.2 版本变更:一条修复的含义

0.2.2 变更日志 只记录了一条变更:

fix: Correct detection ofdrizzleObjectNamewhen it's a nested object

这条修复要解决的是:当 Drizzle 数据库实例不是顶层变量db,而是被封装在嵌套对象中(例如this.dataSource.dbthis.database.dbthis.getDataSource().db),并且用户通过drizzleObjectName配置指定了内部对象名时,规则无法正确识别该调用来自 Drizzle 对象,从而导致误报(把非 Drizzle 的delete()/update()当作 Drizzle 调用)或漏报(真正的 Drizzle 调用未被拦截)。

要理解这条修复,必须先弄清楚drizzleObjectName选项与成员表达式(MemberExpression)解析的实现细节。

二、两条规则与 drizzleObjectName 选项

2.1 规则背景:防止无 WHERE 的全表删除与全表更新

eslint-plugin-drizzle 目前提供两条规则(见 src/index.ts):

  • enforce-delete-with-where:强制.delete()必须搭配.where(),防止误删全表;
  • enforce-update-with-where:强制.update().set()必须搭配.where(),防止误改全表。

两条规则的元数据声明一致:type: 'problem'fixable: 'code',并注册了一个可选的drizzleObjectName配置项,其类型为string | string[],见 enforce-delete-with-where.ts 与 enforce-update-with-where.ts。

2.2 drizzleObjectName 的三种形态

drizzleObjectName用于告诉规则:代码中哪个标识符才是 Drizzle 数据库实例,从而避免把用户自定义类(同样有delete()/update()方法)的调用误判为违规。其判定逻辑集中在 src/utils/options.ts 的isDrizzleObjName函数中:

  • 字符串形态typeof drizzleObjectName === 'string'时做精确相等比较,例如{ "drizzleObjectName": "db" }
  • 数组形态:传入string[]时,只要命中数组中任一名称即视为 Drizzle 对象;特别地,空数组[]等价于「不限制」,任何对象名都会被命中drizzleObjectName.length === 0直接返回true),这也是默认行为;
  • 默认值:两条规则的defaultOptions均为[{ drizzleObjectName: [] }],意味着不配置时规则对任意对象上的delete()/update()都生效。
{ "rules": { "drizzle/enforce-delete-with-where": ["error", { "drizzleObjectName": ["db"] }], "drizzle/enforce-update-with-where": ["error", { "drizzleObjectName": "db" }] } }

三、修复的核心:嵌套对象的成员表达式检测

3.1 修复前的缺陷

isDrizzleObj(src/utils/options.ts)负责判断一个MemberExpression节点是否来自 Drizzle 对象。它逐层检查node.object的类型:

  • Identifier:取node.object.name与配置比对;
  • MemberExpression:取node.object.property.name与配置比对;
  • CallExpression:取 callee 的nameproperty.name与配置比对。

问题在于:当 Drizzle 对象以多级嵌套形式出现时(如this.dataSource.db),isDrizzleObj只检查了第一层成员表达式(this.dataSource)的属性名dataSource,而未递归到内层db。此时如果用户配置的是drizzleObjectName: ["db"]dataSource不匹配,规则就会认为这不是 Drizzle 调用,从而漏报真正的db.delete()/db.update().set()危险操作。

3.2 修复后的检测流程

0.2.2 修复后,检测链按「从外到内」的顺序逐层提取属性名,只要任意一层命中配置的drizzleObjectName,就判定为 Drizzle 对象。以this.dataSource.db.delete()为例:

  1. 外层成员表达式为this.dataSource.db(调用delete的接收者),其property.namedb
  2. isDrizzleObj命中db与配置匹配,判定为 Drizzle 对象,触发规则;
  3. 同样地,this.getDataSource().dbthis.database.getDatabase()等链式嵌套也能被正确识别。

这一点在 delete.test.ts 中有直接印证:this.dataSource.db.delete({})drizzleObjectName: ['db']配置下被报告,且错误消息中的drizzleObjName被解析为完整的this.dataSource.db

3.3 错误消息中的对象路径解析

修复同时让错误提示更精准。规则在context.report中通过resolveMemberExpressionPath(src/utils/ast.ts)还原出完整的调用链文本,用于构造类似下面这条可读性极强的提示(见 enforce-update-with-where.ts):

Without.where(...)you will update all the rows in a table. If you didn't want to do it, please usethis.dataSource.db.update(...).set(...).where(...)instead.

resolveMemberExpressionPath会沿 AST 向上遍历,把MemberExpressionCallExpressionIdentifierThisExpression逐层拼接为字符串。从测试用例可以看到它支持的各种形态:

代码形态解析出的 drizzleObjName
db.update({}).set()db
getDatabase().update({}).set()getDatabase(...)
this.dataSource.getDatabase(arg1, arg2).update({}).set()this.dataSource.getDatabase(...)
this.getDataSource().db.update({}).set()this.getDataSource(...).db

这些断言分别出现在 update.test.ts 与 delete.test.ts 中,覆盖了this嵌套、方法链返回对象、带参数调用等多种真实编码场景。

四、where状态跟踪:规则的触发条件细节

两条规则都通过模块级变量lastNodeName记录「上一次访问过的成员属性名」,以判断.where()是否已经出现:

  • delete 规则(enforce-delete-with-where.ts):当访问到delete属性、且lastNodeName !== 'where'时报告违规;
  • update 规则(enforce-update-with-where.ts):当访问到set属性、其外层是update(...)调用、且lastNodeName !== 'where'时报告违规。

因此合法的链式调用db.update().set().where()db.delete().where()不会触发规则,而db.update().set()db.delete()、甚至db.update({}).set(未调用)都会被标记为错误——对应测试中的 valid/invalid 用例。注意lastNodeName是模块级状态,两条规则分别在各自模块内维护,互不干扰。

五、安装与配置实战

5.1 安装

在项目根目录执行(详见 readme.md):

# npm / yarn / pnpm / bun 任选其一 npm install eslint eslint-plugin-drizzle npm install -D @typescript-eslint/eslint-plugin @typescript-eslint/parser

@typescript-eslint/parser是必要的——规则的RuleTester测试即基于它运行(见 update.test.ts),生产环境同样依赖它解析 TypeScript 语法。

5.2 单条规则配置(.eslintrc.yml)

root: true parser: '@typescript-eslint/parser' parserOptions: project: './tsconfig.json' plugins: - drizzle rules: 'drizzle/enforce-delete-with-where': "error" 'drizzle/enforce-update-with-where': "error"

5.3 推荐配置:全量 / 推荐

插件导出了allrecommended两套预设配置(src/configs/recommended.ts),二者目前等价,均将两条规则设为error

root: true extends: - "plugin:drizzle/recommended" parser: '@typescript-eslint/parser' parserOptions: project: './tsconfig.json' plugins: - drizzle

5.4 减少误报:指定 drizzleObjectName

当项目中存在自带delete()/update()方法的类时,不配置drizzleObjectName会把它们的调用也判为违规。通过配置仅让 Drizzle 对象触发规则:

{ "rules": { "drizzle/enforce-delete-with-where": ["error", { "drizzleObjectName": ["db"] }], "drizzle/enforce-update-with-where": ["error", { "drizzleObjectName": ["db"] }] } }

配置后的行为差异如下(来自 readme.md 与 delete.test.ts):

class MyClass { public delete() { return {} } } const myClassObj = new MyClass(); myClassObj.delete(); // 配置了 drizzleObjectName 后不再误报 this.database.db.delete(); // 嵌套对象:0.2.2 修复后可被正确识别并报错

六、从版本演进看修复脉络

将 0.2.2 放入版本序列中可以更清楚地看到这条修复的价值:

  • 0.2.0(变更日志):首发版本,提供两条规则;
  • 0.2.1(变更日志):完善 README、调整错误文案;
  • 0.2.2(变更日志):修复嵌套对象下的drizzleObjectName检测,补齐了成员表达式递归识别的能力;
  • 0.2.3(变更日志):进一步覆盖「drizzleObjectName来自函数返回值」的场景,并将isDrizzleObjName提取为公共函数消除重复代码。

由此可见,0.2.2 是插件检测能力从「仅识别顶层变量」走向「支持嵌套对象」的关键一步,为后续对函数返回对象形态的支持奠定了基础。

结语

eslint-plugin-drizzle 0.2.2 的这条单行变更日志,背后是对 MemberExpression 递归解析逻辑的一次实质增强:它让drizzleObjectNamethis.dataSource.dbthis.getDataSource().db等嵌套对象场景下能够被正确命中,既避免了危险的无where全表操作漏网,也减少了自定义类方法调用的误报。对于在大型项目中将 Drizzle 实例封装在 Service、DataSource 等容器对象中的团队而言,升级到 0.2.2 及以上版本并配合drizzleObjectName配置,是构建「无 where 即报错」安全底线的高性价比方案。

【免费下载链接】drizzle-ormORM项目地址: https://gitcode.com/gh_mirrors/dr/drizzle-orm

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询