11/**
22 * ParserCSS Class
33 */
4- class Parser {
4+ class Parser {
55
6+ static get EMPTY ( ) { return '' }
67
78 static get DOTS ( ) { return ':' }
89
910 static get COMMA ( ) { return ',' }
1011
1112 static get SEMICOLON ( ) { return ';' }
1213
14+ static get BREAK_LINE ( ) { return '\n' }
15+
1316 static get BEGIN_BLOCK ( ) { return '{' }
1417
1518 static get END_BLOCK ( ) { return '}' }
1619
20+ static get END_BRACKET ( ) { return ')' }
21+
22+ static get END_BRACKET_RULE ( ) { return ');' }
23+
24+ static get DATA_URI ( ) { return 'data:' }
25+
26+ static get DATA_URI_KEYS ( ) { return { ':' : '=' , ';' : '&' } }
27+
28+ static get DATA_URI_VALUES ( ) { return { '=' : ':' , '&' : ';' } }
29+
1730 static get REGEX_COMMENTS ( ) { return / \/ \* ( \r | \n | .) * \* \/ / g }
1831
1932 static get REGEX_BRACKETS ( ) { return / \( ( [ ^ ) ] + ) \) / }
2033
34+ constructor ( css ) {
35+ this . css = css
36+ this . parseCSS ( )
37+
38+ delete this . rules
39+ return this
40+ }
41+
2142 /**
2243 * get blocks of queries and rules
2344 * @param string css
2445 * @return object rule
2546 */
26- parseCSS ( css ) {
47+ parseCSS ( css = '' ) {
2748 let blocks = [ ]
28- let rules = this . remove ( css ) . split ( Parser . END_BLOCK )
29- rules . pop ( )
30- rules . map ( block => {
31- let [ query , rule ] = block . split ( Parser . BEGIN_BLOCK )
49+ this . css = ( css != Parser . EMPTY ) ? css :this . css
50+ this . blocksRule = this . clearCode ( ) . split ( Parser . END_BLOCK )
51+ this . blocksRule . pop ( )
52+
53+ this . blocksRule . map ( block => {
54+ [ this . query , this . rules ] = block . split ( Parser . BEGIN_BLOCK )
55+
3256 blocks . push ( {
33- query : query . trim ( ) ,
34- selectors : query . trim ( ) . split ( ',' ) . map ( s => s . trim ( ) ) ,
35- rule : this . parseCSSBlock ( rule )
57+ query : this . query . trim ( ) ,
58+ selectors : this . parseCSSQuery ( ) ,
59+ rules : this . parseCSSBlock ( )
3660 } )
3761 } )
3862
@@ -44,44 +68,100 @@ class Parser {
4468 * @param string css
4569 * @return object rule
4670 */
47- parseCSSBlock ( css ) {
48- let rule = { }
49- let params = [ ]
50- const regex = / \( ( [ ^ ) ] + ) \) / ;
71+ parseCSSBlock ( rules = '' ) {
72+ let blockRules = [ ]
73+ this . rules = ( rules != Parser . EMPTY ) ? rules : this . rules
74+ this . parseCSSRules ( )
75+ . split ( Parser . SEMICOLON )
76+ . map ( decl => {
77+ let [ prop , value ] = decl . split ( Parser . DOTS ) . map ( i => i . trim ( ) )
78+ if ( prop != Parser . EMPTY && value != Parser . EMPTY )
79+ blockRules . push ( new Rule ( prop , this . _replaceAll ( value , Parser . DATA_URI_VALUES ) ) )
80+ } )
81+
82+ return blockRules
83+ }
5184
52- let decls = css . split ( '\n' )
53- . filter ( d => d != "" )
85+ /**
86+ * treat css selectors
87+ * @param string css rules
88+ * @return string
89+ */
90+ parseCSSRules ( ) {
91+ let params = { }
92+ return this . rules . split ( Parser . BREAK_LINE )
93+ . filter ( d => d != Parser . EMPTY )
5494 . map ( decl => {
55- if ( decl . includes ( '(' ) )
56- params . push ( Parser . REGEX_BRACKETS . exec ( decl ) [ 1 ] )
95+ if ( decl . includes ( Parser . END_BRACKET_RULE ) ) {
96+ let p_key = Parser . REGEX_BRACKETS . exec ( decl ) [ 1 ]
97+ if ( p_key . includes ( Parser . DATA_URI ) ) {
98+ params [ p_key ] = this . _replaceAll ( p_key , Parser . DATA_URI_KEYS )
99+ decl = this . _replaceAll ( decl , params )
100+ }
101+ }
102+
57103 return decl . trim ( )
58104 } ) . join ( '' )
105+ }
59106
60- if ( params . length > 0 ) {
61- let _params = params . map ( p => p . replace ( ':' , '=' ) . replace ( ';' , '&' ) )
62- decls = params . map ( ( p , i ) => {
63- return decls . replace ( p , _params [ i ] )
64- } ) . join ( '' )
65- }
107+ /**
108+ * parse css selectors
109+ * @return array Selector
110+ */
111+ parseCSSQuery ( ) {
112+ return this . query
113+ . trim ( )
114+ . split ( Parser . COMMA )
115+ . map ( s => s . trim ( ) )
116+ }
66117
67- decls = decls . split ( ';' )
68- decls . pop ( )
118+ /**
119+ * clear code and remove comments
120+ * @param string css
121+ * @return string css
122+ */
123+ clearCode ( css = '' ) {
124+ this . css = ( ( css != Parser . EMPTY ) ? css :this . css )
125+ . replace ( Parser . REGEX_COMMENTS , Parser . EMPTY )
126+ // .replaceAll({' ':'', '\n': '', '\t': ''})
127+ return this . css
128+ }
69129
70- decls . map ( decl => {
71- let [ prop , value ] = decl . split ( ":" ) . map ( i => i . trim ( ) )
72- if ( prop != "" && value != "" ) rule [ prop ] = value . replace ( '=' , ':' ) . replace ( '&' , ';' )
73- } )
130+ _replaceAll ( str , obj ) {
131+ return str . replace ( ( new RegExp ( Object . keys ( obj ) . join ( '|' ) ) , 'g' ) , i => obj [ i ] )
132+ }
133+ }
134+
135+
136+ class Rule {
74137
75- return rule
138+ /**
139+ * Rule Constructor
140+ * @param string prop
141+ * @param string value
142+ * @return object Rule
143+ */
144+ constructor ( prop , value ) {
145+ this . prop = prop
146+ this . value = value
147+ this . details ( )
148+
149+ return this
76150 }
77151
78152 /**
79- * remove comments
80- * @param string css
81- * @return string css
153+ * get details of value rule
154+ *
82155 */
83- remove ( css ) {
84- return css . replace ( this . REGEX_COMMENTS , "" )
156+ details ( ) {
157+ if ( this . value . includes ( Parser . END_BRACKET ) ) {
158+ let str = Parser . REGEX_BRACKETS . exec ( this . value ) [ 1 ]
159+ this . detail = { }
160+ this . detail . args = str . split ( Parser . COMMA ) . map ( p => p . trim ( ) )
161+ this . detail . func = this . value . trim ( ) . replace ( `(${ str } )` , Parser . EMPTY )
162+
163+ return this . detail
164+ }
85165 }
86166}
87167
0 commit comments