diff --git a/goldens/trailing_commas.in b/goldens/trailing_commas.in index ff51589..00dee8a 100644 --- a/goldens/trailing_commas.in +++ b/goldens/trailing_commas.in @@ -7,7 +7,6 @@ Trailing comma except for last Trailing comma and a comment -TODO: https://github.com/google/keep-sorted/issues/33 - Fix this keep-sorted-test start 3, # three 1, @@ -15,17 +14,30 @@ TODO: https://github.com/google/keep-sorted/issues/33 - Fix this keep-sorted-test end Trailing comma except for last, last has a comment -TODO: https://github.com/google/keep-sorted/issues/33 - Fix this keep-sorted-test start 3, - 1, - 2 # two + 1, + 2 keep-sorted-test end Trailing comma and a comment, last has a comment -TODO: https://github.com/google/keep-sorted/issues/33 - Fix this keep-sorted-test start - 3, # three + 3, -- three 1, - 2 # two + 2 -- two + keep-sorted-test end + +Trailing commas with inline comment + keep-sorted-test start + "c" /* c */, + "b", + "a" /* a */ + keep-sorted-test end + +Trailing commas with quoted comment characters +TODO: https://github.com/google/keep-sorted/issues/33 - Fix this + keep-sorted-test start + "c", + "b, //", + "a, #" keep-sorted-test end diff --git a/goldens/trailing_commas.out b/goldens/trailing_commas.out index 749e403..6db1901 100644 --- a/goldens/trailing_commas.out +++ b/goldens/trailing_commas.out @@ -7,25 +7,37 @@ Trailing comma except for last Trailing comma and a comment -TODO: https://github.com/google/keep-sorted/issues/33 - Fix this keep-sorted-test start 1, - 2 - 3, # three + 2, + 3 # three keep-sorted-test end Trailing comma except for last, last has a comment -TODO: https://github.com/google/keep-sorted/issues/33 - Fix this keep-sorted-test start - 1, - 2 # two, + 1, + 2, 3 keep-sorted-test end Trailing comma and a comment, last has a comment -TODO: https://github.com/google/keep-sorted/issues/33 - Fix this keep-sorted-test start 1, - 2 # two - 3, # three + 2, -- two + 3 -- three + keep-sorted-test end + +Trailing commas with inline comment + keep-sorted-test start + "a", /* a */ + "b", + "c" /* c */ + keep-sorted-test end + +Trailing commas with quoted comment characters +TODO: https://github.com/google/keep-sorted/issues/33 - Fix this + keep-sorted-test start + "a, #" + "b, //", + "c", keep-sorted-test end diff --git a/keepsorted/block.go b/keepsorted/block.go index 9ff284b..730fb6b 100644 --- a/keepsorted/block.go +++ b/keepsorted/block.go @@ -16,6 +16,7 @@ package keepsorted import ( "fmt" + "regexp" "slices" "strings" @@ -389,13 +390,23 @@ func handleTrailingComma(lgs []*lineGroup) (trimTrailingComma func([]*lineGroup) } } - if n := len(dataGroups); n > 1 && allHaveSuffix(dataGroups[0:n-1], ",") && !dataGroups[n-1].hasSuffix(",") { - dataGroups[n-1].append(",") + knownCommentMarkersList := knownCommentMarkers() + for i, marker := range knownCommentMarkersList { + // Some comment markers, such as "/*", include regex metacharacters. + knownCommentMarkersList[i] = regexp.QuoteMeta(marker) + } + knownCommentMarkersStr := strings.Join(knownCommentMarkersList, "|") + + commaLineEnd := regexp.MustCompile(fmt.Sprintf(",(\\s*(%s).*)?$", knownCommentMarkersStr)) + lineEnd := regexp.MustCompile(fmt.Sprintf("(\\s*(%s).*)?$", knownCommentMarkersStr)) + + if n := len(dataGroups); n > 1 && allMatchSuffix(dataGroups[0:n-1], commaLineEnd) && !dataGroups[n-1].matchesSuffix(commaLineEnd) { + dataGroups[n-1].replaceSuffix(lineEnd, ",$1") return func(lgs []*lineGroup) { for i := len(lgs) - 1; i >= 0; i-- { if len(lgs[i].lines) > 0 { - lgs[i].trimSuffix(",") + lgs[i].replaceSuffix(commaLineEnd, "$1") return } } @@ -405,9 +416,9 @@ func handleTrailingComma(lgs []*lineGroup) (trimTrailingComma func([]*lineGroup) return func([]*lineGroup) {} } -func allHaveSuffix(lgs []*lineGroup, s string) bool { +func allMatchSuffix(lgs []*lineGroup, suffix *regexp.Regexp) bool { for _, lg := range lgs { - if !lg.hasSuffix(s) { + if !lg.matchesSuffix(suffix) { return false } } diff --git a/keepsorted/keep_sorted_test.go b/keepsorted/keep_sorted_test.go index b90cd0b..1dbf752 100644 --- a/keepsorted/keep_sorted_test.go +++ b/keepsorted/keep_sorted_test.go @@ -1126,6 +1126,21 @@ func TestLineSorting(t *testing.T) { "foo", }, }, + { + name: "TrailingCommas_WithComments", + + in: []string{ + "foo,", + "baz, /* baz */", + "bar // bar", + }, + + want: []string{ + "bar, // bar", + "baz, /* baz */", + "foo", + }, + }, { name: "IgnorePrefixes", diff --git a/keepsorted/line_group.go b/keepsorted/line_group.go index a637de8..0cb6adb 100644 --- a/keepsorted/line_group.go +++ b/keepsorted/line_group.go @@ -119,7 +119,7 @@ func groupLines(lines []string, metadata blockMetadata) []*lineGroup { // Returns another boolean indicating whether the group should be ending // after that line if so. shouldAddToRegexDelimitedGroup := func(l string) (addToGroup bool, finishGroupAfter bool) { - if metadata.opts.GroupStartRegex != nil { + if metadata.opts.GroupStartRegex != nil { // For GroupStartRegex, all non-regex-matching lines should be // part of the group including prior lines. return !matchesAnyRegex(l, metadata.opts.GroupStartRegex), false @@ -408,11 +408,20 @@ func (lg *lineGroup) hasSuffix(s string) bool { return len(lg.lines) > 0 && strings.HasSuffix(lg.lines[len(lg.lines)-1], s) } +func (lg *lineGroup) matchesSuffix(re *regexp.Regexp) bool { + return len(lg.lines) > 0 && re.MatchString(lg.lines[len(lg.lines)-1]) +} + func (lg *lineGroup) trimSuffix(s string) { lg.access = accessRecorder{} lg.lines[len(lg.lines)-1] = strings.TrimSuffix(lg.lines[len(lg.lines)-1], s) } +func (lg *lineGroup) replaceSuffix(re *regexp.Regexp, replacement string) { + lg.access = accessRecorder{} + lg.lines[len(lg.lines)-1] = re.ReplaceAllString(lg.lines[len(lg.lines)-1], replacement) +} + func (lg *lineGroup) commentOnly() bool { lg.access.commentOnly = true return len(lg.lines) == 0 diff --git a/keepsorted/options.go b/keepsorted/options.go index 6b5c6fa..928a79f 100644 --- a/keepsorted/options.go +++ b/keepsorted/options.go @@ -312,9 +312,13 @@ func formatIntList(intVals []int) string { return strings.Join(vals, ",") } +func knownCommentMarkers() []string { + return []string{"//", "#", "/*", "--", ";", "