3 exports.__esModule = true;
5 var _declaration = require('./declaration');
7 var _declaration2 = _interopRequireDefault(_declaration);
9 var _tokenize = require('./tokenize');
11 var _tokenize2 = _interopRequireDefault(_tokenize);
13 var _comment = require('./comment');
15 var _comment2 = _interopRequireDefault(_comment);
17 var _atRule = require('./at-rule');
19 var _atRule2 = _interopRequireDefault(_atRule);
21 var _root = require('./root');
23 var _root2 = _interopRequireDefault(_root);
25 var _rule = require('./rule');
27 var _rule2 = _interopRequireDefault(_rule);
29 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
31 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
33 var Parser = function () {
34 function Parser(input) {
35 _classCallCheck(this, Parser);
40 this.root = new _root2.default();
41 this.current = this.root;
43 this.semicolon = false;
45 this.root.source = { input: input, start: { line: 1, column: 1 } };
48 Parser.prototype.tokenize = function tokenize() {
49 this.tokens = (0, _tokenize2.default)(this.input);
52 Parser.prototype.loop = function loop() {
54 while (this.pos < this.tokens.length) {
55 token = this.tokens[this.pos];
76 this.emptyRule(token);
80 this.spaces += token[1];
89 Parser.prototype.comment = function comment(token) {
90 var node = new _comment2.default();
91 this.init(node, token[2], token[3]);
92 node.source.end = { line: token[4], column: token[5] };
94 var text = token[1].slice(2, -2);
95 if (/^\s*$/.test(text)) {
97 node.raws.left = text;
100 var match = text.match(/^(\s*)([^]*[^\s])(\s*)$/);
101 node.text = match[2];
102 node.raws.left = match[1];
103 node.raws.right = match[3];
107 Parser.prototype.emptyRule = function emptyRule(token) {
108 var node = new _rule2.default();
109 this.init(node, token[2], token[3]);
111 node.raws.between = '';
115 Parser.prototype.word = function word() {
123 var start = this.pos;
125 while (this.pos < this.tokens.length) {
126 token = this.tokens[this.pos];
130 if (!bracket) bracket = token;
132 } else if (brackets === 0) {
135 this.decl(this.tokens.slice(start, this.pos + 1));
140 } else if (type === '{') {
141 this.rule(this.tokens.slice(start, this.pos + 1));
143 } else if (type === '}') {
147 } else if (type === ':') {
150 } else if (type === ')') {
152 if (brackets === 0) bracket = null;
157 if (this.pos === this.tokens.length) {
162 if (brackets > 0) this.unclosedBracket(bracket);
165 while (this.pos > start) {
166 token = this.tokens[this.pos][0];
167 if (token !== 'space' && token !== 'comment') break;
170 this.decl(this.tokens.slice(start, this.pos + 1));
174 this.unknownWord(start);
177 Parser.prototype.rule = function rule(tokens) {
180 var node = new _rule2.default();
181 this.init(node, tokens[0][2], tokens[0][3]);
183 node.raws.between = this.spacesFromEnd(tokens);
184 this.raw(node, 'selector', tokens);
188 Parser.prototype.decl = function decl(tokens) {
189 var node = new _declaration2.default();
192 var last = tokens[tokens.length - 1];
193 if (last[0] === ';') {
194 this.semicolon = true;
198 node.source.end = { line: last[4], column: last[5] };
200 node.source.end = { line: last[2], column: last[3] };
203 while (tokens[0][0] !== 'word') {
204 node.raws.before += tokens.shift()[1];
206 node.source.start = { line: tokens[0][2], column: tokens[0][3] };
209 while (tokens.length) {
210 var type = tokens[0][0];
211 if (type === ':' || type === 'space' || type === 'comment') {
214 node.prop += tokens.shift()[1];
217 node.raws.between = '';
220 while (tokens.length) {
221 token = tokens.shift();
223 if (token[0] === ':') {
224 node.raws.between += token[1];
227 node.raws.between += token[1];
231 if (node.prop[0] === '_' || node.prop[0] === '*') {
232 node.raws.before += node.prop[0];
233 node.prop = node.prop.slice(1);
235 node.raws.between += this.spacesFromStart(tokens);
236 this.precheckMissedSemicolon(tokens);
238 for (var i = tokens.length - 1; i > 0; i--) {
240 if (token[1] === '!important') {
241 node.important = true;
242 var string = this.stringFrom(tokens, i);
243 string = this.spacesFromEnd(tokens) + string;
244 if (string !== ' !important') node.raws.important = string;
246 } else if (token[1] === 'important') {
247 var cache = tokens.slice(0);
249 for (var j = i; j > 0; j--) {
250 var _type = cache[j][0];
251 if (str.trim().indexOf('!') === 0 && _type !== 'space') {
254 str = cache.pop()[1] + str;
256 if (str.trim().indexOf('!') === 0) {
257 node.important = true;
258 node.raws.important = str;
263 if (token[0] !== 'space' && token[0] !== 'comment') {
268 this.raw(node, 'value', tokens);
270 if (node.value.indexOf(':') !== -1) this.checkMissedSemicolon(tokens);
273 Parser.prototype.atrule = function atrule(token) {
274 var node = new _atRule2.default();
275 node.name = token[1].slice(1);
276 if (node.name === '') {
277 this.unnamedAtrule(node, token);
279 this.init(node, token[2], token[3]);
286 while (this.pos < this.tokens.length) {
287 token = this.tokens[this.pos];
289 if (token[0] === ';') {
290 node.source.end = { line: token[2], column: token[3] };
291 this.semicolon = true;
293 } else if (token[0] === '{') {
296 } else if (token[0] === '}') {
305 if (this.pos === this.tokens.length) {
309 node.raws.between = this.spacesFromEnd(params);
311 node.raws.afterName = this.spacesFromStart(params);
312 this.raw(node, 'params', params);
314 token = params[params.length - 1];
315 node.source.end = { line: token[4], column: token[5] };
316 this.spaces = node.raws.between;
317 node.raws.between = '';
320 node.raws.afterName = '';
330 Parser.prototype.end = function end(token) {
331 if (this.current.nodes && this.current.nodes.length) {
332 this.current.raws.semicolon = this.semicolon;
334 this.semicolon = false;
336 this.current.raws.after = (this.current.raws.after || '') + this.spaces;
339 if (this.current.parent) {
340 this.current.source.end = { line: token[2], column: token[3] };
341 this.current = this.current.parent;
343 this.unexpectedClose(token);
347 Parser.prototype.endFile = function endFile() {
348 if (this.current.parent) this.unclosedBlock();
349 if (this.current.nodes && this.current.nodes.length) {
350 this.current.raws.semicolon = this.semicolon;
352 this.current.raws.after = (this.current.raws.after || '') + this.spaces;
357 Parser.prototype.init = function init(node, line, column) {
358 this.current.push(node);
360 node.source = { start: { line: line, column: column }, input: this.input };
361 node.raws.before = this.spaces;
363 if (node.type !== 'comment') this.semicolon = false;
366 Parser.prototype.raw = function raw(node, prop, tokens) {
369 var length = tokens.length;
372 for (var i = 0; i < length; i += 1) {
375 if (type === 'comment' || type === 'space' && i === length - 1) {
382 var raw = tokens.reduce(function (all, i) {
385 node.raws[prop] = { value: value, raw: raw };
390 Parser.prototype.spacesFromEnd = function spacesFromEnd(tokens) {
391 var lastTokenType = void 0;
393 while (tokens.length) {
394 lastTokenType = tokens[tokens.length - 1][0];
395 if (lastTokenType !== 'space' && lastTokenType !== 'comment') break;
396 spaces = tokens.pop()[1] + spaces;
401 Parser.prototype.spacesFromStart = function spacesFromStart(tokens) {
404 while (tokens.length) {
406 if (next !== 'space' && next !== 'comment') break;
407 spaces += tokens.shift()[1];
412 Parser.prototype.stringFrom = function stringFrom(tokens, from) {
414 for (var i = from; i < tokens.length; i++) {
415 result += tokens[i][1];
417 tokens.splice(from, tokens.length - from);
421 Parser.prototype.colon = function colon(tokens) {
426 for (var i = 0; i < tokens.length; i++) {
432 } else if (type === ')') {
434 } else if (brackets === 0 && type === ':') {
436 this.doubleColon(token);
437 } else if (prev[0] === 'word' && prev[1] === 'progid') {
451 Parser.prototype.unclosedBracket = function unclosedBracket(bracket) {
452 throw this.input.error('Unclosed bracket', bracket[2], bracket[3]);
455 Parser.prototype.unknownWord = function unknownWord(start) {
456 var token = this.tokens[start];
457 throw this.input.error('Unknown word', token[2], token[3]);
460 Parser.prototype.unexpectedClose = function unexpectedClose(token) {
461 throw this.input.error('Unexpected }', token[2], token[3]);
464 Parser.prototype.unclosedBlock = function unclosedBlock() {
465 var pos = this.current.source.start;
466 throw this.input.error('Unclosed block', pos.line, pos.column);
469 Parser.prototype.doubleColon = function doubleColon(token) {
470 throw this.input.error('Double colon', token[2], token[3]);
473 Parser.prototype.unnamedAtrule = function unnamedAtrule(node, token) {
474 throw this.input.error('At-rule without name', token[2], token[3]);
477 Parser.prototype.precheckMissedSemicolon = function precheckMissedSemicolon(tokens) {
478 // Hook for Safe Parser
482 Parser.prototype.checkMissedSemicolon = function checkMissedSemicolon(tokens) {
483 var colon = this.colon(tokens);
484 if (colon === false) return;
488 for (var j = colon - 1; j >= 0; j--) {
490 if (token[0] !== 'space') {
492 if (founded === 2) break;
495 throw this.input.error('Missed semicolon', token[2], token[3]);
501 exports.default = Parser;
502 module.exports = exports['default'];