oxjsonld/
expansion.rs

1use crate::context::{
2    has_keyword_form, json_node_from_events, JsonLdContext, JsonLdContextProcessor,
3    JsonLdLoadDocumentOptions, JsonLdProcessingMode, JsonLdRemoteDocument,
4};
5use crate::error::JsonLdErrorCode;
6use crate::{JsonLdSyntaxError, MAX_CONTEXT_RECURSION};
7use json_event_parser::JsonEvent;
8use oxiri::Iri;
9use std::borrow::Cow;
10use std::collections::HashMap;
11use std::error::Error;
12use std::panic::{RefUnwindSafe, UnwindSafe};
13use std::sync::{Arc, Mutex};
14
15pub enum JsonLdEvent {
16    StartObject {
17        types: Vec<String>,
18    },
19    EndObject,
20    StartProperty {
21        name: String,
22        reverse: bool,
23    },
24    EndProperty,
25    Id(String),
26    Value {
27        value: JsonLdValue,
28        r#type: Option<String>,
29        language: Option<String>,
30    },
31    StartGraph,
32    EndGraph,
33    StartList,
34    EndList,
35    StartSet,
36    EndSet,
37}
38
39pub enum JsonLdValue {
40    String(String),
41    Number(String),
42    Boolean(bool),
43}
44
45enum JsonLdExpansionState {
46    Element {
47        active_property: Option<String>,
48        is_array: bool,
49        container: &'static [&'static str],
50        reverse: bool,
51    },
52    ObjectOrContainerStart {
53        buffer: Vec<(String, Vec<JsonEvent<'static>>)>,
54        depth: usize,
55        current_key: Option<String>,
56        active_property: Option<String>,
57        container: &'static [&'static str],
58        reverse: bool,
59    },
60    ObjectOrContainerStartStreaming {
61        active_property: Option<String>,
62        container: &'static [&'static str],
63        reverse: bool,
64    },
65    Context {
66        buffer: Vec<JsonEvent<'static>>,
67        depth: usize,
68        active_property: Option<String>,
69        container: &'static [&'static str],
70        reverse: bool,
71    },
72    ObjectStart {
73        types: Vec<String>,
74        id: Option<String>,
75        seen_type: bool,
76        active_property: Option<String>,
77        reverse: bool,
78    },
79    ObjectType {
80        types: Vec<String>,
81        id: Option<String>,
82        is_array: bool,
83        active_property: Option<String>,
84        reverse: bool,
85    },
86    ObjectId {
87        types: Vec<String>,
88        id: Option<String>,
89        from_start: bool,
90        reverse: bool,
91    },
92    Object {
93        in_property: bool,
94        has_emitted_id: bool,
95    },
96    ReverseStart,
97    Reverse {
98        in_property: bool,
99    },
100    Value {
101        r#type: Option<String>,
102        value: Option<JsonLdValue>,
103        language: Option<String>,
104    },
105    ValueValue {
106        r#type: Option<String>,
107        language: Option<String>,
108    },
109    ValueLanguage {
110        r#type: Option<String>,
111        value: Option<JsonLdValue>,
112    },
113    ValueType {
114        value: Option<JsonLdValue>,
115        language: Option<String>,
116    },
117    Index,
118    Graph,
119    RootGraph,
120    ListOrSetContainer {
121        needs_end_object: bool,
122        end_event: Option<JsonLdEvent>,
123    },
124    IndexContainer {
125        active_property: Option<String>,
126    },
127    LanguageContainer,
128    LanguageContainerValue {
129        language: String,
130        is_array: bool,
131    },
132    Skip {
133        is_array: bool,
134    },
135}
136
137/// Applies the [Expansion Algorithm](https://www.w3.org/TR/json-ld-api/#expansion-algorithms)
138pub struct JsonLdExpansionConverter {
139    state: Vec<JsonLdExpansionState>,
140    context: Vec<(JsonLdContext, usize)>,
141    is_end: bool,
142    streaming: bool,
143    lenient: bool,
144    base_url: Option<Iri<String>>,
145    context_processor: JsonLdContextProcessor,
146}
147
148#[allow(clippy::expect_used, clippy::unwrap_in_result)]
149impl JsonLdExpansionConverter {
150    pub fn new(
151        base_url: Option<Iri<String>>,
152        streaming: bool,
153        lenient: bool,
154        processing_mode: JsonLdProcessingMode,
155    ) -> Self {
156        Self {
157            state: vec![JsonLdExpansionState::Element {
158                active_property: None,
159                is_array: false,
160                container: &[],
161                reverse: false,
162            }],
163            context: vec![(JsonLdContext::new_empty(base_url.clone()), 0)],
164            is_end: false,
165            streaming,
166            lenient,
167            base_url,
168            context_processor: JsonLdContextProcessor {
169                processing_mode,
170                lenient,
171                max_context_recursion: MAX_CONTEXT_RECURSION,
172                remote_context_cache: Arc::new(Mutex::new(HashMap::new())), /* TODO: share in the parser */
173                load_document_callback: None,
174            },
175        }
176    }
177
178    pub fn is_end(&self) -> bool {
179        self.is_end
180    }
181
182    pub fn with_load_document_callback(
183        mut self,
184        callback: impl Fn(
185                &str,
186                &JsonLdLoadDocumentOptions,
187            ) -> Result<JsonLdRemoteDocument, Box<dyn Error + Send + Sync>>
188            + Send
189            + Sync
190            + UnwindSafe
191            + RefUnwindSafe
192            + 'static,
193    ) -> Self {
194        self.context_processor.load_document_callback = Some(Arc::new(callback));
195        self
196    }
197
198    pub fn convert_event(
199        &mut self,
200        event: JsonEvent<'_>,
201        results: &mut Vec<JsonLdEvent>,
202        errors: &mut Vec<JsonLdSyntaxError>,
203    ) {
204        if self.state.len() > 4096 {
205            errors.push(JsonLdSyntaxError::msg("Too large state stack"));
206            return;
207        }
208        if event == JsonEvent::Eof {
209            self.is_end = true;
210            return;
211        }
212
213        // Large hack to fetch the last state but keep it if we are in an array
214        let state = self.state.pop().expect("Empty stack");
215        match state {
216            JsonLdExpansionState::Element {
217                active_property,
218                is_array,
219                container,
220                reverse,
221            } => {
222                match event {
223                    JsonEvent::Null => {
224                        // 1)
225                        if is_array {
226                            self.state.push(JsonLdExpansionState::Element {
227                                active_property,
228                                is_array,
229                                container,
230                                reverse,
231                            });
232                        }
233                    }
234                    JsonEvent::String(value) => self.on_literal_value(
235                        JsonLdValue::String(value.into()),
236                        active_property,
237                        is_array,
238                        container,
239                        reverse,
240                        results,
241                        errors,
242                    ),
243                    JsonEvent::Number(value) => self.on_literal_value(
244                        JsonLdValue::Number(value.into()),
245                        active_property,
246                        is_array,
247                        container,
248                        reverse,
249                        results,
250                        errors,
251                    ),
252                    JsonEvent::Boolean(value) => self.on_literal_value(
253                        JsonLdValue::Boolean(value),
254                        active_property,
255                        is_array,
256                        container,
257                        reverse,
258                        results,
259                        errors,
260                    ),
261                    JsonEvent::StartArray => {
262                        // 5)
263                        if is_array {
264                            self.state.push(JsonLdExpansionState::Element {
265                                active_property: active_property.clone(),
266                                is_array,
267                                container,
268                                reverse,
269                            });
270                        } else if container.contains(&"@list") {
271                            if reverse {
272                                errors.push(JsonLdSyntaxError::msg_and_code(
273                                    "Lists are not allowed inside of reverse properties",
274                                    JsonLdErrorCode::InvalidReversePropertyValue,
275                                ))
276                            }
277                            results.push(JsonLdEvent::StartList);
278                            self.state.push(JsonLdExpansionState::ListOrSetContainer {
279                                needs_end_object: false,
280                                end_event: Some(JsonLdEvent::EndList),
281                            })
282                        } else if container.contains(&"@set") {
283                            results.push(JsonLdEvent::StartSet);
284                            self.state.push(JsonLdExpansionState::ListOrSetContainer {
285                                needs_end_object: false,
286                                end_event: Some(JsonLdEvent::EndSet),
287                            })
288                        }
289                        self.state.push(JsonLdExpansionState::Element {
290                            active_property,
291                            is_array: true,
292                            container: &[],
293                            reverse,
294                        });
295                    }
296                    JsonEvent::EndArray => (),
297                    JsonEvent::StartObject => {
298                        if is_array {
299                            self.state.push(JsonLdExpansionState::Element {
300                                active_property: active_property.clone(),
301                                is_array,
302                                container,
303                                reverse,
304                            });
305                        } else if container.contains(&"@index") {
306                            self.state
307                                .push(JsonLdExpansionState::IndexContainer { active_property });
308                            return;
309                        } else if container.contains(&"@language") {
310                            self.state.push(JsonLdExpansionState::LanguageContainer);
311                            return;
312                        }
313                        self.push_same_context();
314                        self.state.push(if self.streaming {
315                            JsonLdExpansionState::ObjectOrContainerStartStreaming {
316                                active_property,
317                                container,
318                                reverse,
319                            }
320                        } else {
321                            JsonLdExpansionState::ObjectOrContainerStart {
322                                buffer: Vec::new(),
323                                depth: 1,
324                                current_key: None,
325                                active_property,
326                                container,
327                                reverse,
328                            }
329                        });
330                    }
331                    JsonEvent::EndObject | JsonEvent::ObjectKey(_) | JsonEvent::Eof => {
332                        unreachable!()
333                    }
334                }
335            }
336            JsonLdExpansionState::ObjectOrContainerStart {
337                mut buffer,
338                mut depth,
339                mut current_key,
340                active_property,
341                container,
342                reverse,
343            } => {
344                // We have to buffer everything to make sure we get the @context key even if it's at the end
345                match event {
346                    JsonEvent::String(_)
347                    | JsonEvent::Number(_)
348                    | JsonEvent::Boolean(_)
349                    | JsonEvent::Null => {
350                        buffer.last_mut().unwrap().1.push(to_owned_event(event));
351                    }
352                    JsonEvent::ObjectKey(key) => {
353                        if depth == 1 {
354                            buffer.push((key.clone().into(), Vec::new()));
355                            current_key = Some(key.into());
356                        } else {
357                            buffer
358                                .last_mut()
359                                .unwrap()
360                                .1
361                                .push(to_owned_event(JsonEvent::ObjectKey(key)));
362                        }
363                    }
364                    JsonEvent::EndArray | JsonEvent::EndObject => {
365                        if depth > 1 {
366                            buffer.last_mut().unwrap().1.push(to_owned_event(event));
367                        }
368                        depth -= 1;
369                    }
370                    JsonEvent::StartArray | JsonEvent::StartObject => {
371                        buffer.last_mut().unwrap().1.push(to_owned_event(event));
372                        depth += 1;
373                    }
374                    JsonEvent::Eof => unreachable!(),
375                }
376                if depth == 0 {
377                    // We look for @context @type, @id and @graph
378                    let mut context_value = None;
379                    let mut type_data = None;
380                    let mut id_data = None;
381                    let mut graph_data = Vec::new();
382                    let mut other_data = Vec::with_capacity(buffer.len());
383                    for (key, value) in buffer {
384                        let expanded = self.expand_iri(key.as_str().into(), false, true, errors);
385                        match expanded.as_deref() {
386                            Some("@context") => {
387                                if context_value.is_some() {
388                                    errors.push(JsonLdSyntaxError::msg("@context is defined twice"))
389                                }
390                                context_value = Some(value);
391                            }
392                            Some("@type") => {
393                                if type_data.is_some() {
394                                    errors.push(JsonLdSyntaxError::msg("@type is defined twice"))
395                                }
396                                type_data = Some((key, value));
397                            }
398                            Some("@id") => {
399                                if id_data.is_some() {
400                                    errors.push(JsonLdSyntaxError::msg("@id is defined twice"))
401                                }
402                                id_data = Some((key, value));
403                            }
404                            Some("@graph") => {
405                                graph_data.push((key, value));
406                            }
407                            _ => other_data.push((key, value)),
408                        }
409                    }
410                    self.state
411                        .push(JsonLdExpansionState::ObjectOrContainerStartStreaming {
412                            active_property,
413                            container,
414                            reverse,
415                        });
416
417                    // We first process @context, @type and @id then other then graph
418                    if let Some(context) = context_value {
419                        self.push_new_context(context, errors);
420                    }
421                    for (key, value) in type_data
422                        .into_iter()
423                        .chain(id_data)
424                        .chain(other_data)
425                        .chain(graph_data)
426                    {
427                        self.convert_event(JsonEvent::ObjectKey(key.into()), results, errors);
428                        for event in value {
429                            self.convert_event(event, results, errors);
430                        }
431                    }
432                    self.convert_event(JsonEvent::EndObject, results, errors);
433                } else {
434                    self.state
435                        .push(JsonLdExpansionState::ObjectOrContainerStart {
436                            buffer,
437                            depth,
438                            current_key,
439                            active_property,
440                            container,
441                            reverse,
442                        });
443                }
444            }
445            JsonLdExpansionState::ObjectOrContainerStartStreaming {
446                active_property,
447                container,
448                reverse,
449            } => match event {
450                JsonEvent::ObjectKey(key) => {
451                    if let Some(iri) = self.expand_iri(key.as_ref().into(), false, true, errors) {
452                        match iri.as_ref() {
453                            "@context" => self.state.push(JsonLdExpansionState::Context {
454                                buffer: Vec::new(),
455                                depth: 0,
456                                active_property,
457                                container,
458                                reverse,
459                            }),
460                            "@index" => {
461                                self.state.push(
462                                    JsonLdExpansionState::ObjectOrContainerStartStreaming {
463                                        active_property,
464                                        container,
465                                        reverse,
466                                    },
467                                );
468                                self.state.push(JsonLdExpansionState::Index);
469                            }
470                            "@list" => {
471                                if active_property.is_some() {
472                                    if reverse {
473                                        errors.push(JsonLdSyntaxError::msg_and_code(
474                                            "Lists are not allowed inside of reverse properties",
475                                            JsonLdErrorCode::InvalidReversePropertyValue,
476                                        ))
477                                    }
478                                    self.state.push(JsonLdExpansionState::ListOrSetContainer {
479                                        needs_end_object: true,
480                                        end_event: Some(JsonLdEvent::EndList),
481                                    });
482                                    self.state.push(JsonLdExpansionState::Element {
483                                        is_array: false,
484                                        active_property,
485                                        container: &[],
486                                        reverse: false,
487                                    });
488                                    results.push(JsonLdEvent::StartList);
489                                } else {
490                                    // We don't have an active property, we skip the list
491                                    self.state
492                                        .push(JsonLdExpansionState::Skip { is_array: false });
493                                    self.state
494                                        .push(JsonLdExpansionState::Skip { is_array: false });
495                                }
496                            }
497                            "@set" => {
498                                let has_property = active_property.is_some();
499                                self.state.push(JsonLdExpansionState::ListOrSetContainer {
500                                    needs_end_object: true,
501                                    end_event: has_property.then_some(JsonLdEvent::EndSet),
502                                });
503                                self.state.push(JsonLdExpansionState::Element {
504                                    is_array: false,
505                                    active_property,
506                                    container: &[],
507                                    reverse: false,
508                                });
509                                if has_property {
510                                    results.push(JsonLdEvent::StartSet);
511                                }
512                            }
513                            _ => {
514                                if container.contains(&"@list") {
515                                    results.push(JsonLdEvent::StartList);
516                                    self.state.push(JsonLdExpansionState::ListOrSetContainer {
517                                        needs_end_object: false,
518                                        end_event: Some(JsonLdEvent::EndList),
519                                    });
520                                } else if container.contains(&"@set") {
521                                    results.push(JsonLdEvent::StartSet);
522                                    self.state.push(JsonLdExpansionState::ListOrSetContainer {
523                                        needs_end_object: false,
524                                        end_event: Some(JsonLdEvent::EndSet),
525                                    });
526                                }
527                                self.state.push(JsonLdExpansionState::ObjectStart {
528                                    types: Vec::new(),
529                                    id: None,
530                                    seen_type: false,
531                                    active_property,
532                                    reverse,
533                                });
534                                self.convert_event(JsonEvent::ObjectKey(key), results, errors)
535                            }
536                        }
537                    } else {
538                        self.state.push(JsonLdExpansionState::ObjectStart {
539                            types: Vec::new(),
540                            id: None,
541                            seen_type: false,
542                            active_property,
543                            reverse,
544                        });
545                        self.convert_event(JsonEvent::ObjectKey(key), results, errors)
546                    }
547                }
548                JsonEvent::EndObject => {
549                    self.state.push(JsonLdExpansionState::ObjectStart {
550                        types: Vec::new(),
551                        id: None,
552                        seen_type: false,
553                        active_property,
554                        reverse,
555                    });
556                    self.convert_event(JsonEvent::EndObject, results, errors)
557                }
558                _ => unreachable!("Inside of an object"),
559            },
560            JsonLdExpansionState::Context {
561                mut buffer,
562                mut depth,
563                active_property,
564                container,
565                reverse,
566            } => {
567                match event {
568                    JsonEvent::String(_)
569                    | JsonEvent::Number(_)
570                    | JsonEvent::Boolean(_)
571                    | JsonEvent::Null
572                    | JsonEvent::ObjectKey(_) => buffer.push(to_owned_event(event)),
573                    JsonEvent::EndArray | JsonEvent::EndObject => {
574                        buffer.push(to_owned_event(event));
575                        depth -= 1;
576                    }
577                    JsonEvent::StartArray | JsonEvent::StartObject => {
578                        buffer.push(to_owned_event(event));
579                        depth += 1;
580                    }
581                    JsonEvent::Eof => unreachable!(),
582                }
583                if depth == 0 {
584                    self.push_new_context(buffer, errors);
585                    self.state
586                        .push(JsonLdExpansionState::ObjectOrContainerStartStreaming {
587                            active_property,
588                            container,
589                            reverse,
590                        });
591                } else {
592                    self.state.push(JsonLdExpansionState::Context {
593                        buffer,
594                        depth,
595                        active_property,
596                        container,
597                        reverse,
598                    });
599                }
600            }
601            JsonLdExpansionState::ObjectStart {
602                types,
603                id,
604                seen_type,
605                active_property,
606                reverse,
607            } => match event {
608                JsonEvent::ObjectKey(key) => {
609                    if let Some(iri) = self.expand_iri(key.as_ref().into(), false, true, errors) {
610                        match iri.as_ref() {
611                            "@type" => {
612                                if seen_type && !self.lenient {
613                                    errors.push(JsonLdSyntaxError::msg_and_code(
614                                        "@type must be the first key of an object or right after @context",
615                                        JsonLdErrorCode::InvalidStreamingKeyOrder,
616                                    ))
617                                }
618                                self.state.push(JsonLdExpansionState::ObjectType {
619                                    id,
620                                    types,
621                                    is_array: false,
622                                    active_property,
623                                    reverse,
624                                });
625                            }
626                            "@value" | "@language" => {
627                                if types.len() > 1 {
628                                    errors.push(JsonLdSyntaxError::msg_and_code(
629                                        "Only a single @type is allowed when @value is present",
630                                        JsonLdErrorCode::InvalidTypedValue,
631                                    ));
632                                }
633                                if id.is_some() {
634                                    errors.push(JsonLdSyntaxError::msg_and_code(
635                                        "@value and @id are incompatible",
636                                        JsonLdErrorCode::InvalidValueObject,
637                                    ));
638                                }
639                                if reverse {
640                                    errors.push(JsonLdSyntaxError::msg_and_code(
641                                        "Literals are not allowed inside of reverse properties",
642                                        JsonLdErrorCode::InvalidReversePropertyValue,
643                                    ))
644                                }
645                                self.state.push(JsonLdExpansionState::Value {
646                                    r#type: types.into_iter().next(),
647                                    value: None,
648                                    language: None,
649                                });
650                                self.convert_event(JsonEvent::ObjectKey(key), results, errors);
651                            }
652                            "@id" => {
653                                if id.is_some() {
654                                    errors.push(JsonLdSyntaxError::msg_and_code(
655                                        "Only a single @id is allowed",
656                                        JsonLdErrorCode::CollidingKeywords,
657                                    ));
658                                }
659                                self.state.push(JsonLdExpansionState::ObjectId {
660                                    types,
661                                    id,
662                                    from_start: true,
663                                    reverse,
664                                });
665                            }
666                            "@graph"
667                                if id.is_none() && types.is_empty() && self.state.is_empty() =>
668                            {
669                                // Graph only for @context
670                                self.state.push(JsonLdExpansionState::RootGraph);
671                                self.state.push(JsonLdExpansionState::Element {
672                                    active_property: None,
673                                    is_array: false,
674                                    container: &[],
675                                    reverse: false,
676                                })
677                            }
678                            "@index" => {
679                                self.state.push(JsonLdExpansionState::ObjectStart {
680                                    types,
681                                    id,
682                                    seen_type,
683                                    active_property,
684                                    reverse,
685                                });
686                                self.state.push(JsonLdExpansionState::Index);
687                            }
688                            _ => {
689                                results.push(JsonLdEvent::StartObject { types });
690                                let has_emitted_id = id.is_some();
691                                if let Some(id) = id {
692                                    results.push(JsonLdEvent::Id(id));
693                                }
694                                self.state.push(JsonLdExpansionState::Object {
695                                    in_property: false,
696                                    has_emitted_id,
697                                });
698                                self.convert_event(JsonEvent::ObjectKey(key), results, errors);
699                            }
700                        }
701                    } else {
702                        self.state.push(JsonLdExpansionState::ObjectStart {
703                            types,
704                            id,
705                            seen_type: true,
706                            active_property,
707                            reverse,
708                        });
709                        self.state
710                            .push(JsonLdExpansionState::Skip { is_array: false });
711                    }
712                }
713                JsonEvent::EndObject => {
714                    results.push(JsonLdEvent::StartObject { types });
715                    if let Some(id) = id {
716                        results.push(JsonLdEvent::Id(id));
717                    }
718                    results.push(JsonLdEvent::EndObject);
719                    self.pop_context();
720                }
721                _ => unreachable!("Inside of an object"),
722            },
723            JsonLdExpansionState::ObjectType {
724                mut types,
725                id,
726                is_array,
727                active_property,
728                reverse,
729            } => {
730                match event {
731                    JsonEvent::Null | JsonEvent::Number(_) | JsonEvent::Boolean(_) => {
732                        // 13.4.4.1)
733                        errors.push(JsonLdSyntaxError::msg_and_code(
734                            "@type value must be a string",
735                            JsonLdErrorCode::InvalidTypeValue,
736                        ));
737                        if is_array {
738                            self.state.push(JsonLdExpansionState::ObjectType {
739                                types,
740                                id,
741                                is_array,
742                                active_property,
743                                reverse,
744                            });
745                        } else {
746                            self.state.push(JsonLdExpansionState::ObjectStart {
747                                types,
748                                id,
749                                seen_type: true,
750                                active_property,
751                                reverse,
752                            });
753                        }
754                    }
755                    JsonEvent::String(value) => {
756                        // 13.4.4.4)
757                        if let Some(iri) = self.expand_iri(value, true, true, errors) {
758                            if has_keyword_form(&iri) {
759                                errors.push(JsonLdSyntaxError::msg(format!(
760                                    "{iri} is not a valid value for @type"
761                                )));
762                            } else {
763                                types.push(iri.into());
764                            }
765                        }
766                        if is_array {
767                            self.state.push(JsonLdExpansionState::ObjectType {
768                                types,
769                                id,
770                                is_array,
771                                active_property,
772                                reverse,
773                            });
774                        } else {
775                            self.state.push(JsonLdExpansionState::ObjectStart {
776                                types,
777                                id,
778                                seen_type: true,
779                                active_property,
780                                reverse,
781                            });
782                        }
783                    }
784                    JsonEvent::StartArray => {
785                        self.state.push(JsonLdExpansionState::ObjectType {
786                            types,
787                            id,
788                            is_array: true,
789                            active_property,
790                            reverse,
791                        });
792                        if is_array {
793                            errors.push(JsonLdSyntaxError::msg_and_code(
794                                "@type cannot contain a nested array",
795                                JsonLdErrorCode::InvalidTypeValue,
796                            ));
797                            self.state
798                                .push(JsonLdExpansionState::Skip { is_array: true });
799                        }
800                    }
801                    JsonEvent::EndArray => {
802                        self.state.push(JsonLdExpansionState::ObjectStart {
803                            types,
804                            id,
805                            seen_type: true,
806                            active_property,
807                            reverse,
808                        });
809                    }
810                    JsonEvent::StartObject => {
811                        // 13.4.4.1)
812                        errors.push(JsonLdSyntaxError::msg_and_code(
813                            "@type value must be a string",
814                            JsonLdErrorCode::InvalidTypeValue,
815                        ));
816                        if is_array {
817                            self.state.push(JsonLdExpansionState::ObjectType {
818                                types,
819                                id,
820                                is_array: true,
821                                active_property,
822                                reverse,
823                            });
824                        } else {
825                            self.state.push(JsonLdExpansionState::ObjectStart {
826                                types,
827                                id,
828                                seen_type: true,
829                                active_property,
830                                reverse,
831                            });
832                        }
833                        self.state
834                            .push(JsonLdExpansionState::Skip { is_array: false });
835                    }
836                    JsonEvent::ObjectKey(_) | JsonEvent::EndObject | JsonEvent::Eof => {
837                        unreachable!()
838                    }
839                }
840            }
841            JsonLdExpansionState::ObjectId {
842                types,
843                mut id,
844                from_start,
845                reverse,
846            } => {
847                if let JsonEvent::String(new_id) = event {
848                    if let Some(new_id) = self.expand_iri(new_id, true, false, errors) {
849                        if has_keyword_form(&new_id) {
850                            errors.push(JsonLdSyntaxError::msg(
851                                "@id value must be an IRI or a blank node",
852                            ));
853                        } else {
854                            id = Some(new_id.into());
855                        }
856                    }
857                    self.state.push(if from_start {
858                        JsonLdExpansionState::ObjectStart {
859                            types,
860                            id,
861                            seen_type: true,
862                            active_property: None,
863                            reverse,
864                        }
865                    } else {
866                        if let Some(id) = id {
867                            results.push(JsonLdEvent::Id(id));
868                        }
869                        JsonLdExpansionState::Object {
870                            in_property: false,
871                            has_emitted_id: true,
872                        }
873                    })
874                } else {
875                    errors.push(JsonLdSyntaxError::msg_and_code(
876                        "@id value must be a string",
877                        JsonLdErrorCode::InvalidIdValue,
878                    ));
879                    self.state.push(if from_start {
880                        JsonLdExpansionState::ObjectStart {
881                            types,
882                            id,
883                            seen_type: true,
884                            active_property: None,
885                            reverse,
886                        }
887                    } else {
888                        JsonLdExpansionState::Object {
889                            in_property: false,
890                            has_emitted_id: true,
891                        }
892                    });
893                    self.state
894                        .push(JsonLdExpansionState::Skip { is_array: false });
895                    self.convert_event(event, results, errors);
896                }
897            }
898            JsonLdExpansionState::Object {
899                in_property,
900                has_emitted_id,
901            } => {
902                if in_property {
903                    results.push(JsonLdEvent::EndProperty);
904                }
905                match event {
906                    JsonEvent::EndObject => {
907                        results.push(JsonLdEvent::EndObject);
908                        self.pop_context();
909                    }
910                    JsonEvent::ObjectKey(key) => {
911                        if let Some(iri) = self.expand_iri(key.as_ref().into(), false, true, errors)
912                        {
913                            match iri.as_ref() {
914                                "@id" => {
915                                    if has_emitted_id {
916                                        errors.push(JsonLdSyntaxError::msg("Duplicated @id key"));
917                                        self.state.push(JsonLdExpansionState::Object {
918                                            in_property: false,
919                                            has_emitted_id: true,
920                                        });
921                                        self.state
922                                            .push(JsonLdExpansionState::Skip { is_array: false });
923                                    } else {
924                                        self.state.push(JsonLdExpansionState::ObjectId {
925                                            types: Vec::new(),
926                                            id: None,
927                                            from_start: false,
928                                            reverse: false,
929                                        });
930                                    }
931                                }
932                                "@graph" => {
933                                    self.state.push(JsonLdExpansionState::Object {
934                                        in_property: false,
935                                        has_emitted_id,
936                                    });
937                                    self.state.push(JsonLdExpansionState::Graph);
938                                    self.state.push(JsonLdExpansionState::Element {
939                                        is_array: false,
940                                        active_property: None,
941                                        container: &[],
942                                        reverse: false,
943                                    });
944                                    results.push(JsonLdEvent::StartGraph);
945                                }
946                                "@context" => {
947                                    errors.push(JsonLdSyntaxError::msg_and_code(
948                                        "@context must be the first key of an object",
949                                        JsonLdErrorCode::InvalidStreamingKeyOrder,
950                                    ));
951                                    self.state.push(JsonLdExpansionState::Object {
952                                        in_property: false,
953                                        has_emitted_id,
954                                    });
955                                    self.state
956                                        .push(JsonLdExpansionState::Skip { is_array: false });
957                                }
958                                "@type" => {
959                                    // TODO: be nice and allow this if lenient
960                                    errors.push(JsonLdSyntaxError::msg_and_code(
961                                        "@type must be the first key of an object or right after @context",
962                                        JsonLdErrorCode::InvalidStreamingKeyOrder,
963                                    ));
964                                    self.state.push(JsonLdExpansionState::Object {
965                                        in_property: false,
966                                        has_emitted_id,
967                                    });
968                                    self.state
969                                        .push(JsonLdExpansionState::Skip { is_array: false });
970                                }
971                                "@index" => {
972                                    self.state.push(JsonLdExpansionState::Object {
973                                        in_property: false,
974                                        has_emitted_id,
975                                    });
976                                    self.state.push(JsonLdExpansionState::Index);
977                                }
978                                "@reverse" => {
979                                    self.state.push(JsonLdExpansionState::Object {
980                                        in_property: false,
981                                        has_emitted_id,
982                                    });
983                                    self.state.push(JsonLdExpansionState::ReverseStart);
984                                }
985                                _ if has_keyword_form(&iri) => {
986                                    errors.push(if iri == "@list" || iri == "@set" {
987                                        JsonLdSyntaxError::msg_and_code(
988                                            "@list and @set must be the only keys of an object",
989                                            JsonLdErrorCode::InvalidSetOrListObject,
990                                        )
991                                    } else if iri == "@context" {
992                                        JsonLdSyntaxError::msg_and_code(
993                                            "@context must be the first key of an object",
994                                            JsonLdErrorCode::InvalidStreamingKeyOrder,
995                                        )
996                                    } else {
997                                        JsonLdSyntaxError::msg(format!(
998                                            "Unsupported JSON-LD keyword: {iri}"
999                                        ))
1000                                    });
1001                                    self.state.push(JsonLdExpansionState::Object {
1002                                        in_property: false,
1003                                        has_emitted_id,
1004                                    });
1005                                    self.state
1006                                        .push(JsonLdExpansionState::Skip { is_array: false });
1007                                }
1008                                _ => {
1009                                    let (container, reverse) = self
1010                                        .context()
1011                                        .term_definitions
1012                                        .get(key.as_ref())
1013                                        .map_or(([].as_slice(), false), |term_definition| {
1014                                            (
1015                                                term_definition.container_mapping,
1016                                                term_definition.reverse_property,
1017                                            )
1018                                        });
1019                                    self.state.push(JsonLdExpansionState::Object {
1020                                        in_property: true,
1021                                        has_emitted_id,
1022                                    });
1023                                    self.state.push(JsonLdExpansionState::Element {
1024                                        active_property: Some(key.clone().into()),
1025                                        is_array: false,
1026                                        container,
1027                                        reverse,
1028                                    });
1029                                    results.push(JsonLdEvent::StartProperty {
1030                                        name: iri.into(),
1031                                        reverse,
1032                                    });
1033                                }
1034                            }
1035                        } else {
1036                            self.state.push(JsonLdExpansionState::Object {
1037                                in_property: false,
1038                                has_emitted_id,
1039                            });
1040                            self.state
1041                                .push(JsonLdExpansionState::Skip { is_array: false });
1042                        }
1043                    }
1044                    JsonEvent::Null
1045                    | JsonEvent::String(_)
1046                    | JsonEvent::Number(_)
1047                    | JsonEvent::Boolean(_)
1048                    | JsonEvent::StartArray
1049                    | JsonEvent::EndArray
1050                    | JsonEvent::StartObject
1051                    | JsonEvent::Eof => unreachable!(),
1052                }
1053            }
1054            JsonLdExpansionState::ReverseStart => {
1055                if matches!(event, JsonEvent::StartObject) {
1056                    self.state
1057                        .push(JsonLdExpansionState::Reverse { in_property: false });
1058                } else {
1059                    errors.push(JsonLdSyntaxError::msg_and_code(
1060                        "@reverse value must be a JSON object",
1061                        JsonLdErrorCode::InvalidReverseValue,
1062                    ));
1063                    self.state
1064                        .push(JsonLdExpansionState::Skip { is_array: false });
1065                    self.convert_event(event, results, errors);
1066                }
1067            }
1068            JsonLdExpansionState::Reverse { in_property } => {
1069                if in_property {
1070                    results.push(JsonLdEvent::EndProperty);
1071                }
1072                match event {
1073                    JsonEvent::EndObject => (),
1074                    JsonEvent::ObjectKey(key) => {
1075                        if let Some(iri) = self.expand_iri(key.as_ref().into(), false, true, errors)
1076                        {
1077                            if has_keyword_form(&iri) {
1078                                errors.push(JsonLdSyntaxError::msg_and_code(
1079                                    format!(
1080                                        "@reverse object value cannot contain any keyword, found {iri}",
1081                                    ),
1082                                    JsonLdErrorCode::InvalidReversePropertyMap,
1083                                ));
1084                                self.state
1085                                    .push(JsonLdExpansionState::Reverse { in_property: false });
1086                                self.state
1087                                    .push(JsonLdExpansionState::Skip { is_array: false });
1088                            } else {
1089                                let (container, reverse) = self
1090                                    .context()
1091                                    .term_definitions
1092                                    .get(key.as_ref())
1093                                    .map_or(([].as_slice(), false), |term_definition| {
1094                                        (
1095                                            term_definition.container_mapping,
1096                                            term_definition.reverse_property,
1097                                        )
1098                                    });
1099                                let reverse = !reverse; // We are in @reverse
1100                                self.state
1101                                    .push(JsonLdExpansionState::Reverse { in_property: true });
1102                                self.state.push(JsonLdExpansionState::Element {
1103                                    active_property: Some(key.clone().into()),
1104                                    is_array: false,
1105                                    container,
1106                                    reverse,
1107                                });
1108                                results.push(JsonLdEvent::StartProperty {
1109                                    name: iri.into(),
1110                                    reverse,
1111                                });
1112                            }
1113                        } else {
1114                            self.state
1115                                .push(JsonLdExpansionState::Reverse { in_property: false });
1116                            self.state
1117                                .push(JsonLdExpansionState::Skip { is_array: false });
1118                        }
1119                    }
1120                    JsonEvent::Null
1121                    | JsonEvent::String(_)
1122                    | JsonEvent::Number(_)
1123                    | JsonEvent::Boolean(_)
1124                    | JsonEvent::StartArray
1125                    | JsonEvent::EndArray
1126                    | JsonEvent::StartObject
1127                    | JsonEvent::Eof => unreachable!(),
1128                }
1129            }
1130            JsonLdExpansionState::Value {
1131                r#type,
1132                value,
1133                language,
1134            } => match event {
1135                JsonEvent::ObjectKey(key) => {
1136                    if let Some(iri) = self.expand_iri(key, false, true, errors) {
1137                        match iri.as_ref() {
1138                            "@value" => {
1139                                if value.is_some() {
1140                                    errors.push(JsonLdSyntaxError::msg_and_code(
1141                                        "@value cannot be set multiple times",
1142                                        JsonLdErrorCode::InvalidValueObject,
1143                                    ));
1144                                    self.state.push(JsonLdExpansionState::Value {
1145                                        r#type,
1146                                        value,
1147                                        language,
1148                                    });
1149                                    self.state
1150                                        .push(JsonLdExpansionState::Skip { is_array: false });
1151                                } else {
1152                                    self.state.push(JsonLdExpansionState::ValueValue {
1153                                        r#type,
1154                                        language,
1155                                    });
1156                                }
1157                            }
1158                            "@language" => {
1159                                if language.is_some() {
1160                                    errors.push(JsonLdSyntaxError::msg_and_code(
1161                                        "@language cannot be set multiple times",
1162                                        JsonLdErrorCode::CollidingKeywords,
1163                                    ));
1164                                    self.state.push(JsonLdExpansionState::Value {
1165                                        r#type,
1166                                        value,
1167                                        language,
1168                                    });
1169                                    self.state
1170                                        .push(JsonLdExpansionState::Skip { is_array: false });
1171                                } else {
1172                                    self.state.push(JsonLdExpansionState::ValueLanguage {
1173                                        r#type,
1174                                        value,
1175                                    });
1176                                }
1177                            }
1178                            "@type" => {
1179                                if !self.lenient {
1180                                    errors.push(JsonLdSyntaxError::msg_and_code(
1181                                        "@type must be the first key of an object or right after @context",
1182                                        JsonLdErrorCode::InvalidStreamingKeyOrder,
1183                                    ))
1184                                }
1185                                if r#type.is_some() {
1186                                    errors.push(JsonLdSyntaxError::msg_and_code(
1187                                        "@type cannot be set multiple times",
1188                                        JsonLdErrorCode::CollidingKeywords,
1189                                    ));
1190                                    self.state.push(JsonLdExpansionState::Value {
1191                                        r#type,
1192                                        value,
1193                                        language,
1194                                    });
1195                                    self.state
1196                                        .push(JsonLdExpansionState::Skip { is_array: false });
1197                                } else {
1198                                    self.state
1199                                        .push(JsonLdExpansionState::ValueType { value, language });
1200                                }
1201                            }
1202                            "@context" => {
1203                                errors.push(JsonLdSyntaxError::msg_and_code(
1204                                    "@context must be the first key of an object",
1205                                    JsonLdErrorCode::InvalidStreamingKeyOrder,
1206                                ));
1207                                self.state.push(JsonLdExpansionState::Value {
1208                                    r#type,
1209                                    value,
1210                                    language,
1211                                });
1212                                self.state
1213                                    .push(JsonLdExpansionState::Skip { is_array: false });
1214                            }
1215                            "@index" => {
1216                                self.state.push(JsonLdExpansionState::Value {
1217                                    r#type,
1218                                    value,
1219                                    language,
1220                                });
1221                                self.state.push(JsonLdExpansionState::Index);
1222                            }
1223                            _ if has_keyword_form(&iri) => {
1224                                errors.push(JsonLdSyntaxError::msg_and_code(
1225                                    format!(
1226                                        "Unsupported JSON-Ld keyword inside of a @value: {iri}",
1227                                    ),
1228                                    JsonLdErrorCode::InvalidValueObject,
1229                                ));
1230                                self.state.push(JsonLdExpansionState::Value {
1231                                    r#type,
1232                                    value,
1233                                    language,
1234                                });
1235                                self.state
1236                                    .push(JsonLdExpansionState::Skip { is_array: false });
1237                            }
1238                            _ => {
1239                                errors.push(JsonLdSyntaxError::msg_and_code(format!("Objects with @value cannot contain properties, {iri} found"), JsonLdErrorCode::InvalidValueObject));
1240                                self.state.push(JsonLdExpansionState::Value {
1241                                    r#type,
1242                                    value,
1243                                    language,
1244                                });
1245                                self.state
1246                                    .push(JsonLdExpansionState::Skip { is_array: false });
1247                            }
1248                        }
1249                    } else {
1250                        self.state.push(JsonLdExpansionState::Value {
1251                            r#type,
1252                            value,
1253                            language,
1254                        });
1255                        self.state
1256                            .push(JsonLdExpansionState::Skip { is_array: false });
1257                    }
1258                }
1259                JsonEvent::EndObject => {
1260                    if let Some(value) = value {
1261                        let mut is_valid = true;
1262                        if language.is_some() && r#type.is_some() {
1263                            errors.push(JsonLdSyntaxError::msg_and_code(
1264                                "@type and @language cannot be used together",
1265                                JsonLdErrorCode::InvalidValueObject,
1266                            ));
1267                            is_valid = false;
1268                        }
1269                        if language.is_some() && !matches!(value, JsonLdValue::String(_)) {
1270                            errors.push(JsonLdSyntaxError::msg_and_code(
1271                                "@language can be used only on a string @value",
1272                                JsonLdErrorCode::InvalidLanguageTaggedValue,
1273                            ));
1274                            is_valid = false;
1275                        }
1276                        if let Some(r#type) = &r#type {
1277                            if r#type.starts_with("_:") {
1278                                errors.push(JsonLdSyntaxError::msg_and_code(
1279                                    "@type cannot be a blank node",
1280                                    JsonLdErrorCode::InvalidTypedValue,
1281                                ));
1282                                is_valid = false;
1283                            } else if !self.lenient {
1284                                if let Err(e) = Iri::parse(r#type.as_str()) {
1285                                    errors.push(JsonLdSyntaxError::msg_and_code(
1286                                        format!("@type value '{type}' must be an IRI: {e}"),
1287                                        JsonLdErrorCode::InvalidTypedValue,
1288                                    ));
1289                                    is_valid = false;
1290                                }
1291                            }
1292                        }
1293                        if is_valid {
1294                            results.push(JsonLdEvent::Value {
1295                                value,
1296                                r#type,
1297                                language,
1298                            })
1299                        }
1300                    }
1301                    self.pop_context();
1302                }
1303                JsonEvent::Null
1304                | JsonEvent::String(_)
1305                | JsonEvent::Number(_)
1306                | JsonEvent::Boolean(_)
1307                | JsonEvent::StartArray
1308                | JsonEvent::EndArray
1309                | JsonEvent::StartObject
1310                | JsonEvent::Eof => unreachable!(),
1311            },
1312            JsonLdExpansionState::ValueValue { r#type, language } => match event {
1313                JsonEvent::Null => self.state.push(JsonLdExpansionState::Value {
1314                    r#type,
1315                    value: None,
1316                    language,
1317                }),
1318                JsonEvent::Number(value) => self.state.push(JsonLdExpansionState::Value {
1319                    r#type,
1320                    value: Some(JsonLdValue::Number(value.into())),
1321                    language,
1322                }),
1323                JsonEvent::Boolean(value) => self.state.push(JsonLdExpansionState::Value {
1324                    r#type,
1325                    value: Some(JsonLdValue::Boolean(value)),
1326                    language,
1327                }),
1328                JsonEvent::String(value) => self.state.push(JsonLdExpansionState::Value {
1329                    r#type,
1330                    value: Some(JsonLdValue::String(value.into())),
1331                    language,
1332                }),
1333                _ => {
1334                    errors.push(JsonLdSyntaxError::msg_and_code(
1335                        "@value value must be a string, number, boolean or null",
1336                        JsonLdErrorCode::InvalidValueObjectValue,
1337                    ));
1338                    self.state.push(JsonLdExpansionState::Value {
1339                        r#type,
1340                        value: None,
1341                        language,
1342                    });
1343                    self.state
1344                        .push(JsonLdExpansionState::Skip { is_array: false });
1345                    self.convert_event(event, results, errors);
1346                }
1347            },
1348            JsonLdExpansionState::ValueLanguage { value, r#type } => {
1349                if let JsonEvent::String(language) = event {
1350                    self.state.push(JsonLdExpansionState::Value {
1351                        r#type,
1352                        value,
1353                        language: Some(language.into()),
1354                    })
1355                } else {
1356                    errors.push(JsonLdSyntaxError::msg_and_code(
1357                        "@value value must be a string",
1358                        JsonLdErrorCode::InvalidLanguageTaggedString,
1359                    ));
1360                    self.state.push(JsonLdExpansionState::Value {
1361                        r#type,
1362                        value,
1363                        language: None,
1364                    });
1365                    self.state
1366                        .push(JsonLdExpansionState::Skip { is_array: false });
1367                    self.convert_event(event, results, errors);
1368                }
1369            }
1370            JsonLdExpansionState::ValueType { value, language } => {
1371                if let JsonEvent::String(t) = event {
1372                    let mut r#type = self.expand_iri(t, true, true, errors);
1373                    if let Some(iri) = &r#type {
1374                        if has_keyword_form(iri) {
1375                            errors.push(JsonLdSyntaxError::msg_and_code(
1376                                format!("{iri} is not a valid value for @type"),
1377                                JsonLdErrorCode::InvalidTypedValue,
1378                            ));
1379                            r#type = None
1380                        }
1381                    }
1382                    self.state.push(JsonLdExpansionState::Value {
1383                        r#type: r#type.map(Into::into),
1384                        value,
1385                        language,
1386                    })
1387                } else {
1388                    errors.push(JsonLdSyntaxError::msg_and_code(
1389                        "@type value must be a string when @value is present",
1390                        JsonLdErrorCode::InvalidTypedValue,
1391                    ));
1392                    self.state.push(JsonLdExpansionState::Value {
1393                        r#type: None,
1394                        value,
1395                        language,
1396                    });
1397                    self.state
1398                        .push(JsonLdExpansionState::Skip { is_array: false });
1399                    self.convert_event(event, results, errors);
1400                }
1401            }
1402            JsonLdExpansionState::Index => {
1403                if let JsonEvent::String(_) = event {
1404                    // TODO: properly emit if we implement expansion output
1405                } else {
1406                    errors.push(JsonLdSyntaxError::msg_and_code(
1407                        "@index value must be a string",
1408                        JsonLdErrorCode::InvalidIndexValue,
1409                    ));
1410                    self.state
1411                        .push(JsonLdExpansionState::Skip { is_array: false });
1412                    self.convert_event(event, results, errors);
1413                }
1414            }
1415            JsonLdExpansionState::Graph => {
1416                results.push(JsonLdEvent::EndGraph);
1417                self.convert_event(event, results, errors)
1418            }
1419            JsonLdExpansionState::RootGraph => match event {
1420                JsonEvent::ObjectKey(key) => {
1421                    errors.push(JsonLdSyntaxError::msg_and_code(
1422                        format!(
1423                            "@graph must be the last property of the object, found {key} after it"
1424                        ),
1425                        JsonLdErrorCode::InvalidStreamingKeyOrder,
1426                    ));
1427                    self.state.push(JsonLdExpansionState::RootGraph);
1428                    self.state
1429                        .push(JsonLdExpansionState::Skip { is_array: false });
1430                }
1431                JsonEvent::EndObject => (),
1432                _ => unreachable!(),
1433            },
1434            JsonLdExpansionState::ListOrSetContainer {
1435                needs_end_object,
1436                end_event,
1437            } => {
1438                if needs_end_object {
1439                    match event {
1440                        JsonEvent::EndObject => {
1441                            results.extend(end_event);
1442                            self.pop_context();
1443                        }
1444                        JsonEvent::ObjectKey(key) => {
1445                            self.state.push(JsonLdExpansionState::ListOrSetContainer {
1446                                needs_end_object,
1447                                end_event,
1448                            });
1449                            if let Some(iri) =
1450                                self.expand_iri(key.as_ref().into(), false, true, errors)
1451                            {
1452                                if iri == "@index" {
1453                                    self.state.push(JsonLdExpansionState::Index);
1454                                } else {
1455                                    errors.push(JsonLdSyntaxError::msg_and_code(
1456                                        format!(
1457                                            "@list must be the only key of an object, {key} found"
1458                                        ),
1459                                        JsonLdErrorCode::InvalidSetOrListObject,
1460                                    ));
1461                                    self.state
1462                                        .push(JsonLdExpansionState::Skip { is_array: false });
1463                                }
1464                            } else {
1465                                self.state
1466                                    .push(JsonLdExpansionState::Skip { is_array: false });
1467                            }
1468                        }
1469                        _ => unreachable!(),
1470                    }
1471                } else {
1472                    results.extend(end_event);
1473                    self.convert_event(event, results, errors)
1474                }
1475            }
1476            JsonLdExpansionState::IndexContainer { active_property } => match event {
1477                JsonEvent::EndObject => (),
1478                JsonEvent::ObjectKey(_) => {
1479                    // TODO: emit @index
1480                    self.state.push(JsonLdExpansionState::IndexContainer {
1481                        active_property: active_property.clone(),
1482                    });
1483                    self.state.push(JsonLdExpansionState::Element {
1484                        active_property,
1485                        is_array: false,
1486                        container: &[],
1487                        reverse: false,
1488                    })
1489                }
1490                _ => unreachable!(),
1491            },
1492            JsonLdExpansionState::LanguageContainer => match event {
1493                JsonEvent::EndObject => (),
1494                JsonEvent::ObjectKey(language) => {
1495                    self.state.push(JsonLdExpansionState::LanguageContainer);
1496                    self.state
1497                        .push(JsonLdExpansionState::LanguageContainerValue {
1498                            language: language.into(),
1499                            is_array: false,
1500                        })
1501                }
1502                _ => unreachable!(),
1503            },
1504            JsonLdExpansionState::LanguageContainerValue { language, is_array } => match event {
1505                JsonEvent::Null => {
1506                    if is_array {
1507                        self.state
1508                            .push(JsonLdExpansionState::LanguageContainerValue {
1509                                language,
1510                                is_array,
1511                            });
1512                    }
1513                }
1514                JsonEvent::String(value) => {
1515                    if is_array {
1516                        self.state
1517                            .push(JsonLdExpansionState::LanguageContainerValue {
1518                                language: language.clone(),
1519                                is_array,
1520                            });
1521                    }
1522                    results.push(JsonLdEvent::Value {
1523                        value: JsonLdValue::String(value.into()),
1524                        r#type: None,
1525                        language: (language != "@none").then_some(language),
1526                    })
1527                }
1528                JsonEvent::StartArray => {
1529                    self.state
1530                        .push(JsonLdExpansionState::LanguageContainerValue {
1531                            language,
1532                            is_array: true,
1533                        });
1534                    if is_array {
1535                        errors.push(JsonLdSyntaxError::msg_and_code(
1536                            "The values in a @language map must be null or strings",
1537                            JsonLdErrorCode::InvalidLanguageMapValue,
1538                        ));
1539                        self.state
1540                            .push(JsonLdExpansionState::Skip { is_array: true })
1541                    }
1542                }
1543                JsonEvent::EndArray => (),
1544                _ => {
1545                    if is_array {
1546                        self.state
1547                            .push(JsonLdExpansionState::LanguageContainerValue {
1548                                language,
1549                                is_array,
1550                            });
1551                    }
1552                    errors.push(JsonLdSyntaxError::msg_and_code(
1553                        "The values in a @language map must be null or strings",
1554                        JsonLdErrorCode::InvalidLanguageMapValue,
1555                    ));
1556                    self.state
1557                        .push(JsonLdExpansionState::Skip { is_array: false });
1558                    self.convert_event(event, results, errors);
1559                }
1560            },
1561            JsonLdExpansionState::Skip { is_array } => match event {
1562                JsonEvent::String(_)
1563                | JsonEvent::Number(_)
1564                | JsonEvent::Boolean(_)
1565                | JsonEvent::Null => {
1566                    if is_array {
1567                        self.state.push(JsonLdExpansionState::Skip { is_array });
1568                    }
1569                }
1570                JsonEvent::EndArray | JsonEvent::EndObject => (),
1571                JsonEvent::StartArray => {
1572                    if is_array {
1573                        self.state.push(JsonLdExpansionState::Skip { is_array });
1574                    }
1575                    self.state
1576                        .push(JsonLdExpansionState::Skip { is_array: true });
1577                }
1578                JsonEvent::StartObject => {
1579                    if is_array {
1580                        self.state.push(JsonLdExpansionState::Skip { is_array });
1581                    }
1582                    self.state
1583                        .push(JsonLdExpansionState::Skip { is_array: false });
1584                }
1585                JsonEvent::ObjectKey(_) => {
1586                    self.state
1587                        .push(JsonLdExpansionState::Skip { is_array: false });
1588                    self.state
1589                        .push(JsonLdExpansionState::Skip { is_array: false });
1590                }
1591                JsonEvent::Eof => unreachable!(),
1592            },
1593        }
1594    }
1595
1596    /// [IRI Expansion](https://www.w3.org/TR/json-ld-api/#iri-expansion)
1597    fn expand_iri<'a>(
1598        &mut self,
1599        value: Cow<'a, str>,
1600        document_relative: bool,
1601        vocab: bool,
1602        errors: &mut Vec<JsonLdSyntaxError>,
1603    ) -> Option<Cow<'a, str>> {
1604        self.context_processor.expand_iri(
1605            &mut self
1606                .context
1607                .last_mut()
1608                .expect("The context stack must not be empty")
1609                .0,
1610            value,
1611            document_relative,
1612            vocab,
1613            None,
1614            &mut HashMap::new(),
1615            errors,
1616        )
1617    }
1618
1619    fn on_literal_value(
1620        &mut self,
1621        value: JsonLdValue,
1622        active_property: Option<String>,
1623        is_array: bool,
1624        container: &'static [&'static str],
1625        reverse: bool,
1626        results: &mut Vec<JsonLdEvent>,
1627        errors: &mut Vec<JsonLdSyntaxError>,
1628    ) {
1629        if !is_array {
1630            if container.contains(&"@list") {
1631                if reverse {
1632                    errors.push(JsonLdSyntaxError::msg_and_code(
1633                        "Lists are not allowed inside of reverse properties",
1634                        JsonLdErrorCode::InvalidReversePropertyValue,
1635                    ))
1636                }
1637                results.push(JsonLdEvent::StartList);
1638            } else if container.contains(&"@set") {
1639                results.push(JsonLdEvent::StartSet);
1640            }
1641        }
1642        if let Some(active_property) = &active_property {
1643            self.expand_value(active_property, value, reverse, results, errors);
1644        }
1645        if is_array {
1646            self.state.push(JsonLdExpansionState::Element {
1647                active_property,
1648                is_array,
1649                container,
1650                reverse,
1651            });
1652        } else if container.contains(&"@list") {
1653            results.push(JsonLdEvent::EndList);
1654        } else if container.contains(&"@set") {
1655            results.push(JsonLdEvent::EndSet);
1656        }
1657    }
1658
1659    /// [Value Expansion](https://www.w3.org/TR/json-ld-api/#value-expansion)
1660    fn expand_value(
1661        &mut self,
1662        active_property: &str,
1663        value: JsonLdValue,
1664        reverse: bool,
1665        results: &mut Vec<JsonLdEvent>,
1666        errors: &mut Vec<JsonLdSyntaxError>,
1667    ) {
1668        let active_context = self.context();
1669        let mut r#type = None;
1670        let mut language = None;
1671        if let Some(term_definition) = active_context.term_definitions.get(active_property) {
1672            if let Some(type_mapping) = &term_definition.type_mapping {
1673                match type_mapping.as_ref() {
1674                    // 1)
1675                    "@id" => {
1676                        if let JsonLdValue::String(value) = value {
1677                            if let Some(id) = self.expand_iri(value.into(), true, false, errors) {
1678                                results.push(JsonLdEvent::StartObject { types: Vec::new() });
1679                                results.push(JsonLdEvent::Id(id.into()));
1680                                results.push(JsonLdEvent::EndObject);
1681                            }
1682                            return;
1683                        }
1684                    }
1685                    // 2)
1686                    "@vocab" => {
1687                        if let JsonLdValue::String(value) = value {
1688                            if let Some(id) = self.expand_iri(value.into(), true, true, errors) {
1689                                results.push(JsonLdEvent::StartObject { types: Vec::new() });
1690                                results.push(JsonLdEvent::Id(id.into()));
1691                                results.push(JsonLdEvent::EndObject);
1692                            }
1693                            return;
1694                        }
1695                    }
1696                    // 4)
1697                    "@none" => (),
1698                    _ => {
1699                        r#type = Some(type_mapping.clone());
1700                    }
1701                }
1702            }
1703            // 5)
1704            if matches!(value, JsonLdValue::String(_)) {
1705                language = term_definition
1706                    .language_mapping
1707                    .clone()
1708                    .unwrap_or_else(|| active_context.default_language.clone());
1709            }
1710        } else {
1711            // 5)
1712            if matches!(value, JsonLdValue::String(_)) && language.is_none() {
1713                language.clone_from(&active_context.default_language);
1714            }
1715        }
1716        if reverse {
1717            errors.push(JsonLdSyntaxError::msg_and_code(
1718                "Literals are not allowed inside of reverse properties",
1719                JsonLdErrorCode::InvalidReversePropertyValue,
1720            ))
1721        }
1722        results.push(JsonLdEvent::Value {
1723            value,
1724            r#type,
1725            language,
1726        });
1727    }
1728
1729    pub fn context(&self) -> &JsonLdContext {
1730        &self
1731            .context
1732            .last()
1733            .expect("The context stack must not be empty")
1734            .0
1735    }
1736
1737    fn push_same_context(&mut self) {
1738        self.context
1739            .last_mut()
1740            .expect("The context stack must not be empty")
1741            .1 += 1;
1742    }
1743
1744    fn push_new_context(
1745        &mut self,
1746        context: Vec<JsonEvent<'static>>,
1747        errors: &mut Vec<JsonLdSyntaxError>,
1748    ) {
1749        let context = self.context_processor.process_context(
1750            self.context(),
1751            json_node_from_events(context.into_iter().map(Ok)).unwrap(),
1752            self.base_url.as_ref(),
1753            &mut Vec::new(),
1754            false,
1755            true,
1756            true,
1757            errors,
1758        );
1759        if let Some((last_context, last_count)) = self.context.pop() {
1760            if last_count > 1 {
1761                self.context.push((last_context, last_count - 1));
1762            }
1763        }
1764        self.context.push((context, 1));
1765    }
1766
1767    fn pop_context(&mut self) {
1768        let Some((last_context, mut last_count)) = self.context.pop() else {
1769            return;
1770        };
1771        last_count -= 1;
1772        if last_count > 0 || self.context.is_empty() {
1773            // We always keep a context to allow reading the root context at the end of the document
1774            self.context.push((last_context, last_count));
1775        }
1776    }
1777}
1778
1779fn to_owned_event(event: JsonEvent<'_>) -> JsonEvent<'static> {
1780    match event {
1781        JsonEvent::String(s) => JsonEvent::String(Cow::Owned(s.into())),
1782        JsonEvent::Number(n) => JsonEvent::Number(Cow::Owned(n.into())),
1783        JsonEvent::Boolean(b) => JsonEvent::Boolean(b),
1784        JsonEvent::Null => JsonEvent::Null,
1785        JsonEvent::StartArray => JsonEvent::StartArray,
1786        JsonEvent::EndArray => JsonEvent::EndArray,
1787        JsonEvent::StartObject => JsonEvent::StartObject,
1788        JsonEvent::EndObject => JsonEvent::EndObject,
1789        JsonEvent::ObjectKey(k) => JsonEvent::ObjectKey(Cow::Owned(k.into())),
1790        JsonEvent::Eof => JsonEvent::Eof,
1791    }
1792}