Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions goldens/group_regex.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# keep-sorted-test start group_start_regex=^CREATE newline_separated=yes
# Foo comment
CREATE PUBLIC FUNCTION Foo(x INT64)
RETURNS INT64
AS (
x + 1
);

# Bar comment
CREATE PUBLIC FUNCTION Bar(x INT64)
RETURNS INT64
AS (
x + 2
);

# Baz comment
CREATE PUBLIC FUNCTION Baz(x INT64)
RETURNS INT64
AS (
x + LENGTH('CREATE')
);
# keep-sorted-test end

# keep-sorted-test start group_start_regex=^CREATE newline_separated=yes by_regex=["\\bFUNCTION (\\w+)\\b"]
# Foo comment
CREATE PUBLIC FUNCTION Foo(x INT64)
RETURNS INT64
AS (
x + 1
);

# Bar comment
CREATE PRIVATE FUNCTION Bar(x INT64)
RETURNS INT64
AS (
x + 2
);

# Baz comment
CREATE PUBLIC AGGREGATE FUNCTION Baz(x INT64)
RETURNS INT64
AS (
SUM(x) + LENGTH('CREATE FUNCTION Aaa')
);
# keep-sorted-test end

# keep-sorted-test start group_end_regex=;$ newline_separated=yes
# Foo comment
CREATE PUBLIC FUNCTION Foo(x INT64)
RETURNS INT64
AS (
x + 1
);

# Bar comment
CREATE PUBLIC FUNCTION Bar(x INT64)
RETURNS INT64
AS (
x + 2
);

# Baz comment
CREATE PUBLIC FUNCTION Baz(x INT64)
RETURNS INT64
AS (
x + LENGTH('CREATE')
);
# keep-sorted-test end
68 changes: 68 additions & 0 deletions goldens/group_regex.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# keep-sorted-test start group_start_regex=^CREATE newline_separated=yes
# Bar comment
CREATE PUBLIC FUNCTION Bar(x INT64)
RETURNS INT64
AS (
x + 2
);

# Baz comment
CREATE PUBLIC FUNCTION Baz(x INT64)
RETURNS INT64
AS (
x + LENGTH('CREATE')
);

# Foo comment
CREATE PUBLIC FUNCTION Foo(x INT64)
RETURNS INT64
AS (
x + 1
);
# keep-sorted-test end

# keep-sorted-test start group_start_regex=^CREATE newline_separated=yes by_regex=["\\bFUNCTION (\\w+)\\b"]
# Bar comment
CREATE PRIVATE FUNCTION Bar(x INT64)
RETURNS INT64
AS (
x + 2
);

# Baz comment
CREATE PUBLIC AGGREGATE FUNCTION Baz(x INT64)
RETURNS INT64
AS (
SUM(x) + LENGTH('CREATE FUNCTION Aaa')
);

# Foo comment
CREATE PUBLIC FUNCTION Foo(x INT64)
RETURNS INT64
AS (
x + 1
);
# keep-sorted-test end

# keep-sorted-test start group_end_regex=;$ newline_separated=yes
# Bar comment
CREATE PUBLIC FUNCTION Bar(x INT64)
RETURNS INT64
AS (
x + 2
);

# Baz comment
CREATE PUBLIC FUNCTION Baz(x INT64)
RETURNS INT64
AS (
x + LENGTH('CREATE')
);

# Foo comment
CREATE PUBLIC FUNCTION Foo(x INT64)
RETURNS INT64
AS (
x + 1
);
# keep-sorted-test end
40 changes: 40 additions & 0 deletions keepsorted/line_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ type accessRecorder struct {
joinedComment bool
}

// matchesAnyRegex returns true if s matches one of the regexes.
func matchesAnyRegex(s string, regexes []*regexp.Regexp) bool {
for _, regex := range regexes {
if regex.FindStringSubmatch(s) != nil {
return true
}
}
return false
}

