stylus-source 0.15.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. data/.DS_Store +0 -0
  2. data/README.md +3 -0
  3. data/lib/.DS_Store +0 -0
  4. data/lib/node_modules/cssom/.idea/CSSOM.iml +9 -0
  5. data/lib/node_modules/cssom/.idea/dictionaries/nv.xml +3 -0
  6. data/lib/node_modules/cssom/.idea/encodings.xml +5 -0
  7. data/lib/node_modules/cssom/.idea/misc.xml +17 -0
  8. data/lib/node_modules/cssom/.idea/modules.xml +9 -0
  9. data/lib/node_modules/cssom/.idea/projectCodeStyle.xml +82 -0
  10. data/lib/node_modules/cssom/.idea/vcs.xml +8 -0
  11. data/lib/node_modules/cssom/.idea/workspace.xml +467 -0
  12. data/lib/node_modules/cssom/.livereload +19 -0
  13. data/lib/node_modules/cssom/Jakefile +37 -0
  14. data/lib/node_modules/cssom/README.mdown +33 -0
  15. data/lib/node_modules/cssom/Rakefile +23 -0
  16. data/lib/node_modules/cssom/docs/.livereload +19 -0
  17. data/lib/node_modules/cssom/docs/bar.css +3 -0
  18. data/lib/node_modules/cssom/docs/demo.css +0 -0
  19. data/lib/node_modules/cssom/docs/foo.css +4 -0
  20. data/lib/node_modules/cssom/docs/parse.html +170 -0
  21. data/lib/node_modules/cssom/docs/parse2.html +431 -0
  22. data/lib/node_modules/cssom/index.html +100 -0
  23. data/lib/node_modules/cssom/lib/CSSImportRule.js +34 -0
  24. data/lib/node_modules/cssom/lib/CSSMediaRule.js +38 -0
  25. data/lib/node_modules/cssom/lib/CSSOM.js +3 -0
  26. data/lib/node_modules/cssom/lib/CSSRule.js +38 -0
  27. data/lib/node_modules/cssom/lib/CSSStyleDeclaration.js +130 -0
  28. data/lib/node_modules/cssom/lib/CSSStyleRule.js +187 -0
  29. data/lib/node_modules/cssom/lib/CSSStyleSheet.js +85 -0
  30. data/lib/node_modules/cssom/lib/MediaList.js +61 -0
  31. data/lib/node_modules/cssom/lib/StyleSheet.js +15 -0
  32. data/lib/node_modules/cssom/lib/clone.js +69 -0
  33. data/lib/node_modules/cssom/lib/index.js +10 -0
  34. data/lib/node_modules/cssom/lib/parse.js +195 -0
  35. data/lib/node_modules/cssom/media.html +17 -0
  36. data/lib/node_modules/cssom/package.json +30 -0
  37. data/lib/node_modules/cssom/plugins/toHTML.js +32 -0
  38. data/lib/node_modules/cssom/server/index.html +22 -0
  39. data/lib/node_modules/cssom/server/index.js +21 -0
  40. data/lib/node_modules/cssom/shorthands.html +21 -0
  41. data/lib/node_modules/cssom/test/CSSStyleDeclaration.test.js +35 -0
  42. data/lib/node_modules/cssom/test/CSSStyleRule.test.js +12 -0
  43. data/lib/node_modules/cssom/test/CSSStyleSheet.test.js +16 -0
  44. data/lib/node_modules/cssom/test/MediaList.test.js +21 -0
  45. data/lib/node_modules/cssom/test/clone.test.js +38 -0
  46. data/lib/node_modules/cssom/test/fixtures/dummy.css +3 -0
  47. data/lib/node_modules/cssom/test/helper.js +97 -0
  48. data/lib/node_modules/cssom/test/index.html +42 -0
  49. data/lib/node_modules/cssom/test/parse.test.js +346 -0
  50. data/lib/node_modules/cssom/test/vendor/qunit.css +189 -0
  51. data/lib/node_modules/cssom/test/vendor/qunit.js +1341 -0
  52. data/lib/node_modules/growl/History.md +16 -0
  53. data/lib/node_modules/growl/Readme.md +74 -0
  54. data/lib/node_modules/growl/lib/growl.js +82 -0
  55. data/lib/node_modules/growl/package.json +6 -0
  56. data/lib/node_modules/growl/test.js +17 -0
  57. data/lib/stylus/colors.js +156 -0
  58. data/lib/stylus/convert/css.js +130 -0
  59. data/lib/stylus/errors.js +58 -0
  60. data/lib/stylus/functions/image.js +120 -0
  61. data/lib/stylus/functions/index.js +722 -0
  62. data/lib/stylus/functions/index.styl +123 -0
  63. data/lib/stylus/functions/url.js +98 -0
  64. data/lib/stylus/lexer.js +728 -0
  65. data/lib/stylus/middleware.js +223 -0
  66. data/lib/stylus/nodes/arguments.js +65 -0
  67. data/lib/stylus/nodes/binop.js +54 -0
  68. data/lib/stylus/nodes/block.js +99 -0
  69. data/lib/stylus/nodes/boolean.js +103 -0
  70. data/lib/stylus/nodes/call.js +57 -0
  71. data/lib/stylus/nodes/charset.js +42 -0
  72. data/lib/stylus/nodes/comment.js +32 -0
  73. data/lib/stylus/nodes/each.js +56 -0
  74. data/lib/stylus/nodes/expression.js +168 -0
  75. data/lib/stylus/nodes/fontface.js +55 -0
  76. data/lib/stylus/nodes/function.js +104 -0
  77. data/lib/stylus/nodes/group.js +79 -0
  78. data/lib/stylus/nodes/hsla.js +256 -0
  79. data/lib/stylus/nodes/ident.js +127 -0
  80. data/lib/stylus/nodes/if.js +55 -0
  81. data/lib/stylus/nodes/import.js +30 -0
  82. data/lib/stylus/nodes/index.js +52 -0
  83. data/lib/stylus/nodes/jsliteral.js +32 -0
  84. data/lib/stylus/nodes/keyframes.js +78 -0
  85. data/lib/stylus/nodes/literal.js +92 -0
  86. data/lib/stylus/nodes/media.js +42 -0
  87. data/lib/stylus/nodes/node.js +209 -0
  88. data/lib/stylus/nodes/null.js +72 -0
  89. data/lib/stylus/nodes/page.js +43 -0
  90. data/lib/stylus/nodes/params.js +72 -0
  91. data/lib/stylus/nodes/property.js +72 -0
  92. data/lib/stylus/nodes/return.js +44 -0
  93. data/lib/stylus/nodes/rgba.js +335 -0
  94. data/lib/stylus/nodes/root.js +50 -0
  95. data/lib/stylus/nodes/selector.js +57 -0
  96. data/lib/stylus/nodes/string.js +120 -0
  97. data/lib/stylus/nodes/ternary.js +51 -0
  98. data/lib/stylus/nodes/unaryop.js +46 -0
  99. data/lib/stylus/nodes/unit.js +207 -0
  100. data/lib/stylus/parser.js +1514 -0
  101. data/lib/stylus/renderer.js +157 -0
  102. data/lib/stylus/source.rb +7 -0
  103. data/lib/stylus/stack/frame.js +66 -0
  104. data/lib/stylus/stack/index.js +146 -0
  105. data/lib/stylus/stack/scope.js +53 -0
  106. data/lib/stylus/stylus.js +102 -0
  107. data/lib/stylus/token.js +53 -0
  108. data/lib/stylus/utils.js +237 -0
  109. data/lib/stylus/visitor/compiler.js +472 -0
  110. data/lib/stylus/visitor/evaluator.js +1070 -0
  111. data/lib/stylus/visitor/index.js +31 -0
  112. data/stylus-source.gemspec +15 -0
  113. metadata +158 -0
