-
-
Notifications
You must be signed in to change notification settings - Fork 140
/
capitalization.go
101 lines (88 loc) · 2.8 KB
/
capitalization.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package check
import (
"fmt"
"strings"
"github.com/errata-ai/vale/v2/config"
"github.com/errata-ai/vale/v2/core"
"github.com/jdkato/prose/transform"
"github.com/jdkato/regexp"
"github.com/mitchellh/mapstructure"
)
// Capitalization checks the case of a string.
type Capitalization struct {
Definition `mapstructure:",squash"`
// `match` (`string`): $title, $sentence, $lower, $upper, or a pattern.
Match string
Check func(s string, ignore []string, re *regexp.Regexp) bool
// `style` (`string`): AP or Chicago; only applies when match is set to
// $title.
Style string
// `exceptions` (`array`): An array of strings to be ignored.
Exceptions []string
// `indicators` (`array`): An array of suffixes that indicate the next
// token should be ignored.
Indicators []string
exceptRe *regexp.Regexp
}
// NewCapitalization creates a new `capitalization`-based rule.
func NewCapitalization(cfg *config.Config, generic baseCheck) (Capitalization, error) {
rule := Capitalization{}
path := generic["path"].(string)
err := mapstructure.Decode(generic, &rule)
if err != nil {
return rule, readStructureError(err, path)
}
regex := makeRegexp(
"",
false,
func() bool { return true },
func() string { return "" },
true)
for term := range cfg.AcceptedTokens {
rule.Exceptions = append(rule.Exceptions, term)
}
regex = fmt.Sprintf(regex, strings.Join(rule.Exceptions, "|"))
rule.exceptRe = regexp.MustCompile(regex)
if rule.Match == "$title" {
var tc *transform.TitleConverter
if rule.Style == "Chicago" {
tc = transform.NewTitleConverter(transform.ChicagoStyle)
} else {
tc = transform.NewTitleConverter(transform.APStyle)
}
rule.Check = func(s string, ignore []string, re *regexp.Regexp) bool {
return title(s, ignore, re, tc)
}
} else if rule.Match == "$sentence" {
rule.Check = func(s string, ignore []string, re *regexp.Regexp) bool {
return sentence(s, ignore, rule.Indicators, re)
}
} else if f, ok := varToFunc[rule.Match]; ok {
rule.Check = f
} else {
re, err := regexp.Compile(rule.Match)
if err != nil {
return rule, core.NewE201FromPosition(err.Error(), path, 1)
}
rule.Check = func(s string, ignore []string, r *regexp.Regexp) bool {
return re.MatchString(s) || core.StringInSlice(s, ignore)
}
}
return rule, nil
}
// Run checks the capitalization style of the provided text.
func (o Capitalization) Run(txt string, f *core.File) []core.Alert {
alerts := []core.Alert{}
if !o.Check(txt, o.Exceptions, o.exceptRe) {
alerts = append(alerts, makeAlert(o.Definition, []int{0, len(txt)}, txt))
}
return alerts
}
// Fields provides access to the internal rule definition.
func (o Capitalization) Fields() Definition {
return o.Definition
}
// Pattern is the internal regex pattern used by this rule.
func (o Capitalization) Pattern() string {
return ""
}