feat(fix): auto-apply ignoreExports rules to fallow config (closes #330)#366
Merged
Conversation
`fallow fix` can now apply the `add-to-config` action for duplicate-export
findings directly to the user's fallow config, instead of just emitting a
paste-ready snippet. The action flips from `auto_fixable: false` to
`auto_fixable: true` whenever a config file exists at the project root;
with no config, fix skips with a clear `Run 'fallow init' to create one`
message. Unblocks shadcn / Radix / bits-ui-style namespace-barrel projects
where users had to hand-paste 30+ ignoreExports entries.
Writer
* `fallow_config::add_ignore_exports_rule(path, entries)` covers all four
supported config formats atomically:
- `.json` / `.jsonc` via `jsonc-parser` CST (format-preserving;
dprint-author crate).
- `.toml` / `.fallow.toml` via `toml_edit` (used by cargo itself).
* Merge semantics: append-only, dedupe on exact `file` match, no reorder,
no replace. Absolute existing entries dedupe against the writer's
relative emissions when they resolve under the config dir.
* Workspace path re-anchoring: when the config lives in a workspace subdir
(e.g. `packages/ui/.fallowrc.json`), emitted paths are relative to that
config's directory.
* CRLF / LF round-trip: detect the existing file's line endings and
preserve them on emit (normalize-then-emit so the CST library's own
CRLF preservation is not doubled into `\r\r\n`).
* UTF-8 BOM round-trip: strip a leading BOM before parse (jsonc-parser
rejects it; toml_edit silently drops it on emit) and re-prepend on
emit. Also stripped in the main config loader so Windows-authored
configs parse cleanly.
* Symlink-safe writes: `atomic_write` canonicalizes the target before
persisting so configs mounted as symlinks (common in Docker setups)
get their target updated rather than being replaced with a regular
file.
* All `json_comments::StripComments` parse sites replaced with
`jsonc-parser` so reads and writes share the same JSONC dialect.
JSON contract
* `AddToConfigAction.auto_fixable` widens from `const false` to
`boolean`.
* TypeScript contract regenerated for both
`editors/vscode/src/generated/output-contract.d.ts` and
`npm/fallow/types/output-contract.d.ts`.
Tests
* Unit coverage for: JSON / JSONC / TOML / .fallow.toml shape; comment
preservation; existing-array merging; workspace-subdir re-anchoring;
CRLF round-trip (with `!output.contains("\r\r")` assertion);
TOML+CRLF round-trip; BOM round-trip on JSON and TOML;
absolute-vs-relative path dedupe on JSON and TOML.
* Integration coverage for: end-to-end fix + post-fix dead-code
round-trip; BOM round-trip through the full binary; symlink
write-through (Unix).
dbe4bd6 to
1907b2f
Compare
This was referenced May 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
fallow fixcan now apply theadd-to-configaction for duplicate-export findings directly to the user's fallow config file, instead of just emitting a paste-ready snippet. The action flips fromauto_fixable: falsetoauto_fixable: truewhenever a config file exists; with no config, fix skips with a clearRun 'fallow init' to create onemessage.This unblocks shadcn / Radix / bits-ui-style namespace-barrel projects where users had to hand-paste 30+ ignoreExports entries.
What ships
fallow_config::add_ignore_exports_rulecovers all four supported config formats atomically. JSON/JSONC go throughjsonc-parser(format-preserving CST); TOML /.fallow.tomlgo throughtoml_edit. Both round-trip comments, ordering, inline-vs-newline shape, trailing commas, CRLF/LF line endings, and a UTF-8 BOM.filematch, no reorder, no replace. Absolute existing entries dedupe against the writer's relative emissions when they resolve under the config dir.packages/ui/.fallowrc.json), emitted paths are relative to that config's directory.atomic_writecanonicalizes the target before persisting so configs mounted as symlinks (common in Docker setups) get their target updated rather than being replaced with a regular file.json_comments::StripCommentsparse sites replaced withjsonc-parserso reads and writes share the same JSONC dialect.AddToConfigAction.auto_fixablewidens fromconst falsetoboolean. TypeScript contract regenerated for botheditors/vscode/src/generated/output-contract.d.tsandnpm/fallow/types/output-contract.d.ts.Test plan
packages/ui/.fallowrc.jsonemitssrc/index.tsnotpackages/ui/src/index.ts)Out of scope (separate issues)
value_schemaURL field onadd-to-configactions for AI-agent input validationfallow fix --dry-runconfig diff preview--config <path>through intoauto_fixable(narrow edge case: user passes--configpointing outside root's ancestors AND agent gates onauto_fixablerather than attempting the fix)