1use std::{
2 borrow::Cow,
3 fmt::{Display, Formatter, Write},
4};
5
6use anyhow::Result;
7use serde::{Deserialize, Serialize};
8use turbo_tasks::{NonLocalValue, trace::TraceRawVcs};
9
10use crate::{rope::Rope, source_context::get_source_context};
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, TraceRawVcs, NonLocalValue)]
13pub struct UnparseableJson {
14 pub message: Cow<'static, str>,
15 pub path: Option<String>,
16 pub start_location: Option<(u32, u32)>,
19 pub end_location: Option<(u32, u32)>,
22}
23
24fn byte_to_location(pos: usize, text: &str) -> (u32, u32) {
26 let text = &text[..pos];
27 let mut lines = text.lines().rev();
28 let last = lines.next().unwrap_or("");
29 let column = last.len();
30 let line = lines.count();
31 (line as u32, column as u32)
32}
33
34impl UnparseableJson {
35 pub fn from_jsonc_error(e: jsonc_parser::errors::ParseError, text: &str) -> Self {
36 Self {
37 message: e.message.clone().into(),
38 path: None,
39 start_location: Some(byte_to_location(e.range.start, text)),
40 end_location: Some(byte_to_location(e.range.end, text)),
41 }
42 }
43
44 pub fn from_serde_path_to_error(e: serde_path_to_error::Error<serde_json::Error>) -> Self {
45 let inner = e.inner();
46 Self {
47 message: inner.to_string().into(),
48 path: Some(e.path().to_string()),
49 start_location: Some((
50 inner.line().saturating_sub(1) as u32,
51 inner.column().saturating_sub(1) as u32,
52 )),
53 end_location: None,
54 }
55 }
56
57 pub fn write_with_content(&self, writer: &mut impl Write, text: &str) -> std::fmt::Result {
58 writeln!(writer, "{}", self.message)?;
59 if let Some(path) = &self.path {
60 writeln!(writer, " at {path}")?;
61 }
62 match (self.start_location, self.end_location) {
63 (Some((line, column)), Some((end_line, end_column))) => {
64 write!(
65 writer,
66 "{}",
67 get_source_context(text.lines(), line, column, end_line, end_column,)
68 )?;
69 }
70 (Some((line, column)), None) | (None, Some((line, column))) => {
71 write!(
72 writer,
73 "{}",
74 get_source_context(text.lines(), line, column, line, column)
75 )?;
76 }
77 (None, None) => {
78 write!(writer, "{}", get_source_context(text.lines(), 0, 0, 0, 0))?;
79 }
80 }
81 Ok(())
82 }
83
84 pub fn to_string_with_content(&self, text: &str) -> String {
85 let mut result = String::new();
86 self.write_with_content(&mut result, text).unwrap();
87 result
88 }
89}
90
91impl Display for UnparseableJson {
92 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
93 write!(f, "{}", self.message)?;
94 if let Some(path) = &self.path {
95 write!(f, " at {path}")?;
96 }
97 Ok(())
98 }
99}
100
101pub fn parse_json_with_source_context<'de, T: Deserialize<'de>>(text: &'de str) -> Result<T> {
102 let de = &mut serde_json::Deserializer::from_str(text);
103 match serde_path_to_error::deserialize(de) {
104 Ok(data) => Ok(data),
105 Err(e) => Err(anyhow::Error::msg(
106 UnparseableJson::from_serde_path_to_error(e).to_string_with_content(text),
107 )),
108 }
109}
110
111pub fn parse_json_rope_with_source_context<'de, T: Deserialize<'de>>(rope: &'de Rope) -> Result<T> {
112 let de = &mut serde_json::Deserializer::from_reader(rope.read());
113 match serde_path_to_error::deserialize(de) {
114 Ok(data) => Ok(data),
115 Err(e) => {
116 let cow = rope.to_str()?;
117 Err(anyhow::Error::msg(
118 UnparseableJson::from_serde_path_to_error(e).to_string_with_content(&cow),
119 ))
120 }
121 }
122}