use super::node_map::{
generate_node_map, merge_value as merge_value_inner, node_map_to_flat_array, NodeMap,
NodeObject,
};
use super::{FlatteningError, FlatteningOptions, JsonLdValue};
use indexmap::IndexMap;
use std::collections::HashSet;
#[inline]
pub fn is_node_object(value: &JsonLdValue) -> bool {
match value {
JsonLdValue::Object(m) => !m.contains_key("@value") && !m.contains_key("@list"),
_ => false,
}
}
#[inline]
pub fn is_value_object(value: &JsonLdValue) -> bool {
match value {
JsonLdValue::Object(m) => m.contains_key("@value"),
_ => false,
}
}
#[inline]
pub fn is_list_object(value: &JsonLdValue) -> bool {
match value {
JsonLdValue::Object(m) => m.contains_key("@list"),
_ => false,
}
}
pub fn merge_value(into: &mut Vec<JsonLdValue>, value: JsonLdValue) {
merge_value_inner(into, value);
}
pub fn flatten_internal(
expanded: Vec<JsonLdValue>,
options: &FlatteningOptions,
) -> Result<JsonLdValue, FlatteningError> {
let node_map = generate_node_map(&expanded, options)?;
let flat_array = node_map_to_flat_array(&node_map, options.ordered);
let mut result_map: IndexMap<String, JsonLdValue> = IndexMap::new();
result_map.insert("@graph".to_string(), JsonLdValue::Array(flat_array));
Ok(JsonLdValue::Object(result_map))
}
pub fn clone_node_recursively(
node: &NodeObject,
node_map: &NodeMap,
visited: &mut HashSet<String>,
) -> Result<JsonLdValue, FlatteningError> {
if visited.contains(&node.id) {
return Err(FlatteningError::CyclicNodeReference(node.id.clone()));
}
visited.insert(node.id.clone());
let mut map: IndexMap<String, JsonLdValue> = IndexMap::new();
map.insert("@id".to_string(), JsonLdValue::Str(node.id.clone()));
if !node.types.is_empty() {
let types: Vec<JsonLdValue> = node
.types
.iter()
.map(|t| JsonLdValue::Str(t.clone()))
.collect();
map.insert("@type".to_string(), JsonLdValue::Array(types));
}
for (prop, values) in &node.properties {
if prop == "@type" {
continue;
}
let mut cloned_values: Vec<JsonLdValue> = Vec::with_capacity(values.len());
for val in values {
cloned_values.push(clone_value_recursively(val, node_map, visited)?);
}
if !cloned_values.is_empty() {
map.insert(prop.clone(), JsonLdValue::Array(cloned_values));
}
}
if let Some(inner_graph) = node_map.graphs.get(&node.id) {
let mut inner_nodes: Vec<&str> = inner_graph.nodes.keys().map(String::as_str).collect();
inner_nodes.sort_unstable();
let mut inner_array: Vec<JsonLdValue> = Vec::with_capacity(inner_nodes.len());
for subj in inner_nodes {
let inner_node = &inner_graph.nodes[subj];
inner_array.push(clone_node_recursively(inner_node, node_map, visited)?);
}
map.insert("@graph".to_string(), JsonLdValue::Array(inner_array));
}
visited.remove(&node.id);
Ok(JsonLdValue::Object(map))
}
fn clone_value_recursively(
value: &JsonLdValue,
node_map: &NodeMap,
visited: &mut HashSet<String>,
) -> Result<JsonLdValue, FlatteningError> {
match value {
JsonLdValue::Object(m) => {
if m.contains_key("@value") || m.contains_key("@list") {
return Ok(value.clone());
}
if let Some(JsonLdValue::Str(id)) = m.get("@id") {
if let Some(node) = node_map.default_graph().nodes.get(id.as_str()) {
return clone_node_recursively(node, node_map, visited);
}
}
Ok(value.clone())
}
JsonLdValue::Array(items) => {
let mut out: Vec<JsonLdValue> = Vec::with_capacity(items.len());
for item in items {
out.push(clone_value_recursively(item, node_map, visited)?);
}
Ok(JsonLdValue::Array(out))
}
other => Ok(other.clone()),
}
}