less 2.5.1 → 2.6.0

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +5 -1
  3. data/README.md +12 -0
  4. data/lib/less/js/.travis.yml +8 -0
  5. data/lib/less/js/CHANGELOG.md +22 -0
  6. data/lib/less/js/CONTRIBUTING.md +1 -1
  7. data/lib/less/js/Gruntfile.js +8 -0
  8. data/lib/less/js/README.md +5 -304
  9. data/lib/less/js/bin/lessc +16 -13
  10. data/lib/less/js/bower.json +2 -2
  11. data/lib/less/js/build/README.md +4 -303
  12. data/lib/less/js/build/build.yml +2 -0
  13. data/lib/less/js/dist/less-1.6.3.js +7627 -0
  14. data/lib/less/js/dist/less-1.6.3.min.js +16 -0
  15. data/lib/less/js/dist/less-1.7.0.js +7921 -0
  16. data/lib/less/js/dist/less-1.7.0.min.js +16 -0
  17. data/lib/less/js/dist/less-rhino-1.6.3.js +9020 -0
  18. data/lib/less/js/dist/less-rhino-1.7.0.js +9301 -0
  19. data/lib/less/js/dist/lessc-rhino-1.6.3.js +449 -0
  20. data/lib/less/js/dist/lessc-rhino-1.7.0.js +449 -0
  21. data/lib/less/js/lib/less/browser.js +22 -9
  22. data/lib/less/js/lib/less/functions.js +47 -16
  23. data/lib/less/js/lib/less/import-visitor.js +29 -5
  24. data/lib/less/js/lib/less/index.js +10 -3
  25. data/lib/less/js/lib/less/parser.js +139 -52
  26. data/lib/less/js/lib/less/to-css-visitor.js +26 -4
  27. data/lib/less/js/lib/less/tree/color.js +11 -1
  28. data/lib/less/js/lib/less/tree/detached-ruleset.js +20 -0
  29. data/lib/less/js/lib/less/tree/dimension.js +17 -6
  30. data/lib/less/js/lib/less/tree/directive.js +33 -29
  31. data/lib/less/js/lib/less/tree/import.js +8 -1
  32. data/lib/less/js/lib/less/tree/keyword.js +1 -0
  33. data/lib/less/js/lib/less/tree/media.js +3 -0
  34. data/lib/less/js/lib/less/tree/mixin.js +15 -11
  35. data/lib/less/js/lib/less/tree/rule.js +14 -4
  36. data/lib/less/js/lib/less/tree/ruleset-call.js +16 -0
  37. data/lib/less/js/lib/less/tree/ruleset.js +48 -19
  38. data/lib/less/js/package.json +13 -13
  39. data/lib/less/js/test/browser/css/postProcessor/postProcessor.css +4 -0
  40. data/lib/less/js/test/browser/less/postProcessor/postProcessor.less +4 -0
  41. data/lib/less/js/test/browser/runner-postProcessor-options.js +4 -0
  42. data/lib/less/js/test/browser/runner-postProcessor.js +3 -0
  43. data/lib/less/js/test/css/debug/linenumbers-all.css +2 -2
  44. data/lib/less/js/test/css/debug/linenumbers-comments.css +1 -1
  45. data/lib/less/js/test/css/debug/linenumbers-mediaquery.css +1 -1
  46. data/lib/less/js/test/css/detached-rulesets.css +71 -0
  47. data/lib/less/js/test/css/functions.css +21 -4
  48. data/lib/less/js/test/css/import-reference.css +23 -4
  49. data/lib/less/js/test/css/merge.css +8 -0
  50. data/lib/less/js/test/css/mixins-pattern.css +4 -0
  51. data/lib/less/js/test/css/scope.css +3 -0
  52. data/lib/less/js/test/css/variables-in-at-rules.css +18 -0
  53. data/lib/less/js/test/less/css-guards.less +3 -0
  54. data/lib/less/js/test/less/detached-rulesets.less +103 -0
  55. data/lib/less/js/test/less/errors/at-rules-undefined-var.less +4 -0
  56. data/lib/less/js/test/less/errors/at-rules-undefined-var.txt +4 -0
  57. data/lib/less/js/test/less/errors/detached-ruleset-1.less +6 -0
  58. data/lib/less/js/test/less/errors/detached-ruleset-1.txt +4 -0
  59. data/lib/less/js/test/less/errors/detached-ruleset-2.less +6 -0
  60. data/lib/less/js/test/less/errors/detached-ruleset-2.txt +4 -0
  61. data/lib/less/js/test/less/errors/detached-ruleset-3.less +4 -0
  62. data/lib/less/js/test/less/errors/detached-ruleset-3.txt +4 -0
  63. data/lib/less/js/test/less/errors/detached-ruleset-4.less +5 -0
  64. data/lib/less/js/test/less/errors/detached-ruleset-4.txt +3 -0
  65. data/lib/less/js/test/less/errors/detached-ruleset-5.less +4 -0
  66. data/lib/less/js/test/less/errors/detached-ruleset-5.txt +3 -0
  67. data/lib/less/js/test/less/errors/detached-ruleset-6.less +5 -0
  68. data/lib/less/js/test/less/errors/detached-ruleset-6.txt +4 -0
  69. data/lib/less/js/test/less/errors/mixin-not-visible-in-scope-1.less +9 -0
  70. data/lib/less/js/test/less/errors/mixin-not-visible-in-scope-1.txt +4 -0
  71. data/lib/less/js/test/less/errors/percentage-missing-space.less +3 -0
  72. data/lib/less/js/test/less/errors/percentage-missing-space.txt +4 -0
  73. data/lib/less/js/test/less/functions.less +25 -7
  74. data/lib/less/js/test/less/import-reference.less +7 -4
  75. data/lib/less/js/test/less/import/import-reference.less +8 -0
  76. data/lib/less/js/test/less/merge.less +20 -1
  77. data/lib/less/js/test/less/mixins-guards.less +7 -1
  78. data/lib/less/js/test/less/mixins-pattern.less +3 -0
  79. data/lib/less/js/test/less/scope.less +25 -0
  80. data/lib/less/js/test/less/variables-in-at-rules.less +20 -0
  81. data/lib/less/version.rb +1 -1
  82. metadata +39 -2
