257 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			257 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| var emptyCharacter = '';
 | |
| 
 | |
| var Breaks = require('../options/format').Breaks;
 | |
| var Spaces = require('../options/format').Spaces;
 | |
| 
 | |
| var Marker = require('../tokenizer/marker');
 | |
| var Token = require('../tokenizer/token');
 | |
| 
 | |
| function supportsAfterClosingBrace(token) {
 | |
|   return token[1][1] == 'background' || token[1][1] == 'transform' || token[1][1] == 'src';
 | |
| }
 | |
| 
 | |
| function afterClosingBrace(token, valueIndex) {
 | |
|   return token[valueIndex][1][token[valueIndex][1].length - 1] == Marker.CLOSE_ROUND_BRACKET;
 | |
| }
 | |
| 
 | |
| function afterComma(token, valueIndex) {
 | |
|   return token[valueIndex][1] == Marker.COMMA;
 | |
| }
 | |
| 
 | |
| function afterSlash(token, valueIndex) {
 | |
|   return token[valueIndex][1] == Marker.FORWARD_SLASH;
 | |
| }
 | |
| 
 | |
| function beforeComma(token, valueIndex) {
 | |
|   return token[valueIndex + 1] && token[valueIndex + 1][1] == Marker.COMMA;
 | |
| }
 | |
| 
 | |
| function beforeSlash(token, valueIndex) {
 | |
|   return token[valueIndex + 1] && token[valueIndex + 1][1] == Marker.FORWARD_SLASH;
 | |
| }
 | |
| 
 | |
| function inFilter(token) {
 | |
|   return token[1][1] == 'filter' || token[1][1] == '-ms-filter';
 | |
| }
 | |
| 
 | |
| function disallowsSpace(context, token, valueIndex) {
 | |
|   return !context.spaceAfterClosingBrace
 | |
|     && supportsAfterClosingBrace(token)
 | |
|     && afterClosingBrace(token, valueIndex)
 | |
|     || beforeSlash(token, valueIndex)
 | |
|     || afterSlash(token, valueIndex)
 | |
|     || beforeComma(token, valueIndex)
 | |
|     || afterComma(token, valueIndex);
 | |
| }
 | |
| 
 | |
