Documentation
¶
Overview ¶
Package autoconfigure provides the shared foundation for linter auto-configuration tools (golangci-lint-auto-configure, oxlint-auto-configure, and future additions like biome-auto-configure).
The two existing tools diverge on their domain-specific concepts — Go project shape (CLI/Library/Web) vs JS framework (React/Next/Vue) — and on their priority models (4-tier enum vs profile presets). Those differences are legitimate and stay in each tool.
What they reinvent identically is the surrounding plumbing:
- Reading and writing YAML/JSON config files (round-trip)
- Emitting findings for config issues (priority → Severity, fix → suggestion)
- Diffing two configs into a typed change list (maps, sets, blobs)
- Discovering which of several recognized config filenames exists
- Deriving a generate-if-missing provider lifecycle from one spec (bootstrap)
- Wiring into BuildFlow as a Detector + Repairer
This package owns that plumbing once. Adding a third auto-configurer becomes a config-schema exercise, not a from-scratch build.
The package uses encoding/json/v2 (standard since Go 1.27).
Index ¶
- Variables
- func BootstrapProviderFromSpec[T any](spec BootstrapSpec[T]) (toolsdk.Spec, error)
- func FindingFromIssue(toolName finding.ToolName, issue ConfigIssue) (finding.Finding, error)
- func FindingsFromIssues(toolName finding.ToolName, issues []ConfigIssue) ([]finding.Finding, error)
- func FirstExisting(root string, candidates ...string) (string, bool)
- func FormatDiff(changes []Change) string
- func ProviderFromSpec(spec ProviderSpec) (toolsdk.Spec, error)
- func StringValue(v any) string
- func Summary(changes []Change) string
- func WorkingDir(ctx context.Context) string
- type BootstrapSpec
- type Change
- type ConfigError
- func LoadJSON[T any](path string) (*T, *ConfigError)
- func MarshalJSONIndented(v any) ([]byte, *ConfigError)
- func ParseJSON[T any](data []byte) (*T, *ConfigError)
- func ReadConfig(path string) ([]byte, *ConfigError)
- func SaveJSON(path string, v any) (bool, *ConfigError)
- func SaveJSONBytes(path string, data []byte) (bool, *ConfigError)
- type ConfigIssue
- type Kind
- type Op
- type ProviderSpec
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrNameRequired = errors.New("autoconfigure: ProviderFromSpec: Name must not be empty") ErrDescriptionRequired = errors.New("autoconfigure: ProviderFromSpec: Description must not be empty") ErrAnalyzeRequired = errors.New("autoconfigure: ProviderFromSpec: Analyze must not be nil") )
Validation sentinels returned by ProviderFromSpec when a required field is missing. The messages are identical to the pre-sentinel dynamic errors, so callers matching on text keep working; new callers should match with errors.Is instead.
var ( ErrConfigFileRequired = errors.New("autoconfigure: BootstrapProviderFromSpec: ConfigFile must not be empty") ErrGenerateRequired = errors.New("autoconfigure: BootstrapProviderFromSpec: Generate must not be nil") ErrCompareRequired = errors.New("autoconfigure: BootstrapProviderFromSpec: Compare must not be nil") )
Validation sentinels returned by BootstrapProviderFromSpec when a required field is missing. Match with errors.Is.
var ErrNoRepair = errors.New("autoconfigure: tool does not support auto-repair")
ErrNoRepair is the pre-bridge sentinel for "this tool does not support auto-repair", kept so pre-v1 code referencing it keeps compiling.
Deprecated: the canonical suggest-only signal is structural. ProviderFromSpec leaves toolsdk.Spec.Repair nil when ProviderSpec.Repair is nil, and BuildFlow reads that directly. This SDK never returns ErrNoRepair, and returning it from a custom Repairer is a repair failure for BuildFlow, not a suggest-only signal. Removed at v1.
Functions ¶
func BootstrapProviderFromSpec ¶ added in v0.5.0
func BootstrapProviderFromSpec[T any](spec BootstrapSpec[T]) (toolsdk.Spec, error)
BootstrapProviderFromSpec converts a BootstrapSpec into the canonical BuildFlow provider contract, deriving the full bootstrap lifecycle:
- Detect emits exactly one warning when the config is missing under every discovery name AND Recognizable (when set) accepts the project.
- Repair generates and writes the config only when it is missing, honoring the dry-run flag; an existing config yields a keep description.
- HealthCheck parses the existing ConfigFile, regenerates the expected config, applies NormalizeExpected, and reports Compare's changes as an advisory error wrapping the drift sentinel with the fix command.
Trigger and DependsOn stay zero; set them on the returned Spec when needed. Inputs derive from ConfigFiles (falling back to ConfigFile), matching ProviderFromSpec.
Example ¶
spec := BootstrapSpec[map[string]string]{
Name: "fake-auto-configure",
Description: "generates .fakerc.json for recognizable projects",
ConfigFile: ".fakerc.json",
ConfigFiles: []finding.FilePath{".fakerc.json", ".fakerc.jsonc"},
MissingRule: "FAKE_CONFIG_MISSING",
FixCommand: "fake-auto-configure configure",
CountLabel: "rules",
Generate: func(ctx context.Context) (map[string]string, int, error) {
return map[string]string{"plugins": "react"}, 3, nil
},
Compare: func(existing, expected map[string]string) []Change {
return DiffMaps(existing, expected, "")
},
}
provider, err := BootstrapProviderFromSpec(spec)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(provider.Name, provider.Inputs)
fmt.Println(provider.Detect != nil, provider.Repair != nil, provider.HealthCheck != nil)
Output: fake-auto-configure [.fakerc.json .fakerc.jsonc] true true true
func FindingFromIssue ¶
FindingFromIssue converts a ConfigIssue to a finding.Finding with the given tool name. The fix strategy is issue.FixStrategy when set; otherwise a non-empty Suggestion yields FixStrategySuggest (so BuildFlow's repair loop can surface it) and an empty one yields FixStrategyNone, set explicitly to avoid the empty-string zero-value split brain.
When issue.Line is 0 (unknown), the finding receives a file-level Position via finding.FilePos rather than a fabricated line number.
Example ¶
issue := ConfigIssue{
Rule: finding.RuleName("missing-linter"),
Message: "errcheck is not enabled",
Severity: finding.SeverityWarning,
File: finding.FilePath(".golangci.yml"),
Line: 5,
Suggestion: "add errcheck to enabled linters",
}
f, err := FindingFromIssue(finding.ToolName("golangci-autoconfigure"), issue)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(f.Rule, f.Severity, f.FixStrategy)
Output: missing-linter warning suggest
func FindingsFromIssues ¶
FindingsFromIssues converts a slice of ConfigIssues to findings. If any issue fails to convert, the entire batch fails and the cause is wrapped.
func FirstExisting ¶ added in v0.4.0
FirstExisting joins each candidate with root, in order, and returns the first that exists. When none exists it returns the FIRST candidate joined with root and false, so callers always hold a usable canonical path (the default write target). Returns "", false when no candidate is given.
Example ¶
dir, _ := os.MkdirTemp("", "example")
defer func() { _ = os.RemoveAll(dir) }()
_ = os.WriteFile(filepath.Join(dir, ".oxlintrc.json"), []byte("{}"), 0o644)
path, found := FirstExisting(dir, ".oxlintrc.json", ".oxlintrc.jsonc")
fmt.Println(filepath.Base(path), found)
missing, found := FirstExisting(dir, ".eslintrc.json", ".eslintrc.jsonc")
fmt.Println(filepath.Base(missing), found)
Output: .oxlintrc.json true .eslintrc.json false
func FormatDiff ¶ added in v0.4.0
FormatDiff renders changes as a unified-diff-flavored listing, one change per line, sorted by Path: "+ path: new", "- path: old", and "~ path: old → new". Returns "No changes." for an empty slice. Every line ends with a newline.
func ProviderFromSpec ¶
func ProviderFromSpec(spec ProviderSpec) (toolsdk.Spec, error)
ProviderFromSpec converts a ProviderSpec into the canonical BuildFlow provider contract: go-finding's toolsdk.Spec (module github.com/larsartmann/go-finding/toolsdk). The result can be handed to toolsdk.Register for BuildFlow discovery, or its Trigger / DependsOn fields can be adjusted first — the returned Spec is a plain value.
Field mapping:
- Name, Description pass through verbatim; Name also becomes the tool name stamped onto every finding the Detect adapter emits.
- ConfigFiles (falling back to ConfigFile alone) becomes Inputs: the config files are what the tool reads. Every recognized filename is an Input, not just the write target, so BuildFlow re-runs the tool when any of them appears or changes — including user-curated formats the tool must never stomp.
- Analyze is wrapped as a finding.Detector that converts each ConfigIssue via FindingFromIssue.
- A non-nil Repair is wrapped as a toolsdk.Repairer; a nil Repair stays nil, the canonical signal for a suggest-only tool (suggestions still flow through findings carrying FixStrategySuggest).
- Trigger and DependsOn have no ProviderSpec equivalent and stay zero; set them on the returned Spec when needed.
Validation errors name the offending field: Name, Description, and Analyze are all required.
Example ¶
spec := ProviderSpec{
Name: "golangci-autoconfigure",
Description: "keeps .golangci.yml aligned with the project shape",
ConfigFile: ".golangci.yml",
Analyze: func(ctx context.Context) ([]ConfigIssue, error) {
return []ConfigIssue{{Rule: "missing-linter", Message: "errcheck is not enabled"}}, nil
},
Repair: func(ctx context.Context) (string, error) {
return "enabled errcheck", nil
},
}
provider, err := ProviderFromSpec(spec)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(provider.Name, provider.Inputs, provider.Repair != nil)
fmt.Println(provider.Detect.Name())
Output: golangci-autoconfigure [.golangci.yml] true golangci-autoconfigure
func StringValue ¶ added in v0.4.0
StringValue renders a config value for diff display: strings display bare; anything else displays as compact deterministic JSON (map keys sorted, so the same value always renders to the same bytes); values that cannot be marshaled fall back to a %v print.
func Summary ¶ added in v0.4.0
Summary renders a one-line human-readable tally of the changes: "Added: 1, Modified: 2, Removed: 3".
func WorkingDir ¶ added in v0.4.0
WorkingDir returns the working directory carried by ctx via finding.WorkingDirFromContext, falling back to "." (the process working directory) when the context carries none — the convention BuildFlow providers follow so the WithWorkingDir fan-out works identically across tools. Analyze/Repair closures should resolve config paths through this helper instead of hand-rolling the fallback.
Example ¶
ctx := finding.WithWorkingDir(context.Background(), "/repo") fmt.Println(WorkingDir(ctx), WorkingDir(context.Background()))
Output: /repo .
Types ¶
type BootstrapSpec ¶ added in v0.5.0
type BootstrapSpec[T any] struct { Name string Description string // ConfigFile is the canonical config file the tool writes (the drift // health check also reads only this name: other discovery names are // user-curated formats the tool never writes). ConfigFile finding.FilePath // ConfigFiles lists every config filename the tool recognizes, in // priority order. An existing file under ANY of these names suppresses // Detect and Repair (generating next to a curated alternative-format // config could shadow it). Defaults to ConfigFile alone. ConfigFiles []finding.FilePath // MissingRule names the missing-config Detect finding (domain-specific, // e.g. "OXLOPT_CONFIG_MISSING"). Defaults to "CONFIG_MISSING". MissingRule finding.RuleName // FixCommand is the user-runnable command that regenerates the config // (e.g. "oxlint-auto-configure configure"); woven into Detect // suggestions and health-check messages. Empty keeps the messages // repair-generic. FixCommand string // CountLabel names Generate's count in repair descriptions (e.g. // "rules" renders "wrote .oxlintrc.json (870 rules)"). Empty omits the // count. CountLabel string // Recognizable gates Detect: when it reports false the project is not // one this tool configures and no finding is emitted. Nil means every // project counts. Recognizable func(ctx context.Context) (bool, error) // Generate produces the canonical config for the current project plus a // domain count for repair descriptions (pass 0 to omit). Generate func(ctx context.Context) (T, int, error) // Marshal renders T to the exact file bytes, including any trailing // newline the tool's format carries. Nil defaults to // MarshalJSONIndented (no trailing newline). Marshal func(T) ([]byte, *ConfigError) // Parse reads existing config bytes into T. Nil defaults to ParseJSON[T]. Parse func(data []byte) (T, *ConfigError) // NormalizeExpected adjusts the freshly generated expected config to // honor user customizations carried by the existing config (e.g. // preserved external-plugin blocks), so deliberate customization does // not read as drift. Nil compares as generated. NormalizeExpected func(existing, expected T) T // Compare projects two parsed configs onto the diff engine and is what // the drift health check reports. Required: the projection is domain // knowledge (which fields carry policy meaning) the SDK cannot guess. Compare func(existing, expected T) []Change }
BootstrapSpec describes a bootstrap-mode auto-configurer: a tool whose job is to generate its config file when it is missing, never to modify an existing one, and to report drift advisorially. BootstrapProviderFromSpec derives the full toolsdk lifecycle (Detect / Repair / HealthCheck) from it.
It is deliberately a separate type from ProviderSpec rather than a Generate field on it: Analyze/Repair specs and bootstrap specs are two different lifecycles, and one struct offering both would invite split-brain specs where the chosen mode is ambiguous. A bootstrap tool uses this type; a config-auditing tool uses ProviderSpec.
The zero value is not usable; Name, Description, ConfigFile, Generate, and Compare are required (validation returns exported sentinels matchable with errors.Is).
type Change ¶ added in v0.4.0
Change is one difference between two linter config versions. Path is the setting identifier (a dotted path like "rules.no-console" or a prefixed name like "plugin:import" — the comparator's caller chooses the scheme via its prefix argument). Old is empty for KindAdded; New is empty for KindRemoved; both are set for KindModified.
func DiffBlobs ¶ added in v0.4.0
DiffBlobs compares two lists of pre-canonicalized blob strings (for example, each config overrides block marshalled to canonical JSON) with set semantics: order is ignored and exact duplicates collapse, because list order carries no policy meaning for these blocks. The canonical blob string itself serves as both the Path suffix and the displayed value. The result is sorted by Path.
func DiffMaps ¶ added in v0.4.0
DiffMaps compares two string maps and returns one Change per key that was added, removed, or whose value differs. Keys are prefixed with prefix (pass "" for bare keys). The result is sorted by Path, so output is deterministic across runs regardless of map iteration order.
Example ¶
before := map[string]string{"no-console": "off", "no-debugger": "off"}
after := map[string]string{"no-console": "warn"}
changes := DiffMaps(before, after, "rules.")
fmt.Println(Summary(changes))
fmt.Print(FormatDiff(changes))
Output: Added: 0, Modified: 1, Removed: 1 ~ rules.no-console: off → warn - rules.no-debugger: off
func DiffSets ¶ added in v0.4.0
DiffSets compares two string slices with set semantics: duplicates collapse and order is ignored (a pure reorder is not a change). Each item present in only one side becomes a Change with Path = prefix + item and the item itself as the value. The result is sorted by Path.
type ConfigError ¶
type ConfigError struct {
// Op is the operation that failed.
Op Op
// Path is the config file path involved.
Path string
// Err is the underlying cause, never nil for a returned ConfigError.
Err error
}
ConfigError describes a failure while reading, parsing, or writing a linter config file. It wraps the underlying cause with the operation attempted and the file path, so callers can produce precise diagnostics or branch with errors.Is / errors.As without parsing error strings.
Op follows os.PathError's convention: "read", "unmarshal", "marshal", "mkdir", or "write". The underlying cause is reachable via the exported Err field and through the Is / As methods (see below), so both errors.Is(err, fs.ErrNotExist) and errors.AsType[*jsontext.SyntacticError](err) still work against a *ConfigError. (The jsonv2 unmarshaler emits *jsontext.SyntacticError for malformed input; v1's json.SyntaxError is the legacy equivalent.)
func LoadJSON ¶
func LoadJSON[T any](path string) (*T, *ConfigError)
LoadJSON reads and unmarshals a JSON config file into a new *T.
Example ¶
dir, _ := os.MkdirTemp("", "example")
defer func() { _ = os.RemoveAll(dir) }()
path := filepath.Join(dir, ".oxlintrc.json")
_ = os.WriteFile(path, []byte(`{"linters":["errcheck","gofmt"]}`), 0o644)
cfg, err := LoadJSON[exampleLintConfig](path)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(cfg.Linters)
Output: [errcheck gofmt]
func MarshalJSONIndented ¶ added in v0.4.0
func MarshalJSONIndented(v any) ([]byte, *ConfigError)
MarshalJSONIndented marshals v with the SDK's canonical options: deterministic map-key ordering (byte-stable output across runs) and 2-space indentation. It is the helper behind SaveJSON; config writers that need the bytes themselves (for example to append a trailing newline before SaveJSONBytes) use it instead of hand-copying these options.
Example ¶
data, err := MarshalJSONIndented(map[string][]string{"categories": {"correctness"}})
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("%s", data)
Output: { "categories": [ "correctness" ] }
func ParseJSON ¶ added in v0.4.0
func ParseJSON[T any](data []byte) (*T, *ConfigError)
ParseJSON unmarshals JSON bytes into a new *T. It is the byte-level counterpart of LoadJSON for callers that already read (or generated) the bytes themselves. The returned *ConfigError uses OpUnmarshal and carries no Path: the bytes did not come from a file this helper knows about.
Example ¶
cfg, err := ParseJSON[exampleLintConfig]([]byte(`{"linters":["errcheck"]}`))
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(cfg.Linters)
Output: [errcheck]
func ReadConfig ¶
func ReadConfig(path string) ([]byte, *ConfigError)
ReadConfig reads a config file's raw bytes. YAML parsing is deliberately left to each tool (different YAML libraries: golangci uses yaml.v3 / v4, oxlint may use go-yaml) — this helper covers the shared read + existence check so both tools stop hand-writing os.ReadFile with the same error wrapping.
func SaveJSON ¶
func SaveJSON(path string, v any) (bool, *ConfigError)
SaveJSON marshals v to indented JSON and writes it to path atomically, creating parent directories: MarshalJSONIndented followed by SaveJSONBytes. Map keys are emitted in sorted order (json.Deterministic), so byte output is stable across runs: the write is idempotent — if the marshalled content is byte-identical to the existing file, the write is skipped entirely (no mtime bump, no spurious diff). Otherwise the file is replaced via an fsync'd temp-file + atomic rename, so a crash cannot truncate the config. Race-safe: a concurrent modification between the content check and the rename surfaces as a non-nil *ConfigError wrapping atomicwrite.ErrConcurrentModification.
The changed return reports whether the file was actually written: false means the on-disk content already matched and the write was skipped. Repair flows use it to distinguish "config updated" from "config already correct".
Indented output is used because linter configs are typically human-edited. The output carries no trailing newline; callers whose format needs one use MarshalJSONIndented + SaveJSONBytes directly.
Example ¶
dir, _ := os.MkdirTemp("", "example")
defer func() { _ = os.RemoveAll(dir) }()
path := filepath.Join(dir, "nested", ".oxlintrc.json")
cfg := exampleLintConfig{Linters: []string{"errcheck", "gofmt"}}
changed, err := SaveJSON(path, cfg)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("changed:", changed)
data, _ := os.ReadFile(path)
fmt.Println(string(data))
Output: changed: true { "linters": [ "errcheck", "gofmt" ] }
func SaveJSONBytes ¶ added in v0.4.0
func SaveJSONBytes(path string, data []byte) (bool, *ConfigError)
SaveJSONBytes writes raw bytes to path atomically, creating parent directories, and reports whether the file content changed (false means the on-disk content already matched and the write was skipped). It is byte-faithful: no newline is appended or trimmed — whether config files end with a trailing newline is the caller's contract. Combine with MarshalJSONIndented plus a manual '\n' append to reproduce a tool's existing file format exactly.
Crash-durable like SaveJSON: fsync'd temp file + atomic rename, so a crash cannot truncate the config. Race-safe: a concurrent modification between the content check and the rename surfaces as a non-nil *ConfigError wrapping atomicwrite.ErrConcurrentModification.
Example ¶
dir, _ := os.MkdirTemp("", "example")
defer func() { _ = os.RemoveAll(dir) }()
path := filepath.Join(dir, ".oxlintrc.json")
data, err := MarshalJSONIndented(exampleLintConfig{Linters: []string{"errcheck"}})
if err != nil {
fmt.Println("error:", err)
return
}
// Trailing newline is the caller's contract: append it to match the
// tool's existing file format.
changed, err := SaveJSONBytes(path, append(data, '\n'))
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("changed:", changed)
Output: changed: true
func (*ConfigError) As ¶
func (e *ConfigError) As(target any) bool
func (*ConfigError) Error ¶
func (e *ConfigError) Error() string
func (*ConfigError) Is ¶
func (e *ConfigError) Is(target error) bool
func (*ConfigError) Unwrap ¶
func (e *ConfigError) Unwrap() error
Unwrap, Is, and As expose the wrapped cause for standard error-chain traversal. Callers can use errors.Is(err, fs.ErrNotExist), errors.AsType[*jsontext.SyntacticError](err), or errors.Unwrap(err) interchangeably.
type ConfigIssue ¶
type ConfigIssue struct {
// Rule is the issue's rule identifier (e.g. "missing-linter", "wrong-priority").
Rule finding.RuleName
// Message describes the problem for the user.
Message string
// Severity rates how serious the issue is.
Severity finding.Severity
// File is the config file path (for Position).
File finding.FilePath
// Line is the 1-based line number in the config file (0 if unknown).
Line int
// Suggestion is the recommended fix text (empty if no auto-fix).
Suggestion string
// Confidence is the issue's confidence. Zero value (ConfidenceNone == 0)
// means unset: the finding keeps the builder default (ConfidenceFull),
// matching pre-extension behavior. Note this makes an explicit
// ConfidenceNone unrepresentable through ConfigIssue; adjust the finding
// afterwards if that level is genuinely needed.
Confidence finding.Confidence
// FixStrategy overrides the default strategy selection: nil (the default)
// picks FixStrategySuggest when Suggestion is non-empty and
// FixStrategyNone otherwise. Set it for issues whose repair is directly
// applicable (FixStrategyDirect) rather than suggestion-only.
FixStrategy *finding.FixStrategy
}
ConfigIssue describes a single problem found in a linter config file. Auto-configurers produce a slice of these; FindingFromIssue converts each to a finding.Finding that BuildFlow can aggregate and gate repairs on.
type Kind ¶ added in v0.4.0
type Kind string
Kind classifies a Change: a setting was added, removed, or modified. There is deliberately no "unchanged" kind: an unchanged setting is the absence of a Change, not a Change with a dead state.
const ( // KindAdded marks a setting that exists only in the after config. KindAdded Kind = "added" // KindRemoved marks a setting that exists only in the before config. KindRemoved Kind = "removed" // KindModified marks a setting that exists in both configs with // different values. KindModified Kind = "modified" )
type Op ¶
type Op string
Op identifies the operation that failed during config I/O. It mirrors the convention from os.PathError: a short, lowercase verb.
type ProviderSpec ¶
type ProviderSpec struct {
Name string
Description string
// ConfigFile is the canonical config file the tool writes (e.g.
// ".golangci.yml", ".oxlintrc.json"). When ConfigFiles is empty it is
// also the only discovery candidate.
ConfigFile finding.FilePath
// ConfigFiles lists every config filename the tool recognizes, in
// priority order (e.g. ".oxlintrc.json", ".oxlintrc.jsonc",
// "oxlint.config.json"). An existing file under ANY of these names means
// the project already carries a config, including user-curated formats
// the tool must not stomp. ProviderFromSpec derives Inputs from
// ConfigFiles when set, falling back to [ConfigFile]. Both fields stay:
// ConfigFile names the write target, ConfigFiles the discovery set.
ConfigFiles []finding.FilePath
// Analyze inspects the config and returns issues. The working directory
// is available via finding.WorkingDirFromContext(ctx).
Analyze func(ctx context.Context) ([]ConfigIssue, error)
// Repair, if non-nil, rewrites the config to fix the issues. Returns a
// human-readable description of what changed. When nil, the spec is
// suggest-only: ProviderFromSpec leaves toolsdk.Spec.Repair nil, the
// canonical signal that BuildFlow should not attempt repairs.
Repair func(ctx context.Context) (string, error)
}
ProviderSpec is the shape an auto-configurer supplies to wire into BuildFlow. It speaks the auto-configurer's domain language: Analyze reports ConfigIssues against the managed config file, Repair describes what was rewritten.
ProviderFromSpec converts a ProviderSpec into the canonical BuildFlow provider contract, go-finding's toolsdk.Spec, ready for toolsdk.Register. The Analyze and Repair closures are also usable standalone without any BuildFlow wiring.
func (ProviderSpec) HasRepair ¶
func (s ProviderSpec) HasRepair() bool
HasRepair reports whether this spec supports auto-repair.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
jsondeterminism
command
Command jsondeterminism runs the SDK's jsondeterminism analyzer as a go vet-compatible vettool, so repositories can enforce byte-stable json.Marshal output without a golangci-lint plugin build:
|
Command jsondeterminism runs the SDK's jsondeterminism analyzer as a go vet-compatible vettool, so repositories can enforce byte-stable json.Marshal output without a golangci-lint plugin build: |
|
Package determinism provides a go/analysis analyzer that flags encoding/json/v2 Marshal calls lacking an explicit determinism option.
|
Package determinism provides a go/analysis analyzer that flags encoding/json/v2 Marshal calls lacking an explicit determinism option. |