tokenize.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. var Marker = require('./marker');
  2. var Token = require('./token');
  3. var formatPosition = require('../utils/format-position');
  4. var Level = {
  5. BLOCK: 'block',
  6. COMMENT: 'comment',
  7. DOUBLE_QUOTE: 'double-quote',
  8. RULE: 'rule',
  9. SINGLE_QUOTE: 'single-quote'
  10. };
  11. var AT_RULES = [
  12. '@charset',
  13. '@import'
  14. ];
  15. var BLOCK_RULES = [
  16. '@-moz-document',
  17. '@document',
  18. '@-moz-keyframes',
  19. '@-ms-keyframes',
  20. '@-o-keyframes',
  21. '@-webkit-keyframes',
  22. '@keyframes',
  23. '@media',
  24. '@supports'
  25. ];
  26. var PAGE_MARGIN_BOXES = [
  27. '@bottom-center',
  28. '@bottom-left',
  29. '@bottom-left-corner',
  30. '@bottom-right',
  31. '@bottom-right-corner',
  32. '@left-bottom',
  33. '@left-middle',
  34. '@left-top',
  35. '@right-bottom',
  36. '@right-middle',
  37. '@right-top',
  38. '@top-center',
  39. '@top-left',
  40. '@top-left-corner',
  41. '@top-right',
  42. '@top-right-corner'
  43. ];
  44. var EXTRA_PAGE_BOXES = [
  45. '@footnote',
  46. '@footnotes',
  47. '@left',
  48. '@page-float-bottom',
  49. '@page-float-top',
  50. '@right'
  51. ];
  52. var REPEAT_PATTERN = /^\[\s{0,31}\d+\s{0,31}\]$/;
  53. var RULE_WORD_SEPARATOR_PATTERN = /[\s\(]/;
  54. var TAIL_BROKEN_VALUE_PATTERN = /[\s|\}]*$/;
  55. function tokenize(source, externalContext) {
  56. var internalContext = {
  57. level: Level.BLOCK,
  58. position: {
  59. source: externalContext.source || undefined,
  60. line: 1,
  61. column: 0,
  62. index: 0
  63. }
  64. };
  65. return intoTokens(source, externalContext, internalContext, false);
  66. }
  67. function intoTokens(source, externalContext, internalContext, isNested) {
  68. var allTokens = [];
  69. var newTokens = allTokens;
  70. var lastToken;
  71. var ruleToken;
  72. var ruleTokens = [];
  73. var propertyToken;
  74. var metadata;
  75. var metadatas = [];
  76. var level = internalContext.level;
  77. var levels = [];
  78. var buffer = [];
  79. var buffers = [];
  80. var serializedBuffer;
  81. var roundBracketLevel = 0;
  82. var isQuoted;
  83. var isSpace;
  84. var isNewLineNix;
  85. var isNewLineWin;
  86. var isCommentStart;
  87. var wasCommentStart = false;
  88. var isCommentEnd;
  89. var wasCommentEnd = false;
  90. var isCommentEndMarker;
  91. var isEscaped;
  92. var wasEscaped = false;
  93. var seekingValue = false;
  94. var seekingPropertyBlockClosing = false;
  95. var position = internalContext.position;
  96. for (; position.index < source.length; position.index++) {
  97. var character = source[position.index];
  98. isQuoted = level == Level.SINGLE_QUOTE || level == Level.DOUBLE_QUOTE;
  99. isSpace = character == Marker.SPACE || character == Marker.TAB;
  100. isNewLineNix = character == Marker.NEW_LINE_NIX;
  101. isNewLineWin = character == Marker.NEW_LINE_NIX && source[position.index - 1] == Marker.NEW_LINE_WIN;
  102. isCommentStart = !wasCommentEnd && level != Level.COMMENT && !isQuoted && character == Marker.ASTERISK && source[position.index - 1] == Marker.FORWARD_SLASH;
  103. isCommentEndMarker = !wasCommentStart && !isQuoted && character == Marker.FORWARD_SLASH && source[position.index - 1] == Marker.ASTERISK;
  104. isCommentEnd = level == Level.COMMENT && isCommentEndMarker;
  105. roundBracketLevel = Math.max(roundBracketLevel, 0);
  106. metadata = buffer.length === 0 ?
  107. [position.line, position.column, position.source] :
  108. metadata;
  109. if (isEscaped) {
  110. // previous character was a backslash
  111. buffer.push(character);
  112. } else if (!isCommentEnd && level == Level.COMMENT) {
  113. buffer.push(character);
  114. } else if (isCommentStart && (level == Level.BLOCK || level == Level.RULE) && buffer.length > 1) {
  115. // comment start within block preceded by some content, e.g. div/*<--
  116. metadatas.push(metadata);
  117. buffer.push(character);
  118. buffers.push(buffer.slice(0, buffer.length - 2));
  119. buffer = buffer.slice(buffer.length - 2);
  120. metadata = [position.line, position.column - 1, position.source];
  121. levels.push(level);
  122. level = Level.COMMENT;
  123. } else if (isCommentStart) {
  124. // comment start, e.g. /*<--
  125. levels.push(level);
  126. level = Level.COMMENT;
  127. buffer.push(character);
  128. } else if (isCommentEnd) {
  129. // comment end, e.g. /* comment */<--
  130. serializedBuffer = buffer.join('').trim() + character;
  131. lastToken = [Token.COMMENT, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]];
  132. newTokens.push(lastToken);
  133. level = levels.pop();
  134. metadata = metadatas.pop() || null;
  135. buffer = buffers.pop() || [];
  136. } else if (isCommentEndMarker && source[position.index + 1] != Marker.ASTERISK) {
  137. externalContext.warnings.push('Unexpected \'*/\' at ' + formatPosition([position.line, position.column, position.source]) + '.');
  138. buffer = [];
  139. } else if (character == Marker.SINGLE_QUOTE && !isQuoted) {
  140. // single quotation start, e.g. a[href^='https<--
  141. levels.push(level);
  142. level = Level.SINGLE_QUOTE;
  143. buffer.push(character);
  144. } else if (character == Marker.SINGLE_QUOTE && level == Level.SINGLE_QUOTE) {
  145. // single quotation end, e.g. a[href^='https'<--
  146. level = levels.pop();
  147. buffer.push(character);
  148. } else if (character == Marker.DOUBLE_QUOTE && !isQuoted) {
  149. // double quotation start, e.g. a[href^="<--
  150. levels.push(level);
  151. level = Level.DOUBLE_QUOTE;
  152. buffer.push(character);
  153. } else if (character == Marker.DOUBLE_QUOTE && level == Level.DOUBLE_QUOTE) {
  154. // double quotation end, e.g. a[href^="https"<--
  155. level = levels.pop();
  156. buffer.push(character);
  157. } else if (!isCommentStart && !isCommentEnd && character != Marker.CLOSE_ROUND_BRACKET && character != Marker.OPEN_ROUND_BRACKET && level != Level.COMMENT && !isQuoted && roundBracketLevel > 0) {
  158. // character inside any function, e.g. hsla(.<--
  159. buffer.push(character);
  160. } else if (character == Marker.OPEN_ROUND_BRACKET && !isQuoted && level != Level.COMMENT && !seekingValue) {
  161. // round open bracket, e.g. @import url(<--
  162. buffer.push(character);
  163. roundBracketLevel++;
  164. } else if (character == Marker.CLOSE_ROUND_BRACKET && !isQuoted && level != Level.COMMENT && !seekingValue) {
  165. // round open bracket, e.g. @import url(test.css)<--
  166. buffer.push(character);
  167. roundBracketLevel--;
  168. } else if (character == Marker.SEMICOLON && level == Level.BLOCK && buffer[0] == Marker.AT) {
  169. // semicolon ending rule at block level, e.g. @import '...';<--
  170. serializedBuffer = buffer.join('').trim();
  171. allTokens.push([Token.AT_RULE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  172. buffer = [];
  173. } else if (character == Marker.COMMA && level == Level.BLOCK && ruleToken) {
  174. // comma separator at block level, e.g. a,div,<--
  175. serializedBuffer = buffer.join('').trim();
  176. ruleToken[1].push([tokenScopeFrom(ruleToken[0]), serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext, ruleToken[1].length)]]);
  177. buffer = [];
  178. } else if (character == Marker.COMMA && level == Level.BLOCK && tokenTypeFrom(buffer) == Token.AT_RULE) {
  179. // comma separator at block level, e.g. @import url(...) screen,<--
  180. // keep iterating as end semicolon will create the token
  181. buffer.push(character);
  182. } else if (character == Marker.COMMA && level == Level.BLOCK) {
  183. // comma separator at block level, e.g. a,<--
  184. ruleToken = [tokenTypeFrom(buffer), [], []];
  185. serializedBuffer = buffer.join('').trim();
  186. ruleToken[1].push([tokenScopeFrom(ruleToken[0]), serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext, 0)]]);
  187. buffer = [];
  188. } else if (character == Marker.OPEN_CURLY_BRACKET && level == Level.BLOCK && ruleToken && ruleToken[0] == Token.NESTED_BLOCK) {
  189. // open brace opening at-rule at block level, e.g. @media{<--
  190. serializedBuffer = buffer.join('').trim();
  191. ruleToken[1].push([Token.NESTED_BLOCK_SCOPE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  192. allTokens.push(ruleToken);
  193. levels.push(level);
  194. position.column++;
  195. position.index++;
  196. buffer = [];
  197. ruleToken[2] = intoTokens(source, externalContext, internalContext, true);
  198. ruleToken = null;
  199. } else if (character == Marker.OPEN_CURLY_BRACKET && level == Level.BLOCK && tokenTypeFrom(buffer) == Token.NESTED_BLOCK) {
  200. // open brace opening at-rule at block level, e.g. @media{<--
  201. serializedBuffer = buffer.join('').trim();
  202. ruleToken = ruleToken || [Token.NESTED_BLOCK, [], []];
  203. ruleToken[1].push([Token.NESTED_BLOCK_SCOPE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  204. allTokens.push(ruleToken);
  205. levels.push(level);
  206. position.column++;
  207. position.index++;
  208. buffer = [];
  209. ruleToken[2] = intoTokens(source, externalContext, internalContext, true);
  210. ruleToken = null;
  211. } else if (character == Marker.OPEN_CURLY_BRACKET && level == Level.BLOCK) {
  212. // open brace opening rule at block level, e.g. div{<--
  213. serializedBuffer = buffer.join('').trim();
  214. ruleToken = ruleToken || [tokenTypeFrom(buffer), [], []];
  215. ruleToken[1].push([tokenScopeFrom(ruleToken[0]), serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext, ruleToken[1].length)]]);
  216. newTokens = ruleToken[2];
  217. allTokens.push(ruleToken);
  218. levels.push(level);
  219. level = Level.RULE;
  220. buffer = [];
  221. } else if (character == Marker.OPEN_CURLY_BRACKET && level == Level.RULE && seekingValue) {
  222. // open brace opening rule at rule level, e.g. div{--variable:{<--
  223. ruleTokens.push(ruleToken);
  224. ruleToken = [Token.PROPERTY_BLOCK, []];
  225. propertyToken.push(ruleToken);
  226. newTokens = ruleToken[1];
  227. levels.push(level);
  228. level = Level.RULE;
  229. seekingValue = false;
  230. } else if (character == Marker.OPEN_CURLY_BRACKET && level == Level.RULE && isPageMarginBox(buffer)) {
  231. // open brace opening page-margin box at rule level, e.g. @page{@top-center{<--
  232. serializedBuffer = buffer.join('').trim();
  233. ruleTokens.push(ruleToken);
  234. ruleToken = [Token.AT_RULE_BLOCK, [], []];
  235. ruleToken[1].push([Token.AT_RULE_BLOCK_SCOPE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  236. newTokens.push(ruleToken);
  237. newTokens = ruleToken[2];
  238. levels.push(level);
  239. level = Level.RULE;
  240. buffer = [];
  241. } else if (character == Marker.COLON && level == Level.RULE && !seekingValue) {
  242. // colon at rule level, e.g. a{color:<--
  243. serializedBuffer = buffer.join('').trim();
  244. propertyToken = [Token.PROPERTY, [Token.PROPERTY_NAME, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]];
  245. newTokens.push(propertyToken);
  246. seekingValue = true;
  247. buffer = [];
  248. } else if (character == Marker.SEMICOLON && level == Level.RULE && propertyToken && ruleTokens.length > 0 && buffer.length > 0 && buffer[0] == Marker.AT) {
  249. // semicolon at rule level for at-rule, e.g. a{--color:{@apply(--other-color);<--
  250. serializedBuffer = buffer.join('').trim();
  251. ruleToken[1].push([Token.AT_RULE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  252. buffer = [];
  253. } else if (character == Marker.SEMICOLON && level == Level.RULE && propertyToken && buffer.length > 0) {
  254. // semicolon at rule level, e.g. a{color:red;<--
  255. serializedBuffer = buffer.join('').trim();
  256. propertyToken.push([Token.PROPERTY_VALUE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  257. propertyToken = null;
  258. seekingValue = false;
  259. buffer = [];
  260. } else if (character == Marker.SEMICOLON && level == Level.RULE && propertyToken && buffer.length === 0) {
  261. // semicolon after bracketed value at rule level, e.g. a{color:rgb(...);<--
  262. propertyToken = null;
  263. seekingValue = false;
  264. } else if (character == Marker.SEMICOLON && level == Level.RULE && buffer.length > 0 && buffer[0] == Marker.AT) {
  265. // semicolon for at-rule at rule level, e.g. a{@apply(--variable);<--
  266. serializedBuffer = buffer.join('');
  267. newTokens.push([Token.AT_RULE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  268. seekingValue = false;
  269. buffer = [];
  270. } else if (character == Marker.SEMICOLON && level == Level.RULE && seekingPropertyBlockClosing) {
  271. // close brace after a property block at rule level, e.g. a{--custom:{color:red;};<--
  272. seekingPropertyBlockClosing = false;
  273. buffer = [];
  274. } else if (character == Marker.SEMICOLON && level == Level.RULE && buffer.length === 0) {
  275. // stray semicolon at rule level, e.g. a{;<--
  276. // noop
  277. } else if (character == Marker.CLOSE_CURLY_BRACKET && level == Level.RULE && propertyToken && seekingValue && buffer.length > 0 && ruleTokens.length > 0) {
  278. // close brace at rule level, e.g. a{--color:{color:red}<--
  279. serializedBuffer = buffer.join('');
  280. propertyToken.push([Token.PROPERTY_VALUE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  281. propertyToken = null;
  282. ruleToken = ruleTokens.pop();
  283. newTokens = ruleToken[2];
  284. level = levels.pop();
  285. seekingValue = false;
  286. buffer = [];
  287. } else if (character == Marker.CLOSE_CURLY_BRACKET && level == Level.RULE && propertyToken && buffer.length > 0 && buffer[0] == Marker.AT && ruleTokens.length > 0) {
  288. // close brace at rule level for at-rule, e.g. a{--color:{@apply(--other-color)}<--
  289. serializedBuffer = buffer.join('');
  290. ruleToken[1].push([Token.AT_RULE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  291. propertyToken = null;
  292. ruleToken = ruleTokens.pop();
  293. newTokens = ruleToken[2];
  294. level = levels.pop();
  295. seekingValue = false;
  296. buffer = [];
  297. } else if (character == Marker.CLOSE_CURLY_BRACKET && level == Level.RULE && propertyToken && ruleTokens.length > 0) {
  298. // close brace at rule level after space, e.g. a{--color:{color:red }<--
  299. propertyToken = null;
  300. ruleToken = ruleTokens.pop();
  301. newTokens = ruleToken[2];
  302. level = levels.pop();
  303. seekingValue = false;
  304. } else if (character == Marker.CLOSE_CURLY_BRACKET && level == Level.RULE && propertyToken && buffer.length > 0) {
  305. // close brace at rule level, e.g. a{color:red}<--
  306. serializedBuffer = buffer.join('');
  307. propertyToken.push([Token.PROPERTY_VALUE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  308. propertyToken = null;
  309. ruleToken = ruleTokens.pop();
  310. newTokens = allTokens;
  311. level = levels.pop();
  312. seekingValue = false;
  313. buffer = [];
  314. } else if (character == Marker.CLOSE_CURLY_BRACKET && level == Level.RULE && buffer.length > 0 && buffer[0] == Marker.AT) {
  315. // close brace after at-rule at rule level, e.g. a{@apply(--variable)}<--
  316. propertyToken = null;
  317. ruleToken = null;
  318. serializedBuffer = buffer.join('').trim();
  319. newTokens.push([Token.AT_RULE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  320. newTokens = allTokens;
  321. level = levels.pop();
  322. seekingValue = false;
  323. buffer = [];
  324. } else if (character == Marker.CLOSE_CURLY_BRACKET && level == Level.RULE && levels[levels.length - 1] == Level.RULE) {
  325. // close brace after a property block at rule level, e.g. a{--custom:{color:red;}<--
  326. propertyToken = null;
  327. ruleToken = ruleTokens.pop();
  328. newTokens = ruleToken[2];
  329. level = levels.pop();
  330. seekingValue = false;
  331. seekingPropertyBlockClosing = true;
  332. buffer = [];
  333. } else if (character == Marker.CLOSE_CURLY_BRACKET && level == Level.RULE) {
  334. // close brace after a rule, e.g. a{color:red;}<--
  335. propertyToken = null;
  336. ruleToken = null;
  337. newTokens = allTokens;
  338. level = levels.pop();
  339. seekingValue = false;
  340. } else if (character == Marker.CLOSE_CURLY_BRACKET && level == Level.BLOCK && !isNested && position.index <= source.length - 1) {
  341. // stray close brace at block level, e.g. a{color:red}color:blue}<--
  342. externalContext.warnings.push('Unexpected \'}\' at ' + formatPosition([position.line, position.column, position.source]) + '.');
  343. buffer.push(character);
  344. } else if (character == Marker.CLOSE_CURLY_BRACKET && level == Level.BLOCK) {
  345. // close brace at block level, e.g. @media screen {...}<--
  346. break;
  347. } else if (character == Marker.OPEN_ROUND_BRACKET && level == Level.RULE && seekingValue) {
  348. // round open bracket, e.g. a{color:hsla(<--
  349. buffer.push(character);
  350. roundBracketLevel++;
  351. } else if (character == Marker.CLOSE_ROUND_BRACKET && level == Level.RULE && seekingValue && roundBracketLevel == 1) {
  352. // round close bracket, e.g. a{color:hsla(0,0%,0%)<--
  353. buffer.push(character);
  354. serializedBuffer = buffer.join('').trim();
  355. propertyToken.push([Token.PROPERTY_VALUE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  356. roundBracketLevel--;
  357. buffer = [];
  358. } else if (character == Marker.CLOSE_ROUND_BRACKET && level == Level.RULE && seekingValue) {
  359. // round close bracket within other brackets, e.g. a{width:calc((10rem / 2)<--
  360. buffer.push(character);
  361. roundBracketLevel--;
  362. } else if (character == Marker.FORWARD_SLASH && source[position.index + 1] != Marker.ASTERISK && level == Level.RULE && seekingValue && buffer.length > 0) {
  363. // forward slash within a property, e.g. a{background:url(image.png) 0 0/<--
  364. serializedBuffer = buffer.join('').trim();
  365. propertyToken.push([Token.PROPERTY_VALUE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  366. propertyToken.push([Token.PROPERTY_VALUE, character, [[position.line, position.column, position.source]]]);
  367. buffer = [];
  368. } else if (character == Marker.FORWARD_SLASH && source[position.index + 1] != Marker.ASTERISK && level == Level.RULE && seekingValue) {
  369. // forward slash within a property after space, e.g. a{background:url(image.png) 0 0 /<--
  370. propertyToken.push([Token.PROPERTY_VALUE, character, [[position.line, position.column, position.source]]]);
  371. buffer = [];
  372. } else if (character == Marker.COMMA && level == Level.RULE && seekingValue && buffer.length > 0) {
  373. // comma within a property, e.g. a{background:url(image.png),<--
  374. serializedBuffer = buffer.join('').trim();
  375. propertyToken.push([Token.PROPERTY_VALUE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  376. propertyToken.push([Token.PROPERTY_VALUE, character, [[position.line, position.column, position.source]]]);
  377. buffer = [];
  378. } else if (character == Marker.COMMA && level == Level.RULE && seekingValue) {
  379. // comma within a property after space, e.g. a{background:url(image.png) ,<--
  380. propertyToken.push([Token.PROPERTY_VALUE, character, [[position.line, position.column, position.source]]]);
  381. buffer = [];
  382. } else if (character == Marker.CLOSE_SQUARE_BRACKET && propertyToken && propertyToken.length > 1 && buffer.length > 0 && isRepeatToken(buffer)) {
  383. buffer.push(character);
  384. serializedBuffer = buffer.join('').trim();
  385. propertyToken[propertyToken.length - 1][1] += serializedBuffer;
  386. buffer = [];
  387. } else if ((isSpace || (isNewLineNix && !isNewLineWin)) && level == Level.RULE && seekingValue && propertyToken && buffer.length > 0) {
  388. // space or *nix newline within property, e.g. a{margin:0 <--
  389. serializedBuffer = buffer.join('').trim();
  390. propertyToken.push([Token.PROPERTY_VALUE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  391. buffer = [];
  392. } else if (isNewLineWin && level == Level.RULE && seekingValue && propertyToken && buffer.length > 1) {
  393. // win newline within property, e.g. a{margin:0\r\n<--
  394. serializedBuffer = buffer.join('').trim();
  395. propertyToken.push([Token.PROPERTY_VALUE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  396. buffer = [];
  397. } else if (isNewLineWin && level == Level.RULE && seekingValue) {
  398. // win newline
  399. buffer = [];
  400. } else if (buffer.length == 1 && isNewLineWin) {
  401. // ignore windows newline which is composed of two characters
  402. buffer.pop();
  403. } else if (buffer.length > 0 || !isSpace && !isNewLineNix && !isNewLineWin) {
  404. // any character
  405. buffer.push(character);
  406. }
  407. wasEscaped = isEscaped;
  408. isEscaped = !wasEscaped && character == Marker.BACK_SLASH;
  409. wasCommentStart = isCommentStart;
  410. wasCommentEnd = isCommentEnd;
  411. position.line = (isNewLineWin || isNewLineNix) ? position.line + 1 : position.line;
  412. position.column = (isNewLineWin || isNewLineNix) ? 0 : position.column + 1;
  413. }
  414. if (seekingValue) {
  415. externalContext.warnings.push('Missing \'}\' at ' + formatPosition([position.line, position.column, position.source]) + '.');
  416. }
  417. if (seekingValue && buffer.length > 0) {
  418. serializedBuffer = buffer.join('').replace(TAIL_BROKEN_VALUE_PATTERN, '');
  419. propertyToken.push([Token.PROPERTY_VALUE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
  420. buffer = [];
  421. }
  422. if (buffer.length > 0) {
  423. externalContext.warnings.push('Invalid character(s) \'' + buffer.join('') + '\' at ' + formatPosition(metadata) + '. Ignoring.');
  424. }
  425. return allTokens;
  426. }
  427. function originalMetadata(metadata, value, externalContext, selectorFallbacks) {
  428. var source = metadata[2];
  429. return externalContext.inputSourceMapTracker.isTracking(source) ?
  430. externalContext.inputSourceMapTracker.originalPositionFor(metadata, value.length, selectorFallbacks) :
  431. metadata;
  432. }
  433. function tokenTypeFrom(buffer) {
  434. var isAtRule = buffer[0] == Marker.AT || buffer[0] == Marker.UNDERSCORE;
  435. var ruleWord = buffer.join('').split(RULE_WORD_SEPARATOR_PATTERN)[0];
  436. if (isAtRule && BLOCK_RULES.indexOf(ruleWord) > -1) {
  437. return Token.NESTED_BLOCK;
  438. } else if (isAtRule && AT_RULES.indexOf(ruleWord) > -1) {
  439. return Token.AT_RULE;
  440. } else if (isAtRule) {
  441. return Token.AT_RULE_BLOCK;
  442. } else {
  443. return Token.RULE;
  444. }
  445. }
  446. function tokenScopeFrom(tokenType) {
  447. if (tokenType == Token.RULE) {
  448. return Token.RULE_SCOPE;
  449. } else if (tokenType == Token.NESTED_BLOCK) {
  450. return Token.NESTED_BLOCK_SCOPE;
  451. } else if (tokenType == Token.AT_RULE_BLOCK) {
  452. return Token.AT_RULE_BLOCK_SCOPE;
  453. }
  454. }
  455. function isPageMarginBox(buffer) {
  456. var serializedBuffer = buffer.join('').trim();
  457. return PAGE_MARGIN_BOXES.indexOf(serializedBuffer) > -1 || EXTRA_PAGE_BOXES.indexOf(serializedBuffer) > -1;
  458. }
  459. function isRepeatToken(buffer) {
  460. return REPEAT_PATTERN.test(buffer.join('') + Marker.CLOSE_SQUARE_BRACKET);
  461. }
  462. module.exports = tokenize;