use json_ld_core::{ExpandedDocument, FlattenedDocument, Loader, Term};
use json_ld_syntax::{IntoJson, Keyword};
use rdf_types::{vocabulary, Vocabulary};
use std::hash::Hash;
use crate::{
iri::{compact_iri, IriConfusedWithPrefix},
CompactFragment,
};
pub type CompactDocumentResult = Result<json_syntax::Value, crate::Error>;
pub trait EmbedContext {
fn embed_context<N>(
&mut self,
vocabulary: &N,
context: json_ld_context_processing::ProcessedRef<N::Iri, N::BlankId>,
options: crate::Options,
) -> Result<(), IriConfusedWithPrefix>
where
N: Vocabulary,
N::Iri: Clone + Hash + Eq,
N::BlankId: Clone + Hash + Eq;
}
pub trait Compact<I, B> {
#[allow(async_fn_in_trait)]
async fn compact_full<'a, N, L>(
&'a self,
vocabulary: &'a mut N,
context: json_ld_context_processing::ProcessedRef<'a, 'a, I, B>,
loader: &'a L,
options: crate::Options,
) -> CompactDocumentResult
where
N: rdf_types::VocabularyMut<Iri = I, BlankId = B>,
I: Clone + Hash + Eq,
B: Clone + Hash + Eq,
L: Loader;
#[allow(async_fn_in_trait)]
async fn compact_with<'a, N, L>(
&'a self,
vocabulary: &'a mut N,
context: json_ld_context_processing::ProcessedRef<'a, 'a, I, B>,
loader: &'a L,
) -> CompactDocumentResult
where
N: rdf_types::VocabularyMut<Iri = I, BlankId = B>,
I: Clone + Hash + Eq,
B: Clone + Hash + Eq,
L: Loader,
{
self.compact_full(vocabulary, context, loader, crate::Options::default())
.await
}
#[allow(async_fn_in_trait)]
async fn compact<'a, L>(
&'a self,
context: json_ld_context_processing::ProcessedRef<'a, 'a, I, B>,
loader: &'a L,
) -> CompactDocumentResult
where
(): rdf_types::VocabularyMut<Iri = I, BlankId = B>,
I: Clone + Hash + Eq,
B: Clone + Hash + Eq,
L: Loader,
{
self.compact_with(vocabulary::no_vocabulary_mut(), context, loader)
.await
}
}
impl<I, B> Compact<I, B> for ExpandedDocument<I, B> {
async fn compact_full<'a, N, L>(
&'a self,
vocabulary: &'a mut N,
context: json_ld_context_processing::ProcessedRef<'a, 'a, I, B>,
loader: &'a L,
options: crate::Options,
) -> CompactDocumentResult
where
N: rdf_types::VocabularyMut<Iri = I, BlankId = B>,
I: Clone + Hash + Eq,
B: Clone + Hash + Eq,
L: Loader,
{
let mut compacted_output = self
.objects()
.compact_fragment_full(
vocabulary,
context.processed(),
context.processed(),
None,
loader,
options,
)
.await?;
compacted_output.embed_context(vocabulary, context, options)?;
Ok(compacted_output)
}
}
impl<I, B> Compact<I, B> for FlattenedDocument<I, B> {
async fn compact_full<'a, N, L>(
&'a self,
vocabulary: &'a mut N,
context: json_ld_context_processing::ProcessedRef<'a, 'a, I, B>,
loader: &'a L,
options: crate::Options,
) -> CompactDocumentResult
where
N: rdf_types::VocabularyMut<Iri = I, BlankId = B>,
I: Clone + Hash + Eq,
B: Clone + Hash + Eq,
L: Loader,
{
let mut compacted_output = self
.compact_fragment_full(
vocabulary,
context.processed(),
context.processed(),
None,
loader,
options,
)
.await?;
compacted_output.embed_context(vocabulary, context, options)?;
Ok(compacted_output)
}
}
impl EmbedContext for json_syntax::Value {
fn embed_context<N>(
&mut self,
vocabulary: &N,
context: json_ld_context_processing::ProcessedRef<N::Iri, N::BlankId>,
options: crate::Options,
) -> Result<(), IriConfusedWithPrefix>
where
N: Vocabulary,
N::Iri: Clone + Hash + Eq,
N::BlankId: Clone + Hash + Eq,
{
let value = self.take();
let obj = match value {
json_syntax::Value::Array(array) => {
let mut obj = json_syntax::Object::new();
if !array.is_empty() {
let key = compact_iri(
vocabulary,
context.processed(),
&Term::Keyword(Keyword::Graph),
true,
false,
options,
)?;
obj.insert(key.unwrap().into(), array.into());
}
Some(obj)
}
json_syntax::Value::Object(obj) => Some(obj),
_null => None,
};
if let Some(mut obj) = obj {
let json_context = IntoJson::into_json(context.unprocessed().clone());
if !obj.is_empty()
&& !json_context.is_null()
&& !json_context.is_empty_array_or_object()
{
obj.insert_front("@context".into(), json_context);
}
*self = obj.into()
};
Ok(())
}
}