UNPKG

motion

Version:

motion - moving development forward

558 lines (509 loc) 20.3 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _createClass = (function () { 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } var _selectorsRoot = require('./selectors/root'); var _selectorsRoot2 = _interopRequireDefault(_selectorsRoot); var _selectorsSelector = require('./selectors/selector'); var _selectorsSelector2 = _interopRequireDefault(_selectorsSelector); var _selectorsClassName = require('./selectors/className'); var _selectorsClassName2 = _interopRequireDefault(_selectorsClassName); var _selectorsComment = require('./selectors/comment'); var _selectorsComment2 = _interopRequireDefault(_selectorsComment); var _selectorsId = require('./selectors/id'); var _selectorsId2 = _interopRequireDefault(_selectorsId); var _selectorsTag = require('./selectors/tag'); var _selectorsTag2 = _interopRequireDefault(_selectorsTag); var _selectorsString = require('./selectors/string'); var _selectorsString2 = _interopRequireDefault(_selectorsString); var _selectorsPseudo = require('./selectors/pseudo'); var _selectorsPseudo2 = _interopRequireDefault(_selectorsPseudo); var _selectorsAttribute = require('./selectors/attribute'); var _selectorsAttribute2 = _interopRequireDefault(_selectorsAttribute); var _selectorsUniversal = require('./selectors/universal'); var _selectorsUniversal2 = _interopRequireDefault(_selectorsUniversal); var _selectorsCombinator = require('./selectors/combinator'); var _selectorsCombinator2 = _interopRequireDefault(_selectorsCombinator); var _sortAscending = require('./sortAscending'); var _sortAscending2 = _interopRequireDefault(_sortAscending); var _tokenize = require('./tokenize'); var _tokenize2 = _interopRequireDefault(_tokenize); var _flatten = require('flatten'); var _flatten2 = _interopRequireDefault(_flatten); var _indexesOf = require('indexes-of'); var _indexesOf2 = _interopRequireDefault(_indexesOf); var _uniq = require('uniq'); var _uniq2 = _interopRequireDefault(_uniq); var Parser = (function () { function Parser(input) { _classCallCheck(this, Parser); this.input = input; this.position = 0; this.root = new _selectorsRoot2['default'](); var selectors = new _selectorsSelector2['default'](); this.root.append(selectors); this.current = selectors; this.tokens = (0, _tokenize2['default'])(input); return this.loop(); } _createClass(Parser, [{ key: 'attribute', value: function attribute() { var attribute = ''; var attr = undefined; var startingToken = this.currToken; this.position++; while (this.position < this.tokens.length && this.currToken[0] !== ']') { attribute += this.tokens[this.position][1]; this.position++; } if (this.position === this.tokens.length && ! ~attribute.indexOf(']')) { this.error('Expected a closing square bracket.'); } var parts = attribute.split(/((?:[*~^$|]?)=)/); var namespace = parts[0].split(/(\|)/g); var attributeProps = { operator: parts[1], value: parts[2], source: { start: { line: startingToken[2], column: startingToken[3] }, end: { line: this.currToken[2], column: this.currToken[3] } }, sourceIndex: startingToken[4] }; if (namespace.length > 1) { if (namespace[0] === '') { namespace[0] = true; } attributeProps.attribute = namespace[2]; attributeProps.namespace = namespace[0]; } else { attributeProps.attribute = parts[0]; } attr = new _selectorsAttribute2['default'](attributeProps); if (parts[2]) { var insensitive = parts[2].split(/(\s+i\s*?)$/); attr.value = insensitive[0]; if (insensitive[1]) { attr.insensitive = true; attr.raw.insensitive = insensitive[1]; } } this.newNode(attr); this.position++; } }, { key: 'combinator', value: function combinator() { if (this.currToken[1] === '|') { return this.namespace(); } var combinator = new _selectorsCombinator2['default']({ value: '', source: { start: { line: this.currToken[2], column: this.currToken[3] }, end: { line: this.currToken[2], column: this.currToken[3] } }, sourceIndex: this.currToken[4] }); while (this.position < this.tokens.length && this.currToken && (this.currToken[0] === 'space' || this.currToken[0] === 'combinator')) { if (this.nextToken && this.nextToken[0] === 'combinator') { combinator.spaces.before = this.currToken[1]; combinator.source.start.line = this.nextToken[2]; combinator.source.start.column = this.nextToken[3]; combinator.source.end.column = this.nextToken[3]; combinator.source.end.line = this.nextToken[2]; combinator.sourceIndex = this.nextToken[4]; } else if (this.prevToken && this.prevToken[0] === 'combinator') { combinator.spaces.after = this.currToken[1]; } else if (this.currToken[0] === 'space' || this.currToken[0] === 'combinator') { combinator.value = this.currToken[1]; } this.position++; } return this.newNode(combinator); } }, { key: 'comma', value: function comma() { if (this.position === this.tokens.length - 1) { this.root.trailingComma = true; this.position++; return; } var selectors = new _selectorsSelector2['default'](); this.current.parent.append(selectors); this.current = selectors; this.position++; } }, { key: 'comment', value: function comment() { var comment = new _selectorsComment2['default']({ value: this.currToken[1], source: { start: { line: this.currToken[2], column: this.currToken[3] }, end: { line: this.currToken[4], column: this.currToken[5] } }, sourceIndex: this.currToken[6] }); this.newNode(comment); this.position++; } }, { key: 'error', value: function error(message) { throw new this.input.error(message); } }, { key: 'namespace', value: function namespace() { var before = this.prevToken && this.prevToken[1] || true; if (this.nextToken[0] === 'word') { this.position++; return this.word(before); } else if (this.nextToken[0] === '*') { this.position++; return this.universal(before); } } }, { key: 'parentheses', value: function parentheses() { var last = this.current.last; if (last && last.type === 'pseudo') { var selector = new _selectorsSelector2['default'](); var cache = this.current; last.append(selector); this.current = selector; var balanced = 1; this.position++; while (this.position < this.tokens.length && balanced) { if (this.currToken[0] === '(') { balanced++; } if (this.currToken[0] === ')') { balanced--; } if (balanced) { this.parse(); } else { selector.parent.source.end.line = this.currToken[2]; selector.parent.source.end.column = this.currToken[3]; this.position++; } } if (balanced) { this.error('Expected closing parenthesis.'); } this.current = cache; } else { var balanced = 1; this.position++; last.value += '('; while (this.position < this.tokens.length && balanced) { if (this.currToken[0] === '(') { balanced++; } if (this.currToken[0] === ')') { balanced--; } last.value += this.currToken[1]; this.position++; } if (balanced) { this.error('Expected closing parenthesis.'); } } } }, { key: 'pseudo', value: function pseudo() { var _this = this; var pseudoStr = ''; var startingToken = this.currToken; while (this.currToken && this.currToken[0] === ':') { pseudoStr += this.currToken[1]; this.position++; } if (!this.currToken) { return this.error('Expected pseudo-class or pseudo-element'); } if (this.currToken[0] === 'word') { (function () { var pseudo = undefined; _this.splitWord(false, function (first, length) { pseudoStr += first; pseudo = new _selectorsPseudo2['default']({ value: pseudoStr, source: { start: { line: startingToken[2], column: startingToken[3] }, end: { line: _this.currToken[4], column: _this.currToken[5] } }, sourceIndex: startingToken[4] }); _this.newNode(pseudo); if (length > 1 && _this.nextToken && _this.nextToken[0] === '(') { _this.error('Misplaced parenthesis.'); } }); })(); } else { this.error('Unexpected "' + this.currToken[0] + '" found.'); } } }, { key: 'space', value: function space() { var token = this.currToken; // Handle space before and after the selector if (this.position === 0 || this.prevToken[0] === ',' || this.prevToken[0] === '(') { this.spaces = token[1]; this.position++; } else if (this.position === this.tokens.length - 1 || this.nextToken[0] === ',' || this.nextToken[0] === ')') { this.current.last.spaces.after = token[1]; this.position++; } else { this.combinator(); } } }, { key: 'string', value: function string() { var token = this.currToken; this.newNode(new _selectorsString2['default']({ value: this.currToken[1], source: { start: { line: token[2], column: token[3] }, end: { line: token[4], column: token[5] } }, sourceIndex: token[6] })); this.position++; } }, { key: 'universal', value: function universal(namespace) { var nextToken = this.nextToken; if (nextToken && nextToken[1] === '|') { this.position++; return this.namespace(); } this.newNode(new _selectorsUniversal2['default']({ value: this.currToken[1], source: { start: { line: this.currToken[2], column: this.currToken[3] }, end: { line: this.currToken[2], column: this.currToken[3] } }, sourceIndex: this.currToken[4] }), namespace); this.position++; } }, { key: 'splitWord', value: function splitWord(namespace, firstCallback) { var _this2 = this; var nextToken = this.nextToken; var word = this.currToken[1]; while (nextToken && nextToken[0] === 'word') { this.position++; var current = this.currToken[1]; word += current; if (current.lastIndexOf('\\') === current.length - 1) { var next = this.nextToken; if (next && next[0] === 'space') { word += next[1]; this.position++; } } nextToken = this.nextToken; } var hasClass = (0, _indexesOf2['default'])(word, '.'); var hasId = (0, _indexesOf2['default'])(word, '#'); var indices = (0, _sortAscending2['default'])((0, _uniq2['default'])((0, _flatten2['default'])([[0], hasClass, hasId]))); indices.forEach(function (ind, i) { var index = indices[i + 1] || word.length; var value = word.slice(ind, index); if (i === 0 && firstCallback) { return firstCallback.call(_this2, value, indices.length); } var node = undefined; if (~hasClass.indexOf(ind)) { node = new _selectorsClassName2['default']({ value: value.slice(1), source: { start: { line: _this2.currToken[2], column: _this2.currToken[3] + ind }, end: { line: _this2.currToken[4], column: _this2.currToken[3] + (index - 1) } }, sourceIndex: _this2.currToken[6] + indices[i] }); } else if (~hasId.indexOf(ind)) { node = new _selectorsId2['default']({ value: value.slice(1), source: { start: { line: _this2.currToken[2], column: _this2.currToken[3] + ind }, end: { line: _this2.currToken[4], column: _this2.currToken[3] + (index - 1) } }, sourceIndex: _this2.currToken[6] + indices[i] }); } else { node = new _selectorsTag2['default']({ value: value, source: { start: { line: _this2.currToken[2], column: _this2.currToken[3] + ind }, end: { line: _this2.currToken[4], column: _this2.currToken[3] + (index - 1) } }, sourceIndex: _this2.currToken[6] + indices[i] }); } _this2.newNode(node, namespace); }); this.position++; } }, { key: 'word', value: function word(namespace) { var nextToken = this.nextToken; if (nextToken && nextToken[1] === '|') { this.position++; return this.namespace(); } return this.splitWord(namespace); } }, { key: 'loop', value: function loop() { while (this.position < this.tokens.length) { this.parse(); } return this.root; } }, { key: 'parse', value: function parse() { switch (this.currToken[0]) { case 'space': this.space(); break; case 'comment': this.comment(); break; case '(': this.parentheses(); break; case '[': this.attribute(); break; case 'at-word': case 'word': this.word(); break; case ':': this.pseudo(); break; case ',': this.comma(); break; case '*': this.universal(); break; case 'combinator': this.combinator(); break; case 'string': this.string(); break; } } /** * Helpers */ }, { key: 'newNode', value: function newNode(node, namespace) { if (namespace) { node.namespace = namespace; } if (this.spaces) { node.spaces.before = this.spaces; this.spaces = ''; } return this.current.append(node); } }, { key: 'currToken', get: function get() { return this.tokens[this.position]; } }, { key: 'nextToken', get: function get() { return this.tokens[this.position + 1]; } }, { key: 'prevToken', get: function get() { return this.tokens[this.position - 1]; } }]); return Parser; })(); exports['default'] = Parser; module.exports = exports['default'];