less 2.6.0 → 2.7.2

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.
Files changed (144) hide show
  1. package/.travis.yml +3 -2
  2. package/CHANGELOG.md +30 -2
  3. package/Gruntfile.js +2 -3
  4. package/README.md +2 -2
  5. package/appveyor.yml +1 -0
  6. package/bin/lessc +47 -23
  7. package/dist/less.js +914 -582
  8. package/dist/less.min.js +9 -12
  9. package/lib/less/environment/abstract-file-manager.js +2 -2
  10. package/lib/less/functions/color.js +6 -3
  11. package/lib/less/index.js +1 -1
  12. package/lib/less/parser/parser-input.js +69 -69
  13. package/lib/less/parser/parser.js +111 -51
  14. package/lib/less/tree/anonymous.js +1 -1
  15. package/lib/less/tree/call.js +7 -4
  16. package/lib/less/tree/comment.js +2 -0
  17. package/lib/less/tree/directive.js +1 -0
  18. package/lib/less/tree/extend.js +1 -0
  19. package/lib/less/tree/import.js +1 -0
  20. package/lib/less/tree/media.js +1 -0
  21. package/lib/less/tree/mixin-call.js +1 -0
  22. package/lib/less/tree/mixin-definition.js +2 -1
  23. package/lib/less/tree/rule.js +1 -0
  24. package/lib/less/tree/ruleset-call.js +1 -0
  25. package/lib/less/tree/ruleset.js +86 -85
  26. package/lib/less/tree/unit.js +2 -2
  27. package/lib/less/visitors/extend-visitor.js +5 -5
  28. package/lib/less/visitors/to-css-visitor.js +20 -10
  29. package/lib/less-browser/error-reporting.js +10 -10
  30. package/lib/less-browser/index.js +48 -25
  31. package/lib/less-node/file-manager.js +1 -1
  32. package/lib/less-node/lessc-helper.js +2 -2
  33. package/lib/source-map/source-map-0.1.31.js +1 -1
  34. package/package.json +29 -22
  35. package/test/browser/common.js +29 -8
  36. package/test/browser/less/console-errors/test-error.txt +1 -1
  37. package/test/browser/less.js +13 -16
  38. package/test/browser/runner-production-options.js +1 -1
  39. package/test/css/comments2.css +6 -0
  40. package/test/css/no-strict-math/mixins-guards.css +12 -0
  41. package/test/css/no-strict-math/no-sm-operations.css +3 -0
  42. package/test/css/operations.css +1 -1
  43. package/test/css/plugin.css +5 -0
  44. package/test/less/comments.less +1 -1
  45. package/test/less/comments2.less +11 -0
  46. package/test/less/errors/detached-ruleset-3.txt +1 -1
  47. package/test/less/errors/functions-1.less +2 -0
  48. package/test/less/errors/functions-1.txt +3 -0
  49. package/test/less/errors/functions-10-keyword.less +2 -0
  50. package/test/less/errors/functions-10-keyword.txt +3 -0
  51. package/test/less/errors/functions-11-operation.less +2 -0
  52. package/test/less/errors/functions-11-operation.txt +3 -0
  53. package/test/less/errors/functions-12-quoted.less +2 -0
  54. package/test/less/errors/functions-12-quoted.txt +3 -0
  55. package/test/less/errors/functions-13-selector.less +2 -0
  56. package/test/less/errors/functions-13-selector.txt +3 -0
  57. package/test/less/errors/functions-14-url.less +2 -0
  58. package/test/less/errors/functions-14-url.txt +3 -0
  59. package/test/less/errors/functions-15-value.less +2 -0
  60. package/test/less/errors/functions-15-value.txt +3 -0
  61. package/test/less/errors/functions-2-alpha.less +2 -0
  62. package/test/less/errors/functions-2-alpha.txt +3 -0
  63. package/test/less/errors/functions-3-assignment.less +2 -0
  64. package/test/less/errors/functions-3-assignment.txt +3 -0
  65. package/test/less/errors/functions-4-call.less +2 -0
  66. package/test/less/errors/functions-4-call.txt +3 -0
  67. package/test/less/errors/functions-5-color-2.less +1 -0
  68. package/test/less/errors/functions-5-color-2.txt +2 -0
  69. package/test/less/errors/functions-5-color.less +2 -0
  70. package/test/less/errors/functions-5-color.txt +3 -0
  71. package/test/less/errors/functions-6-condition.less +2 -0
  72. package/test/less/errors/functions-6-condition.txt +3 -0
  73. package/test/less/errors/functions-7-dimension.less +2 -0
  74. package/test/less/errors/functions-7-dimension.txt +3 -0
  75. package/test/less/errors/functions-8-element.less +2 -0
  76. package/test/less/errors/functions-8-element.txt +3 -0
  77. package/test/less/errors/functions-9-expression.less +2 -0
  78. package/test/less/errors/functions-9-expression.txt +3 -0
  79. package/test/less/errors/property-in-root.txt +1 -1
  80. package/test/less/errors/property-in-root2.txt +1 -1
  81. package/test/less/errors/property-in-root3.txt +1 -1
  82. package/test/less/errors/root-func-undefined-1.less +1 -0
  83. package/test/less/errors/root-func-undefined-1.txt +2 -0
  84. package/test/less/errors/root-func-undefined-2.less +2 -0
  85. package/test/less/errors/root-func-undefined-2.txt +3 -0
  86. package/test/less/extend-chaining.less +1 -1
  87. package/test/less/merge.less +4 -4
  88. package/test/less/mixins-guards.less +1 -1
  89. package/test/less/no-strict-math/mixins-guards.less +25 -0
  90. package/test/less/no-strict-math/no-sm-operations.less +4 -1
  91. package/test/less/operations.less +1 -1
  92. package/test/less/plugin/plugin-tree-nodes.js +80 -0
  93. package/test/less/plugin.less +8 -0
  94. package/test/less-bom/comments.less +1 -1
  95. package/test/less-bom/comments2.less +11 -0
  96. package/test/less-bom/errors/detached-ruleset-3.txt +1 -1
  97. package/test/less-bom/errors/functions-1.less +2 -0
  98. package/test/less-bom/errors/functions-1.txt +3 -0
  99. package/test/less-bom/errors/functions-10-keyword.less +2 -0
  100. package/test/less-bom/errors/functions-10-keyword.txt +3 -0
  101. package/test/less-bom/errors/functions-11-operation.less +2 -0
  102. package/test/less-bom/errors/functions-11-operation.txt +3 -0
  103. package/test/less-bom/errors/functions-12-quoted.less +2 -0
  104. package/test/less-bom/errors/functions-12-quoted.txt +3 -0
  105. package/test/less-bom/errors/functions-13-selector.less +2 -0
  106. package/test/less-bom/errors/functions-13-selector.txt +3 -0
  107. package/test/less-bom/errors/functions-14-url.less +2 -0
  108. package/test/less-bom/errors/functions-14-url.txt +3 -0
  109. package/test/less-bom/errors/functions-15-value.less +2 -0
  110. package/test/less-bom/errors/functions-15-value.txt +3 -0
  111. package/test/less-bom/errors/functions-2-alpha.less +2 -0
  112. package/test/less-bom/errors/functions-2-alpha.txt +3 -0
  113. package/test/less-bom/errors/functions-3-assignment.less +2 -0
  114. package/test/less-bom/errors/functions-3-assignment.txt +3 -0
  115. package/test/less-bom/errors/functions-4-call.less +2 -0
  116. package/test/less-bom/errors/functions-4-call.txt +3 -0
  117. package/test/less-bom/errors/functions-5-color-2.less +1 -0
  118. package/test/less-bom/errors/functions-5-color-2.txt +2 -0
  119. package/test/less-bom/errors/functions-5-color.less +2 -0
  120. package/test/less-bom/errors/functions-5-color.txt +3 -0
  121. package/test/less-bom/errors/functions-6-condition.less +2 -0
  122. package/test/less-bom/errors/functions-6-condition.txt +3 -0
  123. package/test/less-bom/errors/functions-7-dimension.less +2 -0
  124. package/test/less-bom/errors/functions-7-dimension.txt +3 -0
  125. package/test/less-bom/errors/functions-8-element.less +2 -0
  126. package/test/less-bom/errors/functions-8-element.txt +3 -0
  127. package/test/less-bom/errors/functions-9-expression.less +2 -0
  128. package/test/less-bom/errors/functions-9-expression.txt +3 -0
  129. package/test/less-bom/errors/property-in-root.txt +1 -1
  130. package/test/less-bom/errors/property-in-root2.txt +1 -1
  131. package/test/less-bom/errors/property-in-root3.txt +1 -1
  132. package/test/less-bom/errors/root-func-undefined-1.less +1 -0
  133. package/test/less-bom/errors/root-func-undefined-1.txt +2 -0
  134. package/test/less-bom/errors/root-func-undefined-2.less +2 -0
  135. package/test/less-bom/errors/root-func-undefined-2.txt +3 -0
  136. package/test/less-bom/extend-chaining.less +1 -1
  137. package/test/less-bom/merge.less +4 -4
  138. package/test/less-bom/mixins-guards.less +1 -1
  139. package/test/less-bom/no-strict-math/mixins-guards.less +25 -0
  140. package/test/less-bom/no-strict-math/no-sm-operations.less +4 -1
  141. package/test/less-bom/operations.less +1 -1
  142. package/test/less-bom/plugin/plugin-tree-nodes.js +80 -0
  143. package/test/less-bom/plugin.less +8 -0
  144. package/test/sourcemaps/maps/import-map.map +1 -0
