stylus-source 0.21.2 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/VERSION +1 -1
  2. data/vendor/History.md +11 -0
  3. data/vendor/Readme.md +4 -0
  4. data/vendor/bin/stylus +9 -32
  5. data/vendor/docs/bifs.md +16 -0
  6. data/vendor/docs/js.md +2 -0
  7. data/vendor/editors/Stylus.tmbundle/Syntaxes/Stylus.tmLanguage +67 -7
  8. data/vendor/lib/functions/index.styl +16 -0
  9. data/vendor/lib/lexer.js +13 -0
  10. data/vendor/lib/nodes/extend.js +41 -0
  11. data/vendor/lib/nodes/group.js +1 -0
  12. data/vendor/lib/nodes/index.js +1 -0
  13. data/vendor/lib/nodes/page.js +1 -1
  14. data/vendor/lib/parser.js +10 -0
  15. data/vendor/lib/renderer.js +13 -0
  16. data/vendor/lib/stylus.js +1 -1
  17. data/vendor/lib/utils.js +66 -0
  18. data/vendor/lib/visitor/compiler.js +65 -61
  19. data/vendor/lib/visitor/evaluator.js +10 -0
  20. data/vendor/lib/visitor/normalizer.js +226 -0
  21. data/vendor/node_modules/cssom/docs/parse.html +15 -1
  22. data/vendor/node_modules/cssom/docs/parse.html_ +268 -0
  23. data/vendor/node_modules/cssom/lib/CSSStyleDeclaration.js +18 -2
  24. data/vendor/node_modules/cssom/lib/parse.js +0 -18
  25. data/vendor/node_modules/cssom/package.json +1 -1
  26. data/vendor/node_modules/cssom/test/CSSStyleDeclaration.test.js +10 -3
  27. data/vendor/package.json +2 -2
  28. data/vendor/test/cases/bifs.keys.css +4 -0
  29. data/vendor/test/cases/bifs.keys.styl +6 -0
  30. data/vendor/test/cases/bifs.values.css +5 -0
  31. data/vendor/test/cases/bifs.values.styl +6 -0
  32. data/vendor/test/cases/css.extend.css +13 -0
  33. data/vendor/test/cases/css.extend.styl +15 -0
  34. data/vendor/test/cases/extend.complex.css +16 -0
  35. data/vendor/test/cases/extend.complex.styl +15 -0
  36. data/vendor/test/cases/extend.css +22 -0
  37. data/vendor/test/cases/extend.multiple-definitions.css +11 -0
  38. data/vendor/test/cases/extend.multiple-definitions.styl +9 -0
  39. data/vendor/test/cases/extend.styl +22 -0
  40. data/vendor/testing/foo.css +3753 -3
  41. data/vendor/testing/foo.styl +7 -0
  42. data/vendor/testing/index.html +5 -50
  43. data/vendor/testing/test.css +19 -4
  44. data/vendor/testing/test.styl +19 -12
  45. metadata +18 -2
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.21.2
1
+ 0.22.0
data/vendor/History.md CHANGED
@@ -1,4 +1,15 @@
1
1
 
2
+ 0.22.0 / 2012-01-04
3
+ ==================
4
+
5
+ * Added `@extend`. Closes #149
6
+ * Added more syntax highlighting to TextMate bundle [paulmillr]
7
+ * Added `keys(pairs)` and `values(pairs)` BIFs
8
+ * Added JavaScript object coercion support
9
+ * Added JavaScript -> Stylus node coercion utilities
10
+ * Fixed `.define()`ing of functions
11
+ * Fixed `stylus(1)` repl for 0.6.x
12
+
2
13
  0.21.2 / 2011-12-22
3
14
  ==================
4
15
 
