less 2.3.3 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +5 -0
  3. data/less.gemspec +1 -1
  4. data/lib/less/js/.gitattributes +9 -0
  5. data/lib/less/js/.gitignore +1 -0
  6. data/lib/less/js/.npmignore +1 -1
  7. data/lib/less/js/CHANGELOG.md +68 -0
  8. data/lib/less/js/CONTRIBUTING.md +33 -34
  9. data/lib/less/js/Makefile +24 -9
  10. data/lib/less/js/README.md +2 -2
  11. data/lib/less/js/bin/lessc +102 -25
  12. data/lib/less/js/build/amd.js +1 -1
  13. data/lib/less/js/build/header.js +9 -7
  14. data/lib/less/js/dist/less-1.3.3.js +2 -2
  15. data/lib/less/js/dist/less-1.3.3.min.js +2 -2
  16. data/lib/less/js/dist/less-1.4.0-beta.js +5830 -0
  17. data/lib/less/js/dist/less-1.4.0-beta.min.js +11 -0
  18. data/lib/less/js/dist/less-1.4.0.js +5830 -0
  19. data/lib/less/js/dist/less-1.4.0.min.js +11 -0
  20. data/lib/less/js/dist/less-1.4.1.js +5837 -0
  21. data/lib/less/js/dist/less-1.4.1.min.js +11 -0
  22. data/lib/less/js/dist/less-1.4.2.js +5837 -0
  23. data/lib/less/js/dist/less-1.4.2.min.js +11 -0
  24. data/lib/less/js/dist/less-rhino-1.4.0.js +4273 -0
  25. data/lib/less/js/lib/less/browser.js +131 -101
  26. data/lib/less/js/lib/less/env.js +105 -0
  27. data/lib/less/js/lib/less/extend-visitor.js +391 -0
  28. data/lib/less/js/lib/less/functions.js +174 -19
  29. data/lib/less/js/lib/less/import-visitor.js +107 -0
  30. data/lib/less/js/lib/less/index.js +70 -63
  31. data/lib/less/js/lib/less/join-selector-visitor.js +37 -0
  32. data/lib/less/js/lib/less/lessc_helper.js +13 -4
  33. data/lib/less/js/lib/less/parser.js +353 -264
  34. data/lib/less/js/lib/less/rhino.js +5 -2
  35. data/lib/less/js/lib/less/tree.js +1 -1
  36. data/lib/less/js/lib/less/tree/alpha.js +7 -3
  37. data/lib/less/js/lib/less/tree/anonymous.js +1 -0
  38. data/lib/less/js/lib/less/tree/assignment.js +4 -0
  39. data/lib/less/js/lib/less/tree/call.js +14 -8
  40. data/lib/less/js/lib/less/tree/color.js +50 -5
  41. data/lib/less/js/lib/less/tree/comment.js +1 -0
  42. data/lib/less/js/lib/less/tree/condition.js +35 -28
  43. data/lib/less/js/lib/less/tree/dimension.js +270 -16
  44. data/lib/less/js/lib/less/tree/directive.js +7 -2
  45. data/lib/less/js/lib/less/tree/element.js +57 -21
  46. data/lib/less/js/lib/less/tree/expression.js +29 -4
  47. data/lib/less/js/lib/less/tree/extend.js +43 -0
  48. data/lib/less/js/lib/less/tree/import.js +49 -28
  49. data/lib/less/js/lib/less/tree/javascript.js +1 -0
  50. data/lib/less/js/lib/less/tree/keyword.js +3 -2
  51. data/lib/less/js/lib/less/tree/media.js +20 -4
  52. data/lib/less/js/lib/less/tree/mixin.js +38 -18
  53. data/lib/less/js/lib/less/tree/negative.js +22 -0
  54. data/lib/less/js/lib/less/tree/operation.js +32 -17
  55. data/lib/less/js/lib/less/tree/paren.js +5 -1
  56. data/lib/less/js/lib/less/tree/quoted.js +5 -3
  57. data/lib/less/js/lib/less/tree/rule.js +44 -31
  58. data/lib/less/js/lib/less/tree/ruleset.js +50 -23
  59. data/lib/less/js/lib/less/tree/selector.js +49 -39
  60. data/lib/less/js/lib/less/tree/unicode-descriptor.js +1 -0
  61. data/lib/less/js/lib/less/tree/url.js +9 -5
  62. data/lib/less/js/lib/less/tree/value.js +4 -1
  63. data/lib/less/js/lib/less/tree/variable.js +4 -3
  64. data/lib/less/js/lib/less/visitor.js +54 -0
  65. data/lib/less/js/package.json +69 -19
  66. data/lib/less/js/test/browser-test-prepare.js +23 -6
  67. data/lib/less/js/test/browser/common.js +55 -3
  68. data/lib/less/js/test/browser/css/urls.css +13 -0
  69. data/lib/less/js/test/browser/less/relative-urls/urls.less +1 -1
  70. data/lib/less/js/test/browser/less/urls.less +16 -0
  71. data/lib/less/js/test/browser/phantom-runner.js +7 -5
  72. data/lib/less/js/test/browser/runner-browser.js +5 -1
  73. data/lib/less/js/test/browser/runner-errors.js +5 -0
  74. data/lib/less/js/test/browser/runner-legacy.js +6 -0
  75. data/lib/less/js/test/browser/runner-production.js +7 -0
  76. data/lib/less/js/test/browser/template.htm +6 -6
  77. data/lib/less/js/test/css/comments.css +1 -0
  78. data/lib/less/js/test/css/compression/compression.css +2 -0
  79. data/lib/less/js/test/css/css-3.css +4 -0
  80. data/lib/less/js/test/css/css.css +9 -3
  81. data/lib/less/js/test/css/extend-chaining.css +72 -0
  82. data/lib/less/js/test/css/extend-clearfix.css +19 -0
  83. data/lib/less/js/test/css/extend-exact.css +37 -0
  84. data/lib/less/js/test/css/extend-media.css +24 -0
  85. data/lib/less/js/test/css/extend-nest.css +57 -0
  86. data/lib/less/js/test/css/extend-selector.css +72 -0
  87. data/lib/less/js/test/css/extend.css +76 -0
  88. data/lib/less/js/test/css/functions.css +28 -0
  89. data/lib/less/js/test/css/import-interpolation.css +6 -0
  90. data/lib/less/js/test/css/import.css +18 -1
  91. data/lib/less/js/test/css/legacy/legacy.css +7 -0
  92. data/lib/less/js/test/css/media.css +9 -1
  93. data/lib/less/js/test/css/mixins-args.css +18 -0
  94. data/lib/less/js/test/css/mixins-guards.css +5 -0
  95. data/lib/less/js/test/css/parens.css +18 -5
  96. data/lib/less/js/test/css/selectors.css +14 -6
  97. data/lib/less/js/test/css/urls.css +17 -0
  98. data/lib/less/js/test/css/variables.css +22 -3
  99. data/lib/less/js/test/data/data-uri-fail.png +0 -0
  100. data/lib/less/js/test/data/image.jpg +0 -0
  101. data/lib/less/js/test/data/page.html +1 -0
  102. data/lib/less/js/test/less-test.js +41 -9
  103. data/lib/less/js/test/less/colors.less +4 -4
  104. data/lib/less/js/test/less/comments.less +2 -2
  105. data/lib/less/js/test/less/compression/compression.less +16 -0
  106. data/lib/less/js/test/less/css-3.less +5 -1
  107. data/lib/less/js/test/less/css.less +9 -3
  108. data/lib/less/js/test/less/errors/add-mixed-units.less +3 -0
  109. data/lib/less/js/test/less/errors/add-mixed-units.txt +2 -0
  110. data/lib/less/js/test/less/errors/add-mixed-units2.less +3 -0
  111. data/lib/less/js/test/less/errors/add-mixed-units2.txt +2 -0
  112. data/lib/less/js/test/less/errors/bad-variable-declaration1.txt +1 -1
  113. data/lib/less/js/test/less/errors/color-operation-error.less +3 -0
  114. data/lib/less/js/test/less/errors/color-operation-error.txt +2 -0
  115. data/lib/less/js/test/less/errors/comment-in-selector.txt +1 -1
  116. data/lib/less/js/test/less/errors/divide-mixed-units.less +3 -0
  117. data/lib/less/js/test/less/errors/divide-mixed-units.txt +4 -0
  118. data/lib/less/js/test/less/errors/extend-no-selector.less +3 -0
  119. data/lib/less/js/test/less/errors/extend-no-selector.txt +3 -0
  120. data/lib/less/js/test/less/errors/extend-not-at-end.less +3 -0
  121. data/lib/less/js/test/less/errors/extend-not-at-end.txt +3 -0
  122. data/lib/less/js/test/less/errors/import-missing.less +5 -0
  123. data/lib/less/js/test/less/errors/import-missing.txt +3 -3
  124. data/lib/less/js/test/less/errors/import-no-semi.txt +1 -1
  125. data/lib/less/js/test/less/errors/import-subfolder1.txt +1 -1
  126. data/lib/less/js/test/less/errors/import-subfolder2.txt +1 -1
  127. data/lib/less/js/test/less/errors/javascript-error.txt +1 -1
  128. data/lib/less/js/test/less/errors/mixed-mixin-definition-args-1.txt +1 -1
  129. data/lib/less/js/test/less/errors/mixed-mixin-definition-args-2.txt +1 -1
  130. data/lib/less/js/test/less/errors/mixin-not-defined.txt +1 -1
  131. data/lib/less/js/test/less/errors/mixin-not-matched.txt +1 -1
  132. data/lib/less/js/test/less/errors/mixin-not-matched2.txt +1 -1
  133. data/lib/less/js/test/less/errors/multiply-mixed-units.less +7 -0
  134. data/lib/less/js/test/less/errors/multiply-mixed-units.txt +4 -0
  135. data/lib/less/js/test/less/errors/parens-error-1.less +3 -0
  136. data/lib/less/js/test/less/errors/parens-error-1.txt +4 -0
  137. data/lib/less/js/test/less/errors/parens-error-2.less +3 -0
  138. data/lib/less/js/test/less/errors/parens-error-2.txt +4 -0
  139. data/lib/less/js/test/less/errors/parens-error-3.less +3 -0
  140. data/lib/less/js/test/less/errors/parens-error-3.txt +4 -0
  141. data/lib/less/js/test/less/errors/parse-error-curly-bracket.txt +1 -1
  142. data/lib/less/js/test/less/errors/parse-error-missing-bracket.txt +2 -1
  143. data/lib/less/js/test/less/errors/parse-error-with-import.txt +1 -1
  144. data/lib/less/js/test/less/errors/property-ie5-hack.txt +1 -1
  145. data/lib/less/js/test/less/errors/property-in-root.less +4 -0
  146. data/lib/less/js/test/less/errors/property-in-root.txt +4 -0
  147. data/lib/less/js/test/less/errors/property-in-root2.less +1 -0
  148. data/lib/less/js/test/less/errors/property-in-root2.txt +4 -0
  149. data/lib/less/js/test/less/errors/property-in-root3.less +4 -0
  150. data/lib/less/js/test/less/errors/property-in-root3.txt +3 -0
  151. data/lib/less/js/test/less/errors/recursive-variable.txt +1 -1
  152. data/lib/less/js/test/less/extend-chaining.less +79 -0
  153. data/lib/less/js/test/less/extend-clearfix.less +19 -0
  154. data/lib/less/js/test/less/extend-exact.less +46 -0
  155. data/lib/less/js/test/less/extend-media.less +24 -0
  156. data/lib/less/js/test/less/extend-nest.less +65 -0
  157. data/lib/less/js/test/less/extend-selector.less +84 -0
  158. data/lib/less/js/test/less/extend.less +81 -0
  159. data/lib/less/js/test/less/functions.less +37 -6
  160. data/lib/less/js/test/less/import-interpolation.less +8 -0
  161. data/lib/less/js/test/less/import-once.less +4 -4
  162. data/lib/less/js/test/less/import.less +11 -2
  163. data/lib/less/js/test/less/import/deeper/import-once-test-a.less +1 -1
  164. data/lib/less/js/test/less/import/import-interpolation.less +1 -0
  165. data/lib/less/js/test/less/import/import-interpolation2.less +5 -0
  166. data/lib/less/js/test/less/javascript.less +1 -1
  167. data/lib/less/js/test/less/legacy/legacy.less +7 -0
  168. data/lib/less/js/test/less/media.less +14 -3
  169. data/lib/less/js/test/less/mixins-args.less +43 -5
  170. data/lib/less/js/test/less/mixins-guards.less +13 -0
  171. data/lib/less/js/test/less/mixins-named-args.less +5 -5
  172. data/lib/less/js/test/less/mixins-nested.less +2 -2
  173. data/lib/less/js/test/less/mixins-pattern.less +1 -1
  174. data/lib/less/js/test/less/mixins.less +1 -1
  175. data/lib/less/js/test/less/operations.less +27 -27
  176. data/lib/less/js/test/less/parens.less +20 -5
  177. data/lib/less/js/test/less/selectors.less +14 -7
  178. data/lib/less/js/test/less/urls.less +24 -0
  179. data/lib/less/js/test/less/variables.less +42 -12
  180. data/lib/less/loader.rb +33 -0
  181. data/lib/less/version.rb +1 -1
  182. data/spec/less/parser_spec.rb +5 -5
  183. metadata +76 -6
  184. data/lib/less/js/build/ecma-5.js +0 -120
  185. data/lib/less/js/lib/less/tree/ratio.js +0 -13
