开发工具代码质量CLI【免费下载链接】vale:pencil: A markup-aware linter for prose built with speed and extensibility in mind.项目地址https://gitcode.com/gh_mirrors/va/vale点击查看免费下载导读本文围绕仓库 testdata/fixtures/filters/test.md 这份 Markdown 测试样例深入讲解 Vale 的--filter标志规则过滤器如何以表达式expr形式对检查规则进行二次筛选。你将掌握过滤器表达式的三种写法文件路径、StylesPath 资源、内联字符串、可用的规则字段.Name、.Level、.Scope、.Extends等与优先级语义并学会像 e2e 测试那样组合表达式实现只保留 error 级告警只看 heading 范围排除指定规则等实战场景。全文以测试样例为事实基线辅以 filter.go、definition.go 等源码佐证确保每一条结论都可在仓库中复现验证。从test.md看这份样例文件的定位文件内容全景test.md 全文仅 13 行是一份典型的过滤器靶场文档它刻意混排了多种会触发不同检查规则的文本形态# intro Nginx is a web server which can also be used as a reverse proxy, load balancer, mail proxy and HTTP cache. HTTPie is is a command line HTTP client. Its goal is to make CLI interaction with web services as human-friendly as possible. That doesn’t work. That doesnt work. That doesn‘t work. abdominocentesis is a word.这份文件被 testdata/e2e/cli-filter.yaml 引用为dir: fixtures/filters下的唯一测试输入其设计意图是让不同过滤器表达式作用于同一份文档时产生互不相同但完全可预期的告警集合。各行的探测目标如下行内容会命中的检查说明第 1 行# introdemo.Cap标题大小写、demo.HeadingStartsWithCapital标题首字母大写demo.Cap是level: errordemo.HeadingStartsWithCapital是level: suggestion恰好覆盖两个告警级别第 5 行HTTPie is is a ...Vale.Repetition内置重复词规则level: errormessage为%s is repeated!第 7/9/11 行三种doesnt的引号变体直引号、弯引号 U2019、其他弯引号视配置而定拼写/术语类规则用于验证拼写类过滤filters字段见 demo/Filters.yml第 13 行abdominocentesis is a word.词汇表vocab相关用于验证accept.txt/reject.txt的取舍效果从源码结构看这份文件的编排显然是为了让--filter测试用例能以最少的文本覆盖最多的规则维度级别error/suggestion、范围heading/text、扩展类型capitalization/existence/repetition三大过滤维度各有一个明确的探针。样例对应的配置环境测试样例通过 testdata/fixtures/styles/demo/_vale 提供运行配置其中关键设置为StylesPath ../../../styles MinAlertLevel suggestion [*] BasedOnStyles demo [*.md] demo.Reading YES demo.Spellcheck YES demo.Filters YES demo.Smart YES demo.ScopedHeading YES注意demo.Cap NO出现在[*]段中——意味着demo.Cap规则默认不运行而 demo/Cap.yml 声明它的level: error。这就是 cli-filter.yaml 中--filtermin.expr用例依然能输出demo.Cap告警的原因过滤器表达式中出现了.Level字段filter.go 会据此下调全局最低告警级别并显式启用相关规则。这一点我们将在后文源码分析中展开。--filter的三种表达式形态命令行定义--filter标志在 cmd/vale/flag.go 中注册pflag.StringVar(Flags.Filter, filter, , An expression to filter rules by.)其值会通过 internal/check/filter.go 中的filter(mgr *Manager)函数解析解析顺序stringOrPath判定分为三种形态表达式文件路径若该字符串是一个真实存在的文件路径则直接读取文件内容作为表达式。例如--filtermin.expr .。StylesPath 下的资源若该字符串能通过core.FindAsset在StylesPath或 Vale 样式目录中找到对应文件则读取该文件。例如--filtermin.expr会命中 testdata/styles/config/filters/min.expr。内联表达式字符串若以上都不满足则把该字符串本身当作表达式。例如--filter.Extends in [existence]。if system.FileExists(stringOrPath) { // Case 1: 表达式文件 } else if found : core.FindAsset(mgr.Config, stringOrPath); found ! { // Case 2: StylesPath 下的 .expr 资源 } else { // Case 3: 内联表达式 }三种形态可以互换cli-filter.yaml 里就同时演示了文件形态min.expr、scope.expr、levels.expr、extends.expr与内联形态--filter.Extends in [existence]、--filter.Level in [error, suggestion] and .Name ! demo.Cap且二者输出完全一致。表达式引擎与求值方式filter()的核心逻辑是把用户表达式包装进一个名为Rules的集合过滤调用中internal/check/filter.goenv : FilterEnv{} for _, rule : range mgr.rules { env.Rules append(env.Rules, rule.Fields()) } code : fmt.Sprintf(filter(Rules, {%s}), filter) program, err : expr.Compile(code, expr.Env(env))也就是说用户只需要写一个谓词闭包体例如.Level in [error]Vale 会自动把它放进filter(Rules, { ... })的上下文里由github.com/expr-lang/expr编译执行。FilterEnv的定义见 internal/check/definition.go它只有一个字段type FilterEnv struct { Rules []Definition }Rules中每个元素是一个Definition其可用字段internal/check/definition.go就是过滤器表达式能引用的全部属性字段类型含义来源/示例.Namestring规则全名如demo.Cap、Vale.Repetition规则 YAML 的文件名.Levelstring告警级别suggestion/warning/error规则 YAML 的level.Scope[]string规则作用范围如[heading]、[heading.h1]规则 YAML 的scope.Extendsstring扩展类型capitalization、existence、repetition等规则 YAML 的extends.Messagestring告警消息模板规则 YAML 的message.Descriptionstring规则描述规则 YAML 的description.Linkstring规则关联文档链接规则 YAML 的link.Actioncore.Action可执行动作如替换建议action字段.Extends的合法取值集合在 internal/check/definition.go 的extensionPoints中列出包括capitalization、conditional、consistency、existence、occurrence、repetition、substitution、readability、spelling、sequence、metric、script共 12 种。这与 testdata/styles/demo 目录下各规则 YAML 的extends字段一一对应。四个表达式文件逐个拆解四个.expr文件位于 testdata/styles/config/filters它们是官方 e2e 测试挑选的代表性过滤谓词恰好覆盖了.Level、.Scope、.Name、.Extends四类字段的用法。min.expr按告警级别收紧.Level in [error]作用于 test.md 的期望输出cli-filter.yaml为test.md:1:3:demo.Cap:intro should be in title case (Intro). test.md:5:8:Vale.Repetition:is is repeated!即只保留error级告警demo.Cap标题大小写错误与Vale.Repetitionis重复。suggestion级的demo.HeadingStartsWithCapital被过滤掉。exit: 1表示存在告警。scope.expr按作用范围收窄heading in .Scope期望输出只剩demo.Cap一条test.md:1:3:demo.Cap:intro should be in title case (Intro).因为只有demo.Capdemo/Cap.yml 中scope: heading与demo.HeadingStartsWithCapitalscope: heading.h1作用于标题但后者是suggestion级而Vale.Repetition的scope: text不含heading故被排除。注意heading in .Scope是子串包含语义——heading.h1也满足heading in这从 selection.go 中每个标题被包装进带in.id标识的 scope的实现可以印证。levels.expr多级别 排除特定规则.Level in [error, suggestion] and .Name ! demo.Cap期望输出为test.md:1:3:demo.HeadingStartsWithCapital:intro should be capitalized test.md:5:8:Vale.Repetition:is is repeated!这里用布尔逻辑演示了组合谓词先取error与suggestion两个级别再通过.Name ! demo.Cap剔除大小写规则最终留下标题首字母建议与重复词错误。extends.expr按扩展类型筛选.Extends in [existence]期望输出为test.md:1:3:demo.HeadingStartsWithCapital:intro should be capitalized只保留extends: existence的规则demo/HeadingStartsWithCapital.ymlcapitalization与repetition类规则全部被过滤。exit: 0表示命令成功执行即便仍有 suggestion 级输出。内联形态等价演示cli-filter.yaml 还验证了两个内联写法与文件写法结果等价--filter.Extends in [existence] --filter.Level in [error, suggestion] and .Name ! demo.Cap注意内联时使用单引号[existence]即可因为整个表达式作为 CLI 参数传递而.expr文件里用双引号[error]。expr 语言两者均可实际风格取决于 Shell 转义需求。源码层面的过滤语义为什么结果永远是子集过滤发生在规则装载阶段filter(mgr)在规则加载AddRuleFromFile之后时执行返回的filteredmap 会替换mgr.rules从而决定后续shouldRun对哪些规则放行internal/lint/lint.go。它的注释明确点出两条关键语义internal/check/filter.go过滤结果永远只能是完整结果的一个子集——因为规则集合本身就是基于.vale.ini加载的过滤器只是在这一集合上再做一次筛选。也就是说--filter不能启用ini 中未加载的规则只能在已装载规则中做减法。例如demo.Cap虽然在[*]段被 NO关闭但它仍被加载进mgr.rules关闭只是运行时开关所以过滤器可以找回它而一个BasedOnStyles之外、完全没有被引入的样式规则则无法通过--filter凭空启用。.Level的特殊副作用动态下调最低告警级别过滤器命中.Level字段时有一个隐藏行为internal/check/filter.goif strings.Contains(code, .Level) { lvl : core.LevelToInt[rule.Level] if lvl mgr.Config.MinAlertLevel { mgr.Config.MinAlertLevel lvl } }级别映射定义在 internal/core/alert.govar LevelToInt map[string]int{ suggestion: 0, warning: 1, error: 2, }MinAlertLevel的默认装载逻辑见 internal/core/ini.go接受suggestion/warning/error。这正是min.expr用例中demo.Caperror与Vale.Repetitionerror能输出、而suggestion级规则被过滤掉的底层原因过滤器基于MinAlertLevel做二次裁剪.Level谓词会把阈值动态压到表达式允许的最低级别。这也解释了为何extends.expr不含.Level的用例exit: 0——它不触碰级别阈值默认MinAlertLevel suggestion下demo.HeadingStartsWithCapital本就在输出范围内。RuleForAlert过滤后规则名的回退解析过滤结果 map 的键需要经过mgr.RuleForAlert(rule.Name)规范化filter.go。该函数internal/check/manager.go按最长已知前缀把告警名映射回其定义规则——这对consistency这类把匹配词拼进告警名的规则尤为重要其单测见 internal/check/manager_test.go。从测试用例反推实战场景以 cli-filter.yaml 的用例为蓝本可归纳出四类可直接复用的实战组合需求表达式效果只关注硬错误--filter.Level in [error]屏蔽所有 suggestion/warningCI 友好只看标题问题--filterheading in .Scope输出收敛到标题相关检查多级别 豁免个别规则--filter.Level in [error,suggestion] and .Name ! demo.Cap组合布尔逻辑精细控制只跑某类扩展点--filter.Extends in [existence,substitution]按规则类型批量筛选与--minAlertLevel的区别--filter与--minAlertLevelcmd/vale/flag.go不要混淆前者是规则维度的取舍决定哪些规则参与后者是告警维度的阈值决定哪些级别展示。二者叠加时--filter中的.Level会下调MinAlertLevel见上文副作用而--minAlertLevel则在整个过滤链路末端再做一次展示裁剪internal/core/source.go 中 CLI 传入的AlertLevel会覆盖 ini 配置。如何在本仓库中复现验证推荐按以下步骤在仓库根目录复现 e2e 行为对应 internal/e2e/e2e_test.go 的测试框架# 1) 使用表达式文件等价于 cli-filter.yaml 的 min-alert-level 用例 vale --configtestdata/fixtures/styles/demo/_vale \ --filtermin.expr testdata/fixtures/filters # 2) 使用内联表达式 vale --configtestdata/fixtures/styles/demo/_vale \ --filter.Extends in [existence] testdata/fixtures/filters # 3) 运行 e2e 测试套件中的 cli/filter 用例 go test ./internal/e2e/ -run TestCLI -v也可以把表达式文件临时放置到StylesPath下的config/filters/目录如 testdata/styles/config/filters再用--filter文件名直接引用。四种.expr文件均可作为自定义过滤器的起点模板。小结test.md虽是一份仅 13 行的测试样例却是理解 Vale--filter语义的最佳窗口它用精心挑选的文本把capitalization、existence、repetition三类规则、error/suggestion 两种级别、heading/text 两个 scope 全部覆盖而 cli-filter.yaml 的五个用例则为每个过滤维度提供了可复现的期望输出。结合 filter.go 的实现可以确认过滤发生在规则装载阶段、结果恒为子集、.Level谓词会动态压低告警阈值这三条语义决定了任何--filter表达式设计的边界。掌握这些后你就能用一行表达式把 Vale 的输出精确裁剪到团队真正关心的检查维度为 CI 流水线或编辑器插件提供稳定、可预期的 lint 信号。赞分享开发工具代码质量CLI【免费下载链接】vale:pencil: A markup-aware linter for prose built with speed and extensibility in mind.项目地址https://gitcode.com/gh_mirrors/va/vale点击查看免费下载相关推荐Vale Markdown 解析与 Lint 实战以 testdata/fixtures/formats/test.md 为基准的 markup-aware 散文检查剖析Vale Markdown 解析与 Lint 实战以 testdata/fixtures/formats/test.md 为基准的 markup aware开发工具代码质量CLIFluvio regex-filter SmartModule 实战用正则表达式过滤流式数据Fluvio regex filter SmartModule 实战用正则表达式过滤流式数据 导读 本文围绕 Fluvio 仓库中 smartmodule/r流处理消息队列后端Apache RocketMQ 消息过滤实战从 Tag 过滤到 SQL92 表达式过滤Filter Example 详解Apache RocketMQ 消息过滤实战从 Tag 过滤到 SQL92 表达式过滤Filter Example 详解 本指南基于 docs/en/Ex消息队列后端微服务流处理上一篇komorebi clear-workspace-rules 命令详解按显示器与工作区索引批量清除应用关联规则下一篇electron-vue 全局配置完全指南config.js、webpack 与构建选项深度解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?