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/ruleset.js
CHANGED
|
@@ -2,6 +2,7 @@ var Node = require("./node"),
|
|
|
2
2
|
Rule = require("./rule"),
|
|
3
3
|
Selector = require("./selector"),
|
|
4
4
|
Element = require("./element"),
|
|
5
|
+
Paren = require("./paren"),
|
|
5
6
|
contexts = require("../contexts"),
|
|
6
7
|
defaultFunc = require("../functions/default"),
|
|
7
8
|
getDebugInfo = require("./debug-info");
|
|
@@ -57,7 +58,7 @@ Ruleset.prototype.eval = function (context) {
|
|
|
57
58
|
ruleset.firstRoot = this.firstRoot;
|
|
58
59
|
ruleset.allowImports = this.allowImports;
|
|
59
60
|
|
|
60
|
-
if(this.debugInfo) {
|
|
61
|
+
if (this.debugInfo) {
|
|
61
62
|
ruleset.debugInfo = this.debugInfo;
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -107,7 +108,7 @@ Ruleset.prototype.eval = function (context) {
|
|
|
107
108
|
});
|
|
108
109
|
rsRules.splice.apply(rsRules, [i, 1].concat(rules));
|
|
109
110
|
rsRuleCnt += rules.length - 1;
|
|
110
|
-
i += rules.length-1;
|
|
111
|
+
i += rules.length - 1;
|
|
111
112
|
ruleset.resetCache();
|
|
112
113
|
} else if (rsRules[i].type === "RulesetCall") {
|
|
113
114
|
/*jshint loopfunc:true */
|
|
@@ -120,7 +121,7 @@ Ruleset.prototype.eval = function (context) {
|
|
|
120
121
|
});
|
|
121
122
|
rsRules.splice.apply(rsRules, [i, 1].concat(rules));
|
|
122
123
|
rsRuleCnt += rules.length - 1;
|
|
123
|
-
i += rules.length-1;
|
|
124
|
+
i += rules.length - 1;
|
|
124
125
|
ruleset.resetCache();
|
|
125
126
|
}
|
|
126
127
|
}
|
|
@@ -142,7 +143,7 @@ Ruleset.prototype.eval = function (context) {
|
|
|
142
143
|
if (rule.selectors[0].isJustParentSelector()) {
|
|
143
144
|
rsRules.splice(i--, 1);
|
|
144
145
|
|
|
145
|
-
for(var j = 0; j < rule.rules.length; j++) {
|
|
146
|
+
for (var j = 0; j < rule.rules.length; j++) {
|
|
146
147
|
subRule = rule.rules[j];
|
|
147
148
|
if (!(subRule instanceof Rule) || !subRule.variable) {
|
|
148
149
|
rsRules.splice(++i, 0, subRule);
|
|
@@ -173,7 +174,7 @@ Ruleset.prototype.evalImports = function(context) {
|
|
|
173
174
|
importRules = rules[i].eval(context);
|
|
174
175
|
if (importRules && importRules.length) {
|
|
175
176
|
rules.splice.apply(rules, [i, 1].concat(importRules));
|
|
176
|
-
i+= importRules.length-1;
|
|
177
|
+
i+= importRules.length - 1;
|
|
177
178
|
} else {
|
|
178
179
|
rules.splice(i, 1, importRules);
|
|
179
180
|
}
|
|
@@ -182,20 +183,22 @@ Ruleset.prototype.evalImports = function(context) {
|
|
|
182
183
|
}
|
|
183
184
|
};
|
|
184
185
|
Ruleset.prototype.makeImportant = function() {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
186
|
+
var result = new Ruleset(this.selectors, this.rules.map(function (r) {
|
|
187
|
+
if (r.makeImportant) {
|
|
188
|
+
return r.makeImportant();
|
|
189
|
+
} else {
|
|
190
|
+
return r;
|
|
191
|
+
}
|
|
192
|
+
}), this.strictImports);
|
|
193
|
+
|
|
194
|
+
return result;
|
|
192
195
|
};
|
|
193
196
|
Ruleset.prototype.matchArgs = function (args) {
|
|
194
197
|
return !args || args.length === 0;
|
|
195
198
|
};
|
|
196
199
|
// lets you call a css selector with a guard
|
|
197
200
|
Ruleset.prototype.matchCondition = function (args, context) {
|
|
198
|
-
var lastSelector = this.selectors[this.selectors.length-1];
|
|
201
|
+
var lastSelector = this.selectors[this.selectors.length - 1];
|
|
199
202
|
if (!lastSelector.evaldCondition) {
|
|
200
203
|
return false;
|
|
201
204
|
}
|
|
@@ -220,9 +223,10 @@ Ruleset.prototype.variables = function () {
|
|
|
220
223
|
}
|
|
221
224
|
// when evaluating variables in an import statement, imports have not been eval'd
|
|
222
225
|
// so we need to go inside import statements.
|
|
223
|
-
|
|
226
|
+
// guard against root being a string (in the case of inlined less)
|
|
227
|
+
if (r.type === "Import" && r.root && r.root.variables) {
|
|
224
228
|
var vars = r.root.variables();
|
|
225
|
-
for(var name in vars) {
|
|
229
|
+
for (var name in vars) {
|
|
226
230
|
if (vars.hasOwnProperty(name)) {
|
|
227
231
|
hash[name] = vars[name];
|
|
228
232
|
}
|
|
@@ -253,7 +257,11 @@ Ruleset.prototype.rulesets = function () {
|
|
|
253
257
|
};
|
|
254
258
|
Ruleset.prototype.prependRule = function (rule) {
|
|
255
259
|
var rules = this.rules;
|
|
256
|
-
if (rules) {
|
|
260
|
+
if (rules) {
|
|
261
|
+
rules.unshift(rule);
|
|
262
|
+
} else {
|
|
263
|
+
this.rules = [ rule ];
|
|
264
|
+
}
|
|
257
265
|
};
|
|
258
266
|
Ruleset.prototype.find = function (selector, self, filter) {
|
|
259
267
|
self = self || this;
|
|
@@ -268,13 +276,13 @@ Ruleset.prototype.find = function (selector, self, filter) {
|
|
|
268
276
|
match = selector.match(rule.selectors[j]);
|
|
269
277
|
if (match) {
|
|
270
278
|
if (selector.elements.length > match) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
279
|
+
if (!filter || filter(rule)) {
|
|
280
|
+
foundMixins = rule.find(new Selector(selector.elements.slice(match)), self, filter);
|
|
281
|
+
for (var i = 0; i < foundMixins.length; ++i) {
|
|
282
|
+
foundMixins[i].path.push(rule);
|
|
283
|
+
}
|
|
284
|
+
Array.prototype.push.apply(rules, foundMixins);
|
|
275
285
|
}
|
|
276
|
-
Array.prototype.push.apply(rules, foundMixins);
|
|
277
|
-
}
|
|
278
286
|
} else {
|
|
279
287
|
rules.push({ rule: rule, path: []});
|
|
280
288
|
}
|
|
@@ -307,19 +315,17 @@ Ruleset.prototype.genCSS = function (context, output) {
|
|
|
307
315
|
sep;
|
|
308
316
|
|
|
309
317
|
function isRulesetLikeNode(rule, root) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
return rule.isRulesetLike(root);
|
|
319
|
-
}
|
|
318
|
+
// if it has nested rules, then it should be treated like a ruleset
|
|
319
|
+
// medias and comments do not have nested rules, but should be treated like rulesets anyway
|
|
320
|
+
// some directives and anonymous nodes are ruleset like, others are not
|
|
321
|
+
if (typeof rule.isRulesetLike === "boolean") {
|
|
322
|
+
return rule.isRulesetLike;
|
|
323
|
+
} else if (typeof rule.isRulesetLike === "function") {
|
|
324
|
+
return rule.isRulesetLike(root);
|
|
325
|
+
}
|
|
320
326
|
|
|
321
|
-
|
|
322
|
-
|
|
327
|
+
//anything else is assumed to be a rule
|
|
328
|
+
return false;
|
|
323
329
|
}
|
|
324
330
|
|
|
325
331
|
for (i = 0; i < this.rules.length; i++) {
|
|
@@ -413,189 +419,296 @@ Ruleset.prototype.genCSS = function (context, output) {
|
|
|
413
419
|
}
|
|
414
420
|
};
|
|
415
421
|
Ruleset.prototype.markReferenced = function () {
|
|
416
|
-
|
|
417
|
-
|
|
422
|
+
var s;
|
|
423
|
+
if (this.selectors) {
|
|
424
|
+
for (s = 0; s < this.selectors.length; s++) {
|
|
425
|
+
this.selectors[s].markReferenced();
|
|
426
|
+
}
|
|
418
427
|
}
|
|
419
|
-
|
|
420
|
-
|
|
428
|
+
|
|
429
|
+
if (this.rules) {
|
|
430
|
+
for (s = 0; s < this.rules.length; s++) {
|
|
431
|
+
if (this.rules[s].markReferenced) {
|
|
432
|
+
this.rules[s].markReferenced();
|
|
433
|
+
}
|
|
434
|
+
}
|
|
421
435
|
}
|
|
422
436
|
};
|
|
437
|
+
Ruleset.prototype.getIsReferenced = function() {
|
|
438
|
+
var i, j, path, selector;
|
|
439
|
+
|
|
440
|
+
if (this.paths) {
|
|
441
|
+
for (i = 0; i < this.paths.length; i++) {
|
|
442
|
+
path = this.paths[i];
|
|
443
|
+
for (j = 0; j < path.length; j++) {
|
|
444
|
+
if (path[j].getIsReferenced && path[j].getIsReferenced()) {
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (this.selectors) {
|
|
452
|
+
for (i = 0; i < this.selectors.length; i++) {
|
|
453
|
+
selector = this.selectors[i];
|
|
454
|
+
if (selector.getIsReferenced && selector.getIsReferenced()) {
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return false;
|
|
460
|
+
};
|
|
461
|
+
|
|
423
462
|
Ruleset.prototype.joinSelectors = function (paths, context, selectors) {
|
|
424
463
|
for (var s = 0; s < selectors.length; s++) {
|
|
425
464
|
this.joinSelector(paths, context, selectors[s]);
|
|
426
465
|
}
|
|
427
466
|
};
|
|
428
|
-
Ruleset.prototype.joinSelector = function (paths, context, selector) {
|
|
429
|
-
|
|
430
|
-
var i, j, k,
|
|
431
|
-
hasParentSelector, newSelectors, el, sel, parentSel,
|
|
432
|
-
newSelectorPath, afterParentJoin, newJoinedSelector,
|
|
433
|
-
newJoinedSelectorEmpty, lastSelector, currentElements,
|
|
434
|
-
selectorsMultiplied;
|
|
435
467
|
|
|
436
|
-
|
|
437
|
-
el = selector.elements[i];
|
|
438
|
-
if (el.value === '&') {
|
|
439
|
-
hasParentSelector = true;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
468
|
+
Ruleset.prototype.joinSelector = function (paths, context, selector) {
|
|
442
469
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
470
|
+
function createParenthesis(elementsToPak, originalElement) {
|
|
471
|
+
var replacementParen, j;
|
|
472
|
+
if (elementsToPak.length === 0) {
|
|
473
|
+
replacementParen = new Paren(elementsToPak[0]);
|
|
474
|
+
} else {
|
|
475
|
+
var insideParent = [];
|
|
476
|
+
for (j = 0; j < elementsToPak.length; j++) {
|
|
477
|
+
insideParent.push(new Element(null, elementsToPak[j], originalElement.index, originalElement.currentFileInfo));
|
|
447
478
|
}
|
|
479
|
+
replacementParen = new Paren(new Selector(insideParent));
|
|
448
480
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
//
|
|
460
|
-
//
|
|
461
|
-
//
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
// the new list of selectors to add
|
|
480
|
-
selectorsMultiplied = [];
|
|
481
|
+
return replacementParen;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function createSelector(containedElement, originalElement) {
|
|
485
|
+
var element, selector;
|
|
486
|
+
element = new Element(null, containedElement, originalElement.index, originalElement.currentFileInfo);
|
|
487
|
+
selector = new Selector([element]);
|
|
488
|
+
return selector;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// replace all parent selectors inside `inSelector` by content of `context` array
|
|
492
|
+
// resulting selectors are returned inside `paths` array
|
|
493
|
+
// returns true if `inSelector` contained at least one parent selector
|
|
494
|
+
function replaceParentSelector(paths, context, inSelector) {
|
|
495
|
+
// The paths are [[Selector]]
|
|
496
|
+
// The first list is a list of comma separated selectors
|
|
497
|
+
// The inner list is a list of inheritance separated selectors
|
|
498
|
+
// e.g.
|
|
499
|
+
// .a, .b {
|
|
500
|
+
// .c {
|
|
501
|
+
// }
|
|
502
|
+
// }
|
|
503
|
+
// == [[.a] [.c]] [[.b] [.c]]
|
|
504
|
+
//
|
|
505
|
+
var i, j, k, currentElements, newSelectors, selectorsMultiplied, sel, el, hadParentSelector = false, length, lastSelector;
|
|
506
|
+
function findNestedSelector(element) {
|
|
507
|
+
var maybeSelector;
|
|
508
|
+
if (element.value.type !== 'Paren') {
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
481
511
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
this.mergeElementsOnToSelectors(currentElements, newSelectors);
|
|
512
|
+
maybeSelector = element.value.value;
|
|
513
|
+
if (maybeSelector.type !== 'Selector') {
|
|
514
|
+
return null;
|
|
486
515
|
}
|
|
487
516
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
517
|
+
return maybeSelector;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// the elements from the current selector so far
|
|
521
|
+
currentElements = [];
|
|
522
|
+
// the current list of new selectors to add to the path.
|
|
523
|
+
// We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
|
|
524
|
+
// by the parents
|
|
525
|
+
newSelectors = [
|
|
526
|
+
[]
|
|
527
|
+
];
|
|
528
|
+
|
|
529
|
+
for (i = 0; i < inSelector.elements.length; i++) {
|
|
530
|
+
el = inSelector.elements[i];
|
|
531
|
+
// non parent reference elements just get added
|
|
532
|
+
if (el.value !== "&") {
|
|
533
|
+
var nestedSelector = findNestedSelector(el);
|
|
534
|
+
if (nestedSelector != null) {
|
|
535
|
+
// merge the current list of non parent selector elements
|
|
536
|
+
// on to the current list of selectors to add
|
|
537
|
+
mergeElementsOnToSelectors(currentElements, newSelectors);
|
|
538
|
+
|
|
539
|
+
var nestedPaths = [], replaced, replacedNewSelectors = [];
|
|
540
|
+
replaced = replaceParentSelector(nestedPaths, context, nestedSelector);
|
|
541
|
+
hadParentSelector = hadParentSelector || replaced;
|
|
542
|
+
//the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors
|
|
543
|
+
for (k = 0; k < nestedPaths.length; k++) {
|
|
544
|
+
var replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el);
|
|
545
|
+
addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors);
|
|
499
546
|
}
|
|
500
|
-
|
|
547
|
+
newSelectors = replacedNewSelectors;
|
|
548
|
+
currentElements = [];
|
|
549
|
+
|
|
550
|
+
} else {
|
|
551
|
+
currentElements.push(el);
|
|
501
552
|
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
553
|
+
|
|
554
|
+
} else {
|
|
555
|
+
hadParentSelector = true;
|
|
556
|
+
// the new list of selectors to add
|
|
557
|
+
selectorsMultiplied = [];
|
|
558
|
+
|
|
559
|
+
// merge the current list of non parent selector elements
|
|
560
|
+
// on to the current list of selectors to add
|
|
561
|
+
mergeElementsOnToSelectors(currentElements, newSelectors);
|
|
562
|
+
|
|
563
|
+
// loop through our current selectors
|
|
564
|
+
for (j = 0; j < newSelectors.length; j++) {
|
|
565
|
+
sel = newSelectors[j];
|
|
566
|
+
// if we don't have any parent paths, the & might be in a mixin so that it can be used
|
|
567
|
+
// whether there are parents or not
|
|
568
|
+
if (context.length === 0) {
|
|
569
|
+
// the combinator used on el should now be applied to the next element instead so that
|
|
570
|
+
// it is not lost
|
|
517
571
|
if (sel.length > 0) {
|
|
518
|
-
|
|
519
|
-
lastSelector = newSelectorPath.pop();
|
|
520
|
-
newJoinedSelector = selector.createDerived(lastSelector.elements.slice(0));
|
|
521
|
-
newJoinedSelectorEmpty = false;
|
|
572
|
+
sel[0].elements.push(new Element(el.combinator, '', el.index, el.currentFileInfo));
|
|
522
573
|
}
|
|
523
|
-
|
|
524
|
-
|
|
574
|
+
selectorsMultiplied.push(sel);
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
// and the parent selectors
|
|
578
|
+
for (k = 0; k < context.length; k++) {
|
|
579
|
+
// We need to put the current selectors
|
|
580
|
+
// then join the last selector's elements on to the parents selectors
|
|
581
|
+
var newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector);
|
|
582
|
+
// add that to our new set of selectors
|
|
583
|
+
selectorsMultiplied.push(newSelectorPath);
|
|
525
584
|
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
526
587
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
588
|
+
// our new selectors has been multiplied, so reset the state
|
|
589
|
+
newSelectors = selectorsMultiplied;
|
|
590
|
+
currentElements = [];
|
|
591
|
+
}
|
|
592
|
+
}
|
|
531
593
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
// /deep/ is a combinator that is valid without anything in front of it
|
|
536
|
-
// so if the & does not have a combinator that is "" or " " then
|
|
537
|
-
// and there is a combinator on the parent, then grab that.
|
|
538
|
-
// this also allows + a { & .b { .a & { ... though not sure why you would want to do that
|
|
539
|
-
var combinator = el.combinator,
|
|
540
|
-
parentEl = parentSel[0].elements[0];
|
|
541
|
-
if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) {
|
|
542
|
-
combinator = parentEl.combinator;
|
|
543
|
-
}
|
|
544
|
-
// join the elements so far with the first part of the parent
|
|
545
|
-
newJoinedSelector.elements.push(new Element(combinator, parentEl.value, el.index, el.currentFileInfo));
|
|
546
|
-
newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1));
|
|
547
|
-
}
|
|
594
|
+
// if we have any elements left over (e.g. .a& .b == .b)
|
|
595
|
+
// add them on to all the current selectors
|
|
596
|
+
mergeElementsOnToSelectors(currentElements, newSelectors);
|
|
548
597
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
598
|
+
for (i = 0; i < newSelectors.length; i++) {
|
|
599
|
+
length = newSelectors[i].length;
|
|
600
|
+
if (length > 0) {
|
|
601
|
+
paths.push(newSelectors[i]);
|
|
602
|
+
lastSelector = newSelectors[i][length - 1];
|
|
603
|
+
newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
553
606
|
|
|
554
|
-
|
|
555
|
-
|
|
607
|
+
return hadParentSelector;
|
|
608
|
+
}
|
|
556
609
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
610
|
+
// joins selector path from `beginningPath` with selector path in `addPath`
|
|
611
|
+
// `replacedElement` contains element that is being replaced by `addPath`
|
|
612
|
+
// returns concatenated path
|
|
613
|
+
function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) {
|
|
614
|
+
var newSelectorPath, lastSelector, newJoinedSelector;
|
|
615
|
+
// our new selector path
|
|
616
|
+
newSelectorPath = [];
|
|
617
|
+
|
|
618
|
+
//construct the joined selector - if & is the first thing this will be empty,
|
|
619
|
+
// if not newJoinedSelector will be the last set of elements in the selector
|
|
620
|
+
if (beginningPath.length > 0) {
|
|
621
|
+
newSelectorPath = beginningPath.slice(0);
|
|
622
|
+
lastSelector = newSelectorPath.pop();
|
|
623
|
+
newJoinedSelector = originalSelector.createDerived(lastSelector.elements.slice(0));
|
|
624
|
+
}
|
|
625
|
+
else {
|
|
626
|
+
newJoinedSelector = originalSelector.createDerived([]);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if (addPath.length > 0) {
|
|
630
|
+
// /deep/ is a combinator that is valid without anything in front of it
|
|
631
|
+
// so if the & does not have a combinator that is "" or " " then
|
|
632
|
+
// and there is a combinator on the parent, then grab that.
|
|
633
|
+
// this also allows + a { & .b { .a & { ... though not sure why you would want to do that
|
|
634
|
+
var combinator = replacedElement.combinator, parentEl = addPath[0].elements[0];
|
|
635
|
+
if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) {
|
|
636
|
+
combinator = parentEl.combinator;
|
|
561
637
|
}
|
|
638
|
+
// join the elements so far with the first part of the parent
|
|
639
|
+
newJoinedSelector.elements.push(new Element(combinator, parentEl.value, replacedElement.index, replacedElement.currentFileInfo));
|
|
640
|
+
newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1));
|
|
641
|
+
}
|
|
562
642
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
643
|
+
// now add the joined selector - but only if it is not empty
|
|
644
|
+
if (newJoinedSelector.elements.length !== 0) {
|
|
645
|
+
newSelectorPath.push(newJoinedSelector);
|
|
566
646
|
}
|
|
567
|
-
}
|
|
568
647
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
648
|
+
//put together the parent selectors after the join (e.g. the rest of the parent)
|
|
649
|
+
if (addPath.length > 1) {
|
|
650
|
+
newSelectorPath = newSelectorPath.concat(addPath.slice(1));
|
|
651
|
+
}
|
|
652
|
+
return newSelectorPath;
|
|
573
653
|
}
|
|
574
654
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
655
|
+
// joins selector path from `beginningPath` with every selector path in `addPaths` array
|
|
656
|
+
// `replacedElement` contains element that is being replaced by `addPath`
|
|
657
|
+
// returns array with all concatenated paths
|
|
658
|
+
function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) {
|
|
659
|
+
var j;
|
|
660
|
+
for (j = 0; j < beginningPath.length; j++) {
|
|
661
|
+
var newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector);
|
|
662
|
+
result.push(newSelectorPath);
|
|
578
663
|
}
|
|
664
|
+
return result;
|
|
579
665
|
}
|
|
580
|
-
};
|
|
581
|
-
Ruleset.prototype.mergeElementsOnToSelectors = function(elements, selectors) {
|
|
582
|
-
var i, sel;
|
|
583
666
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
667
|
+
function mergeElementsOnToSelectors(elements, selectors) {
|
|
668
|
+
var i, sel;
|
|
669
|
+
|
|
670
|
+
if (elements.length === 0) {
|
|
671
|
+
return ;
|
|
672
|
+
}
|
|
673
|
+
if (selectors.length === 0) {
|
|
674
|
+
selectors.push([ new Selector(elements) ]);
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
for (i = 0; i < selectors.length; i++) {
|
|
679
|
+
sel = selectors[i];
|
|
680
|
+
|
|
681
|
+
// if the previous thing in sel is a parent this needs to join on to it
|
|
682
|
+
if (sel.length > 0) {
|
|
683
|
+
sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
|
|
684
|
+
}
|
|
685
|
+
else {
|
|
686
|
+
sel.push(new Selector(elements));
|
|
687
|
+
}
|
|
688
|
+
}
|
|
587
689
|
}
|
|
588
690
|
|
|
589
|
-
|
|
590
|
-
|
|
691
|
+
// joinSelector code follows
|
|
692
|
+
var i, newPaths, hadParentSelector;
|
|
591
693
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
694
|
+
newPaths = [];
|
|
695
|
+
hadParentSelector = replaceParentSelector(newPaths, context, selector);
|
|
696
|
+
|
|
697
|
+
if (!hadParentSelector) {
|
|
698
|
+
if (context.length > 0) {
|
|
699
|
+
newPaths = [];
|
|
700
|
+
for (i = 0; i < context.length; i++) {
|
|
701
|
+
newPaths.push(context[i].concat(selector));
|
|
702
|
+
}
|
|
595
703
|
}
|
|
596
704
|
else {
|
|
597
|
-
|
|
705
|
+
newPaths = [[selector]];
|
|
598
706
|
}
|
|
599
707
|
}
|
|
708
|
+
|
|
709
|
+
for (i = 0; i < newPaths.length; i++) {
|
|
710
|
+
paths.push(newPaths[i]);
|
|
711
|
+
}
|
|
712
|
+
|
|
600
713
|
};
|
|
601
714
|
module.exports = Ruleset;
|
|
@@ -51,8 +51,9 @@ Selector.prototype.match = function (other) {
|
|
|
51
51
|
return olen; // return number of matched elements
|
|
52
52
|
};
|
|
53
53
|
Selector.prototype.CacheElements = function() {
|
|
54
|
-
if (this._elements)
|
|
54
|
+
if (this._elements) {
|
|
55
55
|
return;
|
|
56
|
+
}
|
|
56
57
|
|
|
57
58
|
var elements = this.elements.map( function(v) {
|
|
58
59
|
return v.combinator.value + (v.value.value || v.value);
|
|
@@ -90,7 +91,7 @@ Selector.prototype.genCSS = function (context, output) {
|
|
|
90
91
|
}
|
|
91
92
|
if (!this._css) {
|
|
92
93
|
//TODO caching? speed comparison?
|
|
93
|
-
for(i = 0; i < this.elements.length; i++) {
|
|
94
|
+
for (i = 0; i < this.elements.length; i++) {
|
|
94
95
|
element = this.elements[i];
|
|
95
96
|
element.genCSS(context, output);
|
|
96
97
|
}
|
package/lib/less/tree/unit.js
CHANGED
|
@@ -23,6 +23,8 @@ Unit.prototype.genCSS = function (context, output) {
|
|
|
23
23
|
output.add(this.numerator[0]); // the ideal situation
|
|
24
24
|
} else if (!strictUnits && this.backupUnit) {
|
|
25
25
|
output.add(this.backupUnit);
|
|
26
|
+
} else if (!strictUnits && this.denominator.length) {
|
|
27
|
+
output.add(this.denominator[0]);
|
|
26
28
|
}
|
|
27
29
|
};
|
|
28
30
|
Unit.prototype.toString = function () {
|
package/lib/less/tree/url.js
CHANGED
|
@@ -23,9 +23,12 @@ URL.prototype.eval = function (context) {
|
|
|
23
23
|
if (!this.isEvald) {
|
|
24
24
|
// Add the base path if the URL is relative
|
|
25
25
|
rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
|
|
26
|
-
if (rootpath &&
|
|
26
|
+
if (rootpath &&
|
|
27
|
+
typeof val.value === "string" &&
|
|
28
|
+
context.isPathRelative(val.value)) {
|
|
29
|
+
|
|
27
30
|
if (!val.quote) {
|
|
28
|
-
rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; });
|
|
31
|
+
rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\" + match; });
|
|
29
32
|
}
|
|
30
33
|
val.value = rootpath + val.value;
|
|
31
34
|
}
|