1use std::sync::Arc;
2
3use json_syntax::{JsonValue, tracing::JsonErrorAt};
4use rdf_syntax::Iri;
5
6use super::{
7 JsonLdCompactResult, JsonLdCompareResult, JsonLdExpandResult, JsonLdFlattenResult,
8 JsonLdOptions, JsonLdProcessor,
9};
10use crate::{
11 JsonLdBacktraceBuilder, JsonLdDocument, JsonLdLocatedError, JsonLdSourceFileRef,
12 RemoteJsonLdContext,
13 algorithms::{AsyncJsonLdEnvironment, JsonLdCompact, JsonLdExpand},
14 context::RawJsonLdProcessedContext,
15 syntax::JsonLdCompare,
16};
17
18impl JsonLdProcessor for JsonLdDocument {
19 async fn async_compare_with(
20 &self,
21 other: &Self,
22 env: impl AsyncJsonLdEnvironment,
23 options: JsonLdOptions,
24 ) -> JsonLdCompareResult {
25 if self.document.compare_json_ld(&other.document) {
26 return Ok(true);
27 }
28
29 let a = JsonLdProcessor::async_expand_with(self, env.as_ref(), options.clone()).await?;
30 let b = JsonLdProcessor::async_expand_with(other, env, options).await?;
31
32 Ok(a == b)
33 }
34
35 async fn async_expand_with(
36 &self,
37 env: impl AsyncJsonLdEnvironment,
38 mut options: JsonLdOptions,
39 ) -> JsonLdExpandResult {
40 let mut active_context =
42 RawJsonLdProcessedContext::new(options.base.clone().or_else(|| self.url.clone()));
43
44 if let Some(expand_context) = options.expand_context.take() {
46 let context_document = expand_context
47 .load(env.loader())
48 .await
49 .map_err(Into::into)
50 .json_err_at(JsonLdBacktraceBuilder::Root)?;
51
52 active_context = context_document
53 .document
54 .context
55 .process_with(
56 env.as_ref(),
57 active_context.original_base_url(),
58 &active_context,
59 options.context_processing_options(),
60 JsonLdBacktraceBuilder::new()
61 .file(JsonLdSourceFileRef::original(context_document.url())),
62 )
63 .await?
64 .into_raw();
65 }
66
67 if let Some(context_url) = self.context_url() {
69 active_context = RemoteJsonLdContext::iri(context_url.to_owned())
70 .load(env.loader())
71 .await
72 .map_err(Into::into)
73 .json_err_at(JsonLdBacktraceBuilder::Root)?
74 .document
75 .context
76 .process_with(
77 env.as_ref(),
78 Some(context_url),
79 &active_context,
80 options.context_processing_options(),
81 JsonLdBacktraceBuilder::new()
82 .file(JsonLdSourceFileRef::original(Some(context_url))),
83 )
84 .await?
85 .into_raw()
86 }
87
88 JsonLdExpand::expand_with(self, env, &active_context, options.expansion_options()).await
90 }
91
92 async fn async_compact_with(
93 &self,
94 context: RemoteJsonLdContext,
95 env: impl AsyncJsonLdEnvironment,
96 options: JsonLdOptions,
97 ) -> JsonLdCompactResult {
98 let expanded_document = Arc::new(
99 JsonLdProcessor::async_expand_with(self, env.as_ref(), options.clone().unordered())
100 .await?,
101 );
102
103 compact_expanded(
104 &expanded_document,
105 self.url(),
106 env,
107 context,
108 options,
109 JsonLdBacktraceBuilder::new().file(JsonLdSourceFileRef::expanded(
110 self.url(),
111 &expanded_document,
112 )),
113 )
114 .await
115 }
116
117 async fn async_flatten_with(
118 &self,
119 context: Option<RemoteJsonLdContext>,
120 env: impl AsyncJsonLdEnvironment,
121 options: JsonLdOptions,
122 ) -> JsonLdFlattenResult {
123 let expanded_input = Arc::new(
124 JsonLdProcessor::async_expand_with(self, env.as_ref(), options.clone().unordered())
125 .await?,
126 );
127
128 let generator = rdf_syntax::generator::BlankIdGenerator::new_with_prefix("b".to_string());
129 let flattened_output = expanded_input
130 .flatten(
131 generator,
132 options.ordered,
133 JsonLdBacktraceBuilder::new()
134 .file(JsonLdSourceFileRef::expanded(self.url(), &expanded_input)),
135 )
136 .map_err(|e| (*e).cast())?;
137
138 match context {
139 Some(context) => {
140 let flattened_output = Arc::new(flattened_output);
141
142 compact_expanded(
143 &flattened_output,
144 self.url(),
145 env,
146 context,
147 options,
148 JsonLdBacktraceBuilder::new().file(JsonLdSourceFileRef::flattened(
149 self.url(),
150 &flattened_output,
151 )),
152 )
153 .await
154 }
155 None => Ok(json_syntax::to_value(flattened_output).unwrap()),
156 }
157 }
158}
159
160async fn compact_expanded(
161 expanded_input: &impl JsonLdCompact,
162 url: Option<&Iri>,
163 env: impl AsyncJsonLdEnvironment,
164 context: RemoteJsonLdContext,
165 options: JsonLdOptions,
166 location: JsonLdBacktraceBuilder<'_>,
167) -> Result<JsonValue, JsonLdLocatedError> {
168 let context_base = url.or(options.base.as_deref());
169
170 let context = context
171 .load(env.loader())
172 .await
173 .map_err(Into::into)
174 .json_err_at(JsonLdBacktraceBuilder::Root)?;
175
176 let mut active_context = context
177 .document
178 .context
179 .process_with(
180 env.as_ref(),
181 context_base,
182 &RawJsonLdProcessedContext::new(None),
183 options.context_processing_options(),
184 json_syntax::tracing::JsonBacktraceBuilder::new()
185 .file(JsonLdSourceFileRef::original(context.url())),
186 )
187 .await?;
188
189 match options.base.as_ref() {
190 Some(base) => active_context.set_base_iri(Some(base.clone())),
191 None => {
192 if options.compact_to_relative && active_context.base_iri().is_none() {
193 active_context.set_base_iri(url.map(ToOwned::to_owned));
194 }
195 }
196 }
197
198 expanded_input
199 .compact_with(env, &active_context, options.compaction_options(), location)
200 .await
201}