source: trip-planner-front/node_modules/css/lib/parse/index.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 10.6 KB
Line 
1// http://www.w3.org/TR/CSS21/grammar.html
2// https://github.com/visionmedia/css-parse/pull/49#issuecomment-30088027
3var commentre = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//g
4
5module.exports = function(css, options){
6 options = options || {};
7
8 /**
9 * Positional.
10 */
11
12 var lineno = 1;
13 var column = 1;
14
15 /**
16 * Update lineno and column based on `str`.
17 */
18
19 function updatePosition(str) {
20 var lines = str.match(/\n/g);
21 if (lines) lineno += lines.length;
22 var i = str.lastIndexOf('\n');
23 column = ~i ? str.length - i : column + str.length;
24 }
25
26 /**
27 * Mark position and patch `node.position`.
28 */
29
30 function position() {
31 var start = { line: lineno, column: column };
32 return function(node){
33 node.position = new Position(start);
34 whitespace();
35 return node;
36 };
37 }
38
39 /**
40 * Store position information for a node
41 */
42
43 function Position(start) {
44 this.start = start;
45 this.end = { line: lineno, column: column };
46 this.source = options.source;
47 }
48
49 /**
50 * Non-enumerable source string
51 */
52
53 Position.prototype.content = css;
54
55 /**
56 * Error `msg`.
57 */
58
59 var errorsList = [];
60
61 function error(msg) {
62 var err = new Error(options.source + ':' + lineno + ':' + column + ': ' + msg);
63 err.reason = msg;
64 err.filename = options.source;
65 err.line = lineno;
66 err.column = column;
67 err.source = css;
68
69 if (options.silent) {
70 errorsList.push(err);
71 } else {
72 throw err;
73 }
74 }
75
76 /**
77 * Parse stylesheet.
78 */
79
80 function stylesheet() {
81 var rulesList = rules();
82
83 return {
84 type: 'stylesheet',
85 stylesheet: {
86 source: options.source,
87 rules: rulesList,
88 parsingErrors: errorsList
89 }
90 };
91 }
92
93 /**
94 * Opening brace.
95 */
96
97 function open() {
98 return match(/^{\s*/);
99 }
100
101 /**
102 * Closing brace.
103 */
104
105 function close() {
106 return match(/^}/);
107 }
108
109 /**
110 * Parse ruleset.
111 */
112
113 function rules() {
114 var node;
115 var rules = [];
116 whitespace();
117 comments(rules);
118 while (css.length && css.charAt(0) != '}' && (node = atrule() || rule())) {
119 if (node !== false) {
120 rules.push(node);
121 comments(rules);
122 }
123 }
124 return rules;
125 }
126
127 /**
128 * Match `re` and return captures.
129 */
130
131 function match(re) {
132 var m = re.exec(css);
133 if (!m) return;
134 var str = m[0];
135 updatePosition(str);
136 css = css.slice(str.length);
137 return m;
138 }
139
140 /**
141 * Parse whitespace.
142 */
143
144 function whitespace() {
145 match(/^\s*/);
146 }
147
148 /**
149 * Parse comments;
150 */
151
152 function comments(rules) {
153 var c;
154 rules = rules || [];
155 while (c = comment()) {
156 if (c !== false) {
157 rules.push(c);
158 }
159 }
160 return rules;
161 }
162
163 /**
164 * Parse comment.
165 */
166
167 function comment() {
168 var pos = position();
169 if ('/' != css.charAt(0) || '*' != css.charAt(1)) return;
170
171 var i = 2;
172 while ("" != css.charAt(i) && ('*' != css.charAt(i) || '/' != css.charAt(i + 1))) ++i;
173 i += 2;
174
175 if ("" === css.charAt(i-1)) {
176 return error('End of comment missing');
177 }
178
179 var str = css.slice(2, i - 2);
180 column += 2;
181 updatePosition(str);
182 css = css.slice(i);
183 column += 2;
184
185 return pos({
186 type: 'comment',
187 comment: str
188 });
189 }
190
191 /**
192 * Parse selector.
193 */
194
195 function selector() {
196 var m = match(/^([^{]+)/);
197 if (!m) return;
198 /* @fix Remove all comments from selectors
199 * http://ostermiller.org/findcomment.html */
200 return trim(m[0])
201 .replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*\/+/g, '')
202 .replace(/"(?:\\"|[^"])*"|'(?:\\'|[^'])*'/g, function(m) {
203 return m.replace(/,/g, '\u200C');
204 })
205 .split(/\s*(?![^(]*\)),\s*/)
206 .map(function(s) {
207 return s.replace(/\u200C/g, ',');
208 });
209 }
210
211 /**
212 * Parse declaration.
213 */
214
215 function declaration() {
216 var pos = position();
217
218 // prop
219 var prop = match(/^(\*?[-#\/\*\\\w]+(\[[0-9a-z_-]+\])?)\s*/);
220 if (!prop) return;
221 prop = trim(prop[0]);
222
223 // :
224 if (!match(/^:\s*/)) return error("property missing ':'");
225
226 // val
227 var val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/);
228
229 var ret = pos({
230 type: 'declaration',
231 property: prop.replace(commentre, ''),
232 value: val ? trim(val[0]).replace(commentre, '') : ''
233 });
234
235 // ;
236 match(/^[;\s]*/);
237
238 return ret;
239 }
240
241 /**
242 * Parse declarations.
243 */
244
245 function declarations() {
246 var decls = [];
247
248 if (!open()) return error("missing '{'");
249 comments(decls);
250
251 // declarations
252 var decl;
253 while (decl = declaration()) {
254 if (decl !== false) {
255 decls.push(decl);
256 comments(decls);
257 }
258 }
259
260 if (!close()) return error("missing '}'");
261 return decls;
262 }
263
264 /**
265 * Parse keyframe.
266 */
267
268 function keyframe() {
269 var m;
270 var vals = [];
271 var pos = position();
272
273 while (m = match(/^((\d+\.\d+|\.\d+|\d+)%?|[a-z]+)\s*/)) {
274 vals.push(m[1]);
275 match(/^,\s*/);
276 }
277
278 if (!vals.length) return;
279
280 return pos({
281 type: 'keyframe',
282 values: vals,
283 declarations: declarations()
284 });
285 }
286
287 /**
288 * Parse keyframes.
289 */
290
291 function atkeyframes() {
292 var pos = position();
293 var m = match(/^@([-\w]+)?keyframes\s*/);
294
295 if (!m) return;
296 var vendor = m[1];
297
298 // identifier
299 var m = match(/^([-\w]+)\s*/);
300 if (!m) return error("@keyframes missing name");
301 var name = m[1];
302
303 if (!open()) return error("@keyframes missing '{'");
304
305 var frame;
306 var frames = comments();
307 while (frame = keyframe()) {
308 frames.push(frame);
309 frames = frames.concat(comments());
310 }
311
312 if (!close()) return error("@keyframes missing '}'");
313
314 return pos({
315 type: 'keyframes',
316 name: name,
317 vendor: vendor,
318 keyframes: frames
319 });
320 }
321
322 /**
323 * Parse supports.
324 */
325
326 function atsupports() {
327 var pos = position();
328 var m = match(/^@supports *([^{]+)/);
329
330 if (!m) return;
331 var supports = trim(m[1]);
332
333 if (!open()) return error("@supports missing '{'");
334
335 var style = comments().concat(rules());
336
337 if (!close()) return error("@supports missing '}'");
338
339 return pos({
340 type: 'supports',
341 supports: supports,
342 rules: style
343 });
344 }
345
346 /**
347 * Parse host.
348 */
349
350 function athost() {
351 var pos = position();
352 var m = match(/^@host\s*/);
353
354 if (!m) return;
355
356 if (!open()) return error("@host missing '{'");
357
358 var style = comments().concat(rules());
359
360 if (!close()) return error("@host missing '}'");
361
362 return pos({
363 type: 'host',
364 rules: style
365 });
366 }
367
368 /**
369 * Parse media.
370 */
371
372 function atmedia() {
373 var pos = position();
374 var m = match(/^@media *([^{]+)/);
375
376 if (!m) return;
377 var media = trim(m[1]);
378
379 if (!open()) return error("@media missing '{'");
380
381 var style = comments().concat(rules());
382
383 if (!close()) return error("@media missing '}'");
384
385 return pos({
386 type: 'media',
387 media: media,
388 rules: style
389 });
390 }
391
392
393 /**
394 * Parse custom-media.
395 */
396
397 function atcustommedia() {
398 var pos = position();
399 var m = match(/^@custom-media\s+(--[^\s]+)\s*([^{;]+);/);
400 if (!m) return;
401
402 return pos({
403 type: 'custom-media',
404 name: trim(m[1]),
405 media: trim(m[2])
406 });
407 }
408
409 /**
410 * Parse paged media.
411 */
412
413 function atpage() {
414 var pos = position();
415 var m = match(/^@page */);
416 if (!m) return;
417
418 var sel = selector() || [];
419
420 if (!open()) return error("@page missing '{'");
421 var decls = comments();
422
423 // declarations
424 var decl;
425 while (decl = declaration()) {
426 decls.push(decl);
427 decls = decls.concat(comments());
428 }
429
430 if (!close()) return error("@page missing '}'");
431
432 return pos({
433 type: 'page',
434 selectors: sel,
435 declarations: decls
436 });
437 }
438
439 /**
440 * Parse document.
441 */
442
443 function atdocument() {
444 var pos = position();
445 var m = match(/^@([-\w]+)?document *([^{]+)/);
446 if (!m) return;
447
448 var vendor = trim(m[1]);
449 var doc = trim(m[2]);
450
451 if (!open()) return error("@document missing '{'");
452
453 var style = comments().concat(rules());
454
455 if (!close()) return error("@document missing '}'");
456
457 return pos({
458 type: 'document',
459 document: doc,
460 vendor: vendor,
461 rules: style
462 });
463 }
464
465 /**
466 * Parse font-face.
467 */
468
469 function atfontface() {
470 var pos = position();
471 var m = match(/^@font-face\s*/);
472 if (!m) return;
473
474 if (!open()) return error("@font-face missing '{'");
475 var decls = comments();
476
477 // declarations
478 var decl;
479 while (decl = declaration()) {
480 decls.push(decl);
481 decls = decls.concat(comments());
482 }
483
484 if (!close()) return error("@font-face missing '}'");
485
486 return pos({
487 type: 'font-face',
488 declarations: decls
489 });
490 }
491
492 /**
493 * Parse import
494 */
495
496 var atimport = _compileAtrule('import');
497
498 /**
499 * Parse charset
500 */
501
502 var atcharset = _compileAtrule('charset');
503
504 /**
505 * Parse namespace
506 */
507
508 var atnamespace = _compileAtrule('namespace');
509
510 /**
511 * Parse non-block at-rules
512 */
513
514
515 function _compileAtrule(name) {
516 var re = new RegExp('^@' + name + '\\s*([^;]+);');
517 return function() {
518 var pos = position();
519 var m = match(re);
520 if (!m) return;
521 var ret = { type: name };
522 ret[name] = m[1].trim();
523 return pos(ret);
524 }
525 }
526
527 /**
528 * Parse at rule.
529 */
530
531 function atrule() {
532 if (css[0] != '@') return;
533
534 return atkeyframes()
535 || atmedia()
536 || atcustommedia()
537 || atsupports()
538 || atimport()
539 || atcharset()
540 || atnamespace()
541 || atdocument()
542 || atpage()
543 || athost()
544 || atfontface();
545 }
546
547 /**
548 * Parse rule.
549 */
550
551 function rule() {
552 var pos = position();
553 var sel = selector();
554
555 if (!sel) return error('selector missing');
556 comments();
557
558 return pos({
559 type: 'rule',
560 selectors: sel,
561 declarations: declarations()
562 });
563 }
564
565 return addParent(stylesheet());
566};
567
568/**
569 * Trim `str`.
570 */
571
572function trim(str) {
573 return str ? str.replace(/^\s+|\s+$/g, '') : '';
574}
575
576/**
577 * Adds non-enumerable parent node reference to each node.
578 */
579
580function addParent(obj, parent) {
581 var isNode = obj && typeof obj.type === 'string';
582 var childParent = isNode ? obj : parent;
583
584 for (var k in obj) {
585 var value = obj[k];
586 if (Array.isArray(value)) {
587 value.forEach(function(v) { addParent(v, childParent); });
588 } else if (value && typeof value === 'object') {
589 addParent(value, childParent);
590 }
591 }
592
593 if (isNode) {
594 Object.defineProperty(obj, 'parent', {
595 configurable: true,
596 writable: true,
597 enumerable: false,
598 value: parent || null
599 });
600 }
601
602 return obj;
603}
Note: See TracBrowser for help on using the repository browser.