1use super::error::{JsonLdErrorCode, JsonLdSyntaxError};
2use super::{JsonLdProcessingMode, JsonLdProfile, JsonLdProfileSet};
3use json_event_parser::{JsonEvent, JsonSyntaxError, SliceJsonParser};
4use oxiri::Iri;
5use std::borrow::Cow;
6use std::collections::hash_map::Entry;
7use std::collections::HashMap;
8use std::error::Error;
9use std::panic::{RefUnwindSafe, UnwindSafe};
10use std::slice;
11use std::sync::{Arc, Mutex};
12
13type LoadDocumentCallback = dyn Fn(
14 &str,
15 &JsonLdLoadDocumentOptions,
16 ) -> Result<JsonLdRemoteDocument, Box<dyn Error + Send + Sync>>
17 + Send
18 + Sync
19 + UnwindSafe
20 + RefUnwindSafe;
21
22type RemoteContextCache = Arc<Mutex<HashMap<String, (Option<Iri<String>>, JsonNode)>>>;
24
25#[derive(Eq, PartialEq, Debug, Clone)]
26pub enum JsonNode {
27 String(String),
28 Number(String),
29 Boolean(bool),
30 Null,
31 Array(Vec<JsonNode>),
32 Object(HashMap<String, JsonNode>),
33}
34
35#[derive(Default, Clone)]
36pub struct JsonLdContext {
37 pub base_iri: Option<Iri<String>>,
38 pub original_base_url: Option<Iri<String>>,
39 pub vocabulary_mapping: Option<String>,
40 pub default_language: Option<String>,
41 pub default_direction: Option<&'static str>,
42 pub term_definitions: HashMap<String, JsonLdTermDefinition>,
43 pub previous_context: Option<Box<JsonLdContext>>,
44}
45
46impl JsonLdContext {
47 pub fn new_empty(original_base_url: Option<Iri<String>>) -> Self {
48 JsonLdContext {
49 base_iri: original_base_url.clone(),
50 original_base_url,
51 vocabulary_mapping: None,
52 default_language: None,
53 default_direction: None,
54 term_definitions: HashMap::new(),
55 previous_context: None,
56 }
57 }
58}
59
60#[derive(Clone)]
61pub struct JsonLdTermDefinition {
62 pub iri_mapping: Option<Option<String>>,
64 pub prefix_flag: bool,
65 pub protected: bool,
66 pub reverse_property: bool,
67 pub base_url: Option<Iri<String>>,
68 pub context: Option<JsonNode>,
69 pub container_mapping: &'static [&'static str],
70 pub direction_mapping: Option<Option<&'static str>>,
71 pub index_mapping: Option<String>,
72 pub language_mapping: Option<Option<String>>,
73 pub nest_value: Option<String>,
74 pub type_mapping: Option<String>,
75}
76
77pub struct JsonLdContextProcessor {
78 pub processing_mode: JsonLdProcessingMode,
79 pub lenient: bool, pub max_context_recursion: usize,
81 pub remote_context_cache: RemoteContextCache,
82 pub load_document_callback: Option<Arc<LoadDocumentCallback>>,
83}
84
85pub struct JsonLdLoadDocumentOptions {
87 pub request_profile: JsonLdProfileSet,
89}
90
91pub struct JsonLdRemoteDocument {
93 pub document: Vec<u8>,
95 pub document_url: String,
97}
98
99impl JsonLdContextProcessor {
100 #[allow(clippy::too_many_arguments)]
102 pub fn process_context(
103 &self,
104 active_context: &JsonLdContext,
105 local_context: JsonNode,
106 base_url: Option<&Iri<String>>,
107 remote_contexts: &mut Vec<String>,
108 override_protected: bool,
109 mut propagate: bool,
110 validate_scoped_context: bool,
111 errors: &mut Vec<JsonLdSyntaxError>,
112 ) -> JsonLdContext {
113 let mut result = active_context.clone();
115 if let JsonNode::Object(local_context) = &local_context {
117 if let Some(propagate_node) = local_context.get("@propagate") {
118 if let JsonNode::Boolean(new) = propagate_node {
119 propagate = *new;
120 } else {
121 errors.push(JsonLdSyntaxError::msg("@propagate value must be a boolean"))
122 }
123 }
124 }
125 if !propagate && result.previous_context.is_none() {
127 result.previous_context = Some(Box::new(active_context.clone()));
128 }
129 let local_context = if let JsonNode::Array(c) = local_context {
131 c
132 } else {
133 vec![local_context]
134 };
135 for context in local_context {
137 let mut context = match context {
138 JsonNode::Null => {
140 if !override_protected {
142 for (name, def) in &active_context.term_definitions {
143 if def.protected {
144 errors.push(JsonLdSyntaxError::msg_and_code(format!("Definition of {name} will be overridden even if it's protected"), JsonLdErrorCode::InvalidContextNullification));
145 }
146 }
147 }
148 result = JsonLdContext::new_empty(active_context.original_base_url.clone());
150 continue;
152 }
153 JsonNode::String(context) => {
155 let context = match if let Some(base_url) = base_url {
157 base_url.resolve(&context)
158 } else {
159 Iri::parse(context.clone())
160 } {
161 Ok(url) => url.into_inner(),
162 Err(e) => {
163 errors.push(JsonLdSyntaxError::msg_and_code(
164 format!("Invalid remote context URL '{context}': {e}"),
165 JsonLdErrorCode::LoadingDocumentFailed,
166 ));
167 continue;
168 }
169 };
170 if !validate_scoped_context && remote_contexts.contains(&context) {
172 continue;
173 }
174 if remote_contexts.len() >= self.max_context_recursion {
176 errors.push(JsonLdSyntaxError::msg_and_code(
177 format!(
178 "This processor only allows {} remote context, threshold exceeded",
179 self.max_context_recursion
180 ),
181 JsonLdErrorCode::ContextOverflow,
182 ));
183 continue;
184 }
185 remote_contexts.push(context.clone());
186 let (loaded_context_base, loaded_context_content) =
187 match self.load_remote_context(&context) {
188 Ok(r) => r,
189 Err(e) => {
190 errors.push(e);
191 continue;
192 }
193 };
194 result = self.process_context(
196 &result,
197 loaded_context_content,
198 loaded_context_base.as_ref(),
199 remote_contexts,
200 false,
201 true,
202 validate_scoped_context,
203 errors,
204 );
205 assert_eq!(
206 remote_contexts.pop(),
207 Some(context),
208 "The remote context stack is invalid"
209 );
210 continue;
211 }
212 JsonNode::Array(_) | JsonNode::Number(_) | JsonNode::Boolean(_) => {
214 errors.push(JsonLdSyntaxError::msg_and_code(
215 "@context value must be null, a string or an object",
216 JsonLdErrorCode::InvalidLocalContext,
217 ));
218 continue;
219 }
220 JsonNode::Object(context) => context,
222 };
223 let mut protected = false;
224 if let Some(value) = context.remove("@version") {
226 if let JsonNode::Number(version) = value {
228 if version != "1.1" {
229 errors.push(JsonLdSyntaxError::msg_and_code(
230 format!("The only supported @version value is 1.1, found {version}"),
231 JsonLdErrorCode::InvalidVersionValue,
232 ));
233 }
234 } else {
235 errors.push(JsonLdSyntaxError::msg_and_code(
236 "@version value must be a number",
237 JsonLdErrorCode::InvalidVersionValue,
238 ));
239 }
240 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
242 errors.push(JsonLdSyntaxError::msg_and_code(
243 "@version is only supported in JSON-LD 1.1",
244 JsonLdErrorCode::ProcessingModeConflict,
245 ));
246 }
247 }
248 if let Some(value) = context.remove("@import") {
250 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
252 errors.push(JsonLdSyntaxError::msg_and_code(
253 "@import is only supported in JSON-LD 1.1",
254 JsonLdErrorCode::InvalidContextEntry,
255 ));
256 }
257 let JsonNode::String(import) = value else {
259 errors.push(JsonLdSyntaxError::msg_and_code(
260 "@import must be a string",
261 JsonLdErrorCode::InvalidImportValue,
262 ));
263 continue;
264 };
265 let import = match if let Some(base_url) = base_url {
267 base_url.resolve(&import)
268 } else {
269 Iri::parse(import.clone())
270 } {
271 Ok(import) => import,
272 Err(e) => {
273 errors.push(JsonLdSyntaxError::msg_and_code(
274 format!("Invalid @import iri {import}: {e}"),
275 JsonLdErrorCode::InvalidImportValue,
276 ));
277 continue;
278 }
279 };
280 let (_, loaded_context_content) = match self.load_remote_context(import.as_str()) {
282 Ok(r) => r,
283 Err(e) => {
284 errors.push(e);
285 continue;
286 }
287 };
288 let JsonNode::Object(loaded_context_content) = loaded_context_content else {
290 errors.push(JsonLdSyntaxError::msg_and_code(
291 format!("Imported context {import} must be an object"),
292 JsonLdErrorCode::InvalidRemoteContext,
293 ));
294 continue;
295 };
296 if loaded_context_content.contains_key("@import") {
298 errors.push(JsonLdSyntaxError::msg_and_code(
299 format!("Imported context {import} must not contain an @import key"),
300 JsonLdErrorCode::InvalidContextEntry,
301 ));
302 continue;
303 }
304 for (key, value) in loaded_context_content {
306 if let Entry::Vacant(e) = context.entry(key) {
307 e.insert(value);
308 }
309 }
310 }
311 if let Some(value) = context.remove("@base") {
313 if remote_contexts.is_empty() {
314 match value {
315 JsonNode::Null => {
317 result.base_iri = None;
318 }
319 JsonNode::String(value) => {
321 if self.lenient {
322 result.base_iri = Some(if let Some(base_iri) = &result.base_iri {
323 Iri::parse_unchecked(
324 base_iri.resolve_unchecked(&value).to_string(),
325 )
326 } else {
327 Iri::parse_unchecked(value.clone())
328 })
329 } else {
330 match if let Some(base_iri) = &result.base_iri {
331 base_iri.resolve(&value)
332 } else {
333 Iri::parse(value.clone())
334 } {
335 Ok(iri) => result.base_iri = Some(iri),
336 Err(e) => errors.push(JsonLdSyntaxError::msg_and_code(
337 format!("Invalid @base '{value}': {e}"),
338 JsonLdErrorCode::InvalidBaseIri,
339 )),
340 }
341 }
342 }
343 _ => errors.push(JsonLdSyntaxError::msg_and_code(
344 "@base value must be a string",
345 JsonLdErrorCode::InvalidBaseIri,
346 )),
347 }
348 }
349 }
350 if let Some(value) = context.remove("@vocab") {
352 match value {
353 JsonNode::Null => {
355 result.vocabulary_mapping = None;
356 }
357 JsonNode::String(value) => {
359 if let Some(vocab) = self
360 .expand_iri(
361 &mut result,
362 value.as_str().into(),
363 true,
364 true,
365 None,
366 &mut HashMap::new(),
367 errors,
368 )
369 .filter(|iri| !has_keyword_form(iri))
370 {
371 result.vocabulary_mapping = Some(vocab.into());
372 } else {
373 errors.push(JsonLdSyntaxError::msg_and_code(
374 format!("Invalid @vocab '{value}'"),
375 JsonLdErrorCode::InvalidVocabMapping,
376 ));
377 };
378 }
379 _ => errors.push(JsonLdSyntaxError::msg_and_code(
380 "@vocab value must be a string",
381 JsonLdErrorCode::InvalidVocabMapping,
382 )),
383 }
384 }
385 if let Some(value) = context.remove("@language") {
387 match value {
388 JsonNode::Null => {
390 result.default_language = None;
391 }
392 JsonNode::String(value) => result.default_language = Some(value),
394 _ => errors.push(JsonLdSyntaxError::msg_and_code(
395 "@language value must be a string or null",
396 JsonLdErrorCode::InvalidDefaultLanguage,
397 )),
398 }
399 }
400 if let Some(value) = context.remove("@direction") {
402 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
404 errors.push(JsonLdSyntaxError::msg_and_code(
405 "@direction is only supported in JSON-LD 1.1",
406 JsonLdErrorCode::InvalidContextEntry,
407 ));
408 }
409 match value {
410 JsonNode::Null => {
412 result.default_direction = None;
413 }
414 JsonNode::String(value) => match value.as_str() {
416 "ltr" => result.default_direction = Some("ltr"),
417 "rtl" => result.default_direction = Some("rtl"),
418 _ => errors.push(JsonLdSyntaxError::msg_and_code(
419 format!("@direction value must be 'ltr' or 'rtl', found '{value}'"),
420 JsonLdErrorCode::InvalidBaseDirection,
421 )),
422 },
423 _ => errors.push(JsonLdSyntaxError::msg_and_code(
424 "@direction value must be a string or null",
425 JsonLdErrorCode::InvalidBaseDirection,
426 )),
427 }
428 }
429 if let Some(value) = context.remove("@propagate") {
431 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
433 errors.push(JsonLdSyntaxError::msg_and_code(
434 "@propagate is only supported in JSON-LD 1.1",
435 JsonLdErrorCode::InvalidContextEntry,
436 ));
437 }
438 if !matches!(value, JsonNode::Boolean(_)) {
440 errors.push(JsonLdSyntaxError::msg_and_code(
441 "@propagate value must be a boolean",
442 JsonLdErrorCode::InvalidPropagateValue,
443 ));
444 continue;
445 };
446 }
447 if let Some(value) = context.remove("@protected") {
449 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
450 errors.push(JsonLdSyntaxError::msg_and_code(
451 "@protected is only supported in JSON-LD 1.1",
452 JsonLdErrorCode::InvalidContextEntry,
453 ));
454 }
455 if let JsonNode::Boolean(value) = value {
456 protected = value
457 } else {
458 errors.push(JsonLdSyntaxError::msg_and_code(
459 "@protected value must be a boolean",
460 JsonLdErrorCode::InvalidProtectedValue,
461 ))
462 }
463 }
464 let mut defined = HashMap::new();
465 for term in context.keys() {
466 self.create_term_definition(
467 &mut result,
468 &context,
469 term,
470 &mut defined,
471 base_url,
472 protected,
473 override_protected,
474 remote_contexts,
475 errors,
476 )
477 }
478 }
479 result
481 }
482
483 #[allow(clippy::too_many_arguments)]
485 fn create_term_definition(
486 &self,
487 active_context: &mut JsonLdContext,
488 local_context: &HashMap<String, JsonNode>,
489 term: &str,
490 defined: &mut HashMap<String, bool>,
491 base_url: Option<&Iri<String>>,
492 protected: bool,
493 override_protected: bool,
494 remote_contexts: &mut Vec<String>,
495 errors: &mut Vec<JsonLdSyntaxError>,
496 ) {
497 if let Some(defined_value) = defined.get(term) {
499 if !defined_value {
500 errors.push(JsonLdSyntaxError::msg_and_code(
501 "Cyclic IRI mapping",
502 JsonLdErrorCode::CyclicIriMapping,
503 ))
504 }
505 return;
506 }
507 if term.is_empty() {
509 errors.push(JsonLdSyntaxError::msg_and_code(
510 "@context terms must not be the empty strings",
511 JsonLdErrorCode::InvalidTermDefinition,
512 ));
513 return;
514 }
515 defined.insert(term.into(), false);
516 let Some(value) = local_context.get(term) else {
518 unreachable!();
519 };
520 if term == "@type" {
522 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
523 errors.push(JsonLdSyntaxError::msg_and_code(
524 "@type keyword can't be redefined in JSON-LD 1.0 @context",
525 JsonLdErrorCode::KeywordRedefinition,
526 ));
527 }
528 if let JsonNode::Object(value) = value {
529 if value.is_empty() {
530 errors.push(JsonLdSyntaxError::msg_and_code(
531 "@type keyword definition can't be empty",
532 JsonLdErrorCode::KeywordRedefinition,
533 ));
534 return;
535 }
536 for (key, key_value) in value {
537 match key.as_str() {
538 "@protected" => (),
539 "@container" => match key_value {
540 JsonNode::String(s) if s == "@set" => (),
541 JsonNode::Array(s)
542 if s.iter().all(|v| {
543 if let JsonNode::String(s) = v {
544 s == "@set"
545 } else {
546 false
547 }
548 }) => {}
549 _ => {
550 errors.push(JsonLdSyntaxError::msg_and_code(
551 "@type definition only allowed @container is @set",
552 JsonLdErrorCode::KeywordRedefinition,
553 ));
554 return;
555 }
556 },
557 _ => {
558 errors.push(JsonLdSyntaxError::msg_and_code(
559 format!("@type definition can only contain @protected and @container keywords, {key} found"),
560 JsonLdErrorCode::KeywordRedefinition,
561 ));
562 return;
563 }
564 }
565 }
566 } else {
567 errors.push(JsonLdSyntaxError::msg_and_code(
568 "@type definition must be an object",
569 JsonLdErrorCode::KeywordRedefinition,
570 ));
571 return;
572 }
573 } else if has_keyword_form(term) {
574 if is_keyword(term) {
576 errors.push(JsonLdSyntaxError::msg_and_code(
577 format!("{term} keyword can't be redefined in context"),
578 JsonLdErrorCode::KeywordRedefinition,
579 ));
580 }
581 return;
582 }
583 let previous_definition = active_context.term_definitions.remove(term);
585 let value = match value {
586 JsonNode::Null => Cow::Owned([("@id".to_owned(), JsonNode::Null)].into()),
588 JsonNode::String(id) => {
590 Cow::Owned([("@id".to_owned(), JsonNode::String(id.clone()))].into())
591 }
592 JsonNode::Object(map) => Cow::Borrowed(map),
594 _ => {
595 errors.push(JsonLdSyntaxError::msg_and_code(
596 "Term definition value must be null, a string or a map",
597 JsonLdErrorCode::InvalidTermDefinition,
598 ));
599 return;
600 }
601 };
602 let mut definition = JsonLdTermDefinition {
604 iri_mapping: None,
605 prefix_flag: false,
606 protected,
607 reverse_property: false,
608 base_url: None,
609 context: None,
610 container_mapping: &[],
611 direction_mapping: None,
612 index_mapping: None,
613 language_mapping: None,
614 nest_value: None,
615 type_mapping: None,
616 };
617 if let Some(key_value) = value.get("@protected") {
619 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
620 errors.push(JsonLdSyntaxError::msg_and_code(
621 "@protected keyword can't be used in JSON-LD 1.0 @context",
622 JsonLdErrorCode::InvalidTermDefinition,
623 ));
624 }
625 let JsonNode::Boolean(key_value) = key_value else {
626 errors.push(JsonLdSyntaxError::msg_and_code(
627 "@protected value must be a boolean",
628 JsonLdErrorCode::InvalidProtectedValue,
629 ));
630 return;
631 };
632 definition.protected = *key_value;
633 }
634 if let Some(key_value) = value.get("@type") {
636 let JsonNode::String(r#type) = key_value else {
638 errors.push(JsonLdSyntaxError::msg_and_code(
639 "The value of @type in a context must be a string",
640 JsonLdErrorCode::InvalidTypeMapping,
641 ));
642 return;
643 };
644 let Some(r#type) = self.expand_iri(
646 active_context,
647 r#type.as_str().into(),
648 false,
649 true,
650 Some(local_context),
651 defined,
652 errors,
653 ) else {
654 errors.push(JsonLdSyntaxError::msg_and_code(
655 format!("Invalid @type value in context: {type}"),
656 JsonLdErrorCode::InvalidTypeMapping,
657 ));
658 return;
659 };
660 if matches!(r#type.as_ref(), "@json" | "@none")
662 && self.processing_mode == JsonLdProcessingMode::JsonLd1_0
663 {
664 errors.push(JsonLdSyntaxError::msg_and_code(
665 format!("@type value {type} in a context is only supported in JSON-LD 1.1"),
666 JsonLdErrorCode::InvalidTypeMapping,
667 ));
668 }
669 let is_keyword = has_keyword_form(&r#type);
671 if is_keyword && !matches!(r#type.as_ref(), "@id" | "@json" | "@none" | "@vocab")
672 || r#type.starts_with("_:")
673 {
674 errors.push(JsonLdSyntaxError::msg_and_code(
675 format!("Invalid @type value in context: {type}"),
676 JsonLdErrorCode::InvalidTypeMapping,
677 ));
678 }
679 if !self.lenient && !is_keyword {
680 if let Err(e) = Iri::parse(r#type.as_ref()) {
681 errors.push(JsonLdSyntaxError::msg_and_code(
682 format!("Invalid @type iri '{type}': {e}"),
683 JsonLdErrorCode::InvalidTypeMapping,
684 ));
685 }
686 }
687 definition.type_mapping = Some(r#type.into());
689 }
690 if let Some(key_value) = value.get("@reverse") {
692 if value.contains_key("@id") {
694 errors.push(JsonLdSyntaxError::msg_and_code(
695 "@reverse and @id cannot be used together in a context",
696 JsonLdErrorCode::InvalidReverseProperty,
697 ));
698 return;
699 }
700 if value.contains_key("@nest") {
701 errors.push(JsonLdSyntaxError::msg_and_code(
702 "@reverse and @nest cannot be used together in a context",
703 JsonLdErrorCode::InvalidReverseProperty,
704 ));
705 return;
706 }
707 let JsonNode::String(key_value) = key_value else {
709 errors.push(JsonLdSyntaxError::msg_and_code(
710 "@reverse value must be a string in a context",
711 JsonLdErrorCode::InvalidIriMapping,
712 ));
713 return;
714 };
715 if let Some(iri) = self.expand_iri(
717 active_context,
718 key_value.into(),
719 false,
720 true,
721 Some(local_context),
722 defined,
723 errors,
724 ) {
725 if self.lenient && !has_keyword_form(&iri)
726 || !self.lenient && (iri.starts_with("_:") || Iri::parse(iri.as_ref()).is_ok())
727 {
728 definition.iri_mapping = Some(Some(iri.into()));
729 } else {
730 errors.push(JsonLdSyntaxError::msg_and_code(
731 format!("{iri} is not a valid IRI or blank node"),
732 JsonLdErrorCode::InvalidIriMapping,
733 ));
734 definition.iri_mapping = Some(None);
735 }
736 } else {
737 definition.iri_mapping = Some(None);
738 }
739 definition.iri_mapping = Some(
740 self.expand_iri(
741 active_context,
742 key_value.into(),
743 false,
744 true,
745 Some(local_context),
746 defined,
747 errors,
748 )
749 .map(Into::into),
750 );
751 if let Some(container_entry) = value.get("@container") {
753 match container_entry {
754 JsonNode::Null => (),
755 JsonNode::String(container_entry) => {
756 if !matches!(container_entry.as_str(), "@index" | "@set") {
757 errors.push(JsonLdSyntaxError::msg_and_code(
758 "@reverse is only compatible with @index and @set containers",
759 JsonLdErrorCode::InvalidReverseProperty,
760 ));
761 }
762 }
763 _ => {
764 errors.push(JsonLdSyntaxError::msg_and_code(
765 "@container value must be a string or null",
766 JsonLdErrorCode::InvalidReverseProperty,
767 ));
768 }
769 }
770 }
771 definition.reverse_property = true;
773 } else if let Some(key_value) = value.get("@id").filter(|v| {
774 if let JsonNode::String(v) = v {
775 v != term
776 } else {
777 true
778 }
779 }) {
780 match key_value {
782 JsonNode::Null => {
784 definition.iri_mapping = Some(None);
785 }
786 JsonNode::String(id) => {
787 if id == term {
788 return;
789 }
790 let Some(expanded) = self.expand_iri(
791 active_context,
792 id.into(),
793 false,
794 true,
795 Some(local_context),
796 defined,
797 errors,
798 ) else {
799 definition.iri_mapping = Some(None);
801 return;
802 };
803 if expanded == "@context" {
805 errors.push(JsonLdSyntaxError::msg_and_code(
806 "@context cannot be aliased with @id: @context",
807 JsonLdErrorCode::InvalidKeywordAlias,
808 ));
809 return;
810 }
811 definition.iri_mapping = Some(Some(expanded.into()));
812 if term
814 .as_bytes()
815 .get(1..term.len() - 1)
816 .is_some_and(|t| t.contains(&b':'))
817 || term.contains('/')
818 {
819 defined.insert(term.into(), true);
821 let expended_term = self.expand_iri(
823 active_context,
824 term.into(),
825 false,
826 true,
827 Some(local_context),
828 defined,
829 errors,
830 );
831 if expended_term.as_deref()
832 != definition.iri_mapping.as_ref().and_then(|o| o.as_deref())
833 {
834 errors.push(JsonLdSyntaxError::msg_and_code(
835 if let (Some(expended_term), Some(Some(iri_mapping))) = (&expended_term, &definition.iri_mapping) {
836 format!("Inconsistent expansion of {term} between {expended_term} and {iri_mapping}")
837 } else {
838 format!("Inconsistent expansion of {term}")
839 },
840 JsonLdErrorCode::InvalidIriMapping,
841 ))
842 }
843 }
844 if !term.contains(':')
846 && !term.contains('/')
847 && definition.iri_mapping.as_ref().is_some_and(|iri| {
848 iri.as_ref().is_some_and(|iri| {
849 iri.ends_with(|c| {
850 matches!(c, ':' | '/' | '?' | '#' | '[' | ']' | '@')
851 }) || iri.starts_with("_:")
852 })
853 })
854 {
855 definition.prefix_flag = true;
856 }
857 }
858 _ => {
860 definition.iri_mapping = Some(None);
861 errors.push(JsonLdSyntaxError::msg_and_code(
862 "@id value must be a string",
863 JsonLdErrorCode::InvalidIriMapping,
864 ))
865 }
866 }
867 } else if let Some((prefix, suffix)) = term.split_once(':').and_then(|(prefix, suffix)| {
868 if prefix.is_empty() {
869 suffix.split_once(':')
871 } else {
872 Some((prefix, suffix))
873 }
874 }) {
875 if local_context.contains_key(prefix) {
877 self.create_term_definition(
879 active_context,
880 local_context,
881 prefix,
882 defined,
883 base_url,
884 false,
885 false,
886 remote_contexts,
887 errors,
888 )
889 }
890 if let Some(term_definition) = active_context.term_definitions.get(prefix) {
891 if let Some(Some(iri_mapping)) = &term_definition.iri_mapping {
893 definition.iri_mapping = Some(Some(format!("{iri_mapping}{suffix}")));
894 } else {
895 errors.push(JsonLdSyntaxError::msg(format!(
896 "The prefix '{prefix}' is not associated with an IRI in the context"
897 )));
898 }
899 } else {
900 definition.iri_mapping = Some(Some(term.into()));
902 }
903 } else if term.contains('/') {
904 let iri = match if let Some(base_url) = base_url {
906 base_url.resolve(term)
907 } else {
908 Iri::parse(term.to_owned())
909 } {
910 Ok(iri) => iri.into_inner(),
911 Err(e) => {
912 errors.push(JsonLdSyntaxError::msg_and_code(
913 format!("Invalid term relative IRI '{term}': {e}"),
914 JsonLdErrorCode::InvalidIriMapping,
915 ));
916 return;
917 }
918 };
919 definition.iri_mapping = Some(Some(iri));
920 } else if term == "@type" {
921 definition.iri_mapping = Some(Some("@type".into()));
923 } else {
924 if let Some(vocabulary_mapping) = &active_context.vocabulary_mapping {
926 definition.iri_mapping = Some(Some(format!("{vocabulary_mapping}{term}")));
927 } else {
928 errors.push(JsonLdSyntaxError::msg_and_code(
929 format!("No @vocab key to build an IRI from context {term} term definition"),
930 JsonLdErrorCode::InvalidIriMapping,
931 ))
932 }
933 }
934 if let Some(key_value) = value.get("@container") {
936 const ALLOWED_CONTAINER_MAPPINGS: &[&[&str]] = &[
937 &["@index"],
938 &["@language"],
939 &["@list"],
940 &["@set"],
941 &["@index", "@set"],
942 &["@language", "@set"],
943 &["@graph"],
944 &["@graph", "@id"],
945 &["@graph", "@index"],
946 &["@graph", "@id", "@set"],
947 &["@graph", "@index", "@set"],
948 &["@id"],
949 &["@id", "@set"],
950 &["@type"],
951 &["@type", "@set"],
952 ];
953
954 let mut container_mapping = Vec::new();
956 for value in if let JsonNode::Array(value) = key_value {
957 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
958 errors.push(JsonLdSyntaxError::msg_and_code(
959 "@container definition with multiple values is not supported in JSON-LD 1.0",
960 JsonLdErrorCode::InvalidContainerMapping,
961 ));
962 }
963 value.as_slice()
964 } else {
965 slice::from_ref(key_value)
966 } {
967 if let JsonNode::String(container) = value {
968 container_mapping.push(container.as_str());
969 } else {
970 errors.push(JsonLdSyntaxError::msg_and_code(
971 "@container value must be a string or an array of strings",
972 JsonLdErrorCode::InvalidContainerMapping,
973 ));
974 }
975 }
976 container_mapping.sort_unstable();
977 let Some(container_mapping) = ALLOWED_CONTAINER_MAPPINGS
978 .iter()
979 .find_map(|c| (*c == container_mapping).then_some(*c))
980 else {
981 errors.push(JsonLdSyntaxError::msg_and_code(
982 "Not supported @container value combination",
983 JsonLdErrorCode::InvalidContainerMapping,
984 ));
985 return;
986 };
987 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
989 if let Some(bad) = ["@graph", "@id", "@type"]
990 .into_iter()
991 .find(|k| container_mapping.contains(k))
992 {
993 errors.push(JsonLdSyntaxError::msg_and_code(
994 format!("{bad} container is not supported in JSON-LD 1.0"),
995 JsonLdErrorCode::InvalidContainerMapping,
996 ));
997 }
998 }
999 definition.container_mapping = container_mapping;
1001 if container_mapping.contains(&"@type") {
1003 if let Some(type_mapping) = &definition.type_mapping {
1004 if !["@id", "@vocab"].contains(&type_mapping.as_str()) {
1005 errors.push(JsonLdSyntaxError::msg_and_code(
1006 format!("Type mapping must be @id or @vocab, not {type_mapping} when used with @type container"),
1007 JsonLdErrorCode::InvalidContainerMapping,
1008 ));
1009 }
1010 } else {
1011 definition.type_mapping = Some("@id".into());
1012 }
1013 }
1014 }
1015 if let Some(key_value) = value.get("@index") {
1017 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
1019 errors.push(JsonLdSyntaxError::msg_and_code(
1020 "@index inside of term definitions is only supported in JSON-LD 1.1",
1021 JsonLdErrorCode::InvalidTermDefinition,
1022 ));
1023 }
1024 if !definition.container_mapping.contains(&"@index") {
1025 errors.push(JsonLdSyntaxError::msg_and_code(
1026 "@index inside of term definitions is only allowed when @container is set to @index",
1027 JsonLdErrorCode::InvalidTermDefinition,
1028 ));
1029 }
1030 let JsonNode::String(index) = key_value else {
1032 errors.push(JsonLdSyntaxError::msg_and_code(
1033 "@index value must be a string",
1034 JsonLdErrorCode::InvalidTermDefinition,
1035 ));
1036 return;
1037 };
1038 let Some(index) = self.expand_iri(
1039 active_context,
1040 index.into(),
1041 false,
1042 true,
1043 Some(local_context),
1044 defined,
1045 errors,
1046 ) else {
1047 errors.push(JsonLdSyntaxError::msg_and_code(
1048 "@index value must be a valid IRI",
1049 JsonLdErrorCode::InvalidTermDefinition,
1050 ));
1051 return;
1052 };
1053 if self.lenient && (has_keyword_form(&index) || index.starts_with("_:"))
1054 || !self.lenient && Iri::parse(index.as_ref()).is_err()
1055 {
1056 errors.push(JsonLdSyntaxError::msg_and_code(
1057 "@index value must be a valid IRI",
1058 JsonLdErrorCode::InvalidTermDefinition,
1059 ));
1060 return;
1061 }
1062 definition.index_mapping = Some(index.into());
1064 }
1065 if let Some(key_value) = value.get("@context") {
1067 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
1069 errors.push(JsonLdSyntaxError::msg_and_code(
1070 "@context inside of term definitions is only supported in JSON-LD 1.1",
1071 JsonLdErrorCode::InvalidTermDefinition,
1072 ));
1073 }
1074 let context = key_value;
1076 let error_count = errors.len();
1078 self.process_context(
1079 active_context,
1080 context.clone(),
1081 base_url,
1082 remote_contexts,
1083 true,
1084 true,
1085 false,
1086 errors,
1087 );
1088 for error in errors.drain(error_count..).collect::<Vec<_>>() {
1089 errors.push(JsonLdSyntaxError::msg_and_code(
1090 format!("Invalid scoped context: {error}"),
1091 JsonLdErrorCode::InvalidScopedContext,
1092 ));
1093 }
1094 definition.context = Some(context.clone());
1096 definition.base_url = base_url.cloned();
1097 }
1098 if let Some(key_value) = value.get("@language") {
1100 if value.contains_key("@type") {
1101 errors.push(JsonLdSyntaxError::msg_and_code(
1102 "Both @language and @type can't be set at the same time",
1103 JsonLdErrorCode::InvalidLanguageMapping,
1104 ));
1105 }
1106 definition.language_mapping = Some(match key_value {
1107 JsonNode::String(language) => Some(language.clone()),
1108 JsonNode::Null => None,
1109 _ => {
1110 errors.push(JsonLdSyntaxError::msg_and_code(
1111 "@language value must be a string or null",
1112 JsonLdErrorCode::InvalidLanguageMapping,
1113 ));
1114 return;
1115 }
1116 })
1117 }
1118 if let Some(key_value) = value.get("@direction") {
1120 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
1122 errors.push(JsonLdSyntaxError::msg_and_code(
1123 "@direction is only supported in JSON-LD 1.1",
1124 JsonLdErrorCode::InvalidTermDefinition,
1125 ));
1126 }
1127 match key_value {
1128 JsonNode::Null => {
1130 definition.direction_mapping = Some(None);
1131 }
1132 JsonNode::String(value) => match value.as_str() {
1134 "ltr" => definition.direction_mapping = Some(Some("ltr")),
1135 "rtl" => definition.direction_mapping = Some(Some("rtl")),
1136 _ => errors.push(JsonLdSyntaxError::msg_and_code(
1137 format!("@direction value must be 'ltr' or 'rtl', found '{value}'"),
1138 JsonLdErrorCode::InvalidBaseDirection,
1139 )),
1140 },
1141 _ => errors.push(JsonLdSyntaxError::msg_and_code(
1142 "@direction value must be a string or null",
1143 JsonLdErrorCode::InvalidBaseDirection,
1144 )),
1145 }
1146 }
1147 if let Some(key_value) = value.get("@nest") {
1149 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
1151 errors.push(JsonLdSyntaxError::msg_and_code(
1152 "@nest is only supported in JSON-LD 1.1",
1153 JsonLdErrorCode::InvalidTermDefinition,
1154 ));
1155 }
1156 let JsonNode::String(value) = key_value else {
1158 errors.push(JsonLdSyntaxError::msg_and_code(
1159 "@nest value must be a string",
1160 JsonLdErrorCode::InvalidNestValue,
1161 ));
1162 return;
1163 };
1164 if is_keyword(value) && value != "@nest" {
1165 errors.push(JsonLdSyntaxError::msg_and_code(
1166 "@nest value must not be a keyword other than @nest",
1167 JsonLdErrorCode::InvalidNestValue,
1168 ));
1169 return;
1170 }
1171 definition.nest_value = Some(value.into());
1172 }
1173 if let Some(key_value) = value.get("@prefix") {
1175 if self.processing_mode == JsonLdProcessingMode::JsonLd1_0 {
1177 errors.push(JsonLdSyntaxError::msg_and_code(
1178 "@prefix is only supported in JSON-LD 1.1",
1179 JsonLdErrorCode::InvalidTermDefinition,
1180 ));
1181 }
1182 if term.contains(':') {
1183 errors.push(JsonLdSyntaxError::msg_and_code(
1184 format!("@prefix cannot be set on terms like {term} that contains a :"),
1185 JsonLdErrorCode::InvalidTermDefinition,
1186 ));
1187 return;
1188 }
1189 if term.contains('/') {
1190 errors.push(JsonLdSyntaxError::msg_and_code(
1191 format!("@prefix cannot be set on terms like {term} that contains a /"),
1192 JsonLdErrorCode::InvalidTermDefinition,
1193 ));
1194 return;
1195 }
1196 let JsonNode::Boolean(value) = key_value else {
1198 errors.push(JsonLdSyntaxError::msg_and_code(
1199 "@prefix value must be a boolean",
1200 JsonLdErrorCode::InvalidPrefixValue,
1201 ));
1202 return;
1203 };
1204 definition.prefix_flag = *value;
1205 if definition.prefix_flag
1207 && definition
1208 .iri_mapping
1209 .as_ref()
1210 .is_some_and(|d| d.as_ref().is_some_and(|d| is_keyword(d)))
1211 {
1212 errors.push(JsonLdSyntaxError::msg_and_code(
1213 format!("@prefix cannot be set on terms like {term} that are keywords"),
1214 JsonLdErrorCode::InvalidTermDefinition,
1215 ));
1216 return;
1217 }
1218 }
1219 if let Some(key) = value.keys().find(|k| {
1221 !matches!(
1222 k.as_str(),
1223 "@id"
1224 | "@reverse"
1225 | "@container"
1226 | "@context"
1227 | "@direction"
1228 | "@index"
1229 | "@language"
1230 | "@nest"
1231 | "@prefix"
1232 | "@protected"
1233 | "@type"
1234 )
1235 }) {
1236 errors.push(JsonLdSyntaxError::msg_and_code(
1237 format!("Unexpected key in term definition '{key}'"),
1238 JsonLdErrorCode::InvalidTermDefinition,
1239 ));
1240 }
1241 if !override_protected {
1243 if let Some(previous_definition) = previous_definition {
1244 if previous_definition.protected {
1245 if definition.iri_mapping != previous_definition.iri_mapping
1247 || definition.prefix_flag != previous_definition.prefix_flag
1248 || definition.reverse_property != previous_definition.reverse_property
1249 || definition.base_url != previous_definition.base_url
1250 || definition.context != previous_definition.context
1251 || definition.container_mapping != previous_definition.container_mapping
1252 || definition.direction_mapping != previous_definition.direction_mapping
1253 || definition.index_mapping != previous_definition.index_mapping
1254 || definition.language_mapping != previous_definition.language_mapping
1255 || definition.nest_value != previous_definition.nest_value
1256 || definition.type_mapping != previous_definition.type_mapping
1257 {
1258 errors.push(JsonLdSyntaxError::msg_and_code(
1260 format!("Overriding the protected term {term}"),
1261 JsonLdErrorCode::ProtectedTermRedefinition,
1262 ));
1263 }
1264 definition = previous_definition;
1266 }
1267 }
1268 }
1269 active_context
1271 .term_definitions
1272 .insert(term.into(), definition);
1273 defined.insert(term.into(), true);
1274 }
1275
1276 #[allow(clippy::too_many_arguments)]
1278 pub fn expand_iri<'a>(
1279 &self,
1280 active_context: &mut JsonLdContext,
1281 value: Cow<'a, str>,
1282 document_relative: bool,
1283 vocab: bool,
1284 local_context: Option<&HashMap<String, JsonNode>>,
1285 defined: &mut HashMap<String, bool>,
1286 errors: &mut Vec<JsonLdSyntaxError>,
1287 ) -> Option<Cow<'a, str>> {
1288 if has_keyword_form(&value) {
1289 return is_keyword(&value).then_some(value);
1291 }
1292 if let Some(local_context) = local_context {
1294 if local_context.contains_key(value.as_ref())
1295 && defined.get(value.as_ref()) != Some(&true)
1296 {
1297 self.create_term_definition(
1298 active_context,
1299 local_context,
1300 &value,
1301 defined,
1302 None,
1303 false,
1304 false,
1305 &mut Vec::new(),
1306 errors,
1307 )
1308 }
1309 }
1310 if let Some(term_definition) = active_context.term_definitions.get(value.as_ref()) {
1311 if let Some(iri_mapping) = &term_definition.iri_mapping {
1312 let iri_mapping = iri_mapping.as_ref()?;
1313 if is_keyword(iri_mapping) {
1315 return Some(iri_mapping.clone().into());
1316 }
1317 if vocab {
1319 return Some(iri_mapping.clone().into());
1320 }
1321 }
1322 }
1323 if let Some((prefix, suffix)) = value.split_once(':') {
1325 if prefix == "_" || suffix.starts_with("//") {
1327 return Some(value);
1328 }
1329 if let Some(local_context) = local_context {
1331 if local_context.contains_key(prefix) && defined.get(prefix) != Some(&true) {
1332 self.create_term_definition(
1333 active_context,
1334 local_context,
1335 prefix,
1336 defined,
1337 None,
1338 false,
1339 false,
1340 &mut Vec::new(),
1341 errors,
1342 )
1343 }
1344 }
1345 if let Some(term_definition) = active_context.term_definitions.get(prefix) {
1347 if let Some(Some(iri_mapping)) = &term_definition.iri_mapping {
1348 if term_definition.prefix_flag {
1349 return Some(format!("{iri_mapping}{suffix}").into());
1350 }
1351 }
1352 }
1353 if Iri::parse(value.as_ref()).is_ok() {
1355 return Some(value);
1356 }
1357 }
1358 if vocab {
1360 if let Some(vocabulary_mapping) = &active_context.vocabulary_mapping {
1361 return Some(format!("{vocabulary_mapping}{value}").into());
1362 }
1363 }
1364 if document_relative {
1366 if let Some(base_iri) = &active_context.base_iri {
1367 if self.lenient {
1368 return Some(base_iri.resolve_unchecked(&value).into_inner().into());
1369 } else if let Ok(value) = base_iri.resolve(&value) {
1370 return Some(value.into_inner().into());
1371 }
1372 }
1373 }
1374
1375 Some(value)
1376 }
1377
1378 fn load_remote_context(
1379 &self,
1380 url: &str,
1381 ) -> Result<(Option<Iri<String>>, JsonNode), JsonLdSyntaxError> {
1382 let mut remote_context_cache = self
1383 .remote_context_cache
1384 .lock()
1385 .map_err(|_| JsonLdSyntaxError::msg("Poisoned mutex"))?;
1386 if let Some(loaded_context) = remote_context_cache.get(url) {
1387 return Ok(loaded_context.clone());
1389 }
1390
1391 let Some(load_document_callback) = &self.load_document_callback else {
1393 return Err(JsonLdSyntaxError::msg_and_code(
1394 "No LoadDocumentCallback has been set to load remote contexts",
1395 JsonLdErrorCode::LoadingRemoteContextFailed,
1396 ));
1397 };
1398 let context_document = match load_document_callback(
1399 url,
1400 &JsonLdLoadDocumentOptions {
1401 request_profile: JsonLdProfile::Context.into(),
1402 },
1403 ) {
1404 Ok(document) => document,
1405 Err(e) => {
1406 return Err(JsonLdSyntaxError::msg_and_code(
1407 format!("Failed to load remote context {url}: {e}"),
1408 JsonLdErrorCode::LoadingRemoteContextFailed,
1409 ));
1410 }
1411 };
1412 let parsed_document = match json_slice_to_node(&context_document.document) {
1413 Ok(d) => d,
1414 Err(e) => {
1415 return Err(JsonLdSyntaxError::msg_and_code(
1416 format!("Failed to parse remote context {url}: {e}"),
1417 JsonLdErrorCode::LoadingRemoteContextFailed,
1418 ));
1419 }
1420 };
1421 let JsonNode::Object(parsed_document) = parsed_document else {
1422 return Err(JsonLdSyntaxError::msg_and_code(
1423 format!("Remote context {url} must be a map"),
1424 JsonLdErrorCode::InvalidRemoteContext,
1425 ));
1426 };
1427 let Some(loaded_context) = parsed_document
1428 .into_iter()
1429 .find_map(|(k, v)| (k == "@context").then_some(v))
1430 else {
1431 return Err(JsonLdSyntaxError::msg_and_code(
1432 format!("Remote context {url} must be contain a @context key"),
1433 JsonLdErrorCode::InvalidRemoteContext,
1434 ));
1435 };
1436 let document_url = Iri::parse(context_document.document_url).ok();
1437 remote_context_cache.insert(url.into(), (document_url.clone(), loaded_context.clone()));
1438 Ok((document_url, loaded_context))
1439 }
1440}
1441
1442pub fn has_keyword_form(value: &str) -> bool {
1443 value
1444 .strip_prefix('@')
1445 .is_some_and(|suffix| !suffix.is_empty() && suffix.bytes().all(|b| b.is_ascii_alphabetic()))
1446}
1447
1448fn is_keyword(value: &str) -> bool {
1449 matches!(
1450 value,
1451 "@base"
1452 | "@container"
1453 | "@context"
1454 | "@direction"
1455 | "@graph"
1456 | "@id"
1457 | "@import"
1458 | "@included"
1459 | "@index"
1460 | "@json"
1461 | "@language"
1462 | "@list"
1463 | "@nest"
1464 | "@none"
1465 | "@prefix"
1466 | "@propagate"
1467 | "@protected"
1468 | "@reverse"
1469 | "@set"
1470 | "@type"
1471 | "@value"
1472 | "@version"
1473 | "@vocab"
1474 )
1475}
1476
1477fn json_slice_to_node(data: &[u8]) -> Result<JsonNode, JsonSyntaxError> {
1478 let mut parser = SliceJsonParser::new(data);
1479 json_node_from_events(std::iter::from_fn(|| match parser.parse_next() {
1480 Ok(JsonEvent::Eof) => None,
1481 Ok(event) => Some(Ok(event)),
1482 Err(e) => Some(Err(e)),
1483 }))
1484}
1485
1486enum BuildingObjectOrArrayNode {
1487 Object(HashMap<String, JsonNode>),
1488 ObjectWithPendingKey(HashMap<String, JsonNode>, String),
1489 Array(Vec<JsonNode>),
1490}
1491
1492pub fn json_node_from_events<'a>(
1493 events: impl IntoIterator<Item = Result<JsonEvent<'a>, JsonSyntaxError>>,
1494) -> Result<JsonNode, JsonSyntaxError> {
1495 let mut stack = Vec::new();
1496 for event in events {
1497 if let Some(result) = match event? {
1498 JsonEvent::String(value) => {
1499 after_to_node_event(&mut stack, JsonNode::String(value.into()))
1500 }
1501 JsonEvent::Number(value) => {
1502 after_to_node_event(&mut stack, JsonNode::Number(value.into()))
1503 }
1504 JsonEvent::Boolean(value) => after_to_node_event(&mut stack, JsonNode::Boolean(value)),
1505 JsonEvent::Null => after_to_node_event(&mut stack, JsonNode::Null),
1506 JsonEvent::EndArray | JsonEvent::EndObject => {
1507 let value = match stack.pop() {
1508 Some(BuildingObjectOrArrayNode::Object(object)) => JsonNode::Object(object),
1509 Some(BuildingObjectOrArrayNode::Array(array)) => JsonNode::Array(array),
1510 _ => unreachable!(),
1511 };
1512 after_to_node_event(&mut stack, value)
1513 }
1514 JsonEvent::StartArray => {
1515 stack.push(BuildingObjectOrArrayNode::Array(Vec::new()));
1516 None
1517 }
1518 JsonEvent::StartObject => {
1519 stack.push(BuildingObjectOrArrayNode::Object(HashMap::new()));
1520 None
1521 }
1522 JsonEvent::ObjectKey(key) => {
1523 if let Some(BuildingObjectOrArrayNode::Object(object)) = stack.pop() {
1524 stack.push(BuildingObjectOrArrayNode::ObjectWithPendingKey(
1525 object,
1526 key.into(),
1527 ));
1528 }
1529 None
1530 }
1531 JsonEvent::Eof => unreachable!(),
1532 } {
1533 return Ok(result);
1534 }
1535 }
1536 unreachable!("The JSON emitted by the parser mut be valid")
1537}
1538
1539fn after_to_node_event(
1540 stack: &mut Vec<BuildingObjectOrArrayNode>,
1541 new_value: JsonNode,
1542) -> Option<JsonNode> {
1543 match stack.pop() {
1544 Some(BuildingObjectOrArrayNode::ObjectWithPendingKey(mut object, key)) => {
1545 object.insert(key, new_value);
1546 stack.push(BuildingObjectOrArrayNode::Object(object));
1547 None
1548 }
1549 Some(BuildingObjectOrArrayNode::Object(object)) => {
1550 stack.push(BuildingObjectOrArrayNode::Object(object));
1551 None
1552 }
1553 Some(BuildingObjectOrArrayNode::Array(mut array)) => {
1554 array.push(new_value);
1555 stack.push(BuildingObjectOrArrayNode::Array(array));
1556 None
1557 }
1558 None => Some(new_value),
1559 }
1560}