less 1.2.2 → 1.3.3
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.
- package/.npmignore +1 -0
- package/CHANGELOG.md +118 -0
- package/CONTRIBUTING.md +50 -0
- package/Makefile +14 -2
- package/benchmark/benchmark.less +11 -11
- package/benchmark/less-benchmark.js +1 -1
- package/bin/lessc +77 -21
- package/build/amd.js +6 -0
- package/build/ecma-5.js +120 -0
- package/build/header.js +7 -0
- package/build/require-rhino.js +7 -0
- package/build/require.js +7 -0
- package/lib/less/browser.js +192 -53
- package/lib/less/colors.js +1 -0
- package/lib/less/functions.js +159 -10
- package/lib/less/index.js +125 -56
- package/lib/less/lessc_helper.js +62 -0
- package/lib/less/parser.js +391 -154
- package/lib/less/rhino.js +84 -23
- package/lib/less/tree/anonymous.js +15 -1
- package/lib/less/tree/assignment.js +3 -1
- package/lib/less/tree/call.js +12 -6
- package/lib/less/tree/color.js +10 -0
- package/lib/less/tree/dimension.js +3 -1
- package/lib/less/tree/directive.js +10 -10
- package/lib/less/tree/element.js +8 -7
- package/lib/less/tree/import.js +17 -14
- package/lib/less/tree/media.js +121 -0
- package/lib/less/tree/mixin.js +133 -45
- package/lib/less/tree/operation.js +5 -0
- package/lib/less/tree/quoted.js +15 -1
- package/lib/less/tree/ratio.js +13 -0
- package/lib/less/tree/rule.js +7 -0
- package/lib/less/tree/ruleset.js +236 -37
- package/lib/less/tree/selector.js +21 -11
- package/lib/less/tree/unicode-descriptor.js +13 -0
- package/lib/less/tree/url.js +16 -14
- package/lib/less/tree/variable.js +13 -1
- package/lib/less/tree.js +28 -0
- package/package.json +13 -3
- package/test/browser/common.js +74 -0
- package/test/browser/css/relative-urls/urls.css +36 -0
- package/test/browser/css/rootpath/urls.css +36 -0
- package/test/browser/css/rootpath-relative/urls.css +36 -0
- package/test/browser/css/urls.css +36 -0
- package/test/browser/jasmine-html.js +681 -0
- package/test/browser/jasmine.css +82 -0
- package/test/browser/jasmine.js +2600 -0
- package/test/browser/less/imports/urls.less +4 -0
- package/test/browser/less/imports/urls2.less +4 -0
- package/test/browser/less/relative-urls/urls.less +33 -0
- package/test/browser/less/rootpath/urls.less +33 -0
- package/test/browser/less/rootpath-relative/urls.less +33 -0
- package/test/browser/less/urls.less +33 -0
- package/test/browser/phantom-runner.js +139 -0
- package/test/browser/runner-browser.js +3 -0
- package/test/browser/runner-main.js +15 -0
- package/test/browser/runner-relative-urls.js +4 -0
- package/test/browser/runner-rootpath-relative.js +5 -0
- package/test/browser/runner-rootpath.js +4 -0
- package/test/browser/template.htm +10 -0
- package/test/browser-test-prepare.js +29 -0
- package/test/css/charsets.css +1 -0
- package/test/css/colors.css +22 -0
- package/test/css/comments.css +7 -0
- package/test/css/css-3.css +57 -2
- package/test/css/css-escapes.css +4 -0
- package/test/css/css.css +11 -11
- package/test/css/debug/linenumbers-all.css +43 -0
- package/test/css/debug/linenumbers-comments.css +35 -0
- package/test/css/debug/linenumbers-mediaquery.css +35 -0
- package/test/css/functions.css +59 -2
- package/test/css/ie-filters.css +7 -3
- package/test/css/import-once.css +3 -0
- package/test/css/import.css +7 -9
- package/test/css/javascript.css +3 -2
- package/test/css/media.css +168 -0
- package/test/css/mixins-args.css +35 -4
- package/test/css/mixins-guards.css +13 -0
- package/test/css/mixins-important.css +21 -0
- package/test/css/mixins-named-args.css +27 -0
- package/test/css/mixins-pattern.css +4 -6
- package/test/css/mixins.css +50 -0
- package/test/css/scope.css +20 -0
- package/test/css/selectors.css +76 -0
- package/test/css/static-urls/urls.css +42 -0
- package/test/css/strings.css +2 -2
- package/test/css/urls.css +42 -0
- package/test/css/variables.css +0 -1
- package/test/css/whitespace.css +4 -0
- package/test/less/charsets.less +3 -0
- package/test/less/colors.less +27 -0
- package/test/less/comments.less +12 -0
- package/test/less/css-3.less +54 -6
- package/test/less/css-escapes.less +6 -1
- package/test/less/css.less +14 -12
- package/test/less/debug/import/test.less +25 -0
- package/test/less/debug/linenumbers.less +23 -0
- package/test/less/errors/bad-variable-declaration1.less +1 -0
- package/test/less/errors/bad-variable-declaration1.txt +2 -0
- package/test/less/errors/comment-in-selector.less +1 -0
- package/test/less/errors/comment-in-selector.txt +2 -0
- package/test/less/errors/import-missing.less +1 -0
- package/test/less/errors/import-missing.txt +3 -0
- package/test/less/errors/import-no-semi.less +1 -0
- package/test/less/errors/import-no-semi.txt +2 -0
- package/test/less/errors/import-subfolder1.less +1 -0
- package/test/less/errors/import-subfolder1.txt +3 -0
- package/test/less/errors/import-subfolder2.less +1 -0
- package/test/less/errors/import-subfolder2.txt +2 -0
- package/test/less/errors/imports/import-subfolder1.less +1 -0
- package/test/less/errors/imports/import-subfolder2.less +1 -0
- package/test/less/errors/imports/import-test.less +4 -0
- package/test/less/errors/imports/subfolder/mixin-not-defined.less +1 -0
- package/test/less/errors/imports/subfolder/parse-error-curly-bracket.less +1 -0
- package/test/less/errors/javascript-error.less +3 -0
- package/test/less/errors/javascript-error.txt +4 -0
- package/test/less/errors/mixed-mixin-definition-args-1.less +6 -0
- package/test/less/errors/mixed-mixin-definition-args-1.txt +4 -0
- package/test/less/errors/mixed-mixin-definition-args-2.less +6 -0
- package/test/less/errors/mixed-mixin-definition-args-2.txt +4 -0
- package/test/less/errors/mixin-not-defined.less +11 -0
- package/test/less/errors/mixin-not-defined.txt +3 -0
- package/test/less/errors/mixin-not-matched.less +6 -0
- package/test/less/errors/mixin-not-matched.txt +3 -0
- package/test/less/errors/mixin-not-matched2.less +6 -0
- package/test/less/errors/mixin-not-matched2.txt +3 -0
- package/test/less/errors/parse-error-curly-bracket.less +1 -0
- package/test/less/errors/parse-error-curly-bracket.txt +2 -0
- package/test/less/errors/parse-error-missing-bracket.less +2 -0
- package/test/less/errors/parse-error-missing-bracket.txt +2 -0
- package/test/less/errors/parse-error-with-import.less +13 -0
- package/test/less/errors/parse-error-with-import.txt +4 -0
- package/test/less/errors/property-ie5-hack.less +3 -0
- package/test/less/errors/property-ie5-hack.txt +4 -0
- package/test/less/errors/recursive-variable.less +1 -0
- package/test/less/errors/recursive-variable.txt +2 -0
- package/test/less/functions.less +64 -2
- package/test/less/ie-filters.less +7 -0
- package/test/less/import/deeper/import-once-test-a.less +1 -0
- package/test/less/import/import-and-relative-paths-test.less +6 -0
- package/test/less/import/import-charset-test.less +1 -0
- package/test/less/import/import-once-test-c.less +6 -0
- package/test/less/import/import-test-a.less +1 -0
- package/test/less/import/import-test-c.less +0 -1
- package/test/less/import/imports/font.less +8 -0
- package/test/less/import/imports/logo.less +5 -0
- package/test/less/import/urls.less +1 -0
- package/test/less/import-once.less +4 -0
- package/test/less/import.less +2 -1
- package/test/less/javascript.less +4 -2
- package/test/less/media.less +169 -1
- package/test/less/mixins-args.less +54 -11
- package/test/less/mixins-guards.less +30 -0
- package/test/less/mixins-important.less +4 -0
- package/test/less/mixins-named-args.less +36 -0
- package/test/less/mixins-pattern.less +3 -0
- package/test/less/mixins.less +47 -0
- package/test/less/scope.less +48 -1
- package/test/less/selectors.less +88 -0
- package/test/less/static-urls/urls.less +33 -0
- package/test/less/strings.less +1 -1
- package/test/less/urls.less +33 -0
- package/test/less/variables.less +0 -1
- package/test/less/whitespace.less +7 -0
- package/test/less-test.js +145 -36
- package/bench.css +0 -5943
- package/benchmark/b1.less +0 -3980
- package/dist/less-1.1.0.js +0 -2695
- package/dist/less-1.1.0.min.js +0 -16
- package/dist/less-1.1.1.js +0 -2710
- package/dist/less-1.1.1.min.js +0 -16
- package/dist/less-1.1.2.js +0 -2712
- package/dist/less-1.1.2.min.js +0 -16
- package/dist/less-1.1.3.js +0 -2721
- package/dist/less-1.1.3.min.js +0 -16
- package/dist/less-1.1.4.js +0 -2769
- package/dist/less-1.1.4.min.js +0 -16
- package/dist/less-1.1.5.js +0 -2805
- package/dist/less-1.1.5.min.js +0 -9
- package/dist/less-1.1.6.js +0 -3004
- package/dist/less-1.1.6.min.js +0 -9
- package/dist/less-1.2.0.js +0 -3293
- package/dist/less-1.2.0.min.js +0 -9
- package/dist/less-1.2.1.js +0 -3318
- package/dist/less-1.2.1.min.js +0 -9
- package/dist/less-1.2.2.js +0 -3337
- package/dist/less-1.2.2.min.js +0 -9
- package/dist/less-rhino-1.1.3.js +0 -2460
- package/dist/less-rhino-1.1.5.js +0 -2481
- package/foo.less +0 -2
- package/lib/less/cssmin.js +0 -355
- package/test/html/index.html +0 -10
- package/test/html/less.js +0 -3333
- package/test/html/lib.less +0 -2
- package/test/html/styles.less +0 -8
- package/x.less +0 -4
package/lib/less/tree/mixin.js
CHANGED
|
@@ -10,46 +10,75 @@ tree.mixin.Call = function (elements, args, index, filename, important) {
|
|
|
10
10
|
};
|
|
11
11
|
tree.mixin.Call.prototype = {
|
|
12
12
|
eval: function (env) {
|
|
13
|
-
var mixins, args, rules = [], match = false;
|
|
13
|
+
var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound;
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
args = this.arguments && this.arguments.map(function (a) {
|
|
16
|
+
return { name: a.name, value: a.value.eval(env) };
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
for (i = 0; i < env.frames.length; i++) {
|
|
16
20
|
if ((mixins = env.frames[i].find(this.selector)).length > 0) {
|
|
17
|
-
|
|
18
|
-
for (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
throw { message: e.message, index: e.index, filename: this.filename, stack: e.stack, call: this.index };
|
|
21
|
+
isOneFound = true;
|
|
22
|
+
for (m = 0; m < mixins.length; m++) {
|
|
23
|
+
mixin = mixins[m];
|
|
24
|
+
isRecursive = false;
|
|
25
|
+
for(f = 0; f < env.frames.length; f++) {
|
|
26
|
+
if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) {
|
|
27
|
+
isRecursive = true;
|
|
28
|
+
break;
|
|
26
29
|
}
|
|
27
30
|
}
|
|
31
|
+
if (isRecursive) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (mixin.matchArgs(args, env)) {
|
|
35
|
+
if (!mixin.matchCondition || mixin.matchCondition(args, env)) {
|
|
36
|
+
try {
|
|
37
|
+
Array.prototype.push.apply(
|
|
38
|
+
rules, mixin.eval(env, args, this.important).rules);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
match = true;
|
|
44
|
+
}
|
|
28
45
|
}
|
|
29
46
|
if (match) {
|
|
30
47
|
return rules;
|
|
31
|
-
} else {
|
|
32
|
-
throw { type: 'Runtime',
|
|
33
|
-
message: 'No matching definition was found for `' +
|
|
34
|
-
this.selector.toCSS().trim() + '(' +
|
|
35
|
-
this.arguments.map(function (a) {
|
|
36
|
-
return a.toCSS();
|
|
37
|
-
}).join(', ') + ")`",
|
|
38
|
-
index: this.index, filename: this.filename };
|
|
39
48
|
}
|
|
40
49
|
}
|
|
41
50
|
}
|
|
42
|
-
|
|
51
|
+
if (isOneFound) {
|
|
52
|
+
throw { type: 'Runtime',
|
|
53
|
+
message: 'No matching definition was found for `' +
|
|
54
|
+
this.selector.toCSS().trim() + '(' +
|
|
55
|
+
(args ? args.map(function (a) {
|
|
56
|
+
var argValue = "";
|
|
57
|
+
if (a.name) {
|
|
58
|
+
argValue += a.name + ":";
|
|
59
|
+
}
|
|
60
|
+
if (a.value.toCSS) {
|
|
61
|
+
argValue += a.value.toCSS();
|
|
62
|
+
} else {
|
|
63
|
+
argValue += "???";
|
|
64
|
+
}
|
|
65
|
+
return argValue;
|
|
66
|
+
}).join(', ') : "") + ")`",
|
|
67
|
+
index: this.index, filename: this.filename };
|
|
68
|
+
} else {
|
|
69
|
+
throw { type: 'Name',
|
|
43
70
|
message: this.selector.toCSS().trim() + " is undefined",
|
|
44
71
|
index: this.index, filename: this.filename };
|
|
72
|
+
}
|
|
45
73
|
}
|
|
46
74
|
};
|
|
47
75
|
|
|
48
|
-
tree.mixin.Definition = function (name, params, rules, condition) {
|
|
76
|
+
tree.mixin.Definition = function (name, params, rules, condition, variadic) {
|
|
49
77
|
this.name = name;
|
|
50
78
|
this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
|
|
51
79
|
this.params = params;
|
|
52
80
|
this.condition = condition;
|
|
81
|
+
this.variadic = variadic;
|
|
53
82
|
this.arity = params.length;
|
|
54
83
|
this.rules = rules;
|
|
55
84
|
this._lookups = {};
|
|
@@ -67,52 +96,111 @@ tree.mixin.Definition.prototype = {
|
|
|
67
96
|
find: function () { return this.parent.find.apply(this, arguments) },
|
|
68
97
|
rulesets: function () { return this.parent.rulesets.apply(this) },
|
|
69
98
|
|
|
70
|
-
evalParams: function (env, args) {
|
|
71
|
-
var frame = new(tree.Ruleset)(null, []);
|
|
99
|
+
evalParams: function (env, mixinEnv, args, evaldArguments) {
|
|
100
|
+
var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex;
|
|
101
|
+
|
|
102
|
+
if (args) {
|
|
103
|
+
args = args.slice(0);
|
|
104
|
+
|
|
105
|
+
for(i = 0; i < args.length; i++) {
|
|
106
|
+
arg = args[i];
|
|
107
|
+
if (name = (arg && arg.name)) {
|
|
108
|
+
isNamedFound = false;
|
|
109
|
+
for(j = 0; j < params.length; j++) {
|
|
110
|
+
if (!evaldArguments[j] && name === params[j].name) {
|
|
111
|
+
evaldArguments[j] = arg.value.eval(env);
|
|
112
|
+
frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env)));
|
|
113
|
+
isNamedFound = true;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (isNamedFound) {
|
|
118
|
+
args.splice(i, 1);
|
|
119
|
+
i--;
|
|
120
|
+
continue;
|
|
121
|
+
} else {
|
|
122
|
+
throw { type: 'Runtime', message: "Named argument for " + this.name +
|
|
123
|
+
' ' + args[i].name + ' not found' };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
argIndex = 0;
|
|
129
|
+
for (i = 0; i < params.length; i++) {
|
|
130
|
+
if (evaldArguments[i]) continue;
|
|
131
|
+
|
|
132
|
+
arg = args && args[argIndex];
|
|
72
133
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
134
|
+
if (name = params[i].name) {
|
|
135
|
+
if (params[i].variadic && args) {
|
|
136
|
+
varargs = [];
|
|
137
|
+
for (j = argIndex; j < args.length; j++) {
|
|
138
|
+
varargs.push(args[j].value.eval(env));
|
|
139
|
+
}
|
|
140
|
+
frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
|
|
77
141
|
} else {
|
|
78
|
-
|
|
142
|
+
val = arg && arg.value;
|
|
143
|
+
if (val) {
|
|
144
|
+
val = val.eval(env);
|
|
145
|
+
} else if (params[i].value) {
|
|
146
|
+
val = params[i].value.eval(mixinEnv);
|
|
147
|
+
} else {
|
|
148
|
+
throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
|
|
79
149
|
' (' + args.length + ' for ' + this.arity + ')' };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
frame.rules.unshift(new(tree.Rule)(name, val));
|
|
153
|
+
evaldArguments[i] = val;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (params[i].variadic && args) {
|
|
158
|
+
for (j = argIndex; j < args.length; j++) {
|
|
159
|
+
evaldArguments[j] = args[j].value.eval(env);
|
|
80
160
|
}
|
|
81
161
|
}
|
|
162
|
+
argIndex++;
|
|
82
163
|
}
|
|
164
|
+
|
|
83
165
|
return frame;
|
|
84
166
|
},
|
|
85
167
|
eval: function (env, args, important) {
|
|
86
|
-
var
|
|
168
|
+
var _arguments = [],
|
|
169
|
+
mixinFrames = this.frames.concat(env.frames),
|
|
170
|
+
frame = this.evalParams(env, {frames: mixinFrames}, args, _arguments),
|
|
171
|
+
context, rules, start, ruleset;
|
|
87
172
|
|
|
88
|
-
for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
|
|
89
|
-
_arguments.push(args[i] || this.params[i].value);
|
|
90
|
-
}
|
|
91
173
|
frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
|
|
92
174
|
|
|
93
175
|
rules = important ?
|
|
94
|
-
this.
|
|
95
|
-
return new(tree.Rule)(r.name, r.value, '!important', r.index);
|
|
96
|
-
}) : this.rules.slice(0);
|
|
176
|
+
this.parent.makeImportant.apply(this).rules : this.rules.slice(0);
|
|
97
177
|
|
|
98
|
-
|
|
99
|
-
frames: [this, frame].concat(
|
|
178
|
+
ruleset = new(tree.Ruleset)(null, rules).eval({
|
|
179
|
+
frames: [this, frame].concat(mixinFrames)
|
|
100
180
|
});
|
|
181
|
+
ruleset.originalRuleset = this;
|
|
182
|
+
return ruleset;
|
|
101
183
|
},
|
|
102
|
-
|
|
103
|
-
var argsLength = (args && args.length) || 0, len, frame;
|
|
104
|
-
|
|
105
|
-
if (argsLength < this.required) { return false }
|
|
106
|
-
if ((this.required > 0) && (argsLength > this.params.length)) { return false }
|
|
184
|
+
matchCondition: function (args, env) {
|
|
107
185
|
if (this.condition && !this.condition.eval({
|
|
108
|
-
frames: [this.evalParams(env, args)].concat(env.frames)
|
|
186
|
+
frames: [this.evalParams(env, {frames: this.frames.concat(env.frames)}, args, [])].concat(env.frames)
|
|
109
187
|
})) { return false }
|
|
188
|
+
return true;
|
|
189
|
+
},
|
|
190
|
+
matchArgs: function (args, env) {
|
|
191
|
+
var argsLength = (args && args.length) || 0, len, frame;
|
|
192
|
+
|
|
193
|
+
if (! this.variadic) {
|
|
194
|
+
if (argsLength < this.required) { return false }
|
|
195
|
+
if (argsLength > this.params.length) { return false }
|
|
196
|
+
if ((this.required > 0) && (argsLength > this.params.length)) { return false }
|
|
197
|
+
}
|
|
110
198
|
|
|
111
199
|
len = Math.min(argsLength, this.arity);
|
|
112
200
|
|
|
113
201
|
for (var i = 0; i < len; i++) {
|
|
114
|
-
if (!this.params[i].name) {
|
|
115
|
-
if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
|
|
202
|
+
if (!this.params[i].name && !this.params[i].variadic) {
|
|
203
|
+
if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
|
|
116
204
|
return false;
|
|
117
205
|
}
|
|
118
206
|
}
|
|
@@ -17,6 +17,11 @@ tree.Operation.prototype.eval = function (env) {
|
|
|
17
17
|
message: "Can't substract or divide a color from a number" };
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
+
if (!a.operate) {
|
|
21
|
+
throw { name: "OperationError",
|
|
22
|
+
message: "Operation on an invalid type" };
|
|
23
|
+
}
|
|
24
|
+
|
|
20
25
|
return a.operate(this.op, b);
|
|
21
26
|
};
|
|
22
27
|
|
package/lib/less/tree/quoted.js
CHANGED
|
@@ -20,9 +20,23 @@ tree.Quoted.prototype = {
|
|
|
20
20
|
return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
|
|
21
21
|
}).replace(/@\{([\w-]+)\}/g, function (_, name) {
|
|
22
22
|
var v = new(tree.Variable)('@' + name, that.index).eval(env);
|
|
23
|
-
return (
|
|
23
|
+
return (v instanceof tree.Quoted) ? v.value : v.toCSS();
|
|
24
24
|
});
|
|
25
25
|
return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
|
|
26
|
+
},
|
|
27
|
+
compare: function (x) {
|
|
28
|
+
if (!x.toCSS) {
|
|
29
|
+
return -1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var left = this.toCSS(),
|
|
33
|
+
right = x.toCSS();
|
|
34
|
+
|
|
35
|
+
if (left === right) {
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return left < right ? -1 : 1;
|
|
26
40
|
}
|
|
27
41
|
};
|
|
28
42
|
|
package/lib/less/tree/rule.js
CHANGED
|
@@ -27,6 +27,13 @@ tree.Rule.prototype.eval = function (context) {
|
|
|
27
27
|
this.index, this.inline);
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
tree.Rule.prototype.makeImportant = function () {
|
|
31
|
+
return new(tree.Rule)(this.name,
|
|
32
|
+
this.value,
|
|
33
|
+
"!important",
|
|
34
|
+
this.index, this.inline);
|
|
35
|
+
};
|
|
36
|
+
|
|
30
37
|
tree.Shorthand = function (a, b) {
|
|
31
38
|
this.a = a;
|
|
32
39
|
this.b = b;
|
package/lib/less/tree/ruleset.js
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
(function (tree) {
|
|
2
2
|
|
|
3
|
-
tree.Ruleset = function (selectors, rules) {
|
|
3
|
+
tree.Ruleset = function (selectors, rules, strictImports) {
|
|
4
4
|
this.selectors = selectors;
|
|
5
5
|
this.rules = rules;
|
|
6
6
|
this._lookups = {};
|
|
7
|
+
this.strictImports = strictImports;
|
|
7
8
|
};
|
|
8
9
|
tree.Ruleset.prototype = {
|
|
9
10
|
eval: function (env) {
|
|
10
11
|
var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) });
|
|
11
|
-
var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0));
|
|
12
|
-
|
|
12
|
+
var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
|
|
13
|
+
var rules;
|
|
14
|
+
|
|
15
|
+
ruleset.originalRuleset = this;
|
|
13
16
|
ruleset.root = this.root;
|
|
14
17
|
ruleset.allowImports = this.allowImports;
|
|
15
18
|
|
|
19
|
+
if(this.debugInfo) {
|
|
20
|
+
ruleset.debugInfo = this.debugInfo;
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
// push the current ruleset to the frames stack
|
|
17
24
|
env.frames.unshift(ruleset);
|
|
18
25
|
|
|
19
26
|
// Evaluate imports
|
|
20
|
-
if (ruleset.root || ruleset.allowImports) {
|
|
21
|
-
|
|
22
|
-
if (ruleset.rules[i] instanceof tree.Import) {
|
|
23
|
-
Array.prototype.splice
|
|
24
|
-
.apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
+
if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
|
|
28
|
+
ruleset.evalImports(env);
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
// Store the frames around mixin definitions,
|
|
@@ -33,12 +35,16 @@ tree.Ruleset.prototype = {
|
|
|
33
35
|
ruleset.rules[i].frames = env.frames.slice(0);
|
|
34
36
|
}
|
|
35
37
|
}
|
|
38
|
+
|
|
39
|
+
var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0;
|
|
36
40
|
|
|
37
41
|
// Evaluate mixin calls.
|
|
38
42
|
for (var i = 0; i < ruleset.rules.length; i++) {
|
|
39
43
|
if (ruleset.rules[i] instanceof tree.mixin.Call) {
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
rules = ruleset.rules[i].eval(env);
|
|
45
|
+
ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules));
|
|
46
|
+
i += rules.length-1;
|
|
47
|
+
ruleset.resetCache();
|
|
42
48
|
}
|
|
43
49
|
}
|
|
44
50
|
|
|
@@ -53,12 +59,47 @@ tree.Ruleset.prototype = {
|
|
|
53
59
|
|
|
54
60
|
// Pop the stack
|
|
55
61
|
env.frames.shift();
|
|
62
|
+
|
|
63
|
+
if (env.mediaBlocks) {
|
|
64
|
+
for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) {
|
|
65
|
+
env.mediaBlocks[i].bubbleSelectors(selectors);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
56
68
|
|
|
57
69
|
return ruleset;
|
|
58
70
|
},
|
|
59
|
-
|
|
71
|
+
evalImports: function(env) {
|
|
72
|
+
var i, rules;
|
|
73
|
+
for (i = 0; i < this.rules.length; i++) {
|
|
74
|
+
if (this.rules[i] instanceof tree.Import) {
|
|
75
|
+
rules = this.rules[i].eval(env);
|
|
76
|
+
if (typeof rules.length === "number") {
|
|
77
|
+
this.rules.splice.apply(this.rules, [i, 1].concat(rules));
|
|
78
|
+
i+= rules.length-1;
|
|
79
|
+
} else {
|
|
80
|
+
this.rules.splice(i, 1, rules);
|
|
81
|
+
}
|
|
82
|
+
this.resetCache();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
makeImportant: function() {
|
|
87
|
+
return new tree.Ruleset(this.selectors, this.rules.map(function (r) {
|
|
88
|
+
if (r.makeImportant) {
|
|
89
|
+
return r.makeImportant();
|
|
90
|
+
} else {
|
|
91
|
+
return r;
|
|
92
|
+
}
|
|
93
|
+
}), this.strictImports);
|
|
94
|
+
},
|
|
95
|
+
matchArgs: function (args) {
|
|
60
96
|
return !args || args.length === 0;
|
|
61
97
|
},
|
|
98
|
+
resetCache: function () {
|
|
99
|
+
this._rulesets = null;
|
|
100
|
+
this._variables = null;
|
|
101
|
+
this._lookups = {};
|
|
102
|
+
},
|
|
62
103
|
variables: function () {
|
|
63
104
|
if (this._variables) { return this._variables }
|
|
64
105
|
else {
|
|
@@ -113,25 +154,41 @@ tree.Ruleset.prototype = {
|
|
|
113
154
|
toCSS: function (context, env) {
|
|
114
155
|
var css = [], // The CSS output
|
|
115
156
|
rules = [], // node.Rule instances
|
|
157
|
+
_rules = [], //
|
|
116
158
|
rulesets = [], // node.Ruleset instances
|
|
117
159
|
paths = [], // Current selectors
|
|
118
160
|
selector, // The fully rendered selector
|
|
161
|
+
debugInfo, // Line number debugging
|
|
119
162
|
rule;
|
|
120
163
|
|
|
121
164
|
if (! this.root) {
|
|
122
|
-
|
|
123
|
-
paths = this.selectors.map(function (s) { return [s] });
|
|
124
|
-
} else {
|
|
125
|
-
this.joinSelectors(paths, context, this.selectors);
|
|
126
|
-
}
|
|
165
|
+
this.joinSelectors(paths, context, this.selectors);
|
|
127
166
|
}
|
|
128
167
|
|
|
129
168
|
// Compile rules and rulesets
|
|
130
169
|
for (var i = 0; i < this.rules.length; i++) {
|
|
131
170
|
rule = this.rules[i];
|
|
132
171
|
|
|
133
|
-
if (rule.rules || (rule instanceof tree.
|
|
172
|
+
if (rule.rules || (rule instanceof tree.Media)) {
|
|
134
173
|
rulesets.push(rule.toCSS(paths, env));
|
|
174
|
+
} else if (rule instanceof tree.Directive) {
|
|
175
|
+
var cssValue = rule.toCSS(paths, env);
|
|
176
|
+
// Output only the first @charset definition as such - convert the others
|
|
177
|
+
// to comments in case debug is enabled
|
|
178
|
+
if (rule.name === "@charset") {
|
|
179
|
+
// Only output the debug info together with subsequent @charset definitions
|
|
180
|
+
// a comment (or @media statement) before the actual @charset directive would
|
|
181
|
+
// be considered illegal css as it has to be on the first line
|
|
182
|
+
if (env.charset) {
|
|
183
|
+
if (rule.debugInfo) {
|
|
184
|
+
rulesets.push(tree.debugInfo(env, rule));
|
|
185
|
+
rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env));
|
|
186
|
+
}
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
env.charset = true;
|
|
190
|
+
}
|
|
191
|
+
rulesets.push(cssValue);
|
|
135
192
|
} else if (rule instanceof tree.Comment) {
|
|
136
193
|
if (!rule.silent) {
|
|
137
194
|
if (this.root) {
|
|
@@ -158,13 +215,22 @@ tree.Ruleset.prototype = {
|
|
|
158
215
|
css.push(rules.join(env.compress ? '' : '\n'));
|
|
159
216
|
} else {
|
|
160
217
|
if (rules.length > 0) {
|
|
218
|
+
debugInfo = tree.debugInfo(env, this);
|
|
161
219
|
selector = paths.map(function (p) {
|
|
162
220
|
return p.map(function (s) {
|
|
163
221
|
return s.toCSS(env);
|
|
164
222
|
}).join('').trim();
|
|
165
|
-
}).join(
|
|
223
|
+
}).join(env.compress ? ',' : ',\n');
|
|
224
|
+
|
|
225
|
+
// Remove duplicates
|
|
226
|
+
for (var i = rules.length - 1; i >= 0; i--) {
|
|
227
|
+
if (_rules.indexOf(rules[i]) === -1) {
|
|
228
|
+
_rules.unshift(rules[i]);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
rules = _rules;
|
|
166
232
|
|
|
167
|
-
css.push(selector
|
|
233
|
+
css.push(debugInfo + selector +
|
|
168
234
|
(env.compress ? '{' : ' {\n ') +
|
|
169
235
|
rules.join(env.compress ? '' : '\n ') +
|
|
170
236
|
(env.compress ? '}' : '\n}\n'));
|
|
@@ -172,7 +238,7 @@ tree.Ruleset.prototype = {
|
|
|
172
238
|
}
|
|
173
239
|
css.push(rulesets);
|
|
174
240
|
|
|
175
|
-
return css.join('')
|
|
241
|
+
return css.join('') + (env.compress ? '\n' : '');
|
|
176
242
|
},
|
|
177
243
|
|
|
178
244
|
joinSelectors: function (paths, context, selectors) {
|
|
@@ -182,33 +248,166 @@ tree.Ruleset.prototype = {
|
|
|
182
248
|
},
|
|
183
249
|
|
|
184
250
|
joinSelector: function (paths, context, selector) {
|
|
185
|
-
var before = [], after = [], beforeElements = [],
|
|
186
|
-
afterElements = [], hasParentSelector = false, el;
|
|
187
251
|
|
|
188
|
-
|
|
252
|
+
var i, j, k,
|
|
253
|
+
hasParentSelector, newSelectors, el, sel, parentSel,
|
|
254
|
+
newSelectorPath, afterParentJoin, newJoinedSelector,
|
|
255
|
+
newJoinedSelectorEmpty, lastSelector, currentElements,
|
|
256
|
+
selectorsMultiplied;
|
|
257
|
+
|
|
258
|
+
for (i = 0; i < selector.elements.length; i++) {
|
|
189
259
|
el = selector.elements[i];
|
|
190
|
-
if (el.
|
|
260
|
+
if (el.value === '&') {
|
|
191
261
|
hasParentSelector = true;
|
|
192
262
|
}
|
|
193
|
-
if (hasParentSelector) afterElements.push(el);
|
|
194
|
-
else beforeElements.push(el);
|
|
195
263
|
}
|
|
264
|
+
|
|
265
|
+
if (!hasParentSelector) {
|
|
266
|
+
if (context.length > 0) {
|
|
267
|
+
for(i = 0; i < context.length; i++) {
|
|
268
|
+
paths.push(context[i].concat(selector));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
paths.push([selector]);
|
|
273
|
+
}
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// The paths are [[Selector]]
|
|
278
|
+
// The first list is a list of comma seperated selectors
|
|
279
|
+
// The inner list is a list of inheritance seperated selectors
|
|
280
|
+
// e.g.
|
|
281
|
+
// .a, .b {
|
|
282
|
+
// .c {
|
|
283
|
+
// }
|
|
284
|
+
// }
|
|
285
|
+
// == [[.a] [.c]] [[.b] [.c]]
|
|
286
|
+
//
|
|
196
287
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
288
|
+
// the elements from the current selector so far
|
|
289
|
+
currentElements = [];
|
|
290
|
+
// the current list of new selectors to add to the path.
|
|
291
|
+
// We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
|
|
292
|
+
// by the parents
|
|
293
|
+
newSelectors = [[]];
|
|
294
|
+
|
|
295
|
+
for (i = 0; i < selector.elements.length; i++) {
|
|
296
|
+
el = selector.elements[i];
|
|
297
|
+
// non parent reference elements just get added
|
|
298
|
+
if (el.value !== "&") {
|
|
299
|
+
currentElements.push(el);
|
|
300
|
+
} else {
|
|
301
|
+
// the new list of selectors to add
|
|
302
|
+
selectorsMultiplied = [];
|
|
303
|
+
|
|
304
|
+
// merge the current list of non parent selector elements
|
|
305
|
+
// on to the current list of selectors to add
|
|
306
|
+
if (currentElements.length > 0) {
|
|
307
|
+
this.mergeElementsOnToSelectors(currentElements, newSelectors);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// loop through our current selectors
|
|
311
|
+
for(j = 0; j < newSelectors.length; j++) {
|
|
312
|
+
sel = newSelectors[j];
|
|
313
|
+
// if we don't have any parent paths, the & might be in a mixin so that it can be used
|
|
314
|
+
// whether there are parents or not
|
|
315
|
+
if (context.length == 0) {
|
|
316
|
+
// the combinator used on el should now be applied to the next element instead so that
|
|
317
|
+
// it is not lost
|
|
318
|
+
if (sel.length > 0) {
|
|
319
|
+
sel[0].elements = sel[0].elements.slice(0);
|
|
320
|
+
sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, ""));
|
|
321
|
+
}
|
|
322
|
+
selectorsMultiplied.push(sel);
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
// and the parent selectors
|
|
326
|
+
for(k = 0; k < context.length; k++) {
|
|
327
|
+
parentSel = context[k];
|
|
328
|
+
// We need to put the current selectors
|
|
329
|
+
// then join the last selector's elements on to the parents selectors
|
|
330
|
+
|
|
331
|
+
// our new selector path
|
|
332
|
+
newSelectorPath = [];
|
|
333
|
+
// selectors from the parent after the join
|
|
334
|
+
afterParentJoin = [];
|
|
335
|
+
newJoinedSelectorEmpty = true;
|
|
336
|
+
|
|
337
|
+
//construct the joined selector - if & is the first thing this will be empty,
|
|
338
|
+
// if not newJoinedSelector will be the last set of elements in the selector
|
|
339
|
+
if (sel.length > 0) {
|
|
340
|
+
newSelectorPath = sel.slice(0);
|
|
341
|
+
lastSelector = newSelectorPath.pop();
|
|
342
|
+
newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0));
|
|
343
|
+
newJoinedSelectorEmpty = false;
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
newJoinedSelector = new(tree.Selector)([]);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
//put together the parent selectors after the join
|
|
350
|
+
if (parentSel.length > 1) {
|
|
351
|
+
afterParentJoin = afterParentJoin.concat(parentSel.slice(1));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (parentSel.length > 0) {
|
|
355
|
+
newJoinedSelectorEmpty = false;
|
|
356
|
+
|
|
357
|
+
// join the elements so far with the first part of the parent
|
|
358
|
+
newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0));
|
|
359
|
+
newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1));
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (!newJoinedSelectorEmpty) {
|
|
363
|
+
// now add the joined selector
|
|
364
|
+
newSelectorPath.push(newJoinedSelector);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// and the rest of the parent
|
|
368
|
+
newSelectorPath = newSelectorPath.concat(afterParentJoin);
|
|
369
|
+
|
|
370
|
+
// add that to our new set of selectors
|
|
371
|
+
selectorsMultiplied.push(newSelectorPath);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// our new selectors has been multiplied, so reset the state
|
|
377
|
+
newSelectors = selectorsMultiplied;
|
|
378
|
+
currentElements = [];
|
|
379
|
+
}
|
|
200
380
|
}
|
|
201
381
|
|
|
202
|
-
if (
|
|
203
|
-
|
|
382
|
+
// if we have any elements left over (e.g. .a& .b == .b)
|
|
383
|
+
// add them on to all the current selectors
|
|
384
|
+
if (currentElements.length > 0) {
|
|
385
|
+
this.mergeElementsOnToSelectors(currentElements, newSelectors);
|
|
204
386
|
}
|
|
205
387
|
|
|
206
|
-
|
|
207
|
-
|
|
388
|
+
for(i = 0; i < newSelectors.length; i++) {
|
|
389
|
+
paths.push(newSelectors[i]);
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
|
|
393
|
+
mergeElementsOnToSelectors: function(elements, selectors) {
|
|
394
|
+
var i, sel;
|
|
395
|
+
|
|
396
|
+
if (selectors.length == 0) {
|
|
397
|
+
selectors.push([ new(tree.Selector)(elements) ]);
|
|
398
|
+
return;
|
|
208
399
|
}
|
|
209
400
|
|
|
210
|
-
for
|
|
211
|
-
|
|
401
|
+
for(i = 0; i < selectors.length; i++) {
|
|
402
|
+
sel = selectors[i];
|
|
403
|
+
|
|
404
|
+
// if the previous thing in sel is a parent this needs to join on to it
|
|
405
|
+
if (sel.length > 0) {
|
|
406
|
+
sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements));
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
sel.push(new(tree.Selector)(elements));
|
|
410
|
+
}
|
|
212
411
|
}
|
|
213
412
|
}
|
|
214
413
|
};
|