less 1.2.21 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -3
- data/.gitmodules +6 -0
- data/Gemfile +3 -0
- data/README.md +39 -46
- data/Rakefile +5 -50
- data/bin/lessc +1 -100
- data/less.gemspec +21 -125
- data/lib/less.rb +11 -30
- data/{LICENSE → lib/less/js/LICENSE} +1 -1
- data/lib/less/js/Makefile +56 -0
- data/lib/less/js/README.md +20 -0
- data/lib/less/js/benchmark/benchmark.less +3979 -0
- data/lib/less/js/benchmark/less-benchmark.js +49 -0
- data/lib/less/js/bin/lessc +105 -0
- data/lib/less/js/build/ecma-5.js +120 -0
- data/lib/less/js/build/header.js +7 -0
- data/lib/less/js/build/require.js +7 -0
- data/lib/less/js/dist/less-1.0.44.js +2655 -0
- data/lib/less/js/dist/less-1.1.0.js +2695 -0
- data/lib/less/js/dist/less-1.1.0.min.js +16 -0
- data/lib/less/js/dist/less-1.1.1.js +2710 -0
- data/lib/less/js/dist/less-1.1.1.min.js +16 -0
- data/lib/less/js/dist/less-1.1.2.js +2712 -0
- data/lib/less/js/dist/less-1.1.2.min.js +16 -0
- data/lib/less/js/dist/less-1.1.3.js +2721 -0
- data/lib/less/js/dist/less-1.1.3.min.js +16 -0
- data/lib/less/js/lib/less/browser.js +369 -0
- data/lib/less/js/lib/less/functions.js +174 -0
- data/lib/less/js/lib/less/index.js +137 -0
- data/lib/less/js/lib/less/parser.js +1098 -0
- data/lib/less/js/lib/less/tree.js +13 -0
- data/lib/less/js/lib/less/tree/alpha.js +17 -0
- data/lib/less/js/lib/less/tree/anonymous.js +13 -0
- data/lib/less/js/lib/less/tree/call.js +45 -0
- data/lib/less/js/lib/less/tree/color.js +98 -0
- data/lib/less/js/lib/less/tree/comment.js +14 -0
- data/lib/less/js/lib/less/tree/dimension.js +34 -0
- data/lib/less/js/lib/less/tree/directive.js +33 -0
- data/lib/less/js/lib/less/tree/element.js +32 -0
- data/lib/less/js/lib/less/tree/expression.js +23 -0
- data/lib/less/js/lib/less/tree/import.js +77 -0
- data/lib/less/js/lib/less/tree/javascript.js +51 -0
- data/lib/less/js/lib/less/tree/keyword.js +9 -0
- data/lib/less/js/lib/less/tree/mixin.js +106 -0
- data/lib/less/js/lib/less/tree/operation.js +32 -0
- data/lib/less/js/lib/less/tree/quoted.js +29 -0
- data/lib/less/js/lib/less/tree/rule.js +38 -0
- data/lib/less/js/lib/less/tree/ruleset.js +179 -0
- data/lib/less/js/lib/less/tree/selector.js +28 -0
- data/lib/less/js/lib/less/tree/url.js +25 -0
- data/lib/less/js/lib/less/tree/value.js +24 -0
- data/lib/less/js/lib/less/tree/variable.js +24 -0
- data/lib/less/js/package.json +13 -0
- data/lib/less/js/test/css/colors.css +42 -0
- data/lib/less/js/test/css/comments.css +52 -0
- data/lib/less/js/test/css/css-3.css +42 -0
- data/lib/less/js/test/css/css-escapes.css +20 -0
- data/lib/less/js/test/css/css.css +82 -0
- data/lib/less/js/test/css/functions.css +30 -0
- data/{spec → lib/less/js/test}/css/import.css +4 -2
- data/lib/less/js/test/css/javascript.css +22 -0
- data/lib/less/js/test/css/lazy-eval.css +3 -0
- data/lib/less/js/test/css/media.css +21 -0
- data/lib/less/js/test/css/mixins-args.css +61 -0
- data/lib/less/js/test/css/mixins-closure.css +9 -0
- data/lib/less/js/test/css/mixins-nested.css +14 -0
- data/lib/less/js/test/css/mixins-pattern.css +49 -0
- data/lib/less/js/test/css/mixins.css +50 -0
- data/{spec → lib/less/js/test}/css/operations.css +20 -2
- data/{spec → lib/less/js/test}/css/parens.css +0 -0
- data/lib/less/js/test/css/rulesets.css +29 -0
- data/{spec → lib/less/js/test}/css/scope.css +6 -2
- data/lib/less/js/test/css/selectors.css +32 -0
- data/lib/less/js/test/css/strings.css +38 -0
- data/lib/less/js/test/css/variables.css +24 -0
- data/lib/less/js/test/css/whitespace.css +36 -0
- data/lib/less/js/test/less-test.js +75 -0
- data/{spec → lib/less/js/test}/less/colors.less +13 -2
- data/{spec → lib/less/js/test}/less/comments.less +19 -2
- data/{spec → lib/less/js/test}/less/css-3.less +4 -1
- data/lib/less/js/test/less/css-escapes.less +28 -0
- data/{spec → lib/less/js/test}/less/css.less +10 -18
- data/lib/less/js/test/less/functions.less +35 -0
- data/{spec → lib/less/js/test}/less/import.less +1 -1
- data/{spec → lib/less/js/test}/less/import/import-test-a.less +0 -0
- data/{spec → lib/less/js/test}/less/import/import-test-b.less +0 -0
- data/{spec → lib/less/js/test}/less/import/import-test-c.less +0 -0
- data/{spec → lib/less/js/test}/less/import/import-test-d.css +0 -0
- data/lib/less/js/test/less/javascript.less +27 -0
- data/{spec → lib/less/js/test}/less/lazy-eval.less +0 -0
- data/lib/less/js/test/less/media.less +25 -0
- data/lib/less/js/test/less/mixins-args.less +118 -0
- data/lib/less/js/test/less/mixins-closure.less +26 -0
- data/lib/less/js/test/less/mixins-nested.less +22 -0
- data/lib/less/js/test/less/mixins-pattern.less +96 -0
- data/{spec → lib/less/js/test}/less/mixins.less +8 -4
- data/{spec → lib/less/js/test}/less/operations.less +19 -0
- data/{spec → lib/less/js/test}/less/parens.less +0 -0
- data/{spec → lib/less/js/test}/less/rulesets.less +2 -2
- data/{spec → lib/less/js/test}/less/scope.less +1 -1
- data/{spec → lib/less/js/test}/less/selectors.less +1 -1
- data/lib/less/js/test/less/strings.less +49 -0
- data/lib/less/js/test/less/variables.less +50 -0
- data/{spec → lib/less/js/test}/less/whitespace.less +3 -0
- data/lib/less/loader.rb +67 -0
- data/lib/less/parser.rb +46 -0
- data/lib/less/version.rb +3 -0
- data/spec/less/one/one.less +1 -0
- data/spec/less/parser_spec.rb +30 -0
- data/spec/less/two/two.less +1 -0
- data/spec/spec_helper.rb +2 -7
- metadata +156 -106
- data/CHANGELOG +0 -62
- data/VERSION +0 -1
- data/lib/less/command.rb +0 -110
- data/lib/less/engine.rb +0 -52
- data/lib/less/engine/grammar/common.tt +0 -29
- data/lib/less/engine/grammar/entity.tt +0 -144
- data/lib/less/engine/grammar/less.tt +0 -341
- data/lib/less/engine/nodes.rb +0 -9
- data/lib/less/engine/nodes/element.rb +0 -281
- data/lib/less/engine/nodes/entity.rb +0 -79
- data/lib/less/engine/nodes/function.rb +0 -93
- data/lib/less/engine/nodes/literal.rb +0 -171
- data/lib/less/engine/nodes/property.rb +0 -232
- data/lib/less/engine/nodes/ruleset.rb +0 -12
- data/lib/less/engine/nodes/selector.rb +0 -44
- data/lib/less/ext.rb +0 -60
- data/spec/command_spec.rb +0 -102
- data/spec/css/accessors.css +0 -18
- data/spec/css/big.css +0 -3768
- data/spec/css/colors.css +0 -14
- data/spec/css/comments.css +0 -9
- data/spec/css/css-3.css +0 -21
- data/spec/css/css.css +0 -50
- data/spec/css/dash-prefix.css +0 -12
- data/spec/css/functions.css +0 -6
- data/spec/css/import-with-extra-paths.css +0 -8
- data/spec/css/import-with-partial-in-extra-path.css +0 -6
- data/spec/css/lazy-eval.css +0 -1
- data/spec/css/mixins-args.css +0 -32
- data/spec/css/mixins.css +0 -28
- data/spec/css/rulesets.css +0 -17
- data/spec/css/selectors.css +0 -13
- data/spec/css/strings.css +0 -12
- data/spec/css/variables.css +0 -8
- data/spec/css/whitespace.css +0 -7
- data/spec/engine_spec.rb +0 -127
- data/spec/less/accessors.less +0 -20
- data/spec/less/big.less +0 -1264
- data/spec/less/dash-prefix.less +0 -21
- data/spec/less/exceptions/mixed-units-error.less +0 -3
- data/spec/less/exceptions/name-error-1.0.less +0 -3
- data/spec/less/exceptions/syntax-error-1.0.less +0 -3
- data/spec/less/extra_import_path/extra.less +0 -1
- data/spec/less/extra_import_path/import/import-test-a.css +0 -1
- data/spec/less/extra_import_path/import/import-test-a.less +0 -4
- data/spec/less/functions.less +0 -6
- data/spec/less/hidden.less +0 -25
- data/spec/less/import-with-extra-paths.less +0 -4
- data/spec/less/literal-css.less +0 -11
- data/spec/less/mixins-args.less +0 -59
- data/spec/less/strings.less +0 -14
- data/spec/less/variables.less +0 -29
- 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
|
+
|