Skip to content

Commit

Permalink
feat: 将样式转为对象插入到代码中
Browse files Browse the repository at this point in the history
  • Loading branch information
luckyadam committed Oct 16, 2023
1 parent ae91b2c commit 644a0d3
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 11 deletions.
5 changes: 2 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ pub fn parse(component: String, styles: Vec<String>) -> String {
let css = styles.join("\n");
let mut style_parser = StyleParser::new(&document);
style_parser.parse(&css);
let style_record = style_parser.calc();
let style_data = style_parser.calc();

let program = Rc::new(RefCell::new(document.program.as_ref().unwrap().clone()));
let jsx_record = Rc::new(RefCell::new(document.jsx_record.as_ref().unwrap().clone()));
let style_record = Rc::new(RefCell::new(style_record));
let mut style_write = StyleWrite::new(program.clone(), jsx_record.clone(), style_record.clone());
let mut style_write = StyleWrite::new(program.clone(), jsx_record.clone(), style_data.style_record.clone(), style_data.all_style.clone());
style_write.write();

// ast 转代码
Expand Down
41 changes: 35 additions & 6 deletions src/style_parser.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{cell::RefCell, collections::HashMap, convert::Infallible, rc::Rc};
use std::{cell::RefCell, collections::HashMap, convert::Infallible, rc::Rc, hash::Hash};

use lightningcss::{
declaration::DeclarationBlock,
Expand All @@ -11,6 +11,11 @@ use lightningcss::{

use crate::{document::JSXDocument, visitor::SpanKey};

pub struct StyleData<'i> {
pub style_record: Rc<RefCell<HashMap<SpanKey, StyleDeclaration<'i>>>>,
pub all_style: Rc<RefCell<HashMap<String, StyleDeclaration<'i>>>>,
}

#[derive(Debug, Clone)]
pub struct StyleDeclaration<'i> {
pub specificity: u32,
Expand All @@ -19,16 +24,19 @@ pub struct StyleDeclaration<'i> {

pub struct StyleVisitor<'i> {
pub style_record: Rc<RefCell<HashMap<SpanKey, Vec<StyleDeclaration<'i>>>>>,
pub all_style: Rc<RefCell<HashMap<String, Vec<StyleDeclaration<'i>>>>>,
pub document: &'i JSXDocument,
}

impl<'i> StyleVisitor<'i> {
pub fn new(
document: &'i JSXDocument,
style_record: Rc<RefCell<HashMap<SpanKey, Vec<StyleDeclaration<'i>>>>>,
all_style: Rc<RefCell<HashMap<String, Vec<StyleDeclaration<'i>>>>>,
) -> Self {
StyleVisitor {
style_record,
all_style,
document,
}
}
Expand All @@ -44,6 +52,15 @@ impl<'i> Visitor<'i> for StyleVisitor<'i> {
let selectors = selectors_str.split(",").collect::<Vec<&str>>();
for index in 0..selectors.len() {
let selector = selectors[index].trim().replace(".", "");
{
let mut all_style = self.all_style.borrow_mut();
let declarations: &mut Vec<StyleDeclaration<'_>> =
all_style.entry(selector.clone()).or_insert(vec![]);
declarations.push(StyleDeclaration {
specificity: style.selectors.0.get(index).unwrap().specificity(),
declaration: style.declarations.clone(),
});
}
let elements = self.document.select(selector.as_str());
for element in elements {
let mut style_record = self.style_record.borrow_mut();
Expand All @@ -64,26 +81,26 @@ impl<'i> Visitor<'i> for StyleVisitor<'i> {

pub struct StyleParser<'i> {
pub style_record: Rc<RefCell<HashMap<SpanKey, Vec<StyleDeclaration<'i>>>>>,
pub all_style: Rc<RefCell<HashMap<String, Vec<StyleDeclaration<'i>>>>>,
pub document: &'i JSXDocument,
}

impl<'i> StyleParser<'i> {
pub fn new(document: &'i JSXDocument) -> Self {
StyleParser {
style_record: Rc::new(RefCell::new(HashMap::new())),
all_style: Rc::new(RefCell::new(HashMap::new())),
document,
}
}

pub fn parse(&mut self, css: &'i str) {
let mut stylesheet = StyleSheet::parse(css, ParserOptions::default()).expect("解析样式失败");
let mut style_visitor = StyleVisitor::new(self.document, Rc::clone(&self.style_record));
let mut style_visitor = StyleVisitor::new(self.document, Rc::clone(&self.style_record), Rc::clone(&self.all_style));
stylesheet.visit(&mut style_visitor).unwrap();
}

pub fn calc(&self) -> HashMap<SpanKey, StyleDeclaration<'i>> {
// 遍历 style_record,计算每个节点的最终样式
let mut style_record = self.style_record.borrow_mut();
fn calc_style_record<T: Hash + Eq + Clone>(&self, style_record: &mut HashMap<T, Vec<StyleDeclaration<'i>>>) -> HashMap<T, StyleDeclaration<'i>> {
let mut final_style_record = HashMap::new();
for (id, declarations) in style_record.iter_mut() {
declarations.sort_by(|a, b| a.specificity.cmp(&b.specificity));
Expand Down Expand Up @@ -117,7 +134,7 @@ impl<'i> StyleParser<'i> {
}
}
final_style_record.insert(
*id,
(*id).clone(),
StyleDeclaration {
specificity: 0,
declaration: DeclarationBlock {
Expand All @@ -129,4 +146,16 @@ impl<'i> StyleParser<'i> {
}
final_style_record
}

pub fn calc(&self) -> StyleData<'i> {
// 遍历 style_record,计算每个节点的最终样式
let mut style_record = self.style_record.borrow_mut();
let mut all_style = self.all_style.borrow_mut();
let final_style_record = self.calc_style_record(&mut style_record);
let final_all_style = self.calc_style_record(&mut all_style);
StyleData {
style_record: Rc::new(RefCell::new(final_style_record)),
all_style: Rc::new(RefCell::new(final_all_style)),
}
}
}
5 changes: 4 additions & 1 deletion src/style_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,26 @@ pub struct StyleWrite<'i> {
pub module: Rc<RefCell<Program>>,
pub jsx_record: Rc<RefCell<JSXRecord>>,
pub style_record: Rc<RefCell<HashMap<SpanKey, StyleDeclaration<'i>>>>,
pub all_style: Rc<RefCell<HashMap<String, StyleDeclaration<'i>>>>,
}

impl<'i> StyleWrite<'i> {
pub fn new(
module: Rc<RefCell<Program>>,
jsx_record: Rc<RefCell<JSXRecord>>,
style_record: Rc<RefCell<HashMap<SpanKey, StyleDeclaration<'i>>>>,
all_style: Rc<RefCell<HashMap<String, StyleDeclaration<'i>>>>,
) -> Self {
StyleWrite {
module,
jsx_record,
style_record,
all_style,
}
}

pub fn write(&mut self) {
let mut style_visitor = AstMutVisitor::new(self.jsx_record.clone(), self.style_record.clone());
let mut style_visitor = AstMutVisitor::new(self.jsx_record.clone(), self.style_record.clone(), self.all_style.clone());
self.module.borrow_mut().visit_mut_with(&mut style_visitor);
}
}
69 changes: 68 additions & 1 deletion src/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use swc_ecma_ast::{
Expr,
Ident, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, JSXElement,
JSXElementName, JSXExpr, KeyValueProp, Lit, Prop, PropName,
PropOrSpread, Str, JSXFragment, ImportDecl, ImportSpecifier, CallExpr, Callee, Null, ExprOrSpread, JSXExprContainer,
PropOrSpread, Str, JSXFragment, ImportDecl, ImportSpecifier, CallExpr, Callee, Null, ExprOrSpread, JSXExprContainer, Module, Stmt, ObjectLit, ExprStmt, AssignExpr, PatOrExpr,Pat, BindingIdent, ModuleItem, ModuleDecl, Decl, VarDecl, VarDeclKind, VarDeclarator
};
use swc_ecma_visit::{
noop_visit_mut_type, noop_visit_type, VisitMut, VisitMutWith, VisitAll, Visit, VisitAllWith,
Expand Down Expand Up @@ -175,23 +175,90 @@ impl<'a> VisitAll for AstVisitor<'a> {
pub struct AstMutVisitor<'a> {
pub jsx_record: Rc<RefCell<JSXRecord>>,
pub style_record: Rc<RefCell<HashMap<SpanKey, StyleDeclaration<'a>>>>,
pub all_style: Rc<RefCell<HashMap<String, StyleDeclaration<'a>>>>,
}

impl<'a> AstMutVisitor<'a> {
pub fn new(
jsx_record: Rc<RefCell<JSXRecord>>,
style_record: Rc<RefCell<HashMap<SpanKey, StyleDeclaration<'a>>>>,
all_style: Rc<RefCell<HashMap<String, StyleDeclaration<'a>>>>,
) -> Self {
AstMutVisitor {
jsx_record,
style_record,
all_style,
}
}
}

impl<'a> VisitMut for AstMutVisitor<'a> {
noop_visit_mut_type!();

fn visit_mut_module(&mut self, module: &mut Module) {
let inner_style_stmt = Stmt::Decl(Decl::Var(Box::new(VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Var,
declare: false,
decls: vec![VarDeclarator {
span: DUMMY_SP,
name: Pat::Ident(BindingIdent {
id: Ident::new("__inner_style__".into(), DUMMY_SP),
type_ann: None,
}),
definite: false,
init: Some(Box::new(Expr::Object(ObjectLit {
span: DUMMY_SP,
props: self
.all_style
.borrow()
.iter()
.map(|(key, value)| {
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(Ident::new(key.clone().into(), DUMMY_SP)),
value: Box::new(Expr::Object(ObjectLit {
span: DUMMY_SP,
props: value
.declaration
.declarations
.iter()
.map(|declaration| {
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(Ident::new(
declaration
.property_id()
.to_css_string(PrinterOptions::default())
.unwrap()
.into(),
DUMMY_SP,
)),
value: declaration
.value_to_css_string(PrinterOptions::default())
.unwrap()
.into(),
})))
})
.collect::<Vec<PropOrSpread>>()
.into(),
})),
})))
})
.collect::<Vec<PropOrSpread>>()
.into(),
})))
}]
})));

// 将 inner_style_stmt 插入到 module 的最后一条 import 语句之后
let mut last_import_index: i32 = -1;
for (index, stmt) in module.body.iter().enumerate() {
if let ModuleItem::ModuleDecl(ModuleDecl::Import(_)) = stmt {
last_import_index = index as i32;
}
}
module.body.insert((last_import_index + 1) as usize, ModuleItem::Stmt(inner_style_stmt));
}

fn visit_mut_jsx_element(&mut self, n: &mut JSXElement) {
let span_key = SpanKey(n.span);
if let Some(element) = self.jsx_record.borrow().get(&span_key) {
Expand Down

0 comments on commit 644a0d3

Please sign in to comment.