oxirs_core/jsonld/
error.rs

1pub use json_event_parser::TextPosition;
2use json_event_parser::{JsonParseError, JsonSyntaxError};
3use std::fmt::Formatter;
4use std::ops::Range;
5use std::{fmt, io};
6
7/// Error returned during JSON-LD parsing.
8#[derive(Debug, thiserror::Error)]
9pub enum JsonLdParseError {
10    /// I/O error during parsing (file not found...).
11    #[error(transparent)]
12    Io(#[from] io::Error),
13    /// An error in the file syntax.
14    #[error(transparent)]
15    Syntax(#[from] JsonLdSyntaxError),
16    /// Processing error during streaming operations
17    #[error("Processing error: {0}")]
18    ProcessingError(String),
19}
20
21impl From<JsonLdParseError> for io::Error {
22    #[inline]
23    fn from(error: JsonLdParseError) -> Self {
24        match error {
25            JsonLdParseError::Io(error) => error,
26            JsonLdParseError::Syntax(error) => error.into(),
27            JsonLdParseError::ProcessingError(msg) => io::Error::new(io::ErrorKind::Other, msg),
28        }
29    }
30}
31
32#[doc(hidden)]
33impl From<JsonParseError> for JsonLdParseError {
34    #[inline]
35    fn from(error: JsonParseError) -> Self {
36        match error {
37            JsonParseError::Io(error) => Self::Io(error),
38            JsonParseError::Syntax(error) => Self::Syntax(error.into()),
39        }
40    }
41}
42
43impl From<crate::OxirsError> for JsonLdParseError {
44    fn from(err: crate::OxirsError) -> Self {
45        JsonLdParseError::ProcessingError(err.to_string())
46    }
47}
48
49/// An error in the syntax of the parsed file.
50#[derive(Debug, thiserror::Error)]
51#[error(transparent)]
52pub struct JsonLdSyntaxError(#[from] SyntaxErrorKind);
53
54#[derive(Debug, thiserror::Error)]
55enum SyntaxErrorKind {
56    #[error(transparent)]
57    Json(#[from] JsonSyntaxError),
58    #[error("{msg}")]
59    Msg {
60        msg: String,
61        code: Option<JsonLdErrorCode>,
62    },
63}
64
65impl JsonLdSyntaxError {
66    /// The [JSON-LD error code](https://www.w3.org/TR/json-ld-api/#dom-jsonlderrorcode) related to this error.
67    pub fn code(&self) -> Option<JsonLdErrorCode> {
68        match &self.0 {
69            SyntaxErrorKind::Json(_) => None,
70            SyntaxErrorKind::Msg { code, .. } => *code,
71        }
72    }
73
74    /// The location of the error inside of the file.
75    pub fn location(&self) -> Option<Range<TextPosition>> {
76        match &self.0 {
77            SyntaxErrorKind::Json(e) => Some(e.location()),
78            SyntaxErrorKind::Msg { .. } => None,
79        }
80    }
81
82    /// Builds an error from a printable error message.
83    pub(crate) fn msg(msg: impl Into<String>) -> Self {
84        Self(SyntaxErrorKind::Msg {
85            msg: msg.into(),
86            code: None,
87        })
88    }
89
90    /// Builds an error from a printable error message and an error code.
91    pub(crate) fn msg_and_code(msg: impl Into<String>, code: JsonLdErrorCode) -> Self {
92        Self(SyntaxErrorKind::Msg {
93            msg: msg.into(),
94            code: Some(code),
95        })
96    }
97}
98
99impl From<JsonLdSyntaxError> for io::Error {
100    #[inline]
101    fn from(error: JsonLdSyntaxError) -> Self {
102        match error.0 {
103            SyntaxErrorKind::Json(error) => error.into(),
104            SyntaxErrorKind::Msg { msg, .. } => Self::new(io::ErrorKind::InvalidData, msg),
105        }
106    }
107}
108
109#[doc(hidden)]
110impl From<JsonSyntaxError> for JsonLdSyntaxError {
111    #[inline]
112    fn from(error: JsonSyntaxError) -> Self {
113        Self(SyntaxErrorKind::Json(error))
114    }
115}
116
117/// A [JSON-LD error code](https://www.w3.org/TR/json-ld-api/#dom-jsonlderrorcode)
118#[derive(Debug, Clone, Copy)]
119#[non_exhaustive]
120pub enum JsonLdErrorCode {
121    /// Two properties which expand to the same keyword have been detected.
122    /// This might occur if a keyword and an alias thereof are used at the same time.
123    CollidingKeywords,
124    /// Multiple conflicting indexes have been found for the same node.
125    ConflictingIndexes,
126    /// Maximum number of @context URLs exceeded.
127    ContextOverflow,
128    /// A cycle in IRI mappings has been detected.
129    CyclicIriMapping,
130    /// An @id entry was encountered whose value was not a string.
131    InvalidIdValue,
132    /// An invalid value for @import has been found.
133    InvalidImportValue,
134    /// An included block contains an invalid value.
135    InvalidIncludedValue,
136    /// An @index entry was encountered whose value was not a string.
137    InvalidIndexValue,
138    /// An invalid value for @nest has been found.
139    InvalidNestValue,
140    /// An invalid value for @prefix has been found.
141    InvalidPrefixValue,
142    /// An invalid value for @propagate has been found.
143    InvalidPropagateValue,
144    /// An invalid value for @protected has been found.
145    InvalidProtectedValue,
146    /// An invalid value for an @reverse entry has been detected, i.e., the value was not a map.
147    InvalidReverseValue,
148    /// The @version entry was used in a context with an out of range value.
149    InvalidVersionValue,
150    /// The value of @direction is not "ltr", "rtl", or null and thus invalid.
151    InvalidBaseDirection,
152    /// An invalid base IRI has been detected, i.e., it is neither an IRI nor null.
153    InvalidBaseIri,
154    /// An @container entry was encountered whose value was not one of the following strings:
155    /// @list, @set, @language, @index, @id, @graph, or @type.
156    InvalidContainerMapping,
157    /// An entry in a context is invalid due to processing mode incompatibility.
158    InvalidContextEntry,
159    /// An attempt was made to nullify a context containing protected term definitions.
160    InvalidContextNullification,
161    /// The value of the default language is not a string or null and thus invalid.
162    InvalidDefaultLanguage,
163    /// A local context contains a term that has an invalid or missing IRI mapping.
164    InvalidIriMapping,
165    /// An invalid JSON literal was detected.
166    InvalidJsonLiteral,
167    /// An invalid keyword alias definition has been encountered.
168    InvalidKeywordAlias,
169    /// An invalid value in a language map has been detected.
170    /// It MUST be a string or an array of strings.
171    InvalidLanguageMapValue,
172    /// An @language entry in a term definition was encountered
173    /// whose value was neither a string nor null and thus invalid.
174    InvalidLanguageMapping,
175    /// A language-tagged string with an invalid language value was detected.
176    InvalidLanguageTaggedString,
177    /// A number, true, or false with an associated language tag was detected.
178    InvalidLanguageTaggedValue,
179    /// An invalid local context was detected.
180    InvalidLocalContext,
181    /// No valid context document has been found for a referenced remote context.
182    InvalidRemoteContext,
183    /// An invalid reverse property definition has been detected.
184    InvalidReverseProperty,
185    /// An invalid reverse property map has been detected.
186    /// No keywords apart from @context are allowed in reverse property maps.
187    InvalidReversePropertyMap,
188    /// An invalid value for a reverse property has been detected.
189    /// The value of an inverse property must be a node object.
190    InvalidReversePropertyValue,
191    /// The local context defined within a term definition is invalid.
192    InvalidScopedContext,
193    /// A set object or list object with disallowed entries has been detected.
194    InvalidSetOrListObject,
195    /// The key ordering is not compatible with the streaming profile.
196    InvalidStreamingKeyOrder,
197    /// An invalid term definition has been detected.
198    InvalidTermDefinition,
199    /// An @type entry in a term definition was encountered whose value could not be expanded to an IRI.
200    InvalidTypeMapping,
201    /// An invalid value for an @type entry has been detected,
202    /// i.e., the value was neither a string nor an array of strings.
203    InvalidTypeValue,
204    /// A typed value with an invalid type was detected.
205    InvalidTypedValue,
206    /// A value object with disallowed entries has been detected.
207    InvalidValueObject,
208    /// An invalid value for the @value entry of a value object has been detected,
209    /// i.e., it is neither a scalar nor null.
210    InvalidValueObjectValue,
211    /// An invalid vocabulary mapping has been detected, i.e., it is neither an IRI nor null.
212    InvalidVocabMapping,
213    /// When compacting an IRI would result in an IRI which could be confused with a compact IRI
214    /// (because its IRI scheme matches a term definition and it has no IRI authority).
215    IriConfusedWithPrefix,
216    /// A keyword redefinition has been detected.
217    KeywordRedefinition,
218    /// The document could not be loaded or parsed as JSON.
219    LoadingDocumentFailed,
220    /// There was a problem encountered loading a remote context.
221    LoadingRemoteContextFailed,
222    /// An attempt was made to change the processing mode which is incompatible with the previous specified version.
223    ProcessingModeConflict,
224    /// An attempt was made to redefine a protected term.
225    ProtectedTermRedefinition,
226}
227
228impl fmt::Display for JsonLdErrorCode {
229    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
230        f.write_str(match self {
231            Self::CollidingKeywords => "colliding keywords",
232            Self::ConflictingIndexes => "conflicting indexes",
233            Self::ContextOverflow => "context overflow",
234            Self::CyclicIriMapping => "cyclic IRI mapping",
235            Self::InvalidIdValue => "invalid @id value",
236            Self::InvalidImportValue => "invalid @import value",
237            Self::InvalidIncludedValue => "invalid @included value",
238            Self::InvalidIndexValue => "invalid @index value",
239            Self::InvalidNestValue => "invalid @nest value",
240            Self::InvalidPrefixValue => "invalid @prefix value",
241            Self::InvalidPropagateValue => "invalid @propagate value",
242            Self::InvalidProtectedValue => "invalid @protected value",
243            Self::InvalidReverseValue => "invalid @reverse value",
244            Self::InvalidVersionValue => "invalid @version value",
245            Self::InvalidBaseDirection => "invalid base direction",
246            Self::InvalidBaseIri => "invalid base IRI",
247            Self::InvalidContainerMapping => "invalid container mapping",
248            Self::InvalidContextEntry => "invalid context entry",
249            Self::InvalidContextNullification => "invalid context nullification",
250            Self::InvalidDefaultLanguage => "invalid default language",
251            Self::InvalidIriMapping => "invalid IRI mapping",
252            Self::InvalidJsonLiteral => "invalid JSON literal",
253            Self::InvalidKeywordAlias => "invalid keyword alias",
254            Self::InvalidLanguageMapValue => "invalid language map value",
255            Self::InvalidLanguageMapping => "invalid language mapping",
256            Self::InvalidLanguageTaggedString => "invalid language-tagged string",
257            Self::InvalidLanguageTaggedValue => "invalid language-tagged value",
258            Self::InvalidLocalContext => "invalid local context",
259            Self::InvalidRemoteContext => "invalid remote context",
260            Self::InvalidReverseProperty => "invalid reverse property",
261            Self::InvalidReversePropertyMap => "invalid reverse property map",
262            Self::InvalidReversePropertyValue => "invalid reverse property value",
263            Self::InvalidScopedContext => "invalid scoped context",
264            Self::InvalidSetOrListObject => "invalid set or list object",
265            Self::InvalidStreamingKeyOrder => "invalid streaming key order",
266            Self::InvalidTermDefinition => "invalid term definition",
267            Self::InvalidTypeMapping => "invalid type mapping",
268            Self::InvalidTypeValue => "invalid type value",
269            Self::InvalidTypedValue => "invalid typed value",
270            Self::InvalidValueObject => "invalid value object",
271            Self::InvalidValueObjectValue => "invalid value object value",
272            Self::InvalidVocabMapping => "invalid vocab mapping",
273            Self::IriConfusedWithPrefix => "IRI confused with prefix",
274            Self::KeywordRedefinition => "keyword redefinition",
275            Self::LoadingDocumentFailed => "loading document failed",
276            Self::LoadingRemoteContextFailed => "loading remote context failed",
277            Self::ProcessingModeConflict => "processing mode conflict",
278            Self::ProtectedTermRedefinition => "protected term redefinition",
279        })
280    }
281}