1use jsonld_core::{ExpandedDocument, FlattenedDocument, Loader};
2use jsonld_syntax::{IntoJson, Keyword};
3use rdfx::vocabulary::{self, Vocabulary};
4use std::hash::Hash;
5
6use crate::{CompactFragment, iri::IriConfusedWithPrefix};
7
8pub type CompactDocumentResult<E> = Result<jstrict::Value, crate::Error<E>>;
10
11pub trait EmbedContext {
17 fn embed_context<N>(
30 &mut self,
31 vocabulary: &N,
32 context: jsonld_context_processing::ProcessedRef<N::Iri, N::BlankId>,
33 options: crate::Options,
34 ) -> Result<(), IriConfusedWithPrefix>
35 where
36 N: Vocabulary,
37 N::Iri: Clone + Hash + Eq,
38 N::BlankId: Clone + Hash + Eq;
39}
40
41pub trait Compact<I, B> {
48 async fn compact_full<'a, N, L>(
50 &'a self,
51 vocabulary: &'a mut N,
52 context: jsonld_context_processing::ProcessedRef<'a, 'a, I, B>,
53 loader: &'a L,
54 options: crate::Options,
55 ) -> CompactDocumentResult<L::Error>
56 where
57 N: rdfx::vocabulary::VocabularyMut<Iri = I, BlankId = B>,
58 I: Clone + Hash + Eq,
59 B: Clone + Hash + Eq,
60 L: Loader;
61
62 async fn compact_with<'a, N, L>(
66 &'a self,
67 vocabulary: &'a mut N,
68 context: jsonld_context_processing::ProcessedRef<'a, 'a, I, B>,
69 loader: &'a L,
70 ) -> CompactDocumentResult<L::Error>
71 where
72 N: rdfx::vocabulary::VocabularyMut<Iri = I, BlankId = B>,
73 I: Clone + Hash + Eq,
74 B: Clone + Hash + Eq,
75 L: Loader,
76 {
77 self.compact_full(vocabulary, context, loader, crate::Options::default()).await
78 }
79
80 async fn compact<'a, L>(&'a self, context: jsonld_context_processing::ProcessedRef<'a, 'a, I, B>, loader: &'a L) -> CompactDocumentResult<L::Error>
84 where
85 (): rdfx::vocabulary::VocabularyMut<Iri = I, BlankId = B>,
86 I: Clone + Hash + Eq,
87 B: Clone + Hash + Eq,
88 L: Loader,
89 {
90 self.compact_with(vocabulary::no_vocabulary_mut(), context, loader).await
91 }
92}
93
94impl<I, B> Compact<I, B> for ExpandedDocument<I, B> {
95 async fn compact_full<'a, N, L>(
96 &'a self,
97 vocabulary: &'a mut N,
98 context: jsonld_context_processing::ProcessedRef<'a, 'a, I, B>,
99 loader: &'a L,
100 options: crate::Options,
101 ) -> CompactDocumentResult<L::Error>
102 where
103 N: rdfx::vocabulary::VocabularyMut<Iri = I, BlankId = B>,
104 I: Clone + Hash + Eq,
105 B: Clone + Hash + Eq,
106 L: Loader,
107 {
108 let mut compacted_output = self
109 .objects()
110 .compact_fragment_full(vocabulary, context.processed(), context.processed(), None, loader, options)
111 .await?;
112
113 compacted_output.embed_context(vocabulary, context, options)?;
114
115 Ok(compacted_output)
116 }
117}
118
119impl<I, B> Compact<I, B> for FlattenedDocument<I, B> {
120 async fn compact_full<'a, N, L>(
121 &'a self,
122 vocabulary: &'a mut N,
123 context: jsonld_context_processing::ProcessedRef<'a, 'a, I, B>,
124 loader: &'a L,
125 options: crate::Options,
126 ) -> CompactDocumentResult<L::Error>
127 where
128 N: rdfx::vocabulary::VocabularyMut<Iri = I, BlankId = B>,
129 I: Clone + Hash + Eq,
130 B: Clone + Hash + Eq,
131 L: Loader,
132 {
133 let mut compacted_output = self
134 .compact_fragment_full(vocabulary, context.processed(), context.processed(), None, loader, options)
135 .await?;
136
137 compacted_output.embed_context(vocabulary, context, options)?;
138
139 Ok(compacted_output)
140 }
141}
142
143impl EmbedContext for jstrict::Value {
144 fn embed_context<N>(
145 &mut self,
146 vocabulary: &N,
147 context: jsonld_context_processing::ProcessedRef<N::Iri, N::BlankId>,
148 options: crate::Options,
149 ) -> Result<(), IriConfusedWithPrefix>
150 where
151 N: Vocabulary,
152 N::Iri: Clone + Hash + Eq,
153 N::BlankId: Clone + Hash + Eq,
154 {
155 let value = self.take();
156
157 let obj = match value {
158 jstrict::Value::Array(array) => {
159 let mut obj = jstrict::Object::new();
160
161 if !array.is_empty() {
162 let key = crate::iri::keyword_alias(vocabulary, context.processed(), options, Keyword::Graph);
163
164 obj.insert(key.into(), array.into());
165 }
166
167 Some(obj)
168 }
169 jstrict::Value::Object(obj) => Some(obj),
170 _null => None,
171 };
172
173 if let Some(mut obj) = obj {
174 let json_context = IntoJson::into_json(context.unprocessed().clone());
175
176 if !obj.is_empty() && !json_context.is_null() && !json_context.is_empty_array_or_object() {
177 obj.insert_front("@context".into(), json_context);
178 }
179
180 *self = obj.into();
181 }
182
183 Ok(())
184 }
185}