char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somdeslop: factor module prep/transpilatione/etc into loader.rsab5df08

main
2 folders2 files

files

src/
tests/
Cargo.toml144 B
README.md4.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.