///|
/// A selected subtree retained with the pointer that identified it.
pub(all) struct SelectedValue {
path : String
value : JsonValue
}
///|
pub fn select_many(
value : JsonValue,
pointers : Array[String],
) -> Result[Array[SelectedValue], String] {
let selected : Array[SelectedValue] = []
for pointer in pointers {
match select_pointer(value, pointer) {
Ok(child) => selected.push({ path: pointer, value: child })
Err(error) => return Err(pointer + ": " + error)
}
}
Ok(selected)
}
///|
/// Project selected values into a deterministic array of `{path,value}`
/// records. This preserves pointer order because callers often use it to
/// generate small review artifacts from a large document.
pub fn project_document(
input : String,
pointers : Array[String],
) -> Result[String, String] {
let value = match parse(input) {
Ok(value) => value
Err(error) => return Err(error.message())
}
let selected = match select_many(value, pointers) {
Ok(selected) => selected
Err(error) => return Err(error)
}
let mut output = "["
let mut first = true
for item in selected {
let serialized = match canonicalize(item.value) {
Ok(serialized) => serialized
Err(error) => return Err(error.message())
}
if !first {
output = output + ","
}
first = false
output = output +
"{\"path\":" +
canonical_string(item.path) +
",\"value\":" +
serialized +
"}"
}
Ok(output + "]")
}
///|
pub fn SelectedValue::to_text(self : SelectedValue) -> String {
self.path + " = " + value_preview(self.value)
}
///|
pub fn selected_text(values : Array[SelectedValue]) -> String {
let mut output = ""
for value in values {
if output != "" {
output = output + "\n"
}
output = output + value.to_text()
}
output
}
///|
pub fn scalar_paths(value : JsonValue) -> Array[String] {
let paths : Array[String] = []
collect_scalar_paths(value, "", paths)
paths
}
///|
fn collect_scalar_paths(
value : JsonValue,
path : String,
paths : Array[String],
) -> Unit {
match value {
Array(values) => {
let mut index = 0
while index < values.length() {
collect_scalar_paths(
values[index],
path + "/" + index.to_string(),
paths,
)
index = index + 1
}
}
Object(entries) =>
for entry in entries {
collect_scalar_paths(
entry.1,
path + "/" + pointer_escape_local(entry.0),
paths,
)
}
_ => paths.push(path)
}
}