You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

243 lines
7.2 KiB

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