Skip to content

Commit 072ac4f

Browse files
committed
fix: don't treat substitution replacements as regexes (#1038)
Signed-off-by: Joseph Kato <joseph@jdkato.io>
1 parent bf175c0 commit 072ac4f

6 files changed

Lines changed: 33 additions & 1 deletion

File tree

internal/check/definition.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,9 @@ func makeRegexp(
325325
return regex
326326
}
327327

328+
// matchToken reports whether `observed` already conforms to `expected`. When
329+
// `expected` is a plain phrase it's an exact comparison; otherwise `expected`
330+
// is treated as a regex (e.g., a vocab term like `[pP]y.*\b`).
328331
func matchToken(expected, observed string, ignorecase bool) bool {
329332
p := expected
330333
if ignorecase {

internal/check/substitution.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,23 @@ func (s Substitution) Run(blk nlp.Block, _ *core.File, cfg *core.Config) ([]core
119119
return alerts, msgErr
120120
}
121121

122-
same := matchToken(expected, observed, false)
122+
// Determine whether `observed` is already in an acceptable
123+
// form (a no-op suggestion). For a `replace` action the swap
124+
// value is literal replacement text -- one or more `|`-separated
125+
// suggestions (the same split used to build `action.Params`
126+
// below) -- so we compare each option literally. Otherwise an
127+
// option like `...` would be read as a regex matching any three
128+
// characters (e.g. `,,,`), suppressing a real finding (#1038).
129+
//
130+
// For non-`replace` rules the value may instead be a regex that
131+
// describes the acceptable forms (e.g. a vocab term `[pP]y.*\b`,
132+
// or a `LookAround`-style pattern), which we still match as one.
133+
var same bool
134+
if s.Fields().Action.Name == "replace" {
135+
same = core.StringInSlice(observed, getOptions(expected))
136+
} else {
137+
same = matchToken(expected, observed, false)
138+
}
123139
if !same && !isMatch(s.exceptRe, observed) {
124140
action := s.Fields().Action
125141
if action.Name == "replace" && len(action.Params) == 0 {

testdata/features/checks.feature

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ Feature: Checks
110110
test.md:25:1:Bugs.SameCase:Use 'MPL 2.0' instead of 'mpl 2.0'
111111
test.md:27:1:Bugs.SameCase:Use 'MPL 2.0' instead of 'MPL2.0'
112112
test.md:31:15:Bugs.EmptyReplace:Use instead of 'obvious'.
113+
test.md:33:4:Bugs.Commas:Use a single comma or an ellipsis, not multiple consecutive commas.
114+
test.md:33:23:Bugs.Commas:Use a single comma or an ellipsis, not multiple consecutive commas.
113115
test2.md:3:1:demo.CapSub:Use 'Change to the `/etc` directory' instead of 'Change into the `/etc` directory'.
114116
test2.md:7:1:demo.CapSub:Use 'Change to the `/home/user` directory' instead of 'Change into the `/home/user` directory'.
115117
test2.md:9:1:demo.CapSub:Use 'Change to the `/etc/X11` directory' instead of 'Change into the `/etc/X11` directory'.

testdata/fixtures/checks/Substitution/.vale.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Bugs.KeepCase = YES
1010
Bugs.TermCase = YES
1111
Bugs.SameCase = YES
1212
Bugs.EmptyReplace = YES
13+
Bugs.Commas = YES
1314

1415
[test2.md]
1516
demo.CapSub = YES

testdata/fixtures/checks/Substitution/test.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,5 @@ MPL2.0
2929
MPL 2.0
3030

3131
The answer is obvious.
32+
33+
Two,, commas and three,,, commas.

testdata/styles/Bugs/Commas.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
extends: substitution
2+
message: "Use a single comma or an ellipsis, not multiple consecutive commas."
3+
level: error
4+
nonword: true
5+
action:
6+
name: replace
7+
swap:
8+
',{2,}': ',|...'

0 commit comments

Comments
 (0)