sabry/sabry_intrnl/src/config/mod.rs

246 lines
7.2 KiB
Rust

pub mod manifest;
use manifest::{ManifestError, ValuableManifest};
use serde::Deserialize;
/// Sabry configuration, as it is from package.metadata.sabry
#[derive(Default, Deserialize, Clone)]
pub struct SabryConfig {
#[serde(default = "SabryCssConfig::default")]
pub css: SabryCssConfig,
#[serde(default = "SabrySassConfig::default")]
pub sass: SabrySassConfig,
#[serde(default = "SabryHashConfig::default")]
pub hash: SabryHashConfig,
#[serde(default = "SabryGrassConfig::default")]
pub grass: SabryGrassConfig,
#[serde(default = "SabryLightCssConfig::default")]
pub lightningcss: SabryLightCssConfig,
}
impl SabryConfig {
/// Require sabry configuration for the current project from every place in the code
pub fn require() -> Result<Self, ManifestError> {
let manifest = manifest::read_manifest()?;
Ok(Self::from(&manifest))
}
}
impl From<&ValuableManifest> for SabryConfig {
fn from(value: &ValuableManifest) -> Self {
value
.package
.as_ref()
.and_then(|p| p.metadata.as_ref())
.and_then(|m| m.sabry.as_ref())
.map_or(Self::default(), |sbr| sbr.clone())
}
}
/// Sabry `css` configuration table
#[derive(Deserialize, Clone)]
pub struct SabryCssConfig {
pub bundle: Option<String>,
pub scopes: Option<String>,
pub prelude: Option<Vec<String>>,
#[serde(default = "SabryCssConfig::default_minify")]
pub minify: bool,
}
impl SabryCssConfig {
fn default_minify() -> bool {
true
}
}
impl Default for SabryCssConfig {
fn default() -> Self {
Self {
bundle: None,
scopes: None,
prelude: None,
minify: Self::default_minify(),
}
}
}
/// Sabry `sass` configuration table
///
/// (SASS/SCSS related config)
#[derive(Deserialize, Clone)]
pub struct SabrySassConfig {
#[serde(default = "SabrySassConfig::default_scanroot")]
pub scanroot: String,
pub modules: Option<Vec<String>>,
pub prelude: Option<Vec<String>>,
#[serde(default = "SabrySassConfig::default_intermediate_dir")]
pub intermediate_dir: String,
#[serde(default = "SabrySassConfig::default_module_name_collision")]
pub module_name_collision: BehavSassModCollision,
}
impl SabrySassConfig {
fn default_scanroot() -> String {
"src".into()
}
fn default_intermediate_dir() -> String {
"target/.sabry/sass".into()
}
fn default_module_name_collision() -> BehavSassModCollision {
BehavSassModCollision::default()
}
}
impl Default for SabrySassConfig {
fn default() -> Self {
Self {
scanroot: Self::default_scanroot(),
modules: None,
prelude: None,
intermediate_dir: Self::default_intermediate_dir(),
module_name_collision: Self::default_module_name_collision(),
}
}
}
/// Sabry `hash` configuration table
#[derive(Deserialize, Clone)]
pub struct SabryHashConfig {
#[serde(default = "SabryHashConfig::default_size")]
pub size: usize,
#[serde(default = "SabryHashConfig::default_collision")]
pub collision: BehavHashCollision,
#[serde(default = "SabryHashConfig::default_use_scope_name")]
pub use_scope_name: bool,
#[serde(default = "SabryHashConfig::default_use_item_names")]
pub use_item_names: bool,
#[serde(default = "SabryHashConfig::default_use_code_size")]
pub use_code_size: bool,
#[serde(default = "SabryHashConfig::default_use_code_text")]
pub use_code_text: bool,
}
impl SabryHashConfig {
fn default_size() -> usize {
6
}
fn default_collision() -> BehavHashCollision {
BehavHashCollision::default()
}
fn default_use_scope_name() -> bool {
true
}
fn default_use_item_names() -> bool {
false
}
fn default_use_code_size() -> bool {
true
}
fn default_use_code_text() -> bool {
false
}
}
impl Default for SabryHashConfig {
fn default() -> Self {
Self {
size: Self::default_size(),
collision: Self::default_collision(),
use_scope_name: Self::default_use_scope_name(),
use_code_size: Self::default_use_code_size(),
use_code_text: Self::default_use_code_text(),
use_item_names: Self::default_use_item_names(),
}
}
}
/// [grass] specific configuration for sabry
#[derive(Default, Deserialize, Clone)]
pub struct SabryGrassConfig {}
/// [lightningcss] specific configuration for sabry
#[derive(Default, Deserialize, Clone)]
pub struct SabryLightCssConfig {
pub targets: SabryLightTargets,
}
/// \[package.metadata.sabry.lightningcss.targets\] configuration.
///
/// This is a convenience layer under [lightningcss::targets::Browsers] structure accepted
/// by lightningcss.
///
/// This structure is a part of [SabryConfig], which faces developer with more convenient
/// `safari = "13.2"` syntax.
#[derive(Default, Deserialize, Clone)]
pub struct SabryLightTargets {
pub android: Option<String>,
pub chrome: Option<String>,
pub edge: Option<String>,
pub firefox: Option<String>,
pub ie: Option<String>,
pub ios_saf: Option<String>,
pub opera: Option<String>,
pub safari: Option<String>,
pub samsung: Option<String>,
}
impl SabryLightTargets {
pub fn parse_ver(ver: &str) -> u32 {
let mut vercode: u32 = 0;
let vers = ver.split('.');
for (i, dig) in vers.into_iter().enumerate() {
let dignum = dig
.parse::<u32>()
.unwrap_or_else(|_| panic!("Invalid browser specifier: '{dig}'"));
let shift = 16 - 8 * i;
vercode |= dignum << shift;
}
vercode
}
}
#[cfg(feature = "compile")]
impl From<SabryLightTargets> for lightningcss::targets::Browsers {
fn from(value: SabryLightTargets) -> Self {
Self {
android: value.android.map(|s| SabryLightTargets::parse_ver(&s)),
chrome: value.chrome.map(|s| SabryLightTargets::parse_ver(&s)),
edge: value.edge.map(|s| SabryLightTargets::parse_ver(&s)),
firefox: value.firefox.map(|s| SabryLightTargets::parse_ver(&s)),
ie: value.ie.map(|s| SabryLightTargets::parse_ver(&s)),
ios_saf: value.ios_saf.map(|s| SabryLightTargets::parse_ver(&s)),
opera: value.opera.map(|s| SabryLightTargets::parse_ver(&s)),
safari: value.safari.map(|s| SabryLightTargets::parse_ver(&s)),
samsung: value.samsung.map(|s| SabryLightTargets::parse_ver(&s)),
}
}
}
/// \[package.metadata.sabry.sass\].module_name_collision option
#[derive(Default, Deserialize, Clone, Copy)]
#[serde(rename_all = "lowercase")]
pub enum BehavSassModCollision {
#[default]
Merge,
Error,
}
/// \[package.metadata.sabry.hash\].collision option
#[derive(Default, Deserialize, Clone, Copy)]
#[serde(rename_all = "lowercase")]
pub enum BehavHashCollision {
#[default]
Ignore,
Error,
}
#[cfg(test)]
mod test {
use super::{manifest, SabryConfig};
#[test]
fn empty_manifest_still_worth_a_read() {
let manifest = manifest::read_manifest().unwrap();
let _conf = SabryConfig::from(&manifest);
}
}