@@ -14,6 +14,7 @@ var Ruleset = function (selectors, rules, strictImports, visibilityInfo) {
14
14
  this._lookups = {};
15
15
  this.strictImports = strictImports;
16
16
  this.copyVisibilityInfo(visibilityInfo);
17
+ this.allowRoot = true;
17
18
  };
18
19
  Ruleset.prototype = new Node();
19
20
  Ruleset.prototype.type = "Ruleset";
@@ -463,6 +464,91 @@ Ruleset.prototype.joinSelector = function (paths, context, selector) {
463
464
  return selector;
464
465
  }
465
466
 
467
+ // joins selector path from `beginningPath` with selector path in `addPath`
468
+ // `replacedElement` contains element that is being replaced by `addPath`
469
+ // returns concatenated path
470
+ function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) {
471
+ var newSelectorPath, lastSelector, newJoinedSelector;
472
+ // our new selector path
473
+ newSelectorPath = [];
474
+
475
+ //construct the joined selector - if & is the first thing this will be empty,
476
+ // if not newJoinedSelector will be the last set of elements in the selector
477
+ if (beginningPath.length > 0) {
478
+ newSelectorPath = beginningPath.slice(0);
479
+ lastSelector = newSelectorPath.pop();
480
+ newJoinedSelector = originalSelector.createDerived(lastSelector.elements.slice(0));
481
+ }
482
+ else {
483
+ newJoinedSelector = originalSelector.createDerived([]);
484
+ }
485
+
486
+ if (addPath.length > 0) {
487
+ // /deep/ is a combinator that is valid without anything in front of it
488
+ // so if the & does not have a combinator that is "" or " " then
489
+ // and there is a combinator on the parent, then grab that.
490
+ // this also allows + a { & .b { .a & { ... though not sure why you would want to do that
491
+ var combinator = replacedElement.combinator, parentEl = addPath[0].elements[0];
492
+ if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) {
493
+ combinator = parentEl.combinator;
494
+ }
495
+ // join the elements so far with the first part of the parent
496
+ newJoinedSelector.elements.push(new Element(combinator, parentEl.value, replacedElement.index, replacedElement.currentFileInfo));
497
+ newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1));
498
+ }
499
+
500
+ // now add the joined selector - but only if it is not empty
501
+ if (newJoinedSelector.elements.length !== 0) {
502
+ newSelectorPath.push(newJoinedSelector);
503
+ }
504
+
505
+ //put together the parent selectors after the join (e.g. the rest of the parent)
506
+ if (addPath.length > 1) {
507
+ var restOfPath = addPath.slice(1);
508
+ restOfPath = restOfPath.map(function (selector) {
509
+ return selector.createDerived(selector.elements, []);
510
+ });
511
+ newSelectorPath = newSelectorPath.concat(restOfPath);
512
+ }
513
+ return newSelectorPath;
514
+ }
515
+
516
+ // joins selector path from `beginningPath` with every selector path in `addPaths` array
517
+ // `replacedElement` contains element that is being replaced by `addPath`
518
+ // returns array with all concatenated paths
519
+ function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) {
520
+ var j;
521
+ for (j = 0; j < beginningPath.length; j++) {
522
+ var newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector);
523
+ result.push(newSelectorPath);
524
+ }
525
+ return result;
526
+ }
527
+
528
+ function mergeElementsOnToSelectors(elements, selectors) {
529
+ var i, sel;
530
+
531
+ if (elements.length === 0) {
532
+ return ;
533
+ }
534
+ if (selectors.length === 0) {
535
+ selectors.push([ new Selector(elements) ]);
536
+ return;
537
+ }
538
+
539
+ for (i = 0; i < selectors.length; i++) {
540
+ sel = selectors[i];
541
+
542
+ // if the previous thing in sel is a parent this needs to join on to it
543
+ if (sel.length > 0) {
544
+ sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
545
+ }
546
+ else {
547
+ sel.push(new Selector(elements));
548
+ }
549
+ }
550
+ }
551
+
466
552
  // replace all parent selectors inside `inSelector` by content of `context` array
