rspack_location/
lib.rs

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/// Represents a position in the source file, including the line number and column number.
15#[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/// Represents the real location of a dependency in a source file, including both start and optional end positions.
32/// These positions are described in terms of lines and columns in the source code.
33#[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/// Represents a synthetic dependency location, such as a generated dependency.
91#[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}