text: '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 _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;
              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);
              if (namespace.length > 1) {
                  if (namespace[0] === '') {
                      namespace[0] = true;
                  }
                  attr = new _selectorsAttribute2['default']({
                      attribute: namespace[2],
                      namespace: namespace[0],
                      operator: parts[1],
                      value: parts[2]
                  });
              } else {
                  attr = new _selectorsAttribute2['default']({
                      attribute: parts[0],
                      operator: parts[1],
                      value: parts[2]
                  });
              }
  
              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: '' });
              while (this.position < this.tokens.length && this.currToken[0] === 'space' || this.currToken[0] === 'combinator') {
                  if (this.nextToken[0] === 'combinator') {
                      combinator.spaces.before = this.currToken[1];
                  } else if (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++;
                  if (this.position === this.tokens.length) {
                      this.error('Unexpected right hand side combinator.');
                  }
              }
              if (!this.current.last) {
                  this.error('Unexpected left hand side combinator.');
              }
              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] });
              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: 'pseudo',
          value: function pseudo() {
              var _this = this;
  
              var pseudoStr = '';
              while (this.currToken[0] === ':') {
                  pseudoStr += this.currToken[1];
                  this.position++;
              }
              if (this.currToken[0] === 'word') {
                  (function () {
                      var pseudo = undefined;
                      _this.splitWord(false, function (first, length) {
                          pseudoStr += first;
                          pseudo = new _selectorsPseudo2['default']({ value: pseudoStr });
                          _this.newNode(pseudo);
                          if (length > 1 && _this.nextToken && _this.nextToken[0] === '(') {
                              _this.error('Misplaced parenthesis.');
                          }
                      });
                      if (_this.currToken && _this.currToken[0] === '(') {
                          var selector = new _selectorsSelector2['default']();
                          var cache = _this.current;
                          pseudo.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 {
                                  _this.position++;
                              }
                          }
                          if (balanced) {
                              _this.error('Expected closing parenthesis.');
                          }
                          _this.current = cache;
                      }
                  })();
              } 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: '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] }), 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) });
                  } else if (~hasId.indexOf(ind)) {
                      node = new _selectorsId2['default']({ value: value.slice(1) });
                  } else {
                      node = new _selectorsTag2['default']({ value: value });
                  }
                  _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.attribute();
                      break;
                  case 'word':
                      this.word();
                      break;
                  case ':':
                      this.pseudo();
                      break;
                  case ',':
                      this.comma();
                      break;
                  case '*':
                      this.universal();
                      break;
                  case 'combinator':
                      this.combinator();
                      break;
              }
          }
      }, {
          key: 'newNode',
  
          /**
           * Helpers
           */
  
          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 () {
              return this.tokens[this.position];
          }
      }, {
          key: 'nextToken',
          get: function () {
              return this.tokens[this.position + 1];
          }
      }, {
          key: 'prevToken',
          get: function () {
              return this.tokens[this.position - 1];
          }
      }]);
  
      return Parser;
  })();
  
  exports['default'] = Parser;
  module.exports = exports['default'];