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