# fJSON Friendly JSON: JSON values with comments, single-quoted strings, ASCII identifier keys, trailing commas, and commas that can be replaced by newlines. Root objects may omit their braces. Empty or comment-only documents represent an empty object. ```text name: "demo" options: { enabled: true targets: ["linux", "macos"] } ``` Values remain JSON data, not JavaScript expressions. Bare string values, duplicate decoded keys, nondecimal numbers, and unescaped control characters are rejected. Only newlines outside block comments separate entries. Container nesting is limited to 128 levels below the root by default, for both parsing and printing. Pass a custom `Options` to `parse_with`, `stringify_with`, `syntax::parse_with`, `syntax::parse_object_with`, or `Document::parse_with` / `Document::parse_object_with` to allow more or less nesting. `Document` remembers its options for later edits. ## Values ```rust let value = serde_fjson::parse("name: 'demo'\nactive: true")?; let text = serde_fjson::stringify(&value)?; # Ok::<(), serde_fjson::Error>(()) ``` `parse` returns a `serde_json::Value` and accepts objects, arrays, and scalar roots. Numbers use the enabled `serde_json::Number` representation; conversion reports out-of-range numbers at their original source spans. Object insertion order is preserved. `stringify` always pretty-prints: two-space indentation, unquoted identifier keys, implicit nonempty root objects, and newline-separated entries. Short scalar arrays stay inline; longer arrays and nested containers expand. It targets an 80-column width, but does not split strings or keys. It does not add a final newline. It returns `Result` and rejects values beyond the nesting limit rather than producing text that cannot be parsed back. `syntax::parse` exposes the span-aware syntax tree without numeric conversion. `syntax::parse_object` requires a root object, for config consumers. Errors expose UTF-8 byte spans and can be rendered with file, line, and character-column locations, including the first occurrence of duplicate keys. `ErrorKind` distinguishes syntax, Unicode, numeric-range, and nesting errors. ## Source-preserving edits ```rust use serde_fjson::Document; use serde_json::json; let mut document = Document::parse("// keep\noptions: {enabled: false}")?; document.set(&["options".into(), "enabled".into()], &json!(true))?; document.set(&["options".into(), "targets".into()], &json!(["linux"]))?; document.remove(&["options".into(), "enabled".into()])?; let text = document.into_source(); # Ok::<(), serde_fjson::Error>(()) ``` `Document::parse_object` requires an object root in its input and preserves config-specific parse diagnostics. The returned document still supports root replacement with any JSON value. Implicit root spans exclude trailing trivia, which survives root replacement, including comments and final line endings. Paths contain `PathSegment::Key(&str)` or `PathSegment::Index(usize)`. Parents must exist. `set` replaces an existing value, inserts a missing object key, or appends at an array index equal to its length. An empty path replaces the root. `remove` returns whether the field/item existed, and does not accept an empty path. Untouched source is retained byte-for-byte. Setting an equal value is a no-op. Scalar string replacements retain their existing quote style. New values are pretty-printed using the document's line endings and surrounding indentation. External comments survive removal, including comments between a key, colon, and value. Comments inside a replaced or removed value disappear with it. No attempt is made to infer which neighboring comments belong to an entry. A member alone on its line is removed with its indentation and line break, and blank gaps around its colon and comma go with it; deletion otherwise does not reformat the document. Edits reparse the result to refresh spans and validate it. A failed edit leaves the document unchanged. `source()` exposes the current text, `root()` its syntax tree, and `to_value()` converts it to JSON data.