| id | 120 |
|---|---|
| title | Unify glob matcher and field naming across mdsmith |
| status | ✅ |
| model | sonnet |
| summary | Pick one glob library and one field name (`files:` vs `glob:`), migrate `ignore:`, `overrides:`, `kind-assignment:`, `<?catalog?>`, and CLI argument expansion to use them consistently, and deprecate the displaced surface. |
Use one glob matcher and one field name across every glob surface in mdsmith. Config sections, directives, and CLI argument expansion should accept the same syntax. Users learn the rules once.
Today three independent glob systems coexist, summarized in docs/reference/globs.md:
| Surface | Matcher | Field name | !-exclusion |
|---|---|---|---|
ignore: / overrides:.files / kind-assignment:.files |
gobwas/glob |
files: |
yes (added in plan 96) |
<?catalog?> |
doublestar |
glob: |
yes |
| CLI argument expansion | stdlib filepath.Glob |
positional | no |
The split surfaces concretely as:
**recursion works in<?catalog?>but is matcher- dependent forignore:patterns.- Brace expansion (
{a,b}) works in<?catalog?>but not in config. - The CLI accepts none of the above; users have to lean on shell expansion.
- The same list-of-patterns concept is called
files:in some places andglob:in others.
Plan 96 added !-prefix exclusion to the config matcher
and documented the current state. Unifying the three
surfaces is a larger change that deserves its own plan.
doublestar is the most capable of the three. It
supports **, brace expansion, character classes, and a
well-defined matching algorithm. It already powers
<?catalog?> with the !-exclusion semantics plan 96
wired into config. Standardizing on it preserves catalog
behavior. Config and CLI gain a strict superset of what
they support today.
The shared matcher lives in a new package
(internal/globpath or a sibling) and exposes:
Match(pattern, path) bool— single-pattern match with the same path/cleaned-path/basename fallbacks the config matcher uses today.MatchAny(patterns, path) bool— list match with!-prefix exclusion (the same semantics as plan 96'sglobMatchAny).SplitIncludeExclude(patterns)— for callers that need the split form (catalog uses this today).
glob: is the better fit. It names the syntactic
artifact (a glob pattern) rather than the result (a
file list), and <?catalog?> and <?include?> already
use a glob-style vocabulary. files: is in older
config blocks but is the easier side to migrate because
it only appears in two keys (overrides:, kind- assignment:).
Migration plan:
- Add
glob:as the canonical key on each block, accepting the same list shape. - Keep
files:as a deprecated alias that loads into the same field; emit a deprecation warning when it is used. - Update
mdsmith initand the docs to writeglob:. - Schedule removal of
files:for the release after the deprecation window.
Replace the filepath.Glob call in
resolveGlob with the
shared matcher. CLI args now accept the same syntax as
config — including ** and !-exclusion — and stop
silently failing on patterns the standard library
doesn't grasp.
- Land the shared matcher package (new
internal/globpath) withMatch,MatchAny, andSplitIncludeExclude. Cover include-only, exclude- only, mixed-order,**recursion, and brace expansion in unit tests. - Migrate
internal/config/ignore.goto call the shared matcher; remove thegobwas/globdependency frominternal/config/. - Migrate
internal/rules/catalog/rule.goto call the shared matcher; remove its privatesplitIncludeExclude. - Migrate
internal/lint/files.go:347resolveGlobto call the shared matcher. - Add
glob:as the canonical key onoverrides:andkind-assignment:entries. Keepfiles:as a deprecated alias and surface a deprecation warning viacfg.Deprecations. - Update
mdsmith initto emitglob:; update docs/reference/globs.md, docs/guides/file-kinds.md, themdsmith help kindspage, and any rule READMEs / fixtures that referencefiles:. - Add a regression test: a config that uses
files:loads correctly and produces a deprecation warning; the same config rewritten withglob:produces no warning and the same effective rule config. - Drop
gobwas/globfromgo.modonce no callers remain.
- Every glob surface in mdsmith — config, catalog,
CLI argument expansion — resolves through one
shared matcher;
gobwas/globand the stdlibfilepath.Globare no longer imported by production code. -
**recursion and brace expansion work on all surfaces (covered by tests).!-prefix exclusion works on config and directive surfaces; CLI positional-argument exclusion is not yet implemented — useignore:in.mdsmith.ymlinstead. -
overrides:andkind-assignment:acceptglob:as the canonical key.files:continues to work and emits a deprecation warning naming the offending block. -
mdsmith initwritesglob:; existingfiles:configs in the repo are migrated. - docs/reference/globs.md
collapses the three-surface table into a single
surface and documents the deprecation timeline
for
files:. - All tests pass:
go test ./... -
go tool golangci-lint runreports no issues