The %include notation lets one file draw defaults from another. Fson::load resolves it automatically.

// service.fson
{
  %include "base.fson",   // base's members fill in as defaults
  timeout: 60             // ... but this host value wins over base's
}
auto result = Fson::load( "service.fson" );
result.document->getInteger( "timeout", 0 );   // 60  (host wins)
result.document->getInteger( "retries", 0 );   // from base.fson

The merged view vs. what save() writes

The query view is the merged result (host over base, shallow). But save() writes only the host file back: the %include line is reproduced verbatim and base's values are not copied in. Programmatic setPath() overrides land only in the host file.

Alias form

{
  %include "secrets.fson" as vault,
}

binds the whole root value of secrets.fson under the key vault (the target root need not be an object). Query it as vault.password.

Provenance — where did a value come from?

result.document->isLocal( "timeout" );          // true  (defined in the host)
auto p = result.document->provenanceOf( "retries" );
// p->sourceFile  → canonical path of base.fson
// p->localPath   → "retries"  (its path WITHIN base.fson — differs for aliases)

auto all = result.document->provenanceMap();     // every resolved top-level key

The dependency set (for reloads)

for( auto const& file : result.dependencySet )   // host + every include, sorted
  watch( file );

// or, without keeping the document:
std::set<std::string> files = Fson::dependenciesOf( "service.fson" );

Edge cases, never thrown

  • Cycles (aba) are reported as an error and broken; the non-cyclic content still loads.
  • A missing target is an error, not an exception.
  • --%include "…" is kept structurally but not resolved.

Continue with Reloading Changed Files.