less 1.2.21 → 2.0.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 (165) hide show
  1. data/.gitignore +4 -3
  2. data/.gitmodules +6 -0
  3. data/Gemfile +3 -0
  4. data/README.md +39 -46
  5. data/Rakefile +5 -50
  6. data/bin/lessc +1 -100
  7. data/less.gemspec +21 -125
  8. data/lib/less.rb +11 -30
  9. data/{LICENSE → lib/less/js/LICENSE} +1 -1
  10. data/lib/less/js/Makefile +56 -0
  11. data/lib/less/js/README.md +20 -0
  12. data/lib/less/js/benchmark/benchmark.less +3979 -0
  13. data/lib/less/js/benchmark/less-benchmark.js +49 -0
  14. data/lib/less/js/bin/lessc +105 -0
  15. data/lib/less/js/build/ecma-5.js +120 -0
  16. data/lib/less/js/build/header.js +7 -0
  17. data/lib/less/js/build/require.js +7 -0
  18. data/lib/less/js/dist/less-1.0.44.js +2655 -0
  19. data/lib/less/js/dist/less-1.1.0.js +2695 -0
  20. data/lib/less/js/dist/less-1.1.0.min.js +16 -0
  21. data/lib/less/js/dist/less-1.1.1.js +2710 -0
  22. data/lib/less/js/dist/less-1.1.1.min.js +16 -0
  23. data/lib/less/js/dist/less-1.1.2.js +2712 -0
  24. data/lib/less/js/dist/less-1.1.2.min.js +16 -0
  25. data/lib/less/js/dist/less-1.1.3.js +2721 -0
  26. data/lib/less/js/dist/less-1.1.3.min.js +16 -0
  27. data/lib/less/js/lib/less/browser.js +369 -0
  28. data/lib/less/js/lib/less/functions.js +174 -0
  29. data/lib/less/js/lib/less/index.js +137 -0
  30. data/lib/less/js/lib/less/parser.js +1098 -0
  31. data/lib/less/js/lib/less/tree.js +13 -0
  32. data/lib/less/js/lib/less/tree/alpha.js +17 -0
  33. data/lib/less/js/lib/less/tree/anonymous.js +13 -0
  34. data/lib/less/js/lib/less/tree/call.js +45 -0
  35. data/lib/less/js/lib/less/tree/color.js +98 -0
  36. data/lib/less/js/lib/less/tree/comment.js +14 -0
  37. data/lib/less/js/lib/less/tree/dimension.js +34 -0
  38. data/lib/less/js/lib/less/tree/directive.js +33 -0
  39. data/lib/less/js/lib/less/tree/element.js +32 -0
  40. data/lib/less/js/lib/less/tree/expression.js +23 -0
  41. data/lib/less/js/lib/less/tree/import.js +77 -0
  42. data/lib/less/js/lib/less/tree/javascript.js +51 -0
  43. data/lib/less/js/lib/less/tree/keyword.js +9 -0
  44. data/lib/less/js/lib/less/tree/mixin.js +106 -0
  45. data/lib/less/js/lib/less/tree/operation.js +32 -0
  46. data/lib/less/js/lib/less/tree/quoted.js +29 -0
  47. data/lib/less/js/lib/less/tree/rule.js +38 -0
  48. data/lib/less/js/lib/less/tree/ruleset.js +179 -0
  49. data/lib/less/js/lib/less/tree/selector.js +28 -0
  50. data/lib/less/js/lib/less/tree/url.js +25 -0
  51. data/lib/less/js/lib/less/tree/value.js +24 -0
  52. data/lib/less/js/lib/less/tree/variable.js +24 -0
  53. data/lib/less/js/package.json +13 -0
  54. data/lib/less/js/test/css/colors.css +42 -0
  55. data/lib/less/js/test/css/comments.css +52 -0
  56. data/lib/less/js/test/css/css-3.css +42 -0
  57. data/lib/less/js/test/css/css-escapes.css +20 -0
  58. data/lib/less/js/test/css/css.css +82 -0
  59. data/lib/less/js/test/css/functions.css +30 -0
  60. data/{spec → lib/less/js/test}/css/import.css +4 -2
  61. data/lib/less/js/test/css/javascript.css +22 -0
  62. data/lib/less/js/test/css/lazy-eval.css +3 -0
  63. data/lib/less/js/test/css/media.css +21 -0
  64. data/lib/less/js/test/css/mixins-args.css +61 -0
  65. data/lib/less/js/test/css/mixins-closure.css +9 -0
  66. data/lib/less/js/test/css/mixins-nested.css +14 -0
  67. data/lib/less/js/test/css/mixins-pattern.css +49 -0
  68. data/lib/less/js/test/css/mixins.css +50 -0
  69. data/{spec → lib/less/js/test}/css/operations.css +20 -2
  70. data/{spec → lib/less/js/test}/css/parens.css +0 -0
  71. data/lib/less/js/test/css/rulesets.css +29 -0
  72. data/{spec → lib/less/js/test}/css/scope.css +6 -2
  73. data/lib/less/js/test/css/selectors.css +32 -0
  74. data/lib/less/js/test/css/strings.css +38 -0
  75. data/lib/less/js/test/css/variables.css +24 -0
  76. data/lib/less/js/test/css/whitespace.css +36 -0
  77. data/lib/less/js/test/less-test.js +75 -0
  78. data/{spec → lib/less/js/test}/less/colors.less +13 -2
  79. data/{spec → lib/less/js/test}/less/comments.less +19 -2
  80. data/{spec → lib/less/js/test}/less/css-3.less +4 -1
  81. data/lib/less/js/test/less/css-escapes.less +28 -0
  82. data/{spec → lib/less/js/test}/less/css.less +10 -18
  83. data/lib/less/js/test/less/functions.less +35 -0
  84. data/{spec → lib/less/js/test}/less/import.less +1 -1
  85. data/{spec → lib/less/js/test}/less/import/import-test-a.less +0 -0
  86. data/{spec → lib/less/js/test}/less/import/import-test-b.less +0 -0
  87. data/{spec → lib/less/js/test}/less/import/import-test-c.less +0 -0
  88. data/{spec → lib/less/js/test}/less/import/import-test-d.css +0 -0
  89. data/lib/less/js/test/less/javascript.less +27 -0
  90. data/{spec → lib/less/js/test}/less/lazy-eval.less +0 -0
  91. data/lib/less/js/test/less/media.less +25 -0
  92. data/lib/less/js/test/less/mixins-args.less +118 -0
  93. data/lib/less/js/test/less/mixins-closure.less +26 -0
  94. data/lib/less/js/test/less/mixins-nested.less +22 -0
  95. data/lib/less/js/test/less/mixins-pattern.less +96 -0
  96. data/{spec → lib/less/js/test}/less/mixins.less +8 -4
  97. data/{spec → lib/less/js/test}/less/operations.less +19 -0
  98. data/{spec → lib/less/js/test}/less/parens.less +0 -0
  99. data/{spec → lib/less/js/test}/less/rulesets.less +2 -2
  100. data/{spec → lib/less/js/test}/less/scope.less +1 -1
  101. data/{spec → lib/less/js/test}/less/selectors.less +1 -1
  102. data/lib/less/js/test/less/strings.less +49 -0
  103. data/lib/less/js/test/less/variables.less +50 -0
  104. data/{spec → lib/less/js/test}/less/whitespace.less +3 -0
  105. data/lib/less/loader.rb +67 -0
  106. data/lib/less/parser.rb +46 -0
  107. data/lib/less/version.rb +3 -0
  108. data/spec/less/one/one.less +1 -0
  109. data/spec/less/parser_spec.rb +30 -0
  110. data/spec/less/two/two.less +1 -0
  111. data/spec/spec_helper.rb +2 -7
  112. metadata +156 -106
  113. data/CHANGELOG +0 -62
  114. data/VERSION +0 -1
  115. data/lib/less/command.rb +0 -110
  116. data/lib/less/engine.rb +0 -52
  117. data/lib/less/engine/grammar/common.tt +0 -29
  118. data/lib/less/engine/grammar/entity.tt +0 -144
  119. data/lib/less/engine/grammar/less.tt +0 -341
  120. data/lib/less/engine/nodes.rb +0 -9
  121. data/lib/less/engine/nodes/element.rb +0 -281
  122. data/lib/less/engine/nodes/entity.rb +0 -79
  123. data/lib/less/engine/nodes/function.rb +0 -93
  124. data/lib/less/engine/nodes/literal.rb +0 -171
  125. data/lib/less/engine/nodes/property.rb +0 -232
  126. data/lib/less/engine/nodes/ruleset.rb +0 -12
  127. data/lib/less/engine/nodes/selector.rb +0 -44
  128. data/lib/less/ext.rb +0 -60
  129. data/spec/command_spec.rb +0 -102
  130. data/spec/css/accessors.css +0 -18
  131. data/spec/css/big.css +0 -3768
  132. data/spec/css/colors.css +0 -14
  133. data/spec/css/comments.css +0 -9
  134. data/spec/css/css-3.css +0 -21
  135. data/spec/css/css.css +0 -50
  136. data/spec/css/dash-prefix.css +0 -12
  137. data/spec/css/functions.css +0 -6
  138. data/spec/css/import-with-extra-paths.css +0 -8
  139. data/spec/css/import-with-partial-in-extra-path.css +0 -6
  140. data/spec/css/lazy-eval.css +0 -1
  141. data/spec/css/mixins-args.css +0 -32
  142. data/spec/css/mixins.css +0 -28
  143. data/spec/css/rulesets.css +0 -17
  144. data/spec/css/selectors.css +0 -13
  145. data/spec/css/strings.css +0 -12
  146. data/spec/css/variables.css +0 -8
  147. data/spec/css/whitespace.css +0 -7
  148. data/spec/engine_spec.rb +0 -127
  149. data/spec/less/accessors.less +0 -20
  150. data/spec/less/big.less +0 -1264
  151. data/spec/less/dash-prefix.less +0 -21
  152. data/spec/less/exceptions/mixed-units-error.less +0 -3
  153. data/spec/less/exceptions/name-error-1.0.less +0 -3
  154. data/spec/less/exceptions/syntax-error-1.0.less +0 -3
  155. data/spec/less/extra_import_path/extra.less +0 -1
  156. data/spec/less/extra_import_path/import/import-test-a.css +0 -1
  157. data/spec/less/extra_import_path/import/import-test-a.less +0 -4
  158. data/spec/less/functions.less +0 -6
  159. data/spec/less/hidden.less +0 -25
  160. data/spec/less/import-with-extra-paths.less +0 -4
  161. data/spec/less/literal-css.less +0 -11
  162. data/spec/less/mixins-args.less +0 -59
  163. data/spec/less/strings.less +0 -14
  164. data/spec/less/variables.less +0 -29
  165. data/spec/spec.css +0 -50
