rspack_style 0.1.16

a rust toolkit bundled for front-end style files
Documentation
use crate::less::node::StyleNode;
use crate::less::var::VarRuleNode;
use crate::less::var_node::VarNode;
use crate::sourcemap::loc::LocMap;
use crate::style_core::context::ParseContext;
use crate::style_core::extension::StyleExtension;
use crate::style_core::filenode::StyleFileNode;
use crate::util::file::{path_join, readfile};
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use std::cell::RefCell;
use std::collections::HashSet;
use std::fmt::{Debug, Formatter};
use std::path::Path;
use std::rc::{Rc, Weak};

#[derive(Clone)]
pub struct FileInfo {
  // 文件的磁盘位置
  pub disk_location: String,
  // 文件的原始内容
  pub origin_txt_content: String,
  // 根据 原始内容 -> 转化的 字符数组
  pub origin_charlist: Vec<char>,
  // 文件的 原始AST节点
  pub block_node: Vec<StyleNode>,
  // 当前所有 索引 对应的 坐标行列 -> 用于执行 sourcemap
  pub locmap: Option<LocMap>,
  // 全局上下文
  pub context: ParseContext,
  // 自身弱引用
  pub self_weak: FileWeakRef,
  // 该文件的引用文件
  pub import_files: Vec<StyleFileNode>,
  // 是否 codegen 时需要处理 css_module
  pub modules: bool,
  // 处理 css 所有的 类选择器的 合集 已经去重
  pub class_selector_collect: HashSet<String>,
  // css_modules 需要增加的 hash 尾串
  pub hash_perfix: String,
  // 处理文件类型
  pub resolve_extension: StyleExtension,
}

pub type FileRef = Rc<RefCell<FileInfo>>;

pub type FileWeakRef = Option<Weak<RefCell<FileInfo>>>;

impl Serialize for FileInfo {
  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  where
    S: Serializer,
  {
    let mut state = serializer.serialize_struct("FileInfo", 3)?;
    state.serialize_field("disk_location", &self.disk_location)?;
    state.serialize_field("origin_txt_content", &self.origin_txt_content)?;
    state.serialize_field("block_node", &self.block_node)?;
    state.serialize_field("import_file", &self.import_files)?;
    state.serialize_field("class_selector_collect", &self.class_selector_collect)?;
    state.serialize_field("hash_perfix", &self.hash_perfix)?;
    state.serialize_field("resolve_extension", &self.resolve_extension)?;
    state.end()
  }
}

impl Debug for FileInfo {
  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    f.debug_struct("FileInfo")
      .field("disk_location", &self.disk_location)
      .field("block_node", &self.block_node)
      .field("import_file", &self.import_files)
      .field("class_selector_collect", &self.class_selector_collect)
      .field("hash_perfix", &self.hash_perfix)
      .field("resolve_extension", &self.resolve_extension)
      .finish()
  }
}

impl FileInfo {
  ///
  /// 转 heap 堆上对象
  ///
  pub fn toheap(self) -> FileRef {
    let heapobj = Rc::new(RefCell::new(self));
    heapobj.borrow_mut().self_weak = Some(Rc::downgrade(&heapobj));
    heapobj
  }

  ///
  /// 获取 某文件下 所有的 变量节点
  /// 递归 获取所有 fileinfo 上 block_node -> var 节点
  /// 只取 less 文件 上的变量
  ///
  pub fn collect_vars(&self) -> Vec<VarNode> {
    let mut varlist = vec![];
    for filenode in &self.import_files {
      if let StyleFileNode::Less(less_node) = filenode {
        for item in &less_node.info.borrow().block_node {
          if let StyleNode::Var(VarRuleNode::Var(var)) = &item {
            varlist.push(var.clone());
          }
        }
        // 递归收集
        let mut child_var_list = less_node.info.borrow().collect_vars();
        varlist.append(&mut child_var_list);
      }
    }
    varlist
  }

  ///
  /// 生成整个文件的 locmap 地图
  ///
  pub fn get_loc_by_content(chars: &[char]) -> LocMap {
    LocMap::new(chars)
  }

  ///
  /// 获取指定文件的路径
  /// 如果是路径 -> 直接返回该路径
  ///
  pub fn get_dir(path_value: &str) -> Result<String, String> {
    let path = Path::new(path_value);
    if path.is_file() {
      Ok(path.parent().unwrap().to_str().unwrap().to_string())
    } else if path.is_dir() {
      Ok(path_value.to_string())
    } else {
      Err(format!(
        "path type is file or dir please check {}",
        path_value
      ))
    }
  }

  ///
  /// 是否是相对路径
  ///
  pub fn is_relative_path(txt: &str) -> bool {
    let path = Path::new(txt);
    path.is_relative()
  }

  ///
  /// 文件查找对应解析路径
  /// 返回值 -> (路径, 文件内容)
  ///
  pub fn resolve(filepath: String, include_path: &Vec<String>) -> Result<(String, String), String> {
    // 相对路径 和 绝对路径 分开计算
    return if Self::is_relative_path(&filepath) {
      // 相对路径的情况
      let mut abs_path: Option<String> = None;
      let mut failpath = vec![];
      let mut content: Option<String> = None;
      for basepath in include_path {
        let temp_path = path_join(basepath.as_str(), filepath.as_str());
        match readfile(temp_path.as_str()) {
          Ok(res) => {
            content = Some(res);
            abs_path = Some(temp_path.clone());
            break;
          }
          Err(_) => failpath.push(temp_path.clone()),
        }
      }
      return if let Some(match_path) = abs_path {
        Ok((match_path, content.unwrap()))
      } else {
        Err(format!(
          "Nothings File is find in cmdpath and inculdepath,{}",
          failpath.join(";")
        ))
      };
    } else {
      // 绝对路径的情况
      let res = readfile(filepath.as_str())?;
      Ok((filepath, res))
    };
  }
}