| 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 isPropertyBlock = token[2][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); |
| break; |
| case Token.PROPERTY: |
| store(context, token[1]); |
| store(context, colon(context)); |
| 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 allowsBreak(context, where) { |
| return context.format && context.format.breaks[where]; |
| } |
| |
| 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 + |
| (allowsBreak(context, where) ? context.format.breakWith : emptyCharacter) + |
| context.indentWith; |
| } else { |
| 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 (allowsBreak(context, Breaks.AfterProperty) || beforeBlockEnd && allowsBreak(context, Breaks.BeforeBlockEnds) ? context.format.breakWith : emptyCharacter) + |
| context.indentWith + |
| Marker.CLOSE_CURLY_BRACKET + |
| (isLast ? emptyCharacter : (allowsBreak(context, where) ? context.format.breakWith : emptyCharacter) + context.indentWith); |
| } else { |
| 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 || !allowsBreak(context, where) ? emptyCharacter : context.format.breakWith + context.indentWith) : |
| Marker.SEMICOLON; |
| } |
| |
| function comma(context) { |
| return context.format ? |
| Marker.COMMA + (allowsBreak(context, Breaks.BetweenSelectors) ? context.format.breakWith : emptyCharacter) + 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, allowsBreak(context, Breaks.AfterComment) ? context.format.breakWith : emptyCharacter); |
| 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 |
| }; |