less 2.1.2 → 2.4.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.
- package/.idea/inspectionProfiles/Project_Default.xml +1 -0
- package/.idea/jsLinters/jscs.xml +4 -0
- package/.idea/jsLinters/jshint.xml +58 -4
- package/.idea/workspace.xml +499 -760
- package/.jscsrc +73 -0
- package/.jshintrc +0 -2
- package/.travis.yml +1 -0
- package/CHANGELOG.md +59 -0
- package/Gruntfile.js +37 -3
- package/appveyor.yml +5 -0
- package/bin/lessc +383 -316
- package/bower.json +1 -1
- package/dist/less.js +1638 -1244
- package/dist/less.min.js +7 -7
- package/lib/less/contexts.js +3 -3
- package/lib/less/data/unit-conversions.js +3 -3
- package/lib/less/environment/abstract-file-manager.js +8 -8
- package/lib/less/environment/environment.js +2 -2
- package/lib/less/functions/color-blending.js +3 -3
- package/lib/less/functions/color.js +20 -12
- package/lib/less/functions/data-uri.js +26 -18
- package/lib/less/functions/math.js +1 -1
- package/lib/less/functions/number.js +2 -2
- package/lib/less/functions/string.js +3 -1
- package/lib/less/functions/svg.js +12 -15
- package/lib/less/functions/types.js +33 -10
- package/lib/less/import-manager.js +14 -9
- package/lib/less/index.js +2 -1
- package/lib/less/less-error.js +1 -1
- package/lib/less/logger.js +2 -2
- package/lib/less/parse-tree.js +48 -42
- package/lib/less/parse.js +68 -0
- package/lib/less/parser/parser-input.js +6 -5
- package/lib/less/parser/parser.js +76 -29
- package/lib/less/plugin-manager.js +30 -3
- package/lib/less/render.js +11 -37
- package/lib/less/source-map-builder.js +4 -0
- package/lib/less/source-map-output.js +6 -6
- package/lib/less/transform-tree.js +4 -4
- package/lib/less/tree/anonymous.js +1 -1
- package/lib/less/tree/assignment.js +0 -1
- package/lib/less/tree/call.js +1 -1
- package/lib/less/tree/color.js +6 -6
- package/lib/less/tree/condition.js +9 -5
- package/lib/less/tree/debug-info.js +6 -2
- package/lib/less/tree/dimension.js +5 -5
- package/lib/less/tree/directive.js +25 -6
- package/lib/less/tree/element.js +1 -1
- package/lib/less/tree/expression.js +2 -2
- package/lib/less/tree/extend.js +3 -3
- package/lib/less/tree/import.js +2 -2
- package/lib/less/tree/index.js +1 -0
- package/lib/less/tree/javascript.js +2 -2
- package/lib/less/tree/media.js +20 -19
- package/lib/less/tree/mixin-call.js +5 -6
- package/lib/less/tree/mixin-definition.js +33 -11
- package/lib/less/tree/quoted.js +3 -3
- package/lib/less/tree/rule.js +3 -4
- package/lib/less/tree/ruleset.js +290 -177
- package/lib/less/tree/selector.js +3 -2
- package/lib/less/tree/unit.js +2 -0
- package/lib/less/tree/url.js +5 -2
- package/lib/less/tree/value.js +2 -2
- package/lib/less/tree/variable.js +1 -1
- package/lib/less/visitors/extend-visitor.js +72 -36
- package/lib/less/visitors/import-sequencer.js +20 -14
- package/lib/less/visitors/import-visitor.js +15 -12
- package/lib/less/visitors/to-css-visitor.js +41 -9
- package/lib/less-browser/add-default-options.js +5 -1
- package/lib/less-browser/bootstrap.js +10 -8
- package/lib/less-browser/cache.js +3 -3
- package/lib/less-browser/file-manager.js +96 -96
- package/lib/less-browser/index.js +206 -205
- package/lib/less-browser/log-listener.js +2 -2
- package/lib/less-browser/utils.js +6 -6
- package/lib/less-node/file-manager.js +58 -30
- package/lib/less-node/image-size.js +34 -0
- package/lib/less-node/index.js +6 -3
- package/lib/less-node/lessc-helper.js +3 -2
- package/lib/less-node/plugin-loader.js +3 -3
- package/lib/less-node/url-file-manager.js +6 -3
- package/lib/less-rhino/index.js +15 -13
- package/lib/source-map/source-map-0.1.31.js +1 -1
- package/package.json +10 -7
- package/test/browser/common.js +13 -11
- package/test/browser/css/relative-urls/urls.css +1 -0
- package/test/browser/css/urls.css +6 -3
- package/test/browser/jasmine-jsreporter.js +2 -3
- package/test/browser/less/nested-gradient-with-svg-gradient/mixin-consumer.less +5 -0
- package/test/browser/less/nested-gradient-with-svg-gradient/svg-gradient-mixin.less +15 -0
- package/test/browser/less/relative-urls/urls.less +1 -0
- package/test/browser/less/urls.less +1 -0
- package/test/browser/runner-browser-options.js +23 -23
- package/test/browser/runner-errors-options.js +0 -1
- package/test/browser/runner-errors-spec.js +1 -2
- package/test/browser/runner-global-vars-spec.js +1 -1
- package/test/browser/runner-legacy-options.js +0 -1
- package/test/browser/runner-main-options.js +5 -5
- package/test/browser/runner-main-spec.js +1 -1
- package/test/browser/runner-no-js-errors-spec.js +0 -1
- package/test/browser/runner-production-options.js +0 -1
- package/test/browser/runner-relative-urls-options.js +0 -1
- package/test/browser/runner-rootpath-options.js +0 -1
- package/test/browser/runner-rootpath-relative-options.js +0 -1
- package/test/browser/runner-strict-units-options.js +0 -1
- package/test/copy-bom.js +72 -0
- package/test/css/comments.css +1 -0
- package/test/css/css-3.css +2 -0
- package/test/css/functions.css +10 -0
- package/test/css/import-interpolation.css +7 -0
- package/test/css/import-reference.css +25 -0
- package/test/css/include-path/include-path.css +6 -0
- package/test/css/mixins-important.css +12 -0
- package/test/css/selectors.css +15 -1
- package/test/css/static-urls/urls.css +1 -0
- package/test/css/url-args/urls.css +3 -3
- package/test/css/urls.css +13 -4
- package/test/css/variables.css +7 -1
- package/test/data/image.svg +3 -0
- package/test/index.js +15 -10
- package/test/less/comments.less +1 -0
- package/test/less/css-3.less +3 -0
- package/test/less/css-guards.less +2 -1
- package/test/less/errors/detached-ruleset-2.txt +1 -1
- package/test/less/errors/import-missing.txt +1 -1
- package/test/less/errors/parens-error-1.txt +1 -1
- package/test/less/errors/parens-error-2.txt +1 -1
- package/test/less/errors/parens-error-3.txt +1 -1
- package/test/less/errors/single-character.less +1 -0
- package/test/less/errors/single-character.txt +2 -0
- package/test/less/functions.less +18 -0
- package/test/less/import/import-interpolation.less +1 -0
- package/test/less/import/import-reference.less +38 -0
- package/test/less/import/imports/logo.less +1 -0
- package/test/less/import-reference.less +3 -1
- package/test/less/import.less +2 -0
- package/test/less/include-path/include-path.less +6 -0
- package/test/less/mixins-important.less +28 -0
- package/test/less/nested-gradient-with-svg-gradient/mixin-consumer.less +5 -0
- package/test/less/nested-gradient-with-svg-gradient/svg-gradient-mixin.less +15 -0
- package/test/less/selectors.less +29 -4
- package/test/less/sourcemaps-empty/empty.less +0 -0
- package/test/less/sourcemaps-empty/var-defs.less +1 -0
- package/test/less/urls.less +10 -1
- package/test/less/variables.less +17 -3
- package/test/less-test.js +133 -52
- package/test/modify-vars.js +14 -12
- package/test/browser/less.js +0 -9473
package/lib/less/tree/value.js
CHANGED
|
@@ -24,9 +24,9 @@ Value.prototype.eval = function (context) {
|
|
|
24
24
|
};
|
|
25
25
|
Value.prototype.genCSS = function (context, output) {
|
|
26
26
|
var i;
|
|
27
|
-
for(i = 0; i < this.value.length; i++) {
|
|
27
|
+
for (i = 0; i < this.value.length; i++) {
|
|
28
28
|
this.value[i].genCSS(context, output);
|
|
29
|
-
if (i+1 < this.value.length) {
|
|
29
|
+
if (i + 1 < this.value.length) {
|
|
30
30
|
output.add((context && context.compress) ? ',' : ', ');
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -27,7 +27,7 @@ Variable.prototype.eval = function (context) {
|
|
|
27
27
|
var v = frame.variable(name);
|
|
28
28
|
if (v) {
|
|
29
29
|
if (v.important) {
|
|
30
|
-
var importantScope = context.importantScope[context.importantScope.length-1];
|
|
30
|
+
var importantScope = context.importantScope[context.importantScope.length - 1];
|
|
31
31
|
importantScope.important = v.important;
|
|
32
32
|
}
|
|
33
33
|
return v.value.eval(context);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
var tree = require("../tree"),
|
|
2
|
-
Visitor = require("./visitor")
|
|
2
|
+
Visitor = require("./visitor"),
|
|
3
|
+
logger = require("../logger");
|
|
3
4
|
|
|
4
5
|
/*jshint loopfunc:true */
|
|
5
6
|
|
|
@@ -30,7 +31,7 @@ ExtendFinderVisitor.prototype = {
|
|
|
30
31
|
|
|
31
32
|
// get &:extend(.a); rules which apply to all selectors in this ruleset
|
|
32
33
|
var rules = rulesetNode.rules, ruleCnt = rules ? rules.length : 0;
|
|
33
|
-
for(i = 0; i < ruleCnt; i++) {
|
|
34
|
+
for (i = 0; i < ruleCnt; i++) {
|
|
34
35
|
if (rulesetNode.rules[i] instanceof tree.Extend) {
|
|
35
36
|
allSelectorsExtendList.push(rules[i]);
|
|
36
37
|
rulesetNode.extendOnEveryPath = true;
|
|
@@ -40,7 +41,7 @@ ExtendFinderVisitor.prototype = {
|
|
|
40
41
|
// now find every selector and apply the extends that apply to all extends
|
|
41
42
|
// and the ones which apply to an individual extend
|
|
42
43
|
var paths = rulesetNode.paths;
|
|
43
|
-
for(i = 0; i < paths.length; i++) {
|
|
44
|
+
for (i = 0; i < paths.length; i++) {
|
|
44
45
|
var selectorPath = paths[i],
|
|
45
46
|
selector = selectorPath[selectorPath.length - 1],
|
|
46
47
|
selExtendList = selector.extendList;
|
|
@@ -54,13 +55,13 @@ ExtendFinderVisitor.prototype = {
|
|
|
54
55
|
});
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
for(j = 0; j < extendList.length; j++) {
|
|
58
|
+
for (j = 0; j < extendList.length; j++) {
|
|
58
59
|
this.foundExtends = true;
|
|
59
60
|
extend = extendList[j];
|
|
60
61
|
extend.findSelfSelectors(selectorPath);
|
|
61
62
|
extend.ruleset = rulesetNode;
|
|
62
63
|
if (j === 0) { extend.firstExtendOnThisSelectorPath = true; }
|
|
63
|
-
this.allExtendsStack[this.allExtendsStack.length-1].push(extend);
|
|
64
|
+
this.allExtendsStack[this.allExtendsStack.length - 1].push(extend);
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
|
|
@@ -94,23 +95,44 @@ var ProcessExtendsVisitor = function() {
|
|
|
94
95
|
ProcessExtendsVisitor.prototype = {
|
|
95
96
|
run: function(root) {
|
|
96
97
|
var extendFinder = new ExtendFinderVisitor();
|
|
98
|
+
this.extendIndicies = {};
|
|
97
99
|
extendFinder.run(root);
|
|
98
100
|
if (!extendFinder.foundExtends) { return root; }
|
|
99
101
|
root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
|
|
100
102
|
this.allExtendsStack = [root.allExtends];
|
|
101
|
-
|
|
103
|
+
var newRoot = this._visitor.visit(root);
|
|
104
|
+
this.checkExtendsForNonMatched(root.allExtends);
|
|
105
|
+
return newRoot;
|
|
106
|
+
},
|
|
107
|
+
checkExtendsForNonMatched: function(extendList) {
|
|
108
|
+
var indicies = this.extendIndicies;
|
|
109
|
+
extendList.filter(function(extend) {
|
|
110
|
+
return !extend.hasFoundMatches && extend.parent_ids.length == 1;
|
|
111
|
+
}).forEach(function(extend) {
|
|
112
|
+
var selector = "_unknown_";
|
|
113
|
+
try {
|
|
114
|
+
selector = extend.selector.toCSS({});
|
|
115
|
+
}
|
|
116
|
+
catch(_) {}
|
|
117
|
+
|
|
118
|
+
if (!indicies[extend.index + ' ' + selector]) {
|
|
119
|
+
indicies[extend.index + ' ' + selector] = true;
|
|
120
|
+
logger.warn("extend '" + selector + "' has no matches");
|
|
121
|
+
}
|
|
122
|
+
});
|
|
102
123
|
},
|
|
103
124
|
doExtendChaining: function (extendsList, extendsListTarget, iterationCount) {
|
|
104
125
|
//
|
|
105
|
-
// chaining is different from normal extension.. if we extend an extend then we are not just copying, altering
|
|
106
|
-
// the selector we would do normally, but we are also adding an extend with the same target selector
|
|
126
|
+
// chaining is different from normal extension.. if we extend an extend then we are not just copying, altering
|
|
127
|
+
// and pasting the selector we would do normally, but we are also adding an extend with the same target selector
|
|
107
128
|
// this means this new extend can then go and alter other extends
|
|
108
129
|
//
|
|
109
130
|
// this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
|
|
110
|
-
// this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already
|
|
111
|
-
// we look at each selector at a time, as is done in visitRuleset
|
|
131
|
+
// this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already
|
|
132
|
+
// processed if we look at each selector at a time, as is done in visitRuleset
|
|
112
133
|
|
|
113
|
-
var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath,
|
|
134
|
+
var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath,
|
|
135
|
+
extend, targetExtend, newExtend;
|
|
114
136
|
|
|
115
137
|
iterationCount = iterationCount || 0;
|
|
116
138
|
|
|
@@ -120,14 +142,14 @@ ProcessExtendsVisitor.prototype = {
|
|
|
120
142
|
// and the second is the target.
|
|
121
143
|
// the seperation into two lists allows us to process a subset of chains with a bigger set, as is the
|
|
122
144
|
// case when processing media queries
|
|
123
|
-
for(extendIndex = 0; extendIndex < extendsList.length; extendIndex++){
|
|
124
|
-
for(targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++){
|
|
145
|
+
for (extendIndex = 0; extendIndex < extendsList.length; extendIndex++) {
|
|
146
|
+
for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) {
|
|
125
147
|
|
|
126
148
|
extend = extendsList[extendIndex];
|
|
127
149
|
targetExtend = extendsListTarget[targetExtendIndex];
|
|
128
150
|
|
|
129
151
|
// look for circular references
|
|
130
|
-
if( extend.parent_ids.indexOf( targetExtend.object_id ) >= 0 ){ continue; }
|
|
152
|
+
if ( extend.parent_ids.indexOf( targetExtend.object_id ) >= 0 ) { continue; }
|
|
131
153
|
|
|
132
154
|
// find a match in the target extends self selector (the bit before :extend)
|
|
133
155
|
selectorPath = [targetExtend.selfSelectors[0]];
|
|
@@ -135,6 +157,8 @@ ProcessExtendsVisitor.prototype = {
|
|
|
135
157
|
|
|
136
158
|
if (matches.length) {
|
|
137
159
|
|
|
160
|
+
extend.hasFoundMatches = true;
|
|
161
|
+
|
|
138
162
|
// we found a match, so for each self selector..
|
|
139
163
|
extend.selfSelectors.forEach(function(selfSelector) {
|
|
140
164
|
|
|
@@ -146,7 +170,7 @@ ProcessExtendsVisitor.prototype = {
|
|
|
146
170
|
newExtend.selfSelectors = newSelector;
|
|
147
171
|
|
|
148
172
|
// add the extend onto the list of extends for that selector
|
|
149
|
-
newSelector[newSelector.length-1].extendList = [newExtend];
|
|
173
|
+
newSelector[newSelector.length - 1].extendList = [newExtend];
|
|
150
174
|
|
|
151
175
|
// record that we need to add it.
|
|
152
176
|
extendsToAdd.push(newExtend);
|
|
@@ -180,11 +204,13 @@ ProcessExtendsVisitor.prototype = {
|
|
|
180
204
|
selectorTwo = extendsToAdd[0].selector.toCSS();
|
|
181
205
|
}
|
|
182
206
|
catch(e) {}
|
|
183
|
-
throw {message: "extend circular reference detected. One of the circular extends is currently:"
|
|
207
|
+
throw { message: "extend circular reference detected. One of the circular extends is currently:" +
|
|
208
|
+
selectorOne + ":extend(" + selectorTwo + ")"};
|
|
184
209
|
}
|
|
185
210
|
|
|
186
|
-
// now process the new extends on the existing rules so that we can handle a extending b extending c
|
|
187
|
-
|
|
211
|
+
// now process the new extends on the existing rules so that we can handle a extending b extending c extending
|
|
212
|
+
// d extending e...
|
|
213
|
+
return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1));
|
|
188
214
|
} else {
|
|
189
215
|
return extendsToAdd;
|
|
190
216
|
}
|
|
@@ -202,22 +228,24 @@ ProcessExtendsVisitor.prototype = {
|
|
|
202
228
|
if (rulesetNode.root) {
|
|
203
229
|
return;
|
|
204
230
|
}
|
|
205
|
-
var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1],
|
|
231
|
+
var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length - 1],
|
|
232
|
+
selectorsToAdd = [], extendVisitor = this, selectorPath;
|
|
206
233
|
|
|
207
234
|
// look at each selector path in the ruleset, find any extend matches and then copy, find and replace
|
|
208
235
|
|
|
209
|
-
for(extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {
|
|
210
|
-
for(pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {
|
|
236
|
+
for (extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {
|
|
237
|
+
for (pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {
|
|
211
238
|
selectorPath = rulesetNode.paths[pathIndex];
|
|
212
239
|
|
|
213
240
|
// extending extends happens initially, before the main pass
|
|
214
241
|
if (rulesetNode.extendOnEveryPath) { continue; }
|
|
215
|
-
var extendList = selectorPath[selectorPath.length-1].extendList;
|
|
242
|
+
var extendList = selectorPath[selectorPath.length - 1].extendList;
|
|
216
243
|
if (extendList && extendList.length) { continue; }
|
|
217
244
|
|
|
218
245
|
matches = this.findMatch(allExtends[extendIndex], selectorPath);
|
|
219
246
|
|
|
220
247
|
if (matches.length) {
|
|
248
|
+
allExtends[extendIndex].hasFoundMatches = true;
|
|
221
249
|
|
|
222
250
|
allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) {
|
|
223
251
|
selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector));
|
|
@@ -239,24 +267,25 @@ ProcessExtendsVisitor.prototype = {
|
|
|
239
267
|
potentialMatches = [], potentialMatch, matches = [];
|
|
240
268
|
|
|
241
269
|
// loop through the haystack elements
|
|
242
|
-
for(haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) {
|
|
270
|
+
for (haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) {
|
|
243
271
|
hackstackSelector = haystackSelectorPath[haystackSelectorIndex];
|
|
244
272
|
|
|
245
|
-
for(hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) {
|
|
273
|
+
for (hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) {
|
|
246
274
|
|
|
247
275
|
haystackElement = hackstackSelector.elements[hackstackElementIndex];
|
|
248
276
|
|
|
249
277
|
// if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
|
|
250
278
|
if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) {
|
|
251
|
-
potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0,
|
|
279
|
+
potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0,
|
|
280
|
+
initialCombinator: haystackElement.combinator});
|
|
252
281
|
}
|
|
253
282
|
|
|
254
|
-
for(i = 0; i < potentialMatches.length; i++) {
|
|
283
|
+
for (i = 0; i < potentialMatches.length; i++) {
|
|
255
284
|
potentialMatch = potentialMatches[i];
|
|
256
285
|
|
|
257
286
|
// selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
|
|
258
|
-
// then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to
|
|
259
|
-
// what the resulting combinator will be
|
|
287
|
+
// then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to
|
|
288
|
+
// work out what the resulting combinator will be
|
|
260
289
|
targetCombinator = haystackElement.combinator.value;
|
|
261
290
|
if (targetCombinator === '' && hackstackElementIndex === 0) {
|
|
262
291
|
targetCombinator = ' ';
|
|
@@ -274,7 +303,8 @@ ProcessExtendsVisitor.prototype = {
|
|
|
274
303
|
if (potentialMatch) {
|
|
275
304
|
potentialMatch.finished = potentialMatch.matched === needleElements.length;
|
|
276
305
|
if (potentialMatch.finished &&
|
|
277
|
-
(!extend.allowAfter &&
|
|
306
|
+
(!extend.allowAfter &&
|
|
307
|
+
(hackstackElementIndex + 1 < hackstackSelector.elements.length || haystackSelectorIndex + 1 < haystackSelectorPath.length))) {
|
|
278
308
|
potentialMatch = null;
|
|
279
309
|
}
|
|
280
310
|
}
|
|
@@ -320,7 +350,7 @@ ProcessExtendsVisitor.prototype = {
|
|
|
320
350
|
if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) {
|
|
321
351
|
return false;
|
|
322
352
|
}
|
|
323
|
-
for(var i = 0; i
|
|
353
|
+
for (var i = 0; i < elementValue1.elements.length; i++) {
|
|
324
354
|
if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) {
|
|
325
355
|
if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) {
|
|
326
356
|
return false;
|
|
@@ -358,7 +388,8 @@ ProcessExtendsVisitor.prototype = {
|
|
|
358
388
|
);
|
|
359
389
|
|
|
360
390
|
if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {
|
|
361
|
-
path[path.length - 1].elements = path[path.length - 1]
|
|
391
|
+
path[path.length - 1].elements = path[path.length - 1]
|
|
392
|
+
.elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
|
|
362
393
|
currentSelectorPathElementIndex = 0;
|
|
363
394
|
currentSelectorPathIndex++;
|
|
364
395
|
}
|
|
@@ -387,7 +418,8 @@ ProcessExtendsVisitor.prototype = {
|
|
|
387
418
|
}
|
|
388
419
|
|
|
389
420
|
if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {
|
|
390
|
-
path[path.length - 1].elements = path[path.length - 1]
|
|
421
|
+
path[path.length - 1].elements = path[path.length - 1]
|
|
422
|
+
.elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
|
|
391
423
|
currentSelectorPathIndex++;
|
|
392
424
|
}
|
|
393
425
|
|
|
@@ -398,20 +430,24 @@ ProcessExtendsVisitor.prototype = {
|
|
|
398
430
|
visitRulesetOut: function (rulesetNode) {
|
|
399
431
|
},
|
|
400
432
|
visitMedia: function (mediaNode, visitArgs) {
|
|
401
|
-
var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
|
|
433
|
+
var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);
|
|
402
434
|
newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));
|
|
403
435
|
this.allExtendsStack.push(newAllExtends);
|
|
404
436
|
},
|
|
405
437
|
visitMediaOut: function (mediaNode) {
|
|
406
|
-
|
|
438
|
+
var lastIndex = this.allExtendsStack.length - 1;
|
|
439
|
+
this.checkExtendsForNonMatched(this.allExtendsStack[lastIndex]);
|
|
440
|
+
this.allExtendsStack.length = lastIndex;
|
|
407
441
|
},
|
|
408
442
|
visitDirective: function (directiveNode, visitArgs) {
|
|
409
|
-
var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
|
|
443
|
+
var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);
|
|
410
444
|
newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends));
|
|
411
445
|
this.allExtendsStack.push(newAllExtends);
|
|
412
446
|
},
|
|
413
447
|
visitDirectiveOut: function (directiveNode) {
|
|
414
|
-
|
|
448
|
+
var lastIndex = this.allExtendsStack.length - 1;
|
|
449
|
+
this.checkExtendsForNonMatched(this.allExtendsStack[lastIndex]);
|
|
450
|
+
this.allExtendsStack.length = lastIndex;
|
|
415
451
|
}
|
|
416
452
|
};
|
|
417
453
|
|
|
@@ -2,6 +2,7 @@ function ImportSequencer(onSequencerEmpty) {
|
|
|
2
2
|
this.imports = [];
|
|
3
3
|
this.variableImports = [];
|
|
4
4
|
this._onSequencerEmpty = onSequencerEmpty;
|
|
5
|
+
this._currentDepth = 0;
|
|
5
6
|
}
|
|
6
7
|
|
|
7
8
|
ImportSequencer.prototype.addImport = function(callback) {
|
|
@@ -24,23 +25,28 @@ ImportSequencer.prototype.addVariableImport = function(callback) {
|
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
ImportSequencer.prototype.tryRun = function() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
this._currentDepth++;
|
|
29
|
+
try {
|
|
30
|
+
while (true) {
|
|
31
|
+
while (this.imports.length > 0) {
|
|
32
|
+
var importItem = this.imports[0];
|
|
33
|
+
if (!importItem.isReady) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.imports = this.imports.slice(1);
|
|
37
|
+
importItem.callback.apply(null, importItem.args);
|
|
32
38
|
}
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
if (this.variableImports.length === 0) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
var variableImport = this.variableImports[0];
|
|
43
|
+
this.variableImports = this.variableImports.slice(1);
|
|
44
|
+
variableImport();
|
|
38
45
|
}
|
|
39
|
-
|
|
40
|
-
this.
|
|
41
|
-
variableImport();
|
|
46
|
+
} finally {
|
|
47
|
+
this._currentDepth--;
|
|
42
48
|
}
|
|
43
|
-
if (this._onSequencerEmpty) {
|
|
49
|
+
if (this._currentDepth === 0 && this._onSequencerEmpty) {
|
|
44
50
|
this._onSequencerEmpty();
|
|
45
51
|
}
|
|
46
52
|
};
|
|
@@ -11,26 +11,28 @@ var ImportVisitor = function(importer, finish) {
|
|
|
11
11
|
this.importCount = 0;
|
|
12
12
|
this.onceFileDetectionMap = {};
|
|
13
13
|
this.recursionDetector = {};
|
|
14
|
-
this._sequencer = new ImportSequencer();
|
|
14
|
+
this._sequencer = new ImportSequencer(this._onSequencerEmpty.bind(this));
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
ImportVisitor.prototype = {
|
|
18
18
|
isReplacing: false,
|
|
19
19
|
run: function (root) {
|
|
20
|
-
var error;
|
|
21
20
|
try {
|
|
22
21
|
// process the contents
|
|
23
22
|
this._visitor.visit(root);
|
|
24
23
|
}
|
|
25
24
|
catch(e) {
|
|
26
|
-
error = e;
|
|
25
|
+
this.error = e;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
this.isFinished = true;
|
|
30
29
|
this._sequencer.tryRun();
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
},
|
|
31
|
+
_onSequencerEmpty: function() {
|
|
32
|
+
if (!this.isFinished) {
|
|
33
|
+
return;
|
|
33
34
|
}
|
|
35
|
+
this._finish(this.error);
|
|
34
36
|
},
|
|
35
37
|
visitImport: function (importNode, visitArgs) {
|
|
36
38
|
var inlineCSS = importNode.options.inline;
|
|
@@ -55,7 +57,7 @@ ImportVisitor.prototype = {
|
|
|
55
57
|
|
|
56
58
|
try {
|
|
57
59
|
evaldImportNode = importNode.evalForImport(context);
|
|
58
|
-
} catch(e){
|
|
60
|
+
} catch(e) {
|
|
59
61
|
if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
|
|
60
62
|
// attempt to eval properly and treat as css
|
|
61
63
|
importNode.css = true;
|
|
@@ -72,7 +74,7 @@ ImportVisitor.prototype = {
|
|
|
72
74
|
// try appending if we haven't determined if it is css or not
|
|
73
75
|
var tryAppendLessExtension = evaldImportNode.css === undefined;
|
|
74
76
|
|
|
75
|
-
for(var i = 0; i < importParent.rules.length; i++) {
|
|
77
|
+
for (var i = 0; i < importParent.rules.length; i++) {
|
|
76
78
|
if (importParent.rules[i] === importNode) {
|
|
77
79
|
importParent.rules[i] = evaldImportNode;
|
|
78
80
|
break;
|
|
@@ -82,9 +84,13 @@ ImportVisitor.prototype = {
|
|
|
82
84
|
var onImported = this.onImported.bind(this, evaldImportNode, context),
|
|
83
85
|
sequencedOnImported = this._sequencer.addImport(onImported);
|
|
84
86
|
|
|
85
|
-
this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.currentFileInfo,
|
|
87
|
+
this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.currentFileInfo,
|
|
88
|
+
evaldImportNode.options, sequencedOnImported);
|
|
86
89
|
} else {
|
|
87
90
|
this.importCount--;
|
|
91
|
+
if (this.isFinished) {
|
|
92
|
+
this._sequencer.tryRun();
|
|
93
|
+
}
|
|
88
94
|
}
|
|
89
95
|
},
|
|
90
96
|
onImported: function (importNode, context, e, root, importedAtRoot, fullPath) {
|
|
@@ -134,10 +140,7 @@ ImportVisitor.prototype = {
|
|
|
134
140
|
importVisitor.importCount--;
|
|
135
141
|
|
|
136
142
|
if (importVisitor.isFinished) {
|
|
137
|
-
|
|
138
|
-
if (importVisitor.importCount === 0) {
|
|
139
|
-
importVisitor._finish(importVisitor.error);
|
|
140
|
-
}
|
|
143
|
+
importVisitor._sequencer.tryRun();
|
|
141
144
|
}
|
|
142
145
|
},
|
|
143
146
|
visitRule: function (ruleNode, visitArgs) {
|
|
@@ -46,16 +46,16 @@ ToCSSVisitor.prototype = {
|
|
|
46
46
|
},
|
|
47
47
|
|
|
48
48
|
visitDirective: function(directiveNode, visitArgs) {
|
|
49
|
-
if (directiveNode.currentFileInfo.reference && !directiveNode.isReferenced) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
49
|
if (directiveNode.name === "@charset") {
|
|
50
|
+
if (!directiveNode.getIsReferenced()) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
53
|
// Only output the debug info together with subsequent @charset definitions
|
|
54
54
|
// a comment (or @media statement) before the actual @charset directive would
|
|
55
55
|
// be considered illegal css as it has to be on the first line
|
|
56
56
|
if (this.charset) {
|
|
57
57
|
if (directiveNode.debugInfo) {
|
|
58
|
-
var comment = new tree.Comment("/* " + directiveNode.toCSS(this._context).replace(/\n/g, "")+" */\n");
|
|
58
|
+
var comment = new tree.Comment("/* " + directiveNode.toCSS(this._context).replace(/\n/g, "") + " */\n");
|
|
59
59
|
comment.debugInfo = directiveNode.debugInfo;
|
|
60
60
|
return this._visitor.visit(comment);
|
|
61
61
|
}
|
|
@@ -65,13 +65,45 @@ ToCSSVisitor.prototype = {
|
|
|
65
65
|
}
|
|
66
66
|
if (directiveNode.rules && directiveNode.rules.rules) {
|
|
67
67
|
this._mergeRules(directiveNode.rules.rules);
|
|
68
|
+
//process childs
|
|
69
|
+
directiveNode.accept(this._visitor);
|
|
70
|
+
visitArgs.visitDeeper = false;
|
|
71
|
+
|
|
72
|
+
// the directive was directly referenced and therefore needs to be shown in the output
|
|
73
|
+
if (directiveNode.getIsReferenced()) {
|
|
74
|
+
return directiveNode;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!directiveNode.rules.rules) {
|
|
78
|
+
return ;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//the directive was not directly referenced
|
|
82
|
+
for (var r = 0; r < directiveNode.rules.rules.length; r++) {
|
|
83
|
+
var rule = directiveNode.rules.rules[r];
|
|
84
|
+
if (rule.getIsReferenced && rule.getIsReferenced()) {
|
|
85
|
+
//the directive contains something that was referenced (likely by extend)
|
|
86
|
+
//therefore it needs to be shown in output too
|
|
87
|
+
|
|
88
|
+
//marking as referenced in case the directive is stored inside another directive
|
|
89
|
+
directiveNode.markReferenced();
|
|
90
|
+
return directiveNode;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//The directive was not directly referenced and does not contain anything that
|
|
94
|
+
//was referenced. Therefore it must not be shown in output.
|
|
95
|
+
return ;
|
|
96
|
+
} else {
|
|
97
|
+
if (!directiveNode.getIsReferenced()) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
68
100
|
}
|
|
69
101
|
return directiveNode;
|
|
70
102
|
},
|
|
71
103
|
|
|
72
104
|
checkPropertiesInRoot: function(rules) {
|
|
73
105
|
var ruleNode;
|
|
74
|
-
for(var i = 0; i < rules.length; i++) {
|
|
106
|
+
for (var i = 0; i < rules.length; i++) {
|
|
75
107
|
ruleNode = rules[i];
|
|
76
108
|
if (ruleNode instanceof tree.Rule && !ruleNode.variable) {
|
|
77
109
|
throw { message: "properties must be inside selector blocks, they cannot be in the root.",
|
|
@@ -93,7 +125,7 @@ ToCSSVisitor.prototype = {
|
|
|
93
125
|
if (p[0].elements[0].combinator.value === ' ') {
|
|
94
126
|
p[0].elements[0].combinator = new(tree.Combinator)('');
|
|
95
127
|
}
|
|
96
|
-
for(i = 0; i < p.length; i++) {
|
|
128
|
+
for (i = 0; i < p.length; i++) {
|
|
97
129
|
if (p[i].getIsReferenced() && p[i].getIsOutput()) {
|
|
98
130
|
return true;
|
|
99
131
|
}
|
|
@@ -158,7 +190,7 @@ ToCSSVisitor.prototype = {
|
|
|
158
190
|
var ruleCache = {},
|
|
159
191
|
ruleList, rule, i;
|
|
160
192
|
|
|
161
|
-
for(i = rules.length - 1; i >= 0 ; i--) {
|
|
193
|
+
for (i = rules.length - 1; i >= 0 ; i--) {
|
|
162
194
|
rule = rules[i];
|
|
163
195
|
if (rule instanceof tree.Rule) {
|
|
164
196
|
if (!ruleCache[rule.name]) {
|
|
@@ -225,8 +257,8 @@ ToCSSVisitor.prototype = {
|
|
|
225
257
|
var spacedGroups = [];
|
|
226
258
|
var lastSpacedGroup = [];
|
|
227
259
|
parts.map(function (p) {
|
|
228
|
-
|
|
229
|
-
|
|
260
|
+
if (p.merge === "+") {
|
|
261
|
+
if (lastSpacedGroup.length > 0) {
|
|
230
262
|
spacedGroups.push(toExpression(lastSpacedGroup));
|
|
231
263
|
}
|
|
232
264
|
lastSpacedGroup = [];
|
|
@@ -7,7 +7,7 @@ module.exports = function(window, options) {
|
|
|
7
7
|
addDataAttr(options, browser.currentScript(window));
|
|
8
8
|
|
|
9
9
|
if (options.isFileProtocol === undefined) {
|
|
10
|
-
options.isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(window.location.protocol);
|
|
10
|
+
options.isFileProtocol = /^(file|(chrome|safari)(-extension)?|resource|qrc|app):/.test(window.location.protocol);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// Load styles asynchronously (default: false)
|
|
@@ -39,4 +39,8 @@ module.exports = function(window, options) {
|
|
|
39
39
|
options.useFileCache = true;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
if (options.onReady === undefined) {
|
|
43
|
+
options.onReady = true;
|
|
44
|
+
}
|
|
45
|
+
|
|
42
46
|
};
|
|
@@ -13,12 +13,14 @@ require("./add-default-options")(window, options);
|
|
|
13
13
|
|
|
14
14
|
var less = module.exports = require("./index")(window, options);
|
|
15
15
|
|
|
16
|
-
if (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
less.pageLoadFinished = less.registerStylesheets().then(
|
|
21
|
-
function () {
|
|
22
|
-
return less.refresh(less.env === 'development');
|
|
16
|
+
if (options.onReady) {
|
|
17
|
+
if (/!watch/.test(window.location.hash)) {
|
|
18
|
+
less.watch();
|
|
23
19
|
}
|
|
24
|
-
|
|
20
|
+
|
|
21
|
+
less.pageLoadFinished = less.registerStylesheets().then(
|
|
22
|
+
function () {
|
|
23
|
+
return less.refresh(less.env === 'development');
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -4,19 +4,19 @@ module.exports = function(window, options, logger) {
|
|
|
4
4
|
var cache = null;
|
|
5
5
|
if (options.env !== 'development') {
|
|
6
6
|
try {
|
|
7
|
-
cache = (typeof
|
|
7
|
+
cache = (typeof window.localStorage === 'undefined') ? null : window.localStorage;
|
|
8
8
|
} catch (_) {}
|
|
9
9
|
}
|
|
10
10
|
return {
|
|
11
11
|
setCSS: function(path, lastModified, styles) {
|
|
12
12
|
if (cache) {
|
|
13
|
-
logger.info('saving ' + path+ ' to cache.');
|
|
13
|
+
logger.info('saving ' + path + ' to cache.');
|
|
14
14
|
try {
|
|
15
15
|
cache.setItem(path, styles);
|
|
16
16
|
cache.setItem(path + ':timestamp', lastModified);
|
|
17
17
|
} catch(e) {
|
|
18
18
|
//TODO - could do with adding more robust error handling
|
|
19
|
-
logger.error('failed to save');
|
|
19
|
+
logger.error('failed to save "' + path + '" to local storage for caching.');
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
},
|