1use std::fmt::{self, Debug};
2
3pub use itoa::Buffer;
4use rspack_cacheable::cacheable;
5use swc_core::common::{SourceMap, Span};
6
7#[macro_export]
8macro_rules! itoa {
9 ($i:expr) => {{
10 itoa::Buffer::new().format($i)
11 }};
12}
13
14#[cacheable]
16#[derive(Debug, Clone, Copy)]
17pub struct SourcePosition {
18 pub line: usize,
19 pub column: usize,
20}
21
22impl From<(u32, u32)> for SourcePosition {
23 fn from(range: (u32, u32)) -> Self {
24 Self {
25 line: range.0 as usize,
26 column: range.1 as usize,
27 }
28 }
29}
30
31#[cacheable]
34#[derive(Debug, Clone)]
35pub struct RealDependencyLocation {
36 pub start: SourcePosition,
37 pub end: Option<SourcePosition>,
38}
39
40impl RealDependencyLocation {
41 pub fn new(start: SourcePosition, end: Option<SourcePosition>) -> Self {
42 Self { start, end }
43 }
44
45 pub fn from_span(span: &Span, source_map: &SourceMap) -> Self {
46 let start_char_pos = source_map.lookup_char_pos(span.lo);
47 let end_char_pos = source_map.lookup_char_pos(span.hi);
48 RealDependencyLocation::new(
49 SourcePosition {
50 line: start_char_pos.line,
51 column: start_char_pos.col_display,
52 },
53 Some(SourcePosition {
54 line: end_char_pos.line,
55 column: end_char_pos.col_display,
56 }),
57 )
58 }
59}
60
61impl fmt::Display for RealDependencyLocation {
62 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63 if let Some(end) = self.end {
64 if self.start.line == end.line && self.start.column == end.column {
65 write!(f, "{}:{}", itoa!(self.start.line), itoa!(self.start.column))
66 } else if self.start.line == end.line {
67 write!(
68 f,
69 "{}:{}-{}",
70 itoa!(self.start.line),
71 itoa!(self.start.column),
72 itoa!(end.column)
73 )
74 } else {
75 write!(
76 f,
77 "{}:{}-{}:{}",
78 itoa!(self.start.line),
79 itoa!(self.start.column),
80 itoa!(end.line),
81 itoa!(end.column)
82 )
83 }
84 } else {
85 write!(f, "{}:{}", itoa!(self.start.line), itoa!(self.start.column))
86 }
87 }
88}
89
90#[cacheable]
92#[derive(Debug, Clone)]
93pub struct SyntheticDependencyLocation {
94 pub name: String,
95}
96
97impl SyntheticDependencyLocation {
98 pub fn new(name: &str) -> Self {
99 SyntheticDependencyLocation {
100 name: name.to_string(),
101 }
102 }
103}
104
105impl fmt::Display for SyntheticDependencyLocation {
106 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107 write!(f, "{}", self.name)
108 }
109}
110
111#[cacheable]
112#[derive(Debug, Clone)]
113pub enum DependencyLocation {
114 Real(RealDependencyLocation),
115 Synthetic(SyntheticDependencyLocation),
116}
117
118impl DependencyLocation {
119 pub fn from_span(span: &Span, source_map: &SourceMap) -> Self {
120 DependencyLocation::Real(RealDependencyLocation::from_span(span, source_map))
121 }
122}
123
124impl fmt::Display for DependencyLocation {
125 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
126 let loc = match self {
127 DependencyLocation::Real(real) => real.to_string(),
128 DependencyLocation::Synthetic(synthetic) => synthetic.to_string(),
129 };
130 write!(f, "{loc}")
131 }
132}