Replace, create, remove

#include "fson/Number.hh"
#include "fson/String.hh"

// replace a value (or append the member if the path's last key is missing)
doc.setPath( "database.host", std::make_unique<String>( "db1" ) );

// create missing intermediate OBJECTS in one call
doc.setPath( "database.pool.size", std::make_unique<Number>( 8LL ) );

// remove an active member, or erase an array element
doc.removePath( "retries[1]" );

setPath():

  • never grows arrays and never creates them — an index in the path must already exist;
  • never resurrects a disabled member — a new active member is appended beside it (consistent with the query semantics);
  • fails without side effects — any intermediate objects it created during a walk that then failed are rolled back.

Switch members off and on

doc.getRoot().disable( "retries" );          // active → disabled
doc.getRoot().at( "database" ).asObject()->enable( "user" );  // first disabled → active

The data is kept either way — disable() / enable() only flip the flag. enable() fails if an active member with that name already exists.

Save

if( !Fson::save( doc, "config.fson" ) )
  std::cerr << "cannot write config.fson\n";

Or drive FsonWriter directly for a stream, a string, or a non-default dialect.

The round-trip guarantee

The writer pretty-prints — 2-space indent, one member/element per line, key: value with a single space after : — and writes back everything the parser captured:

Preserved exactlyNormalised
comments and their positions (header, leading, trailing, dangling, footer; nested blocks)indentation, blank-line runs
member and element order
quoted-vs-bare key form (unless preferBareKeys)
-- disabled markers
number lexemes — 1.50 stays 1.50, 0xFF stays 0xFF, Infinity stays Infinity
`\`-block string formthe block is re-emitted at the value's indentation

Output is a fixed point: writing an already-written document changes nothing (write(parse(write(x))) == write(parse(x))), and a modify-then-write cycle keeps every unrelated comment.

Empty containers stay compact ({} / []) — unless they carry dangling comments, which would otherwise be lost, so the expanded form is forced.

Strings are re-emitted double-quoted, escaping only the mandatory set; raw UTF-8 (including decoded \uXXXX) passes through — "ü" becomes "ü".