1use crate::dom::DomError;
2use crate::util::mapper::{Mapper, Range};
3use serde::{Deserialize, Serialize};
4use thiserror::Error;
5
6#[derive(Debug, Clone, Error)]
7pub enum Error {
8 #[error("invalid syntax")]
9 InvalidSyntax { errors: Vec<crate::parser::Error> },
10 #[error("invalid dom")]
11 InvalidDom { errors: Vec<DomError> },
12}
13
14const ERROR_SOURCE: &str = "jsona";
15
16impl Error {
17 pub fn to_error_objects(&self, mapper: &Mapper) -> Vec<ErrorObject> {
18 match self {
19 Error::InvalidSyntax { errors } => errors
20 .iter()
21 .map(|err| {
22 let message = err.to_string();
23 let range = mapper.range(err.range);
24 ErrorObject::new(ERROR_SOURCE, "InvalidSyntax", message, range)
25 })
26 .collect(),
27 Error::InvalidDom { errors } => errors
28 .iter()
29 .flat_map(|err| {
30 let message = err.to_string();
31 match err {
32 DomError::ConflictingKeys { key, other_key } => {
33 let key_range = key.mapper_range(mapper);
34 let other_key_range = other_key.mapper_range(mapper);
35 vec![
36 ErrorObject::new(
37 ERROR_SOURCE,
38 "ConflictingKeys",
39 message.clone(),
40 key_range,
41 ),
42 ErrorObject::new(
43 ERROR_SOURCE,
44 "ConflictingKeys",
45 message,
46 other_key_range,
47 ),
48 ]
49 }
50 DomError::InvalidNode { syntax } => {
51 let range = mapper.range(syntax.text_range());
52 vec![ErrorObject::new(
53 ERROR_SOURCE,
54 "InvalidNode",
55 message,
56 range,
57 )]
58 }
59 DomError::InvalidNumber { syntax } => {
60 let range = mapper.range(syntax.text_range());
61 vec![ErrorObject::new(
62 ERROR_SOURCE,
63 "InvalidNumber",
64 message,
65 range,
66 )]
67 }
68 DomError::InvalidString { syntax } => {
69 let range = mapper.range(syntax.text_range());
70 vec![ErrorObject::new(
71 ERROR_SOURCE,
72 "InvalidString",
73 message,
74 range,
75 )]
76 }
77 }
78 })
79 .collect(),
80 }
81 }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
85pub struct ErrorObject {
86 pub source: String,
87 pub kind: String,
88 pub message: String,
89 pub range: Option<Range>,
90}
91
92impl ErrorObject {
93 pub fn new(source: &str, kind: &str, message: String, range: Option<Range>) -> Self {
94 Self {
95 source: source.to_string(),
96 kind: kind.into(),
97 message,
98 range,
99 }
100 }
101}