1
+ const inspect = require ( 'util' ) . inspect ;
2
+ const css = require ( '../parse-css' ) ;
3
+
4
+ module . exports . parse = function parse ( source ) {
5
+ return acceptStylesheet (
6
+ css . parseAStylesheet ( source )
7
+ ) ;
8
+ } ;
9
+
10
+ function acceptStylesheet ( node ) {
11
+ return {
12
+ type : 'StyleSheet' ,
13
+ rules : acceptRules ( node . value )
14
+ } ;
15
+ }
16
+
17
+ function acceptRules ( nodes ) {
18
+ return nodes . map ( acceptRule ) ;
19
+ }
20
+
21
+ function acceptRule ( node ) {
22
+ switch ( node . type ) {
23
+ case 'QUALIFIED-RULE' : return acceptStyleRule ( node ) ;
24
+ case 'AT-RULE' : return acceptAtRule ( node ) ;
25
+ default : throw new Error ( "Unknown rule type: " + node . type ) ;
26
+ }
27
+ }
28
+
29
+ function acceptStyleRule ( node ) {
30
+ return {
31
+ type : 'StyleRule' ,
32
+ selectors : [ acceptSelector ( node . prelude ) ] ,
33
+ body : acceptDeclarations ( node . value . value , acceptStyleDeclaration )
34
+ }
35
+ }
36
+
37
+ function acceptSelector ( tokens ) {
38
+ return tokens . map ( function ( token ) {
39
+ return token . toSource ( ) ;
40
+ } ) . join ( '' ) . trimRight ( ) ;
41
+ }
42
+
43
+ function acceptDeclarations ( tokens , acceptor ) {
44
+ var nodes = css . consumeAListOfDeclarations (
45
+ new css . TokenStream ( tokens )
46
+ ) ;
47
+
48
+ return nodes . map ( function ( node ) {
49
+ return acceptor ( node ) ;
50
+ } ) ;
51
+ }
52
+
53
+ function acceptStyleDeclaration ( node ) {
54
+ switch ( node . type ) {
55
+ case 'DECLARATION' : return acceptStylePropertyDeclaration ( node ) ;
56
+ case 'AT-RULE' : return acceptAtRule ( node ) ;
57
+ default : throw new Error ( "Unknown style declaration type: " + node . type ) ;
58
+ }
59
+ }
60
+
61
+ function acceptStylePropertyDeclaration ( node ) {
62
+ return {
63
+ type : 'StylePropertyDeclaration' ,
64
+ important : node . important ,
65
+ name : node . name ,
66
+ value : acceptContextualValue ( node . name , node . value )
67
+ } ;
68
+ }
69
+
70
+ function acceptContextualValue ( name , parts ) {
71
+ parts = trimWhitespaceTokens ( parts ) ;
72
+
73
+ if ( name [ 0 ] === '-' && name [ 1 ] === '-' ) {
74
+ return acceptCustomPropertyValue ( name , parts ) ;
75
+ } else {
76
+ return acceptStyleValue ( name , parts ) ;
77
+ }
78
+ }
79
+
80
+ function acceptCustomPropertyValue ( name , parts ) {
81
+ if ( parts [ 0 ] . type === 'BLOCK' ) {
82
+ return acceptMixin ( parts ) ;
83
+ } else {
84
+ return acceptStyleValue ( name , parts ) ;
85
+ }
86
+ }
87
+
88
+ function acceptMixin ( parts ) {
89
+ var block = parts [ 0 ] ;
90
+
91
+ return {
92
+ type : 'Mixin' ,
93
+ body : acceptDeclarations ( block . value , acceptMixinStyleDeclaration )
94
+ } ;
95
+ }
96
+
97
+ function acceptStyleValue ( name , parts ) {
98
+ return printValue ( parts ) ;
99
+ }
100
+
101
+ function printValue ( parts ) {
102
+ return parts . map ( function ( part ) {
103
+ if ( part . tokenType ) {
104
+ return part . toSource ( ) ;
105
+ } else if ( part . type === 'FUNCTION' ) {
106
+ return part . name + '(' + printValue ( part . value ) + ')' ;
107
+ } else {
108
+ throw new Error ( "Unsupported value part: " + JSON . stringify ( part . toJSON ( ) ) ) ;
109
+ }
110
+ } ) . join ( '' ) ;
111
+ }
112
+
113
+ function acceptStyleValueParts ( name , parts ) {
114
+ return parts . map ( acceptStyleValuePart ) ;
115
+ }
116
+
117
+ function acceptStyleValuePart ( node ) {
118
+ if ( node . tokenType ) {
119
+ return node ;
120
+ }
121
+
122
+ switch ( node . type ) {
123
+ case 'FUNCTION' : return acceptFunction ( node ) ;
124
+ default : throw new Error ( "Unknown style part: " + node . tokenType + " " + node . type + " " + node )
125
+ }
126
+ }
127
+
128
+ function acceptFunction ( node ) {
129
+ throw new Error ( "Functions in property values (e.g. calc and color) are not yet supported." ) ;
130
+ }
131
+
132
+ function acceptMixinStyleDeclaration ( node ) {
133
+ switch ( node . type ) {
134
+ case 'DECLARATION' : return acceptStylePropertyDeclaration ( node ) ;
135
+ default : throw new Error ( "Unknown style declaration type: " + node . type ) ;
136
+ }
137
+ }
138
+
139
+
140
+ function acceptAtRule ( node ) {
141
+ return {
142
+ type : 'AtRule' ,
143
+ name : node . name ,
144
+ prelude : node . prelude ,
145
+ value : node . value
146
+ } ;
147
+ }
148
+
149
+ function trimWhitespaceTokens ( tokens ) {
150
+ var startIndex = 0 ;
151
+ var endIndex = tokens . length ;
152
+
153
+ while ( tokens [ startIndex ] . tokenType === 'WHITESPACE' ) { startIndex ++ ; }
154
+ while ( tokens [ endIndex - 1 ] . tokenType === 'WHITESPACE' ) { endIndex -- ; }
155
+
156
+ return tokens . slice ( startIndex , endIndex ) ;
157
+ }
0 commit comments