1+ //! CSS bundling.
2+ //!
3+ //! A [Bundler](Bundler) can be used to combine a CSS file and all of its dependencies
4+ //! into a single merged style sheet. It works together with a [SourceProvider](SourceProvider)
5+ //! (e.g. [FileProvider](FileProvider)) to read files from the file system or another source,
6+ //! and returns a [StyleSheet](super::stylesheet::StyleSheet) containing the rules from all
7+ //! of the dependencies of the entry file, recursively.
8+ //!
9+ //! Rules are bundled following `@import` order, and wrapped in the necessary `@media`, `@supports`,
10+ //! and `@layer` rules as appropriate to preserve the authored behavior.
11+ //!
12+ //! # Example
13+ //!
14+ //! ```no_run
15+ //! use std::path::Path;
16+ //! use parcel_css::{
17+ //! bundler::{Bundler, FileProvider},
18+ //! stylesheet::ParserOptions
19+ //! };
20+ //!
21+ //! let fs = FileProvider::new();
22+ //! let mut bundler = Bundler::new(&fs, None, ParserOptions::default());
23+ //! let stylesheet = bundler.bundle(Path::new("style.css")).unwrap();
24+ //! ```
25+
126use crate :: {
227 error:: ErrorLocation ,
328 rules:: {
@@ -27,6 +52,8 @@ use std::{
2752 sync:: Mutex ,
2853} ;
2954
55+ /// A Bundler combines a CSS file and all imported dependencies together into
56+ /// a single merged style sheet.
3057pub struct Bundler < ' a , ' s , P > {
3158 source_map : Option < Mutex < & ' s mut SourceMap > > ,
3259 fs : & ' a P ,
@@ -47,15 +74,23 @@ struct BundleStyleSheet<'i> {
4774 loc : Location ,
4875}
4976
77+ /// A trait to provide the contents of files to a Bundler.
78+ ///
79+ /// See [FileProvider](FileProvider) for an implementation that uses the
80+ /// file system.
5081pub trait SourceProvider : Send + Sync {
82+ /// Reads the contents of the given file path to a string.
5183 fn read < ' a > ( & ' a self , file : & Path ) -> std:: io:: Result < & ' a str > ;
5284}
5385
86+ /// Provides an implementation of [SourceProvider](SourceProvider)
87+ /// that reads files from the file system.
5488pub struct FileProvider {
5589 inputs : Mutex < Vec < * mut String > > ,
5690}
5791
5892impl FileProvider {
93+ /// Creates a new FileProvider.
5994 pub fn new ( ) -> FileProvider {
6095 FileProvider {
6196 inputs : Mutex :: new ( Vec :: new ( ) ) ,
@@ -86,12 +121,18 @@ impl Drop for FileProvider {
86121 }
87122}
88123
124+ /// An error that could occur during bundling.
89125#[ derive( Debug , Serialize ) ]
90126pub enum BundleErrorKind < ' i > {
127+ /// An I/O error occurred.
91128 IOError ( #[ serde( skip) ] std:: io:: Error ) ,
129+ /// A parser error occurred.
92130 ParserError ( ParserError < ' i > ) ,
131+ /// An unsupported `@import` condition was encountered.
93132 UnsupportedImportCondition ,
133+ /// An unsupported cascade layer combination was encountered.
94134 UnsupportedLayerCombination ,
135+ /// Unsupported media query boolean logic was encountered.
95136 UnsupportedMediaBooleanLogic ,
96137}
97138
@@ -119,12 +160,16 @@ impl<'i> std::fmt::Display for BundleErrorKind<'i> {
119160
120161impl < ' i > BundleErrorKind < ' i > {
121162 #[ deprecated( note = "use `BundleErrorKind::to_string()` or `std::fmt::Display` instead" ) ]
163+ #[ allow( missing_docs) ]
122164 pub fn reason ( & self ) -> String {
123165 self . to_string ( )
124166 }
125167}
126168
127169impl < ' a , ' s , P : SourceProvider > Bundler < ' a , ' s , P > {
170+ /// Creates a new Bundler using the given source provider.
171+ /// If a source map is given, the content of each source file included in the bundle will
172+ /// be added accordingly.
128173 pub fn new ( fs : & ' a P , source_map : Option < & ' s mut SourceMap > , options : ParserOptions ) -> Self {
129174 Bundler {
130175 source_map : source_map. map ( Mutex :: new) ,
@@ -135,6 +180,7 @@ impl<'a, 's, P: SourceProvider> Bundler<'a, 's, P> {
135180 }
136181 }
137182
183+ /// Bundles the given entry file and all dependencies into a single style sheet.
138184 pub fn bundle < ' e > ( & mut self , entry : & ' e Path ) -> Result < StyleSheet < ' a > , Error < BundleErrorKind < ' a > > > {
139185 // Phase 1: load and parse all files. This is done in parallel.
140186 self . load_file (
@@ -193,7 +239,7 @@ impl<'a, 's, P: SourceProvider> Bundler<'a, 's, P> {
193239 {
194240 return Err ( Error {
195241 kind : BundleErrorKind :: UnsupportedImportCondition ,
196- loc : Some ( ErrorLocation :: from ( rule. loc , self . find_filename ( rule. loc . source_index ) ) ) ,
242+ loc : Some ( ErrorLocation :: new ( rule. loc , self . find_filename ( rule. loc . source_index ) ) ) ,
197243 } ) ;
198244 }
199245
@@ -217,7 +263,7 @@ impl<'a, 's, P: SourceProvider> Bundler<'a, 's, P> {
217263 if layer != existing_layer || ( layer. is_none ( ) && existing_layer. is_none ( ) ) {
218264 return Err ( Error {
219265 kind : BundleErrorKind :: UnsupportedLayerCombination ,
220- loc : Some ( ErrorLocation :: from ( rule. loc , self . find_filename ( rule. loc . source_index ) ) ) ,
266+ loc : Some ( ErrorLocation :: new ( rule. loc , self . find_filename ( rule. loc . source_index ) ) ) ,
221267 } ) ;
222268 }
223269 } else {
@@ -250,7 +296,7 @@ impl<'a, 's, P: SourceProvider> Bundler<'a, 's, P> {
250296
251297 let code = self . fs . read ( file) . map_err ( |e| Error {
252298 kind : BundleErrorKind :: IOError ( e) ,
253- loc : Some ( ErrorLocation :: from ( rule. loc , self . find_filename ( rule. loc . source_index ) ) ) ,
299+ loc : Some ( ErrorLocation :: new ( rule. loc , self . find_filename ( rule. loc . source_index ) ) ) ,
254300 } ) ?;
255301
256302 let mut opts = self . options . clone ( ) ;
@@ -288,7 +334,7 @@ impl<'a, 's, P: SourceProvider> Bundler<'a, 's, P> {
288334 let mut media = rule. media . clone ( ) ;
289335 let result = media. and ( & import. media ) . map_err ( |_| Error {
290336 kind : BundleErrorKind :: UnsupportedMediaBooleanLogic ,
291- loc : Some ( ErrorLocation :: from (
337+ loc : Some ( ErrorLocation :: new (
292338 import. loc ,
293339 self . find_filename ( import. loc . source_index ) ,
294340 ) ) ,
@@ -304,7 +350,7 @@ impl<'a, 's, P: SourceProvider> Bundler<'a, 's, P> {
304350 // Cannot combine anonymous layers
305351 return Some ( Err ( Error {
306352 kind : BundleErrorKind :: UnsupportedLayerCombination ,
307- loc : Some ( ErrorLocation :: from (
353+ loc : Some ( ErrorLocation :: new (
308354 import. loc ,
309355 self . find_filename ( import. loc . source_index ) ,
310356 ) ) ,
0 commit comments