467
553
  // resulting selectors are returned inside `paths` array
468
554
  // returns true if `inSelector` contained at least one parent selector
@@ -583,91 +669,6 @@ Ruleset.prototype.joinSelector = function (paths, context, selector) {
583
669
  return hadParentSelector;
584
670
  }
585
671
 
586
- // joins selector path from `beginningPath` with selector path in `addPath`
587
- // `replacedElement` contains element that is being replaced by `addPath`
588
- // returns concatenated path
589
- function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) {
590
- var newSelectorPath, lastSelector, newJoinedSelector;
591
- // our new selector path
592
- newSelectorPath = [];
593
-
594
- //construct the joined selector - if & is the first thing this will be empty,
595
- // if not newJoinedSelector will be the last set of elements in the selector
596
- if (beginningPath.length > 0) {
597
- newSelectorPath = beginningPath.slice(0);
598
- lastSelector = newSelectorPath.pop();
599
- newJoinedSelector = originalSelector.createDerived(lastSelector.elements.slice(0));
600
- }
601
- else {
602
- newJoinedSelector = originalSelector.createDerived([]);
603
- }
604
-
605
- if (addPath.length > 0) {
606
- // /deep/ is a combinator that is valid without anything in front of it
607
- // so if the & does not have a combinator that is "" or " " then
608
- // and there is a combinator on the parent, then grab that.
609
- // this also allows + a { & .b { .a & { ... though not sure why you would want to do that
610
- var combinator = replacedElement.combinator, parentEl = addPath[0].elements[0];
611
- if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) {
612
- combinator = parentEl.combinator;
613
- }
614
- // join the elements so far with the first part of the parent
615
- newJoinedSelector.elements.push(new Element(combinator, parentEl.value, replacedElement.index, replacedElement.currentFileInfo));
616
- newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1));
617
- }
618
-
619
- // now add the joined selector - but only if it is not empty
620
- if (newJoinedSelector.elements.length !== 0) {
621
- newSelectorPath.push(newJoinedSelector);
622
- }
623
-
624
- //put together the parent selectors after the join (e.g. the rest of the parent)
625
- if (addPath.length > 1) {
626
- var restOfPath = addPath.slice(1);
627
- restOfPath = restOfPath.map(function (selector) {
628
- return selector.createDerived(selector.elements, []);
629
- });
630
- newSelectorPath = newSelectorPath.concat(restOfPath);
631
- }
632
- return newSelectorPath;
633
- }
634
-
635
- // joins selector path from `beginningPath` with every selector path in `addPaths` array
636
- // `replacedElement` contains element that is being replaced by `addPath`
637
- // returns array with all concatenated paths
638
- function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) {
639
- var j;
640
- for (j = 0; j < beginningPath.length; j++) {
641
- var newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector);
642
- result.push(newSelectorPath);
643
- }
644
- return result;
645
- }
646
-
647
- function mergeElementsOnToSelectors(elements, selectors) {
648
- var i, sel;
649
-
650
- if (elements.length === 0) {
651
- return ;
652
- }
653
- if (selectors.length === 0) {
654
- selectors.push([ new Selector(elements) ]);
655
- return;
656
- }
657
-
658
- for (i = 0; i < selectors.length; i++) {
659
- sel = selectors[i];
660
-
661
- // if the previous thing in sel is a parent this needs to join on to it
662
- if (sel.length > 0) {
663
- sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
664
- }
665
- else {
666
- sel.push(new Selector(elements));
667
- }
668
- }
669
- }
670
-
671
672
  function deriveSelector(visibilityInfo, deriveFrom) {
672
673
  var newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition);
