web 3d图形渲染器
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.

1224 lines
37 KiB

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