| function rules(context, tokens) {
 | |
|   var store = context.store;
 | |
| 
 | |
|   for (var i = 0, l = tokens.length; i < l; i++) {
 | |
|     store(context, tokens[i]);
 | |
| 
 | |
|     if (i < l - 1) {
 | |
|       store(context, comma(context));
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| function body(context, tokens) {
 | |
|   var lastPropertyAt = lastPropertyIndex(tokens);
 | |
| 
 | |
|   for (var i = 0, l = tokens.length; i < l; i++) {
 | |
|     property(context, tokens, i, lastPropertyAt);
 | |
|   }
 | |
| }
 | |
| 
 | |
| function lastPropertyIndex(tokens) {
 | |
|   var index = tokens.length - 1;
 | |
| 
 | |
|   for (; index >= 0; index--) {
 | |
|     if (tokens[index][0] != Token.COMMENT) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return index;
 | |
| }
 | |
| 
 | |
| function property(context, tokens, position, lastPropertyAt) {
 | |
|   var store = context.store;
 | |
|   var token = tokens[position];
 | |
| 
 | |
|   var propertyValue = token[2];
 | |
|   var isPropertyBlock = propertyValue && propertyValue[0] === Token.PROPERTY_BLOCK;
 | |
| 
 | |
|   var needsSemicolon;
 | |
|   if (context.format) {
 | |
|     if (context.format.semicolonAfterLastProperty || isPropertyBlock) {
 | |
|       needsSemicolon = true;
 | |
|     } else if (position < lastPropertyAt) {
 | |
|       needsSemicolon = true;
 | |
|     } else {
 | |
|       needsSemicolon = false;
 | |
|     }
 | |
|   } else {
 | |
|     needsSemicolon = position < lastPropertyAt || isPropertyBlock;
 | |
|   }
 | |
| 
 | |
|   var isLast = position === lastPropertyAt;
 | |
| 
 | |
|   switch (token[0]) {
 | |
|   case Token.AT_RULE:
 | |
|     store(context, token);
 | |
|     store(context, semicolon(context, Breaks.AfterProperty, false));
 | |
|     break;
 | |
|   case Token.AT_RULE_BLOCK:
 | |
|     rules(context, token[1]);
 | |
|     store(context, openBrace(context, Breaks.AfterRuleBegins, true));
 | |
|     body(context, token[2]);
 | |
|     store(context, closeBrace(context, Breaks.AfterRuleEnds, false, isLast));
 | |
|     break;
 | |
|   case Token.COMMENT:
 | |
|     store(context, token);
 | |
|     store(context, breakFor(context, Breaks.AfterComment) + context.indentWith);
 | |
|     break;
 | |
|   case Token.PROPERTY:
 | |
|     store(context, token[1]);
 | |
|     store(context, colon(context));
 | |
|     if (propertyValue) {
 | |
|       value(context, token);
 | |
|     }
 | |
|     store(
 | |
|       context,
 | |
|       needsSemicolon ? semicolon(context, Breaks.AfterProperty, isLast) : emptyCharacter
 | |
|     );
 | |
|     break;
 | |
|   case Token.RAW:
 | |
|     store(context, token);
 | |
|   }
 | |
| }
 | |
| 
 | |
| function value(context, token) {
 | |
|   var store = context.store;
 | |
|   var j, m;
 | |
| 
 | |
|   if (token[2][0] == Token.PROPERTY_BLOCK) {
 | |
|     store(context, openBrace(context, Breaks.AfterBlockBegins, false));
 | |
|     body(context, token[2][1]);
 | |
|     store(context, closeBrace(context, Breaks.AfterBlockEnds, false, true));
 | |
|   } else {
 | |
|     for (j = 2, m = token.length; j < m; j++) {
 | |
|       store(context, token[j]);
 | |
| 
 | |
|       if (j < m - 1 && (inFilter(token) || !disallowsSpace(context, token, j))) {
 | |
|         store(context, Marker.SPACE);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| function breakFor(context, where) {
 | |
|   return context.format ? context.format.breaks[where] : emptyCharacter;
 | |
| }
 | |
| 
 | |
| function allowsSpace(context, where) {
 | |
|   return context.format && context.format.spaces[where];
 | |
| }
 | |
| 
 | |
| function openBrace(context, where, needsPrefixSpace) {
 | |
|   if (context.format) {
 | |
|     context.indentBy += context.format.indentBy;
 | |
|     context.indentWith = context.format.indentWith.repeat(context.indentBy);
 | |
|     return (
 | |
|       needsPrefixSpace
 | |
|       && allowsSpace(context, Spaces.BeforeBlockBegins) ? Marker.SPACE : emptyCharacter
 | |
|     ) + Marker.OPEN_CURLY_BRACKET
 | |
|       + breakFor(context, where)
 | |
|       + context.indentWith;
 | |
|   }
 | |
|   return Marker.OPEN_CURLY_BRACKET;
 | |
| }
 | |
| 
 | |
| function closeBrace(context, where, beforeBlockEnd, isLast) {
 | |
|   if (context.format) {
 | |
|     context.indentBy -= context.format.indentBy;
 | |
|     context.indentWith = context.format.indentWith.repeat(context.indentBy);
 | |
|     return (
 | |
|       beforeBlockEnd
 | |
|         ? breakFor(context, Breaks.BeforeBlockEnds)
 | |
|         : breakFor(context, Breaks.AfterProperty)
 | |
|     ) + context.indentWith
 | |
|       + Marker.CLOSE_CURLY_BRACKET
 | |
|       + (isLast ? emptyCharacter : breakFor(context, where) + context.indentWith);
 | |
|   }
 | |
|   return Marker.CLOSE_CURLY_BRACKET;
 | |
| }
 | |
| 
 | |
| function colon(context) {
 | |
|   return context.format
 | |
|     ? Marker.COLON + (allowsSpace(context, Spaces.BeforeValue) ? Marker.SPACE : emptyCharacter)
 | |
|     : Marker.COLON;
 | |
| }
 | |
| 
 | |
| function semicolon(context, where, isLast) {
 | |
|   return context.format
 | |
|     ? Marker.SEMICOLON + (isLast ? emptyCharacter : (breakFor(context, where) + context.indentWith))
 | |
|     : Marker.SEMICOLON;
 | |
| }
 | |
| 
 | |
| function comma(context) {
 | |
|   return context.format
 | |
|     ? Marker.COMMA + breakFor(context, Breaks.BetweenSelectors) + context.indentWith
 | |
|     : Marker.COMMA;
 | |
| }
 | |
| 
 | |
| function all(context, tokens) {
 | |
|   var store = context.store;
 | |
|   var token;
 | |
|   var isLast;
 | |
|   var i, l;
 | |
| 
 | |
|   for (i = 0, l = tokens.length; i < l; i++) {
 | |
|     token = tokens[i];
 | |
|     isLast = i == l - 1;
 | |
| 
 | |
|     switch (token[0]) {
 | |
|     case Token.AT_RULE:
 | |
|       store(context, token);
 | |
|       store(context, semicolon(context, Breaks.AfterAtRule, isLast));
 | |
|       break;
 | |
|     case Token.AT_RULE_BLOCK:
 | |
|       rules(context, token[1]);
 | |
|       store(context, openBrace(context, Breaks.AfterRuleBegins, true));
 | |
|       body(context, token[2]);
 | |
|       store(context, closeBrace(context, Breaks.AfterRuleEnds, false, isLast));
 | |
|       break;
 | |
|     case Token.NESTED_BLOCK:
 | |
|       rules(context, token[1]);
 | |
|       store(context, openBrace(context, Breaks.AfterBlockBegins, true));
 | |
|       all(context, token[2]);
 | |
|       store(context, closeBrace(context, Breaks.AfterBlockEnds, true, isLast));
 | |
|       break;
 | |
|     case Token.COMMENT:
 | |
|       store(context, token);
 | |
|       store(context, breakFor(context, Breaks.AfterComment) + context.indentWith);
 | |
|       break;
 | |
|     case Token.RAW:
 | |
|       store(context, token);
 | |
|       break;
 | |
|     case Token.RULE:
 | |
|       rules(context, token[1]);
 | |
|       store(context, openBrace(context, Breaks.AfterRuleBegins, true));
 | |
|       body(context, token[2]);
 | |
|       store(context, closeBrace(context, Breaks.AfterRuleEnds, false, isLast));
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| module.exports = {
 | |
|   all: all,
 | |
|   body: body,
 | |
|   property: property,
 | |
|   rules: rules,
 | |
|   value: value
 | |
| };
 |