less 1.2.21 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+