detect

package
v0.2.6 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2026 License: MIT Imports: 20 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
  • G1E — Foreign Holder
  • G2 — Stutter Names
  • G3 — Build-Tag Pair Sprawl
  • G4 — God Dependency Bag
  • G5 — Disconnected File Concerns
  • G6 — Facade Method
  • G7 — Init Coupling
  • G8 — Internal Re-Export Tunnel
  • G9 — Prefix Cluster
  • G10 — Shadow Suffix
  • G11 — Generic Filename
  • G12 — Premature Package
  • G13 — Large Cohesive File
  • G14 — Cross-Layer Orchestration

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, LayersCmd — 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 LayersCmd added in v0.2.4

func LayersCmd(f *Flags) *cobra.Command

LayersCmd returns the `layers` subcommand: configured G14 policies.

func MixedCmd

func MixedCmd(f *Flags) *cobra.Command

MixedCmd returns the `mixed` subcommand: G5 and G13.

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. It walks the filesystem directly because a loaded package only exposes files selected for the current build tags. Loaded package metadata is used only to map directories to import paths for G12 production-reuse evidence.

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 files when an init in one file reads package-level state written by an init in another. This establishes a real cross-file ordering dependency rather than merely counting independent registration inits.

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

func ScanLayerPolicy added in v0.2.4

func ScanLayerPolicy(pkgs []*packages.Package, rules []LayerPolicyRule) []audit.Finding

ScanLayerPolicy reports configured cross-layer orchestration. It is opt-in: no rules means no findings. The detector uses typed call targets so aliases and local import names do not affect its result.

func ScanMixedConcern

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

ScanMixedConcern flags very large files only when their top-level declarations form at least two substantial disconnected reference clusters. The graph includes implicit interface-implementation edges so idiomatic Go interface families remain one cohesive component.

func ScanMixedConcernWithOptions added in v0.2.4

func ScanMixedConcernWithOptions(pkgs []*packages.Package, options MixedOptions) []audit.Finding

ScanMixedConcernWithOptions runs G5 with explicit thresholds and severity.

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 ScanRoot added in v0.2.4

func ScanRoot(args []string) string

ScanRoot exposes the normalized target root for CLI configuration loading.

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.

func ValidateLayerPolicyRules added in v0.2.4

func ValidateLayerPolicyRules(rules []LayerPolicyRule) error

ValidateLayerPolicyRules rejects incomplete policy and malformed severity before package loading begins.

func ValidateMixedOptions added in v0.2.4

func ValidateMixedOptions(options MixedOptions) error

ValidateMixedOptions rejects non-positive thresholds and unknown severities.

Types

type Flags

type Flags struct {
	Tags             string
	Format           string
	Exclude          []string
	Suppress         []string
	FailOn           string
	ConfigPath       string
	LoadedConfigPath string
	Mixed            MixedOptions
	MixedSeverity    string
	LayerPolicy      []LayerPolicyRule
}

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.

type LayerPolicyRule added in v0.2.4

type LayerPolicyRule struct {
	Name                       string
	Paths                      []string
	Dependencies               []string
	GeneratedTypes             []string
	MaxCoordinatedDependencies int
	Severity                   audit.Severity
}

LayerPolicyRule is one resolved, repository-owned G14 policy. Patterns may be full import paths or module-relative globs using *, **, and ?.

type MixedOptions added in v0.2.4

type MixedOptions struct {
	MinLines                     int
	MinComponentMembers          int
	MinComponentLines            int
	MinSingleComponentComplexity int
	Severity                     audit.Severity
	CohesiveMinLines             int
}

MixedOptions controls G5's evidence floor and severity plus G13's separate cohesive-file navigation threshold. Defaults favor precision.

func DefaultMixedOptions added in v0.2.4

func DefaultMixedOptions() MixedOptions

DefaultMixedOptions returns Lagotto's precision-oriented G5 policy.

Jump to

Keyboard shortcuts

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