less 2.0.4 → 2.1.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.
- data/.gitmodules +0 -3
- data/.travis.yml +10 -0
- data/README.md +1 -1
- data/Rakefile +2 -0
- data/bin/lessc +21 -2
- data/less.gemspec +5 -3
- data/lib/less/defaults.rb +13 -0
- data/lib/less/js/CHANGELOG +41 -0
- data/lib/less/js/Makefile +21 -2
- data/lib/less/js/benchmark/benchmark.less +11 -11
- data/lib/less/js/benchmark/less-benchmark.js +3 -5
- data/lib/less/js/bin/lessc +52 -18
- data/lib/less/js/build/amd.js +6 -0
- data/lib/less/js/build/require-rhino.js +7 -0
- data/lib/less/js/dist/{less-1.0.44.js → less-1.1.4.js} +159 -45
- data/lib/less/js/dist/less-1.1.4.min.js +16 -0
- data/lib/less/js/dist/less-1.1.5.js +2805 -0
- data/lib/less/js/dist/less-1.1.5.min.js +9 -0
- data/lib/less/js/dist/less-1.1.6.js +3004 -0
- data/lib/less/js/dist/less-1.1.6.min.js +9 -0
- data/lib/less/js/dist/less-1.2.0.js +3293 -0
- data/lib/less/js/dist/less-1.2.0.min.js +9 -0
- data/lib/less/js/dist/less-1.2.1.js +3318 -0
- data/lib/less/js/dist/less-1.2.1.min.js +9 -0
- data/lib/less/js/dist/less-1.2.2.js +3337 -0
- data/lib/less/js/dist/less-1.2.2.min.js +9 -0
- data/lib/less/js/dist/less-1.3.0.js +3478 -0
- data/lib/less/js/dist/less-1.3.0.min.js +9 -0
- data/lib/less/js/dist/less-rhino-1.1.3.js +2460 -0
- data/lib/less/js/dist/less-rhino-1.1.5.js +2481 -0
- data/lib/less/js/lib/less/browser.js +38 -27
- data/lib/less/js/lib/less/colors.js +151 -0
- data/lib/less/js/lib/less/cssmin.js +355 -0
- data/lib/less/js/lib/less/functions.js +61 -7
- data/lib/less/js/lib/less/index.js +48 -37
- data/lib/less/js/lib/less/parser.js +327 -120
- data/lib/less/js/lib/less/rhino.js +62 -0
- data/lib/less/js/lib/less/tree/alpha.js +1 -1
- data/lib/less/js/lib/less/tree/anonymous.js +1 -1
- data/lib/less/js/lib/less/tree/assignment.js +17 -0
- data/lib/less/js/lib/less/tree/call.js +7 -4
- data/lib/less/js/lib/less/tree/color.js +9 -6
- data/lib/less/js/lib/less/tree/comment.js +1 -1
- data/lib/less/js/lib/less/tree/condition.js +42 -0
- data/lib/less/js/lib/less/tree/dimension.js +16 -1
- data/lib/less/js/lib/less/tree/directive.js +4 -2
- data/lib/less/js/lib/less/tree/element.js +20 -5
- data/lib/less/js/lib/less/tree/expression.js +2 -2
- data/lib/less/js/lib/less/tree/import.js +16 -14
- data/lib/less/js/lib/less/tree/javascript.js +1 -1
- data/lib/less/js/lib/less/tree/keyword.js +12 -2
- data/lib/less/js/lib/less/tree/media.js +114 -0
- data/lib/less/js/lib/less/tree/mixin.js +49 -20
- data/lib/less/js/lib/less/tree/operation.js +1 -1
- data/lib/less/js/lib/less/tree/paren.js +16 -0
- data/lib/less/js/lib/less/tree/quoted.js +2 -2
- data/lib/less/js/lib/less/tree/rule.js +8 -4
- data/lib/less/js/lib/less/tree/ruleset.js +49 -12
- data/lib/less/js/lib/less/tree/selector.js +18 -4
- data/lib/less/js/lib/less/tree/url.js +2 -2
- data/lib/less/js/lib/less/tree/value.js +1 -1
- data/lib/less/js/lib/less/tree/variable.js +5 -3
- data/lib/less/js/lib/less/tree.js +6 -2
- data/lib/less/js/package.json +2 -2
- data/lib/less/js/test/css/colors.css +16 -0
- data/lib/less/js/test/css/comments.css +9 -5
- data/lib/less/js/test/css/css-3.css +18 -2
- data/lib/less/js/test/css/css-escapes.css +1 -1
- data/lib/less/js/test/css/css.css +11 -4
- data/lib/less/js/test/css/functions.css +13 -0
- data/lib/less/js/test/css/ie-filters.css +5 -0
- data/lib/less/js/test/css/import.css +12 -3
- data/lib/less/js/test/css/media.css +60 -2
- data/lib/less/js/test/css/mixins-args.css +17 -2
- data/lib/less/js/test/css/mixins-guards.css +58 -0
- data/lib/less/js/test/css/mixins-important.css +17 -0
- data/lib/less/js/test/css/mixins-pattern.css +4 -6
- data/lib/less/js/test/css/mixins.css +21 -0
- data/lib/less/js/test/css/operations.css +3 -0
- data/lib/less/js/test/css/parens.css +1 -1
- data/lib/less/js/test/css/rulesets.css +6 -2
- data/lib/less/js/test/css/scope.css +6 -6
- data/lib/less/js/test/css/selectors.css +38 -1
- data/lib/less/js/test/css/strings.css +6 -4
- data/lib/less/js/test/css/variables.css +3 -0
- data/lib/less/js/test/css/whitespace.css +5 -3
- data/lib/less/js/test/less/colors.less +19 -0
- data/lib/less/js/test/less/comments.less +8 -6
- data/lib/less/js/test/less/css-3.less +10 -0
- data/lib/less/js/test/less/css.less +4 -0
- data/lib/less/js/test/less/functions.less +15 -1
- data/lib/less/js/test/less/ie-filters.less +8 -0
- data/lib/less/js/test/less/import/import-test-e.less +2 -0
- data/lib/less/js/test/less/import.less +4 -1
- data/lib/less/js/test/less/media.less +55 -1
- data/lib/less/js/test/less/mixins-args.less +20 -1
- data/lib/less/js/test/less/mixins-guards.less +94 -0
- data/lib/less/js/test/less/mixins-important.less +18 -0
- data/lib/less/js/test/less/mixins-pattern.less +3 -0
- data/lib/less/js/test/less/mixins.less +20 -0
- data/lib/less/js/test/less/operations.less +4 -0
- data/lib/less/js/test/less/selectors.less +31 -0
- data/lib/less/js/test/less/strings.less +2 -0
- data/lib/less/js/test/less/variables.less +4 -0
- data/lib/less/js/test/less-test.js +3 -5
- data/lib/less/loader.rb +24 -25
- data/lib/less/parser.rb +32 -6
- data/lib/less/version.rb +1 -1
- data/lib/less.rb +7 -8
- data/spec/less/faulty/faulty.less +3 -0
- data/spec/less/parser_spec.rb +28 -2
- metadata +321 -149
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
var name;
|
|
2
|
+
|
|
3
|
+
function loadStyleSheet(sheet, callback, reload, remaining) {
|
|
4
|
+
var sheetName = name.slice(0, name.lastIndexOf('/') + 1) + sheet.href;
|
|
5
|
+
var input = readFile(sheetName);
|
|
6
|
+
var parser = new less.Parser({
|
|
7
|
+
paths: [sheet.href.replace(/[\w\.-]+$/, '')]
|
|
8
|
+
});
|
|
9
|
+
parser.parse(input, function (e, root) {
|
|
10
|
+
if (e) {
|
|
11
|
+
print("Error: " + e);
|
|
12
|
+
quit(1);
|
|
13
|
+
}
|
|
14
|
+
callback(root, sheet, { local: false, lastModified: 0, remaining: remaining });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// callback({}, sheet, { local: true, remaining: remaining });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function writeFile(filename, content) {
|
|
21
|
+
var fstream = new java.io.FileWriter(filename);
|
|
22
|
+
var out = new java.io.BufferedWriter(fstream);
|
|
23
|
+
out.write(content);
|
|
24
|
+
out.close();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Command line integration via Rhino
|
|
28
|
+
(function (args) {
|
|
29
|
+
name = args[0];
|
|
30
|
+
var output = args[1];
|
|
31
|
+
|
|
32
|
+
if (!name) {
|
|
33
|
+
print('No files present in the fileset; Check your pattern match in build.xml');
|
|
34
|
+
quit(1);
|
|
35
|
+
}
|
|
36
|
+
path = name.split("/");path.pop();path=path.join("/")
|
|
37
|
+
|
|
38
|
+
var input = readFile(name);
|
|
39
|
+
|
|
40
|
+
if (!input) {
|
|
41
|
+
print('lesscss: couldn\'t open file ' + name);
|
|
42
|
+
quit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var result;
|
|
46
|
+
var parser = new less.Parser();
|
|
47
|
+
parser.parse(input, function (e, root) {
|
|
48
|
+
if (e) {
|
|
49
|
+
quit(1);
|
|
50
|
+
} else {
|
|
51
|
+
result = root.toCSS();
|
|
52
|
+
if (output) {
|
|
53
|
+
writeFile(output, result);
|
|
54
|
+
print("Written to " + output);
|
|
55
|
+
} else {
|
|
56
|
+
print(result);
|
|
57
|
+
}
|
|
58
|
+
quit(0);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
print("done");
|
|
62
|
+
}(arguments));
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
(function (tree) {
|
|
2
|
+
|
|
3
|
+
tree.Assignment = function (key, val) {
|
|
4
|
+
this.key = key;
|
|
5
|
+
this.value = val;
|
|
6
|
+
};
|
|
7
|
+
tree.Assignment.prototype = {
|
|
8
|
+
toCSS: function () {
|
|
9
|
+
return this.key + '=' + (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('../tree'));
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
//
|
|
4
4
|
// A function call node.
|
|
5
5
|
//
|
|
6
|
-
tree.Call = function (name, args, index) {
|
|
6
|
+
tree.Call = function (name, args, index, filename) {
|
|
7
7
|
this.name = name;
|
|
8
8
|
this.args = args;
|
|
9
9
|
this.index = index;
|
|
10
|
+
this.filename = filename;
|
|
10
11
|
};
|
|
11
12
|
tree.Call.prototype = {
|
|
12
13
|
//
|
|
@@ -28,8 +29,10 @@ tree.Call.prototype = {
|
|
|
28
29
|
try {
|
|
29
30
|
return tree.functions[this.name].apply(tree.functions, args);
|
|
30
31
|
} catch (e) {
|
|
31
|
-
throw {
|
|
32
|
-
|
|
32
|
+
throw { type: e.type || "Runtime",
|
|
33
|
+
message: "error evaluating function `" + this.name + "`" +
|
|
34
|
+
(e.message ? ': ' + e.message : ''),
|
|
35
|
+
index: this.index, filename: this.filename };
|
|
33
36
|
}
|
|
34
37
|
} else { // 2.
|
|
35
38
|
return new(tree.Anonymous)(this.name +
|
|
@@ -42,4 +45,4 @@ tree.Call.prototype = {
|
|
|
42
45
|
}
|
|
43
46
|
};
|
|
44
47
|
|
|
45
|
-
})(require('
|
|
48
|
+
})(require('../tree'));
|
|
@@ -15,11 +15,6 @@ tree.Color = function (rgb, a) {
|
|
|
15
15
|
this.rgb = rgb.match(/.{2}/g).map(function (c) {
|
|
16
16
|
return parseInt(c, 16);
|
|
17
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
18
|
} else {
|
|
24
19
|
this.rgb = rgb.split('').map(function (c) {
|
|
25
20
|
return parseInt(c + c, 16);
|
|
@@ -91,8 +86,16 @@ tree.Color.prototype = {
|
|
|
91
86
|
h /= 6;
|
|
92
87
|
}
|
|
93
88
|
return { h: h * 360, s: s, l: l, a: a };
|
|
89
|
+
},
|
|
90
|
+
toARGB: function () {
|
|
91
|
+
var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
|
|
92
|
+
return '#' + argb.map(function (i) {
|
|
93
|
+
i = Math.round(i);
|
|
94
|
+
i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
|
|
95
|
+
return i.length === 1 ? '0' + i : i;
|
|
96
|
+
}).join('');
|
|
94
97
|
}
|
|
95
98
|
};
|
|
96
99
|
|
|
97
100
|
|
|
98
|
-
})(require('
|
|
101
|
+
})(require('../tree'));
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
(function (tree) {
|
|
2
|
+
|
|
3
|
+
tree.Condition = function (op, l, r, i, negate) {
|
|
4
|
+
this.op = op.trim();
|
|
5
|
+
this.lvalue = l;
|
|
6
|
+
this.rvalue = r;
|
|
7
|
+
this.index = i;
|
|
8
|
+
this.negate = negate;
|
|
9
|
+
};
|
|
10
|
+
tree.Condition.prototype.eval = function (env) {
|
|
11
|
+
var a = this.lvalue.eval(env),
|
|
12
|
+
b = this.rvalue.eval(env);
|
|
13
|
+
|
|
14
|
+
var i = this.index, result;
|
|
15
|
+
|
|
16
|
+
var result = (function (op) {
|
|
17
|
+
switch (op) {
|
|
18
|
+
case 'and':
|
|
19
|
+
return a && b;
|
|
20
|
+
case 'or':
|
|
21
|
+
return a || b;
|
|
22
|
+
default:
|
|
23
|
+
if (a.compare) {
|
|
24
|
+
result = a.compare(b);
|
|
25
|
+
} else if (b.compare) {
|
|
26
|
+
result = b.compare(a);
|
|
27
|
+
} else {
|
|
28
|
+
throw { type: "Type",
|
|
29
|
+
message: "Unable to perform comparison",
|
|
30
|
+
index: i };
|
|
31
|
+
}
|
|
32
|
+
switch (result) {
|
|
33
|
+
case -1: return op === '<' || op === '=<';
|
|
34
|
+
case 0: return op === '=' || op === '>=' || op === '=<';
|
|
35
|
+
case 1: return op === '>' || op === '>=';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
})(this.op);
|
|
39
|
+
return this.negate ? !result : result;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
})(require('../tree'));
|
|
@@ -28,7 +28,22 @@ tree.Dimension.prototype = {
|
|
|
28
28
|
return new(tree.Dimension)
|
|
29
29
|
(tree.operate(op, this.value, other.value),
|
|
30
30
|
this.unit || other.unit);
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
// TODO: Perform unit conversion before comparing
|
|
34
|
+
compare: function (other) {
|
|
35
|
+
if (other instanceof tree.Dimension) {
|
|
36
|
+
if (other.value > this.value) {
|
|
37
|
+
return -1;
|
|
38
|
+
} else if (other.value < this.value) {
|
|
39
|
+
return 1;
|
|
40
|
+
} else {
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
return -1;
|
|
45
|
+
}
|
|
31
46
|
}
|
|
32
47
|
};
|
|
33
48
|
|
|
34
|
-
})(require('
|
|
49
|
+
})(require('../tree'));
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
(function (tree) {
|
|
2
2
|
|
|
3
|
-
tree.Directive = function (name, value) {
|
|
3
|
+
tree.Directive = function (name, value, features) {
|
|
4
4
|
this.name = name;
|
|
5
|
+
|
|
5
6
|
if (Array.isArray(value)) {
|
|
6
7
|
this.ruleset = new(tree.Ruleset)([], value);
|
|
8
|
+
this.ruleset.allowImports = true;
|
|
7
9
|
} else {
|
|
8
10
|
this.value = value;
|
|
9
11
|
}
|
|
@@ -30,4 +32,4 @@ tree.Directive.prototype = {
|
|
|
30
32
|
rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
|
|
31
33
|
};
|
|
32
34
|
|
|
33
|
-
})(require('
|
|
35
|
+
})(require('../tree'));
|
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
(function (tree) {
|
|
2
2
|
|
|
3
|
-
tree.Element = function (combinator, value) {
|
|
3
|
+
tree.Element = function (combinator, value, index) {
|
|
4
4
|
this.combinator = combinator instanceof tree.Combinator ?
|
|
5
5
|
combinator : new(tree.Combinator)(combinator);
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
if (typeof(value) === 'string') {
|
|
8
|
+
this.value = value.trim();
|
|
9
|
+
} else if (value) {
|
|
10
|
+
this.value = value;
|
|
11
|
+
} else {
|
|
12
|
+
this.value = "";
|
|
13
|
+
}
|
|
14
|
+
this.index = index;
|
|
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);
|
|
7
20
|
};
|
|
8
21
|
tree.Element.prototype.toCSS = function (env) {
|
|
9
|
-
return this.combinator.toCSS(env || {}) + this.value;
|
|
22
|
+
return this.combinator.toCSS(env || {}) + (this.value.toCSS ? this.value.toCSS(env) : this.value);
|
|
10
23
|
};
|
|
11
24
|
|
|
12
25
|
tree.Combinator = function (value) {
|
|
13
26
|
if (value === ' ') {
|
|
14
27
|
this.value = ' ';
|
|
28
|
+
} else if (value === '& ') {
|
|
29
|
+
this.value = '& ';
|
|
15
30
|
} else {
|
|
16
31
|
this.value = value ? value.trim() : "";
|
|
17
32
|
}
|
|
@@ -21,12 +36,12 @@ tree.Combinator.prototype.toCSS = function (env) {
|
|
|
21
36
|
'' : '',
|
|
22
37
|
' ' : ' ',
|
|
23
38
|
'&' : '',
|
|
39
|
+
'& ' : ' ',
|
|
24
40
|
':' : ' :',
|
|
25
|
-
'::': '::',
|
|
26
41
|
'+' : env.compress ? '+' : ' + ',
|
|
27
42
|
'~' : env.compress ? '~' : ' ~ ',
|
|
28
43
|
'>' : env.compress ? '>' : ' > '
|
|
29
44
|
}[this.value];
|
|
30
45
|
};
|
|
31
46
|
|
|
32
|
-
})(require('
|
|
47
|
+
})(require('../tree'));
|
|
@@ -11,27 +11,27 @@
|
|
|
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) {
|
|
14
|
+
tree.Import = function (path, imports, features, index) {
|
|
15
15
|
var that = this;
|
|
16
16
|
|
|
17
|
+
this.index = index;
|
|
17
18
|
this._path = path;
|
|
19
|
+
this.features = features && new(tree.Value)(features);
|
|
18
20
|
|
|
19
21
|
// The '.less' extension is optional
|
|
20
22
|
if (path instanceof tree.Quoted) {
|
|
21
|
-
this.path = /\.(le?|c)ss
|
|
23
|
+
this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less';
|
|
22
24
|
} else {
|
|
23
25
|
this.path = path.value.value || path.value;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
this.css = /css
|
|
28
|
+
this.css = /css(\?.*)?$/.test(this.path);
|
|
27
29
|
|
|
28
30
|
// Only pre-compile .less files
|
|
29
31
|
if (! this.css) {
|
|
30
|
-
imports.push(this.path, function (root) {
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
that.root = root;
|
|
32
|
+
imports.push(this.path, function (e, root) {
|
|
33
|
+
if (e) { e.index = index }
|
|
34
|
+
that.root = root || new(tree.Ruleset)([], []);
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
};
|
|
@@ -46,20 +46,22 @@ tree.Import = function (path, imports) {
|
|
|
46
46
|
// ruleset.
|
|
47
47
|
//
|
|
48
48
|
tree.Import.prototype = {
|
|
49
|
-
toCSS: function () {
|
|
49
|
+
toCSS: function (env) {
|
|
50
|
+
var features = this.features ? ' ' + this.features.toCSS(env) : '';
|
|
51
|
+
|
|
50
52
|
if (this.css) {
|
|
51
|
-
return "@import " + this._path.toCSS() + ';\n';
|
|
53
|
+
return "@import " + this._path.toCSS() + features + ';\n';
|
|
52
54
|
} else {
|
|
53
55
|
return "";
|
|
54
56
|
}
|
|
55
57
|
},
|
|
56
58
|
eval: function (env) {
|
|
57
|
-
var ruleset;
|
|
59
|
+
var ruleset, features = this.features && this.features.eval(env);
|
|
58
60
|
|
|
59
61
|
if (this.css) {
|
|
60
62
|
return this;
|
|
61
63
|
} else {
|
|
62
|
-
ruleset = new(tree.Ruleset)(
|
|
64
|
+
ruleset = new(tree.Ruleset)([], this.root.rules.slice(0));
|
|
63
65
|
|
|
64
66
|
for (var i = 0; i < ruleset.rules.length; i++) {
|
|
65
67
|
if (ruleset.rules[i] instanceof tree.Import) {
|
|
@@ -69,9 +71,9 @@ tree.Import.prototype = {
|
|
|
69
71
|
[i, 1].concat(ruleset.rules[i].eval(env)));
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
|
-
return ruleset.rules;
|
|
74
|
+
return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
};
|
|
76
78
|
|
|
77
|
-
})(require('
|
|
79
|
+
})(require('../tree'));
|
|
@@ -3,7 +3,17 @@
|
|
|
3
3
|
tree.Keyword = function (value) { this.value = value };
|
|
4
4
|
tree.Keyword.prototype = {
|
|
5
5
|
eval: function () { return this },
|
|
6
|
-
toCSS: function () { return this.value }
|
|
6
|
+
toCSS: function () { return this.value },
|
|
7
|
+
compare: function (other) {
|
|
8
|
+
if (other instanceof tree.Keyword) {
|
|
9
|
+
return other.value === this.value ? 0 : 1;
|
|
10
|
+
} else {
|
|
11
|
+
return -1;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
7
14
|
};
|
|
8
15
|
|
|
9
|
-
|
|
16
|
+
tree.True = new(tree.Keyword)('true');
|
|
17
|
+
tree.False = new(tree.Keyword)('false');
|
|
18
|
+
|
|
19
|
+
})(require('../tree'));
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
(function (tree) {
|
|
2
|
+
|
|
3
|
+
tree.Media = function (value, features) {
|
|
4
|
+
var el = new(tree.Element)('&', null, 0),
|
|
5
|
+
selectors = [new(tree.Selector)([el])];
|
|
6
|
+
|
|
7
|
+
this.features = new(tree.Value)(features);
|
|
8
|
+
this.ruleset = new(tree.Ruleset)(selectors, value);
|
|
9
|
+
this.ruleset.allowImports = true;
|
|
10
|
+
};
|
|
11
|
+
tree.Media.prototype = {
|
|
12
|
+
toCSS: function (ctx, env) {
|
|
13
|
+
var features = this.features.toCSS(env);
|
|
14
|
+
|
|
15
|
+
this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia);
|
|
16
|
+
return '@media ' + features + (env.compress ? '{' : ' {\n ') +
|
|
17
|
+
this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
|
|
18
|
+
(env.compress ? '}': '\n}\n');
|
|
19
|
+
},
|
|
20
|
+
eval: function (env) {
|
|
21
|
+
if (!env.mediaBlocks) {
|
|
22
|
+
env.mediaBlocks = [];
|
|
23
|
+
env.mediaPath = [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var blockIndex = env.mediaBlocks.length;
|
|
27
|
+
env.mediaPath.push(this);
|
|
28
|
+
env.mediaBlocks.push(this);
|
|
29
|
+
|
|
30
|
+
var media = new(tree.Media)([], []);
|
|
31
|
+
media.features = this.features.eval(env);
|
|
32
|
+
|
|
33
|
+
env.frames.unshift(this.ruleset);
|
|
34
|
+
media.ruleset = this.ruleset.eval(env);
|
|
35
|
+
env.frames.shift();
|
|
36
|
+
|
|
37
|
+
env.mediaBlocks[blockIndex] = media;
|
|
38
|
+
env.mediaPath.pop();
|
|
39
|
+
|
|
40
|
+
return env.mediaPath.length === 0 ? media.evalTop(env) :
|
|
41
|
+
media.evalNested(env)
|
|
42
|
+
},
|
|
43
|
+
variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
|
|
44
|
+
find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
|
|
45
|
+
rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) },
|
|
46
|
+
|
|
47
|
+
evalTop: function (env) {
|
|
48
|
+
var result = this;
|
|
49
|
+
|
|
50
|
+
// Render all dependent Media blocks.
|
|
51
|
+
if (env.mediaBlocks.length > 1) {
|
|
52
|
+
var el = new(tree.Element)('&', null, 0);
|
|
53
|
+
var selectors = [new(tree.Selector)([el])];
|
|
54
|
+
result = new(tree.Ruleset)(selectors, env.mediaBlocks);
|
|
55
|
+
result.multiMedia = true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
delete env.mediaBlocks;
|
|
59
|
+
delete env.mediaPath;
|
|
60
|
+
|
|
61
|
+
return result;
|
|
62
|
+
},
|
|
63
|
+
evalNested: function (env) {
|
|
64
|
+
var i, value,
|
|
65
|
+
path = env.mediaPath.concat([this]);
|
|
66
|
+
|
|
67
|
+
// Extract the media-query conditions separated with `,` (OR).
|
|
68
|
+
for (i = 0; i < path.length; i++) {
|
|
69
|
+
value = path[i].features instanceof tree.Value ?
|
|
70
|
+
path[i].features.value : path[i].features;
|
|
71
|
+
path[i] = Array.isArray(value) ? value : [value];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Trace all permutations to generate the resulting media-query.
|
|
75
|
+
//
|
|
76
|
+
// (a, b and c) with nested (d, e) ->
|
|
77
|
+
// a and d
|
|
78
|
+
// a and e
|
|
79
|
+
// b and c and d
|
|
80
|
+
// b and c and e
|
|
81
|
+
this.features = new(tree.Value)(this.permute(path).map(function (path) {
|
|
82
|
+
path = path.map(function (fragment) {
|
|
83
|
+
return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
for(i = path.length - 1; i > 0; i--) {
|
|
87
|
+
path.splice(i, 0, new(tree.Anonymous)("and"));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return new(tree.Expression)(path);
|
|
91
|
+
}));
|
|
92
|
+
|
|
93
|
+
// Fake a tree-node that doesn't output anything.
|
|
94
|
+
return new(tree.Ruleset)([], []);
|
|
95
|
+
},
|
|
96
|
+
permute: function (arr) {
|
|
97
|
+
if (arr.length === 0) {
|
|
98
|
+
return [];
|
|
99
|
+
} else if (arr.length === 1) {
|
|
100
|
+
return arr[0];
|
|
101
|
+
} else {
|
|
102
|
+
var result = [];
|
|
103
|
+
var rest = this.permute(arr.slice(1));
|
|
104
|
+
for (var i = 0; i < rest.length; i++) {
|
|
105
|
+
for (var j = 0; j < arr[0].length; j++) {
|
|
106
|
+
result.push([arr[0][j]].concat(rest[i]));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
})(require('../tree'));
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
(function (tree) {
|
|
2
2
|
|
|
3
3
|
tree.mixin = {};
|
|
4
|
-
tree.mixin.Call = function (elements, args, index) {
|
|
4
|
+
tree.mixin.Call = function (elements, args, index, filename, important) {
|
|
5
5
|
this.selector = new(tree.Selector)(elements);
|
|
6
6
|
this.arguments = args;
|
|
7
7
|
this.index = index;
|
|
8
|
+
this.filename = filename;
|
|
9
|
+
this.important = important;
|
|
8
10
|
};
|
|
9
11
|
tree.mixin.Call.prototype = {
|
|
10
12
|
eval: function (env) {
|
|
@@ -17,34 +19,38 @@ tree.mixin.Call.prototype = {
|
|
|
17
19
|
if (mixins[m].match(args, env)) {
|
|
18
20
|
try {
|
|
19
21
|
Array.prototype.push.apply(
|
|
20
|
-
rules, mixins[m].eval(env, this.arguments).rules);
|
|
22
|
+
rules, mixins[m].eval(env, this.arguments, this.important).rules);
|
|
21
23
|
match = true;
|
|
22
24
|
} catch (e) {
|
|
23
|
-
throw { message: e.message, index:
|
|
25
|
+
throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack };
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
if (match) {
|
|
28
30
|
return rules;
|
|
29
31
|
} else {
|
|
30
|
-
throw {
|
|
32
|
+
throw { type: 'Runtime',
|
|
33
|
+
message: 'No matching definition was found for `' +
|
|
31
34
|
this.selector.toCSS().trim() + '(' +
|
|
32
35
|
this.arguments.map(function (a) {
|
|
33
36
|
return a.toCSS();
|
|
34
37
|
}).join(', ') + ")`",
|
|
35
|
-
index: this.index };
|
|
38
|
+
index: this.index, filename: this.filename };
|
|
36
39
|
}
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
|
-
throw {
|
|
40
|
-
|
|
42
|
+
throw { type: 'Name',
|
|
43
|
+
message: this.selector.toCSS().trim() + " is undefined",
|
|
44
|
+
index: this.index, filename: this.filename };
|
|
41
45
|
}
|
|
42
46
|
};
|
|
43
47
|
|
|
44
|
-
tree.mixin.Definition = function (name, params, rules) {
|
|
48
|
+
tree.mixin.Definition = function (name, params, rules, condition, variadic) {
|
|
45
49
|
this.name = name;
|
|
46
50
|
this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
|
|
47
51
|
this.params = params;
|
|
52
|
+
this.condition = condition;
|
|
53
|
+
this.variadic = variadic;
|
|
48
54
|
this.arity = params.length;
|
|
49
55
|
this.rules = rules;
|
|
50
56
|
this._lookups = {};
|
|
@@ -62,33 +68,56 @@ tree.mixin.Definition.prototype = {
|
|
|
62
68
|
find: function () { return this.parent.find.apply(this, arguments) },
|
|
63
69
|
rulesets: function () { return this.parent.rulesets.apply(this) },
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
var frame = new(tree.Ruleset)(null, []),
|
|
71
|
+
evalParams: function (env, args) {
|
|
72
|
+
var frame = new(tree.Ruleset)(null, []), varargs;
|
|
67
73
|
|
|
68
|
-
for (var i = 0, val; i < this.params.length; i++) {
|
|
69
|
-
if (this.params[i].name) {
|
|
70
|
-
if (
|
|
71
|
-
|
|
74
|
+
for (var i = 0, val, name; i < this.params.length; i++) {
|
|
75
|
+
if (name = this.params[i].name) {
|
|
76
|
+
if (this.params[i].variadic && args) {
|
|
77
|
+
varargs = [];
|
|
78
|
+
for (var j = i; j < args.length; j++) {
|
|
79
|
+
varargs.push(args[j].eval(env));
|
|
80
|
+
}
|
|
81
|
+
frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
|
|
82
|
+
} else if (val = (args && args[i]) || this.params[i].value) {
|
|
83
|
+
frame.rules.unshift(new(tree.Rule)(name, val.eval(env)));
|
|
72
84
|
} else {
|
|
73
|
-
throw { message: "wrong number of arguments for " + this.name +
|
|
85
|
+
throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
|
|
74
86
|
' (' + args.length + ' for ' + this.arity + ')' };
|
|
75
87
|
}
|
|
76
88
|
}
|
|
77
89
|
}
|
|
90
|
+
return frame;
|
|
91
|
+
},
|
|
92
|
+
eval: function (env, args, important) {
|
|
93
|
+
var frame = this.evalParams(env, args), context, _arguments = [], rules, start;
|
|
94
|
+
|
|
78
95
|
for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
|
|
79
96
|
_arguments.push(args[i] || this.params[i].value);
|
|
80
97
|
}
|
|
81
98
|
frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
|
|
82
99
|
|
|
83
|
-
|
|
100
|
+
rules = important ?
|
|
101
|
+
this.rules.map(function (r) {
|
|
102
|
+
return new(tree.Rule)(r.name, r.value, '!important', r.index);
|
|
103
|
+
}) : this.rules.slice(0);
|
|
104
|
+
|
|
105
|
+
return new(tree.Ruleset)(null, rules).eval({
|
|
84
106
|
frames: [this, frame].concat(this.frames, env.frames)
|
|
85
107
|
});
|
|
86
108
|
},
|
|
87
109
|
match: function (args, env) {
|
|
88
|
-
var argsLength = (args && args.length) || 0, len;
|
|
110
|
+
var argsLength = (args && args.length) || 0, len, frame;
|
|
111
|
+
|
|
112
|
+
if (! this.variadic) {
|
|
113
|
+
if (argsLength < this.required) { return false }
|
|
114
|
+
if (argsLength > this.params.length) { return false }
|
|
115
|
+
if ((this.required > 0) && (argsLength > this.params.length)) { return false }
|
|
116
|
+
}
|
|
89
117
|
|
|
90
|
-
if (
|
|
91
|
-
|
|
118
|
+
if (this.condition && !this.condition.eval({
|
|
119
|
+
frames: [this.evalParams(env, args)].concat(env.frames)
|
|
120
|
+
})) { return false }
|
|
92
121
|
|
|
93
122
|
len = Math.min(argsLength, this.arity);
|
|
94
123
|
|
|
@@ -103,4 +132,4 @@ tree.mixin.Definition.prototype = {
|
|
|
103
132
|
}
|
|
104
133
|
};
|
|
105
134
|
|
|
106
|
-
})(require('
|
|
135
|
+
})(require('../tree'));
|