@@ -202,14 +202,36 @@
202
202
  }
203
203
 
204
204
  Object.keys(groups).map(function (k) {
205
+
206
+ function toExpression(values) {
207
+ return new (tree.Expression)(values.map(function (p) {
208
+ return p.value;
209
+ }));
210
+ }
211
+
212
+ function toValue(values) {
213
+ return new (tree.Value)(values.map(function (p) {
214
+ return p;
215
+ }));
216
+ }
217
+
205
218
  parts = groups[k];
206
219
 
207
220
  if (parts.length > 1) {
208
221
  rule = parts[0];
209
-
210
- rule.value = new (tree.Value)(parts.map(function (p) {
211
- return p.value;
212
- }));
222
+ var spacedGroups = [];
223
+ var lastSpacedGroup = [];
224
+ parts.map(function (p) {
225
+ if (p.merge==="+") {
226
+ if (lastSpacedGroup.length > 0) {
227
+ spacedGroups.push(toExpression(lastSpacedGroup));
228
+ }
229
+ lastSpacedGroup = [];
230
+ }
231
+ lastSpacedGroup.push(p);
232
+ });
233
+ spacedGroups.push(toExpression(lastSpacedGroup));
234
+ rule.value = toValue(spacedGroups);
213
235
  }
214
236
  });
215
237
  }
@@ -28,7 +28,17 @@ var transparentKeyword = "transparent";
28
28
  tree.Color.prototype = {
29
29
  type: "Color",
30
30
  eval: function () { return this; },
31
- luma: function () { return (0.2126 * this.rgb[0] / 255) + (0.7152 * this.rgb[1] / 255) + (0.0722 * this.rgb[2] / 255); },
31
+ luma: function () {
32
+ var r = this.rgb[0] / 255,
33
+ g = this.rgb[1] / 255,
34
+ b = this.rgb[2] / 255;
35
+
36
+ r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4);
37
+ g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4);
38
+ b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4);
39
+
40
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
41
+ },
32
42
 