data/vendor/Readme.md CHANGED
@@ -110,6 +110,10 @@ form input {
110
110
  - [Connect](/LearnBoost/stylus/blob/master/docs/middleware.md)
111
111
  - [Ruby On Rails](https://github.com/lucasmazza/stylus_rails)
112
112
 
113
+ ### CMS Support
114
+
115
+ - [DocPad](https://github.com/bevry/docpad)
116
+
113
117
  ### Screencasts
114
118
 
115
119
  - [Stylus Intro](http://screenr.com/bNY)
data/vendor/bin/stylus CHANGED
@@ -353,7 +353,7 @@ function repl() {
353
353
  , parser = new stylus.Parser('', options)
354
354
  , evaluator = new stylus.Evaluator(parser.parse(), options)
355
355
  , rl = require('readline')
356
- , repl = rl.createInterface(process.stdin, process.stdout, true)
356
+ , repl = rl.createInterface(process.stdin, process.stdout, autocomplete)
357
357
  , global = evaluator.global.scope;
358
358
 
359
359
  // expose BIFs
@@ -364,56 +364,33 @@ function repl() {
364
364
  repl.prompt();
365
365
 
366
366
  // HACK: flat-list auto-complete
367
- repl._tabComplete = function(){
368
- var out = this.output
369
- , line = this.line
367
+ function autocomplete(line){
368
+ var out = process.stdout
370
369
  , keys = Object.keys(global.locals)
371
370
  , len = keys.length
372
371
  , words = line.split(/\s+/)
373
372
  , word = words.pop()
374
373
  , names = []
375
374
  , name
376
- , obj
375
+ , node
377
376
  , key;
378
377
 
379
378
  // find words that match
380
379
  for (var i = 0; i < len; ++i) {
381
380
  key = keys[i];
382
381
  if (0 == key.indexOf(word)) {
383
- names.push(key);
384
- }
385
- }
386
-
387
- // several candidates
388
- if (names.length > 1) {
389
- out.write('\r\n\r\n\033[90m');
390
- names.forEach(function(name){
391
- var node = global.lookup(name);
382
+ node = global.lookup(key);
392
383
  switch (node.nodeName) {
393
384
  case 'function':
394
- out.write(' - ' + node + '\r\n');
385
+ names.push(node.toString());
395
386
  break;
396
387
  default:
397
- out.write(' - ' + name + '\r\n');
388
+ names.push(key);
398
389
  }
399
- });
400
- out.write('\r\n\033[0m');
401
- this._refreshLine();
402
- // single candidate
403
- } else if (names.length) {
404
- name = names.pop();
405
- obj = global.lookup(name);
406
- name = name.replace(word, '');
407
- switch (obj.nodeName) {
408
- case 'function':
409
- this._insertString(name + '()');
410
- this.cursor--;
411
- break;
412
- default:
413
- this._insertString(name);
414
390
  }
415
- this._refreshLine();
416
391
  }
392
+
393
+ return [names, line];
417
394
  };
418
395
 
419
396
  repl.on('line', function(line){
data/vendor/docs/bifs.md CHANGED
@@ -104,6 +104,22 @@ Return the lightness of the given `color`.
104
104
 
105
105
  Aliased as `prepend()`
106
106
 
107
+ ### keys(pairs)
108
+
109
+ Return keys in the given `pairs`:
110
+
111
+ pairs = (one 1) (two 2) (three 3)
112
+ keys(pairs)
113
+ // => one two three
114
+
115
+ ### values(pairs)
116
+
117
+ Return values in the given `pairs`:
118
+
119
+ pairs = (one 1) (two 2) (three 3)
120
+ values(pairs)
121
+ // => 1 2 3
122
+
107
123
  ### typeof(node)
108
124
 
109
125
  Return type of `node` as a string.
data/vendor/docs/js.md CHANGED
@@ -63,6 +63,8 @@ Defer importing of the given `path` until evaluation is performed. The example b
63
63
  .define('number', 15.5)
64
64
  .define('some-bool', true)
65
65
  .define('list', [1,2,3])
66
+ .define('list', [1,2,[3,4,[5,6]]])
67
+ .define('list', { foo: 'bar', bar: 'baz' })
66
68
  .define('families', ['Helvetica Neue', 'Helvetica', 'sans-serif'])
67
69
 
68
70
  ### .define(name, fn)
@@ -71,13 +71,33 @@
71
71
  <key>name</key>
72
72
  <string>entity.other.attribute-name.pseudo-class.stylus</string>
73
73
  </dict>
74
+ <dict>
75
+ <key>match</key>
76
+ <string>\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|datalist|dd|del|details|dfn|dialog|div|dl|dt|em|eventsource|fieldset|figure|figcaption|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|label|legend|li|link|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|samp|script|section|select|small|span|strike|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\b</string>
77
+ <key>name</key>
78
+ <string>entity.name.tag.stylus</string>
79
+ </dict>
80
+ <dict>
81
+ <key>captures</key>
82
+ <dict>
83
+ <key>1</key>
84
+ <dict>
85
+ <key>name</key>
86
+ <string>punctuation.definition.constant.stylus</string>
87
+ </dict>
88
+ </dict>
89
+ <key>match</key>
90
+ <string>(#)([0-9a-fA-F]{3}|[0-9a-fA-F]{6})\b</string>
91
+ <key>name</key>
92
+ <string>constant.other.color.rgb-value.stylus</string>
93
+ </dict>
74
94
  <dict>
75
95
  <key>captures</key>
76
96
  <dict>
77
97
  <key>1</key>
78
98
  <dict>
79
99
  <key>name</key>
80
- <string>punctuation.definition.entity.css</string>
100
+ <string>punctuation.definition.entity.stylus</string>
81
101
  </dict>
82
102
  </dict>
83
103
  <key>match</key>
@@ -91,6 +111,12 @@
91
111
  <key>name</key>
92
112
  <string>keyword.control.stylus</string>
93
113
  </dict>
114
+ <dict>
115
+ <key>match</key>
116
+ <string>((?:!|~|\+|-|(?:\*)?\*|\/|%|(?:\.)\.\.|&lt;|&gt;|(?:=|:|\?|\+|-|\*|\/|%|&lt;|&gt;)?=|!=)|(?:in|is(?:nt)?|not)\b)</string>
117
+ <key>name</key>
118
+ <string>keyword.operator.stylus</string>
119
+ </dict>
94
120
  <dict>
95
121
  <key>begin</key>
96
122
  <string>"</string>
@@ -123,12 +149,6 @@
123
149
  <key>name</key>
124
150
  <string>comment.block.js</string>
125
151
  </dict>
126
- <dict>
127
- <key>match</key>
128
- <string>(?:\b(\d+))|(#[a-fA-F0-9]+)</string>
129
- <key>name</key>
130
- <string>constant.numeric.stylus</string>
131
- </dict>
132
152
  <dict>
133
153
  <key>captures</key>
134
154
  <dict>
@@ -157,6 +177,46 @@
157
177
  <key>name</key>
158
178
  <string>meta.function.stylus</string>
159
179
  </dict>
180
+ <dict>
181
+ <key>comment</key>
182
+ <string>http://www.w3.org/TR/CSS21/syndata.html#value-def-color</string>
183
+ <key>match</key>
184
+ <string>\b(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow)\b</string>
185
+ <key>name</key>
186
+ <string>support.constant.color.w3c-standard-color-name.stylus</string>
187
+ </dict>
188
+ <dict>
189
+ <key>match</key>
190
+ <string>(\b(?i:arial|century|comic|courier|garamond|georgia|helvetica|impact|lucida|symbol|system|tahoma|times|trebuchet|utopia|verdana|webdings|sans-serif|serif|monospace)\b)</string>
191
+ <key>name</key>
192
+ <string>support.constant.font-name.stylus</string>
193
+ </dict>
194
+ <dict>
195
+ <key>captures</key>
196
+ <dict>
197
+ <key>1</key>
198
+ <dict>
199
+ <key>name</key>
200
+ <string>keyword.other.unit.stylus</string>
201
+ </dict>
202
+ </dict>
203
+ <key>match</key>
204
+ <string>(?x)
205
+ (?:-|\+)?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))
206
+ ((?:px|pt|ch|cm|mm|in|r?em|ex|pc|deg|g?rad|dpi|dpcm|s)\b|%)?</string>
207
+ <key>name</key>
208
+ <string>constant.numeric.stylus</string>
209
+ </dict>
210
+ <dict>
211
+ <key>match</key> <string>\b(azimuth|background-attachment|background-color|background-image|background-position|background-repeat|background|box-shadow|border-radius|border-bottom-color|border-bottom-style|border-bottom-width|border-bottom|border-collapse|border-color|border-left-color|border-left-style|border-left-width|border-left|border-right-color|border-right-style|border-right-width|border-right|border-spacing|border-style|border-top-color|border-top-style|border-top-width|border-top|border-width|border|bottom|caption-side|clear|clip|color|content|counter-increment|counter-reset|cue-after|cue-before|cue|cursor|direction|display|elevation|empty-cells|float|font-family|font-size-adjust|font-size|font-stretch|font-style|font-variant|font-weight|font|height|image-rendering|left|letter-spacing|line-height|list-style-image|list-style-position|list-style-type|list-style|margin-bottom|margin-left|margin-right|margin-top|marker-offset|margin|marks|max-height|max-width|min-height|min-width|-moz-border-radius|opacity|orphans|outline-color|outline-style|outline-width|outline|overflow(-[xy])?|padding-bottom|padding-left|padding-right|padding-top|padding|page-break-after|page-break-before|page-break-inside|page|pause-after|pause-before|pause|pitch-range|pitch|play-during|pointer-events|position|quotes|resize|richness|right|size|speak-header|speak-numeral|speak-punctuation|speech-rate|speak|src|stress|table-layout|text-(align|decoration|indent|rendering|shadow|transform)|top|transition|transform|unicode-bidi|vertical-align|visibility|voice-family|volume|white-space|widows|width|word-(spacing|wrap)|zoom|z-index)\b</string>
212
+ <key>name</key>
213
+ <string>support.type.property-name.stylus</string>
214
+ </dict>
215
+ <dict>
216
+ <key>match</key> <string>\b(absolute|all(-scroll)?|always|armenian|auto|avoid|baseline|below|bidi-override|block|bold|bolder|both|bottom|break-all|break-word|capitalize|center|char|circle|cjk-ideographic|col-resize|collapse|crosshair|dashed|decimal-leading-zero|decimal|default|disabled|disc|distribute-all-lines|distribute-letter|distribute-space|distribute|dotted|double|e-resize|ellipsis|fixed|geometricPrecision|georgian|groove|hand|hebrew|help|hidden|hiragana-iroha|hiragana|horizontal|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|inactive|inherit|inline-block|inline|inset|inside|inter-ideograph|inter-word|italic|justify|katakana-iroha|katakana|keep-all|left|lighter|line-edge|line-through|line|list-item|loose|lower-alpha|lower-greek|lower-latin|lower-roman|lowercase|lr-tb|ltr|medium|middle|move|n-resize|ne-resize|newspaper|no-drop|no-repeat|nw-resize|none|normal|not-allowed|nowrap|oblique|optimize(Legibility|Quality|Speed)|outset|outside|overline|pointer|pre(-(wrap|line))?|progress|relative|repeat-x|repeat-y|repeat|right|ridge|row-resize|rtl|s-resize|scroll|se-resize|separate|small-caps|solid|square|static|strict|sub|super|sw-resize|table-footer-group|table-header-group|tb-rl|text-bottom|text-top|text|thick|thin|top|transparent|underline|upper-alpha|upper-latin|upper-roman|uppercase|vertical(-(ideographic|text))?|visible(Painted|Fill|Stroke)?|w-resize|wait|whitespace|zero|smaller|larger|((xx?-)?(small|large))|painted|fill|stroke)\b</string>
217
+ <key>name</key>
218
+ <string>support.constant.property-value.stylus</string>
219
+ </dict>
160
220
  </array>
161
221
  <key>scopeName</key>
162
222
  <string>source.stylus</string>
@@ -128,6 +128,22 @@ spin(color, amount)
128
128
  last(expr)
129
129
  expr[length(expr) - 1]
130
130
 
131
+ // return keys in the given pairs
132
+
133
+ keys(pairs)
134
+ ret = ()
135
+ for pair in pairs
136
+ push(ret, pair[0]);
137
+ ret
138
+
139
+ // return values in the given pairs
140
+
141
+ values(pairs)
142
+ ret = ()
143
+ for pair in pairs
144
+ push(ret, pair[1]);
145
+ ret
146
+
131
147
  // join values with the given delimiter
132
148
 
133
149
  join(delim, vals...)
data/vendor/lib/lexer.js CHANGED
@@ -150,6 +150,7 @@ Lexer.prototype = {
150
150
  || this.urlchars()
151
151
  || this.atrule()
152
152
  || this.scope()
153
+ || this.extends()
153
154
  || this.media()
154
155
  || this.comment()
155
156
  || this.newline()
@@ -424,6 +425,18 @@ Lexer.prototype = {
424
425
  }
425
426
  },
426
427
 
428
+ /**
429
+ * '@extends' ([^{\n]+)
430
+ */
431
+
432
+ extends: function() {
433
+ var captures;
434
+ if (captures = /^@extends?[ \t]*([^\/{\n;]+)/.exec(this.str)) {
435
+ this.skip(captures);
436
+ return new Token('extend', captures[1].trim());
437
+ }
438
+ },
439
+
427
440
  /**
428
441
  * '@media' ([^{\n]+)
429
442
  */
@@ -0,0 +1,41 @@
1
+
2
+ /*!
3
+ * Stylus - Extend
4
+ * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
5
+ * MIT Licensed
6
+ */
7
+
8
+ /**
9
+ * Module dependencies.
10
+ */
11
+
12
+ var Node = require('./node');
13
+
14
+ /**
15
+ * Initialize a new `Extend` with the given `selector`.
16
+ *
17
+ * @param {Selector} selector
18
+ * @api public
19
+ */
20
+
21
+ var Extend = module.exports = function Extend(selector){
22
+ Node.call(this);
23
+ this.selector = selector;
24
+ };
25
+
26
+ /**
27
+ * Inherit from `Node.prototype`.
28
+ */
29
+
30
+ Extend.prototype.__proto__ = Node.prototype;
31
+
32
+ /**
33
+ * Return `@extend selector`.
34
+ *
35
+ * @return {String}
36
+ * @api public
37
+ */
38
+
39
+ Extend.prototype.toString = function(){
40
+ return '@extend ' + this.selector;
41
+ };
@@ -20,6 +20,7 @@ var Node = require('./node');
20
20
  var Group = module.exports = function Group(){
21
21
  Node.call(this);
22
22
  this.nodes = [];
23
+ this.extends = [];
23
24
  };
24
25
 
25
26
  /**
@@ -37,6 +37,7 @@ exports.Comment = require('./comment');
37
37
  exports.Keyframes = require('./keyframes');
38
38
  exports.Charset = require('./charset');
39
39
  exports.Import = require('./import');
40
+ exports.Extend = require('./extend');
40
41
  exports.Function = require('./function');
41
42
  exports.Property = require('./property');
42
43
  exports.Selector = require('./selector');
@@ -32,7 +32,7 @@ var Page = module.exports = function Page(selector, block){
32
32
  Page.prototype.__proto__ = Node.prototype;
33
33
 
34
34
  /**
35
- * Return `@oage name`.
35
+ * Return `@page name`.
36
36
  *
37
37
  * @return {String}
38
38
  * @api public
data/vendor/lib/parser.js CHANGED
@@ -515,6 +515,7 @@ Parser.prototype = {
515
515
  case 'literal':
516
516
  case 'charset':
517
517
  case 'import':
518
+ case 'extend':
518
519
  case 'media':
519
520
  case 'page':
520
521
  case 'ident':
@@ -692,6 +693,15 @@ Parser.prototype = {
692
693
  return nodes.null;
693
694
  },
694
695
 
696
+ /**
697
+ * extend
698
+ */
699
+
700
+ extend: function(){
701
+ var val = this.expect('extend').val;
702
+ return new nodes.Extend(val);
703
+ },
704
+
695
705
  /**
696
706
  * media
697
707
  */
@@ -12,6 +12,7 @@
12
12
  var Parser = require('./parser')
13
13
  , Compiler = require('./visitor/compiler')
14
14
  , Evaluator = require('./visitor/evaluator')
15
+ , Normalizer = require('./visitor/normalizer')
15
16
  , utils = require('./utils')
16
17
  , nodes = require('./nodes')
17
18
  , path = require('path')
@@ -47,12 +48,22 @@ Renderer.prototype.render = function(fn){
47
48
  var parser = this.parser = new Parser(this.str, this.options);
48
49
  try {
49
50
  nodes.filename = this.options.filename;
51
+ // parse
50
52
  var ast = parser.parse();
53
+
54
+ // evaluate
51
55
  this.evaluator = new Evaluator(ast, this.options);
52
56
  ast = this.evaluator.evaluate();
57
+
58
+ // normalize
59
+ var normalizer = new Normalizer(ast, this.options);
60
+ ast = normalizer.normalize();
61
+
62
+ // compile
53
63
  var compiler = new Compiler(ast, this.options)
54
64
  , css = compiler.compile()
55
65
  , js = compiler.js;
66
+
56
67
  fn(null, css, js);
57
68
  } catch (err) {
58
69
  var options = {};
@@ -130,6 +141,8 @@ Renderer.prototype.use = function(fn){
130
141
  */
131
142
 
132
143
  Renderer.prototype.define = function(name, fn, raw){
144
+ fn = utils.coerce(fn);
145
+
133
146
  if (fn.nodeName) {
134
147
  this.options.globals[name] = fn;
135
148
  return this;
data/vendor/lib/stylus.js CHANGED
@@ -24,7 +24,7 @@ exports = module.exports = render;
24
24
  * Library version.
25
25
  */
26
26
 
27
- exports.version = '0.21.2';
27
+ exports.version = '0.22.0';
28
28
 
29
29
  /**
30
30
  * Expose nodes.
data/vendor/lib/utils.js CHANGED
@@ -208,6 +208,72 @@ exports.unwrap = function(expr){
208
208
  return exports.unwrap(expr.nodes[0]);
209
209
  };
210
210
 
211
+ /**
212
+ * Coerce JavaScript values to their Stylus equivalents.
213
+ *
214
+ * @param {Mixed} val
215
+ * @return {Node}
216
+ * @api public
217
+ */
218
+
219
+ exports.coerce = function(val){
220
+ switch (typeof val) {
221
+ case 'function':
222
+ return val;
223
+ case 'string':
224
+ return new nodes.String(val);
225
+ case 'boolean':
226
+ return new nodes.Boolean(val);
227
+ case 'number':
228
+ return new nodes.Unit(val);
229
+ default:
230
+ if (null == val) return nodes.null;
231
+ if (Array.isArray(val)) return exports.coerceArray(val);
232
+ if (val.nodeName) return val;
233
+ return exports.coerceObject(val);
234
+ }
235
+ };
236
+
237
+ /**
238
+ * Coerce a javascript `Array` to a Stylus `Expression`.
239
+ *
240
+ * @param {Array} val
241
+ * @return {Expression}
242
+ * @api private
243
+ */
244
+
245
+ exports.coerceArray = function(val){
246
+ var expr = new nodes.Expression;
247
+ val.forEach(function(val){
248
+ expr.push(exports.coerce(val));
249
+ });
250
+ return expr;
251
+ };
252
+
253
+ /**
254
+ * Coerce a javascript object to a Stylus `Expression`.
255
+ *
256
+ * For example `{ foo: 'bar', bar: 'baz' }` would become
257
+ * the expression `(foo 'bar') (bar 'baz')`.
258
+ *
259
+ * @param {Object} obj
260
+ * @return {Expression}
261
+ * @api public
262
+ */
263
+
264
+ exports.coerceObject = function(obj){
265
+ var expr = new nodes.Expression
266
+ , val;
267
+
268
+ for (var key in obj) {
269
+ val = exports.coerce(obj[key]);
270
+ key = new nodes.Ident(key);
271
+ expr.push(exports.coerceArray([key, val]));
272
+ }
273
+
274
+ return expr;
275
+ };
276
+
211
277
  /**
212
278
  * Return param names for `fn`.
213
279
  *
@@ -34,7 +34,7 @@ var Compiler = module.exports = function Compiler(root, options) {
34
34
  this.spaces = options['indent spaces'] || 2;
35
35
  this.indents = 1;
36
36
  Visitor.call(this, root);
37
- this.tree = [];
37
+ this.stack = [];
38
38
  this.js = '';
39
39
  };
40
40
 
@@ -75,18 +75,9 @@ Compiler.prototype.visitRoot = function(block){
75
75
  this.buf = '';
76
76
  for (var i = 0, len = block.nodes.length; i < len; ++i) {
77
77
  var node = block.nodes[i];
78
- switch (node.nodeName) {
79
- case 'null':
80
- case 'expression':
81
- case 'function':
82
- case 'jsliteral':
83
- case 'unit':
84
- continue;
85
- default:
86
- if (this.linenos || this.firebug) this.debugInfo(node);
87
- var ret = this.visit(node);
88
- if (ret) this.buf += ret + '\n';
89
- }
78
+ if (this.linenos || this.firebug) this.debugInfo(node);
79
+ var ret = this.visit(node);
80
+ if (ret) this.buf += ret + '\n';
90
81
  }
91
82
  return this.buf;
92
83
  };
@@ -310,61 +301,19 @@ Compiler.prototype.visitUnit = function(unit){
310
301
  */
311
302
 
312
303
  Compiler.prototype.visitGroup = function(group){
313
- var self = this
314
- , tree = this.tree
315
- , prev = tree[tree.length - 1]
316
- , curr = [];
317
-
318
- // Construct an array of arrays
319
- // representing the selector hierarchy
320
- group.nodes.forEach(function(node){
321
- curr.push(node.parent
322
- ? node
323
- : node.val);
324
- });
304
+ var stack = this.stack;
325
305
 
326
- tree.push(curr);
306
+ stack.push(group.nodes);
327
307
 
328
- // Reverse recurse the
329
- // hierarchy array to build
330
- // up the selector combinations.
331
- // When we reach root, we have our
332
- // selector string built
333
- var selectors = []
334
- , buf = [];
335
- function join(arr, i) {
336
- if (i) {
337
- arr[i].forEach(function(str){
338
- buf.unshift(str);
339
- join(arr, i - 1);
340
- buf.shift();
341
- });
342
- } else {
343
- arr[0].forEach(function(selector){
344
- var str = selector.trim();
345
- if (buf.length) {
346
- for (var i = 0, len = buf.length; i < len; ++i) {
347
- if (~buf[i].indexOf('&')) {
348
- str = buf[i].replace(/&/g, str).trim();
349
- } else {
350
- str += ' ' + buf[i].trim();
351
- }
352
- }
353
- }
354
- selectors.push(self.indent + str.trimRight());
355
- });
356
- }
357
- }
358
-
359
- // Join selectors
308
+ // selectors
360
309
  if (group.block.hasProperties) {
361
- join(tree, tree.length - 1);
310
+ var selectors = this.compileSelectors(stack);
362
311
  this.buf += (this.selector = selectors.join(this.compress ? ',' : ',\n'));
363
312
  }
364
313
 
365
- // Output blocks
314
+ // output block
366
315
  this.visit(group.block);
367
- tree.pop();
316
+ stack.pop();
368
317
  };
369
318
 
370
319
  /**
@@ -450,6 +399,61 @@ Compiler.prototype.visitProperty = function(prop){
450
399
  : ';');
451
400
  };
452
401
 
402
+ /**
403
+ * Compile selector strings in `arr` from the bottom-up
404
+ * to produce the selector combinations. For example
405
+ * the following Stylus:
406
+ *
407
+ * ul
408
+ * li
409
+ * p
410
+ * a
411
+ * color: red
412
+ *
413
+ * Would return:
414
+ *
415
+ * [ 'ul li a', 'ul p a' ]
416
+ *
417
+ * @param {Array} arr
418
+ * @return {Array}
419
+ * @api private
420
+ */
421
+
422
+ Compiler.prototype.compileSelectors = function(arr){
423
+ var stack = this.stack
424
+ , self = this
425
+ , selectors = []
426
+ , buf = [];
427
+
428
+ function compile(arr, i) {
429
+ if (i) {
430
+ arr[i].forEach(function(selector){
431
+ buf.unshift(selector.val);
432
+ compile(arr, i - 1);
433
+ buf.shift();
434
+ });
435
+ } else {
436
+ arr[0].forEach(function(selector){
437
+ var str = selector.val.trim();
438
+ if (buf.length) {
439
+ for (var i = 0, len = buf.length; i < len; ++i) {
440
+ if (~buf[i].indexOf('&')) {
441
+ str = buf[i].replace(/&/g, str).trim();
442
+ } else {
443
+ str += ' ' + buf[i].trim();
444
+ }
445
+ }
446
+ }
447
+ selectors.push(self.indent + str.trimRight());
448
+ });
449
+ }
450
+ }
451
+
452
+ compile(arr, arr.length - 1);
453
+
454
+ return selectors;
455
+ };
456
+
453
457
  /**
454
458
  * Debug info.
455
459
  */