source: trip-planner-front/node_modules/stylus/lib/visitor/compiler.js

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

initial commit

  • Property mode set to 100644
File size: 12.6 KB
RevLine 
[6a3a178]1/*!
2 * Stylus - Compiler
3 * Copyright (c) Automattic <developer.wordpress.com>
4 * MIT Licensed
5 */
6
7/**
8 * Module dependencies.
9 */
10
11var Visitor = require('./')
12 , utils = require('../utils')
13 , fs = require('fs');
14
15/**
16 * Initialize a new `Compiler` with the given `root` Node
17 * and the following `options`.
18 *
19 * Options:
20 *
21 * - `compress` Compress the CSS output (default: false)
22 *
23 * @param {Node} root
24 * @api public
25 */
26
27var Compiler = module.exports = function Compiler(root, options) {
28 options = options || {};
29 this.compress = options.compress;
30 this.firebug = options.firebug;
31 this.linenos = options.linenos;
32 this.spaces = options['indent spaces'] || 2;
33 this.indents = 1;
34 Visitor.call(this, root);
35 this.stack = [];
36};
37
38/**
39 * Inherit from `Visitor.prototype`.
40 */
41
42Compiler.prototype.__proto__ = Visitor.prototype;
43
44/**
45 * Compile to css, and return a string of CSS.
46 *
47 * @return {String}
48 * @api private
49 */
50
51Compiler.prototype.compile = function(){
52 return this.visit(this.root);
53};
54
55/**
56 * Output `str`
57 *
58 * @param {String} str
59 * @param {Node} node
60 * @return {String}
61 * @api private
62 */
63
64Compiler.prototype.out = function(str, node){
65 return str;
66};
67
68/**
69 * Return indentation string.
70 *
71 * @return {String}
72 * @api private
73 */
74
75Compiler.prototype.__defineGetter__('indent', function(){
76 if (this.compress) return '';
77 return new Array(this.indents).join(Array(this.spaces + 1).join(' '));
78});
79
80/**
81 * Check if given `node` needs brackets.
82 *
83 * @param {Node} node
84 * @return {Boolean}
85 * @api private
86 */
87
88Compiler.prototype.needBrackets = function(node){
89 return 1 == this.indents
90 || 'atrule' != node.nodeName
91 || node.hasOnlyProperties;
92};
93
94/**
95 * Visit Root.
96 */
97
98Compiler.prototype.visitRoot = function(block){
99 this.buf = '';
100 for (var i = 0, len = block.nodes.length; i < len; ++i) {
101 var node = block.nodes[i];
102 if (this.linenos || this.firebug) this.debugInfo(node);
103 var ret = this.visit(node);
104 if (ret) this.buf += this.out(ret + '\n', node);
105 }
106 return this.buf;
107};
108
109/**
110 * Visit Block.
111 */
112
113Compiler.prototype.visitBlock = function(block){
114 var node
115 , separator = this.compress ? '' : '\n'
116 , needBrackets
117 , lastPropertyIndex;
118
119 if (block.hasProperties && !block.lacksRenderedSelectors) {
120 needBrackets = this.needBrackets(block.node);
121
122 if (this.compress) {
123 for (var i = block.nodes.length - 1; i >= 0; --i) {
124 if (block.nodes[i].nodeName === 'property') {
125 lastPropertyIndex = i;
126 break;
127 }
128 }
129 }
130 if (needBrackets) {
131 this.buf += this.out(this.compress ? '{' : ' {\n');
132 ++this.indents;
133 }
134 for (var i = 0, len = block.nodes.length; i < len; ++i) {
135 this.last = lastPropertyIndex === i;
136 node = block.nodes[i];
137 switch (node.nodeName) {
138 case 'null':
139 case 'expression':
140 case 'function':
141 case 'group':
142 case 'block':
143 case 'unit':
144 case 'media':
145 case 'keyframes':
146 case 'atrule':
147 case 'supports':
148 continue;
149 // inline comments
150 case !this.compress && node.inline && 'comment':
151 this.buf = this.buf.slice(0, -1);
152 this.buf += this.out(' ' + this.visit(node) + '\n', node);
153 break;
154 case 'property':
155 var ret = this.visit(node) + separator;
156 this.buf += this.compress ? ret : this.out(ret, node);
157 break;
158 default:
159 this.buf += this.out(this.visit(node) + separator, node);
160 }
161 }
162 if (needBrackets) {
163 --this.indents;
164 this.buf += this.out(this.indent + '}' + separator);
165 }
166 }
167
168 // Nesting
169 for (var i = 0, len = block.nodes.length; i < len; ++i) {
170 node = block.nodes[i];
171 switch (node.nodeName) {
172 case 'group':
173 case 'block':
174 case 'keyframes':
175 if (this.linenos || this.firebug) this.debugInfo(node);
176 this.visit(node);
177 break;
178 case 'media':
179 case 'import':
180 case 'atrule':
181 case 'supports':
182 this.visit(node);
183 break;
184 case 'comment':
185 // only show unsuppressed comments
186 if (!node.suppress) {
187 this.buf += this.out(this.indent + this.visit(node) + '\n', node);
188 }
189 break;
190 case 'charset':
191 case 'literal':
192 case 'namespace':
193 this.buf += this.out(this.visit(node) + '\n', node);
194 break;
195 }
196 }
197};
198
199/**
200 * Visit Keyframes.
201 */
202
203Compiler.prototype.visitKeyframes = function(node){
204 if (!node.frames) return;
205
206 var prefix = 'official' == node.prefix
207 ? ''
208 : '-' + node.prefix + '-';
209
210 this.buf += this.out('@' + prefix + 'keyframes '
211 + this.visit(node.val)
212 + (this.compress ? '{' : ' {\n'), node);
213
214 this.keyframe = true;
215 ++this.indents;
216 this.visit(node.block);
217 --this.indents;
218 this.keyframe = false;
219
220 this.buf += this.out('}' + (this.compress ? '' : '\n'));
221};
222
223/**
224 * Visit Media.
225 */
226
227Compiler.prototype.visitMedia = function(media){
228 var val = media.val;
229 if (!media.hasOutput || !val.nodes.length) return;
230
231 this.buf += this.out('@media ', media);
232 this.visit(val);
233 this.buf += this.out(this.compress ? '{' : ' {\n');
234 ++this.indents;
235 this.visit(media.block);
236 --this.indents;
237 this.buf += this.out('}' + (this.compress ? '' : '\n'));
238};
239
240/**
241 * Visit QueryList.
242 */
243
244Compiler.prototype.visitQueryList = function(queries){
245 for (var i = 0, len = queries.nodes.length; i < len; ++i) {
246 this.visit(queries.nodes[i]);
247 if (len - 1 != i) this.buf += this.out(',' + (this.compress ? '' : ' '));
248 }
249};
250
251/**
252 * Visit Query.
253 */
254
255Compiler.prototype.visitQuery = function(node){
256 var len = node.nodes.length;
257 if (node.predicate) this.buf += this.out(node.predicate + ' ');
258 if (node.type) this.buf += this.out(node.type + (len ? ' and ' : ''));
259 for (var i = 0; i < len; ++i) {
260 this.buf += this.out(this.visit(node.nodes[i]));
261 if (len - 1 != i) this.buf += this.out(' and ');
262 }
263};
264
265/**
266 * Visit Feature.
267 */
268
269Compiler.prototype.visitFeature = function(node){
270 if (!node.expr) {
271 return node.name;
272 } else if (node.expr.isEmpty) {
273 return '(' + node.name + ')';
274 } else {
275 return '(' + node.name + ':' + (this.compress ? '' : ' ') + this.visit(node.expr) + ')';
276 }
277};
278
279/**
280 * Visit Import.
281 */
282
283Compiler.prototype.visitImport = function(imported){
284 this.buf += this.out('@import ' + this.visit(imported.path) + ';\n', imported);
285};
286
287/**
288 * Visit Atrule.
289 */
290
291Compiler.prototype.visitAtrule = function(atrule){
292 var newline = this.compress ? '' : '\n';
293
294 this.buf += this.out(this.indent + '@' + atrule.type, atrule);
295
296 if (atrule.val) this.buf += this.out(' ' + atrule.val.trim());
297
298 if (atrule.block) {
299 if (atrule.block.isEmpty) {
300 this.buf += this.out((this.compress ? '' : ' ') + '{}' + newline);
301 } else if (atrule.hasOnlyProperties) {
302 this.visit(atrule.block);
303 } else {
304 this.buf += this.out(this.compress ? '{' : ' {\n');
305 ++this.indents;
306 this.visit(atrule.block);
307 --this.indents;
308 this.buf += this.out(this.indent + '}' + newline);
309 }
310 } else {
311 this.buf += this.out(';' + newline);
312 }
313};
314
315/**
316 * Visit Supports.
317 */
318
319Compiler.prototype.visitSupports = function(node){
320 if (!node.hasOutput) return;
321
322 this.buf += this.out(this.indent + '@supports ', node);
323 this.isCondition = true;
324 this.buf += this.out(this.visit(node.condition));
325 this.isCondition = false;
326 this.buf += this.out(this.compress ? '{' : ' {\n');
327 ++this.indents;
328 this.visit(node.block);
329 --this.indents;
330 this.buf += this.out(this.indent + '}' + (this.compress ? '' : '\n'));
331},
332
333/**
334 * Visit Comment.
335 */
336
337Compiler.prototype.visitComment = function(comment){
338 return this.compress
339 ? comment.suppress
340 ? ''
341 : comment.str
342 : comment.str;
343};
344
345/**
346 * Visit Function.
347 */
348
349Compiler.prototype.visitFunction = function(fn){
350 return fn.name;
351};
352
353/**
354 * Visit Charset.
355 */
356
357Compiler.prototype.visitCharset = function(charset){
358 return '@charset ' + this.visit(charset.val) + ';';
359};
360
361/**
362 * Visit Namespace.
363 */
364
365Compiler.prototype.visitNamespace = function(namespace){
366 return '@namespace '
367 + (namespace.prefix ? this.visit(namespace.prefix) + ' ' : '')
368 + this.visit(namespace.val) + ';';
369};
370
371/**
372 * Visit Literal.
373 */
374
375Compiler.prototype.visitLiteral = function(lit){
376 var val = lit.val;
377 if (lit.css) val = val.replace(/^ /gm, '');
378 return val;
379};
380
381/**
382 * Visit Boolean.
383 */
384
385Compiler.prototype.visitBoolean = function(bool){
386 return bool.toString();
387};
388
389/**
390 * Visit RGBA.
391 */
392
393Compiler.prototype.visitRGBA = function(rgba){
394 return rgba.toString();
395};
396
397/**
398 * Visit HSLA.
399 */
400
401Compiler.prototype.visitHSLA = function(hsla){
402 return hsla.rgba.toString();
403};
404
405/**
406 * Visit Unit.
407 */
408
409Compiler.prototype.visitUnit = function(unit){
410 var type = unit.type || ''
411 , n = unit.val
412 , float = n != (n | 0);
413
414 // Compress
415 if (this.compress) {
416 // Always return '0' unless the unit is a percentage or time
417 if ('%' != type && 's' != type && 'ms' != type && 0 == n) return '0';
418 // Omit leading '0' on floats
419 if (float && n < 1 && n > -1) {
420 return n.toString().replace('0.', '.') + type;
421 }
422 }
423
424 return (float ? parseFloat(n.toFixed(15)) : n).toString() + type;
425};
426
427/**
428 * Visit Group.
429 */
430
431Compiler.prototype.visitGroup = function(group){
432 var stack = this.keyframe ? [] : this.stack
433 , comma = this.compress ? ',' : ',\n';
434
435 stack.push(group.nodes);
436
437 // selectors
438 if (group.block.hasProperties) {
439 var selectors = utils.compileSelectors.call(this, stack)
440 , len = selectors.length;
441
442 if (len) {
443 if (this.keyframe) comma = this.compress ? ',' : ', ';
444
445 for (var i = 0; i < len; ++i) {
446 var selector = selectors[i]
447 , last = (i == len - 1);
448
449 // keyframe blocks (10%, 20% { ... })
450 if (this.keyframe) selector = i ? selector.trim() : selector;
451
452 this.buf += this.out(selector + (last ? '' : comma), group.nodes[i]);
453 }
454 } else {
455 group.block.lacksRenderedSelectors = true;
456 }
457 }
458
459 // output block
460 this.visit(group.block);
461 stack.pop();
462};
463
464/**
465 * Visit Ident.
466 */
467
468Compiler.prototype.visitIdent = function(ident){
469 return ident.name;
470};
471
472/**
473 * Visit String.
474 */
475
476Compiler.prototype.visitString = function(string){
477 return this.isURL
478 ? string.val
479 : string.toString();
480};
481
482/**
483 * Visit Null.
484 */
485
486Compiler.prototype.visitNull = function(node){
487 return '';
488};
489
490/**
491 * Visit Call.
492 */
493
494Compiler.prototype.visitCall = function(call){
495 this.isURL = 'url' == call.name;
496 var args = call.args.nodes.map(function(arg){
497 return this.visit(arg);
498 }, this).join(this.compress ? ',' : ', ');
499 if (this.isURL) args = '"' + args + '"';
500 this.isURL = false;
501 return call.name + '(' + args + ')';
502};
503
504/**
505 * Visit Expression.
506 */
507
508Compiler.prototype.visitExpression = function(expr){
509 var buf = []
510 , self = this
511 , len = expr.nodes.length
512 , nodes = expr.nodes.map(function(node){ return self.visit(node); });
513
514 nodes.forEach(function(node, i){
515 var last = i == len - 1;
516 buf.push(node);
517 if ('/' == nodes[i + 1] || '/' == node) return;
518 if (last) return;
519
520 var space = self.isURL || (self.isCondition
521 && (')' == nodes[i + 1] || '(' == node))
522 ? '' : ' ';
523
524 buf.push(expr.isList
525 ? (self.compress ? ',' : ', ')
526 : space);
527 });
528
529 return buf.join('');
530};
531
532/**
533 * Visit Arguments.
534 */
535
536Compiler.prototype.visitArguments = Compiler.prototype.visitExpression;
537
538/**
539 * Visit Property.
540 */
541
542Compiler.prototype.visitProperty = function(prop){
543 var val = this.visit(prop.expr).trim()
544 , name = (prop.name || prop.segments.join(''))
545 , arr = [];
546
547 if (name === '@apply') {
548 arr.push(
549 this.out(this.indent),
550 this.out(name + ' ', prop),
551 this.out(val, prop.expr),
552 this.out(this.compress ? (this.last ? '' : ';') : ';')
553 );
554 return arr.join('');
555 }
556 arr.push(
557 this.out(this.indent),
558 this.out(name + (this.compress ? ':' : ': '), prop),
559 this.out(val, prop.expr),
560 this.out(this.compress ? (this.last ? '' : ';') : ';')
561 );
562 return arr.join('');
563};
564
565/**
566 * Debug info.
567 */
568
569Compiler.prototype.debugInfo = function(node){
570
571 var path = node.filename == 'stdin' ? 'stdin' : fs.realpathSync(node.filename)
572 , line = (node.nodes && node.nodes.length ? node.nodes[0].lineno : node.lineno) || 1;
573
574 if (this.linenos){
575 this.buf += '\n/* ' + 'line ' + line + ' : ' + path + ' */\n';
576 }
577
578 if (this.firebug){
579 // debug info for firebug, the crazy formatting is needed
580 path = 'file\\\:\\\/\\\/' + path.replace(/([.:/\\])/g, function(m) {
581 return '\\' + (m === '\\' ? '\/' : m)
582 });
583 line = '\\00003' + line;
584 this.buf += '\n@media -stylus-debug-info'
585 + '{filename{font-family:' + path
586 + '}line{font-family:' + line + '}}\n';
587 }
588}
Note: See TracBrowser for help on using the repository browser.