char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
ab5df08
main
files
| src/ | |
| tests/ | |
| Cargo.toml | 144 B |
| README.md | 4.0 KiB |
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.
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
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<String, Error> 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
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.