// groupLines splits lines into one or more lineGroups based on the provided options.
func groupLines(lines []string, metadata blockMetadata) []*lineGroup {
var groups []*lineGroup
Expand Down Expand Up @@ -128,6 +138,12 @@ func groupLines(lines []string, metadata blockMetadata) []*lineGroup {
}
// finish an outstanding lineGroup and reset our state to prepare for a new lineGroup.
finishGroup := func() {
// If the current lineRange ends with an extra empty line, remove it and place it in a separate group.
endingEmptyLines := 0
for lineRange.size() > 1 && lines[lineRange.end-1] == "" {
endingEmptyLines++
lineRange.end--
}
groups = append(groups, &lineGroup{
opts: metadata.opts,
prefixOrder: prefixOrder,
Expand All @@ -136,6 +152,14 @@ func groupLines(lines []string, metadata blockMetadata) []*lineGroup {
commentRange = indexRange{}
lineRange = indexRange{}
block = codeBlock{}
for endingEmptyLines > 0 {
groups = append(groups, &lineGroup{
opts: metadata.opts,
prefixOrder: prefixOrder,
lineGroupContent: lineGroupContent{lines: []string{""}},
})
endingEmptyLines--
}
}
for i, l := range lines {
if shouldAddToBlock() || shouldAddToGroup(i, l) {
Expand All @@ -154,6 +178,15 @@ func groupLines(lines []string, metadata blockMetadata) []*lineGroup {
// count end directives via its appendLine call.
countStartDirectives(l)
}
} else if metadata.opts.GroupEndRegex != nil {
if matchesAnyRegex(l, metadata.opts.GroupEndRegex) {
appendLine(i, l)
finishGroup()
} else {
appendLine(i, l)
}
} else if metadata.opts.GroupStartRegex != nil && !matchesAnyRegex(l, metadata.opts.GroupStartRegex) {
appendLine(i, l)
} else {
// Begin a new block or group.
if !lineRange.empty() {
Expand Down Expand Up @@ -225,6 +258,13 @@ func (r *indexRange) empty() bool {
return !r.init || r.start == r.end
}

func (r *indexRange) size() int {
if !r.init {
return 0
}
return r.end - r.start
}

func (r *indexRange) append(i int) {
if !r.init {
r.start = i
Expand Down
18 changes: 17 additions & 1 deletion keepsorted/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type ByRegexOption struct {
type SortOrder string

const (
OrderAsc SortOrder = "asc"
OrderAsc SortOrder = "asc"
OrderDesc SortOrder = "desc"
)

Expand Down Expand Up @@ -96,6 +96,15 @@ type blockOptions struct {
StickyComments bool `key:"sticky_comments"`
// StickyPrefixes tells us about other types of lines that should behave as sticky comments.
StickyPrefixes map[string]bool `key:"sticky_prefixes"`
// GroupStartRegex is a list of regexes that match the start of a group of lines (does not need to match the whole line).
// If none of the listed regexes match a given line, the line is considered to be part of the same
// group as the previous line.
GroupStartRegex []*regexp.Regexp `key:"group_start_regex"`
// GroupEndRegex is a list of regexes that match the end of a group of lines (does not need to match the whole line).
// If any of the listed regexes match a given line, the line will end the current group,
// provided that it does not get ignored by other options (indented/prefixed group, block, sticky comment).
// Non-comment lines no longer end groups when GroupEndRegex is used.
GroupEndRegex []*regexp.Regexp `key:"group_end_regex"`

///////////////////////
// Sorting options //
Expand Down Expand Up @@ -240,6 +249,13 @@ func formatValue(val reflect.Value) (string, error) {
return fmt.Sprintf("[%s]", strings.Join(vals, ", ")), nil
}
return formatList(vals)
case reflect.TypeFor[[]*regexp.Regexp]():
regexps := val.Interface().([]*regexp.Regexp)
vals := make([]string, len(regexps))
for i, regex := range regexps {
vals[i] = regex.String()
}
return formatList(vals)
}

panic(fmt.Errorf("unsupported blockOptions type: %v", val.Type()))
Expand Down
17 changes: 15 additions & 2 deletions keepsorted/options_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,13 @@ func (p *parser) popValue(typ reflect.Type) (reflect.Value, error) {
val, err := p.popSet()
return reflect.ValueOf(val), err
case reflect.TypeFor[[]ByRegexOption]():
val, err := p.popListRegexOption()
val, err := p.popByRegexOption()
if err != nil {
return reflect.Zero(typ), err
}
return reflect.ValueOf(val), nil
case reflect.TypeFor[[]*regexp.Regexp]():
val, err := p.popRegexListOption()
if err != nil {
return reflect.Zero(typ), err
}
Expand Down Expand Up @@ -183,13 +189,20 @@ func (p *parser) popList() ([]string, error) {
return popListValue(p, func(s string) (string, error) { return s, nil })
}

func (p *parser) popListRegexOption() ([]ByRegexOption, error) {
func (p *parser) popByRegexOption() ([]ByRegexOption, error) {
return popListValue(p, func(s string) (ByRegexOption, error) {
pat, err := regexp.Compile(s)
return ByRegexOption{Pattern: pat}, err
})
}

func (p *parser) popRegexListOption() ([]*regexp.Regexp, error) {
return popListValue(p, func(s string) (*regexp.Regexp, error) {
pat, err := regexp.Compile(s)
return pat, err
})
}

func (p *parser) popSortOrder() (SortOrder, error) {
val, rest, _ := strings.Cut(p.line, " ")
p.line = rest
Expand Down
18 changes: 18 additions & 0 deletions keepsorted/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,24 @@ func TestBlockOptions(t *testing.T) {
want: blockOptions{Order: OrderAsc},
wantErr: `while parsing option "order": unrecognized order value "foo", expected 'asc' or 'desc'`,
},
{
name: "GroupStartRegex",
in: "group_start_regex=^CREATE",

want: blockOptions{
GroupStartRegex: []*regexp.Regexp{regexp.MustCompile("^CREATE")},
},
},
{
name: "GroupStartRegex_YAML",
in: "group_start_regex=['^CREATE', 'b']",
defaultOptions: blockOptions{AllowYAMLLists: true},

want: blockOptions{
AllowYAMLLists: true,
GroupStartRegex: []*regexp.Regexp{regexp.MustCompile("^CREATE"), regexp.MustCompile("b")},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
initZerolog(t)
Expand Down
Loading