673
674
  newSelector.copyVisibilityInfo(visibilityInfo);
@@ -61,7 +61,7 @@ Unit.prototype.map = function(callback) {
61
61
  }
62
62
  };
63
63
  Unit.prototype.usedUnits = function() {
64
- var group, result = {}, mapUnit;
64
+ var group, result = {}, mapUnit, groupName;
65
65
 
66
66
  mapUnit = function (atomicUnit) {
67
67
  /*jshint loopfunc:true */
@@ -72,7 +72,7 @@ Unit.prototype.usedUnits = function() {
72
72
  return atomicUnit;
73
73
  };
74
74
 
75
- for (var groupName in unitConversions) {
75
+ for (groupName in unitConversions) {
76
76
  if (unitConversions.hasOwnProperty(groupName)) {
77
77
  group = unitConversions[groupName];
78
78
 
@@ -95,7 +95,7 @@ var ProcessExtendsVisitor = function() {
95
95
  ProcessExtendsVisitor.prototype = {
96
96
  run: function(root) {
97
97
  var extendFinder = new ExtendFinderVisitor();
98
- this.extendIndicies = {};
98
+ this.extendIndices = {};
99
99
  extendFinder.run(root);
100
100
  if (!extendFinder.foundExtends) { return root; }
101
101
  root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
@@ -105,7 +105,7 @@ ProcessExtendsVisitor.prototype = {
105
105
  return newRoot;
106
106
  },
107
107
  checkExtendsForNonMatched: function(extendList) {
108
- var indicies = this.extendIndicies;
108
+ var indices = this.extendIndices;
109
109
  extendList.filter(function(extend) {
110
110
  return !extend.hasFoundMatches && extend.parent_ids.length == 1;
111
111
  }).forEach(function(extend) {
@@ -115,8 +115,8 @@ ProcessExtendsVisitor.prototype = {
115
115
  }
116
116
  catch(_) {}
117
117
 
118
- if (!indicies[extend.index + ' ' + selector]) {
119
- indicies[extend.index + ' ' + selector] = true;
118
+ if (!indices[extend.index + ' ' + selector]) {
119
+ indices[extend.index + ' ' + selector] = true;
120
120
  logger.warn("extend '" + selector + "' has no matches");
121
121
  }
122
122
  });
@@ -140,7 +140,7 @@ ProcessExtendsVisitor.prototype = {
140
140
  // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
141
141
  // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one
142
142
  // and the second is the target.
143
- // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the
143
+ // the separation into two lists allows us to process a subset of chains with a bigger set, as is the
144
144
  // case when processing media queries
145
145
  for (extendIndex = 0; extendIndex < extendsList.length; extendIndex++) {
146
146
  for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) {
@@ -144,7 +144,6 @@ ToCSSVisitor.prototype = {
144
144
  } else {
145
145
  return this.visitDirectiveWithoutBody(directiveNode, visitArgs);
146
146
  }
147
- return directiveNode;
148
147
  },
149
148
 
150
149
  visitDirectiveWithBody: function(directiveNode, visitArgs) {
@@ -199,13 +198,24 @@ ToCSSVisitor.prototype = {
199
198
  return directiveNode;
200
199
  },
201
200
 
202
- checkPropertiesInRoot: function(rules) {
203
- var ruleNode;
201
+ checkValidNodes: function(rules, isRoot) {
202
+ if (!rules) {
203
+ return;
204
+ }
205
+
204
206
  for (var i = 0; i < rules.length; i++) {
205
- ruleNode = rules[i];
206
- if (ruleNode instanceof tree.Rule && !ruleNode.variable) {
207
- throw { message: "properties must be inside selector blocks, they cannot be in the root.",
208
- index: ruleNode.index, filename: ruleNode.currentFileInfo ? ruleNode.currentFileInfo.filename : null};
207
+ var ruleNode = rules[i];
208
+ if (isRoot && ruleNode instanceof tree.Rule && !ruleNode.variable) {
209
+ throw { message: "Properties must be inside selector blocks. They cannot be in the root",
210
+ index: ruleNode.index, filename: ruleNode.currentFileInfo && ruleNode.currentFileInfo.filename};
211
+ }
212
+ if (ruleNode instanceof tree.Call) {
213
+ throw { message: "Function '" + ruleNode.name + "' is undefined",
214
+ index: ruleNode.index, filename: ruleNode.currentFileInfo && ruleNode.currentFileInfo.filename};
215
+ }
216
+ if (ruleNode.type && !ruleNode.allowRoot) {
217
+ throw { message: ruleNode.type + " node returned by a function is not valid here",
218
+ index: ruleNode.index, filename: ruleNode.currentFileInfo && ruleNode.currentFileInfo.filename};
209
219
  }
210
220
  }
211
221
  },
@@ -213,9 +223,9 @@ ToCSSVisitor.prototype = {
213
223
  visitRuleset: function (rulesetNode, visitArgs) {
214
224
  //at this point rulesets are nested into each other
215
225
  var rule, rulesets = [];
216
- if (rulesetNode.firstRoot) {
217
- this.checkPropertiesInRoot(rulesetNode.rules);
218
- }
226
+
227
+ this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot);
228
+
219
229
  if (! rulesetNode.root) {
220
230
  //remove invisible paths
221
231
  this._compileRulesetPaths(rulesetNode);
@@ -104,16 +104,6 @@ module.exports = function(window, less, options) {
104
104
  }
105
105
  }
106
106
 
107
- function error(e, rootHref) {
108
- if (!options.errorReporting || options.errorReporting === "html") {
109
- errorHTML(e, rootHref);
110
- } else if (options.errorReporting === "console") {
111
- errorConsole(e, rootHref);
112
- } else if (typeof options.errorReporting === 'function') {
113
- options.errorReporting("add", e, rootHref);
114
- }
115
- }
116
-
117
107
  function removeErrorHTML(path) {
118
108
  var node = window.document.getElementById('less-error-message:' + utils.extractId(path));
119
109
  if (node) {
@@ -163,6 +153,16 @@ module.exports = function(window, less, options) {
163
153
  less.logger.error(content);
164
154
  }
165
155
 
156
+ function error(e, rootHref) {
157
+ if (!options.errorReporting || options.errorReporting === "html") {
158
+ errorHTML(e, rootHref);
159
+ } else if (options.errorReporting === "console") {
160
+ errorConsole(e, rootHref);
161
+ } else if (typeof options.errorReporting === 'function') {
162
+ options.errorReporting("add", e, rootHref);
163
+ }
164
+ }
165
+
166
166
  return {
167
167
  add: error,
168
168
  remove: removeError
@@ -225,34 +225,57 @@ module.exports = function(window, options) {
225
225
  fileManager.clearFileCache();
226
226
  }
227
227
  return new Promise(function (resolve, reject) {
228
- var startTime, endTime, totalMilliseconds;
228
+ var startTime, endTime, totalMilliseconds, remainingSheets;
229
229
  startTime = endTime = new Date();
230
230
 
231
- loadStyleSheets(function (e, css, _, sheet, webInfo) {
232
- if (e) {
233
- errors.add(e, e.href || sheet.href);
234
- reject(e);
235
- return;
236
- }
237
- if (webInfo.local) {
238
- less.logger.info("loading " + sheet.href + " from cache.");
239
- } else {
240
- less.logger.info("rendered " + sheet.href + " successfully.");
241
- }
242
- browser.createCSS(window.document, css, sheet);
243
- less.logger.info("css for " + sheet.href + " generated in " + (new Date() - endTime) + 'ms');
244
- if (webInfo.remaining === 0) {
245
- totalMilliseconds = new Date() - startTime;
246
- less.logger.info("less has finished. css generated in " + totalMilliseconds + 'ms');
247
- resolve({
248
- startTime: startTime,
249
- endTime: endTime,
250
- totalMilliseconds: totalMilliseconds,
251
- sheets: less.sheets.length
252
- });
253
- }
231
+ // Set counter for remaining unprocessed sheets
232
+ remainingSheets = less.sheets.length;
233
+
234
+ if (remainingSheets === 0) {
235
+
254
236
  endTime = new Date();
255
- }, reload, modifyVars);
237
+ totalMilliseconds = endTime - startTime;
238
+ less.logger.info("Less has finished and no sheets were loaded.");
239
+ resolve({
240
+ startTime: startTime,
241
+ endTime: endTime,
242
+ totalMilliseconds: totalMilliseconds,
243
+ sheets: less.sheets.length
244
+ });
245
+
246
+ } else {
247
+ // Relies on less.sheets array, callback seems to be guaranteed to be called for every element of the array
248
+ loadStyleSheets(function (e, css, _, sheet, webInfo) {
249
+ if (e) {
250
+ errors.add(e, e.href || sheet.href);
251
+ reject(e);
252
+ return;
253
+ }
254
+ if (webInfo.local) {
255
+ less.logger.info("Loading " + sheet.href + " from cache.");
256
+ } else {
257
+ less.logger.info("Rendered " + sheet.href + " successfully.");
258
+ }
259
+ browser.createCSS(window.document, css, sheet);
260
+ less.logger.info("CSS for " + sheet.href + " generated in " + (new Date() - endTime) + 'ms');
261
+
262
+ // Count completed sheet
263
+ remainingSheets--;
264
+
265
+ // Check if the last remaining sheet was processed and then call the promise
266
+ if (remainingSheets === 0) {
267
+ totalMilliseconds = new Date() - startTime;
268
+ less.logger.info("Less has finished. CSS generated in " + totalMilliseconds + 'ms');
269
+ resolve({
270
+ startTime: startTime,
271
+ endTime: endTime,
272
+ totalMilliseconds: totalMilliseconds,
273
+ sheets: less.sheets.length
274
+ });
275
+ }
276
+ endTime = new Date();
277
+ }, reload, modifyVars);
278
+ }
256
279
 
257
280
  loadStyles(modifyVars);
258
281
  });
@@ -38,7 +38,7 @@ FileManager.prototype.loadFile = function(filename, currentDirectory, options, e
38
38
  if (options.paths) { paths.push.apply(paths, options.paths); }
39
39
  if (!isAbsoluteFilename && paths.indexOf('.') === -1) { paths.push('.'); }
40
40
 
41
- // promise is guarenteed to be asyncronous
41
+ // promise is guaranteed to be asyncronous
42
42
  // which helps as it allows the file handle
43
43
  // to be closed before it continues with the next file
44
44
  return new PromiseConstructor(function(fulfill, reject) {
@@ -15,8 +15,8 @@ var lessc_helper = {
15
15
  'red' : [31, 39],
16
16
  'grey' : [90, 39]
17
17
  };
18
- return '\033[' + styles[style][0] + 'm' + str +
19
- '\033[' + styles[style][1] + 'm';
18
+ return '\x1b[' + styles[style][0] + 'm' + str +
19
+ '\x1b[' + styles[style][1] + 'm';
20
20
  },
21
21
 
22
22
  //Print command line options
@@ -1338,7 +1338,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
1338
1338
  /**
1339
1339
  * Returns the original source content. The only argument is the url of the
1340
1340
  * original source file. Returns null if no original source content is
1341
- * availible.
1341
+ * available.
1342
1342
  */
1343
1343
  SourceMapConsumer.prototype.sourceContentFor =
1344
1344
  function SourceMapConsumer_sourceContentFor(aSource) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "less",
3
- "version": "2.6.0",
3
+ "version": "2.7.2",
4
4
  "description": "Leaner CSS",
5
5
  "homepage": "http://lesscss.org",
6
6
  "author": {
@@ -17,6 +17,10 @@
17
17
  "type": "git",
18
18
  "url": "https://github.com/less/less.js.git"
19
19
  },
20
+ "master": {
21
+ "url": "https://github.com/less/less.js/blob/master/",
22
+ "raw": "https://raw.githubusercontent.com/less/less.js/master/"
23
+ },
20
24
  "license": "Apache-2.0",
21
25
  "bin": {
22
26
  "lessc": "./bin/lessc"
@@ -30,36 +34,37 @@
30
34
  },
31
35
  "browser": "./dist/less.js",
32
36
  "engines": {
33
- "node": ">=0.10.0"
37
+ "node": ">=0.12"
34
38
  },
35
39
  "scripts": {
36
40
  "test": "grunt test"
37
41
  },
38
42
  "optionalDependencies": {
39
43
  "errno": "^0.1.1",
40
- "graceful-fs": "^3.0.5",
41
- "image-size": "~0.3.5",
44
+ "graceful-fs": "^4.1.2",
45
+ "image-size": "~0.5.0",
42
46
  "mime": "^1.2.11",
43
47
  "mkdirp": "^0.5.0",
44
- "promise": "^6.0.1",
45
- "request": "^2.51.0",
46
- "source-map": "^0.4.2"
48
+ "promise": "^7.1.1",
49
+ "source-map": "^0.5.3",
50
+ "request": "^2.72.0"
47
51
  },
48
52
  "devDependencies": {
49
- "diff": "^1.0",
50
- "grunt": "^0.4.5",
51
- "grunt-browserify": "~3.5.0",
52
- "grunt-contrib-clean": "^0.6.0",
53
- "grunt-contrib-concat": "^0.5.0",
54
- "grunt-contrib-connect": "^0.9.0",
55
- "grunt-contrib-jasmine": "^0.8.2",
56
- "grunt-contrib-jshint": "^0.11.0",
57
- "grunt-contrib-uglify": "^0.8.0",
58
- "grunt-jscs": "^1.6.0",
59
- "grunt-saucelabs": "^8.3.2",
60
- "grunt-shell": "^1.1.1",
61
- "jit-grunt": "^0.9.1",
62
- "time-grunt": "^1.0.0"
53
+ "diff": "^2.2.2",
54
+ "grunt": "~0.4.5",
55
+ "grunt-browserify": "^5.0.0",
56
+ "grunt-contrib-clean": "^1.0.0",
57
+ "grunt-contrib-concat": "^1.0.1",
58
+ "grunt-contrib-connect": "^1.0.2",
59
+ "grunt-contrib-jasmine": "^1.0.3",
60
+ "grunt-contrib-jshint": "^1.0.0",
61
+ "grunt-contrib-uglify": "^1.0.1",
62
+ "grunt-jscs": "^2.8.0",
63
+ "grunt-saucelabs": "^8.6.2",
64
+ "grunt-shell": "^1.3.0",
65
+ "jit-grunt": "^0.10.0",
66
+ "phantomjs-prebuilt": "^2.1.7",
67
+ "time-grunt": "^1.3.0"
63
68
  },
64
69
  "keywords": [
65
70
  "compile less",
@@ -85,5 +90,7 @@
85
90
  "stylesheet",
86
91
  "variables in css",
87
92
  "css less"
88
- ]
93
+ ],
94
+ "rawcurrent": "https://raw.github.com/less/less.js/v",
95
+ "sourcearchive": "https://github.com/less/less.js/archive/v"
89
96
  }
@@ -6,19 +6,40 @@ jasmine.getEnv().addReporter(new jasmine.JSReporter2());
6
6
 
7
7
  var logMessages = [];
8
8
  window.less = window.less || {};
9
+
10
+ var logLevel_debug = 4,
11
+ logLevel_info = 3,
12
+ logLevel_warn = 2,
13
+ logLevel_error = 1;
14
+
15
+ // The amount of logging in the javascript console.
16
+ // 3 - Debug, information and errors
17
+ // 2 - Information and errors
18
+ // 1 - Errors
19
+ // 0 - None
20
+ // Defaults to 2
21
+
9
22
  less.loggers = [
10
23
  {
11
- info: function (msg) {
12
- logMessages.push(msg);
24
+ debug: function(msg) {
25
+ if (less.options.logLevel >= logLevel_debug) {
26
+ logMessages.push(msg);
27
+ }
13
28
  },
14
- debug: function (msg) {
15
- logMessages.push(msg);
29
+ info: function(msg) {
30
+ if (less.options.logLevel >= logLevel_info) {
31
+ logMessages.push(msg);
32
+ }
16
33
  },
17
- warn: function (msg) {
18
- logMessages.push(msg);
34
+ warn: function(msg) {
35
+ if (less.options.logLevel >= logLevel_warn) {
36
+ logMessages.push(msg);
37
+ }
19
38
  },
20
- error: function (msg) {
21
- logMessages.push(msg);
39
+ error: function(msg) {
40
+ if (less.options.logLevel >= logLevel_error) {
41
+ logMessages.push(msg);
42
+ }
22
43
  }
23
44
  }
24
45
  ];
@@ -1,2 +1,2 @@
1
- less: OperationError: Can't substract or divide a color from a number in {pathhref}console-errors/test-error.less on line null, column 0:
1
+ less: OperationError: Can't subtract or divide a color from a number in {pathhref}console-errors/test-error.less on line null, column 0:
2
2
  1 prop: (3 / #fff);