use std::sync::Arc;
use json_syntax::{JsonValue, tracing::JsonErrorAt};
use rdf_syntax::Iri;
use super::{
JsonLdCompactResult, JsonLdCompareResult, JsonLdExpandResult, JsonLdFlattenResult,
JsonLdOptions, JsonLdProcessor,
};
use crate::{
JsonLdBacktraceBuilder, JsonLdDocument, JsonLdLocatedError, JsonLdSourceFileRef,
RemoteJsonLdContext,
algorithms::{AsyncJsonLdEnvironment, JsonLdCompact, JsonLdExpand},
context::RawJsonLdProcessedContext,
syntax::JsonLdCompare,
};
impl JsonLdProcessor for JsonLdDocument {
async fn async_compare_with(
&self,
other: &Self,
env: impl AsyncJsonLdEnvironment,
options: JsonLdOptions,
) -> JsonLdCompareResult {
if self.document.compare_json_ld(&other.document) {
return Ok(true);
}
let a = JsonLdProcessor::async_expand_with(self, env.as_ref(), options.clone()).await?;
let b = JsonLdProcessor::async_expand_with(other, env, options).await?;
Ok(a == b)
}
async fn async_expand_with(
&self,
env: impl AsyncJsonLdEnvironment,
mut options: JsonLdOptions,
) -> JsonLdExpandResult {
let mut active_context =
RawJsonLdProcessedContext::new(options.base.clone().or_else(|| self.url.clone()));
if let Some(expand_context) = options.expand_context.take() {
let context_document = expand_context
.load(env.loader())
.await
.map_err(Into::into)
.json_err_at(JsonLdBacktraceBuilder::Root)?;
active_context = context_document
.document
.context
.process_with(
env.as_ref(),
active_context.original_base_url(),
&active_context,
options.context_processing_options(),
JsonLdBacktraceBuilder::new()
.file(JsonLdSourceFileRef::original(context_document.url())),
)
.await?
.into_raw();
}
if let Some(context_url) = self.context_url() {
active_context = RemoteJsonLdContext::iri(context_url.to_owned())
.load(env.loader())
.await
.map_err(Into::into)
.json_err_at(JsonLdBacktraceBuilder::Root)?
.document
.context
.process_with(
env.as_ref(),
Some(context_url),
&active_context,
options.context_processing_options(),
JsonLdBacktraceBuilder::new()
.file(JsonLdSourceFileRef::original(Some(context_url))),
)
.await?
.into_raw()
}
JsonLdExpand::expand_with(self, env, &active_context, options.expansion_options()).await
}
async fn async_compact_with(
&self,
context: RemoteJsonLdContext,
env: impl AsyncJsonLdEnvironment,
options: JsonLdOptions,
) -> JsonLdCompactResult {
let expanded_document = Arc::new(
JsonLdProcessor::async_expand_with(self, env.as_ref(), options.clone().unordered())
.await?,
);
compact_expanded(
&expanded_document,
self.url(),
env,
context,
options,
JsonLdBacktraceBuilder::new().file(JsonLdSourceFileRef::expanded(
self.url(),
&expanded_document,
)),
)
.await
}
async fn async_flatten_with(
&self,
context: Option<RemoteJsonLdContext>,
env: impl AsyncJsonLdEnvironment,
options: JsonLdOptions,
) -> JsonLdFlattenResult {
let expanded_input = Arc::new(
JsonLdProcessor::async_expand_with(self, env.as_ref(), options.clone().unordered())
.await?,
);
let generator = rdf_syntax::generator::BlankIdGenerator::new_with_prefix("b".to_string());
let flattened_output = expanded_input
.flatten(
generator,
options.ordered,
JsonLdBacktraceBuilder::new()
.file(JsonLdSourceFileRef::expanded(self.url(), &expanded_input)),
)
.map_err(|e| (*e).cast())?;
match context {
Some(context) => {
let flattened_output = Arc::new(flattened_output);
compact_expanded(
&flattened_output,
self.url(),
env,
context,
options,
JsonLdBacktraceBuilder::new().file(JsonLdSourceFileRef::flattened(
self.url(),
&flattened_output,
)),
)
.await
}
None => Ok(json_syntax::to_value(flattened_output).unwrap()),
}
}
}
async fn compact_expanded(
expanded_input: &impl JsonLdCompact,
url: Option<&Iri>,
env: impl AsyncJsonLdEnvironment,
context: RemoteJsonLdContext,
options: JsonLdOptions,
location: JsonLdBacktraceBuilder<'_>,
) -> Result<JsonValue, JsonLdLocatedError> {
let context_base = url.or(options.base.as_deref());
let context = context
.load(env.loader())
.await
.map_err(Into::into)
.json_err_at(JsonLdBacktraceBuilder::Root)?;
let mut active_context = context
.document
.context
.process_with(
env.as_ref(),
context_base,
&RawJsonLdProcessedContext::new(None),
options.context_processing_options(),
json_syntax::tracing::JsonBacktraceBuilder::new()
.file(JsonLdSourceFileRef::original(context.url())),
)
.await?;
match options.base.as_ref() {
Some(base) => active_context.set_base_iri(Some(base.clone())),
None => {
if options.compact_to_relative && active_context.base_iri().is_none() {
active_context.set_base_iri(url.map(ToOwned::to_owned));
}
}
}
expanded_input
.compact_with(env, &active_context, options.compaction_options(), location)
.await
}