@@ -0,0 +1,53 @@
1
+
2
+ /*!
3
+ * Stylus - Token
4
+ * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
5
+ * MIT Licensed
6
+ */
7
+
8
+ /**
9
+ * Module dependencies.
10
+ */
11
+
12
+ var inspect = require('sys').inspect;
13
+
14
+ /**
15
+ * Initialize a new `Token` with the given `type` and `val`.
16
+ *
17
+ * @param {String} type
18
+ * @param {Mixed} val
19
+ * @api private
20
+ */
21
+
22
+ var Token = exports = module.exports = function Token(type, val) {
23
+ this.type = type;
24
+ this.val = val;
25
+ };
26
+
27
+ /**
28
+ * Custom inspect.
29
+ *
30
+ * @return {String}
31
+ * @api public
32
+ */
33
+
34
+ Token.prototype.inspect = function(){
35
+ var val = ' ' + inspect(this.val);
36
+ return '[Token:' + this.lineno + ' '
37
+ + '\x1b[32m' + this.type + '\x1b[0m'
38
+ + '\x1b[33m' + (this.val ? val : '') + '\x1b[0m'
39
+ + ']';
40
+ };
41
+
42
+ /**
43
+ * Return type or val.
44
+ *
45
+ * @return {String}
46
+ * @api public
47
+ */
48
+
49
+ Token.prototype.toString = function(){
50
+ return (undefined === this.val
51
+ ? this.type
52
+ : this.val).toString();
53
+ };
@@ -0,0 +1,237 @@
1
+
2
+ /*!
3
+ * Stylus - utils
4
+ * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
5
+ * MIT Licensed
6
+ */
7
+
8
+ /**
9
+ * Module dependencies.
10
+ */
11
+
12
+ var nodes = require('./nodes')
13
+ , join = require('path').join
14
+ , fs = require('fs');
15
+
16
+ /**
17
+ * Check if `path` looks absolute.
18
+ *
19
+ * @param {String} path
20
+ * @return {Boolean}
21
+ * @api private
22
+ */
23
+
24
+ exports.absolute = function(path){
25
+ return /^([a-z]:\\)|\//i.test(path);
26
+ };
27
+
28
+ /**
29
+ * Attempt to lookup `path` within `paths` from tail to head.
30
+ * Optionally a path to `ignore` may be passed.
31
+ *
32
+ * @param {String} path
33
+ * @param {String} paths
34
+ * @param {String} ignore
35
+ * @return {String}
36
+ * @api private
37
+ */
38
+
39
+ exports.lookup = function(path, paths, ignore){
40
+ var lookup
41
+ , i = paths.length;
42
+
43
+ // Absolute
44
+ if (exports.absolute(path)) {
45
+ try {
46
+ fs.statSync(path);
47
+ return path;
48
+ } catch (err) {
49
+ // Ignore, continue on
50
+ // to trying relative lookup.
51
+ // Needed for url(/images/foo.png)
52
+ // for example
53
+ }
54
+ }
55
+
56
+ // Relative
57
+ while (i--) {
58
+ try {
59
+ lookup = join(paths[i], path);
60
+ if (ignore == lookup) continue;
61
+ fs.statSync(lookup);
62
+ return lookup;
63
+ } catch (err) {
64
+ // Ignore
65
+ }
66
+ }
67
+ };
68
+
69
+ /**
70
+ * Format the given `err` with the given `options`.
71
+ *
72
+ * Options:
73
+ *
74
+ * - `filename` context filename
75
+ * - `context` context line count [8]
76
+ * - `lineno` context line number
77
+ * - `input` input string
78
+ *
79
+ * @param {Error} err
80
+ * @param {Object} options
81
+ * @return {Error}
82
+ * @api private
83
+ */
84
+
85
+ exports.formatException = function(err, options){
86
+ var lineno = options.lineno
87
+ , filename = options.filename
88
+ , str = options.input
89
+ , context = options.context || 8
90
+ , context = context / 2
91
+ , lines = ('\n' + str).split('\n')
92
+ , start = Math.max(lineno - context, 1)
93
+ , end = Math.min(lines.length, lineno + context)
94
+ , pad = end.toString().length;
95
+
96
+ var context = lines.slice(start, end).map(function(line, i){
97
+ var curr = i + start;
98
+ return (curr == lineno ? ' > ' : ' ')
99
+ + Array(pad - curr.toString().length + 1).join(' ')
100
+ + curr
101
+ + '| '
102
+ + line;
103
+ }).join('\n');
104
+
105
+ err.message = filename
106
+ + ':' + lineno
107
+ + '\n' + context
108
+ + '\n\n' + err.message + '\n'
109
+ + (err.stylusStack ? err.stylusStack + '\n' : '');
110
+
111
+ return err;
112
+ };
113
+
114
+ /**
115
+ * Assert that `node` is of the given `type`, or throw.
116
+ *
117
+ * @param {Node} node
118
+ * @param {Function} type
119
+ * @param {String} param
120
+ * @api public
121
+ */
122
+
123
+ exports.assertType = function(node, type, param){
124
+ exports.assertPresent(node, param);
125
+ if (node.nodeName == type) return;
126
+ var actual = node.nodeName
127
+ , msg = 'expected "'
128
+ + param + '" to be a '
129
+ + type + ', but got '
130
+ + actual + ':' + node;
131
+ throw new Error('TypeError: ' + msg);
132
+ };
133
+
134
+ /**
135
+ * Assert that `node` is a `String` or `Ident`.
136
+ *
137
+ * @param {Node} node
138
+ * @param {String} param
139
+ * @api public
140
+ */
141
+
142
+ exports.assertString = function(node, param){
143
+ exports.assertPresent(node, param);
144
+ switch (node.nodeName) {
145
+ case 'string':
146
+ case 'ident':
147
+ case 'literal':
148
+ return;
149
+ default:
150
+ var actual = node.nodeName
151
+ , msg = 'expected string, ident or literal, but got ' + actual + ':' + node;
152
+ throw new Error('TypeError: ' + msg);
153
+ }
154
+ };
155
+
156
+ /**
157
+ * Assert that `node` is a `RGBA` or `HSLA`.
158
+ *
159
+ * @param {Node} node
160
+ * @param {String} param
161
+ * @api public
162
+ */
163
+
164
+ exports.assertColor = function(node, param){
165
+ exports.assertPresent(node, param);
166
+ switch (node.nodeName) {
167
+ case 'rgba':
168
+ case 'hsla':
169
+ return;
170
+ default:
171
+ var actual = node.nodeName
172
+ , msg = 'expected rgba or hsla, but got ' + actual + ':' + node;
173
+ throw new Error('TypeError: ' + msg);
174
+ }
175
+ };
176
+
177
+ /**
178
+ * Assert that param `name` is given, aka the `node` is passed.
179
+ *
180
+ * @param {Node} node
181
+ * @param {String} name
182
+ * @api public
183
+ */
184
+
185
+ exports.assertPresent = function(node, name){
186
+ if (node) return;
187
+ if (name) throw new Error('"' + name + '" argument required');
188
+ throw new Error('argument missing');
189
+ };
190
+
191
+ /**
192
+ * Unwrap `expr`.
193
+ *
194
+ * Takes an expressions with length of 1
195
+ * such as `((1 2 3))` and unwraps it to `(1 2 3)`.
196
+ *
197
+ * @param {Expression} expr
198
+ * @return {Node}
199
+ * @api public
200
+ */
201
+
202
+ exports.unwrap = function(expr){
203
+ // explicitly preserve the expression
204
+ if (expr.preserve) return expr;
205
+ if ('arguments' != expr.nodeName && 'expression' != expr.nodeName) return expr;
206
+ if (1 != expr.nodes.length) return expr;
207
+ if ('arguments' != expr.nodes[0].nodeName && 'expression' != expr.nodes[0].nodeName) return expr;
208
+ return exports.unwrap(expr.nodes[0]);
209
+ };
210
+
211
+ /**
212
+ * Return param names for `fn`.
213
+ *
214
+ * @param {Function} fn
215
+ * @return {Array}
216
+ * @api private
217
+ */
218
+
219
+ exports.params = function(fn){
220
+ return fn
221
+ .toString()
222
+ .match(/\(([^)]*)\)/)[1].split(/ *, */);
223
+ };
224
+
225
+ /**
226
+ * Merge object `b` with `a`.
227
+ *
228
+ * @param {Object} a
229
+ * @param {Object} b
230
+ * @return {Object} a
231
+ * @api private
232
+ */
233
+
234
+ exports.merge = function(a, b){
235
+ for (var k in b) a[k] = b[k];
236
+ return a;
237
+ }
@@ -0,0 +1,472 @@
1
+
2
+ /*!
3
+ * Stylus - Compiler
4
+ * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
5
+ * MIT Licensed
6
+ */
7
+
8
+ /**
9
+ * Module dependencies.
10
+ */
11
+
12
+ var Visitor = require('./')
13
+ , nodes = require('../nodes')
14
+ , fs = require('fs');
15
+
16
+ /**
17
+ * Initialize a new `Compiler` with the given `root` Node
18
+ * and the following `options`.
19
+ *
20
+ * Options:
21
+ *
22
+ * - `compress` Compress the css output, defaults to false
23
+ *
24
+ * @param {Node} root
25
+ * @api public
26
+ */
27
+
28
+ var Compiler = module.exports = function Compiler(root, options) {
29
+ options = options || {};
30
+ this.compress = options.compress;
31
+ this.firebug = options.firebug;
32
+ this.linenos = options.linenos;
33
+ this.indents = 1;
34
+ Visitor.call(this, root);
35
+ this.tree = [];
36
+ this.js = '';
37
+ };
38
+
39
+ /**
40
+ * Inherit from `Visitor.prototype`.
41
+ */
42
+
43
+ Compiler.prototype.__proto__ = Visitor.prototype;
44
+
45
+ /**
46
+ * Compile to css, and return a string of CSS.
47
+ *
48
+ * @return {String}
49
+ * @api private
50
+ */
51
+
52
+ Compiler.prototype.compile = function(){
53
+ return this.visit(this.root);
54
+ };
55
+
56
+ /**
57
+ * Return indentation string.
58
+ *
59
+ * @return {String}
60
+ * @api private
61
+ */
62
+
63
+ Compiler.prototype.__defineGetter__('indent', function(){
64
+ return this.compress
65
+ ? ''
66
+ : new Array(this.indents).join(' ');
67
+ });
68
+
69
+ /**
70
+ * Visit Root.
71
+ */
72
+
73
+ Compiler.prototype.visitRoot = function(block){
74
+ this.buf = '';
75
+ for (var i = 0, len = block.nodes.length; i < len; ++i) {
76
+ var node = block.nodes[i];
77
+ switch (node.nodeName) {
78
+ case 'null':
79
+ case 'expression':
80
+ case 'function':
81
+ case 'jsliteral':
82
+ case 'unit':
83
+ continue;
84
+ default:
85
+ if (this.linenos || this.firebug) this.debugInfo(node);
86
+ var ret = this.visit(node);
87
+ if (ret) this.buf += ret + '\n';
88
+ }
89
+ }
90
+ return this.buf;
91
+ };
92
+
93
+ /**
94
+ * Visit Block.
95
+ */
96
+
97
+ Compiler.prototype.visitBlock = function(block){
98
+ var node;
99
+
100
+ if (block.hasProperties) {
101
+ var arr = [this.compress ? '{' : ' {'];
102
+ ++this.indents;
103
+ for (var i = 0, len = block.nodes.length; i < len; ++i) {
104
+ this.last = len - 1 == i;
105
+ node = block.nodes[i];
106
+ switch (node.nodeName) {
107
+ case 'null':
108
+ case 'expression':
109
+ case 'function':
110
+ case 'jsliteral':
111
+ case 'group':
112
+ case 'unit':
113
+ continue;
114
+ default:
115
+ arr.push(this.visit(node));
116
+ }
117
+ }
118
+ --this.indents;
119
+ arr.push(this.indent + '}');
120
+ this.buf += arr.join(this.compress ? '' : '\n');
121
+ this.buf += '\n';
122
+ }
123
+
124
+ // Nesting
125
+ for (var i = 0, len = block.nodes.length; i < len; ++i) {
126
+ node = block.nodes[i];
127
+ switch (node.nodeName) {
128
+ case 'group':
129
+ case 'print':
130
+ case 'page':
131
+ case 'block':
132
+ case 'keyframes':
133
+ if (this.linenos || this.firebug) this.debugInfo(node);
134
+ this.visit(node);
135
+ break;
136
+ case 'media':
137
+ case 'import':
138
+ this.visit(node);
139
+ break;
140
+ }
141
+ }
142
+ };
143
+
144
+ /**
145
+ * Visit Keyframes.
146
+ */
147
+
148
+ Compiler.prototype.visitKeyframes = function(node){
149
+ var prefix = 'official' == node.prefix
150
+ ? ''
151
+ : '-' + node.prefix + '-';
152
+
153
+ this.buf += '@' + prefix + 'keyframes '
154
+ + this.visit(node.name)
155
+ + (this.compress ? '{' : ' {');
156
+ ++this.indents;
157
+ node.frames.forEach(function(frame){
158
+ if (!this.compress) this.buf += '\n ';
159
+ this.buf += this.visit(frame.pos);
160
+ this.visit(frame.block);
161
+ }, this);
162
+ --this.indents;
163
+ this.buf += '}' + (this.compress ? '' : '\n');
164
+ };
165
+
166
+ /**
167
+ * Visit Media.
168
+ */
169
+
170
+ Compiler.prototype.visitMedia = function(media){
171
+ this.buf += '@media ' + media.val;
172
+ this.buf += this.compress ? '{' : ' {\n';
173
+ ++this.indents;
174
+ this.visit(media.block);
175
+ --this.indents;
176
+ this.buf += '}' + (this.compress ? '' : '\n');
177
+ };
178
+
179
+ /**
180
+ * Visit Page.
181
+ */
182
+
183
+ Compiler.prototype.visitPage = function(page){
184
+ this.buf += this.indent + '@page';
185
+ this.buf += page.selector ? ' ' + page.selector : '';
186
+ this.visit(page.block);
187
+ };
188
+
189
+ /**
190
+ * Visit Import.
191
+ */
192
+
193
+ Compiler.prototype.visitImport = function(imported){
194
+ this.buf += '@import ' + this.visit(imported.path) + ';\n';
195
+ };
196
+
197
+ /**
198
+ * Visit FontFace.
199
+ */
200
+
201
+ Compiler.prototype.visitFontFace = function(face){
202
+ this.buf += this.indent + '@font-face';
203
+ this.visit(face.block);
204
+ };
205
+
206
+ /**
207
+ * Visit JSLiteral.
208
+ */
209
+
210
+ Compiler.prototype.visitJSLiteral = function(js){
211
+ this.js += '\n' + js.val.replace(/@selector/g, '"' + this.selector + '"');
212
+ return '';
213
+ };
214
+
215
+ /**
216
+ * Visit Comment.
217
+ */
218
+
219
+ Compiler.prototype.visitComment = function(comment){
220
+ return this.compress
221
+ ? comment.suppress
222
+ ? ''
223
+ : comment.str
224
+ : comment.str;
225
+ };
226
+
227
+ /**
228
+ * Visit Function.
229
+ */
230
+
231
+ Compiler.prototype.visitFunction = function(fn){
232
+ return fn.name;
233
+ };
234
+
235
+ /**
236
+ * Visit Variable.
237
+ */
238
+
239
+ Compiler.prototype.visitVariable = function(variable){
240
+ return '';
241
+ };
242
+
243
+ /**
244
+ * Visit Charset.
245
+ */
246
+
247
+ Compiler.prototype.visitCharset = function(charset){
248
+ return '@charset ' + this.visit(charset.val) + ';';
249
+ };
250
+
251
+ /**
252
+ * Visit Literal.
253
+ */
254
+
255
+ Compiler.prototype.visitLiteral = function(lit){
256
+ return lit.val.trim().replace(/^ /gm, '');
257
+ };
258
+
259
+ /**
260
+ * Visit Boolean.
261
+ */
262
+
263
+ Compiler.prototype.visitBoolean = function(bool){
264
+ return bool.toString();
265
+ };
266
+
267
+ /**
268
+ * Visit RGBA.
269
+ */
270
+
271
+ Compiler.prototype.visitRGBA = function(rgba){
272
+ return rgba.toString();
273
+ };
274
+
275
+ /**
276
+ * Visit HSLA.
277
+ */
278
+
279
+ Compiler.prototype.visitHSLA = function(hsla){
280
+ return hsla.rgba.toString();
281
+ };
282
+
283
+ /**
284
+ * Visit Unit.
285
+ */
286
+
287
+ Compiler.prototype.visitUnit = function(unit){
288
+ var type = unit.type || ''
289
+ , n = unit.val
290
+ , float = n != (n | 0);
291
+
292
+ // Compress
293
+ if (this.compress) {
294
+ // Zero is always '0', unless when
295
+ // a percentage, this is required by keyframes
296
+ if ('%' != type && 0 == n) return '0';
297
+ // Omit leading '0' on floats
298
+ if (float && n < 1 && n > -1) {
299
+ return n.toString().replace('0.', '.') + type;
300
+ }
301
+ }
302
+
303
+ return n.toString() + type;
304
+ };
305
+
306
+ /**
307
+ * Visit Group.
308
+ */
309
+
310
+ Compiler.prototype.visitGroup = function(group){
311
+ var self = this
312
+ , tree = this.tree
313
+ , prev = tree[tree.length - 1]
314
+ , curr = [];
315
+
316
+ // Construct an array of arrays
317
+ // representing the selector hierarchy
318
+ group.nodes.forEach(function(node){
319
+ curr.push(node.parent
320
+ ? node
321
+ : node.val);
322
+ });
323
+
324
+ tree.push(curr);
325
+
326
+ // Reverse recurse the
327
+ // hierarchy array to build
328
+ // up the selector combinations.
329
+ // When we reach root, we have our
330
+ // selector string built
331
+ var selectors = []
332
+ , buf = [];
333
+ function join(arr, i) {
334
+ if (i) {
335
+ arr[i].forEach(function(str){
336
+ buf.unshift(str);
337
+ join(arr, i - 1);
338
+ buf.shift();
339
+ });
340
+ } else {
341
+ arr[0].forEach(function(selector){
342
+ var str = selector.trim();
343
+ if (buf.length) {
344
+ for (var i = 0, len = buf.length; i < len; ++i) {
345
+ if (~buf[i].indexOf('&')) {
346
+ str = buf[i].replace(/&/g, str).trim();
347
+ } else {
348
+ str += ' ' + buf[i].trim();
349
+ }
350
+ }
351
+ }
352
+ selectors.push(self.indent + str.trimRight());
353
+ });
354
+ }
355
+ }
356
+
357
+ // Join selectors
358
+ if (group.block.hasProperties) {
359
+ join(tree, tree.length - 1);
360
+ this.buf += (this.selector = selectors.join(this.compress ? ',' : ',\n'));
361
+ }
362
+
363
+ // Output blocks
364
+ this.visit(group.block);
365
+ tree.pop();
366
+ };
367
+
368
+ /**
369
+ * Visit Ident.
370
+ */
371
+
372
+ Compiler.prototype.visitIdent = function(ident){
373
+ return ident.name;
374
+ };
375
+
376
+ /**
377
+ * Visit String.
378
+ */
379
+
380
+ Compiler.prototype.visitString = function(string){
381
+ return this.isURL
382
+ ? string.val
383
+ : string.toString();
384
+ };
385
+
386
+ /**
387
+ * Visit Null.
388
+ */
389
+
390
+ Compiler.prototype.visitNull = function(node){
391
+ return '';
392
+ };
393
+
394
+ /**
395
+ * Visit Call.
396
+ */
397
+
398
+ Compiler.prototype.visitCall = function(call){
399
+ this.isURL = 'url' == call.name;
400
+ var args = call.args.nodes.map(function(arg){
401
+ return this.visit(arg);
402
+ }, this).join(this.compress ? ',' : ', ');
403
+ if (this.isURL) args = '"' + args + '"';
404
+ delete this.isURL;
405
+ return call.name + '(' + args + ')';
406
+ };
407
+
408
+ /**
409
+ * Visit Expression.
410
+ */
411
+
412
+ Compiler.prototype.visitExpression = function(expr){
413
+ var buf = []
414
+ , self = this
415
+ , len = expr.nodes.length
416
+ , nodes = expr.nodes.map(function(node){ return self.visit(node); });
417
+
418
+ nodes.forEach(function(node, i){
419
+ var last = i == len - 1;
420
+ buf.push(node);
421
+ if ('/' == nodes[i + 1] || '/' == node) return;
422
+ if (last) return;
423
+ buf.push(expr.isList
424
+ ? (self.compress ? ',' : ', ')
425
+ : (self.isURL ? '' : ' '));
426
+ });
427
+
428
+ return buf.join('');
429
+ };
430
+
431
+ /**
432
+ * Visit Arguments.
433
+ */
434
+
435
+ Compiler.prototype.visitArguments = Compiler.prototype.visitExpression;
436
+
437
+ /**
438
+ * Visit Property.
439
+ */
440
+
441
+ Compiler.prototype.visitProperty = function(prop){
442
+ var self = this
443
+ , val = this.visit(prop.expr);
444
+ return this.indent + (prop.name || prop.segments.join(''))
445
+ + (this.compress ? ':' + val : ': ' + val)
446
+ + (this.compress
447
+ ? (this.last ? '' : ';')
448
+ : ';');
449
+ };
450
+
451
+ /**
452
+ * Debug info.
453
+ */
454
+
455
+ Compiler.prototype.debugInfo = function(node){
456
+
457
+ var path = fs.realpathSync(node.filename)
458
+ , line = node.nodes ? node.nodes[0].lineno : node.lineno;
459
+
460
+ if (this.linenos){
461
+ this.buf += '\n/* ' + 'line ' + line + ' : ' + path + ' */\n';
462
+ }
463
+
464
+ if (this.firebug){
465
+ // debug info for firebug, the crazy formatting is needed
466
+ path = 'file\\\:\\\/\\\/' + path.replace(/(\/|\.)/g, '\\$1');
467
+ line = '\\00003' + line;
468
+ this.buf += '\n@media -stylus-debug-info'
469
+ + '{filename{font-family:' + path
470
+ + '}line{font-family:' + line + '}}\n';
471
+ }
472
+ }