1+ use std:: { collections:: HashMap , rc:: Rc } ;
2+
3+ use lightningcss:: { properties:: { custom:: TokenOrValue , Property } , traits:: ToCss , values:: time:: Time } ;
4+ use swc_common:: { comments:: SingleThreadedComments , sync:: Lrc , SourceMap , DUMMY_SP } ;
5+ use swc_ecma_ast:: { AssignExpr , AssignOp , CallExpr , Callee , ComputedPropName , Expr , ExprOrSpread , ExprStmt , KeyValueProp , Lit , MemberExpr , MemberProp , Module , ModuleItem , Number , ObjectLit , PatOrExpr , Program , Prop , PropName , PropOrSpread , Stmt } ;
6+ use swc_ecma_codegen:: { text_writer:: JsWriter , Emitter } ;
7+ use swc_ecma_utils:: quote_ident;
8+
9+ use crate :: style_propetries:: unit:: { convert_color_keywords_to_hex, generate_expr_by_length_value, Platform } ;
10+
11+
12+ pub fn parse ( properties : Vec < ( String , Property < ' _ > ) > ) -> HashMap < String , Expr > {
13+
14+ // properties.iter().for_each(|(key, value)| {
15+ // println!("key: {}, value: {:?}", key, value);
16+ // });
17+ let mut css_variables = HashMap :: new ( ) ;
18+ properties. iter ( ) . for_each ( |( key, value) | {
19+ let mut expr: Option < Expr > = None ;
20+ match value. clone ( ) {
21+ Property :: Custom ( custom) => {
22+ let token_or_value = custom. value . 0 . get ( 0 ) ;
23+ if let Some ( token_or_value) = token_or_value {
24+ expr = Some ( get_token_or_value ( token_or_value. to_owned ( ) ) ) ;
25+ }
26+ } ,
27+ _ => { }
28+ } ;
29+ if let Some ( expr) = expr {
30+ css_variables. insert ( key. to_string ( ) , expr) ;
31+ }
32+ } ) ;
33+ css_variables
34+ }
35+
36+
37+ pub fn write ( css_variables : HashMap < String , Expr > ) -> String {
38+ // css_variables.iter().for_each(|(key, value)| {
39+ // println!("key: {}, value: {:?}", key, value);
40+ // });
41+
42+ let obj = Expr :: Object ( ObjectLit {
43+ span : DUMMY_SP ,
44+ props : css_variables. iter ( ) . map ( |( key, value) | {
45+ PropOrSpread :: Prop ( Box :: new ( Prop :: KeyValue ( KeyValueProp {
46+ key : PropName :: Computed ( ComputedPropName {
47+ span : DUMMY_SP ,
48+ expr : Box :: new ( Expr :: Lit ( Lit :: Str ( key. to_string ( ) . into ( ) ) ) ) ,
49+ } ) ,
50+ value : Box :: new ( value. clone ( ) ) ,
51+ } ) ) )
52+ } ) . collect :: < Vec < PropOrSpread > > ( ) . into ( ) ,
53+ } ) ;
54+
55+ let cm: Lrc < SourceMap > = Default :: default ( ) ;
56+ let comments = SingleThreadedComments :: default ( ) ;
57+ let program = Program :: Module ( Module {
58+ span : DUMMY_SP ,
59+ body : vec ! [
60+ ModuleItem :: Stmt (
61+ Stmt :: Expr ( ExprStmt {
62+ span: DUMMY_SP ,
63+ expr: Box :: new( Expr :: Assign ( AssignExpr {
64+ span: DUMMY_SP ,
65+ op: AssignOp :: Assign ,
66+ left: PatOrExpr :: Expr ( Box :: new( Expr :: Ident ( quote_ident!( "css_var_map" ) ) ) ) ,
67+ right: Box :: new( obj)
68+ } ) )
69+ } )
70+ ) ,
71+ ] ,
72+ shebang : None ,
73+ } ) ;
74+ // 生成代码
75+ let mut buf = vec ! [ ] ;
76+ {
77+ let mut emitter = Emitter {
78+ cfg : swc_ecma_codegen:: Config :: default ( ) ,
79+ cm : cm. clone ( ) ,
80+ comments : Some ( & comments) ,
81+ wr : JsWriter :: new ( cm. clone ( ) , "\n " , & mut buf, None ) ,
82+ } ;
83+ emitter. emit_program ( & program) . unwrap ( ) ;
84+ }
85+ String :: from_utf8 ( buf) . unwrap ( ) . replace ( "\r \n " , "\n " )
86+ }
87+
88+ pub fn get_token_or_value ( token_or_value : TokenOrValue < ' _ > ) -> Expr {
89+ match token_or_value {
90+ TokenOrValue :: Token ( _) => {
91+ Expr :: Lit ( Lit :: Str ( "" . into ( ) ) )
92+ } ,
93+ TokenOrValue :: Color ( color) => {
94+ let color_string = convert_color_keywords_to_hex ( color. to_css_string ( lightningcss:: stylesheet:: PrinterOptions {
95+ minify : false ,
96+ targets : lightningcss:: targets:: Targets {
97+ include : lightningcss:: targets:: Features :: HexAlphaColors ,
98+ ..lightningcss:: targets:: Targets :: default ( )
99+ } ,
100+ ..lightningcss:: stylesheet:: PrinterOptions :: default ( )
101+ } ) . unwrap ( ) ) ;
102+ Expr :: Lit ( Lit :: Str ( color_string. into ( ) ) )
103+ } ,
104+ TokenOrValue :: UnresolvedColor ( _) => {
105+ // 解析不到的颜色
106+ Expr :: Lit ( Lit :: Str ( "" . into ( ) ) )
107+ } ,
108+ TokenOrValue :: Url ( url) => {
109+ // url("https://www.example.com") => { src: "https://www.example.com" }
110+ let url_string = url. url . to_string ( ) ;
111+ Expr :: Object ( ObjectLit {
112+ span : DUMMY_SP ,
113+ props : vec ! [
114+ PropOrSpread :: Prop ( Box :: new( Prop :: KeyValue ( KeyValueProp {
115+ key: PropName :: Ident ( quote_ident!( "src" ) ) ,
116+ value: Box :: new( Expr :: Lit ( Lit :: Str ( url_string. into( ) ) ) ) ,
117+ } ) ) )
118+ ]
119+ . into ( ) ,
120+ } )
121+ } ,
122+ TokenOrValue :: Var ( var) => {
123+ // var(--color-primary, #000000) => var_fn(css_var_map["--color-primary"], "#000000")
124+ let mut expr_or_spead = vec ! [ ] ;
125+ let ident_string = var. name . to_css_string ( Default :: default ( ) ) . unwrap ( ) ;
126+ expr_or_spead. push ( ExprOrSpread {
127+ spread : None ,
128+ expr : Box :: new (
129+ Expr :: Member ( MemberExpr {
130+ span : DUMMY_SP ,
131+ obj : Box :: new ( Expr :: Ident ( quote_ident ! ( "css_var_map" ) ) ) ,
132+ prop : MemberProp :: Computed ( ComputedPropName {
133+ span : DUMMY_SP ,
134+ expr : Box :: new ( Expr :: Lit ( Lit :: Str ( ident_string. into ( ) ) ) ) ,
135+ } )
136+ } )
137+ )
138+ } ) ;
139+ if let Some ( fallback) = & var. fallback {
140+ fallback. 0 . iter ( ) . for_each ( |token_or_value| {
141+ expr_or_spead. push ( ExprOrSpread {
142+ spread : None ,
143+ expr : Box :: new ( get_token_or_value ( token_or_value. to_owned ( ) ) ) ,
144+ } )
145+ } ) ;
146+ }
147+ Expr :: Call ( CallExpr {
148+ span : Default :: default ( ) ,
149+ callee : Callee :: Expr ( Box :: new ( Expr :: Ident ( quote_ident ! ( "var_fn" ) ) ) ) ,
150+ args : expr_or_spead,
151+ type_args : None ,
152+ } )
153+
154+ } ,
155+ TokenOrValue :: Env ( _) => {
156+ // 环境变量
157+ Expr :: Lit ( Lit :: Str ( "" . into ( ) ) )
158+ } ,
159+ TokenOrValue :: Function ( _) => {
160+ // 函数
161+ Expr :: Lit ( Lit :: Str ( "" . into ( ) ) )
162+ } ,
163+ TokenOrValue :: Length ( length_value) => {
164+ generate_expr_by_length_value ( & length_value, Platform :: Harmony )
165+ } ,
166+ TokenOrValue :: Angle ( angle) => {
167+ let angle_string = angle. to_css_string ( Default :: default ( ) ) . unwrap ( ) ;
168+ Expr :: Lit ( Lit :: Str ( angle_string. into ( ) ) )
169+ } ,
170+ TokenOrValue :: Time ( time) => {
171+ let time_num = match time {
172+ Time :: Seconds ( s) => s,
173+ Time :: Milliseconds ( m) => m * 60.0 ,
174+ } ;
175+ Expr :: Lit ( Lit :: Num ( Number {
176+ span : DUMMY_SP ,
177+ value : time_num as f64 ,
178+ raw : None ,
179+ } ) )
180+ } ,
181+ TokenOrValue :: Resolution ( resolution) => {
182+ let string = resolution. to_css_string ( Default :: default ( ) ) . unwrap ( ) ;
183+ Expr :: Lit ( Lit :: Str ( string. into ( ) ) )
184+ } ,
185+ TokenOrValue :: DashedIdent ( dashed_ident) => {
186+ let ident_string = dashed_ident. to_css_string ( Default :: default ( ) ) . unwrap ( ) ;
187+ Expr :: Member ( MemberExpr {
188+ span : DUMMY_SP ,
189+ obj : Box :: new ( Expr :: Ident ( quote_ident ! ( "css_var_map" ) ) ) ,
190+ prop : MemberProp :: Computed ( ComputedPropName {
191+ span : DUMMY_SP ,
192+ expr : Box :: new ( Expr :: Lit ( Lit :: Str ( ident_string. into ( ) ) ) ) ,
193+ } )
194+ } )
195+ } ,
196+ }
197+ }
0 commit comments