@@ -11,11 +11,16 @@ tree.Directive = function (name, value) {
11
11
  }
12
12
  };
13
13
  tree.Directive.prototype = {
14
- toCSS: function (ctx, env) {
14
+ type: "Directive",
15
+ accept: function (visitor) {
16
+ this.ruleset = visitor.visit(this.ruleset);
17
+ this.value = visitor.visit(this.value);
18
+ },
19
+ toCSS: function (env) {
15
20
  if (this.ruleset) {
16
21
  this.ruleset.root = true;
17
22
  return this.name + (env.compress ? '{' : ' {\n ') +
18
- this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
23
+ this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') +
19
24
  (env.compress ? '}': '\n}\n');
20
25
  } else {
21
26
  return this.name + ' ' + this.value.toCSS() + ';\n';
@@ -13,18 +13,51 @@ tree.Element = function (combinator, value, index) {
13
13
  }
14
14
  this.index = index;
15
15
  };
16
- tree.Element.prototype.eval = function (env) {
17
- return new(tree.Element)(this.combinator,
18
- this.value.eval ? this.value.eval(env) : this.value,
19
- this.index);
16
+ tree.Element.prototype = {
17
+ type: "Element",
18
+ accept: function (visitor) {
19
+ this.combinator = visitor.visit(this.combinator);
20
+ this.value = visitor.visit(this.value);
21
+ },
22
+ eval: function (env) {
23
+ return new(tree.Element)(this.combinator,
24
+ this.value.eval ? this.value.eval(env) : this.value,
25
+ this.index);
26
+ },
27
+ toCSS: function (env) {
28
+ var value = (this.value.toCSS ? this.value.toCSS(env) : this.value);
29
+ if (value == '' && this.combinator.value.charAt(0) == '&') {
30
+ return '';
31
+ } else {
32
+ return this.combinator.toCSS(env || {}) + value;
33
+ }
34
+ }
20
35
  };
21
- tree.Element.prototype.toCSS = function (env) {
22
- var value = (this.value.toCSS ? this.value.toCSS(env) : this.value);
23
- if (value == '' && this.combinator.value.charAt(0) == '&') {
24
- return '';
25
- } else {
26
- return this.combinator.toCSS(env || {}) + value;
27
- }
36
+
37
+ tree.Attribute = function (key, op, value) {
38
+ this.key = key;
39
+ this.op = op;
40
+ this.value = value;
41
+ };
42
+ tree.Attribute.prototype = {
43
+ type: "Attribute",
44
+ accept: function (visitor) {
45
+ this.value = visitor.visit(this.value);
46
+ },
47
+ eval: function (env) {
48
+ return new(tree.Attribute)(this.key.eval ? this.key.eval(env) : this.key,
49
+ this.op, (this.value && this.value.eval) ? this.value.eval(env) : this.value);
50
+ },
51
+ toCSS: function (env) {
52
+ var value = this.key.toCSS ? this.key.toCSS(env) : this.key;
53
+
54
+ if (this.op) {
55
+ value += this.op;
56
+ value += (this.value.toCSS ? this.value.toCSS(env) : this.value);
57
+ }
58
+
59
+ return '[' + value + ']';
60
+ }
28
61
  };
29
62
 
30
63
  tree.Combinator = function (value) {
@@ -34,16 +67,19 @@ tree.Combinator = function (value) {
34
67
  this.value = value ? value.trim() : "";
35
68
  }
36
69
  };
37
- tree.Combinator.prototype.toCSS = function (env) {
38
- return {
39
- '' : '',
40
- ' ' : ' ',
41
- ':' : ' :',
42
- '+' : env.compress ? '+' : ' + ',
43
- '~' : env.compress ? '~' : ' ~ ',
44
- '>' : env.compress ? '>' : ' > ',
45
- '|' : env.compress ? '|' : ' | '
46
- }[this.value];
70
+ tree.Combinator.prototype = {
71
+ type: "Combinator",
72
+ toCSS: function (env) {
73
+ return {
74
+ '' : '',
75
+ ' ' : ' ',
76
+ ':' : ' :',
77
+ '+' : env.compress ? '+' : ' + ',
78
+ '~' : env.compress ? '~' : ' ~ ',
79
+ '>' : env.compress ? '>' : ' > ',
80
+ '|' : env.compress ? '|' : ' | '
81
+ }[this.value];
82
+ }
47
83
  };
48
84
 
49
85
  })(require('../tree'));
@@ -1,22 +1,47 @@
1
1
  (function (tree) {
2
2
 
3
- tree.Expression = function (value) { this.value = value };
3
+ tree.Expression = function (value) { this.value = value; };
4
4
  tree.Expression.prototype = {
5
+ type: "Expression",
6
+ accept: function (visitor) {
7
+ this.value = visitor.visit(this.value);
8
+ },
5
9
  eval: function (env) {
10
+ var returnValue,
11
+ inParenthesis = this.parens && !this.parensInOp,
12
+ doubleParen = false;
13
+ if (inParenthesis) {
14
+ env.inParenthesis();
15
+ }
6
16
  if (this.value.length > 1) {
7
- return new(tree.Expression)(this.value.map(function (e) {
17
+ returnValue = new(tree.Expression)(this.value.map(function (e) {
8
18
  return e.eval(env);
9
19
  }));
10
20
  } else if (this.value.length === 1) {
11
- return this.value[0].eval(env);
21
+ if (this.value[0].parens && !this.value[0].parensInOp) {
22
+ doubleParen = true;
23
+ }
24
+ returnValue = this.value[0].eval(env);
12
25
  } else {
13
- return this;
26
+ returnValue = this;
27
+ }
28
+ if (inParenthesis) {
29
+ env.outOfParenthesis();
14
30
  }
31
+ if (this.parens && this.parensInOp && !(env.isMathOn()) && !doubleParen) {
32
+ returnValue = new(tree.Paren)(returnValue);
33
+ }
34
+ return returnValue;
15
35
  },
16
36
  toCSS: function (env) {
17
37
  return this.value.map(function (e) {
18
38
  return e.toCSS ? e.toCSS(env) : '';
19
39
  }).join(' ');
40
+ },
41
+ throwAwayComments: function () {
42
+ this.value = this.value.filter(function(v) {
43
+ return !(v instanceof tree.Comment);
44
+ });
20
45
  }
21
46
  };
22
47
 
@@ -0,0 +1,43 @@
1
+ (function (tree) {
2
+
3
+ tree.Extend = function Extend(selector, option, index) {
4
+ this.selector = selector;
5
+ this.option = option;
6
+ this.index = index;
7
+
8
+ switch(option) {
9
+ case "all":
10
+ this.allowBefore = true;
11
+ this.allowAfter = true;
12
+ break;
13
+ default:
14
+ this.allowBefore = false;
15
+ this.allowAfter = false;
16
+ break;
17
+ }
18
+ };
19
+
20
+ tree.Extend.prototype = {
21
+ type: "Extend",
22
+ accept: function (visitor) {
23
+ this.selector = visitor.visit(this.selector);
24
+ },
25
+ eval: function (env) {
26
+ return new(tree.Extend)(this.selector.eval(env), this.option, this.index);
27
+ },
28
+ clone: function (env) {
29
+ return new(tree.Extend)(this.selector, this.option, this.index);
30
+ },
31
+ findSelfSelectors: function (selectors) {
32
+ var selfElements = [],
33
+ i;
34
+
35
+ for(i = 0; i < selectors.length; i++) {
36
+ selfElements = selfElements.concat(selectors[i].elements);
37
+ }
38
+
39
+ this.selfSelectors = [{ elements: selfElements }];
40
+ }
41
+ };
42
+
43
+ })(require('../tree'));
@@ -11,31 +11,22 @@
11
11
  // `import,push`, we also pass it a callback, which it'll call once
12
12
  // the file has been fetched, and parsed.
13
13
  //
14
- tree.Import = function (path, imports, features, once, index, rootpath) {
14
+ tree.Import = function (path, features, options, index, currentFileInfo) {
15
15
  var that = this;
16
16
 
17
- this.once = once;
17
+ this.options = options;
18
18
  this.index = index;
19
- this._path = path;
20
- this.features = features && new(tree.Value)(features);
21
- this.rootpath = rootpath;
22
-
23
- // The '.less' extension is optional
24
- if (path instanceof tree.Quoted) {
25
- this.path = /(\.[a-z]*$)|([\?;].*)$/.test(path.value) ? path.value : path.value + '.less';
26
- } else {
27
- this.path = path.value.value || path.value;
28
- }
19
+ this.path = path;
20
+ this.features = features;
21
+ this.currentFileInfo = currentFileInfo;
29
22
 
30
- this.css = /css([\?;].*)?$/.test(this.path);
31
-
32
- // Only pre-compile .less files
33
- if (! this.css) {
34
- imports.push(this.path, function (e, root, imported) {
35
- if (e) { e.index = index }
36
- if (imported && that.once) that.skip = imported;
37
- that.root = root || new(tree.Ruleset)([], []);
38
- });
23
+ if (this.options.less !== undefined) {
24
+ this.css = !this.options.less;
25
+ } else {
26
+ var pathValue = this.getPath();
27
+ if (pathValue && /css([\?;].*)?$/.test(pathValue)) {
28
+ this.css = true;
29
+ }
39
30
  }
40
31
  };
41
32
 
@@ -49,26 +40,56 @@ tree.Import = function (path, imports, features, once, index, rootpath) {
49
40
  // ruleset.
50
41
  //
51
42
  tree.Import.prototype = {
43
+ type: "Import",
44
+ accept: function (visitor) {
45
+ this.features = visitor.visit(this.features);
46
+ this.path = visitor.visit(this.path);
47
+ this.root = visitor.visit(this.root);
48
+ },
52
49
  toCSS: function (env) {
53
50
  var features = this.features ? ' ' + this.features.toCSS(env) : '';
54
51
 
55
52
  if (this.css) {
56
- // Add the base path if the import is relative
57
- if (typeof this._path.value === "string" && !/^(?:[a-z-]+:|\/)/.test(this._path.value)) {
58
- this._path.value = this.rootpath + this._path.value;
59
- }
60
- return "@import " + this._path.toCSS() + features + ';\n';
53
+ return "@import " + this.path.toCSS() + features + ';\n';
61
54
  } else {
62
55
  return "";
63
56
  }
64
57
  },
58
+ getPath: function () {
59
+ if (this.path instanceof tree.Quoted) {
60
+ var path = this.path.value;
61
+ return (this.css !== undefined || /(\.[a-z]*$)|([\?;].*)$/.test(path)) ? path : path + '.less';
62
+ } else if (this.path instanceof tree.URL) {
63
+ return this.path.value.value;
64
+ }
65
+ return null;
66
+ },
67
+ evalForImport: function (env) {
68
+ return new(tree.Import)(this.path.eval(env), this.features, this.options, this.index, this.currentFileInfo);
69
+ },
70
+ evalPath: function (env) {
71
+ var path = this.path.eval(env);
72
+ var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
73
+ if (rootpath && !(path instanceof tree.URL)) {
74
+ var pathValue = path.value;
75
+ // Add the base path if the import is relative
76
+ if (pathValue && env.isPathRelative(pathValue)) {
77
+ path.value = rootpath + pathValue;
78
+ }
79
+ }
80
+ return path;
81
+ },
65
82
  eval: function (env) {
66
83
  var ruleset, features = this.features && this.features.eval(env);
67
84
 
68
- if (this.skip) return [];
85
+ if (this.skip) { return []; }
69
86
 
70
87
  if (this.css) {
71
- return this;
88
+ var newImport = new(tree.Import)(this.evalPath(env), features, this.options, this.index);
89
+ if (!newImport.css && this.error) {
90
+ throw this.error;
91
+ }
92
+ return newImport;
72
93
  } else {
73
94
  ruleset = new(tree.Ruleset)([], this.root.rules.slice(0));
74
95
 
@@ -6,6 +6,7 @@ tree.JavaScript = function (string, index, escaped) {
6
6
  this.index = index;
7
7
  };
8
8
  tree.JavaScript.prototype = {
9
+ type: "JavaScript",
9
10
  eval: function (env) {
10
11
  var result,
11
12
  that = this,
@@ -2,8 +2,9 @@
2
2
 
3
3
  tree.Keyword = function (value) { this.value = value };
4
4
  tree.Keyword.prototype = {
5
- eval: function () { return this },
6
- toCSS: function () { return this.value },
5
+ type: "Keyword",
6
+ eval: function () { return this; },
7
+ toCSS: function () { return this.value; },
7
8
  compare: function (other) {
8
9
  if (other instanceof tree.Keyword) {
9
10
  return other.value === this.value ? 0 : 1;
@@ -8,12 +8,16 @@ tree.Media = function (value, features) {
8
8
  this.ruleset.allowImports = true;
9
9
  };
10
10
  tree.Media.prototype = {
11
- toCSS: function (ctx, env) {
11
+ type: "Media",
12
+ accept: function (visitor) {
13
+ this.features = visitor.visit(this.features);
14
+ this.ruleset = visitor.visit(this.ruleset);
15
+ },
16
+ toCSS: function (env) {
12
17
  var features = this.features.toCSS(env);
13
18
 
14
- this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia);
15
19
  return '@media ' + features + (env.compress ? '{' : ' {\n ') +
16
- this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
20
+ this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') +
17
21
  (env.compress ? '}': '\n}\n');
18
22
  },
19
23
  eval: function (env) {
@@ -27,7 +31,19 @@ tree.Media.prototype = {
27
31
  this.ruleset.debugInfo = this.debugInfo;
28
32
  media.debugInfo = this.debugInfo;
29
33
  }
30
- media.features = this.features.eval(env);
34
+ var strictMathBypass = false;
35
+ if (!env.strictMath) {
36
+ strictMathBypass = true;
37
+ env.strictMath = true;
38
+ }
39
+ try {
40
+ media.features = this.features.eval(env);
41
+ }
42
+ finally {
43
+ if (strictMathBypass) {
44
+ env.strictMath = false;
45
+ }
46
+ }
31
47
 
32
48
  env.mediaPath.push(media);
33
49
  env.mediaBlocks.push(media);
@@ -1,14 +1,19 @@
1
1
  (function (tree) {
2
2
 
3
3
  tree.mixin = {};
4
- tree.mixin.Call = function (elements, args, index, filename, important) {
4
+ tree.mixin.Call = function (elements, args, index, currentFileInfo, important) {
5
5
  this.selector = new(tree.Selector)(elements);
6
6
  this.arguments = args;
7
7
  this.index = index;
8
- this.filename = filename;
8
+ this.currentFileInfo = currentFileInfo;
9
9
  this.important = important;
10
10
  };
11
11
  tree.mixin.Call.prototype = {
12
+ type: "MixinCall",
13
+ accept: function (visitor) {
14
+ this.selector = visitor.visit(this.selector);
15
+ this.arguments = visitor.visit(this.arguments);
16
+ },
12
17
  eval: function (env) {
13
18
  var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound;
14
19
 
@@ -37,7 +42,7 @@ tree.mixin.Call.prototype = {
37
42
  Array.prototype.push.apply(
38
43
  rules, mixin.eval(env, args, this.important).rules);
39
44
  } catch (e) {
40
- throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack };
45
+ throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack };
41
46
  }
42
47
  }
43
48
  match = true;
@@ -64,11 +69,11 @@ tree.mixin.Call.prototype = {
64
69
  }
65
70
  return argValue;
66
71
  }).join(', ') : "") + ")`",
67
- index: this.index, filename: this.filename };
72
+ index: this.index, filename: this.currentFileInfo.filename };
68
73
  } else {
69
74
  throw { type: 'Name',
70
75
  message: this.selector.toCSS().trim() + " is undefined",
71
- index: this.index, filename: this.filename };
76
+ index: this.index, filename: this.currentFileInfo.filename };
72
77
  }
73
78
  }
74
79
  };
@@ -90,14 +95,25 @@ tree.mixin.Definition = function (name, params, rules, condition, variadic) {
90
95
  this.frames = [];
91
96
  };
92
97
  tree.mixin.Definition.prototype = {
93
- toCSS: function () { return "" },
94
- variable: function (name) { return this.parent.variable.call(this, name) },
95
- variables: function () { return this.parent.variables.call(this) },
96
- find: function () { return this.parent.find.apply(this, arguments) },
97
- rulesets: function () { return this.parent.rulesets.apply(this) },
98
+ type: "MixinDefinition",
99
+ accept: function (visitor) {
100
+ this.params = visitor.visit(this.params);
101
+ this.rules = visitor.visit(this.rules);
102
+ this.condition = visitor.visit(this.condition);
103
+ },
104
+ toCSS: function () { return ""; },
105
+ variable: function (name) { return this.parent.variable.call(this, name); },
106
+ variables: function () { return this.parent.variables.call(this); },
107
+ find: function () { return this.parent.find.apply(this, arguments); },
108
+ rulesets: function () { return this.parent.rulesets.apply(this); },
98
109
 
99
110
  evalParams: function (env, mixinEnv, args, evaldArguments) {
100
- var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex;
111
+ var frame = new(tree.Ruleset)(null, []),
112
+ varargs, arg,
113
+ params = this.params.slice(0),
114
+ i, j, val, name, isNamedFound, argIndex;
115
+
116
+ mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames));
101
117
 
102
118
  if (args) {
103
119
  args = args.slice(0);
@@ -144,6 +160,7 @@ tree.mixin.Definition.prototype = {
144
160
  val = val.eval(env);
145
161
  } else if (params[i].value) {
146
162
  val = params[i].value.eval(mixinEnv);
163
+ frame.resetCache();
147
164
  } else {
148
165
  throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
149
166
  ' (' + args.length + ' for ' + this.arity + ')' };
@@ -167,7 +184,7 @@ tree.mixin.Definition.prototype = {
167
184
  eval: function (env, args, important) {
168
185
  var _arguments = [],
169
186
  mixinFrames = this.frames.concat(env.frames),
170
- frame = this.evalParams(env, {frames: mixinFrames}, args, _arguments),
187
+ frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments),
171
188
  context, rules, start, ruleset;
172
189
 
173
190
  frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
@@ -175,16 +192,19 @@ tree.mixin.Definition.prototype = {
175
192
  rules = important ?
176
193
  this.parent.makeImportant.apply(this).rules : this.rules.slice(0);
177
194
 
178
- ruleset = new(tree.Ruleset)(null, rules).eval({
179
- frames: [this, frame].concat(mixinFrames)
180
- });
195
+ ruleset = new(tree.Ruleset)(null, rules).eval(new(tree.evalEnv)(env,
196
+ [this, frame].concat(mixinFrames)));
181
197
  ruleset.originalRuleset = this;
182
198
  return ruleset;
183
199
  },
184
200
  matchCondition: function (args, env) {
185
- if (this.condition && !this.condition.eval({
186
- frames: [this.evalParams(env, {frames: this.frames.concat(env.frames)}, args, [])].concat(env.frames)
187
- })) { return false }
201
+
202
+ if (this.condition && !this.condition.eval(
203
+ new(tree.evalEnv)(env,
204
+ [this.evalParams(env, new(tree.evalEnv)(env, this.frames.concat(env.frames)), args, [])]
205
+ .concat(env.frames)))) {
206
+ return false;
207
+ }
188
208
  return true;
189
209
  },
190
210
  matchArgs: function (args, env) {