turbopack_node/source_map/
trace.rs1use std::{borrow::Cow, fmt::Display};
2
3use bincode::{
4 Decode, Encode,
5 de::Decoder,
6 enc::Encoder,
7 error::{DecodeError, EncodeError},
8 impl_borrow_decode,
9};
10use serde::{Deserialize, Serialize};
11use turbopack_core::source_map::{SourceMap, Token};
12use turbopack_ecmascript::magic_identifier::unmangle_identifiers;
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
18pub struct StackFrame<'a> {
19 pub file: Cow<'a, str>,
20 #[serde(rename = "lineNumber")]
21 pub line: Option<u32>,
22 pub column: Option<u32>,
23 #[serde(rename = "methodName")]
24 pub name: Option<Cow<'a, str>>,
25}
26
27impl<'a> StackFrame<'a> {
28 pub fn unmangle_identifiers<T: Display>(&self, magic: impl Fn(String) -> T) -> StackFrame<'_> {
29 StackFrame {
30 file: Cow::Borrowed(self.file.as_ref()),
31 line: self.line,
32 column: self.column,
33 name: self
34 .name
35 .as_ref()
36 .map(|n| unmangle_identifiers(n.as_ref(), magic)),
37 }
38 }
39
40 pub fn with_path<'b>(&'a self, path: &'b str) -> StackFrame<'b>
41 where
42 'a: 'b,
43 {
44 StackFrame {
45 file: Cow::Borrowed(path),
46 line: self.line,
47 column: self.column,
48 name: self.name.as_ref().map(|n| Cow::Borrowed(n.as_ref())),
49 }
50 }
51
52 pub fn with_name<'b>(&'a self, name: Option<&'b str>) -> StackFrame<'b>
53 where
54 'a: 'b,
55 {
56 StackFrame {
57 file: Cow::Borrowed(self.file.as_ref()),
58 line: self.line,
59 column: self.column,
60 name: name.map(Cow::Borrowed),
61 }
62 }
63
64 pub fn get_pos(&self) -> Option<(u32, u32)> {
65 self.line.zip(self.column)
66 }
67}
68
69impl Display for StackFrame<'_> {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 match self.get_pos() {
72 Some((l, c)) => match &self.name.as_deref() {
73 None | Some("<unknown>") | Some("(anonymous)") => {
74 write!(f, "{}:{}:{}", self.file, l, c)
75 }
76 Some(n) => write!(f, "{} ({}:{}:{})", n, self.file, l, c),
77 },
78 None => write!(f, "{}", self.file),
79 }
80 }
81}
82
83impl Encode for StackFrame<'_> {
84 fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
85 self.file.encode(encoder)?;
86 self.line.encode(encoder)?;
87 self.column.encode(encoder)?;
88 self.name.encode(encoder)?;
89 Ok(())
90 }
91}
92
93impl<Context> Decode<Context> for StackFrame<'_> {
95 fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
96 Ok(Self {
97 file: Decode::decode(decoder)?,
98 line: Decode::decode(decoder)?,
99 column: Decode::decode(decoder)?,
100 name: Decode::decode(decoder)?,
101 })
102 }
103}
104
105impl_borrow_decode!(StackFrame<'_>);
106
107#[derive(Debug)]
109pub enum TraceResult {
110 NotFound,
111 Found(StackFrame<'static>),
112}
113
114pub fn trace_source_map(
125 map: &SourceMap,
126 line: u32,
127 column: u32,
128 name: Option<&str>,
129) -> TraceResult {
130 let token = map.lookup_token(line.saturating_sub(1), column.saturating_sub(1));
131 match token {
132 Token::Original(t) => TraceResult::Found(StackFrame {
133 file: Cow::Owned(t.original_file.into_owned()),
134 line: Some(t.original_line.saturating_add(1)),
135 column: Some(t.original_column.saturating_add(1)),
136 name: t
137 .name
138 .clone()
139 .map(|v| v.into_owned())
140 .or_else(|| name.map(ToString::to_string))
141 .map(Cow::Owned),
142 }),
143 _ => TraceResult::NotFound,
144 }
145}