Security update for Core, with self-updated composer
[yaffs-website] / node_modules / uncss / node_modules / postcss / lib / parser.js
1 'use strict';
2
3 exports.__esModule = true;
4
5 var _declaration = require('./declaration');
6
7 var _declaration2 = _interopRequireDefault(_declaration);
8
9 var _tokenize = require('./tokenize');
10
11 var _tokenize2 = _interopRequireDefault(_tokenize);
12
13 var _comment = require('./comment');
14
15 var _comment2 = _interopRequireDefault(_comment);
16
17 var _atRule = require('./at-rule');
18
19 var _atRule2 = _interopRequireDefault(_atRule);
20
21 var _root = require('./root');
22
23 var _root2 = _interopRequireDefault(_root);
24
25 var _rule = require('./rule');
26
27 var _rule2 = _interopRequireDefault(_rule);
28
29 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
30
31 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
32
33 var Parser = function () {
34     function Parser(input) {
35         _classCallCheck(this, Parser);
36
37         this.input = input;
38
39         this.pos = 0;
40         this.root = new _root2.default();
41         this.current = this.root;
42         this.spaces = '';
43         this.semicolon = false;
44
45         this.root.source = { input: input, start: { line: 1, column: 1 } };
46     }
47
48     Parser.prototype.tokenize = function tokenize() {
49         this.tokens = (0, _tokenize2.default)(this.input);
50     };
51
52     Parser.prototype.loop = function loop() {
53         var token = void 0;
54         while (this.pos < this.tokens.length) {
55             token = this.tokens[this.pos];
56
57             switch (token[0]) {
58                 case 'word':
59                 case ':':
60                     this.word();
61                     break;
62
63                 case '}':
64                     this.end(token);
65                     break;
66
67                 case 'comment':
68                     this.comment(token);
69                     break;
70
71                 case 'at-word':
72                     this.atrule(token);
73                     break;
74
75                 case '{':
76                     this.emptyRule(token);
77                     break;
78
79                 default:
80                     this.spaces += token[1];
81                     break;
82             }
83
84             this.pos += 1;
85         }
86         this.endFile();
87     };
88
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] };
93
94         var text = token[1].slice(2, -2);
95         if (/^\s*$/.test(text)) {
96             node.text = '';
97             node.raws.left = text;
98             node.raws.right = '';
99         } else {
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];
104         }
105     };
106
107     Parser.prototype.emptyRule = function emptyRule(token) {
108         var node = new _rule2.default();
109         this.init(node, token[2], token[3]);
110         node.selector = '';
111         node.raws.between = '';
112         this.current = node;
113     };
114
115     Parser.prototype.word = function word() {
116         var token = void 0;
117         var end = false;
118         var type = null;
119         var colon = false;
120         var bracket = null;
121         var brackets = 0;
122
123         var start = this.pos;
124         this.pos += 1;
125         while (this.pos < this.tokens.length) {
126             token = this.tokens[this.pos];
127             type = token[0];
128
129             if (type === '(') {
130                 if (!bracket) bracket = token;
131                 brackets += 1;
132             } else if (brackets === 0) {
133                 if (type === ';') {
134                     if (colon) {
135                         this.decl(this.tokens.slice(start, this.pos + 1));
136                         return;
137                     } else {
138                         break;
139                     }
140                 } else if (type === '{') {
141                     this.rule(this.tokens.slice(start, this.pos + 1));
142                     return;
143                 } else if (type === '}') {
144                     this.pos -= 1;
145                     end = true;
146                     break;
147                 } else if (type === ':') {
148                     colon = true;
149                 }
150             } else if (type === ')') {
151                 brackets -= 1;
152                 if (brackets === 0) bracket = null;
153             }
154
155             this.pos += 1;
156         }
157         if (this.pos === this.tokens.length) {
158             this.pos -= 1;
159             end = true;
160         }
161
162         if (brackets > 0) this.unclosedBracket(bracket);
163
164         if (end && colon) {
165             while (this.pos > start) {
166                 token = this.tokens[this.pos][0];
167                 if (token !== 'space' && token !== 'comment') break;
168                 this.pos -= 1;
169             }
170             this.decl(this.tokens.slice(start, this.pos + 1));
171             return;
172         }
173
174         this.unknownWord(start);
175     };
176
177     Parser.prototype.rule = function rule(tokens) {
178         tokens.pop();
179
180         var node = new _rule2.default();
181         this.init(node, tokens[0][2], tokens[0][3]);
182
183         node.raws.between = this.spacesFromEnd(tokens);
184         this.raw(node, 'selector', tokens);
185         this.current = node;
186     };
187
188     Parser.prototype.decl = function decl(tokens) {
189         var node = new _declaration2.default();
190         this.init(node);
191
192         var last = tokens[tokens.length - 1];
193         if (last[0] === ';') {
194             this.semicolon = true;
195             tokens.pop();
196         }
197         if (last[4]) {
198             node.source.end = { line: last[4], column: last[5] };
199         } else {
200             node.source.end = { line: last[2], column: last[3] };
201         }
202
203         while (tokens[0][0] !== 'word') {
204             node.raws.before += tokens.shift()[1];
205         }
206         node.source.start = { line: tokens[0][2], column: tokens[0][3] };
207
208         node.prop = '';
209         while (tokens.length) {
210             var type = tokens[0][0];
211             if (type === ':' || type === 'space' || type === 'comment') {
212                 break;
213             }
214             node.prop += tokens.shift()[1];
215         }
216
217         node.raws.between = '';
218
219         var token = void 0;
220         while (tokens.length) {
221             token = tokens.shift();
222
223             if (token[0] === ':') {
224                 node.raws.between += token[1];
225                 break;
226             } else {
227                 node.raws.between += token[1];
228             }
229         }
230
231         if (node.prop[0] === '_' || node.prop[0] === '*') {
232             node.raws.before += node.prop[0];
233             node.prop = node.prop.slice(1);
234         }
235         node.raws.between += this.spacesFromStart(tokens);
236         this.precheckMissedSemicolon(tokens);
237
238         for (var i = tokens.length - 1; i > 0; i--) {
239             token = tokens[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;
245                 break;
246             } else if (token[1] === 'important') {
247                 var cache = tokens.slice(0);
248                 var str = '';
249                 for (var j = i; j > 0; j--) {
250                     var _type = cache[j][0];
251                     if (str.trim().indexOf('!') === 0 && _type !== 'space') {
252                         break;
253                     }
254                     str = cache.pop()[1] + str;
255                 }
256                 if (str.trim().indexOf('!') === 0) {
257                     node.important = true;
258                     node.raws.important = str;
259                     tokens = cache;
260                 }
261             }
262
263             if (token[0] !== 'space' && token[0] !== 'comment') {
264                 break;
265             }
266         }
267
268         this.raw(node, 'value', tokens);
269
270         if (node.value.indexOf(':') !== -1) this.checkMissedSemicolon(tokens);
271     };
272
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);
278         }
279         this.init(node, token[2], token[3]);
280
281         var last = false;
282         var open = false;
283         var params = [];
284
285         this.pos += 1;
286         while (this.pos < this.tokens.length) {
287             token = this.tokens[this.pos];
288
289             if (token[0] === ';') {
290                 node.source.end = { line: token[2], column: token[3] };
291                 this.semicolon = true;
292                 break;
293             } else if (token[0] === '{') {
294                 open = true;
295                 break;
296             } else if (token[0] === '}') {
297                 this.end(token);
298                 break;
299             } else {
300                 params.push(token);
301             }
302
303             this.pos += 1;
304         }
305         if (this.pos === this.tokens.length) {
306             last = true;
307         }
308
309         node.raws.between = this.spacesFromEnd(params);
310         if (params.length) {
311             node.raws.afterName = this.spacesFromStart(params);
312             this.raw(node, 'params', params);
313             if (last) {
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 = '';
318             }
319         } else {
320             node.raws.afterName = '';
321             node.params = '';
322         }
323
324         if (open) {
325             node.nodes = [];
326             this.current = node;
327         }
328     };
329
330     Parser.prototype.end = function end(token) {
331         if (this.current.nodes && this.current.nodes.length) {
332             this.current.raws.semicolon = this.semicolon;
333         }
334         this.semicolon = false;
335
336         this.current.raws.after = (this.current.raws.after || '') + this.spaces;
337         this.spaces = '';
338
339         if (this.current.parent) {
340             this.current.source.end = { line: token[2], column: token[3] };
341             this.current = this.current.parent;
342         } else {
343             this.unexpectedClose(token);
344         }
345     };
346
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;
351         }
352         this.current.raws.after = (this.current.raws.after || '') + this.spaces;
353     };
354
355     // Helpers
356
357     Parser.prototype.init = function init(node, line, column) {
358         this.current.push(node);
359
360         node.source = { start: { line: line, column: column }, input: this.input };
361         node.raws.before = this.spaces;
362         this.spaces = '';
363         if (node.type !== 'comment') this.semicolon = false;
364     };
365
366     Parser.prototype.raw = function raw(node, prop, tokens) {
367         var token = void 0,
368             type = void 0;
369         var length = tokens.length;
370         var value = '';
371         var clean = true;
372         for (var i = 0; i < length; i += 1) {
373             token = tokens[i];
374             type = token[0];
375             if (type === 'comment' || type === 'space' && i === length - 1) {
376                 clean = false;
377             } else {
378                 value += token[1];
379             }
380         }
381         if (!clean) {
382             var raw = tokens.reduce(function (all, i) {
383                 return all + i[1];
384             }, '');
385             node.raws[prop] = { value: value, raw: raw };
386         }
387         node[prop] = value;
388     };
389
390     Parser.prototype.spacesFromEnd = function spacesFromEnd(tokens) {
391         var lastTokenType = void 0;
392         var spaces = '';
393         while (tokens.length) {
394             lastTokenType = tokens[tokens.length - 1][0];
395             if (lastTokenType !== 'space' && lastTokenType !== 'comment') break;
396             spaces = tokens.pop()[1] + spaces;
397         }
398         return spaces;
399     };
400
401     Parser.prototype.spacesFromStart = function spacesFromStart(tokens) {
402         var next = void 0;
403         var spaces = '';
404         while (tokens.length) {
405             next = tokens[0][0];
406             if (next !== 'space' && next !== 'comment') break;
407             spaces += tokens.shift()[1];
408         }
409         return spaces;
410     };
411
412     Parser.prototype.stringFrom = function stringFrom(tokens, from) {
413         var result = '';
414         for (var i = from; i < tokens.length; i++) {
415             result += tokens[i][1];
416         }
417         tokens.splice(from, tokens.length - from);
418         return result;
419     };
420
421     Parser.prototype.colon = function colon(tokens) {
422         var brackets = 0;
423         var token = void 0,
424             type = void 0,
425             prev = void 0;
426         for (var i = 0; i < tokens.length; i++) {
427             token = tokens[i];
428             type = token[0];
429
430             if (type === '(') {
431                 brackets += 1;
432             } else if (type === ')') {
433                 brackets -= 1;
434             } else if (brackets === 0 && type === ':') {
435                 if (!prev) {
436                     this.doubleColon(token);
437                 } else if (prev[0] === 'word' && prev[1] === 'progid') {
438                     continue;
439                 } else {
440                     return i;
441                 }
442             }
443
444             prev = token;
445         }
446         return false;
447     };
448
449     // Errors
450
451     Parser.prototype.unclosedBracket = function unclosedBracket(bracket) {
452         throw this.input.error('Unclosed bracket', bracket[2], bracket[3]);
453     };
454
455     Parser.prototype.unknownWord = function unknownWord(start) {
456         var token = this.tokens[start];
457         throw this.input.error('Unknown word', token[2], token[3]);
458     };
459
460     Parser.prototype.unexpectedClose = function unexpectedClose(token) {
461         throw this.input.error('Unexpected }', token[2], token[3]);
462     };
463
464     Parser.prototype.unclosedBlock = function unclosedBlock() {
465         var pos = this.current.source.start;
466         throw this.input.error('Unclosed block', pos.line, pos.column);
467     };
468
469     Parser.prototype.doubleColon = function doubleColon(token) {
470         throw this.input.error('Double colon', token[2], token[3]);
471     };
472
473     Parser.prototype.unnamedAtrule = function unnamedAtrule(node, token) {
474         throw this.input.error('At-rule without name', token[2], token[3]);
475     };
476
477     Parser.prototype.precheckMissedSemicolon = function precheckMissedSemicolon(tokens) {
478         // Hook for Safe Parser
479         tokens;
480     };
481
482     Parser.prototype.checkMissedSemicolon = function checkMissedSemicolon(tokens) {
483         var colon = this.colon(tokens);
484         if (colon === false) return;
485
486         var founded = 0;
487         var token = void 0;
488         for (var j = colon - 1; j >= 0; j--) {
489             token = tokens[j];
490             if (token[0] !== 'space') {
491                 founded += 1;
492                 if (founded === 2) break;
493             }
494         }
495         throw this.input.error('Missed semicolon', token[2], token[3]);
496     };
497
498     return Parser;
499 }();
500
501 exports.default = Parser;
502 module.exports = exports['default'];