Skip to content

Commit bc5378a

Browse files
committed
Remaining docs
1 parent 4d5d427 commit bc5378a

File tree

12 files changed

+299
-41
lines changed

12 files changed

+299
-41
lines changed

src/bundler.rs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,28 @@
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+
126
use 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.
3057
pub 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.
5081
pub 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.
5488
pub struct FileProvider {
5589
inputs: Mutex<Vec<*mut String>>,
5690
}
5791

5892
impl 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)]
90126
pub 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

120161
impl<'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

127169
impl<'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
)),

src/css_modules.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
//! CSS module exports.
2+
//!
3+
//! [CSS modules](https://github.com/css-modules/css-modules) are a way of locally scoping names in a
4+
//! CSS file. This includes class names, ids, keyframe animation names, and any other places where the
5+
//! [CustomIdent](super::values::ident::CustomIdent) type is used.
6+
//!
7+
//! CSS modules can be enabled using the `css_modules` option when parsing a style sheet. When the
8+
//! style sheet is printed, hashes will be added to any declared names, and references to those names
9+
//! will be updated accordingly. A map of the original names to compiled (hashed) names will be returned.
10+
111
use crate::error::PrinterErrorKind;
212
use crate::properties::css_modules::{Composes, ComposesFrom};
313
use crate::selector::Selectors;
@@ -9,22 +19,44 @@ use std::collections::hash_map::DefaultHasher;
919
use std::collections::HashMap;
1020
use std::hash::{Hash, Hasher};
1121

22+
/// A referenced name within a CSS module, e.g. via the `composes` property.
23+
///
24+
/// See [CssModuleExport](CssModuleExport).
1225
#[derive(PartialEq, Debug, Clone, Serialize)]
1326
#[serde(tag = "type", rename_all = "lowercase")]
1427
pub enum CssModuleReference {
15-
Local { name: String },
16-
Global { name: String },
17-
Dependency { name: String, specifier: String },
28+
/// A local reference.
29+
Local {
30+
/// The local (compiled) name for the reference.
31+
name: String,
32+
},
33+
/// A global reference.
34+
Global {
35+
/// The referenced global name.
36+
name: String,
37+
},
38+
/// A reference to an export in a different file.
39+
Dependency {
40+
/// The name to reference within the dependency.
41+
name: String,
42+
/// The dependency specifier for the referenced file.
43+
specifier: String,
44+
},
1845
}
1946

47+
/// An exported value from a CSS module.
2048
#[derive(PartialEq, Debug, Clone, Serialize)]
2149
#[serde(rename_all = "camelCase")]
2250
pub struct CssModuleExport {
51+
/// The local (compiled) name for this export.
2352
pub name: String,
53+
/// Other names that are composed by this export.
2454
pub composes: Vec<CssModuleReference>,
55+
/// Whether the export is referenced in this file.
2556
pub is_referenced: bool,
2657
}
2758

59+
/// A map of exported names to values.
2860
pub type CssModuleExports = HashMap<String, CssModuleExport>;
2961

3062
lazy_static! {

src/declaration.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! CSS declarations.
2+
13
use crate::context::PropertyHandlerContext;
24
use crate::error::{ParserError, PrinterError};
35
use crate::parser::ParserOptions;
@@ -29,13 +31,21 @@ use crate::targets::Browsers;
2931
use crate::traits::{PropertyHandler, ToCss};
3032
use cssparser::*;
3133

34+
/// A CSS declaration block.
35+
///
36+
/// Properties are separated into a list of `!important` declararations,
37+
/// and a list of normal declarations. This reduces memory usage compared
38+
/// with storing a boolean along with each property.
3239
#[derive(Debug, PartialEq, Clone)]
3340
pub struct DeclarationBlock<'i> {
41+
/// A list of `!important` declarations in the block.
3442
pub important_declarations: Vec<Property<'i>>,
43+
/// A list of normal declarations in the block.
3544
pub declarations: Vec<Property<'i>>,
3645
}
3746

3847
impl<'i> DeclarationBlock<'i> {
48+
/// Parses a declaration block from CSS syntax.
3949
pub fn parse<'t>(
4050
input: &mut Parser<'i, 't>,
4151
options: &ParserOptions,
@@ -126,6 +136,7 @@ impl<'i> DeclarationBlock<'i> {
126136
self.declarations = std::mem::take(&mut handler.decls);
127137
}
128138

139+
/// Returns whether the declaration block is empty.
129140
pub fn is_empty(&self) -> bool {
130141
return self.declarations.is_empty() && self.important_declarations.is_empty();
131142
}

src/dependencies.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
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+
111
use crate::css_modules::hash;
212
use crate::printer::PrinterOptions;
313
use crate::rules::import::ImportRule;
@@ -6,22 +16,31 @@ use crate::values::url::Url;
616
use cssparser::SourceLocation;
717
use serde::Serialize;
818

19+
/// A dependency.
920
#[derive(Serialize)]
1021
#[serde(tag = "type", rename_all = "lowercase")]
1122
pub enum Dependency {
23+
/// An `@import` dependency.
1224
Import(ImportDependency),
25+
/// A `url()` dependency.
1326
Url(UrlDependency),
1427
}
1528

29+
/// An `@import` dependency.
1630
#[derive(Serialize)]
1731
pub struct ImportDependency {
32+
/// The url to import.
1833
pub url: String,
34+
/// An optional `supports()` condition.
1935
pub supports: Option<String>,
36+
/// A media query.
2037
pub media: Option<String>,
38+
/// The location of the dependency in the source file.
2139
pub loc: SourceRange,
2240
}
2341

2442
impl ImportDependency {
43+
/// Creates a new dependency from an `@import` rule.
2544
pub fn new(rule: &ImportRule, filename: &str) -> ImportDependency {
2645
let supports = if let Some(supports) = &rule.supports {
2746
let s = supports.to_css_string(PrinterOptions::default()).unwrap();
@@ -54,14 +73,19 @@ impl ImportDependency {
5473
}
5574
}
5675

76+
/// A `url()` dependency.
5777
#[derive(Serialize)]
5878
pub struct UrlDependency {
79+
/// The url of the dependency.
5980
pub url: String,
81+
/// The placeholder that the URL was replaced with.
6082
pub placeholder: String,
83+
/// The location of the dependency in the source file.
6184
pub loc: SourceRange,
6285
}
6386

6487
impl UrlDependency {
88+
/// Creates a new url dependency.
6589
pub fn new(url: &Url, filename: &str) -> UrlDependency {
6690
let placeholder = hash(&format!("{}_{}", filename, url.url));
6791
UrlDependency {
@@ -72,17 +96,24 @@ impl UrlDependency {
7296
}
7397
}
7498

99+
/// Represents the range of source code where a dependency was found.
75100
#[derive(Serialize)]
76101
#[serde(rename_all = "camelCase")]
77102
pub struct SourceRange {
103+
/// The filename in which the dependency was found.
78104
pub file_path: String,
105+
/// The starting line and column position of the dependency.
79106
pub start: Location,
107+
/// THe ending line and column position of the dependency.
80108
pub end: Location,
81109
}
82110

111+
/// A line and column position within a source file.
83112
#[derive(Serialize)]
84113
pub struct Location {
114+
/// The line number, starting from 0.
85115
pub line: u32,
116+
/// The column number, starting from 1.
86117
pub column: u32,
87118
}
88119

0 commit comments

Comments
 (0)