Skip to content

feat: loader formatter architecture#2

Merged
monokrome merged 13 commits intomainfrom
feat/loader-formatter-architecture
Feb 13, 2026
Merged

feat: loader formatter architecture#2
monokrome merged 13 commits intomainfrom
feat/loader-formatter-architecture

Conversation

@monokrome
Copy link
Copy Markdown
Member

No description provided.

Introduces the plugin-based loading abstraction that replaces manual
Source wiring. Loaders declare what identifiers they handle via
provides() and are discoverable through the registry (coming next).

FileLoader handles bare names, file:// URLs, and explicit paths by
delegating to the existing discovery module.
Introduces the Formatter trait that separates format parsing from source
loading. Each formatter declares what extensions it handles and provides
serialize/deserialize methods.

Extracts all parsing logic from the monolithic formats.rs into individual
formatter modules: json, yaml, toml, ini, xml. The old formats.rs
remains for backward compatibility during the transition.
Loaders and formatters now self-register at link time via
inventory::submit!. The registry finds the right loader/formatter
by calling provides() on each registered plugin.

All built-in loaders (FileLoader) and formatters (json, yaml, toml,
ini, xml) are auto-registered. External crates like prefer_db can
register their own plugins by depending on prefer and submitting
to the inventory.
Adds NoLoaderFound, NoFormatterFound, and WatchNotSupported error
variants for the registry-based loading path.

Adds an Emitter type for "changed" events, matching Python prefer's
event system. Config will use this to notify listeners when values
are set or updated.
…stry

Config now holds loader_name, formatter_name, and source metadata from
the loading path. Adds set() method with event emission via on_change().
Clone drops the emitter (event handlers are instance-specific).

The top-level load() and watch() functions now route through the
registry: find_loader -> load -> find_formatter -> deserialize. This
means prefer::load("postgres://...") will work when prefer_db registers
its DbLoader.
Source and FileSource are deprecated in favor of Loader + Formatter.
EnvSource, MemorySource, LayeredSource, and ConfigBuilder remain
functional for layering use cases.

Adds comprehensive registry tests covering loader discovery, formatter
matching by extension and hint, the full load pipeline through the
registry, and Config::set() with event emission.
Cover serialize/deserialize paths for all formatters (JSON, YAML, TOML,
INI, XML), Config metadata and event edge cases, error Display variants,
and formatter mod utilities. Coverage 73.95% -> 83.68%.
@codecov
Copy link
Copy Markdown

codecov bot commented Feb 13, 2026

Codecov Report

❌ Patch coverage is 97.97707% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.85%. Comparing base (f14f870) to head (9cf758f).
⚠️ Report is 14 commits behind head on main.

Files with missing lines Patch % Lines
prefer/src/events.rs 94.18% 3 Missing and 2 partials ⚠️
prefer/src/formatter/ini.rs 96.15% 5 Missing ⚠️
prefer/src/config.rs 98.24% 1 Missing and 3 partials ⚠️
prefer/src/formatter/yaml.rs 98.43% 2 Missing and 1 partial ⚠️
prefer/src/loader/file.rs 95.08% 3 Missing ⚠️
prefer/src/formatter/json.rs 98.81% 1 Missing and 1 partial ⚠️
prefer/src/formatter/xml.rs 98.93% 1 Missing and 1 partial ⚠️
prefer/src/lib.rs 92.30% 0 Missing and 2 partials ⚠️
prefer/src/loader/mod.rs 0.00% 2 Missing ⚠️
prefer/src/formatter/toml.rs 99.51% 1 Missing ⚠️
... and 1 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main       #2      +/-   ##
==========================================
+ Coverage   91.37%   93.85%   +2.47%     
==========================================
  Files          11       21      +10     
  Lines        2133     3610    +1477     
  Branches     2133     3610    +1477     
==========================================
+ Hits         1949     3388    +1439     
- Misses        147      174      +27     
- Partials       37       48      +11     
Files with missing lines Coverage Δ
prefer/src/builder.rs 100.00% <ø> (ø)
prefer/src/error.rs 98.36% <100.00%> (+3.12%) ⬆️
prefer/src/formatter/mod.rs 100.00% <100.00%> (ø)
prefer/src/registry.rs 100.00% <100.00%> (ø)
prefer/src/formatter/toml.rs 99.51% <99.51%> (ø)
prefer/src/source.rs 99.38% <99.10%> (-0.15%) ⬇️
prefer/src/formatter/json.rs 98.81% <98.81%> (ø)
prefer/src/formatter/xml.rs 98.93% <98.93%> (ø)
prefer/src/lib.rs 92.30% <92.30%> (-7.70%) ⬇️
prefer/src/loader/mod.rs 0.00% <0.00%> (ø)
... and 5 more

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Replace unnecessary if-let nesting with guards, extract duplicated
escape helpers, remove unnecessary closures (or_else -> or,
ok_or_else -> ok_or), and restructure XML text parsing into a match.
Use slice::contains instead of iter().any() in extension/hint matching,
and use EventHandler type alias in Config::on_change signature.
Use 3.15 instead of 3.14 to avoid approx_constant lint, and add
allow(deprecated) to coverage_tests.rs which intentionally tests
the deprecated Source/FileSource API.
Move tests using deprecated Source/FileSource API from coverage_tests.rs
into source.rs where allow(deprecated) is already set. Use 3.15 instead
of 3.14 in test floats to avoid approx_constant lint.
@monokrome monokrome merged commit c1a9c55 into main Feb 13, 2026
4 checks passed
@monokrome monokrome deleted the feat/loader-formatter-architecture branch February 13, 2026 10:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant