ae23a7aa8c32d279df4f1452ef8f8de4d827bca1a0dbc608d4d8166c32c1994f9c77d082d84eaa9250280d4a82d6a1aded1e3f92a121de9e7c3582d368c04f 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. 'use strict';
  2. exports.__esModule = true;
  3. exports.default = tokenize;
  4. var _tokenTypes = require('./tokenTypes');
  5. var t = _interopRequireWildcard(_tokenTypes);
  6. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
  7. var wordEnd = /[ \n\t\r\(\)\*:;!&'"\+\|~>,=$^\[\]\\]|\/(?=\*)/g;
  8. function tokenize(input) {
  9. var tokens = [];
  10. var css = input.css.valueOf();
  11. var _css = css,
  12. length = _css.length;
  13. var offset = -1;
  14. var line = 1;
  15. var start = 0;
  16. var end = 0;
  17. var code = void 0,
  18. content = void 0,
  19. endColumn = void 0,
  20. endLine = void 0,
  21. escaped = void 0,
  22. escapePos = void 0,
  23. last = void 0,
  24. lines = void 0,
  25. next = void 0,
  26. nextLine = void 0,
  27. nextOffset = void 0,
  28. quote = void 0,
  29. tokenType = void 0;
  30. function unclosed(what, fix) {
  31. if (input.safe) {
  32. // fyi: this is never set to true.
  33. css += fix;
  34. next = css.length - 1;
  35. } else {
  36. throw input.error('Unclosed ' + what, line, start - offset, start);
  37. }
  38. }
  39. while (start < length) {
  40. code = css.charCodeAt(start);
  41. if (code === t.newline) {
  42. offset = start;
  43. line += 1;
  44. }
  45. switch (code) {
  46. case t.newline:
  47. case t.space:
  48. case t.tab:
  49. case t.cr:
  50. case t.feed:
  51. next = start;
  52. do {
  53. next += 1;
  54. code = css.charCodeAt(next);
  55. if (code === t.newline) {
  56. offset = next;
  57. line += 1;
  58. }
  59. } while (code === t.space || code === t.newline || code === t.tab || code === t.cr || code === t.feed);
  60. tokenType = t.space;
  61. endLine = line;
  62. endColumn = start - offset;
  63. end = next;
  64. break;
  65. case t.plus:
  66. case t.greaterThan:
  67. case t.tilde:
  68. case t.pipe:
  69. next = start;
  70. do {
  71. next += 1;
  72. code = css.charCodeAt(next);
  73. } while (code === t.plus || code === t.greaterThan || code === t.tilde || code === t.pipe);
  74. tokenType = t.combinator;
  75. endLine = line;
  76. endColumn = start - offset;
  77. end = next;
  78. break;
  79. // Consume these characters as single tokens.
  80. case t.asterisk:
  81. case t.ampersand:
  82. case t.comma:
  83. case t.equals:
  84. case t.dollar:
  85. case t.caret:
  86. case t.openSquare:
  87. case t.closeSquare:
  88. case t.colon:
  89. case t.semicolon:
  90. case t.openParenthesis:
  91. case t.closeParenthesis:
  92. next = start;
  93. tokenType = code;
  94. endLine = line;
  95. endColumn = start - offset;
  96. end = next + 1;
  97. break;
  98. case t.singleQuote:
  99. case t.doubleQuote:
  100. quote = code === t.singleQuote ? "'" : '"';
  101. next = start;
  102. do {
  103. escaped = false;
  104. next = css.indexOf(quote, next + 1);
  105. if (next === -1) {
  106. unclosed('quote', quote);
  107. }
  108. escapePos = next;
  109. while (css.charCodeAt(escapePos - 1) === t.backslash) {
  110. escapePos -= 1;
  111. escaped = !escaped;
  112. }
  113. } while (escaped);
  114. tokenType = t.str;
  115. endLine = line;
  116. endColumn = start - offset;
  117. end = next + 1;
  118. break;
  119. case t.backslash:
  120. next = start;
  121. escaped = true;
  122. while (css.charCodeAt(next + 1) === t.backslash) {
  123. next += 1;
  124. escaped = !escaped;
  125. }
  126. code = css.charCodeAt(next + 1);
  127. if (escaped && code !== t.slash && code !== t.space && code !== t.newline && code !== t.tab && code !== t.cr && code !== t.feed) {
  128. next += 1;
  129. }
  130. tokenType = t.word;
  131. endLine = line;
  132. endColumn = next - offset;
  133. end = next + 1;
  134. break;
  135. default:
  136. if (code === t.slash && css.charCodeAt(start + 1) === t.asterisk) {
  137. next = css.indexOf('*/', start + 2) + 1;
  138. if (next === 0) {
  139. unclosed('comment', '*/');
  140. }
  141. content = css.slice(start, next + 1);
  142. lines = content.split('\n');
  143. last = lines.length - 1;
  144. if (last > 0) {
  145. nextLine = line + last;
  146. nextOffset = next - lines[last].length;
  147. } else {
  148. nextLine = line;
  149. nextOffset = offset;
  150. }
  151. tokenType = t.comment;
  152. line = nextLine;
  153. endLine = nextLine;
  154. endColumn = next - nextOffset;
  155. } else {
  156. wordEnd.lastIndex = start + 1;
  157. wordEnd.test(css);
  158. if (wordEnd.lastIndex === 0) {
  159. next = css.length - 1;
  160. } else {
  161. next = wordEnd.lastIndex - 2;
  162. }
  163. tokenType = t.word;
  164. endLine = line;
  165. endColumn = next - offset;
  166. }
  167. end = next + 1;
  168. break;
  169. }
  170. // Ensure that the token structure remains consistent
  171. tokens.push([tokenType, // [0] Token type
  172. line, // [1] Starting line
  173. start - offset, // [2] Starting column
  174. endLine, // [3] Ending line
  175. endColumn, // [4] Ending column
  176. start, // [5] Start position / Source index
  177. end] // [6] End position
  178. );
  179. // Reset offset for the next token
  180. if (nextOffset) {
  181. offset = nextOffset;
  182. nextOffset = null;
  183. }
  184. start = end;
  185. }
  186. return tokens;
  187. }
  188. module.exports = exports['default'];