detect

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 11, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package detect contains every lagotto layout-smell detector and the cobra subcommand factories that expose them.

Smells

See README.md and docs/patterns/ for full descriptions, examples, and remediation guidance. The catalog at a glance:

  • G1 — Receiver Monolith
  • G1B — Decomposition Theatre
  • G1C — Aggregate Holder
  • G1D — Hidden Holder via Registry
  • G2 — Stutter Names
  • G3 — Build-Tag Pair Sprawl
  • G4 — God Dependency Bag
  • G5 — Mixed-Concern File
  • G6 — Facade Method
  • G7 — Init Coupling
  • G8 — Internal Re-Export Tunnel
  • G9 — Prefix Cluster
  • G10 — Shadow Suffix
  • G11 — Junk Drawer
  • G12 — Premature Package

Output contract

Every detector returns a slice of audit.Finding values. The CLI aggregates them into an audit.Report and serializes JSON (default) or text. JSON is the stable contract; downstream tooling depends on the field names.

Architecture

One file per detector (receivers.go, deps.go, mixed.go, …) with each detector exposing a Scan*() entry point. Cross-detector helpers live in support.go and concerns.go. The cobra subcommand factories — AuditCmd, MonolithsCmd, StutterCmd, FacadesCmd, DepsCmd, MixedCmd, FSCmd, InitsCmd, TunnelCmd — are defined in cmd.go and wired up by cmd/lagotto/main.go.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AuditCmd

func AuditCmd(f *Flags) *cobra.Command

AuditCmd returns the `audit` subcommand: run every detector and emit the aggregated report.

func DepsCmd

func DepsCmd(f *Flags) *cobra.Command

DepsCmd returns the `deps` subcommand: G4.

func FSCmd

func FSCmd(f *Flags) *cobra.Command

FSCmd returns the `fs` subcommand: G3, G9, G10, G11, G12.

func FacadesCmd

func FacadesCmd(f *Flags) *cobra.Command

FacadesCmd returns the `facades` subcommand: G6.

func InitsCmd

func InitsCmd(f *Flags) *cobra.Command

InitsCmd returns the `inits` subcommand: G7.

func MixedCmd

func MixedCmd(f *Flags) *cobra.Command

MixedCmd returns the `mixed` subcommand: G5.

func MonolithsCmd

func MonolithsCmd(f *Flags) *cobra.Command

MonolithsCmd returns the `monoliths` subcommand: G1/G1B/G1C/G1D.

func ScanDepsBag

func ScanDepsBag(pkgs []*packages.Package) []audit.Finding

ScanDepsBag finds struct types whose name matches the dependency- bag pattern and counts heterogeneous field package types.

func ScanFS

func ScanFS(root string, pkgs []*packages.Package, exclude []string) []audit.Finding

ScanFS aggregates every filesystem-level smell (G3, G9, G10, G11, G12) for each package directory under root. Filesystem detectors reason about directory listings, not AST; the loaded packages are only used to determine the directory set, with a filesystem walk fallback when no packages were loaded.

func ScanFacades

func ScanFacades(pkgs []*packages.Package) []audit.Finding

ScanFacades inspects every method body to find thin pass-throughs to a function in a different package.

A method is a facade when:

  • Its body has 1 statement that is a ReturnStmt or ExprStmt with a single CallExpr, and the callee resolves to a function in a different package.
  • Or its body has 2-3 statements where all but the final return are trivial guards/assignments and the final statement is the above pattern.

Methods on types that embed an interface in another package are flagged with reduced severity (interface-dispatch facades may be load-bearing).

func ScanInitCoupling

func ScanInitCoupling(pkgs []*packages.Package) []audit.Finding

ScanInitCoupling flags packages that have multiple `func init()` declarations spread across more than one file. Go runs init() functions in alphabetical filename order (and source order within a file), so cross-file init coupling depends on an implicit ordering rule that is fragile when files are renamed or split.

Single-file multiple init() is not flagged: the source-order rule is local and visible.

func ScanMixedConcern

func ScanMixedConcern(pkgs []*packages.Package) []audit.Finding

ScanMixedConcern flags files that mix three or more declaration groups (types, methods, validation, utilities) over the 100-line floor. The smell predicts the file is a junk drawer disguised as a module.

func ScanReExportTunnel

func ScanReExportTunnel(pkgs []*packages.Package) []audit.Finding

ScanReExportTunnel finds packages whose top-level public surface is dominated by re-exports from a single deeper package. This is the TypeScript "barrel" pattern, which is wrong in Go: it adds indirection, makes call paths harder to trace, and the package has no genuine identity of its own.

A re-export is one of:

type X = otherPkg.Y                       (type alias to another pkg)
var  X = otherPkg.Y                       (variable bound to qualified ident)
func X(args) ret { return otherPkg.X(args...) } (transparent function wrapper)

A package is flagged when ≥50% of its exported top-level decls are re-exports AND a single target package accounts for at least half of those re-exports.

func ScanReceivers

func ScanReceivers(pkgs []*packages.Package) []audit.Finding

ScanReceivers returns Receiver Monolith (G1) findings computed from the type-checker's full method set on each named struct, plus Decomposition Theatre (G1B) findings for alias clusters that pretend to split a god type without actually moving methods.

Counting via the method set (rather than source-AST receiver names) is critical: a god type that "decomposes" itself by embedding a helper struct and adding nine type aliases (`type Mutator = helper`) is the same monolith with a costume on. The method-set view sees through both tricks because Go's type system promotes methods through embedding and resolves aliases.

func ScanStutter

func ScanStutter(pkgs []*packages.Package) []audit.Finding

ScanStutter detects exported types and functions whose names start with the package name (case-insensitive at the leading segment, identifier-aware so `lanes.LaneConfig` is flagged but `lanes.Land` is not).

func StutterCmd

func StutterCmd(f *Flags) *cobra.Command

StutterCmd returns the `stutter` subcommand: G2.

func TunnelCmd

func TunnelCmd(f *Flags) *cobra.Command

TunnelCmd returns the `tunnel` subcommand: G8.

Types

type Flags

type Flags struct {
	Tags    string
	Format  string
	Exclude []string
}

Flags carries the persistent CLI flag values shared by every subcommand. cmd/lagotto/main.go binds these to cobra persistent flags; the detect package reads them at RunE time.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL