Skip to content

Commit

Permalink
feat: add capture group support to substitution
Browse files Browse the repository at this point in the history
  • Loading branch information
jdkato committed Jul 20, 2024
1 parent 906c544 commit 7f2c55e
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 7 deletions.
29 changes: 23 additions & 6 deletions internal/check/substitution.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Substitution struct {
Vocab bool
Capitalize bool

msgMap map[string]string
msgMap []string
// Deprecated
POS string
}
Expand Down Expand Up @@ -64,17 +64,16 @@ func NewSubstitution(cfg *core.Config, generic baseCheck, path string) (Substitu

replacements := []string{}
for _, regexstr := range terms {
rule.msgMap = append(rule.msgMap, regexstr)
replacement := rule.Swap[regexstr]

opens := strings.Count(regexstr, "(")
if opens != strings.Count(regexstr, "(?")+strings.Count(regexstr, `\(`) {
old := regexstr
// We have a capture group, so we need to make it non-capturing.
regexstr, err = convertCaptureGroups(regexstr)
if err != nil {
return rule, core.NewE201FromTarget(err.Error(), regexstr, path)
}
rule.msgMap[regexstr] = old
}
tokens += `(` + regexstr + `)|`
replacements = append(replacements, replacement)
Expand Down Expand Up @@ -114,10 +113,11 @@ func (s Substitution) Run(blk nlp.Block, _ *core.File) ([]core.Alert, error) {
return alerts, err
}

// Based on the current capture group (`idx`), we can determine
// the associated replacement string by using the `repl` slice:
expected := s.repl[(idx/2)-1]
observed := strings.TrimSpace(converted)
expected, msgErr := subMsg(s, (idx/2)-1, observed)
if msgErr != nil {
return alerts, msgErr
}

same := matchToken(expected, observed, s.Ignorecase)
if !same && !isMatch(s.exceptRe, observed) {
Expand Down Expand Up @@ -180,3 +180,20 @@ func convertCaptureGroups(msg string) (string, error) {
captureOpen := regexp2.MustCompileStd(`(?<!\\)\((?!\?)`)
return captureOpen.Replace(msg, "(?:", -1, -1)
}

func subMsg(s Substitution, index int, observed string) (string, error) {
// Based on the current capture group (`idx`), we can determine
// the associated replacement string by using the `repl` slice:
expected := s.repl[index]
if s.Capitalize && observed == core.CapFirst(observed) {
expected = core.CapFirst(expected)
}

msg := s.msgMap[index]
if s.Ignorecase {
msg = `(?i)` + msg
}

msgRe := regexp2.MustCompileStd(msg)
return msgRe.Replace(observed, expected, -1, -1)
}
3 changes: 3 additions & 0 deletions testdata/features/checks.feature
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ Feature: Checks
test.md:21:1:Bugs.TermCase:Use 'JavaScript' rather than Javascript.
test.md:21:53:Bugs.TermCase:Use 'JavaScript' rather than javascript.
test.md:23:1:Bugs.TermCase:Use 'iOS' rather than IOS.
test2.md:3:1:demo.CapSub:Use 'Change to the `/etc` directory' instead of 'Change into the `/etc` directory'.
test2.md:7:1:demo.CapSub:Use 'Change to the `/home/user` directory' instead of 'Change into the `/home/user` directory'.
test2.md:9:1:demo.CapSub:Use 'Change to the `/etc/X11` directory' instead of 'Change into the `/etc/X11` directory'.
"""

Scenario: Sequence
Expand Down
5 changes: 4 additions & 1 deletion testdata/fixtures/checks/Substitution/.vale.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ StylesPath = ../../../styles/

Vocab = Cap

[*]
[test.md]
Bugs.Newline = YES
Bugs.URLCtx = YES
Bugs.MatchCase = YES
Bugs.KeepCase = YES
Bugs.TermCase = YES

[test2.md]
demo.CapSub = YES
9 changes: 9 additions & 0 deletions testdata/fixtures/checks/Substitution/test2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Test

Change into the `/etc` directory.

Within the home directory.

Change into the `/home/user` directory.

Change into the `/etc/X11` directory.
10 changes: 10 additions & 0 deletions testdata/styles/demo/CapSub.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
extends: substitution
message: "Use '%s' instead of '%s'."
level: error
scope: raw
capitalize: true
ignorecase: true
action:
name: replace
swap:
"change in(?: )?to the (.*) directory": change to the $1 directory

0 comments on commit 7f2c55e

Please sign in to comment.