Documentation
¶
Overview ¶
Package codemod holds forge's deterministic rewrites of a project's OWN files: the mechanical half of a release that changed a shape the project wrote down. Each codemod is keyed to the release that broke the shape — the same key its migration skill (skills/forge/migrations/<version>) carries — and is reachable two ways:
- `forge fix <name>` runs one on request (`--dry-run` lists what it would rewrite);
- `forge project upgrade` runs every codemod marked Upgrade whose release the project's baseline predates, before it touches a template.
A codemod is idempotent and decides from the tree, never from a version: on a project that does not have the old shape it rewrites nothing and reports nothing. That is what lets upgrade run it on every crossing, and what makes a second run a no-op.
The intent-bearing half of a migration — the choices only a person or an agent can make — stays prose, in the migration skill. A codemod that cannot decide something says so in its report rather than guessing.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Codemod ¶
type Codemod struct {
// Name is the `forge fix <name>` subcommand.
Name string
// Version is the release that broke the shape this rewrites. It names
// the migration skill that tells the rest of the story
// (skills/forge/migrations/<Version>).
Version string
// Short is the one-line summary `forge fix --help` prints.
Short string
// Long is the subcommand's help body.
Long string
// Upgrade marks a codemod `forge project upgrade` runs on its own when
// the project's baseline predates Version. Only a rewrite that keeps the
// program's meaning exactly — a rename, a moved symbol — qualifies; a
// restructuring is run on request, after the person running it has read
// what it does.
Upgrade bool
// CleanTree marks a codemod that replaces files wholesale: `forge fix`
// refuses to run it over uncommitted changes (unless --allow-dirty), so
// `git diff` is the review and `git checkout .` the undo.
CleanTree bool
// Scoped marks a codemod that honours Options.Scope: `forge fix <name>
// --scope <path>` rewrites only the files under the paths named, while
// whatever it analyses to decide a rewrite still reads the whole
// project. A codemod whose rewrite is one decision over the whole tree
// (a restructuring) leaves it false, and `forge fix` offers no --scope.
Scoped bool
// Run rewrites the project at dir, as opts asks.
Run func(dir string, opts Options) (Report, error)
}
Codemod is one deterministic rewrite.
type Options ¶
type Options struct {
// Write false changes nothing: the run reports what it would rewrite.
Write bool
// Scope restricts the files the run may rewrite (and reports on) to
// those under its paths. Nil is the whole project. Only a Scoped
// codemod is handed one.
Scope *Scope
}
Options is how one codemod run is asked to behave.
type Report ¶
type Report struct {
// Rewrites are the mechanical rewrites, one human-readable line each
// ("internal/app/lifecycle.go: lifecyclekit.Run → operatorkit.Run"),
// in the order they were made.
Rewrites []string
// Next is what the codemod could not decide, as the exact edits left to
// make, in order. Empty when the rewrite is the whole job.
Next []string
// Blocked are the shapes that stop a restructuring codemod from
// writing anything — each with its file:line and the edit that clears
// it. A codemod that reports any rewrites nothing: a conversion that
// compiles but silently changes what a process does is worse than none.
Blocked []string
// Verify are the commands that prove the result. Empty means the
// default: go build, forge generate, forge lint.
Verify []string
}
Report is what one codemod run did, or (dry run) would do.
type Scope ¶
type Scope struct {
// contains filtered or unexported fields
}
Scope is a set of project-relative paths — directories or files — that bounds the files a run rewrites. Parallel lanes in one checkout each run a codemod over their own slice, as `forge lint --scope` lints one. A nil *Scope is the whole project, and every method is nil-safe.
func ParseScope ¶
ParseScope validates raw scope paths against the project at root. Each must exist and lie inside the project: a typo would otherwise scope the run to nothing and report it clean.
func (*Scope) Contains ¶
Contains reports whether rel — a project-relative path — lies under the scope. Everything does under a nil scope.