Function bodies 497 total
metrics.Document.LineCount method · go · L49-L58 (10 LOC)internal/metrics/document.go
func (d *Document) LineCount() int {
if len(d.Source) == 0 {
return 0
}
lines := bytes.Count(d.Source, []byte("\n"))
if d.Source[len(d.Source)-1] != '\n' {
lines++
}
return lines
}metrics.Document.File method · go · L61-L76 (16 LOC)internal/metrics/document.go
func (d *Document) File() (*lint.File, error) {
if d.fileReady {
return d.file, d.fileErr
}
f, err := lint.NewFile(d.Path, d.Source)
if err != nil {
d.fileErr = fmt.Errorf("parsing markdown: %w", err)
d.fileReady = true
return nil, d.fileErr
}
d.file = f
d.fileReady = true
return d.file, nil
}metrics.Document.PlainText method · go · L79-L94 (16 LOC)internal/metrics/document.go
func (d *Document) PlainText() (string, error) {
if d.plainTextReady {
return d.plainText, d.plainTextErr
}
f, err := d.File()
if err != nil {
d.plainTextErr = err
d.plainTextReady = true
return "", err
}
d.plainText = mdtext.ExtractPlainText(f.AST, f.Source)
d.plainTextReady = true
return d.plainText, nil
}metrics.Document.WordCount method · go · L97-L112 (16 LOC)internal/metrics/document.go
func (d *Document) WordCount() (int, error) {
if d.wordCountReady {
return d.wordCount, d.wordCountErr
}
text, err := d.PlainText()
if err != nil {
d.wordCountErr = err
d.wordCountReady = true
return 0, err
}
d.wordCount = mdtext.CountWords(text)
d.wordCountReady = true
return d.wordCount, nil
}metrics.Document.HeadingCount method · go · L115-L140 (26 LOC)internal/metrics/document.go
func (d *Document) HeadingCount() (int, error) {
if d.headingCountReady {
return d.headingCount, d.headingCountErr
}
f, err := d.File()
if err != nil {
d.headingCountErr = err
d.headingCountReady = true
return 0, err
}
count := 0
_ = ast.Walk(f.AST, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if entering {
if _, ok := n.(*ast.Heading); ok {
count++
}
}
return ast.WalkContinue, nil
})
d.headingCount = count
d.headingCountReady = true
return d.headingCount, nil
}metrics.Collect function · go · L18-L42 (25 LOC)internal/metrics/rank.go
func Collect(paths []string, defs []Definition) ([]Row, error) {
rows := make([]Row, 0, len(paths))
for _, path := range paths {
source, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("reading %q: %w", path, err)
}
doc := NewDocument(path, source)
values := make(map[string]Value, len(defs))
for _, def := range defs {
v, err := def.Compute(doc)
if err != nil {
return nil, fmt.Errorf("computing %q for %q: %w", def.Name, path, err)
}
values[def.Name] = v
}
rows = append(rows, Row{
Path: path,
Metrics: values,
})
}
return rows, nil
}metrics.SortRows function · go · L45-L68 (24 LOC)internal/metrics/rank.go
func SortRows(rows []Row, by Definition, order Order) {
sort.Slice(rows, func(i, j int) bool {
a := rows[i].Metrics[by.Name]
b := rows[j].Metrics[by.Name]
// Available values sort before unavailable values.
if a.Available != b.Available {
return a.Available
}
if a.Available && b.Available {
diff := a.Number - b.Number
if math.Abs(diff) > 1e-9 {
if order == OrderAsc {
return diff < 0
}
return diff > 0
}
}
// Stable deterministic tie-break.
return rows[i].Path < rows[j].Path
})
}Repobility · open methodology · https://repobility.com/research/
metrics.LimitRows function · go · L71-L76 (6 LOC)internal/metrics/rank.go
func LimitRows(rows []Row, top int) []Row {
if top <= 0 || top >= len(rows) {
return rows
}
return rows[:top]
}metrics.FormatValue function · go · L79-L93 (15 LOC)internal/metrics/rank.go
func FormatValue(def Definition, value Value) string {
v := JSONValue(def, value)
if v == nil {
return "-"
}
switch n := v.(type) {
case int64:
return strconv.FormatInt(n, 10)
case float64:
return fmt.Sprintf("%.*f", def.Precision, n)
default:
return "-"
}
}metrics.JSONValue function · go · L97-L114 (18 LOC)internal/metrics/rank.go
func JSONValue(def Definition, value Value) any {
if !value.Available {
return nil
}
switch def.Kind {
case KindInteger:
return int64(math.Round(value.Number))
case KindFloat:
if def.Precision < 0 {
return value.Number
}
scale := math.Pow10(def.Precision)
return math.Round(value.Number*scale) / scale
default:
return value.Number
}
}metrics.All function · go · L109-L115 (7 LOC)internal/metrics/registry.go
func All() []Definition {
defs := append([]Definition(nil), registry...)
sort.Slice(defs, func(i, j int) bool {
return defs[i].ID < defs[j].ID
})
return defs
}metrics.ForScope function · go · L118-L127 (10 LOC)internal/metrics/registry.go
func ForScope(scope Scope) []Definition {
all := All()
defs := make([]Definition, 0, len(all))
for _, def := range all {
if def.Scope == scope {
defs = append(defs, def)
}
}
return defs
}metrics.Defaults function · go · L130-L139 (10 LOC)internal/metrics/registry.go
func Defaults(scope Scope) []Definition {
defs := ForScope(scope)
out := make([]Definition, 0, len(defs))
for _, def := range defs {
if def.Default {
out = append(out, def)
}
}
return out
}metrics.Lookup function · go · L142-L149 (8 LOC)internal/metrics/registry.go
func Lookup(query string) (Definition, bool) {
for _, def := range All() {
if matches(def, query) {
return def, true
}
}
return Definition{}, false
}metrics.LookupScope function · go · L152-L159 (8 LOC)internal/metrics/registry.go
func LookupScope(scope Scope, query string) (Definition, bool) {
for _, def := range ForScope(scope) {
if matches(def, query) {
return def, true
}
}
return Definition{}, false
}Repobility analyzer · published findings · https://repobility.com
metrics.Resolve function · go · L163-L192 (30 LOC)internal/metrics/registry.go
func Resolve(scope Scope, names []string) ([]Definition, error) {
if len(names) == 0 {
return Defaults(scope), nil
}
seen := make(map[string]struct{}, len(names))
defs := make([]Definition, 0, len(names))
for _, raw := range names {
name := strings.TrimSpace(raw)
if name == "" {
continue
}
def, ok := LookupScope(scope, name)
if !ok {
return nil, unknownMetricErr(scope, name)
}
if _, exists := seen[def.ID]; exists {
continue
}
seen[def.ID] = struct{}{}
defs = append(defs, def)
}
if len(defs) == 0 {
return nil, fmt.Errorf("no metrics selected")
}
return defs, nil
}metrics.SplitList function · go · L195-L208 (14 LOC)internal/metrics/registry.go
func SplitList(raw string) []string {
if strings.TrimSpace(raw) == "" {
return nil
}
parts := strings.Split(raw, ",")
out := make([]string, 0, len(parts))
for _, p := range parts {
p = strings.TrimSpace(p)
if p != "" {
out = append(out, p)
}
}
return out
}metrics.matches function · go · L210-L216 (7 LOC)internal/metrics/registry.go
func matches(def Definition, query string) bool {
q := strings.TrimSpace(query)
if q == "" {
return false
}
return strings.EqualFold(def.ID, q) || def.Name == strings.ToLower(q)
}metrics.unknownMetricErr function · go · L218-L224 (7 LOC)internal/metrics/registry.go
func unknownMetricErr(scope Scope, name string) error {
return fmt.Errorf(
"unknown metric %q (available: %s)",
name,
strings.Join(availableNames(scope), ", "),
)
}metrics.availableNames function · go · L226-L234 (9 LOC)internal/metrics/registry.go
func availableNames(scope Scope) []string {
defs := ForScope(scope)
names := make([]string, 0, len(defs))
for _, def := range defs {
names = append(names, def.Name)
}
sort.Strings(names)
return names
}metrics.ParseScope function · go · L17-L24 (8 LOC)internal/metrics/types.go
func ParseScope(raw string) (Scope, error) {
switch strings.ToLower(strings.TrimSpace(raw)) {
case "", string(ScopeFile):
return ScopeFile, nil
default:
return "", fmt.Errorf("unknown scope %q (supported: file)", raw)
}
}metrics.ParseOrder function · go · L37-L46 (10 LOC)internal/metrics/types.go
func ParseOrder(raw string) (Order, error) {
switch strings.ToLower(strings.TrimSpace(raw)) {
case "", string(OrderDesc):
return OrderDesc, nil
case string(OrderAsc):
return OrderAsc, nil
default:
return "", fmt.Errorf("unknown order %q (supported: asc, desc)", raw)
}
}metrics.AvailableValue function · go · L65-L70 (6 LOC)internal/metrics/types.go
func AvailableValue(n float64) Value {
return Value{
Number: n,
Available: true,
}
}Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
output.JSONFormatter.Format method · go · L25-L41 (17 LOC)internal/output/json.go
func (f *JSONFormatter) Format(w io.Writer, diagnostics []lint.Diagnostic) error {
items := make([]jsonDiagnostic, 0, len(diagnostics))
for _, d := range diagnostics {
items = append(items, jsonDiagnostic{
File: d.File,
Line: d.Line,
Column: d.Column,
Rule: d.RuleID,
Name: d.RuleName,
Severity: string(d.Severity),
Message: d.Message,
})
}
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
return enc.Encode(items)
}output.TextFormatter.Format method · go · L18-L34 (17 LOC)internal/output/text.go
func (f *TextFormatter) Format(w io.Writer, diagnostics []lint.Diagnostic) error {
for _, d := range diagnostics {
var err error
if f.Color {
// file in cyan, rule in yellow
_, err = fmt.Fprintf(w, "\033[36m%s:%d:%d\033[0m \033[33m%s\033[0m %s\n",
d.File, d.Line, d.Column, d.RuleID, d.Message)
} else {
_, err = fmt.Fprintf(w, "%s:%d:%d %s %s\n",
d.File, d.Line, d.Column, d.RuleID, d.Message)
}
if err != nil {
return err
}
}
return nil
}rule.CloneRule function · go · L9-L33 (25 LOC)internal/rule/clone.go
func CloneRule(r Rule) Rule {
if c, ok := r.(Configurable); ok {
// Create a new zero-value instance of the same concrete type.
rv := reflect.ValueOf(r)
if rv.Kind() == reflect.Ptr {
newPtr := reflect.New(rv.Elem().Type())
clone := newPtr.Interface().(Rule)
if cc, ok := clone.(Configurable); ok {
_ = cc.ApplySettings(c.DefaultSettings())
}
return clone
}
}
// Fallback: reflect-based copy for non-Configurable rules.
rv := reflect.ValueOf(r)
if rv.Kind() == reflect.Ptr {
newPtr := reflect.New(rv.Elem().Type())
newPtr.Elem().Set(rv.Elem())
return newPtr.Interface().(Rule)
}
// Value type — already a copy.
return r
}rule.ByID function · go · L18-L25 (8 LOC)internal/rule/registry.go
func ByID(id string) Rule {
for _, r := range registry {
if r.ID() == id {
return r
}
}
return nil
}blanklinearoundfencedcode.Rule.Check method · go · L30-L87 (58 LOC)internal/rules/blanklinearoundfencedcode/rule.go
func (r *Rule) Check(f *lint.File) []lint.Diagnostic {
var diags []lint.Diagnostic
_ = ast.Walk(f.AST, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
fcb, ok := n.(*ast.FencedCodeBlock)
if !ok {
return ast.WalkContinue, nil
}
openStart, openEnd := fencedcodestyle.FenceOpenLineRange(f.Source, fcb)
closeStart, _ := fencedcodestyle.FenceCloseLineRange(f.Source, fcb, openEnd)
openLine := f.LineOfOffset(openStart)
closeLine := f.LineOfOffset(closeStart)
// Check blank line before opening fence
if openLine > 1 {
prevLineIdx := openLine - 2 // 0-based index of the line before
if prevLineIdx >= 0 && prevLineIdx < len(f.Lines) {
if !isBlank(f.Lines[prevLineIdx]) {
diags = append(diags, lint.Diagnostic{
File: f.Path,
Line: openLine,
Column: 1,
RuleID: r.ID(),
RuleName: r.Name(),
Severity: lint.Warning,
Message: "fenced code block should blanklinearoundfencedcode.Rule.Fix method · go · L90-L110 (21 LOC)internal/rules/blanklinearoundfencedcode/rule.go
func (r *Rule) Fix(f *lint.File) []byte {
insertBeforeLine, insertAfterLine := collectFenceBlankLineInsertions(f)
if len(insertBeforeLine) == 0 && len(insertAfterLine) == 0 {
return f.Source
}
var result []string
for i, line := range f.Lines {
lineNum := i + 1
if insertBeforeLine[lineNum] {
result = append(result, "")
}
result = append(result, string(line))
if insertAfterLine[lineNum] {
result = append(result, "")
}
}
return []byte(strings.Join(result, "\n"))
}blanklinearoundfencedcode.collectFenceBlankLineInsertions function · go · L114-L144 (31 LOC)internal/rules/blanklinearoundfencedcode/rule.go
func collectFenceBlankLineInsertions(f *lint.File) (beforeSet, afterSet map[int]bool) {
beforeSet = make(map[int]bool)
afterSet = make(map[int]bool)
_ = ast.Walk(f.AST, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
fcb, ok := n.(*ast.FencedCodeBlock)
if !ok {
return ast.WalkContinue, nil
}
openStart, openEnd := fencedcodestyle.FenceOpenLineRange(f.Source, fcb)
closeStart, _ := fencedcodestyle.FenceCloseLineRange(f.Source, fcb, openEnd)
openLine := f.LineOfOffset(openStart)
closeLine := f.LineOfOffset(closeStart)
if needsBlankBefore(f, openLine) {
beforeSet[openLine] = true
}
if needsBlankAfter(f, closeLine) {
afterSet[closeLine] = true
}
return ast.WalkContinue, nil
})
return beforeSet, afterSet
}blanklinearoundfencedcode.needsBlankBefore function · go · L148-L154 (7 LOC)internal/rules/blanklinearoundfencedcode/rule.go
func needsBlankBefore(f *lint.File, line int) bool {
if line <= 1 {
return false
}
prevIdx := line - 2
return prevIdx >= 0 && prevIdx < len(f.Lines) && !isBlank(f.Lines[prevIdx])
}All rows above produced by Repobility · https://repobility.com
blanklinearoundheadings.Rule.Check method · go · L28-L89 (62 LOC)internal/rules/blanklinearoundheadings/rule.go
func (r *Rule) Check(f *lint.File) []lint.Diagnostic {
var diags []lint.Diagnostic
codeLines := lint.CollectCodeBlockLines(f)
_ = ast.Walk(f.AST, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
heading, ok := n.(*ast.Heading)
if !ok {
return ast.WalkContinue, nil
}
line := headingLine(heading, f)
// Skip headings whose lines overlap with code block regions.
if codeLines[line] {
return ast.WalkContinue, nil
}
lastLine := headingLastLine(heading, f)
// Check blank line before (not needed for line 1)
if line > 1 {
prevLineIdx := line - 2 // 0-based index
if prevLineIdx >= 0 && prevLineIdx < len(f.Lines) {
prevLine := strings.TrimSpace(string(f.Lines[prevLineIdx]))
if prevLine != "" {
diags = append(diags, lint.Diagnostic{
File: f.Path,
Line: line,
Column: 1,
RuleID: r.ID(),
RuleName: r.Name(),
Severity: lint.Warning,
Messablanklinearoundheadings.Rule.Fix method · go · L92-L121 (30 LOC)internal/rules/blanklinearoundheadings/rule.go
func (r *Rule) Fix(f *lint.File) []byte {
insertBefore, insertAfter := collectHeadingBlankLineInsertions(f)
if len(insertBefore) == 0 && len(insertAfter) == 0 {
return f.Source
}
lines := make([]string, len(f.Lines))
for i, l := range f.Lines {
lines[i] = string(l)
}
var result []string
for i, line := range lines {
lineNum := i + 1
if insertBefore[lineNum] {
// Avoid inserting a blank line if one was just inserted
// after the previous line (prevents double blank lines).
if !insertAfter[lineNum-1] {
result = append(result, "")
}
}
result = append(result, line)
if insertAfter[lineNum] {
result = append(result, "")
}
}
return []byte(strings.Join(result, "\n"))
}blanklinearoundheadings.collectHeadingBlankLineInsertions function · go · L125-L163 (39 LOC)internal/rules/blanklinearoundheadings/rule.go
func collectHeadingBlankLineInsertions(f *lint.File) (insertBefore, insertAfter map[int]bool) {
insertBefore = make(map[int]bool)
insertAfter = make(map[int]bool)
codeLines := lint.CollectCodeBlockLines(f)
type headingInfo struct {
line int
lastLine int
}
var headings []headingInfo
_ = ast.Walk(f.AST, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
heading, ok := n.(*ast.Heading)
if !ok {
return ast.WalkContinue, nil
}
line := headingLine(heading, f)
if codeLines[line] {
return ast.WalkContinue, nil
}
headings = append(headings, headingInfo{line: line, lastLine: headingLastLine(heading, f)})
return ast.WalkContinue, nil
})
lines := f.Lines
for _, h := range headings {
if h.line > 1 && isNonBlankLine(lines, h.line-2) {
insertBefore[h.line] = true
}
if isNonBlankLine(lines, h.lastLine) {
insertAfter[h.lastLine] = true
}
}
return insertBefore, insertAfter
}blanklinearoundheadings.isNonBlankLine function · go · L167-L172 (6 LOC)internal/rules/blanklinearoundheadings/rule.go
func isNonBlankLine(lines [][]byte, idx int) bool {
if idx < 0 || idx >= len(lines) {
return false
}
return strings.TrimSpace(string(lines[idx])) != ""
}blanklinearoundheadings.headingLine function · go · L174-L185 (12 LOC)internal/rules/blanklinearoundheadings/rule.go
func headingLine(heading *ast.Heading, f *lint.File) int {
lines := heading.Lines()
if lines.Len() > 0 {
return f.LineOfOffset(lines.At(0).Start)
}
for c := heading.FirstChild(); c != nil; c = c.NextSibling() {
if t, ok := c.(*ast.Text); ok {
return f.LineOfOffset(t.Segment.Start)
}
}
return 1
}blanklinearoundheadings.headingLastLine function · go · L187-L201 (15 LOC)internal/rules/blanklinearoundheadings/rule.go
func headingLastLine(heading *ast.Heading, f *lint.File) int {
lines := heading.Lines()
if lines.Len() > 0 {
// Setext headings: the underline is on the line after the text
lastSeg := lines.At(lines.Len() - 1)
textLine := f.LineOfOffset(lastSeg.Start)
// Check if next line is an underline (setext)
if isSetextHeading(heading, f.Source) {
return textLine + 1
}
return textLine
}
// ATX heading is a single line
return headingLine(heading, f)
}blanklinearoundheadings.isSetextHeading function · go · L203-L217 (15 LOC)internal/rules/blanklinearoundheadings/rule.go
func isSetextHeading(heading *ast.Heading, source []byte) bool {
lines := heading.Lines()
if lines.Len() == 0 {
return false
}
seg := lines.At(0)
lineStart := seg.Start
for lineStart > 0 && source[lineStart-1] != '\n' {
lineStart--
}
if lineStart < len(source) && source[lineStart] == '#' {
return false
}
return true
}blanklinearoundlists.Rule.Check method · go · L28-L64 (37 LOC)internal/rules/blanklinearoundlists/rule.go
func (r *Rule) Check(f *lint.File) []lint.Diagnostic {
var diags []lint.Diagnostic
codeLines := lint.CollectCodeBlockLines(f)
_ = ast.Walk(f.AST, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
list, ok := n.(*ast.List)
if !ok {
return ast.WalkContinue, nil
}
if _, isListItem := list.Parent().(*ast.ListItem); isListItem {
return ast.WalkContinue, nil
}
listStartLine := lineOfNode(f, list)
listEndLine := lastLineOfNode(f, list)
if codeLines[listStartLine] || codeLines[listEndLine] {
return ast.WalkContinue, nil
}
if d, ok := r.checkAdjacentBlank(f, listStartLine, -1, "list should be preceded by a blank line"); ok {
diags = append(diags, d)
}
if d, ok := r.checkAdjacentBlank(f, listEndLine, +1, "list should be followed by a blank line"); ok {
diags = append(diags, d)
}
return ast.WalkContinue, nil
})
return diags
}Repobility · open methodology · https://repobility.com/research/
blanklinearoundlists.Rule.checkAdjacentBlank method · go · L68-L86 (19 LOC)internal/rules/blanklinearoundlists/rule.go
func (r *Rule) checkAdjacentBlank(f *lint.File, targetLine, direction int, msg string) (lint.Diagnostic, bool) {
totalLines := len(f.Lines)
adjLine := targetLine + direction
if adjLine < 1 || adjLine > totalLines {
return lint.Diagnostic{}, false
}
if isBlank(f.Lines[adjLine-1]) {
return lint.Diagnostic{}, false
}
return lint.Diagnostic{
File: f.Path,
Line: targetLine,
Column: 1,
RuleID: r.ID(),
RuleName: r.Name(),
Severity: lint.Warning,
Message: msg,
}, true
}blanklinearoundlists.isInlineNode function · go · L89-L96 (8 LOC)internal/rules/blanklinearoundlists/rule.go
func isInlineNode(n ast.Node) bool {
switch n.(type) {
case *ast.Text, *ast.String, *ast.CodeSpan, *ast.Emphasis,
*ast.Link, *ast.Image, *ast.AutoLink, *ast.RawHTML:
return true
}
return false
}blanklinearoundlists.lineOfNode function · go · L98-L129 (32 LOC)internal/rules/blanklinearoundlists/rule.go
func lineOfNode(f *lint.File, n ast.Node) int {
// Inline nodes do not have Lines(); use Segment for Text nodes.
if t, ok := n.(*ast.Text); ok {
return f.LineOfOffset(t.Segment.Start)
}
if isInlineNode(n) {
// For other inline nodes, recurse into children.
if n.HasChildren() {
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
line := lineOfNode(f, c)
if line > 0 {
return line
}
}
}
return 0
}
if n.Lines().Len() > 0 {
seg := n.Lines().At(0)
return f.LineOfOffset(seg.Start)
}
// For container nodes, find the first child with lines.
if n.HasChildren() {
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
line := lineOfNode(f, c)
if line > 0 {
return line
}
}
}
return 0
}blanklinearoundlists.lastLineOfNode function · go · L131-L161 (31 LOC)internal/rules/blanklinearoundlists/rule.go
func lastLineOfNode(f *lint.File, n ast.Node) int {
// Inline nodes do not have Lines(); use Segment for Text nodes.
if t, ok := n.(*ast.Text); ok {
return f.LineOfOffset(t.Segment.Stop - 1)
}
if isInlineNode(n) {
if n.HasChildren() {
for c := n.LastChild(); c != nil; c = c.PreviousSibling() {
line := lastLineOfNode(f, c)
if line > 0 {
return line
}
}
}
return 0
}
if n.Lines().Len() > 0 {
seg := n.Lines().At(n.Lines().Len() - 1)
return f.LineOfOffset(seg.Start)
}
// For container nodes, find the last child with lines.
if n.HasChildren() {
for c := n.LastChild(); c != nil; c = c.PreviousSibling() {
line := lastLineOfNode(f, c)
if line > 0 {
return line
}
}
}
return 0
}blanklinearoundlists.Rule.Fix method · go · L168-L190 (23 LOC)internal/rules/blanklinearoundlists/rule.go
func (r *Rule) Fix(f *lint.File) []byte {
beforeSet, afterSet := r.collectBlankLineInsertions(f)
if len(beforeSet) == 0 && len(afterSet) == 0 {
result := make([]byte, len(f.Source))
copy(result, f.Source)
return result
}
var resultLines [][]byte
for i, line := range f.Lines {
lineNum := i + 1
if beforeSet[lineNum] {
resultLines = append(resultLines, []byte{})
}
resultLines = append(resultLines, line)
if afterSet[lineNum] {
resultLines = append(resultLines, []byte{})
}
}
return bytes.Join(resultLines, []byte("\n"))
}blanklinearoundlists.Rule.collectBlankLineInsertions method · go · L194-L231 (38 LOC)internal/rules/blanklinearoundlists/rule.go
func (r *Rule) collectBlankLineInsertions(f *lint.File) (beforeSet, afterSet map[int]bool) {
beforeSet = make(map[int]bool)
afterSet = make(map[int]bool)
codeLines := lint.CollectCodeBlockLines(f)
_ = ast.Walk(f.AST, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
list, ok := n.(*ast.List)
if !ok {
return ast.WalkContinue, nil
}
if _, isListItem := list.Parent().(*ast.ListItem); isListItem {
return ast.WalkContinue, nil
}
listStartLine := lineOfNode(f, list)
listEndLine := lastLineOfNode(f, list)
if codeLines[listStartLine] || codeLines[listEndLine] {
return ast.WalkContinue, nil
}
if needsBlankAdjacent(f, listStartLine, -1) {
beforeSet[listStartLine] = true
}
if needsBlankAdjacent(f, listEndLine, +1) {
afterSet[listEndLine] = true
}
return ast.WalkContinue, nil
})
return beforeSet, afterSet
}blanklinearoundlists.needsBlankAdjacent function · go · L235-L241 (7 LOC)internal/rules/blanklinearoundlists/rule.go
func needsBlankAdjacent(f *lint.File, targetLine, direction int) bool {
adjLine := targetLine + direction
if adjLine < 1 || adjLine > len(f.Lines) {
return false
}
return !isBlank(f.Lines[adjLine-1])
}catalog.renderTemplate function · go · L21-L65 (45 LOC)internal/rules/catalog/generate.go
func renderTemplate(params map[string]string, entries []fileEntry, columns ...map[string]columnConfig) (string, error) {
var buf strings.Builder
header := params["header"]
row := params["row"]
footer := params["footer"]
// Build column map from the row template if we have column constraints.
var cols map[string]columnConfig
var colMap map[int]string
if len(columns) > 0 && columns[0] != nil && len(columns[0]) > 0 {
cols = columns[0]
colMap = buildColumnMap(row)
}
if header != "" {
buf.WriteString(ensureTrailingNewline(header))
}
tmpl, err := template.New("row").Option("missingkey=zero").Parse(row)
if err != nil {
return "", err
}
for _, entry := range entries {
var rowBuf bytes.Buffer
if err := tmpl.Execute(&rowBuf, entry.fields); err != nil {
return "", err
}
rendered := rowBuf.String()
// Apply column constraints to table rows.
if cols != nil && colMap != nil {
rendered = applyColumnConstraints(rendered, cols, colMap)
}
buf.WriteStriRepobility analyzer · published findings · https://repobility.com
catalog.renderMinimal function · go · L69-L77 (9 LOC)internal/rules/catalog/generate.go
func renderMinimal(entries []fileEntry) string {
var buf strings.Builder
for _, entry := range entries {
path := entry.fields["filename"]
basename := filepath.Base(path)
buf.WriteString("- [" + basename + "](" + path + ")\n")
}
return buf.String()
}catalog.renderEmpty function · go · L80-L86 (7 LOC)internal/rules/catalog/generate.go
func renderEmpty(params map[string]string) string {
empty := params["empty"]
if empty == "" {
return ""
}
return ensureTrailingNewline(empty)
}catalog.parseColumnConfig function · go · L15-L28 (14 LOC)internal/rules/catalog/parse.go
func parseColumnConfig(raw map[string]any) map[string]columnConfig {
gc := gensection.ParseColumnConfig(raw)
if gc == nil {
return nil
}
result := make(map[string]columnConfig, len(gc))
for k, v := range gc {
result[k] = columnConfig{
maxWidth: v.MaxWidth,
wrap: v.Wrap,
}
}
return result
}