diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-09-25 17:35:56 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-09-25 17:37:16 +0200 |
| commit | fffb55f79a3369fa2dcf39371091c48ff61f55a8 (patch) | |
| tree | 6d48f81b7edd5f70a1eadf3ada88379646ebbe10 /src/library | |
| parent | ddd3b6a82b8c0353c942bfba8b89ca5476eedc58 (diff) | |
JSON reading
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/mod.rs | 1 | ||||
| -rw-r--r-- | src/library/utility/data.rs | 43 |
2 files changed, 44 insertions, 0 deletions
diff --git a/src/library/mod.rs b/src/library/mod.rs index 566a4f26..d806f298 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -97,6 +97,7 @@ pub fn new() -> Scope { std.def_fn("symbol", utility::symbol); std.def_fn("lorem", utility::lorem); std.def_fn("csv", utility::csv); + std.def_fn("json", utility::json); // Predefined colors. std.define("black", Color::BLACK); diff --git a/src/library/utility/data.rs b/src/library/utility/data.rs index 1ae8949a..e3efe6e7 100644 --- a/src/library/utility/data.rs +++ b/src/library/utility/data.rs @@ -41,3 +41,46 @@ fn format_csv_error(error: csv::Error) -> String { _ => "failed to parse csv file".into(), } } + +/// Read structured data from a JSON file. +pub fn json(vm: &mut Vm, args: &mut Args) -> SourceResult<Value> { + let Spanned { v: path, span } = + args.expect::<Spanned<EcoString>>("path to json file")?; + + let path = vm.locate(&path).at(span)?; + let data = vm.world.file(&path).at(span)?; + let value: serde_json::Value = + serde_json::from_slice(&data).map_err(format_json_error).at(span)?; + + Ok(convert_json(value)) +} + +/// Convert a JSON value to a Typst value. +fn convert_json(value: serde_json::Value) -> Value { + match value { + serde_json::Value::Null => Value::None, + serde_json::Value::Bool(v) => Value::Bool(v), + serde_json::Value::Number(v) => match v.as_i64() { + Some(int) => Value::Int(int), + None => Value::Float(v.as_f64().unwrap_or(f64::NAN)), + }, + serde_json::Value::String(v) => Value::Str(v.into()), + serde_json::Value::Array(v) => { + Value::Array(v.into_iter().map(convert_json).collect()) + } + serde_json::Value::Object(v) => Value::Dict( + v.into_iter() + .map(|(key, value)| (key.into(), convert_json(value))) + .collect(), + ), + } +} + +/// Format the user-facing JSON error message. +fn format_json_error(error: serde_json::Error) -> String { + assert!(error.is_syntax() || error.is_eof()); + format!( + "failed to parse json file: syntax error in line {}", + error.line() + ) +} |
