Skip to content

Commit 488401a

Browse files
authored
refactor: Move sorting logic from block.go to line_group.go. (#87)
This also moves the logic a bit more towards an imperative style from the current functional style, which might be a bit easier to reason about moving forward.
1 parent 24d2c00 commit 488401a

File tree

3 files changed

+217
-162
lines changed

3 files changed

+217
-162
lines changed

keepsorted/block.go

Lines changed: 13 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ func (b block) sorted() (sorted []string, alreadySorted bool) {
243243
wasNewlineSeparated := true
244244
if b.metadata.opts.NewlineSeparated > 0 {
245245
wasNewlineSeparated = isNewlineSeparated(groups, numNewlines)
246-
var withoutNewlines []lineGroup
246+
var withoutNewlines []*lineGroup
247247
for _, lg := range groups {
248248
if !isAllEmpty(lg) {
249249
withoutNewlines = append(withoutNewlines, lg)
@@ -255,7 +255,7 @@ func (b block) sorted() (sorted []string, alreadySorted bool) {
255255
removedDuplicate := false
256256
if b.metadata.opts.RemoveDuplicates {
257257
seen := map[string]bool{}
258-
var deduped []lineGroup
258+
var deduped []*lineGroup
259259
for _, lg := range groups {
260260
if s := lg.joinedLines() + "\n" + strings.Join(lg.comment, "\n"); !seen[s] {
261261
seen[s] = true
@@ -267,20 +267,18 @@ func (b block) sorted() (sorted []string, alreadySorted bool) {
267267
groups = deduped
268268
}
269269

270-
less := b.lessFn()
271-
272-
if alreadySorted && wasNewlineSeparated && !removedDuplicate && slices.IsSortedFunc(groups, less) {
270+
if alreadySorted && wasNewlineSeparated && !removedDuplicate && slices.IsSortedFunc(groups, compareLineGroups) {
273271
trimTrailingComma(groups)
274272
return lines, true
275273
}
276274

277-
slices.SortStableFunc(groups, less)
275+
slices.SortStableFunc(groups, compareLineGroups)
278276

279277
trimTrailingComma(groups)
280278

281279
if b.metadata.opts.NewlineSeparated > 0 {
282-
var separated []lineGroup
283-
newline := lineGroup{lines: make([]string, numNewlines)}
280+
var separated []*lineGroup
281+
newline := &lineGroup{lineGroupContent: lineGroupContent{lines: make([]string, numNewlines)}}
284282
for _, lg := range groups {
285283
if separated != nil {
286284
separated = append(separated, newline)
@@ -309,7 +307,7 @@ func (b block) sorted() (sorted []string, alreadySorted bool) {
309307
// .
310308
// .
311309
// non-empty group
312-
func isNewlineSeparated(gs []lineGroup, numNewlines int) bool {
310+
func isNewlineSeparated(gs []*lineGroup, numNewlines int) bool {
313311
if len(gs) == 0 {
314312
return true
315313
}
@@ -346,7 +344,7 @@ func isNewlineSeparated(gs []lineGroup, numNewlines int) bool {
346344
return true
347345
}
348346

349-
func isAllEmpty(lg lineGroup) bool {
347+
func isAllEmpty(lg *lineGroup) bool {
350348
if len(lg.comment) > 0 {
351349
return false
352350
}
@@ -361,8 +359,8 @@ func isAllEmpty(lg lineGroup) bool {
361359
// handleTrailingComma handles the special case that all lines of a sorted segment are terminated
362360
// by a comma except for the final element; in this case, we add a ',' to the
363361
// last linegroup and strip it again after sorting.
364-
func handleTrailingComma(lgs []lineGroup) (trimTrailingComma func([]lineGroup)) {
365-
var dataGroups []lineGroup
362+
func handleTrailingComma(lgs []*lineGroup) (trimTrailingComma func([]*lineGroup)) {
363+
var dataGroups []*lineGroup
366364
for _, lg := range lgs {
367365
if len(lg.lines) > 0 {
368366
dataGroups = append(dataGroups, lg)
@@ -372,7 +370,7 @@ func handleTrailingComma(lgs []lineGroup) (trimTrailingComma func([]lineGroup))
372370
if n := len(dataGroups); n > 1 && allHaveSuffix(dataGroups[0:n-1], ",") && !dataGroups[n-1].hasSuffix(",") {
373371
dataGroups[n-1].append(",")
374372

375-
return func(lgs []lineGroup) {
373+
return func(lgs []*lineGroup) {
376374
for i := len(lgs) - 1; i >= 0; i-- {
377375
if len(lgs[i].lines) > 0 {
378376
lgs[i].trimSuffix(",")
@@ -382,66 +380,14 @@ func handleTrailingComma(lgs []lineGroup) (trimTrailingComma func([]lineGroup))
382380
}
383381
}
384382

385-
return func([]lineGroup) {}
383+
return func([]*lineGroup) {}
386384
}
387385

388-
func allHaveSuffix(lgs []lineGroup, s string) bool {
386+
func allHaveSuffix(lgs []*lineGroup, s string) bool {
389387
for _, lg := range lgs {
390388
if !lg.hasSuffix(s) {
391389
return false
392390
}
393391
}
394392
return true
395393
}
396-
397-
func (b block) lessFn() cmpFunc[lineGroup] {
398-
// Always put groups that are only comments last.
399-
commentOnlyBlock := comparing(func(lg lineGroup) int {
400-
if len(lg.lines) > 0 {
401-
return 0
402-
}
403-
return 1
404-
})
405-
406-
regexTransform := func(lg lineGroup) []regexMatch {
407-
return b.metadata.opts.matchRegexes(lg.joinedLines())
408-
}
409-
410-
ord := newPrefixOrder(b.metadata.opts)
411-
prefixOrder := comparingFunc(func(s []string) orderedPrefix {
412-
if len(s) == 0 {
413-
return orderedPrefix{}
414-
}
415-
return ord.match(s[0])
416-
}, orderedPrefix.compare)
417-
418-
// Combinations of switches (for example, case-insensitive and numeric
419-
// ordering) which must be applied to create a single comparison key,
420-
// otherwise a sub-ordering can preempt a total ordering:
421-
// Foo_45
422-
// foo_123
423-
// foo_6
424-
// would be sorted as either (numeric but not case-insensitive)
425-
// Foo_45
426-
// foo_6
427-
// foo_123
428-
// or (case-insensitive but not numeric)
429-
// foo_123
430-
// Foo_45
431-
// foo_6
432-
// but should be (case-insensitive and numeric)
433-
// foo_6
434-
// Foo_45
435-
// foo_123
436-
transformOrder := comparingFunc(func(s string) numericTokens {
437-
s = b.metadata.opts.trimIgnorePrefix(s)
438-
if !b.metadata.opts.CaseSensitive {
439-
s = strings.ToLower(s)
440-
}
441-
return b.metadata.opts.maybeParseNumeric(s)
442-
}, numericTokens.compare)
443-
444-
return commentOnlyBlock.
445-
andThen(comparingFunc(regexTransform, compareRegexMatches(prefixOrder.andThen(lexicographically(transformOrder))))).
446-
andThen(lineGroup.less)
447-
}

0 commit comments

Comments
 (0)