1 | var emptyCharacter = '';
|
2 |
|
3 | var Breaks = require('../options/format').Breaks;
|
4 | var Spaces = require('../options/format').Spaces;
|
5 |
|
6 | var Marker = require('../tokenizer/marker');
|
7 | var Token = require('../tokenizer/token');
|
8 |
|
9 | function supportsAfterClosingBrace(token) {
|
10 | return token[1][1] == 'background' || token[1][1] == 'transform' || token[1][1] == 'src';
|
11 | }
|
12 |
|
13 | function afterClosingBrace(token, valueIndex) {
|
14 | return token[valueIndex][1][token[valueIndex][1].length - 1] == Marker.CLOSE_ROUND_BRACKET;
|
15 | }
|
16 |
|
17 | function afterComma(token, valueIndex) {
|
18 | return token[valueIndex][1] == Marker.COMMA;
|
19 | }
|
20 |
|
21 | function afterSlash(token, valueIndex) {
|
22 | return token[valueIndex][1] == Marker.FORWARD_SLASH;
|
23 | }
|
24 |
|
25 | function beforeComma(token, valueIndex) {
|
26 | return token[valueIndex + 1] && token[valueIndex + 1][1] == Marker.COMMA;
|
27 | }
|
28 |
|
29 | function beforeSlash(token, valueIndex) {
|
30 | return token[valueIndex + 1] && token[valueIndex + 1][1] == Marker.FORWARD_SLASH;
|
31 | }
|
32 |
|
33 | function inFilter(token) {
|
34 | return token[1][1] == 'filter' || token[1][1] == '-ms-filter';
|
35 | }
|
36 |
|
37 | function disallowsSpace(context, token, valueIndex) {
|
38 | return !context.spaceAfterClosingBrace && supportsAfterClosingBrace(token) && afterClosingBrace(token, valueIndex) ||
|
39 | beforeSlash(token, valueIndex) ||
|
40 | afterSlash(token, valueIndex) ||
|
41 | beforeComma(token, valueIndex) ||
|
42 | afterComma(token, valueIndex);
|
43 | }
|
44 |
|
45 | function rules(context, tokens) {
|
46 | var store = context.store;
|
47 |
|
48 | for (var i = 0, l = tokens.length; i < l; i++) {
|
49 | store(context, tokens[i]);
|
50 |
|
51 | if (i < l - 1) {
|
52 | store(context, comma(context));
|
53 | }
|
54 | }
|
55 | }
|
56 |
|
57 | function body(context, tokens) {
|
58 | var lastPropertyAt = lastPropertyIndex(tokens);
|
59 |
|
60 | for (var i = 0, l = tokens.length; i < l; i++) {
|
61 | property(context, tokens, i, lastPropertyAt);
|
62 | }
|
63 | }
|
64 |
|
65 | function lastPropertyIndex(tokens) {
|
66 | var index = tokens.length - 1;
|
67 |
|
68 | for (; index >= 0; index--) {
|
69 | if (tokens[index][0] != Token.COMMENT) {
|
70 | break;
|
71 | }
|
72 | }
|
73 |
|
74 | return index;
|
75 | }
|
76 |
|
77 | function property(context, tokens, position, lastPropertyAt) {
|
78 | var store = context.store;
|
79 | var token = tokens[position];
|
80 |
|
81 | var propertyValue = token[2];
|
82 | var isPropertyBlock = propertyValue && propertyValue[0] === Token.PROPERTY_BLOCK;
|
83 |
|
84 | var needsSemicolon;
|
85 | if ( context.format ) {
|
86 | if ( context.format.semicolonAfterLastProperty || isPropertyBlock ) {
|
87 | needsSemicolon = true;
|
88 | } else if ( position < lastPropertyAt ) {
|
89 | needsSemicolon = true;
|
90 | } else {
|
91 | needsSemicolon = false;
|
92 | }
|
93 | } else {
|
94 | needsSemicolon = position < lastPropertyAt || isPropertyBlock;
|
95 | }
|
96 |
|
97 | var isLast = position === lastPropertyAt;
|
98 |
|
99 | switch (token[0]) {
|
100 | case Token.AT_RULE:
|
101 | store(context, token);
|
102 | store(context, semicolon(context, Breaks.AfterProperty, false));
|
103 | break;
|
104 | case Token.AT_RULE_BLOCK:
|
105 | rules(context, token[1]);
|
106 | store(context, openBrace(context, Breaks.AfterRuleBegins, true));
|
107 | body(context, token[2]);
|
108 | store(context, closeBrace(context, Breaks.AfterRuleEnds, false, isLast));
|
109 | break;
|
110 | case Token.COMMENT:
|
111 | store(context, token);
|
112 | break;
|
113 | case Token.PROPERTY:
|
114 | store(context, token[1]);
|
115 | store(context, colon(context));
|
116 | if (propertyValue) {
|
117 | value(context, token);
|
118 | }
|
119 | store(context, needsSemicolon ? semicolon(context, Breaks.AfterProperty, isLast) : emptyCharacter);
|
120 | break;
|
121 | case Token.RAW:
|
122 | store(context, token);
|
123 | }
|
124 | }
|
125 |
|
126 | function value(context, token) {
|
127 | var store = context.store;
|
128 | var j, m;
|
129 |
|
130 | if (token[2][0] == Token.PROPERTY_BLOCK) {
|
131 | store(context, openBrace(context, Breaks.AfterBlockBegins, false));
|
132 | body(context, token[2][1]);
|
133 | store(context, closeBrace(context, Breaks.AfterBlockEnds, false, true));
|
134 | } else {
|
135 | for (j = 2, m = token.length; j < m; j++) {
|
136 | store(context, token[j]);
|
137 |
|
138 | if (j < m - 1 && (inFilter(token) || !disallowsSpace(context, token, j))) {
|
139 | store(context, Marker.SPACE);
|
140 | }
|
141 | }
|
142 | }
|
143 | }
|
144 |
|
145 | function allowsBreak(context, where) {
|
146 | return context.format && context.format.breaks[where];
|
147 | }
|
148 |
|
149 | function allowsSpace(context, where) {
|
150 | return context.format && context.format.spaces[where];
|
151 | }
|
152 |
|
153 | function openBrace(context, where, needsPrefixSpace) {
|
154 | if (context.format) {
|
155 | context.indentBy += context.format.indentBy;
|
156 | context.indentWith = context.format.indentWith.repeat(context.indentBy);
|
157 | return (needsPrefixSpace && allowsSpace(context, Spaces.BeforeBlockBegins) ? Marker.SPACE : emptyCharacter) +
|
158 | Marker.OPEN_CURLY_BRACKET +
|
159 | (allowsBreak(context, where) ? context.format.breakWith : emptyCharacter) +
|
160 | context.indentWith;
|
161 | } else {
|
162 | return Marker.OPEN_CURLY_BRACKET;
|
163 | }
|
164 | }
|
165 |
|
166 | function closeBrace(context, where, beforeBlockEnd, isLast) {
|
167 | if (context.format) {
|
168 | context.indentBy -= context.format.indentBy;
|
169 | context.indentWith = context.format.indentWith.repeat(context.indentBy);
|
170 | return (allowsBreak(context, Breaks.AfterProperty) || beforeBlockEnd && allowsBreak(context, Breaks.BeforeBlockEnds) ? context.format.breakWith : emptyCharacter) +
|
171 | context.indentWith +
|
172 | Marker.CLOSE_CURLY_BRACKET +
|
173 | (isLast ? emptyCharacter : (allowsBreak(context, where) ? context.format.breakWith : emptyCharacter) + context.indentWith);
|
174 | } else {
|
175 | return Marker.CLOSE_CURLY_BRACKET;
|
176 | }
|
177 | }
|
178 |
|
179 | function colon(context) {
|
180 | return context.format ?
|
181 | Marker.COLON + (allowsSpace(context, Spaces.BeforeValue) ? Marker.SPACE : emptyCharacter) :
|
182 | Marker.COLON;
|
183 | }
|
184 |
|
185 | function semicolon(context, where, isLast) {
|
186 | return context.format ?
|
187 | Marker.SEMICOLON + (isLast || !allowsBreak(context, where) ? emptyCharacter : context.format.breakWith + context.indentWith) :
|
188 | Marker.SEMICOLON;
|
189 | }
|
190 |
|
191 | function comma(context) {
|
192 | return context.format ?
|
193 | Marker.COMMA + (allowsBreak(context, Breaks.BetweenSelectors) ? context.format.breakWith : emptyCharacter) + context.indentWith :
|
194 | Marker.COMMA;
|
195 | }
|
196 |
|
197 | function all(context, tokens) {
|
198 | var store = context.store;
|
199 | var token;
|
200 | var isLast;
|
201 | var i, l;
|
202 |
|
203 | for (i = 0, l = tokens.length; i < l; i++) {
|
204 | token = tokens[i];
|
205 | isLast = i == l - 1;
|
206 |
|
207 | switch (token[0]) {
|
208 | case Token.AT_RULE:
|
209 | store(context, token);
|
210 | store(context, semicolon(context, Breaks.AfterAtRule, isLast));
|
211 | break;
|
212 | case Token.AT_RULE_BLOCK:
|
213 | rules(context, token[1]);
|
214 | store(context, openBrace(context, Breaks.AfterRuleBegins, true));
|
215 | body(context, token[2]);
|
216 | store(context, closeBrace(context, Breaks.AfterRuleEnds, false, isLast));
|
217 | break;
|
218 | case Token.NESTED_BLOCK:
|
219 | rules(context, token[1]);
|
220 | store(context, openBrace(context, Breaks.AfterBlockBegins, true));
|
221 | all(context, token[2]);
|
222 | store(context, closeBrace(context, Breaks.AfterBlockEnds, true, isLast));
|
223 | break;
|
224 | case Token.COMMENT:
|
225 | store(context, token);
|
226 | store(context, allowsBreak(context, Breaks.AfterComment) ? context.format.breakWith : emptyCharacter);
|
227 | break;
|
228 | case Token.RAW:
|
229 | store(context, token);
|
230 | break;
|
231 | case Token.RULE:
|
232 | rules(context, token[1]);
|
233 | store(context, openBrace(context, Breaks.AfterRuleBegins, true));
|
234 | body(context, token[2]);
|
235 | store(context, closeBrace(context, Breaks.AfterRuleEnds, false, isLast));
|
236 | break;
|
237 | }
|
238 | }
|
239 | }
|
240 |
|
241 | module.exports = {
|
242 | all: all,
|
243 | body: body,
|
244 | property: property,
|
245 | rules: rules,
|
246 | value: value
|
247 | };
|