lightningcss 1.0.0-alpha.37

A CSS parser, transformer, and minifier
Documentation
//! Browser target options.
// This file is autogenerated by build-prefixes.js. DO NOT EDIT!

use serde::{Deserialize, Serialize};

/// Browser versions to compile CSS for.
///
/// Versions are represented as a single 24-bit integer, with one byte
/// per `major.minor.patch` component.
///
/// # Example
///
/// This example represents a target of Safari 13.2.0.
///
/// ```
/// use lightningcss::targets::Browsers;
///
/// let targets = Browsers {
///   safari: Some((13 << 16) | (2 << 8)),
///   ..Browsers::default()
/// };
/// ```
#[derive(Serialize, Debug, Deserialize, Clone, Copy, Default)]
#[allow(missing_docs)]
pub struct Browsers {
  pub android: Option<u32>,
  pub chrome: Option<u32>,
  pub edge: Option<u32>,
  pub firefox: Option<u32>,
  pub ie: Option<u32>,
  pub ios_saf: Option<u32>,
  pub opera: Option<u32>,
  pub safari: Option<u32>,
  pub samsung: Option<u32>,
}

#[cfg(feature = "browserslist")]
impl Browsers {
  /// Parses a list of browserslist queries into Lightning CSS targets.
  pub fn from_browserslist<S: AsRef<str>, I: IntoIterator<Item = S>>(
    query: I,
  ) -> Result<Option<Browsers>, browserslist::Error> {
    use browserslist::{resolve, Opts};

    Self::from_distribs(resolve(query, &Opts::new())?)
  }

  /// Finds browserslist configuration, selects queries by environment and loads the resulting queries into LightningCSS targets.
  ///
  /// Configuration resolution is modeled after the original `browserslist` nodeJS package.
  /// The configuration is resolved in the following order:
  ///
  /// - If a `BROWSERSLIST` environment variable is present, then load targets from its value. This is analog to the `--targets` CLI option.
  ///   Example: `BROWSERSLIST="firefox ESR" lightningcss [OPTIONS] <INPUT_FILE>`
  /// - If a `BROWSERSLIST_CONFIG` environment variable is present, then resolve the file at the provided path.
  ///   Then parse and use targets from `package.json` or any browserslist configuration file pointed to by the environment variable.
  ///   Example: `BROWSERSLIST_CONFIG="../config/browserslist" lightningcss [OPTIONS] <INPUT_FILE>`
  /// - If none of the above apply, then find, parse and use targets from the first `browserslist`, `.browserslistrc`
  ///   or `package.json` configuration file in any parent directory.
  ///
  /// When using parsed configuration from `browserslist`, `.browserslistrc` or `package.json` configuration files,
  /// the environment determined by:
  ///
  /// - the `BROWSERSLIST_ENV` environment variable if present,
  /// - otherwise the `NODE_ENV` environment varialbe if present,
  /// - otherwise `production` is used.
  ///
  /// If no targets are found for the resulting environment, then the `defaults` configuration section is used.
  pub fn load_browserslist() -> Result<Option<Browsers>, browserslist::Error> {
    use browserslist::{execute, Opts};

    Self::from_distribs(execute(&Opts::new())?)
  }

  fn from_distribs(distribs: Vec<browserslist::Distrib>) -> Result<Option<Browsers>, browserslist::Error> {
    let mut browsers = Browsers::default();
    let mut has_any = false;
    for distrib in distribs {
      macro_rules! browser {
        ($browser: ident) => {{
          if let Some(v) = parse_version(distrib.version()) {
            if browsers.$browser.is_none() || v < browsers.$browser.unwrap() {
              browsers.$browser = Some(v);
              has_any = true;
            }
          }
        }};
      }

      match distrib.name() {
        "android" => browser!(android),
        "chrome" | "and_chr" => browser!(chrome),
        "edge" => browser!(edge),
        "firefox" | "and_ff" => browser!(firefox),
        "ie" => browser!(ie),
        "ios_saf" => browser!(ios_saf),
        "opera" | "op_mob" => browser!(opera),
        "safari" => browser!(safari),
        "samsung" => browser!(samsung),
        _ => {}
      }
    }

    if !has_any {
      return Ok(None);
    }

    Ok(Some(browsers))
  }
}

#[cfg(feature = "browserslist")]
fn parse_version(version: &str) -> Option<u32> {
  let version = version.split('-').next();
  if version.is_none() {
    return None;
  }

  let mut version = version.unwrap().split('.');
  let major = version.next().and_then(|v| v.parse::<u32>().ok());
  if let Some(major) = major {
    let minor = version.next().and_then(|v| v.parse::<u32>().ok()).unwrap_or(0);
    let patch = version.next().and_then(|v| v.parse::<u32>().ok()).unwrap_or(0);
    let v: u32 = (major & 0xff) << 16 | (minor & 0xff) << 8 | (patch & 0xff);
    return Some(v);
  }

  None
}