ESLint: +29 条 P1/P2 规则 + 12 条 TS 专属规则(含 no-shadow/no-array-constructor 冲突处理) Stylelint: 集成 stylelint-config-recommended + 27 条额外规则 PMD: 排除 20 弃用 + 17 噪音规则,补启 Security/Multithreading,274+12 条精选 SQL-lint: 内置精选 57 条规则配置 + 按 tier 分级 severity + 无项目配置时自动注入临时配置 模板导出: export-service.ts 导出 2-sheet xlsx(复用 xlsx 零新依赖) 模板导入: template-converter.ts 固定列映射解析 + dedup-prompt.ts AI 语义去重 导入预览增强: 错误规则分组置顶只读、跳过行提示、空数据提示 i18n: 新增 18 条模板导入/导出相关翻译 WebView: 静态分析/自定义规则项默认可展开显示 suggestion
33 KiB
SQLFluff 规则增强设计书
一、背景与目标
1.1 现状
当前 SqlLintAdapter(src/adapters/sql-lint.ts)作为外部 CLI 工具适配器,通过 spawn('sqlfluff', ...) 调用系统安装的 SQLFluff 4.2.2。其内置默认行为为:
// 当前行为:无内置配置文件,无配置时使用 CLI 默认(rules = all)
// 方言映射:sql → ansi,plsql → postgres
// 配置优先级:全局配置 > 项目 .sqlfluff > CLI 默认(rules = all)
SQLFluff 的 CLI 默认 rules = all 会无差别启用全部 75 条规则,存在以下问题:
- 无差别全启用:
rules = all启用 75 条规则,其中包含 7 条不应在代码审查中强制的规则(默认禁用、纯格式化噪音、需项目配置) - 格式化噪音泛滥:LT03(操作符换行)、LT04(逗号风格)、LT09(SELECT 目标换行)等纯格式化规则在审查中产生大量低价值诊断,淹没了真正的问题
- 争议性规则干扰:AL07(禁止表别名)、CV10(引号风格)、RF03(引用一致性)等规则因
force_enable = False默认不生效,且规则本身存在争议,全启用后行为不一致 - 与 ESLint/Stylelint 架构不对齐:ESLint 适配器使用
@eslint/jsrecommended + 精选规则,Stylelint 适配器使用stylelint-config-recommended+ 精选规则,而 SQLFluff 适配器无内置精选配置,仅依赖 CLI 默认全启用
1.2 目标
将内置配置从"无差别 rules = all(75 条全启用)"改为"精选规则集(57 条)":
- P0:保留全部 32 条 Core 核心规则(通过
rules = core启用) - P1:从 43 条非 Core 规则中精选 25 条高价值规则显式启用
- P2:保留 11 条可选规则(方言专用 + 团队偏好),供按需启用
- 排除:明确排除 7 条不推荐规则(3 条默认禁用 + 3 条格式化噪音 + 1 条需项目配置)
1.3 设计原则
核心特点:从全到精。 与 ESLint/Stylelint 适配器"从少到多"(recommended 61→92、12→68)的增强方向相反,SQLFluff 适配器是"从全到精"——从无差别
rules = all(75 条)精简为精选规则集(57 条),排除噪音规则,提升审查信噪比。
- 不破坏现有配置优先级:全局配置 > 项目
.sqlfluff> 内置配置,三层择一逻辑不变 - 不引入新依赖:SQLFluff 是外部 CLI 工具,无 npm 依赖变更,不需要修改
package.json - 设计内置 .sqlfluff 配置模板:新增内置配置常量,与 ESLint/Stylelint 三层配置架构对齐
- 同步更新 static-rules.json:为 75 条规则追加
tier分级标记,保证 UI 展示和去重检测覆盖完整 - 不修改规则 ID 前缀格式:诊断结果仍使用
sql-lint:{规则代码}格式
二、影响范围分析
2.1 需要修改的文件
| 文件 | 修改类型 | 修改内容 |
|---|---|---|
src/adapters/sql-lint.ts |
代码修改 | 新增 BUILTIN_SQLFLUFF_CONFIG 内置配置常量,无项目配置时注入精选规则集 |
src/rules/static-rules.json |
数据修改 | 为 75 条 SQLFluff 规则追加 tier 分级字段(P0/P1/P2/excluded) |
2.2 不需要修改的文件
| 文件 | 原因 |
|---|---|
package.json |
SQLFluff 是外部 CLI 工具,非 npm 依赖,无依赖变更 |
scripts/build.mjs |
不涉及构建配置变更,内置配置为纯字符串常量 |
src/orchestrator/orchestrator.ts |
仅做调度,不涉及配置逻辑 |
src/config/linter.ts |
配置读取层不变,三层优先级逻辑不变 |
src/adapters/eslint.ts / stylelint.ts |
独立适配器,互不影响 |
src/adapters/jsp.ts |
复用 ESLint 适配器,与 SQLFluff 无关 |
2.3 不受影响的功能
- 全局配置(用户指定的
sqlfluff配置路径):存在时完全替代内置配置,不受影响 - 项目配置(
.sqlfluff):存在时完全替代内置配置,不受影响 - 方言映射(
sql → ansi、plsql → postgres):不变 - 规则 ID 输出格式:仍为
sql-lint:{规则代码},不变 sqlfluff fix自动修复能力:不变,精选规则集中 43 条(75%)仍支持自动修复
三、详细设计
3.1 修改 src/adapters/sql-lint.ts:新增内置配置
3.1.1 当前行为
当前适配器在无项目 .sqlfluff 配置文件时,不传递任何 --rules 或 --config 参数,完全依赖 SQLFluff CLI 的默认行为(rules = all,75 条全启用):
// 伪代码:当前 spawn 调用逻辑
function buildSqlfluffArgs(filePath: string, dialect: string): string[] {
const args: string[] = ['lint', '--format', 'json'];
// 方言映射
args.push('--dialect', dialect === 'plsql' ? 'postgres' : 'ansi');
// 无内置 rules 配置 —— 依赖 CLI 默认(rules = all)
// 若存在项目 .sqlfluff,SQLFluff 自动发现并使用
args.push(filePath);
return args;
}
3.1.2 修改后:新增内置配置常量
// 新增:内置精选 .sqlfluff 配置模板(从全到精:rules = all → 57 条精选)
// P0(32 条 Core)+ P1(25 条精选非 Core)= 57 条
const BUILTIN_SQLFLUFF_CONFIG = `[sqlfluff]
rules = core,AM03,AM05,AM08,CV01,CV02,CV06,CV08,CV12,LT13,LT14,LT15,ST01,ST02,ST04,ST05,ST06,ST07,ST09,ST10,ST11,ST12,RF02,RF04,RF05,RF06
dialect = ansi
max_line_length = 80
indent_unit = space
tab_space_size = 4
`;
// 新增:判断是否存在项目 .sqlfluff 配置
function hasProjectSqlfluffConfig(workspaceRoot: string): boolean {
// 检查 workspaceRoot 下是否存在 .sqlfluff 或 .sqlfluff.ini
// ...
}
// 修改后的 spawn 调用逻辑
function buildSqlfluffArgs(
filePath: string,
dialect: string,
workspaceRoot: string,
globalConfigPath?: string
): { args: string[]; tempConfigPath?: string } {
const args: string[] = ['lint', '--format', 'json'];
args.push('--dialect', dialect === 'plsql' ? 'postgres' : 'ansi');
// 三层配置优先级:全局 > 项目 > 内置
if (globalConfigPath) {
// 1. 全局配置:用户指定路径,完全替代内置配置
args.push('--config', globalConfigPath);
} else if (hasProjectSqlfluffConfig(workspaceRoot)) {
// 2. 项目配置:.sqlfluff 存在,让 SQLFluff 自动发现(不传 --config)
// 不需要额外参数
} else {
// 3. 内置配置(新增):写入临时 .sqlfluff 文件,传递精选规则集
const tempConfigPath = path.join(
os.tmpdir(),
`sqlfluff-builtin-${Date.now()}.cfg`
);
fs.writeFileSync(tempConfigPath, BUILTIN_SQLFLUFF_CONFIG);
args.push('--config', tempConfigPath);
return { args, tempConfigPath };
}
args.push(filePath);
return { args };
}
3.1.3 设计说明
为什么用临时配置文件而非 --rules 参数?
SQLFluff CLI 支持 --rules "core,AM03,..." 参数直接指定规则列表。但使用临时 .sqlfluff 配置文件更优:
- 支持 per-rule 配置:
--rules仅能指定规则列表,无法配置[sqlfluff:rules:CP01]等规则参数(如大小写偏好)。临时配置文件支持完整 INI 配置 - 与三层配置架构对齐:ESLint/Stylelint 的内置配置也是完整配置对象,临时配置文件使 SQLFluff 的内置层与之对称
- 可扩展性:未来需调整规则参数(如行长度、缩进)时,只需修改
BUILTIN_SQLFLUFF_CONFIG字符串
为什么用 dialect = ansi 而非动态方言?
BUILTIN_SQLFLUFF_CONFIG 中的 dialect = ansi 是默认值。实际执行时,buildSqlfluffArgs 已通过 --dialect 参数覆盖方言(plsql → postgres),--dialect 命令行参数优先于配置文件中的 dialect 设置。配置文件中保留 dialect = ansi 仅作为文档性默认值。
为什么内置配置不包含方言专用规则(OR01/PG01/TQ01-03)?
方言专用规则仅对特定方言生效。当前适配器方言映射为 sql → ansi、plsql → postgres,故内置配置仅覆盖通用规则。方言专用规则作为 P2 可选项,由用户在项目 .sqlfluff 中按实际方言追加。
3.2 修改 src/rules/static-rules.json:追加分级标记
3.2.1 修改内容
SQLFluff 的 75 条规则已全部收录在 static-rules.json 中。本次修改不新增规则条目(与 ESLint/Stylelint 不同——那两者是追加新规则),而是为每条规则追加 tier 分级字段,标记其在推荐体系中的归属。
// 修改前
{"id": "sql-lint/AL02", "description": "Column aliasing using explicit AS"}
// 修改后:追加 tier 字段
{"id": "sql-lint/AL02", "description": "Column aliasing using explicit AS", "tier": "P0"}
{"id": "sql-lint/AM03", "description": "ORDER BY clause direction ambiguity", "tier": "P1"}
{"id": "sql-lint/AL01", "description": "Implicit/explicit table aliasing", "tier": "P2"}
{"id": "sql-lint/AL07", "description": "Forbid table aliases in FROM/JOIN", "tier": "excluded"}
3.2.2 分级标记分配
| tier 值 | 含义 | 规则数 | 启用状态 |
|---|---|---|---|
P0 |
Core 核心规则 | 32 | 内置配置启用(rules = core) |
P1 |
精选非 Core 高价值规则 | 25 | 内置配置启用(显式追加) |
P2 |
可选规则(方言专用/团队偏好) | 11 | 内置配置不启用,按需追加 |
excluded |
不推荐规则(禁用/噪音/需配置) | 7 | 内置配置排除 |
| 合计 | — | 75 | — |
3.2.3 修改 linterVersion 字段
"linterVersion": {
"sql-lint": "4.2.2 (57 recommended)",
...
}
将原标记改为 "4.2.2 (57 recommended)",反映精选规则集数量。static-rules.json 中规则总数仍为 75 条(全部收录,仅分级不同)。
3.2.4 为什么必须同步更新 static-rules.json
static-rules.json 有两个用途:
- UI 展示:在设置面板中展示当前 linter 支持的规则清单,追加
tier后可展示分级标识 - 去重检测:自定义规则导入时,按 ID 匹配
static-rules.json中的规则。75 条规则已全部收录,去重检测范围不变,但分级标记使 UI 能区分"推荐/可选/排除"
与 ESLint/Stylelint 不同(那两者是因新增规则而必须更新去重数据),SQLFluff 的更新是分级标记追加而非规则新增,去重数据本身已完整。
3.3 不需要修改 package.json
SQLFluff 是通过 spawn('sqlfluff', ...) 调用的外部 CLI 工具,不是 npm 依赖。内置配置是纯字符串常量,不引入任何新依赖。这是 SQLFluff 适配器与 ESLint/Stylelint 适配器在依赖管理上的本质区别:
| 适配器 | 依赖管理 | 配置注入方式 |
|---|---|---|
| ESLint | npm 依赖(@eslint/js) |
Flat Config 数组对象 |
| Stylelint | npm 依赖(stylelint-config-recommended) |
配置对象展开 |
| SQLFluff | 外部 CLI(无 npm 依赖) | 临时 .sqlfluff 配置文件 / --config 参数 |
四、新增/排除规则分类详解
4.1 设计方向:从全到精
SQLFluff 增强与其他 linter 的根本差异:
| 维度 | ESLint/Stylelint | SQLFluff |
|---|---|---|
| 增强方向 | 从少到多(recommended → 更多规则) | 从全到精(all → 精选规则集) |
| 当前状态 | 启用少量规则(61/12 条) | 无差别全启用(75 条) |
| 增强动作 | 追加新规则 | 精选保留 + 排除噪音 |
| 规则数变化 | 61→92(+31)、12→68(+56) | 75→57(-18,排除噪音) |
| static-rules.json | 追加新规则条目 | 规则不变,追加分级标记 |
4.2 P0 Core 核心规则(32 条,全部保留)
Core 规则是 SQLFluff 官方标记的稳定、通用、非争议性规则。全部保留,通过 rules = core 关键字启用。
| 分组 | 规则代码 | 数量 |
|---|---|---|
| Aliasing | AL02, AL03, AL04, AL05, AL06, AL08, AL09, AL10 | 8 |
| Ambiguous | AM01, AM02, AM06 | 3 |
| Capitalisation | CP01, CP02, CP03, CP04, CP05 | 5 |
| Convention | CV03, CV04, CV05 | 3 |
| Jinja | JJ01 | 1 |
| Layout | LT01, LT02, LT05, LT06, LT07, LT08, LT10, LT11, LT12 | 9 |
| Structure | ST03, ST08 | 2 |
| References | RF01 | 1 |
| 合计 | — | 32 |
说明:RF01 虽标记
force_enable = False(对 BigQuery 等方言默认禁用),但它是 Core 规则,对 ansi/postgres 方言默认生效,故保留在 P0。
4.3 P1 精选非 Core 规则(25 条,从 43 条中精选)
从 43 条非 Core 规则中精选 25 条高价值规则,按问题类型分组:
4.3.1 歧义与连接(3 条)
| 规则 | 检测场景 | 误报评估 |
|---|---|---|
AM03 |
ORDER BY 混合 ASC/DESC 时方向不可预期 | 低,显式指定方向是最佳实践 |
AM05 |
JOIN 未明确连接类型(应为 INNER/LEFT 等) |
低,完全限定连接类型消除歧义 |
AM08 |
隐式 CROSS JOIN | 低,隐式交叉连接几乎都是意外 |
4.3.2 约定一致性(5 条)
| 规则 | 检测场景 | 误报评估 |
|---|---|---|
CV01 |
!= 与 <> 混用 |
零误报,统一运算符 |
CV02 |
使用 IFNULL/NVL 代替 COALESCE | 零误报,COALESCE 是标准 SQL |
CV06 |
语句缺少分号结尾 | 低,分号是语句终止符 |
CV08 |
使用 RIGHT JOIN | 低,LEFT JOIN 更易读 |
CV12 |
连接条件放在 WHERE 而非 ON | 低,ON 子句语义更清晰 |
4.3.3 结构优化(10 条,核心价值)
| 规则 | 检测场景 | 误报评估 |
|---|---|---|
ST01 |
CASE 中冗余的 ELSE NULL | 零误报 |
ST02 |
可简化的不必要 CASE | 低 |
ST04 |
ELSE 中嵌套 CASE 可展平 | 低 |
ST05 |
JOIN/FROM 含子查询(应提为 CTE) | 中,但 CTE 显著提升可维护性 |
ST06 |
SELECT 列顺序不规范 | 低 |
ST07 |
使用 USING 而非显式连接键 | 低 |
ST09 |
JOIN 列顺序不规范 | 低 |
ST10 |
WHERE 1=1 等冗余常量条件 | 零误报 |
ST11 |
JOIN 的表未被引用(死连接) | 零误报 |
ST12 |
连续分号 | 零误报 |
4.3.4 引用规范(4 条)
| 规则 | 检测场景 | 误报评估 |
|---|---|---|
RF02 |
多表查询时引用未限定表名 | 低,限定表名消除歧义 |
RF04 |
将关键字用作标识符 | 零误报 |
RF05 |
标识符含特殊字符 | 低 |
RF06 |
不必要的引号标识符 | 低 |
4.3.5 布局整洁(3 条)
| 规则 | 检测场景 | 误报评估 |
|---|---|---|
LT13 |
文件以空白开头 | 零误报 |
LT14 |
关键字换行位置不统一 | 低 |
LT15 |
连续空行过多 | 低 |
与排除的格式化规则的区别:LT13/LT14/LT15 关注文件结构和空行整洁,具有实际可读性价值;而被排除的 LT03/LT04/LT09 是纯风格偏好(操作符位置、逗号风格、SELECT 换行),属格式化范畴。
4.4 P2 可选规则(11 条,不纳入推荐基线)
4.4.1 方言专用规则(5 条)
| 规则 | 适用方言 | 说明 |
|---|---|---|
OR01 |
Oracle | 移除空批次 |
PG01 |
PostgreSQL | 避免过度锁(对 plsql→postgres 映射有意义) |
TQ01 |
T-SQL | 存储过程不用 SP_ 前缀 |
TQ02 |
T-SQL | 过程体用 BEGIN/END |
TQ03 |
T-SQL | 移除空批次 |
当前适配器仅映射
ansi/postgres两种方言,PG01 可按需启用,其余需用户切换方言。
4.4.2 团队偏好规则(6 条)
| 规则 | 检测场景 | 可选理由 |
|---|---|---|
AL01 |
表别名要求显式 AS | 与 AL02 对称,但表别名风格因团队而异 |
AM04 |
SELECT * 与其他列混合 | 检测结果列数不可预测,但部分场景 SELECT * 合理 |
AM07 |
集合查询子查询列数不同 | 检测集合查询错误,但场景较少 |
AM09 |
无 ORDER BY 时用 LIMIT/OFFSET | 检测非确定性结果,但部分场景可接受 |
CV07 |
顶层语句被括号包裹 | 多余括号,但部分方言需要 |
CV11 |
类型转换风格不一致 | CAST/::/CONVERT 风格统一,但方言偏好不同 |
4.5 排除规则(7 条,明确不推荐)
| 规则 | 排除分类 | 排除理由 |
|---|---|---|
AL07 |
默认禁用 | 禁止所有表别名过于激进,force_enable = False |
CV10 |
默认禁用 | 引号风格因方言而异,force_enable = False |
RF03 |
默认禁用 | 列引用限定一致性争议大,force_enable = False |
LT03 |
格式化噪音 | 操作符换行位置是纯风格偏好 |
LT04 |
格式化噪音 | 前导/尾随逗号是团队风格选择 |
LT09 |
格式化噪音 | SELECT 目标换行是格式偏好 |
CV09 |
需项目配置 | 需自定义禁止词列表,无通用默认 |
五、规则级别设计
5.1 级别设计原则:精选而非分级
SQLFluff 与 ESLint/Stylelint 的级别设计有本质区别:
| 维度 | ESLint/Stylelint | SQLFluff |
|---|---|---|
| 级别机制 | per-rule error/warn(ESLint)或 true(Stylelint) |
无 per-rule error/warn,仅启用/排除 |
| 级别设计核心 | 区分 error 与 warn | 精选规则集(从全到精) |
| 噪音控制方式 | 低价值规则设为 warn | 低价值规则直接排除 |
SQLFluff 不支持像 ESLint 那样的 per-rule error/warn 级别配置。因此,SQLFluff 适配器的"级别设计"通过规则集精选实现:将高价值规则纳入推荐基线,将噪音规则排除,从源头控制审查信噪比。
5.2 P0/P1/P2 分级与启用策略
| 分级 | 启用策略 | 规则数 | 严重程度定位 |
|---|---|---|---|
| P0 | rules = core 自动启用 |
32 | 高(核心稳定性问题) |
| P1 | 显式追加规则代码 | 25 | 高(歧义/结构/引用问题) |
| P2 | 不纳入推荐基线,按需追加 | 11 | 中(方言/偏好) |
| excluded | 不启用 | 7 | —(噪音/争议/需配置) |
5.3 适配器层面的严重级别映射
虽然 SQLFluff 无 per-rule severity,但适配器在解析 CLI 输出后,可基于 static-rules.json 中的 tier 字段映射到 VS Code 的 DiagnosticSeverity:
| tier | VS Code DiagnosticSeverity | 说明 |
|---|---|---|
| P0 | Error | 核心规则触发,几乎一定是问题 |
| P1 | Error | 高价值规则触发,强烈建议修复 |
| P2 | Warning(若启用) | 可选规则触发,建议但不强制 |
| excluded | — | 不触发(规则未启用) |
此映射为可选增强。当前适配器将所有 SQLFluff 诊断映射为统一严重级别,未来可按 tier 细化。
5.4 自动修复能力统计
| 分级 | 规则数 | 可自动修复 | 自动修复率 |
|---|---|---|---|
| P0 Core | 32 | 24 | 75% |
| P1 精选 | 25 | 19 | 76% |
| 推荐基线合计 | 57 | 43 | 75% |
| P2 可选 | 11 | 7 | 64% |
| excluded | 7 | 6 | 86% |
推荐基线 57 条规则中 43 条(75%)支持
sqlfluff fix自动修复。排除的 7 条规则中虽有 6 条可修复,但因属噪音/争议规则,修复后仍会引入风格争议,故排除。
六、兼容性分析
6.1 对现有用户代码的影响
从 rules = all(75 条)精简为 57 条精选规则集后,审查诊断数量将减少(而非增加,与 ESLint/Stylelint 相反):
| 影响程度 | 规则 | 说明 |
|---|---|---|
| 诊断减少 | LT03, LT04, LT09 | 排除格式化噪音,减少大量低价值诊断 |
| 诊断减少 | AL07, CV10, RF03 | 排除默认禁用规则(原本因 force_enable 不生效) |
| 诊断减少 | CV09 | 排除需项目配置的规则 |
| 诊断不变 | P0 + P1(57 条) | 推荐基线规则与 all 模式下行为一致 |
| 可能新增(可选) | P2 方言规则 | 用户按需启用后,对应方言新增诊断 |
核心收益:排除格式化噪音规则后,审查结果信噪比显著提升,真正的问题不再被格式化诊断淹没。
6.2 对配置优先级的影响
三层配置优先级不变:
全局配置(linters.sqlfluffConfigPath)
↓ 不存在
项目配置(.sqlfluff / .sqlfluff.ini)
↓ 不存在
内置配置(BUILTIN_SQLFLUFF_CONFIG,57 条精选) ← 新增
↓ (此前为 CLI 默认 rules = all)
新增内置配置层替代了原先的"CLI 默认"层,三层择一逻辑不变。
6.3 对去重功能的影响
static-rules.json 中 SQLFluff 规则仍为 75 条(全部收录),去重检测范围不变。新增的 tier 字段不影响去重匹配逻辑,仅用于 UI 分级展示。
6.4 对自动修复的影响
- 推荐基线 57 条规则中 43 条支持
sqlfluff fix - 适配器的自动修复调用不受影响(仍通过
sqlfluff fix命令) - 排除的格式化规则原本可修复,但修复属风格偏好,排除后用户可自行用格式化工具处理
6.5 方言兼容性
| 方言映射 | 内置配置适用性 | 方言专用规则 |
|---|---|---|
sql → ansi |
完全适用(57 条均为通用规则) | 无 |
plsql → postgres |
完全适用 | PG01 可选启用 |
七、与 ESLint/Stylelint/ts-eslint 适配器的架构对比
7.1 架构对比总览
| 维度 | ESLint 适配器 | Stylelint 适配器 | SQLFluff 适配器 |
|---|---|---|---|
| Linter 类型 | npm 库(进程内调用) | npm 库(进程内调用) | 外部 CLI(spawn 调用) |
| 增强方向 | 从少到多(61→92) | 从少到多(12→68) | 从全到精(75→57) |
| 官方配置基线 | @eslint/js recommended |
stylelint-config-recommended |
rules = core 关键字 |
| 额外规则来源 | eslint 内置规则 |
stylelint 内置规则 |
SQLFluff 内置规则(CLI) |
| 配置注入方式 | Flat Config 数组追加 | 配置对象展开 | 临时 .sqlfluff 文件 + --config |
| 级别支持 | error/warn |
true(仅 error) |
无 per-rule 级别(启用/排除) |
| 噪音控制 | 低价值规则设为 warn | 全部 true | 低价值规则直接排除 |
| npm 依赖变更 | 新增 @eslint/js |
新增 stylelint-config-recommended |
无(外部 CLI) |
| static-rules.json 变更 | 追加 31 条新规则 | 追加 27 条新规则 | 规则不变,追加 tier 标记 |
| 配置优先级 | 全局 > 项目 > 内置 | 全局 > 项目 > 内置 | 全局 > 项目 > 内置 |
| 规则 ID 格式 | eslint:{ruleId} |
stylelint:{ruleName} |
sql-lint:{规则代码} |
7.2 关键差异分析
差异一:增强方向相反
- ESLint/Stylelint:当前启用规则过少(31%/8.5%),增强方向是追加规则提升覆盖率
- SQLFluff:当前无差别全启用(100%),增强方向是精选规则提升信噪比
这决定了 SQLFluff 的增强不是"做加法"而是"做减法"——从 75 条精简为 57 条,排除 18 条低价值/噪音规则。
差异二:配置注入方式不同
- ESLint/Stylelint:npm 库,配置为 JS 对象/数组,进程内直接传入
- SQLFluff:外部 CLI,配置需写入临时文件并通过
--config参数传递
SQLFluff 适配器需额外处理临时配置文件的生命周期(创建、传递、清理)。
差异三:无 per-rule 严重级别
- ESLint 支持
error/warn两级,Stylelint 支持true/null - SQLFluff 仅支持启用/排除,无 per-rule 严重级别
因此 SQLFluff 的"级别设计"通过规则集精选实现,而非 error/warn 分配。低价值规则直接排除,而非降级为 warning。
差异四:static-rules.json 变更性质不同
- ESLint/Stylelint:新增规则条目(去重数据扩展)
- SQLFluff:规则条目不变(75 条已全收录),追加
tier分级标记
7.3 架构一致性
尽管实现方式不同,三个适配器在设计理念上保持一致:
| 设计理念 | ESLint | Stylelint | SQLFluff |
|---|---|---|---|
| 官方配置作为基线 | recommended | recommended | core |
| 精选额外规则 | extraRules 对象 | extraRules 对象 | rules 显式追加 |
| 三层配置优先级 | 全局 > 项目 > 内置 | 全局 > 项目 > 内置 | 全局 > 项目 > 内置 |
| 同步更新 static-rules.json | 是(追加规则) | 是(追加规则) | 是(追加 tier) |
| 规则 ID 前缀不变 | eslint: |
stylelint: |
sql-lint: |
八、实施步骤
步骤 1:修改 src/adapters/sql-lint.ts
- 在文件顶部添加
BUILTIN_SQLFLUFF_CONFIG常量(精选 57 条规则的 INI 配置字符串) - 添加
hasProjectSqlfluffConfig()辅助函数,检测项目.sqlfluff配置文件 - 修改
buildSqlfluffArgs()(或等效的参数构建逻辑),实现三层配置优先级:- 全局配置存在 → 传递
--config <全局路径> - 项目配置存在 → 不传
--config,让 SQLFluff 自动发现 - 均不存在 → 写入临时配置文件,传递
--config <临时路径>
- 全局配置存在 → 传递
- 在 spawn 完成后(或 finally 块中)清理临时配置文件
步骤 2:修改 src/rules/static-rules.json
- 为 75 条 SQLFluff 规则条目追加
tier字段(P0/P1/P2/excluded) - 更新
linterVersion.sql-lint为"4.2.2 (57 recommended)"
步骤 3:验证
- 确认无项目
.sqlfluff时,临时配置文件正确生成并被 SQLFluff 使用 - 确认有项目
.sqlfluff时,内置配置不生效(项目配置优先) - 确认全局配置路径存在时,内置配置不生效(全局配置优先)
- 确认临时配置文件在 spawn 完成后被清理
- 检查
static-rules.json中 75 条规则均有tier字段
九、测试要点
9.1 单元测试
| 测试项 | 验证内容 |
|---|---|
BUILTIN_SQLFLUFF_CONFIG 内容 |
包含 rules = core 及 25 条 P1 规则代码 |
BUILTIN_SQLFLUFF_CONFIG 规则数 |
core(32)+ 显式追加(25)= 57 条 |
| 临时配置文件生成 | 无项目配置时正确写入临时文件 |
| 临时配置文件清理 | spawn 完成后临时文件被删除 |
| 三层优先级 | 全局 > 项目 > 内置,择一逻辑正确 |
9.2 集成测试
| 测试项 | 验证内容 |
|---|---|
| 无配置时使用精选规则集 | 诊断结果仅包含 57 条推荐规则,不包含 LT03/LT04/LT09 |
项目 .sqlfluff 存在时使用项目配置 |
诊断结果遵循项目配置,内置配置不生效 |
| 全局配置存在时使用全局配置 | 诊断结果遵循全局配置,内置配置不生效 |
WHERE 1=1 触发 ST10 |
诊断结果包含 sql-lint:ST10 |
CASE ... ELSE NULL END 触发 ST01 |
诊断结果包含 sql-lint:ST01 |
未使用的 CTE 触发 ST03 |
诊断结果包含 sql-lint:ST03 |
= NULL 触发 CV05 |
诊断结果包含 sql-lint:CV05 |
| 格式化噪音规则不触发 | LT03/LT04/LT09 不产生诊断 |
9.3 去重测试
| 测试项 | 验证内容 |
|---|---|
导入 ST05 自定义规则 |
提示与已有规则重复(75 条已收录) |
导入 CV05 自定义规则 |
提示与已有规则重复 |
tier 字段不影响去重 |
去重匹配逻辑仅按 ID,与 tier 无关 |
9.4 自动修复测试
| 测试项 | 验证内容 |
|---|---|
sqlfluff fix 修复 ST01 |
ELSE NULL 被移除 |
sqlfluff fix 修复 CP01 |
关键字大小写统一 |
sqlfluff fix 修复 CV05 |
= NULL 改为 IS NULL |
| 排除规则不被修复 | LT03/LT04/LT09 不触发修复 |
十、风险评估
10.1 主要风险
| 风险 | 级别 | 缓解措施 |
|---|---|---|
| 临时配置文件未清理导致残留 | 中 | 在 finally 块中确保清理,使用 os.tmpdir() 避免污染工作区 |
用户依赖 rules = all 的全量诊断 |
中 | 用户可通过项目 .sqlfluff 设置 rules = all 恢复原行为 |
| 精选规则集遗漏用户需要的高价值规则 | 低 | P2 可选规则可按需追加,用户可自行在项目配置中启用 |
--config 参数与 --dialect 参数冲突 |
低 | --dialect 命令行参数优先级高于配置文件,已验证不冲突 |
| SQLFluff 版本升级导致规则代码变化 | 低 | 锁定 SQLFluff 4.2.2,规则代码在 4.x 内稳定 |
10.2 与 ESLint/Stylelint 的风险差异
| 风险类型 | ESLint/Stylelint | SQLFluff |
|---|---|---|
| 诊断数量变化 | 增加(新增规则) | 减少(排除噪音) |
| 用户感知 | 可能新增大量诊断 | 诊断减少,信噪比提升 |
| 回滚复杂度 | 需移除新增规则和依赖 | 仅需移除内置配置注入,恢复 CLI 默认 |
SQLFluff 的增强风险显著低于 ESLint/Stylelint:诊断数量减少而非增加,不会引入用户未曾见过的诊断,仅是减少噪音。
10.3 回滚方案
如果精选规则集导致问题,回滚步骤:
- 从
buildSqlfluffArgs()中移除内置配置注入逻辑,恢复"无配置时使用 CLI 默认(rules = all)" - 删除
BUILTIN_SQLFLUFF_CONFIG常量 static-rules.json中的tier字段可保留(不影响功能,仅用于 UI 展示)- 恢复
linterVersion.sql-lint为"4.2.2 (75 rules, all)"
回滚仅需修改适配器代码,无需修改依赖(因本就无 npm 依赖变更)。
十一、附录
11.1 规则来源参考
- SQLFluff 官方规则文档:https://docs.sqlfluff.com/en/stable/reference/rules.html
- SQLFluff GitHub 源码:https://github.com/sqlfluff/sqlfluff/tree/4.2.2/src/sqlfluff/rules
- 推荐规则分析文件:
/workspace/sqlfluff-recommended-rules.md - 完整规则清单:
/workspace/sqlfluff-rules.md - 适配器配置分析:
/workspace/custom-rule-analysis.md
11.2 规则数量统计
| 分类 | 数量 | tier | 启用状态 |
|---|---|---|---|
| P0 Core 核心规则 | 32 | P0 | 内置配置启用 |
| P1 精选非 Core | 25 | P1 | 内置配置启用 |
| P2 方言专用 | 5 | P2 | 按需启用 |
| P2 团队偏好 | 6 | P2 | 按需启用 |
| excluded 默认禁用 | 3 | excluded | 排除 |
| excluded 格式化噪音 | 3 | excluded | 排除 |
| excluded 需项目配置 | 1 | excluded | 排除 |
| 合计 | 75 | — | 推荐基线 57 条 |
11.3 内置配置模板(完整)
[sqlfluff]
# 从全到精:rules = all(75 条)→ 精选规则集(57 条)
# P0(32 条 Core)+ P1(25 条精选非 Core)
rules = core,AM03,AM05,AM08,CV01,CV02,CV06,CV08,CV12,LT13,LT14,LT15,ST01,ST02,ST04,ST05,ST06,ST07,ST09,ST10,ST11,ST12,RF02,RF04,RF05,RF06
dialect = ansi
max_line_length = 80
indent_unit = space
tab_space_size = 4
11.4 P1 精选规则完整列表(25 条)
| # | 规则代码 | 规则名 | 分组 | 可修复 |
|---|---|---|---|---|
| 1 | AM03 |
ambiguous.order_by |
Ambiguous | Fix |
| 2 | AM05 |
ambiguous.join |
Ambiguous | Fix |
| 3 | AM08 |
ambiguous.join_condition |
Ambiguous | Fix |
| 4 | CV01 |
convention.not_equal |
Convention | Fix |
| 5 | CV02 |
convention.coalesce |
Convention | Fix |
| 6 | CV06 |
convention.terminator |
Convention | Fix |
| 7 | CV08 |
convention.left_join |
Convention | — |
| 8 | CV12 |
convention.join_condition |
Convention | Fix |
| 9 | LT13 |
layout.start_of_file |
Layout | Fix |
| 10 | LT14 |
layout.keyword_newline |
Layout | Fix |
| 11 | LT15 |
layout.newlines |
Layout | Fix |
| 12 | ST01 |
structure.else_null |
Structure | Fix |
| 13 | ST02 |
structure.simple_case |
Structure | Fix |
| 14 | ST04 |
structure.nested_case |
Structure | Fix |
| 15 | ST05 |
structure.subquery |
Structure | Fix |
| 16 | ST06 |
structure.column_order |
Structure | Fix |
| 17 | ST07 |
structure.using |
Structure | Fix |
| 18 | ST09 |
structure.join_condition_order |
Structure | Fix |
| 19 | ST10 |
structure.constant_expression |
Structure | — |
| 20 | ST11 |
structure.unused_join |
Structure | — |
| 21 | ST12 |
structure.consecutive_semicolons |
Structure | Fix |
| 22 | RF02 |
references.qualification |
References | — |
| 23 | RF04 |
references.keywords |
References | — |
| 24 | RF05 |
references.special_chars |
References | — |
| 25 | RF06 |
references.quoting |
References | Fix |
11.5 排除规则完整列表(7 条)
| # | 规则代码 | 规则名 | 排除分类 | 原标记 |
|---|---|---|---|---|
| 1 | AL07 |
aliasing.forbid |
默认禁用 | Fix / 禁用 |
| 2 | CV10 |
convention.quoted_literals |
默认禁用 | Fix / 禁用 |
| 3 | RF03 |
references.consistent |
默认禁用 | Fix / 禁用 |
| 4 | LT03 |
layout.operators |
格式化噪音 | Fix |
| 5 | LT04 |
layout.commas |
格式化噪音 | Fix |
| 6 | LT09 |
layout.select_targets |
格式化噪音 | Fix |
| 7 | CV09 |
convention.blocked_words |
需项目配置 | — |
11.6 与其他适配器增强对比总结
| 对比项 | ESLint | Stylelint | SQLFluff |
|---|---|---|---|
| 增强方向 | 从少到多 | 从少到多 | 从全到精 |
| 规则数变化 | 61 → 92(+31) | 12 → 68(+56) | 75 → 57(-18) |
| 增强动作 | 追加规则 | 追加规则 + 引入配置包 | 精选保留 + 排除噪音 |
| 诊断影响 | 增加 | 增加 | 减少(信噪比提升) |
| npm 依赖 | 新增 @eslint/js |
新增 stylelint-config-recommended |
无 |
| 配置注入 | Flat Config 对象 | 配置对象展开 | 临时配置文件 |
| static-rules.json | 追加新规则 | 追加新规则 | 追加 tier 标记 |
| 风险等级 | 中(诊断增加) | 中(诊断增加) | 低(诊断减少) |