lint

package
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Jun 18, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

README

pkg/lint

Specification linting engine with pluggable rules. Validates spec trees for structural conventions.

Outstanding Questions

None at this time.

Documentation

Overview

specscore:feature/cli/spec/lint

Implements the `index-entries` rule and its --fix support. The bidirectional check (phantom links + orphan children) satisfies REQ:index-entries-bidirectional. The fixer satisfies REQ:index-entries-fix-deletes-phantom-rows (Phase 1) and REQ:index-entries-fix-inserts-orphan-rows (Phase 2). All three REQs and their ACs live under the "Features index synchronization" subsection of the cli/spec/lint feature README.

Index

Constants

View Source
const (
	FixTargetAll      = "all"
	FixTargetNoSource = "no-source"
)

Fix target sentinels. FixTargetAll is the implicit target of a bare `--fix` (run every standard fixer). FixTargetNoSource is the opt-in plan fix that rewrites a sourceless plan to `**Source:** none` — never enabled by the unscoped pass; only when explicitly named.

View Source
const CatalogPath = "docs/lint-rules.md"

CatalogPath is the canonical location of the rendered lint-rule catalog, relative to the repository root (cli/rules#req:catalog-canonical-path).

Variables

This section is empty.

Functions

func AllRuleNames

func AllRuleNames() map[string]bool

AllRuleNames returns the canonical set of known rule names, derived from the structured rule registry (the single source of truth).

func CheckRegistryParity added in v0.6.0

func CheckRegistryParity() error

CheckRegistryParity verifies that the rule registry and the set of rule IDs a checker can emit are in full parity. It compares the registry ID set (keys of the canonical registry, as returned by AllRuleNames) against the emittable ID set (the rule names a freshly built default linter registers checkers under).

A default linter (newLinter(Options{})) registers no custom checkers, so the emittable set is the built-in surface only.

It returns a non-nil error naming the offending IDs when either an orphan registry entry (an ID no checker can emit) or an unregistered emission (an ID a checker can emit that is absent from the registry) exists. On full parity it returns nil.

func FixTargetNames added in v0.10.0

func FixTargetNames() []string

FixTargetNames returns the sorted set of valid `--fix=<target>` action names: every fixer-backed rule name (both fixer-interface and check-time fixers) plus the opt-in "no-source" action. It excludes the "all" sentinel, which is always valid. Used by the CLI to validate `--fix=<targets>` and to render help.

func Migrate added in v0.7.0

func Migrate(specRoot string) ([]string, error)

Migrate performs the one-shot artifact-frontmatter-convention backfill (cli/spec/migrate): for every artifact the convention rules walk, it ensures a leading frontmatter block carrying the type's canonical `format:` URL and, for status-bearing types, a `status:` mirroring the body `**Status:**`; it then aligns the adherence-footer URL to `format:`. It is deterministic, offline, and idempotent (a conformant artifact is left byte-unchanged).

Returns the spec-root-relative, slash-separated paths of the files it changed, sorted.

func RegisterChecker

func RegisterChecker(c Checker)

RegisterChecker registers a custom checker that will run alongside built-in checkers during Lint(). Must be called before any concurrent use of Lint (typically during init or program startup).

func RenderCatalog added in v0.6.0

func RenderCatalog() string

RenderCatalog builds the full markdown lint-rule catalog from the registry.

The output is deterministic: it derives entirely from AllRules() (itself an ID-sorted copy of the registry) and carries no timestamps, host, path, or other environment-dependent content. Families are emitted in sorted order, and rules within each family are listed in ID order, so re-rendering an unchanged registry yields byte-identical output (cli/rules#req:catalog-deterministic). The document is grouped by family, each rule showing its id and description (cli/rules#req:catalog-canonical-path).

func RenderStudioToolbar

func RenderStudioToolbar(name, urlStr, host, org, repo, artifactPath string) string

RenderStudioToolbar returns the canonical toolbar line per studio-toolbar#req:toolbar-line-shape. The returned string includes the trailing LF. Callers (lint, --fix) compare or replace line 3 with this exact byte sequence.

Inputs:

  • name: studio.name (with or without dots; bold-wrap rules apply per brand-attribution-rendering / brand-attribution-no-dot / brand-attribution-multi-dot).
  • url: studio.url; MUST end in exactly one "/" — the validation is enforced upstream in projectdef.Validate(). The renderer strips the trailing "/" per url-grammar-trailing-slash before joining with the path grammar.
  • host, org, repo: resolved from specscore.yaml project.host/.org/.repo, falling back to git origin parsing.
  • artifactPath: the feature directory path from repo root, e.g. "spec/features/repo-config". MUST NOT include "/README.md".

func ResetCustomCheckers

func ResetCustomCheckers()

ResetCustomCheckers clears all registered custom checkers (for testing).

func ValidateFixTargets added in v0.10.0

func ValidateFixTargets(targets []string) error

ValidateFixTargets rejects any target that is neither the "all" sentinel nor a known fix-target name. Empty input is valid (no targets).

func ValidateRuleNames

func ValidateRuleNames(names []string) error

ValidateRuleNames checks that all names are known rules. The legacy `view-link` rule was removed by the studio-toolbar Feature; flagging it surfaces a migration message naming `studio-toolbar` as the replacement (studio-toolbar#req:studio-toolbar-lint-removes-view-link).

func WriteCatalog added in v0.6.0

func WriteCatalog(repoRoot string) error

WriteCatalog renders the catalog and writes it to CatalogPath under repoRoot, creating the parent directory if needed. It is a reusable helper for the commands that own the `--write`/`--check` behavior; it does not itself wire to any flag.

Types

type Checker

type Checker interface {
	Name() string
	Severity() string
	Check(specRoot string) ([]Violation, error)
}

Checker is the public interface for custom rule implementations. External tools can implement this to add custom rules to the linter.

type Options

type Options struct {
	SpecRoot string
	Rules    []string // enabled rules; nil = all
	Ignore   []string // disabled rules
	Severity string   // minimum severity: error, warning, info
	Fix      bool     // when true, auto-fixable violations are repaired on disk by checkers that support it
	// FixTargets names opt-in fixes to enable on top of the standard fix pass
	// (only consulted when Fix is true). These are fixes that are deliberately
	// off by default because they mask a likely authoring mistake — e.g.
	// "no-source" rewrites a plan with no source line to `**Source:** none`.
	FixTargets []string
	// CLIVersion is the running CLI's own version as a semver string (e.g.
	// "0.3.0", with optional leading "v"). Used by the dogfood-version-bump
	// rule to detect stale pins in .github/workflows/*.yml. Empty, "dev",
	// or any non-semver value disables the comparison silently.
	CLIVersion string
}

Options holds linting options.

type Result added in v0.6.0

type Result struct {
	Violations []Violation
	Fixed      []string
}

Result is the full outcome of a lint pass. Fixed is populated only when opts.Fix is true and lists the specRoot-relative paths of files whose bytes changed during the fix pass (de-duplicated, sorted). It matches how Violation.File paths are rendered (relative to opts.SpecRoot).

func LintWithResult added in v0.6.0

func LintWithResult(opts Options) (Result, error)

LintWithResult runs all enabled lint rules against the spec tree and returns both the violations and, when opts.Fix is true, the set of files the fix pass modified.

type Rule added in v0.6.0

type Rule struct {
	ID          string `json:"id" yaml:"id"`
	Description string `json:"description" yaml:"description"`
	Family      string `json:"family" yaml:"family"`
	Severity    string `json:"severity" yaml:"severity"`
}

Rule is a structured registry entry describing a single lint rule. The registry of Rule values is the single source of truth for the set of known rule names, their human-readable descriptions, the family they belong to, and the severity at which their checker reports.

Tags mirror the Violation struct style so downstream commands can emit registry entries as JSON/YAML directly.

func AllRules added in v0.6.0

func AllRules() []Rule

AllRules returns a deterministically sorted (by ID) copy of the registry entries. Downstream consumers (the `rules` command, the catalog renderer) read structured rules through this accessor.

type Violation

type Violation struct {
	File     string `json:"file" yaml:"file"`
	Line     int    `json:"line" yaml:"line"`
	Severity string `json:"severity" yaml:"severity"`
	Rule     string `json:"rule" yaml:"rule"`
	Message  string `json:"message" yaml:"message"`
	// FixTarget, when non-empty, names the `--fix=<target>` action that repairs
	// this specific violation (e.g. "no-source"). Only set on violations a fixer
	// can actually resolve; drives the "How to fix" hint in text output.
	FixTarget string `json:"fix_target,omitempty" yaml:"fix_target,omitempty"`
}

Violation represents a single linting violation.

func CheckIdeas

func CheckIdeas(specRoot string, fix bool) ([]Violation, error)

CheckIdeas runs all idea lint rules. If fix is true, auto-fixable violations are repaired on disk and omitted from the returned slice.

func FilterBySeverity

func FilterBySeverity(violations []Violation, minSeverity string) []Violation

FilterBySeverity filters violations to those at or above the minimum severity.

func Lint

func Lint(opts Options) ([]Violation, error)

Lint runs all enabled lint rules against the spec tree.

Jump to

Keyboard shortcuts

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