33
43
  genCSS: function (env, output) {
34
44
  output.add(this.toCSS(env));
@@ -0,0 +1,20 @@
1
+ (function (tree) {
2
+
3
+ tree.DetachedRuleset = function (ruleset, frames) {
4
+ this.ruleset = ruleset;
5
+ this.frames = frames;
6
+ };
7
+ tree.DetachedRuleset.prototype = {
8
+ type: "DetachedRuleset",
9
+ accept: function (visitor) {
10
+ this.ruleset = visitor.visit(this.ruleset);
11
+ },
12
+ eval: function (env) {
13
+ var frames = this.frames || env.frames.slice(0);
14
+ return new tree.DetachedRuleset(this.ruleset, frames);
15
+ },
16
+ callEval: function (env) {
17
+ return this.ruleset.eval(this.frames ? new(tree.evalEnv)(env, this.frames.concat(env.frames)) : env);
18
+ }
19
+ };
20
+ })(require('../tree'));
@@ -89,17 +89,27 @@ tree.Dimension.prototype = {
89
89
 
90
90
  compare: function (other) {
91
91
  if (other instanceof tree.Dimension) {
92
- var a = this.unify(), b = other.unify(),
93
- aValue = a.value, bValue = b.value;
92
+ var a, b,
93
+ aValue, bValue;
94
+
95
+ if (this.unit.isEmpty() || other.unit.isEmpty()) {
96
+ a = this;
97
+ b = other;
98
+ } else {
99
+ a = this.unify();
100
+ b = other.unify();
101
+ if (a.unit.compare(b.unit) !== 0) {
102
+ return -1;
103
+ }
104
+ }
105
+ aValue = a.value;
106
+ bValue = b.value;
94
107
 
95
108
  if (bValue > aValue) {
96
109
  return -1;
97
110
  } else if (bValue < aValue) {
98
111
  return 1;
99
112
  } else {
100
- if (!b.unit.isEmpty() && a.unit.compare(b.unit) !== 0) {
101
- return -1;
102
- }
103
113
  return 0;
104
114
  }
105
115
  } else {
@@ -108,7 +118,7 @@ tree.Dimension.prototype = {
108
118
  },
109
119
 
110
120
  unify: function () {
111
- return this.convertTo({ length: 'm', duration: 's', angle: 'rad' });
121
+ return this.convertTo({ length: 'px', duration: 's', angle: 'rad' });
112
122
  },
113
123
 
114
124
  convertTo: function (conversions) {
@@ -161,6 +171,7 @@ tree.UnitConversions = {
161
171
  'cm': 0.01,
162
172
  'mm': 0.001,
163
173
  'in': 0.0254,
174
+ 'px': 0.0254 / 96,
164
175
  'pt': 0.0254 / 72,
165
176
  'pc': 0.0254 / 72 * 12
166
177
  },
@@ -1,58 +1,62 @@
1
1
  (function (tree) {
2
2
 
3
- tree.Directive = function (name, value, index, currentFileInfo) {
4
- this.name = name;
5
-
6
- if (Array.isArray(value)) {
7
- this.rules = [new(tree.Ruleset)(null, value)];
8
- this.rules[0].allowImports = true;
9
- } else {
10
- this.value = value;
3
+ tree.Directive = function (name, value, rules, index, currentFileInfo, debugInfo) {
4
+ this.name = name;
5
+ this.value = value;
6
+ if (rules) {
7
+ this.rules = rules;
8
+ this.rules.allowImports = true;
11
9
  }
12
10
  this.index = index;
13
11
  this.currentFileInfo = currentFileInfo;
14
-
12
+ this.debugInfo = debugInfo;
15
13
  };
14
+
16
15
  tree.Directive.prototype = {
17
16
  type: "Directive",
18
17
  accept: function (visitor) {
19
- if (this.rules) {
20
- this.rules = visitor.visitArray(this.rules);
18
+ var value = this.value, rules = this.rules;
19
+ if (rules) {
20
+ rules = visitor.visit(rules);
21
21
  }
22
- if (this.value) {
23
- this.value = visitor.visit(this.value);
22
+ if (value) {
23
+ value = visitor.visit(value);
24
24
  }
25
25
  },
26
26
  genCSS: function (env, output) {
27
+ var value = this.value, rules = this.rules;
27
28
  output.add(this.name, this.currentFileInfo, this.index);
28
- if (this.rules) {
29
- tree.outputRuleset(env, output, this.rules);
30
- } else {
29
+ if (value) {
31
30
  output.add(' ');
32
- this.value.genCSS(env, output);
31
+ value.genCSS(env, output);
32
+ }
33
+ if (rules) {
34
+ tree.outputRuleset(env, output, [rules]);
35
+ } else {
33
36
  output.add(';');
34
37
  }
35
38
  },
36
39
  toCSS: tree.toCSS,
37
40
  eval: function (env) {
38
- var evaldDirective = this;
39
- if (this.rules) {
40
- env.frames.unshift(this);
41
- evaldDirective = new(tree.Directive)(this.name, null, this.index, this.currentFileInfo);
42
- evaldDirective.rules = [this.rules[0].eval(env)];
43
- evaldDirective.rules[0].root = true;
44
- env.frames.shift();
41
+ var value = this.value, rules = this.rules;
42
+ if (value) {
43
+ value = value.eval(env);
44
+ }
45
+ if (rules) {
46
+ rules = rules.eval(env);
47
+ rules.root = true;
45
48
  }
46
- return evaldDirective;
49
+ return new(tree.Directive)(this.name, value, rules,
50
+ this.index, this.currentFileInfo, this.debugInfo);
47
51
  },
48
- variable: function (name) { return tree.Ruleset.prototype.variable.call(this.rules[0], name); },
49
- find: function () { return tree.Ruleset.prototype.find.apply(this.rules[0], arguments); },
50
- rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.rules[0]); },
52
+ variable: function (name) { if (this.rules) return tree.Ruleset.prototype.variable.call(this.rules, name); },
53
+ find: function () { if (this.rules) return tree.Ruleset.prototype.find.apply(this.rules, arguments); },
54
+ rulesets: function () { if (this.rules) return tree.Ruleset.prototype.rulesets.apply(this.rules); },
51
55
  markReferenced: function () {
52
56
  var i, rules;
53
57
  this.isReferenced = true;
54
58
  if (this.rules) {
55
- rules = this.rules[0].rules;
59
+ rules = this.rules.rules;
56
60
  for (i = 0; i < rules.length; i++) {
57
61
  if (rules[i].markReferenced) {
58
62
  rules[i].markReferenced();
@@ -92,7 +92,14 @@ tree.Import.prototype = {
92
92
  eval: function (env) {
93
93
  var ruleset, features = this.features && this.features.eval(env);
94
94
 
95
- if (this.skip) { return []; }
95
+ if (this.skip) {
96
+ if (typeof this.skip === "function") {
97
+ this.skip = this.skip();
98
+ }
99
+ if (this.skip) {
100
+ return [];
101
+ }
102
+ }
96
103
 
97
104
  if (this.options.inline) {
98
105
  //todo needs to reference css file not import
@@ -5,6 +5,7 @@ tree.Keyword.prototype = {
5
5
  type: "Keyword",
6
6
  eval: function () { return this; },
7
7
  genCSS: function (env, output) {
8
+ if (this.value === '%') { throw { type: "Syntax", message: "Invalid % without number" }; }
8
9
  output.add(this.value);
9
10
  },
10
11
  toCSS: tree.toCSS,
@@ -74,6 +74,7 @@ tree.Media.prototype = {
74
74
  },
75
75
  markReferenced: function () {
76
76
  var i, rules = this.rules[0].rules;
77
+ this.rules[0].markReferenced();
77
78
  this.isReferenced = true;
78
79
  for (i = 0; i < rules.length; i++) {
79
80
  if (rules[i].markReferenced) {
@@ -147,6 +148,8 @@ tree.Media.prototype = {
147
148
  }
148
149
  },
149
150
  bubbleSelectors: function (selectors) {
151
+ if (!selectors)
152
+ return;
150
153
  this.rules = [new(tree.Ruleset)(selectors.slice(0), [this.rules[0]])];
151
154
  }
152
155
  };
@@ -103,7 +103,7 @@ tree.mixin.Call.prototype = {
103
103
  mixin.originalRuleset = mixins[m].originalRuleset || mixins[m];
104
104
  }
105
105
  Array.prototype.push.apply(
106
- rules, mixin.eval(env, args, this.important).rules);
106
+ rules, mixin.evalCall(env, args, this.important).rules);
107
107
  } catch (e) {
108
108
  throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack };
109
109
  }
@@ -150,7 +150,7 @@ tree.mixin.Call.prototype = {
150
150
  }
151
151
  };
152
152
 
153
- tree.mixin.Definition = function (name, params, rules, condition, variadic) {
153
+ tree.mixin.Definition = function (name, params, rules, condition, variadic, frames) {
154
154
  this.name = name;
155
155
  this.selectors = [new(tree.Selector)([new(tree.Element)(null, name, this.index, this.currentFileInfo)])];
156
156
  this.params = params;
@@ -164,7 +164,7 @@ tree.mixin.Definition = function (name, params, rules, condition, variadic) {
164
164
  else { return count; }
165
165
  }, 0);
166
166
  this.parent = tree.Ruleset.prototype;
167
- this.frames = [];
167
+ this.frames = frames;
168
168
  };
169
169
  tree.mixin.Definition.prototype = {
170
170
  type: "MixinDefinition",
@@ -187,14 +187,15 @@ tree.mixin.Definition.prototype = {
187
187
  var frame = new(tree.Ruleset)(null, null),
188
188
  varargs, arg,
189
189
  params = this.params.slice(0),
190
- i, j, val, name, isNamedFound, argIndex;
190
+ i, j, val, name, isNamedFound, argIndex, argsLength = 0;
191
191
 
192
192
  mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames));
193
193
 
194
194
  if (args) {
195
195
  args = args.slice(0);
196
+ argsLength = args.length;
196
197
 
197
- for(i = 0; i < args.length; i++) {
198
+ for(i = 0; i < argsLength; i++) {
198
199
  arg = args[i];
199
200
  if (name = (arg && arg.name)) {
200
201
  isNamedFound = false;
@@ -224,9 +225,9 @@ tree.mixin.Definition.prototype = {
224
225
  arg = args && args[argIndex];
225
226
 
226
227
  if (name = params[i].name) {
227
- if (params[i].variadic && args) {
228
+ if (params[i].variadic) {
228
229
  varargs = [];
229
- for (j = argIndex; j < args.length; j++) {
230
+ for (j = argIndex; j < argsLength; j++) {
230
231
  varargs.push(args[j].value.eval(env));
231
232
  }
232
233
  frame.prependRule(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
@@ -239,7 +240,7 @@ tree.mixin.Definition.prototype = {
239
240
  frame.resetCache();
240
241
  } else {
241
242
  throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
242
- ' (' + args.length + ' for ' + this.arity + ')' };
243
+ ' (' + argsLength + ' for ' + this.arity + ')' };
243
244
  }
244
245
 
245
246
  frame.prependRule(new(tree.Rule)(name, val));
@@ -248,7 +249,7 @@ tree.mixin.Definition.prototype = {
248
249
  }
249
250
 
250
251
  if (params[i].variadic && args) {
251
- for (j = argIndex; j < args.length; j++) {
252
+ for (j = argIndex; j < argsLength; j++) {
252
253
  evaldArguments[j] = args[j].value.eval(env);
253
254
  }
254
255
  }
@@ -257,9 +258,12 @@ tree.mixin.Definition.prototype = {
257
258
 
258
259
  return frame;
259
260
  },
260
- eval: function (env, args, important) {
261
+ eval: function (env) {
262
+ return new tree.mixin.Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || env.frames.slice(0));
263
+ },
264
+ evalCall: function (env, args, important) {
261
265
  var _arguments = [],
262
- mixinFrames = this.frames.concat(env.frames),
266
+ mixinFrames = this.frames ? this.frames.concat(env.frames) : env.frames,
263
267
  frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments),
264
268
  rules, ruleset;
265
269
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  tree.Rule = function (name, value, important, merge, index, currentFileInfo, inline) {
4
4
  this.name = name;
5
- this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
5
+ this.value = (value instanceof tree.Value || value instanceof tree.Ruleset) ? value : new(tree.Value)([value]);
6
6
  this.important = important ? ' ' + important.trim() : '';
7
7
  this.merge = merge;
8
8
  this.index = index;
@@ -30,7 +30,7 @@ tree.Rule.prototype = {
30
30
  },
31
31
  toCSS: tree.toCSS,
32
32
  eval: function (env) {
33
- var strictMathBypass = false, name = this.name;
33
+ var strictMathBypass = false, name = this.name, evaldValue;
34
34
  if (typeof name !== "string") {
35
35
  // expand 'primitive' name directly to get
36
36
  // things faster (~10% for benchmark.less):
@@ -43,14 +43,24 @@ tree.Rule.prototype = {
43
43
  env.strictMath = true;
44
44
  }
45
45
  try {
46
+ evaldValue = this.value.eval(env);
47
+
48
+ if (!this.variable && evaldValue.type === "DetachedRuleset") {
49
+ throw { message: "Rulesets cannot be evaluated on a property.",
50
+ index: this.index, filename: this.currentFileInfo.filename };
51
+ }
52
+
46
53
  return new(tree.Rule)(name,
47
- this.value.eval(env),
54
+ evaldValue,
48
55
  this.important,
49
56
  this.merge,
50
57
  this.index, this.currentFileInfo, this.inline);
51
58
  }
52
59
  catch(e) {
53
- e.index = e.index || this.index;
60
+ if (typeof e.index !== 'number') {
61
+ e.index = this.index;
62
+ e.filename = this.currentFileInfo.filename;
63
+ }
54
64
  throw e;
55
65
  }
56
66
  finally {
@@ -0,0 +1,16 @@
1
+ (function (tree) {
2
+
3
+ tree.RulesetCall = function (variable) {
4
+ this.variable = variable;
5
+ };
6
+ tree.RulesetCall.prototype = {
7
+ type: "RulesetCall",
8
+ accept: function (visitor) {
9
+ },
10
+ eval: function (env) {
11
+ var detachedRuleset = new(tree.Variable)(this.variable).eval(env);
12
+ return detachedRuleset.callEval(env);
13
+ }
14
+ };
15
+
16
+ })(require('../tree'));
@@ -20,7 +20,8 @@ tree.Ruleset.prototype = {
20
20
  },
21
21
  eval: function (env) {
22
22
  var thisSelectors = this.selectors, selectors,
23
- selCnt, i, defaultFunc = tree.defaultFunc;
23
+ selCnt, selector, i, defaultFunc = tree.defaultFunc, hasOnePassingSelector = false;
24
+
24
25
  if (thisSelectors && (selCnt = thisSelectors.length)) {
25
26
  selectors = [];
26
27
  defaultFunc.error({
@@ -28,9 +29,15 @@ tree.Ruleset.prototype = {
28
29
  message: "it is currently only allowed in parametric mixin guards,"
29
30
  });
30
31
  for (i = 0; i < selCnt; i++) {
31
- selectors.push(thisSelectors[i].eval(env));
32
+ selector = thisSelectors[i].eval(env);
33
+ selectors.push(selector);
34
+ if (selector.evaldCondition) {
35
+ hasOnePassingSelector = true;
36
+ }
32
37
  }
33
38
  defaultFunc.reset();
39
+ } else {
40
+ hasOnePassingSelector = true;
34
41
  }
35
42
 
36
43
  var rules = this.rules ? this.rules.slice(0) : null,
@@ -45,6 +52,10 @@ tree.Ruleset.prototype = {
45
52
  if(this.debugInfo) {
46
53
  ruleset.debugInfo = this.debugInfo;
47
54
  }
55
+
56
+ if (!hasOnePassingSelector) {
57
+ rules.length = 0;
58
+ }
48
59
 
49
60
  // push the current ruleset to the frames stack
50
61
  var envFrames = env.frames;
@@ -66,8 +77,8 @@ tree.Ruleset.prototype = {
66
77
  // so they can be evaluated like closures when the time comes.
67
78
  var rsRules = ruleset.rules, rsRuleCnt = rsRules ? rsRules.length : 0;
68
79
  for (i = 0; i < rsRuleCnt; i++) {
69
- if (rsRules[i] instanceof tree.mixin.Definition) {
70
- rsRules[i].frames = envFrames.slice(0);
80
+ if (rsRules[i] instanceof tree.mixin.Definition || rsRules[i] instanceof tree.DetachedRuleset) {
81
+ rsRules[i] = rsRules[i].eval(env);
71
82
  }
72
83
  }
73
84
 
@@ -90,28 +101,43 @@ tree.Ruleset.prototype = {
90
101
  rsRuleCnt += rules.length - 1;
91
102
  i += rules.length-1;
92
103
  ruleset.resetCache();
104
+ } else if (rsRules[i] instanceof tree.RulesetCall) {
105
+ /*jshint loopfunc:true */
106
+ rules = rsRules[i].eval(env).rules.filter(function(r) {
107
+ if ((r instanceof tree.Rule) && r.variable) {
108
+ // do not pollute the scope at all
109
+ return false;
110
+ }
111
+ return true;
112
+ });
113
+ rsRules.splice.apply(rsRules, [i, 1].concat(rules));
114
+ rsRuleCnt += rules.length - 1;
115
+ i += rules.length-1;
116
+ ruleset.resetCache();
93
117
  }
94
118
  }
95
119
 
96
120
  // Evaluate everything else
97
121
  for (i = 0; i < rsRules.length; i++) {
98
122
  rule = rsRules[i];
99
- if (! (rule instanceof tree.mixin.Definition)) {
123
+ if (! (rule instanceof tree.mixin.Definition || rule instanceof tree.DetachedRuleset)) {
100
124
  rsRules[i] = rule = rule.eval ? rule.eval(env) : rule;
101
- // for rulesets, check if it is a css guard and can be removed
102
- if (rule instanceof tree.Ruleset && rule.selectors && rule.selectors.length === 1) {
103
- // check if it can be folded in (e.g. & where)
104
- if (rule.selectors[0].isJustParentSelector()) {
105
- rsRules.splice(i--, 1);
106
- // cannot call if there is no selector, so we can just continue
107
- if (!rule.selectors[0].evaldCondition) {
108
- continue;
109
- }
110
- for(var j = 0; j < rule.rules.length; j++) {
111
- subRule = rule.rules[j];
112
- if (!(subRule instanceof tree.Rule) || !subRule.variable) {
113
- rsRules.splice(++i, 0, subRule);
114
- }
125
+ }
126
+ }
127
+
128
+ // Evaluate everything else
129
+ for (i = 0; i < rsRules.length; i++) {
130
+ rule = rsRules[i];
131
+ // for rulesets, check if it is a css guard and can be removed
132
+ if (rule instanceof tree.Ruleset && rule.selectors && rule.selectors.length === 1) {
133
+ // check if it can be folded in (e.g. & where)
134
+ if (rule.selectors[0].isJustParentSelector()) {
135
+ rsRules.splice(i--, 1);
136
+
137
+ for(var j = 0; j < rule.rules.length; j++) {
138
+ subRule = rule.rules[j];
139
+ if (!(subRule instanceof tree.Rule) || !subRule.variable) {
140
+ rsRules.splice(++i, 0, subRule);
115
141
  }
116
142
  }
117
143
  }
@@ -345,6 +371,9 @@ tree.Ruleset.prototype = {
345
371
  toCSS: tree.toCSS,
346
372
 
347
373
  markReferenced: function () {
374
+ if (!this.selectors) {
375
+ return;
376
+ }
348
377
  for (var s = 0; s < this.selectors.length; s++) {
349
378
  this.selectors[s].markReferenced();
350
379
  }