parser.js 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. "use strict";
  2. exports.__esModule = true;
  3. exports["default"] = void 0;
  4. var _root = _interopRequireDefault(require("./selectors/root"));
  5. var _selector = _interopRequireDefault(require("./selectors/selector"));
  6. var _className = _interopRequireDefault(require("./selectors/className"));
  7. var _comment = _interopRequireDefault(require("./selectors/comment"));
  8. var _id = _interopRequireDefault(require("./selectors/id"));
  9. var _tag = _interopRequireDefault(require("./selectors/tag"));
  10. var _string = _interopRequireDefault(require("./selectors/string"));
  11. var _pseudo = _interopRequireDefault(require("./selectors/pseudo"));
  12. var _attribute = _interopRequireWildcard(require("./selectors/attribute"));
  13. var _universal = _interopRequireDefault(require("./selectors/universal"));
  14. var _combinator = _interopRequireDefault(require("./selectors/combinator"));
  15. var _nesting = _interopRequireDefault(require("./selectors/nesting"));
  16. var _sortAscending = _interopRequireDefault(require("./sortAscending"));
  17. var _tokenize = _interopRequireWildcard(require("./tokenize"));
  18. var tokens = _interopRequireWildcard(require("./tokenTypes"));
  19. var types = _interopRequireWildcard(require("./selectors/types"));
  20. var _util = require("./util");
  21. var _WHITESPACE_TOKENS, _Object$assign;
  22. function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
  23. function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  24. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  25. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  26. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
  27. var WHITESPACE_TOKENS = (_WHITESPACE_TOKENS = {}, _WHITESPACE_TOKENS[tokens.space] = true, _WHITESPACE_TOKENS[tokens.cr] = true, _WHITESPACE_TOKENS[tokens.feed] = true, _WHITESPACE_TOKENS[tokens.newline] = true, _WHITESPACE_TOKENS[tokens.tab] = true, _WHITESPACE_TOKENS);
  28. var WHITESPACE_EQUIV_TOKENS = Object.assign({}, WHITESPACE_TOKENS, (_Object$assign = {}, _Object$assign[tokens.comment] = true, _Object$assign));
  29. function tokenStart(token) {
  30. return {
  31. line: token[_tokenize.FIELDS.START_LINE],
  32. column: token[_tokenize.FIELDS.START_COL]
  33. };
  34. }
  35. function tokenEnd(token) {
  36. return {
  37. line: token[_tokenize.FIELDS.END_LINE],
  38. column: token[_tokenize.FIELDS.END_COL]
  39. };
  40. }
  41. function getSource(startLine, startColumn, endLine, endColumn) {
  42. return {
  43. start: {
  44. line: startLine,
  45. column: startColumn
  46. },
  47. end: {
  48. line: endLine,
  49. column: endColumn
  50. }
  51. };
  52. }
  53. function getTokenSource(token) {
  54. return getSource(token[_tokenize.FIELDS.START_LINE], token[_tokenize.FIELDS.START_COL], token[_tokenize.FIELDS.END_LINE], token[_tokenize.FIELDS.END_COL]);
  55. }
  56. function getTokenSourceSpan(startToken, endToken) {
  57. if (!startToken) {
  58. return undefined;
  59. }
  60. return getSource(startToken[_tokenize.FIELDS.START_LINE], startToken[_tokenize.FIELDS.START_COL], endToken[_tokenize.FIELDS.END_LINE], endToken[_tokenize.FIELDS.END_COL]);
  61. }
  62. function unescapeProp(node, prop) {
  63. var value = node[prop];
  64. if (typeof value !== "string") {
  65. return;
  66. }
  67. if (value.indexOf("\\") !== -1) {
  68. (0, _util.ensureObject)(node, 'raws');
  69. node[prop] = (0, _util.unesc)(value);
  70. if (node.raws[prop] === undefined) {
  71. node.raws[prop] = value;
  72. }
  73. }
  74. return node;
  75. }
  76. function indexesOf(array, item) {
  77. var i = -1;
  78. var indexes = [];
  79. while ((i = array.indexOf(item, i + 1)) !== -1) {
  80. indexes.push(i);
  81. }
  82. return indexes;
  83. }
  84. function uniqs() {
  85. var list = Array.prototype.concat.apply([], arguments);
  86. return list.filter(function (item, i) {
  87. return i === list.indexOf(item);
  88. });
  89. }
  90. var Parser = /*#__PURE__*/function () {
  91. function Parser(rule, options) {
  92. if (options === void 0) {
  93. options = {};
  94. }
  95. this.rule = rule;
  96. this.options = Object.assign({
  97. lossy: false,
  98. safe: false
  99. }, options);
  100. this.position = 0;
  101. this.css = typeof this.rule === 'string' ? this.rule : this.rule.selector;
  102. this.tokens = (0, _tokenize["default"])({
  103. css: this.css,
  104. error: this._errorGenerator(),
  105. safe: this.options.safe
  106. });
  107. var rootSource = getTokenSourceSpan(this.tokens[0], this.tokens[this.tokens.length - 1]);
  108. this.root = new _root["default"]({
  109. source: rootSource
  110. });
  111. this.root.errorGenerator = this._errorGenerator();
  112. var selector = new _selector["default"]({
  113. source: {
  114. start: {
  115. line: 1,
  116. column: 1
  117. }
  118. },
  119. sourceIndex: 0
  120. });
  121. this.root.append(selector);
  122. this.current = selector;
  123. this.loop();
  124. }
  125. var _proto = Parser.prototype;
  126. _proto._errorGenerator = function _errorGenerator() {
  127. var _this = this;
  128. return function (message, errorOptions) {
  129. if (typeof _this.rule === 'string') {
  130. return new Error(message);
  131. }
  132. return _this.rule.error(message, errorOptions);
  133. };
  134. };
  135. _proto.attribute = function attribute() {
  136. var attr = [];
  137. var startingToken = this.currToken;
  138. this.position++;
  139. while (this.position < this.tokens.length && this.currToken[_tokenize.FIELDS.TYPE] !== tokens.closeSquare) {
  140. attr.push(this.currToken);
  141. this.position++;
  142. }
  143. if (this.currToken[_tokenize.FIELDS.TYPE] !== tokens.closeSquare) {
  144. return this.expected('closing square bracket', this.currToken[_tokenize.FIELDS.START_POS]);
  145. }
  146. var len = attr.length;
  147. var node = {
  148. source: getSource(startingToken[1], startingToken[2], this.currToken[3], this.currToken[4]),
  149. sourceIndex: startingToken[_tokenize.FIELDS.START_POS]
  150. };
  151. if (len === 1 && !~[tokens.word].indexOf(attr[0][_tokenize.FIELDS.TYPE])) {
  152. return this.expected('attribute', attr[0][_tokenize.FIELDS.START_POS]);
  153. }
  154. var pos = 0;
  155. var spaceBefore = '';
  156. var commentBefore = '';
  157. var lastAdded = null;
  158. var spaceAfterMeaningfulToken = false;
  159. while (pos < len) {
  160. var token = attr[pos];
  161. var content = this.content(token);
  162. var next = attr[pos + 1];
  163. switch (token[_tokenize.FIELDS.TYPE]) {
  164. case tokens.space:
  165. // if (
  166. // len === 1 ||
  167. // pos === 0 && this.content(next) === '|'
  168. // ) {
  169. // return this.expected('attribute', token[TOKEN.START_POS], content);
  170. // }
  171. spaceAfterMeaningfulToken = true;
  172. if (this.options.lossy) {
  173. break;
  174. }
  175. if (lastAdded) {
  176. (0, _util.ensureObject)(node, 'spaces', lastAdded);
  177. var prevContent = node.spaces[lastAdded].after || '';
  178. node.spaces[lastAdded].after = prevContent + content;
  179. var existingComment = (0, _util.getProp)(node, 'raws', 'spaces', lastAdded, 'after') || null;
  180. if (existingComment) {
  181. node.raws.spaces[lastAdded].after = existingComment + content;
  182. }
  183. } else {
  184. spaceBefore = spaceBefore + content;
  185. commentBefore = commentBefore + content;
  186. }
  187. break;
  188. case tokens.asterisk:
  189. if (next[_tokenize.FIELDS.TYPE] === tokens.equals) {
  190. node.operator = content;
  191. lastAdded = 'operator';
  192. } else if ((!node.namespace || lastAdded === "namespace" && !spaceAfterMeaningfulToken) && next) {
  193. if (spaceBefore) {
  194. (0, _util.ensureObject)(node, 'spaces', 'attribute');
  195. node.spaces.attribute.before = spaceBefore;
  196. spaceBefore = '';
  197. }
  198. if (commentBefore) {
  199. (0, _util.ensureObject)(node, 'raws', 'spaces', 'attribute');
  200. node.raws.spaces.attribute.before = spaceBefore;
  201. commentBefore = '';
  202. }
  203. node.namespace = (node.namespace || "") + content;
  204. var rawValue = (0, _util.getProp)(node, 'raws', 'namespace') || null;
  205. if (rawValue) {
  206. node.raws.namespace += content;
  207. }
  208. lastAdded = 'namespace';
  209. }
  210. spaceAfterMeaningfulToken = false;
  211. break;
  212. case tokens.dollar:
  213. if (lastAdded === "value") {
  214. var oldRawValue = (0, _util.getProp)(node, 'raws', 'value');
  215. node.value += "$";
  216. if (oldRawValue) {
  217. node.raws.value = oldRawValue + "$";
  218. }
  219. break;
  220. }
  221. // Falls through
  222. case tokens.caret:
  223. if (next[_tokenize.FIELDS.TYPE] === tokens.equals) {
  224. node.operator = content;
  225. lastAdded = 'operator';
  226. }
  227. spaceAfterMeaningfulToken = false;
  228. break;
  229. case tokens.combinator:
  230. if (content === '~' && next[_tokenize.FIELDS.TYPE] === tokens.equals) {
  231. node.operator = content;
  232. lastAdded = 'operator';
  233. }
  234. if (content !== '|') {
  235. spaceAfterMeaningfulToken = false;
  236. break;
  237. }
  238. if (next[_tokenize.FIELDS.TYPE] === tokens.equals) {
  239. node.operator = content;
  240. lastAdded = 'operator';
  241. } else if (!node.namespace && !node.attribute) {
  242. node.namespace = true;
  243. }
  244. spaceAfterMeaningfulToken = false;
  245. break;
  246. case tokens.word:
  247. if (next && this.content(next) === '|' && attr[pos + 2] && attr[pos + 2][_tokenize.FIELDS.TYPE] !== tokens.equals &&
  248. // this look-ahead probably fails with comment nodes involved.
  249. !node.operator && !node.namespace) {
  250. node.namespace = content;
  251. lastAdded = 'namespace';
  252. } else if (!node.attribute || lastAdded === "attribute" && !spaceAfterMeaningfulToken) {
  253. if (spaceBefore) {
  254. (0, _util.ensureObject)(node, 'spaces', 'attribute');
  255. node.spaces.attribute.before = spaceBefore;
  256. spaceBefore = '';
  257. }
  258. if (commentBefore) {
  259. (0, _util.ensureObject)(node, 'raws', 'spaces', 'attribute');
  260. node.raws.spaces.attribute.before = commentBefore;
  261. commentBefore = '';
  262. }
  263. node.attribute = (node.attribute || "") + content;
  264. var _rawValue = (0, _util.getProp)(node, 'raws', 'attribute') || null;
  265. if (_rawValue) {
  266. node.raws.attribute += content;
  267. }
  268. lastAdded = 'attribute';
  269. } else if (!node.value && node.value !== "" || lastAdded === "value" && !(spaceAfterMeaningfulToken || node.quoteMark)) {
  270. var _unescaped = (0, _util.unesc)(content);
  271. var _oldRawValue = (0, _util.getProp)(node, 'raws', 'value') || '';
  272. var oldValue = node.value || '';
  273. node.value = oldValue + _unescaped;
  274. node.quoteMark = null;
  275. if (_unescaped !== content || _oldRawValue) {
  276. (0, _util.ensureObject)(node, 'raws');
  277. node.raws.value = (_oldRawValue || oldValue) + content;
  278. }
  279. lastAdded = 'value';
  280. } else {
  281. var insensitive = content === 'i' || content === "I";
  282. if ((node.value || node.value === '') && (node.quoteMark || spaceAfterMeaningfulToken)) {
  283. node.insensitive = insensitive;
  284. if (!insensitive || content === "I") {
  285. (0, _util.ensureObject)(node, 'raws');
  286. node.raws.insensitiveFlag = content;
  287. }
  288. lastAdded = 'insensitive';
  289. if (spaceBefore) {
  290. (0, _util.ensureObject)(node, 'spaces', 'insensitive');
  291. node.spaces.insensitive.before = spaceBefore;
  292. spaceBefore = '';
  293. }
  294. if (commentBefore) {
  295. (0, _util.ensureObject)(node, 'raws', 'spaces', 'insensitive');
  296. node.raws.spaces.insensitive.before = commentBefore;
  297. commentBefore = '';
  298. }
  299. } else if (node.value || node.value === '') {
  300. lastAdded = 'value';
  301. node.value += content;
  302. if (node.raws.value) {
  303. node.raws.value += content;
  304. }
  305. }
  306. }
  307. spaceAfterMeaningfulToken = false;
  308. break;
  309. case tokens.str:
  310. if (!node.attribute || !node.operator) {
  311. return this.error("Expected an attribute followed by an operator preceding the string.", {
  312. index: token[_tokenize.FIELDS.START_POS]
  313. });
  314. }
  315. var _unescapeValue = (0, _attribute.unescapeValue)(content),
  316. unescaped = _unescapeValue.unescaped,
  317. quoteMark = _unescapeValue.quoteMark;
  318. node.value = unescaped;
  319. node.quoteMark = quoteMark;
  320. lastAdded = 'value';
  321. (0, _util.ensureObject)(node, 'raws');
  322. node.raws.value = content;
  323. spaceAfterMeaningfulToken = false;
  324. break;
  325. case tokens.equals:
  326. if (!node.attribute) {
  327. return this.expected('attribute', token[_tokenize.FIELDS.START_POS], content);
  328. }
  329. if (node.value) {
  330. return this.error('Unexpected "=" found; an operator was already defined.', {
  331. index: token[_tokenize.FIELDS.START_POS]
  332. });
  333. }
  334. node.operator = node.operator ? node.operator + content : content;
  335. lastAdded = 'operator';
  336. spaceAfterMeaningfulToken = false;
  337. break;
  338. case tokens.comment:
  339. if (lastAdded) {
  340. if (spaceAfterMeaningfulToken || next && next[_tokenize.FIELDS.TYPE] === tokens.space || lastAdded === 'insensitive') {
  341. var lastComment = (0, _util.getProp)(node, 'spaces', lastAdded, 'after') || '';
  342. var rawLastComment = (0, _util.getProp)(node, 'raws', 'spaces', lastAdded, 'after') || lastComment;
  343. (0, _util.ensureObject)(node, 'raws', 'spaces', lastAdded);
  344. node.raws.spaces[lastAdded].after = rawLastComment + content;
  345. } else {
  346. var lastValue = node[lastAdded] || '';
  347. var rawLastValue = (0, _util.getProp)(node, 'raws', lastAdded) || lastValue;
  348. (0, _util.ensureObject)(node, 'raws');
  349. node.raws[lastAdded] = rawLastValue + content;
  350. }
  351. } else {
  352. commentBefore = commentBefore + content;
  353. }
  354. break;
  355. default:
  356. return this.error("Unexpected \"" + content + "\" found.", {
  357. index: token[_tokenize.FIELDS.START_POS]
  358. });
  359. }
  360. pos++;
  361. }
  362. unescapeProp(node, "attribute");
  363. unescapeProp(node, "namespace");
  364. this.newNode(new _attribute["default"](node));
  365. this.position++;
  366. }
  367. /**
  368. * return a node containing meaningless garbage up to (but not including) the specified token position.
  369. * if the token position is negative, all remaining tokens are consumed.
  370. *
  371. * This returns an array containing a single string node if all whitespace,
  372. * otherwise an array of comment nodes with space before and after.
  373. *
  374. * These tokens are not added to the current selector, the caller can add them or use them to amend
  375. * a previous node's space metadata.
  376. *
  377. * In lossy mode, this returns only comments.
  378. */;
  379. _proto.parseWhitespaceEquivalentTokens = function parseWhitespaceEquivalentTokens(stopPosition) {
  380. if (stopPosition < 0) {
  381. stopPosition = this.tokens.length;
  382. }
  383. var startPosition = this.position;
  384. var nodes = [];
  385. var space = "";
  386. var lastComment = undefined;
  387. do {
  388. if (WHITESPACE_TOKENS[this.currToken[_tokenize.FIELDS.TYPE]]) {
  389. if (!this.options.lossy) {
  390. space += this.content();
  391. }
  392. } else if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.comment) {
  393. var spaces = {};
  394. if (space) {
  395. spaces.before = space;
  396. space = "";
  397. }
  398. lastComment = new _comment["default"]({
  399. value: this.content(),
  400. source: getTokenSource(this.currToken),
  401. sourceIndex: this.currToken[_tokenize.FIELDS.START_POS],
  402. spaces: spaces
  403. });
  404. nodes.push(lastComment);
  405. }
  406. } while (++this.position < stopPosition);
  407. if (space) {
  408. if (lastComment) {
  409. lastComment.spaces.after = space;
  410. } else if (!this.options.lossy) {
  411. var firstToken = this.tokens[startPosition];
  412. var lastToken = this.tokens[this.position - 1];
  413. nodes.push(new _string["default"]({
  414. value: '',
  415. source: getSource(firstToken[_tokenize.FIELDS.START_LINE], firstToken[_tokenize.FIELDS.START_COL], lastToken[_tokenize.FIELDS.END_LINE], lastToken[_tokenize.FIELDS.END_COL]),
  416. sourceIndex: firstToken[_tokenize.FIELDS.START_POS],
  417. spaces: {
  418. before: space,
  419. after: ''
  420. }
  421. }));
  422. }
  423. }
  424. return nodes;
  425. }
  426. /**
  427. *
  428. * @param {*} nodes
  429. */;
  430. _proto.convertWhitespaceNodesToSpace = function convertWhitespaceNodesToSpace(nodes, requiredSpace) {
  431. var _this2 = this;
  432. if (requiredSpace === void 0) {
  433. requiredSpace = false;
  434. }
  435. var space = "";
  436. var rawSpace = "";
  437. nodes.forEach(function (n) {
  438. var spaceBefore = _this2.lossySpace(n.spaces.before, requiredSpace);
  439. var rawSpaceBefore = _this2.lossySpace(n.rawSpaceBefore, requiredSpace);
  440. space += spaceBefore + _this2.lossySpace(n.spaces.after, requiredSpace && spaceBefore.length === 0);
  441. rawSpace += spaceBefore + n.value + _this2.lossySpace(n.rawSpaceAfter, requiredSpace && rawSpaceBefore.length === 0);
  442. });
  443. if (rawSpace === space) {
  444. rawSpace = undefined;
  445. }
  446. var result = {
  447. space: space,
  448. rawSpace: rawSpace
  449. };
  450. return result;
  451. };
  452. _proto.isNamedCombinator = function isNamedCombinator(position) {
  453. if (position === void 0) {
  454. position = this.position;
  455. }
  456. return this.tokens[position + 0] && this.tokens[position + 0][_tokenize.FIELDS.TYPE] === tokens.slash && this.tokens[position + 1] && this.tokens[position + 1][_tokenize.FIELDS.TYPE] === tokens.word && this.tokens[position + 2] && this.tokens[position + 2][_tokenize.FIELDS.TYPE] === tokens.slash;
  457. };
  458. _proto.namedCombinator = function namedCombinator() {
  459. if (this.isNamedCombinator()) {
  460. var nameRaw = this.content(this.tokens[this.position + 1]);
  461. var name = (0, _util.unesc)(nameRaw).toLowerCase();
  462. var raws = {};
  463. if (name !== nameRaw) {
  464. raws.value = "/" + nameRaw + "/";
  465. }
  466. var node = new _combinator["default"]({
  467. value: "/" + name + "/",
  468. source: getSource(this.currToken[_tokenize.FIELDS.START_LINE], this.currToken[_tokenize.FIELDS.START_COL], this.tokens[this.position + 2][_tokenize.FIELDS.END_LINE], this.tokens[this.position + 2][_tokenize.FIELDS.END_COL]),
  469. sourceIndex: this.currToken[_tokenize.FIELDS.START_POS],
  470. raws: raws
  471. });
  472. this.position = this.position + 3;
  473. return node;
  474. } else {
  475. this.unexpected();
  476. }
  477. };
  478. _proto.combinator = function combinator() {
  479. var _this3 = this;
  480. if (this.content() === '|') {
  481. return this.namespace();
  482. }
  483. // We need to decide between a space that's a descendant combinator and meaningless whitespace at the end of a selector.
  484. var nextSigTokenPos = this.locateNextMeaningfulToken(this.position);
  485. if (nextSigTokenPos < 0 || this.tokens[nextSigTokenPos][_tokenize.FIELDS.TYPE] === tokens.comma || this.tokens[nextSigTokenPos][_tokenize.FIELDS.TYPE] === tokens.closeParenthesis) {
  486. var nodes = this.parseWhitespaceEquivalentTokens(nextSigTokenPos);
  487. if (nodes.length > 0) {
  488. var last = this.current.last;
  489. if (last) {
  490. var _this$convertWhitespa = this.convertWhitespaceNodesToSpace(nodes),
  491. space = _this$convertWhitespa.space,
  492. rawSpace = _this$convertWhitespa.rawSpace;
  493. if (rawSpace !== undefined) {
  494. last.rawSpaceAfter += rawSpace;
  495. }
  496. last.spaces.after += space;
  497. } else {
  498. nodes.forEach(function (n) {
  499. return _this3.newNode(n);
  500. });
  501. }
  502. }
  503. return;
  504. }
  505. var firstToken = this.currToken;
  506. var spaceOrDescendantSelectorNodes = undefined;
  507. if (nextSigTokenPos > this.position) {
  508. spaceOrDescendantSelectorNodes = this.parseWhitespaceEquivalentTokens(nextSigTokenPos);
  509. }
  510. var node;
  511. if (this.isNamedCombinator()) {
  512. node = this.namedCombinator();
  513. } else if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.combinator) {
  514. node = new _combinator["default"]({
  515. value: this.content(),
  516. source: getTokenSource(this.currToken),
  517. sourceIndex: this.currToken[_tokenize.FIELDS.START_POS]
  518. });
  519. this.position++;
  520. } else if (WHITESPACE_TOKENS[this.currToken[_tokenize.FIELDS.TYPE]]) {
  521. // pass
  522. } else if (!spaceOrDescendantSelectorNodes) {
  523. this.unexpected();
  524. }
  525. if (node) {
  526. if (spaceOrDescendantSelectorNodes) {
  527. var _this$convertWhitespa2 = this.convertWhitespaceNodesToSpace(spaceOrDescendantSelectorNodes),
  528. _space = _this$convertWhitespa2.space,
  529. _rawSpace = _this$convertWhitespa2.rawSpace;
  530. node.spaces.before = _space;
  531. node.rawSpaceBefore = _rawSpace;
  532. }
  533. } else {
  534. // descendant combinator
  535. var _this$convertWhitespa3 = this.convertWhitespaceNodesToSpace(spaceOrDescendantSelectorNodes, true),
  536. _space2 = _this$convertWhitespa3.space,
  537. _rawSpace2 = _this$convertWhitespa3.rawSpace;
  538. if (!_rawSpace2) {
  539. _rawSpace2 = _space2;
  540. }
  541. var spaces = {};
  542. var raws = {
  543. spaces: {}
  544. };
  545. if (_space2.endsWith(' ') && _rawSpace2.endsWith(' ')) {
  546. spaces.before = _space2.slice(0, _space2.length - 1);
  547. raws.spaces.before = _rawSpace2.slice(0, _rawSpace2.length - 1);
  548. } else if (_space2.startsWith(' ') && _rawSpace2.startsWith(' ')) {
  549. spaces.after = _space2.slice(1);
  550. raws.spaces.after = _rawSpace2.slice(1);
  551. } else {
  552. raws.value = _rawSpace2;
  553. }
  554. node = new _combinator["default"]({
  555. value: ' ',
  556. source: getTokenSourceSpan(firstToken, this.tokens[this.position - 1]),
  557. sourceIndex: firstToken[_tokenize.FIELDS.START_POS],
  558. spaces: spaces,
  559. raws: raws
  560. });
  561. }
  562. if (this.currToken && this.currToken[_tokenize.FIELDS.TYPE] === tokens.space) {
  563. node.spaces.after = this.optionalSpace(this.content());
  564. this.position++;
  565. }
  566. return this.newNode(node);
  567. };
  568. _proto.comma = function comma() {
  569. if (this.position === this.tokens.length - 1) {
  570. this.root.trailingComma = true;
  571. this.position++;
  572. return;
  573. }
  574. this.current._inferEndPosition();
  575. var selector = new _selector["default"]({
  576. source: {
  577. start: tokenStart(this.tokens[this.position + 1])
  578. },
  579. sourceIndex: this.tokens[this.position + 1][_tokenize.FIELDS.START_POS]
  580. });
  581. this.current.parent.append(selector);
  582. this.current = selector;
  583. this.position++;
  584. };
  585. _proto.comment = function comment() {
  586. var current = this.currToken;
  587. this.newNode(new _comment["default"]({
  588. value: this.content(),
  589. source: getTokenSource(current),
  590. sourceIndex: current[_tokenize.FIELDS.START_POS]
  591. }));
  592. this.position++;
  593. };
  594. _proto.error = function error(message, opts) {
  595. throw this.root.error(message, opts);
  596. };
  597. _proto.missingBackslash = function missingBackslash() {
  598. return this.error('Expected a backslash preceding the semicolon.', {
  599. index: this.currToken[_tokenize.FIELDS.START_POS]
  600. });
  601. };
  602. _proto.missingParenthesis = function missingParenthesis() {
  603. return this.expected('opening parenthesis', this.currToken[_tokenize.FIELDS.START_POS]);
  604. };
  605. _proto.missingSquareBracket = function missingSquareBracket() {
  606. return this.expected('opening square bracket', this.currToken[_tokenize.FIELDS.START_POS]);
  607. };
  608. _proto.unexpected = function unexpected() {
  609. return this.error("Unexpected '" + this.content() + "'. Escaping special characters with \\ may help.", this.currToken[_tokenize.FIELDS.START_POS]);
  610. };
  611. _proto.unexpectedPipe = function unexpectedPipe() {
  612. return this.error("Unexpected '|'.", this.currToken[_tokenize.FIELDS.START_POS]);
  613. };
  614. _proto.namespace = function namespace() {
  615. var before = this.prevToken && this.content(this.prevToken) || true;
  616. if (this.nextToken[_tokenize.FIELDS.TYPE] === tokens.word) {
  617. this.position++;
  618. return this.word(before);
  619. } else if (this.nextToken[_tokenize.FIELDS.TYPE] === tokens.asterisk) {
  620. this.position++;
  621. return this.universal(before);
  622. }
  623. this.unexpectedPipe();
  624. };
  625. _proto.nesting = function nesting() {
  626. if (this.nextToken) {
  627. var nextContent = this.content(this.nextToken);
  628. if (nextContent === "|") {
  629. this.position++;
  630. return;
  631. }
  632. }
  633. var current = this.currToken;
  634. this.newNode(new _nesting["default"]({
  635. value: this.content(),
  636. source: getTokenSource(current),
  637. sourceIndex: current[_tokenize.FIELDS.START_POS]
  638. }));
  639. this.position++;
  640. };
  641. _proto.parentheses = function parentheses() {
  642. var last = this.current.last;
  643. var unbalanced = 1;
  644. this.position++;
  645. if (last && last.type === types.PSEUDO) {
  646. var selector = new _selector["default"]({
  647. source: {
  648. start: tokenStart(this.tokens[this.position])
  649. },
  650. sourceIndex: this.tokens[this.position][_tokenize.FIELDS.START_POS]
  651. });
  652. var cache = this.current;
  653. last.append(selector);
  654. this.current = selector;
  655. while (this.position < this.tokens.length && unbalanced) {
  656. if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.openParenthesis) {
  657. unbalanced++;
  658. }
  659. if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.closeParenthesis) {
  660. unbalanced--;
  661. }
  662. if (unbalanced) {
  663. this.parse();
  664. } else {
  665. this.current.source.end = tokenEnd(this.currToken);
  666. this.current.parent.source.end = tokenEnd(this.currToken);
  667. this.position++;
  668. }
  669. }
  670. this.current = cache;
  671. } else {
  672. // I think this case should be an error. It's used to implement a basic parse of media queries
  673. // but I don't think it's a good idea.
  674. var parenStart = this.currToken;
  675. var parenValue = "(";
  676. var parenEnd;
  677. while (this.position < this.tokens.length && unbalanced) {
  678. if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.openParenthesis) {
  679. unbalanced++;
  680. }
  681. if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.closeParenthesis) {
  682. unbalanced--;
  683. }
  684. parenEnd = this.currToken;
  685. parenValue += this.parseParenthesisToken(this.currToken);
  686. this.position++;
  687. }
  688. if (last) {
  689. last.appendToPropertyAndEscape("value", parenValue, parenValue);
  690. } else {
  691. this.newNode(new _string["default"]({
  692. value: parenValue,
  693. source: getSource(parenStart[_tokenize.FIELDS.START_LINE], parenStart[_tokenize.FIELDS.START_COL], parenEnd[_tokenize.FIELDS.END_LINE], parenEnd[_tokenize.FIELDS.END_COL]),
  694. sourceIndex: parenStart[_tokenize.FIELDS.START_POS]
  695. }));
  696. }
  697. }
  698. if (unbalanced) {
  699. return this.expected('closing parenthesis', this.currToken[_tokenize.FIELDS.START_POS]);
  700. }
  701. };
  702. _proto.pseudo = function pseudo() {
  703. var _this4 = this;
  704. var pseudoStr = '';
  705. var startingToken = this.currToken;
  706. while (this.currToken && this.currToken[_tokenize.FIELDS.TYPE] === tokens.colon) {
  707. pseudoStr += this.content();
  708. this.position++;
  709. }
  710. if (!this.currToken) {
  711. return this.expected(['pseudo-class', 'pseudo-element'], this.position - 1);
  712. }
  713. if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.word) {
  714. this.splitWord(false, function (first, length) {
  715. pseudoStr += first;
  716. _this4.newNode(new _pseudo["default"]({
  717. value: pseudoStr,
  718. source: getTokenSourceSpan(startingToken, _this4.currToken),
  719. sourceIndex: startingToken[_tokenize.FIELDS.START_POS]
  720. }));
  721. if (length > 1 && _this4.nextToken && _this4.nextToken[_tokenize.FIELDS.TYPE] === tokens.openParenthesis) {
  722. _this4.error('Misplaced parenthesis.', {
  723. index: _this4.nextToken[_tokenize.FIELDS.START_POS]
  724. });
  725. }
  726. });
  727. } else {
  728. return this.expected(['pseudo-class', 'pseudo-element'], this.currToken[_tokenize.FIELDS.START_POS]);
  729. }
  730. };
  731. _proto.space = function space() {
  732. var content = this.content();
  733. // Handle space before and after the selector
  734. if (this.position === 0 || this.prevToken[_tokenize.FIELDS.TYPE] === tokens.comma || this.prevToken[_tokenize.FIELDS.TYPE] === tokens.openParenthesis || this.current.nodes.every(function (node) {
  735. return node.type === 'comment';
  736. })) {
  737. this.spaces = this.optionalSpace(content);
  738. this.position++;
  739. } else if (this.position === this.tokens.length - 1 || this.nextToken[_tokenize.FIELDS.TYPE] === tokens.comma || this.nextToken[_tokenize.FIELDS.TYPE] === tokens.closeParenthesis) {
  740. this.current.last.spaces.after = this.optionalSpace(content);
  741. this.position++;
  742. } else {
  743. this.combinator();
  744. }
  745. };
  746. _proto.string = function string() {
  747. var current = this.currToken;
  748. this.newNode(new _string["default"]({
  749. value: this.content(),
  750. source: getTokenSource(current),
  751. sourceIndex: current[_tokenize.FIELDS.START_POS]
  752. }));
  753. this.position++;
  754. };
  755. _proto.universal = function universal(namespace) {
  756. var nextToken = this.nextToken;
  757. if (nextToken && this.content(nextToken) === '|') {
  758. this.position++;
  759. return this.namespace();
  760. }
  761. var current = this.currToken;
  762. this.newNode(new _universal["default"]({
  763. value: this.content(),
  764. source: getTokenSource(current),
  765. sourceIndex: current[_tokenize.FIELDS.START_POS]
  766. }), namespace);
  767. this.position++;
  768. };
  769. _proto.splitWord = function splitWord(namespace, firstCallback) {
  770. var _this5 = this;
  771. var nextToken = this.nextToken;
  772. var word = this.content();
  773. while (nextToken && ~[tokens.dollar, tokens.caret, tokens.equals, tokens.word].indexOf(nextToken[_tokenize.FIELDS.TYPE])) {
  774. this.position++;
  775. var current = this.content();
  776. word += current;
  777. if (current.lastIndexOf('\\') === current.length - 1) {
  778. var next = this.nextToken;
  779. if (next && next[_tokenize.FIELDS.TYPE] === tokens.space) {
  780. word += this.requiredSpace(this.content(next));
  781. this.position++;
  782. }
  783. }
  784. nextToken = this.nextToken;
  785. }
  786. var hasClass = indexesOf(word, '.').filter(function (i) {
  787. // Allow escaped dot within class name
  788. var escapedDot = word[i - 1] === '\\';
  789. // Allow decimal numbers percent in @keyframes
  790. var isKeyframesPercent = /^\d+\.\d+%$/.test(word);
  791. return !escapedDot && !isKeyframesPercent;
  792. });
  793. var hasId = indexesOf(word, '#').filter(function (i) {
  794. return word[i - 1] !== '\\';
  795. });
  796. // Eliminate Sass interpolations from the list of id indexes
  797. var interpolations = indexesOf(word, '#{');
  798. if (interpolations.length) {
  799. hasId = hasId.filter(function (hashIndex) {
  800. return !~interpolations.indexOf(hashIndex);
  801. });
  802. }
  803. var indices = (0, _sortAscending["default"])(uniqs([0].concat(hasClass, hasId)));
  804. indices.forEach(function (ind, i) {
  805. var index = indices[i + 1] || word.length;
  806. var value = word.slice(ind, index);
  807. if (i === 0 && firstCallback) {
  808. return firstCallback.call(_this5, value, indices.length);
  809. }
  810. var node;
  811. var current = _this5.currToken;
  812. var sourceIndex = current[_tokenize.FIELDS.START_POS] + indices[i];
  813. var source = getSource(current[1], current[2] + ind, current[3], current[2] + (index - 1));
  814. if (~hasClass.indexOf(ind)) {
  815. var classNameOpts = {
  816. value: value.slice(1),
  817. source: source,
  818. sourceIndex: sourceIndex
  819. };
  820. node = new _className["default"](unescapeProp(classNameOpts, "value"));
  821. } else if (~hasId.indexOf(ind)) {
  822. var idOpts = {
  823. value: value.slice(1),
  824. source: source,
  825. sourceIndex: sourceIndex
  826. };
  827. node = new _id["default"](unescapeProp(idOpts, "value"));
  828. } else {
  829. var tagOpts = {
  830. value: value,
  831. source: source,
  832. sourceIndex: sourceIndex
  833. };
  834. unescapeProp(tagOpts, "value");
  835. node = new _tag["default"](tagOpts);
  836. }
  837. _this5.newNode(node, namespace);
  838. // Ensure that the namespace is used only once
  839. namespace = null;
  840. });
  841. this.position++;
  842. };
  843. _proto.word = function word(namespace) {
  844. var nextToken = this.nextToken;
  845. if (nextToken && this.content(nextToken) === '|') {
  846. this.position++;
  847. return this.namespace();
  848. }
  849. return this.splitWord(namespace);
  850. };
  851. _proto.loop = function loop() {
  852. while (this.position < this.tokens.length) {
  853. this.parse(true);
  854. }
  855. this.current._inferEndPosition();
  856. return this.root;
  857. };
  858. _proto.parse = function parse(throwOnParenthesis) {
  859. switch (this.currToken[_tokenize.FIELDS.TYPE]) {
  860. case tokens.space:
  861. this.space();
  862. break;
  863. case tokens.comment:
  864. this.comment();
  865. break;
  866. case tokens.openParenthesis:
  867. this.parentheses();
  868. break;
  869. case tokens.closeParenthesis:
  870. if (throwOnParenthesis) {
  871. this.missingParenthesis();
  872. }
  873. break;
  874. case tokens.openSquare:
  875. this.attribute();
  876. break;
  877. case tokens.dollar:
  878. case tokens.caret:
  879. case tokens.equals:
  880. case tokens.word:
  881. this.word();
  882. break;
  883. case tokens.colon:
  884. this.pseudo();
  885. break;
  886. case tokens.comma:
  887. this.comma();
  888. break;
  889. case tokens.asterisk:
  890. this.universal();
  891. break;
  892. case tokens.ampersand:
  893. this.nesting();
  894. break;
  895. case tokens.slash:
  896. case tokens.combinator:
  897. this.combinator();
  898. break;
  899. case tokens.str:
  900. this.string();
  901. break;
  902. // These cases throw; no break needed.
  903. case tokens.closeSquare:
  904. this.missingSquareBracket();
  905. case tokens.semicolon:
  906. this.missingBackslash();
  907. default:
  908. this.unexpected();
  909. }
  910. }
  911. /**
  912. * Helpers
  913. */;
  914. _proto.expected = function expected(description, index, found) {
  915. if (Array.isArray(description)) {
  916. var last = description.pop();
  917. description = description.join(', ') + " or " + last;
  918. }
  919. var an = /^[aeiou]/.test(description[0]) ? 'an' : 'a';
  920. if (!found) {
  921. return this.error("Expected " + an + " " + description + ".", {
  922. index: index
  923. });
  924. }
  925. return this.error("Expected " + an + " " + description + ", found \"" + found + "\" instead.", {
  926. index: index
  927. });
  928. };
  929. _proto.requiredSpace = function requiredSpace(space) {
  930. return this.options.lossy ? ' ' : space;
  931. };
  932. _proto.optionalSpace = function optionalSpace(space) {
  933. return this.options.lossy ? '' : space;
  934. };
  935. _proto.lossySpace = function lossySpace(space, required) {
  936. if (this.options.lossy) {
  937. return required ? ' ' : '';
  938. } else {
  939. return space;
  940. }
  941. };
  942. _proto.parseParenthesisToken = function parseParenthesisToken(token) {
  943. var content = this.content(token);
  944. if (token[_tokenize.FIELDS.TYPE] === tokens.space) {
  945. return this.requiredSpace(content);
  946. } else {
  947. return content;
  948. }
  949. };
  950. _proto.newNode = function newNode(node, namespace) {
  951. if (namespace) {
  952. if (/^ +$/.test(namespace)) {
  953. if (!this.options.lossy) {
  954. this.spaces = (this.spaces || '') + namespace;
  955. }
  956. namespace = true;
  957. }
  958. node.namespace = namespace;
  959. unescapeProp(node, "namespace");
  960. }
  961. if (this.spaces) {
  962. node.spaces.before = this.spaces;
  963. this.spaces = '';
  964. }
  965. return this.current.append(node);
  966. };
  967. _proto.content = function content(token) {
  968. if (token === void 0) {
  969. token = this.currToken;
  970. }
  971. return this.css.slice(token[_tokenize.FIELDS.START_POS], token[_tokenize.FIELDS.END_POS]);
  972. };
  973. /**
  974. * returns the index of the next non-whitespace, non-comment token.
  975. * returns -1 if no meaningful token is found.
  976. */
  977. _proto.locateNextMeaningfulToken = function locateNextMeaningfulToken(startPosition) {
  978. if (startPosition === void 0) {
  979. startPosition = this.position + 1;
  980. }
  981. var searchPosition = startPosition;
  982. while (searchPosition < this.tokens.length) {
  983. if (WHITESPACE_EQUIV_TOKENS[this.tokens[searchPosition][_tokenize.FIELDS.TYPE]]) {
  984. searchPosition++;
  985. continue;
  986. } else {
  987. return searchPosition;
  988. }
  989. }
  990. return -1;
  991. };
  992. _createClass(Parser, [{
  993. key: "currToken",
  994. get: function get() {
  995. return this.tokens[this.position];
  996. }
  997. }, {
  998. key: "nextToken",
  999. get: function get() {
  1000. return this.tokens[this.position + 1];
  1001. }
  1002. }, {
  1003. key: "prevToken",
  1004. get: function get() {
  1005. return this.tokens[this.position - 1];
  1006. }
  1007. }]);
  1008. return Parser;
  1009. }();
  1010. exports["default"] = Parser;
  1011. module.exports = exports.default;