pub(crate) mod doc;
mod error;
pub(crate) mod less;
pub(crate) mod merge;
pub(crate) mod print;
#[doc(hidden)]
pub mod scss;
pub(crate) mod sourcemap;
pub(crate) mod text;
use std::path::Path;
pub use error::CompileError;
#[derive(Debug, Default)]
pub struct Output {
pub css: String,
pub map: Option<String>,
pub deps: Vec<String>,
}
#[derive(Debug, Clone, Default)]
pub struct Options {
pub paths: Vec<std::path::PathBuf>,
pub source_map: bool,
pub project_root: Option<String>,
pub less: LessOptions,
}
#[derive(Debug, Clone, Default)]
pub struct LessOptions {
pub global_vars: Vec<(String, String)>,
}
#[doc(hidden)]
pub struct LineIndex {
starts: Vec<usize>,
}
impl LineIndex {
pub fn new(src: &str) -> Self {
let mut starts = vec![0usize];
for (i, b) in src.bytes().enumerate() {
if b == b'\n' {
starts.push(i + 1);
}
}
Self { starts }
}
pub fn line_col(&self, offset: usize, src: &str) -> (u32, u32) {
let line = match self.starts.binary_search(&offset) {
Ok(l) => l,
Err(l) => l - 1,
};
let start = self.starts[line];
let end = offset.min(src.len());
let col: usize = src[start..end].chars().map(|c| c.len_utf16()).sum();
(line as u32, col as u32)
}
}
pub fn compile_file(path: &Path, source: &str, opts: &Options) -> Result<Output, CompileError> {
let name = path.to_string_lossy();
if name.ends_with(".less") {
less::compile(path, source, opts).map_err(|e| *e)
} else if name.ends_with(".scss")
|| name.ends_with(".sass")
|| name.ends_with(".css")
|| name.ends_with(".wxss")
{
scss::compile(path, source, opts).map_err(|e| *e)
} else {
Err(CompileError::new(format!("不支持的样式后缀: {name}")))
}
}