@@ -0,0 +1,13 @@
1
+ require('less/tree').find = function (obj, fun) {
2
+ for (var i = 0, r; i < obj.length; i++) {
3
+ if (r = fun.call(obj, obj[i])) { return r }
4
+ }
5
+ return null;
6
+ };
7
+ require('less/tree').jsify = function (obj) {
8
+ if (Array.isArray(obj.value) && (obj.value.length > 1)) {
9
+ return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
10
+ } else {
11
+ return obj.toCSS(false);
12
+ }
13
+ };
@@ -0,0 +1,17 @@
1
+ (function (tree) {
2
+
3
+ tree.Alpha = function (val) {
4
+ this.value = val;
5
+ };
6
+ tree.Alpha.prototype = {
7
+ toCSS: function () {
8
+ return "alpha(opacity=" +
9
+ (this.value.toCSS ? this.value.toCSS() : this.value) + ")";
10
+ },
11
+ eval: function (env) {
12
+ if (this.value.eval) { this.value = this.value.eval(env) }
13
+ return this;
14
+ }
15
+ };
16
+
17
+ })(require('less/tree'));
@@ -0,0 +1,13 @@
1
+ (function (tree) {
2
+
3
+ tree.Anonymous = function (string) {
4
+ this.value = string.value || string;
5
+ };
6
+ tree.Anonymous.prototype = {
7
+ toCSS: function () {
8
+ return this.value;
9
+ },
10
+ eval: function () { return this }
11
+ };
12
+
13
+ })(require('less/tree'));
@@ -0,0 +1,45 @@
1
+ (function (tree) {
2
+
3
+ //
4
+ // A function call node.
5
+ //
6
+ tree.Call = function (name, args, index) {
7
+ this.name = name;
8
+ this.args = args;
9
+ this.index = index;
10
+ };
11
+ tree.Call.prototype = {
12
+ //
13
+ // When evaluating a function call,
14
+ // we either find the function in `tree.functions` [1],
15
+ // in which case we call it, passing the evaluated arguments,
16
+ // or we simply print it out as it appeared originally [2].
17
+ //
18
+ // The *functions.js* file contains the built-in functions.
19
+ //
20
+ // The reason why we evaluate the arguments, is in the case where
21
+ // we try to pass a variable to a function, like: `saturate(@color)`.
22
+ // The function should receive the value, not the variable.
23
+ //
24
+ eval: function (env) {
25
+ var args = this.args.map(function (a) { return a.eval(env) });
26
+
27
+ if (this.name in tree.functions) { // 1.
28
+ try {
29
+ return tree.functions[this.name].apply(tree.functions, args);
30
+ } catch (e) {
31
+ throw { message: "error evaluating function `" + this.name + "`",
32
+ index: this.index };
33
+ }
34
+ } else { // 2.
35
+ return new(tree.Anonymous)(this.name +
36
+ "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")");
37
+ }
38
+ },
39
+
40
+ toCSS: function (env) {
41
+ return this.eval(env).toCSS();
42
+ }
43
+ };
44
+
45
+ })(require('less/tree'));
@@ -0,0 +1,98 @@
1
+ (function (tree) {
2
+ //
3
+ // RGB Colors - #ff0014, #eee
4
+ //
5
+ tree.Color = function (rgb, a) {
6
+ //
7
+ // The end goal here, is to parse the arguments
8
+ // into an integer triplet, such as `128, 255, 0`
9
+ //
10
+ // This facilitates operations and conversions.
11
+ //
12
+ if (Array.isArray(rgb)) {
13
+ this.rgb = rgb;
14
+ } else if (rgb.length == 6) {
15
+ this.rgb = rgb.match(/.{2}/g).map(function (c) {
16
+ return parseInt(c, 16);
17
+ });
18
+ } else if (rgb.length == 8) {
19
+ this.alpha = parseInt(rgb.substring(0,2), 16) / 255.0;
20
+ this.rgb = rgb.substr(2).match(/.{2}/g).map(function (c) {
21
+ return parseInt(c, 16);
22
+ });
23
+ } else {
24
+ this.rgb = rgb.split('').map(function (c) {
25
+ return parseInt(c + c, 16);
26
+ });
27
+ }
28
+ this.alpha = typeof(a) === 'number' ? a : 1;
29
+ };
30
+ tree.Color.prototype = {
31
+ eval: function () { return this },
32
+
33
+ //
34
+ // If we have some transparency, the only way to represent it
35
+ // is via `rgba`. Otherwise, we use the hex representation,
36
+ // which has better compatibility with older browsers.
37
+ // Values are capped between `0` and `255`, rounded and zero-padded.
38
+ //
39
+ toCSS: function () {
40
+ if (this.alpha < 1.0) {
41
+ return "rgba(" + this.rgb.map(function (c) {
42
+ return Math.round(c);
43
+ }).concat(this.alpha).join(', ') + ")";
44
+ } else {
45
+ return '#' + this.rgb.map(function (i) {
46
+ i = Math.round(i);
47
+ i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
48
+ return i.length === 1 ? '0' + i : i;
49
+ }).join('');
50
+ }
51
+ },
52
+
53
+ //
54
+ // Operations have to be done per-channel, if not,
55
+ // channels will spill onto each other. Once we have
56
+ // our result, in the form of an integer triplet,
57
+ // we create a new Color node to hold the result.
58
+ //
59
+ operate: function (op, other) {
60
+ var result = [];
61
+
62
+ if (! (other instanceof tree.Color)) {
63
+ other = other.toColor();
64
+ }
65
+
66
+ for (var c = 0; c < 3; c++) {
67
+ result[c] = tree.operate(op, this.rgb[c], other.rgb[c]);
68
+ }
69
+ return new(tree.Color)(result, this.alpha + other.alpha);
70
+ },
71
+
72
+ toHSL: function () {
73
+ var r = this.rgb[0] / 255,
74
+ g = this.rgb[1] / 255,
75
+ b = this.rgb[2] / 255,
76
+ a = this.alpha;
77
+
78
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
79
+ var h, s, l = (max + min) / 2, d = max - min;
80
+
81
+ if (max === min) {
82
+ h = s = 0;
83
+ } else {
84
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
85
+
86
+ switch (max) {
87
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
88
+ case g: h = (b - r) / d + 2; break;
89
+ case b: h = (r - g) / d + 4; break;
90
+ }
91
+ h /= 6;
92
+ }
93
+ return { h: h * 360, s: s, l: l, a: a };
94
+ }
95
+ };
96
+
97
+
98
+ })(require('less/tree'));
@@ -0,0 +1,14 @@
1
+ (function (tree) {
2
+
3
+ tree.Comment = function (value, silent) {
4
+ this.value = value;
5
+ this.silent = !!silent;
6
+ };
7
+ tree.Comment.prototype = {
8
+ toCSS: function (env) {
9
+ return env.compress ? '' : this.value;
10
+ },
11
+ eval: function () { return this }
12
+ };
13
+
14
+ })(require('less/tree'));
@@ -0,0 +1,34 @@
1
+ (function (tree) {
2
+
3
+ //
4
+ // A number with a unit
5
+ //
6
+ tree.Dimension = function (value, unit) {
7
+ this.value = parseFloat(value);
8
+ this.unit = unit || null;
9
+ };
10
+
11
+ tree.Dimension.prototype = {
12
+ eval: function () { return this },
13
+ toColor: function () {
14
+ return new(tree.Color)([this.value, this.value, this.value]);
15
+ },
16
+ toCSS: function () {
17
+ var css = this.value + this.unit;
18
+ return css;
19
+ },
20
+
21
+ // In an operation between two Dimensions,
22
+ // we default to the first Dimension's unit,
23
+ // so `1px + 2em` will yield `3px`.
24
+ // In the future, we could implement some unit
25
+ // conversions such that `100cm + 10mm` would yield
26
+ // `101cm`.
27
+ operate: function (op, other) {
28
+ return new(tree.Dimension)
29
+ (tree.operate(op, this.value, other.value),
30
+ this.unit || other.unit);
31
+ }
32
+ };
33
+
34
+ })(require('less/tree'));
@@ -0,0 +1,33 @@
1
+ (function (tree) {
2
+
3
+ tree.Directive = function (name, value) {
4
+ this.name = name;
5
+ if (Array.isArray(value)) {
6
+ this.ruleset = new(tree.Ruleset)([], value);
7
+ } else {
8
+ this.value = value;
9
+ }
10
+ };
11
+ tree.Directive.prototype = {
12
+ toCSS: function (ctx, env) {
13
+ if (this.ruleset) {
14
+ this.ruleset.root = true;
15
+ return this.name + (env.compress ? '{' : ' {\n ') +
16
+ this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
17
+ (env.compress ? '}': '\n}\n');
18
+ } else {
19
+ return this.name + ' ' + this.value.toCSS() + ';\n';
20
+ }
21
+ },
22
+ eval: function (env) {
23
+ env.frames.unshift(this);
24
+ this.ruleset = this.ruleset && this.ruleset.eval(env);
25
+ env.frames.shift();
26
+ return this;
27
+ },
28
+ variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
29
+ find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
30
+ rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
31
+ };
32
+
33
+ })(require('less/tree'));
@@ -0,0 +1,32 @@
1
+ (function (tree) {
2
+
3
+ tree.Element = function (combinator, value) {
4
+ this.combinator = combinator instanceof tree.Combinator ?
5
+ combinator : new(tree.Combinator)(combinator);
6
+ this.value = value.trim();
7
+ };
8
+ tree.Element.prototype.toCSS = function (env) {
9
+ return this.combinator.toCSS(env || {}) + this.value;
10
+ };
11
+
12
+ tree.Combinator = function (value) {
13
+ if (value === ' ') {
14
+ this.value = ' ';
15
+ } else {
16
+ this.value = value ? value.trim() : "";
17
+ }
18
+ };
19
+ tree.Combinator.prototype.toCSS = function (env) {
20
+ return {
21
+ '' : '',
22
+ ' ' : ' ',
23
+ '&' : '',
24
+ ':' : ' :',
25
+ '::': '::',
26
+ '+' : env.compress ? '+' : ' + ',
27
+ '~' : env.compress ? '~' : ' ~ ',
28
+ '>' : env.compress ? '>' : ' > '
29
+ }[this.value];
30
+ };
31
+
32
+ })(require('less/tree'));
@@ -0,0 +1,23 @@
1
+ (function (tree) {
2
+
3
+ tree.Expression = function (value) { this.value = value };
4
+ tree.Expression.prototype = {
5
+ eval: function (env) {
6
+ if (this.value.length > 1) {
7
+ return new(tree.Expression)(this.value.map(function (e) {
8
+ return e.eval(env);
9
+ }));
10
+ } else if (this.value.length === 1) {
11
+ return this.value[0].eval(env);
12
+ } else {
13
+ return this;
14
+ }
15
+ },
16
+ toCSS: function (env) {
17
+ return this.value.map(function (e) {
18
+ return e.toCSS(env);
19
+ }).join(' ');
20
+ }
21
+ };
22
+
23
+ })(require('less/tree'));
@@ -0,0 +1,77 @@
1
+ (function (tree) {
2
+ //
3
+ // CSS @import node
4
+ //
5
+ // The general strategy here is that we don't want to wait
6
+ // for the parsing to be completed, before we start importing
7
+ // the file. That's because in the context of a browser,
8
+ // most of the time will be spent waiting for the server to respond.
9
+ //
10
+ // On creation, we push the import path to our import queue, though
11
+ // `import,push`, we also pass it a callback, which it'll call once
12
+ // the file has been fetched, and parsed.
13
+ //
14
+ tree.Import = function (path, imports) {
15
+ var that = this;
16
+
17
+ this._path = path;
18
+
19
+ // The '.less' extension is optional
20
+ if (path instanceof tree.Quoted) {
21
+ this.path = /\.(le?|c)ss$/.test(path.value) ? path.value : path.value + '.less';
22
+ } else {
23
+ this.path = path.value.value || path.value;
24
+ }
25
+
26
+ this.css = /css$/.test(this.path);
27
+
28
+ // Only pre-compile .less files
29
+ if (! this.css) {
30
+ imports.push(this.path, function (root) {
31
+ if (! root) {
32
+ throw new(Error)("Error parsing " + that.path);
33
+ }
34
+ that.root = root;
35
+ });
36
+ }
37
+ };
38
+
39
+ //
40
+ // The actual import node doesn't return anything, when converted to CSS.
41
+ // The reason is that it's used at the evaluation stage, so that the rules
42
+ // it imports can be treated like any other rules.
43
+ //
44
+ // In `eval`, we make sure all Import nodes get evaluated, recursively, so
45
+ // we end up with a flat structure, which can easily be imported in the parent
46
+ // ruleset.
47
+ //
48
+ tree.Import.prototype = {
49
+ toCSS: function () {
50
+ if (this.css) {
51
+ return "@import " + this._path.toCSS() + ';\n';
52
+ } else {
53
+ return "";
54
+ }
55
+ },
56
+ eval: function (env) {
57
+ var ruleset;
58
+
59
+ if (this.css) {
60
+ return this;
61
+ } else {
62
+ ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0));
63
+
64
+ for (var i = 0; i < ruleset.rules.length; i++) {
65
+ if (ruleset.rules[i] instanceof tree.Import) {
66
+ Array.prototype
67
+ .splice
68
+ .apply(ruleset.rules,
69
+ [i, 1].concat(ruleset.rules[i].eval(env)));
70
+ }
71
+ }
72
+ return ruleset.rules;
73
+ }
74
+ }
75
+ };
76
+
77
+ })(require('less/tree'));
@@ -0,0 +1,51 @@
1
+ (function (tree) {
2
+
3
+ tree.JavaScript = function (string, index, escaped) {
4
+ this.escaped = escaped;
5
+ this.expression = string;
6
+ this.index = index;
7
+ };
8
+ tree.JavaScript.prototype = {
9
+ eval: function (env) {
10
+ var result,
11
+ that = this,
12
+ context = {};
13
+
14
+ var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
15
+ return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env));
16
+ });
17
+
18
+ try {
19
+ expression = new(Function)('return (' + expression + ')');
20
+ } catch (e) {
21
+ throw { message: "JavaScript evaluation error: `" + expression + "`" ,
22
+ index: this.index };
23
+ }
24
+
25
+ for (var k in env.frames[0].variables()) {
26
+ context[k.slice(1)] = {
27
+ value: env.frames[0].variables()[k].value,
28
+ toJS: function () {
29
+ return this.value.eval(env).toCSS();
30
+ }
31
+ };
32
+ }
33
+
34
+ try {
35
+ result = expression.call(context);
36
+ } catch (e) {
37
+ throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" ,
38
+ index: this.index };
39
+ }
40
+ if (typeof(result) === 'string') {
41
+ return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index);
42
+ } else if (Array.isArray(result)) {
43
+ return new(tree.Anonymous)(result.join(', '));
44
+ } else {
45
+ return new(tree.Anonymous)(result);
46
+ }
47
+ }
48
+ };
49
+
50
+ })(require('less/tree'));
51
+