JSON5
JSON5 and JSON with comments read as values: tsconfig.json and editor settings, with comments, trailing commas and unquoted keys.
Version 1.0.0 · 3 functions · 1 crate
Functions
What use json5.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use json5_parse, json5_read_file from json5 (Quillo 0.6).
json5_parse(text: str) → anyor an errorJSON5 text as a value: // and /* */ comments, trailing commas, 'single' quotes, unquoted keys, hex numbers, +Infinity and NaN (as null), and plain JSON too. The error says the line and column.
json5_read_file(path: str) → anyor an errorA JSON5 or JSONC file (tsconfig.json, .vscode/settings.json) read as json5_parse reads text.
jsonc_strip(text: str) → stror an errortext with its comments and trailing commas taken out, as plain JSON text that any JSON reader takes; strings are kept as they are, comments inside them too. For JSONC that must go on to a strict parser unchanged otherwise.
Get it
$ quillo install json5 # json5.qwer into this folder$ quillo install json5 --example # and its example, json5.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/json5.qwer$ curl -O https://quillolang.org/plugins/files/json5.qwe$ curl -O https://quillolang.org/plugins/files/json5_sample.jsoncThen, in your program, all of it or only what you call:
use json5.qweruse json5_parse, json5_read_file from json5 // Quillo 0.6: only theseIt uses this crate, which cargo fetches the first time the plugin is built:
json5 = "0.4"Example
// Reading a project's tsconfig.json (JSON with comments) and a JSON5 settings text.//// quillo run json5.qwe then open http://localhost:8080/tsconfiguse "json5.qwer"route GET /tsconfig { let ts = json5_read_file("json5_sample.jsonc")? { target: ts.compilerOptions.target, strict: ts.compilerOptions.strict, include: ts.include, builtin_json_refuses: is_err(json.parse(read_file("json5_sample.jsonc")?)) }}route GET /settings = json5_parse("{ theme: 'dark', fontSize: 14, maxSize: 0x400, plugins: ['git', 'quillo',], /* off for now */ telemetry: false }")?route GET /strip = { json: json.parse(jsonc_strip(read_file("json5_sample.jsonc")?)?)? }$ quillo run json5.qwe$ curl 'localhost:8080/tsconfig'$ curl 'localhost:8080/settings'$ curl 'localhost:8080/strip'Source
//! JSON5 and JSON with comments read as values: tsconfig.json, VS Code settings, devcontainer and Deno files, with comments, trailing commas, single quotes and unquoted keys.//! version: 1.0.0//!//! [dependencies]//! json5 = "0.4"use serde_json::Value;/// Texts up to 10 MB are read.const MAX: usize = 10 * 1024 * 1024;/// The deepest nesting of brackets outside strings: the parser recurses, and text nested thousands deep would overflow/// the server's stack, so it is refused first.fn too_deep(text: &str, max: usize) -> bool { let (mut depth, mut quote, mut esc) = (0usize, None::<char>, false); for c in text.chars() { if let Some(q) = quote { if esc { esc = false } else if c == '\\' { esc = true } else if c == q { quote = None } continue; } match c { '"' | '\'' => quote = Some(c), '[' | '{' | '(' => { depth += 1; if depth > max { return true; } } ']' | '}' | ')' => depth = depth.saturating_sub(1), _ => {} } } false}/// JSON5 text as a value: `//` and `/* */` comments, trailing commas, `'single'` quotes, unquoted keys, hex numbers,/// `+Infinity` and `NaN` (as null), and plain JSON too. The error says the line and column.pub fn json5_parse(text: &str) -> Result<Value, String> { if text.len() > MAX { return Err("texts up to 10 MB".into()); } if too_deep(text, 128) { return Err("nested more than 128 deep".into()); } let v: Value = json5::from_str(text).map_err(|e| format!("not JSON5: {}", e))?; Ok(v)}/// A JSON5 or JSONC file (tsconfig.json, .vscode/settings.json) read as json5_parse reads text.pub fn json5_read_file(path: &str) -> Result<Value, String> { let size = std::fs::metadata(path).map_err(|e| format!("{}: {}", path, e))?.len(); if size as usize > MAX { return Err(format!("{}: files up to 10 MB", path)); } json5_parse(&std::fs::read_to_string(path).map_err(|e| format!("{}: {}", path, e))?)}/// `text` with its comments and trailing commas taken out, as plain JSON text that any JSON reader takes; strings are kept as/// they are, comments inside them too. For JSONC that must go on to a strict parser unchanged otherwise.pub fn jsonc_strip(text: &str) -> Result<String, String> { if text.len() > MAX { return Err("texts up to 10 MB".into()); } let b: Vec<char> = text.chars().collect(); let mut out = String::with_capacity(text.len()); let mut i = 0; let mut in_str: Option<char> = None; while i < b.len() { let c = b[i]; if let Some(q) = in_str { out.push(c); if c == '\\' && i + 1 < b.len() { out.push(b[i + 1]); i += 2; continue; } if c == q { in_str = None; } i += 1; continue; } if c == '"' { in_str = Some(c); out.push(c); i += 1; } else if c == '/' && b.get(i + 1) == Some(&'/') { while i < b.len() && b[i] != '\n' { i += 1; } } else if c == '/' && b.get(i + 1) == Some(&'*') { i += 2; while i < b.len() && !(b[i] == '*' && b.get(i + 1) == Some(&'/')) { i += 1; } i += 2; } else if c == ',' { // A comma followed only by blanks and comments before `}` or `]` goes. let mut j = i + 1; loop { while j < b.len() && b[j].is_whitespace() { j += 1; } if b.get(j) == Some(&'/') && b.get(j + 1) == Some(&'/') { while j < b.len() && b[j] != '\n' { j += 1; } } else if b.get(j) == Some(&'/') && b.get(j + 1) == Some(&'*') { j += 2; while j < b.len() && !(b[j] == '*' && b.get(j + 1) == Some(&'/')) { j += 1; } j += 2; } else { break; } } if !matches!(b.get(j), Some('}') | Some(']')) { out.push(c); } i += 1; } else { out.push(c); i += 1; } } Ok(out)}Related
ini.qwer · 1.0.0INI files read and written, sections and keys: php.ini, setup.cfg, .gitconfig and the settings of older software.8 views · 7 downloads.env files dotenv.qwer · 1.0.0.env files read with their quoting rules and ${VAR} expansion, linted and compared with .env.example, and written or changed one key at a time with comments kept.8 views · 9 downloadsHCL hcl.qwer · 1.0.0HCL, the language of Terraform, Nomad and Packer files: read as values, expressions worked out from your variables, and written back.7 views · 6 downloadsJava properties java_properties.qwer · 1.0.0Java .properties files read and written: Spring settings and translation bundles, with continued lines and \u escapes.6 views · 8 downloadsJSON Lines ndjson.qwer · 1.0.0JSON Lines (NDJSON) read a page at a time from files of any size, searched by field, appended to and written: logs, exports and imports.7 views · 6 downloadsProperty lists plist.qwer · 1.0.0Apple property lists, XML and binary: Info.plist, profiles and preferences read as values, and values written back as either.6 views · 9 downloadsThread 0 posts
On JSON5: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.