Coverage Report

Created: 2026-10-28 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/lightningcss-1.0.0-alpha.72/src/dependencies.rs
Line
Count
Source
1
//! Dependency analysis.
2
//!
3
//! Dependencies in CSS can be analyzed using the `analyze_dependencies` option
4
//! when printing a style sheet. These include other style sheets referenved via
5
//! the `@import` rule, as well as `url()` references. See [PrinterOptions](PrinterOptions).
6
//!
7
//! When dependency analysis is enabled, `@import` rules are removed, and `url()`
8
//! dependencies are replaced with hashed placeholders that can be substituted with
9
//! the final urls later (e.g. after bundling and content hashing).
10
11
use crate::css_modules::hash;
12
use crate::printer::PrinterOptions;
13
use crate::rules::import::ImportRule;
14
use crate::traits::ToCss;
15
use crate::values::url::Url;
16
#[cfg(feature = "visitor")]
17
use crate::visitor::Visit;
18
use cssparser::SourceLocation;
19
#[cfg(any(feature = "serde", feature = "nodejs"))]
20
use serde::Serialize;
21
22
/// Options for `analyze_dependencies` in `PrinterOptions`.
23
#[derive(Default)]
24
pub struct DependencyOptions {
25
  /// Whether to remove `@import` rules.
26
  pub remove_imports: bool,
27
}
28
29
/// A dependency.
30
#[derive(Debug)]
31
#[cfg_attr(any(feature = "serde", feature = "nodejs"), derive(Serialize))]
32
#[cfg_attr(
33
  any(feature = "serde", feature = "nodejs"),
34
  serde(tag = "type", rename_all = "lowercase")
35
)]
36
pub enum Dependency {
37
  /// An `@import` dependency.
38
  Import(ImportDependency),
39
  /// A `url()` dependency.
40
  Url(UrlDependency),
41
}
42
43
/// An `@import` dependency.
44
#[derive(Debug)]
45
#[cfg_attr(any(feature = "serde", feature = "nodejs"), derive(Serialize))]
46
pub struct ImportDependency {
47
  /// The url to import.
48
  pub url: String,
49
  /// The placeholder that the URL was replaced with.
50
  pub placeholder: String,
51
  /// An optional `supports()` condition.
52
  pub supports: Option<String>,
53
  /// A media query.
54
  pub media: Option<String>,
55
  /// The location of the dependency in the source file.
56
  pub loc: SourceRange,
57
}
58
59
impl ImportDependency {
60
  /// Creates a new dependency from an `@import` rule.
61
0
  pub fn new(rule: &ImportRule, filename: &str) -> ImportDependency {
62
0
    let supports = if let Some(supports) = &rule.supports {
63
0
      let s = supports.to_css_string(PrinterOptions::default()).unwrap();
64
0
      Some(s)
65
    } else {
66
0
      None
67
    };
68
69
0
    let media = if !rule.media.media_queries.is_empty() {
70
0
      let s = rule.media.to_css_string(PrinterOptions::default()).unwrap();
71
0
      Some(s)
72
    } else {
73
0
      None
74
    };
75
76
0
    let placeholder = hash(&format!("{}_{}", filename, rule.url), false);
77
78
0
    ImportDependency {
79
0
      url: rule.url.as_ref().to_owned(),
80
0
      placeholder,
81
0
      supports,
82
0
      media,
83
0
      loc: SourceRange::new(
84
0
        filename,
85
0
        Location {
86
0
          line: rule.loc.line + 1,
87
0
          column: rule.loc.column,
88
0
        },
89
0
        8,
90
0
        rule.url.len() + 2,
91
0
      ), // TODO: what about @import url(...)?
92
0
    }
93
0
  }
94
}
95
96
/// A `url()` dependency.
97
#[derive(Debug)]
98
#[cfg_attr(any(feature = "serde", feature = "nodejs"), derive(Serialize))]
99
pub struct UrlDependency {
100
  /// The url of the dependency.
101
  pub url: String,
102
  /// The placeholder that the URL was replaced with.
103
  pub placeholder: String,
104
  /// The location of the dependency in the source file.
105
  pub loc: SourceRange,
106
}
107
108
impl UrlDependency {
109
  /// Creates a new url dependency.
110
0
  pub fn new(url: &Url, filename: &str) -> UrlDependency {
111
0
    let placeholder = hash(&format!("{}_{}", filename, url.url), false);
112
0
    UrlDependency {
113
0
      url: url.url.to_string(),
114
0
      placeholder,
115
0
      loc: SourceRange::new(filename, url.loc, 4, url.url.len()),
116
0
    }
117
0
  }
118
}
119
120
/// Represents the range of source code where a dependency was found.
121
#[derive(Debug)]
122
#[cfg_attr(any(feature = "serde", feature = "nodejs"), derive(Serialize))]
123
#[cfg_attr(any(feature = "serde", feature = "nodejs"), serde(rename_all = "camelCase"))]
124
pub struct SourceRange {
125
  /// The filename in which the dependency was found.
126
  pub file_path: String,
127
  /// The starting line and column position of the dependency.
128
  pub start: Location,
129
  /// The ending line and column position of the dependency.
130
  pub end: Location,
131
}
132
133
/// A line and column position within a source file.
134
#[derive(Debug, Clone, Copy, PartialEq)]
135
0
#[cfg_attr(feature = "visitor", derive(Visit))]
Unexecuted instantiation: <lightningcss::dependencies::Location as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::ValueCollector>>::visit_children
Unexecuted instantiation: <lightningcss::dependencies::Location as lightningcss::visitor::Visit<lightningcss::parser::DefaultAtRule, fallow_extract::css_metrics::FirstRgbColorCollector>>::visit_children
Unexecuted instantiation: <lightningcss::dependencies::Location as lightningcss::visitor::Visit<_, _>>::visit_children
136
#[cfg_attr(any(feature = "serde", feature = "nodejs"), derive(serde::Serialize))]
137
#[cfg_attr(any(feature = "serde"), derive(serde::Deserialize))]
138
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
139
#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
140
pub struct Location {
141
  /// The line number, starting from 1.
142
  pub line: u32,
143
  /// The column number, starting from 1.
144
  pub column: u32,
145
}
146
147
impl From<SourceLocation> for Location {
148
19.7k
  fn from(loc: SourceLocation) -> Location {
149
19.7k
    Location {
150
19.7k
      line: loc.line + 1,
151
19.7k
      column: loc.column,
152
19.7k
    }
153
19.7k
  }
154
}
155
156
impl SourceRange {
157
0
  fn new(filename: &str, loc: Location, offset: u32, len: usize) -> SourceRange {
158
0
    SourceRange {
159
0
      file_path: filename.into(),
160
0
      start: Location {
161
0
        line: loc.line,
162
0
        column: loc.column + offset,
163
0
      },
164
0
      end: Location {
165
0
        line: loc.line,
166
0
        column: loc.column + offset + (len as u32) - 1,
167
0
      },
168
0
    }
169
0
  }
170
}