Skip to content

Commit 124bbb1

Browse files
perf: compile regexp only once
1 parent 77cb26d commit 124bbb1

1 file changed

Lines changed: 18 additions & 10 deletions

File tree

parser.go

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@ import (
88
"strings"
99
)
1010

11+
// from https://github.com/conventional-commits/parser#the-grammar
12+
13+
// <header/summary> ::= <type>, "(", <scope>, ")", ["!"], ":", <whitespace>*, <text> <type>, ["!"], ":", <whitespace>*, <text>
14+
// <type> ::= <any UTF8-octets except newline or parens or ":" or "!:" or whitespace>+
15+
// <scope> ::= <any UTF8-octets except newline or parens>+
16+
17+
const (
18+
headRegExStr = `^(?P<type>[^\n\(\)(:|!:| )]+)(?:\((?P<scope>[^\n\(\)]+)\))?(?P<breaking>!)?: (?P<description>[^\n]+)(?:\n\s*\n(?P<body>(?:.|\n)*)(?:\n\s+\n(?P<footers>(?:[A-Za-z-]+: (?:.|\n)*)|(?:BREAKING CHANGE: (?:.|\n)*)|(?:[A-Za-z]+ \#(?:.|\n)*)))?)?$`
19+
footRegExStr = `^(?:(BREAKING[- ]CHANGE|(?:[A-Za-z-])+): |((?:[A-Za-z-])+) #)(.+)$`
20+
)
21+
22+
var (
23+
headerRegexp = regexp.MustCompile(headRegExStr)
24+
footerRegexp = regexp.MustCompile(footRegExStr)
25+
)
26+
1127
var (
1228
errHeader = errors.New("unable to parse commit header")
1329
errNoNewLine = errors.New("commit description not followed by an empty line")
@@ -93,7 +109,6 @@ func Parse(message string) (*Commit, error) {
93109
// parseLineAsFooter attempts to parse the given line as a footer, returning both the key and the value of the header.
94110
// If the line cannot be parsed then both return values will be empty.
95111
func parseLineAsFooter(line string) (key, value string) {
96-
footerRegexp := regexp.MustCompile(`^(?:(BREAKING[- ]CHANGE|(?:[A-Za-z-])+): |((?:[A-Za-z-])+) #)(.+)$`)
97112
matches := footerRegexp.FindStringSubmatch(line)
98113
if len(matches) != 4 {
99114
return "", ""
@@ -107,14 +122,6 @@ func parseLineAsFooter(line string) (key, value string) {
107122

108123
// parseHeader attempts to parse the commit description line and set the appropriate values in the the given commit
109124
func parseHeader(header string, commit *Commit) error {
110-
// from https://github.com/conventional-commits/parser#the-grammar
111-
112-
// <header/summary> ::= <type>, "(", <scope>, ")", ["!"], ":", <whitespace>*, <text> <type>, ["!"], ":", <whitespace>*, <text>
113-
// <type> ::= <any UTF8-octets except newline or parens or ":" or "!:" or whitespace>+
114-
// <scope> ::= <any UTF8-octets except newline or parens>+
115-
116-
headerRegexp := regexp.MustCompile(`^(?P<type>[^\n\(\)(:|!:| )]+)(?:\((?P<scope>[^\n\(\)]+)\))?(?P<breaking>!)?: (?P<description>[^\n]+)(?:\n\s*\n(?P<body>(?:.|\n)*)(?:\n\s+\n(?P<footers>(?:[A-Za-z-]+: (?:.|\n)*)|(?:BREAKING CHANGE: (?:.|\n)*)|(?:[A-Za-z]+ \#(?:.|\n)*)))?)?$`)
117-
// TODO: comma separated multiple scopes?
118125
matches := headerRegexp.FindStringSubmatch(header)
119126
if matches == nil {
120127
return errHeader
@@ -130,6 +137,7 @@ func parseHeader(header string, commit *Commit) error {
130137
case "type":
131138
head.Type = match
132139
case "scope":
140+
// TODO: comma separated multiple scopes?
133141
head.Scope = match
134142
case "description":
135143
head.Description = match
@@ -142,7 +150,7 @@ func parseHeader(header string, commit *Commit) error {
142150
return nil
143151
}
144152

145-
// IsHeaderErr checks if given error is parser header error
153+
// IsHeaderErr checks if given error is header parse error
146154
func IsHeaderErr(err error) bool {
147155
return errors.Is(err, errHeader)
148156
}

0 commit comments

Comments
 (0)