/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 | | } |