less 2.6.1 → 2.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/.travis.yml +3 -2
  2. package/CHANGELOG.md +26 -1
  3. package/Gruntfile.js +2 -3
  4. package/README.md +1 -1
  5. package/appveyor.yml +1 -0
  6. package/bin/lessc +47 -23
  7. package/dist/less.js +678 -374
  8. package/dist/less.min.js +9 -13
  9. package/lib/less/environment/abstract-file-manager.js +2 -2
  10. package/lib/less/functions/color.js +1 -1
  11. package/lib/less/index.js +1 -1
  12. package/lib/less/parser/parser-input.js +2 -2
  13. package/lib/less/parser/parser.js +45 -13
  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 +1 -0
  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 +1 -0
  26. package/lib/less/visitors/extend-visitor.js +5 -5
  27. package/lib/less/visitors/to-css-visitor.js +20 -10
  28. package/lib/less-browser/index.js +48 -25
  29. package/lib/less-node/file-manager.js +1 -1
  30. package/lib/less-node/lessc-helper.js +2 -2
  31. package/lib/source-map/source-map-0.1.31.js +1 -1
  32. package/package.json +25 -18
  33. package/test/browser/common.js +29 -8
  34. package/test/browser/less/console-errors/test-error.txt +1 -1
  35. package/test/browser/less.js +13 -17
  36. package/test/browser/runner-production-options.js +1 -1
  37. package/test/css/no-strict-math/no-sm-operations.css +3 -0
  38. package/test/css/operations.css +1 -1
  39. package/test/css/plugin.css +5 -0
  40. package/test/less/comments.less +1 -1
  41. package/test/less/errors/detached-ruleset-3.txt +1 -1
  42. package/test/less/errors/functions-1.less +2 -0
  43. package/test/less/errors/functions-1.txt +3 -0
  44. package/test/less/errors/functions-10-keyword.less +2 -0
  45. package/test/less/errors/functions-10-keyword.txt +3 -0
  46. package/test/less/errors/functions-11-operation.less +2 -0
  47. package/test/less/errors/functions-11-operation.txt +3 -0
  48. package/test/less/errors/functions-12-quoted.less +2 -0
  49. package/test/less/errors/functions-12-quoted.txt +3 -0
  50. package/test/less/errors/functions-13-selector.less +2 -0
  51. package/test/less/errors/functions-13-selector.txt +3 -0
  52. package/test/less/errors/functions-14-url.less +2 -0
  53. package/test/less/errors/functions-14-url.txt +3 -0
  54. package/test/less/errors/functions-15-value.less +2 -0
  55. package/test/less/errors/functions-15-value.txt +3 -0
  56. package/test/less/errors/functions-2-alpha.less +2 -0
  57. package/test/less/errors/functions-2-alpha.txt +3 -0
  58. package/test/less/errors/functions-3-assignment.less +2 -0
  59. package/test/less/errors/functions-3-assignment.txt +3 -0
  60. package/test/less/errors/functions-4-call.less +2 -0
  61. package/test/less/errors/functions-4-call.txt +3 -0
  62. package/test/less/errors/functions-5-color-2.less +1 -0
  63. package/test/less/errors/functions-5-color-2.txt +2 -0
  64. package/test/less/errors/functions-5-color.less +2 -0
  65. package/test/less/errors/functions-5-color.txt +3 -0
  66. package/test/less/errors/functions-6-condition.less +2 -0
  67. package/test/less/errors/functions-6-condition.txt +3 -0
  68. package/test/less/errors/functions-7-dimension.less +2 -0
  69. package/test/less/errors/functions-7-dimension.txt +3 -0
  70. package/test/less/errors/functions-8-element.less +2 -0
  71. package/test/less/errors/functions-8-element.txt +3 -0
  72. package/test/less/errors/functions-9-expression.less +2 -0
  73. package/test/less/errors/functions-9-expression.txt +3 -0
  74. package/test/less/errors/property-in-root.txt +1 -1
  75. package/test/less/errors/property-in-root2.txt +1 -1
  76. package/test/less/errors/property-in-root3.txt +1 -1
  77. package/test/less/errors/root-func-undefined-1.less +1 -0
  78. package/test/less/errors/root-func-undefined-1.txt +2 -0
  79. package/test/less/errors/root-func-undefined-2.less +2 -0
  80. package/test/less/errors/root-func-undefined-2.txt +3 -0
  81. package/test/less/extend-chaining.less +1 -1
  82. package/test/less/merge.less +4 -4
  83. package/test/less/mixins-guards.less +1 -1
  84. package/test/less/no-strict-math/no-sm-operations.less +4 -1
  85. package/test/less/operations.less +1 -1
  86. package/test/less/plugin/plugin-tree-nodes.js +80 -0
  87. package/test/less/plugin.less +8 -0
  88. package/test/less-bom/comments.less +1 -1
  89. package/test/less-bom/errors/detached-ruleset-3.txt +1 -1
  90. package/test/less-bom/errors/functions-1.less +2 -0
  91. package/test/less-bom/errors/functions-1.txt +3 -0
  92. package/test/less-bom/errors/functions-10-keyword.less +2 -0
  93. package/test/less-bom/errors/functions-10-keyword.txt +3 -0
  94. package/test/less-bom/errors/functions-11-operation.less +2 -0
  95. package/test/less-bom/errors/functions-11-operation.txt +3 -0
  96. package/test/less-bom/errors/functions-12-quoted.less +2 -0
  97. package/test/less-bom/errors/functions-12-quoted.txt +3 -0
  98. package/test/less-bom/errors/functions-13-selector.less +2 -0
  99. package/test/less-bom/errors/functions-13-selector.txt +3 -0
  100. package/test/less-bom/errors/functions-14-url.less +2 -0
  101. package/test/less-bom/errors/functions-14-url.txt +3 -0
  102. package/test/less-bom/errors/functions-15-value.less +2 -0
  103. package/test/less-bom/errors/functions-15-value.txt +3 -0
  104. package/test/less-bom/errors/functions-2-alpha.less +2 -0
  105. package/test/less-bom/errors/functions-2-alpha.txt +3 -0
  106. package/test/less-bom/errors/functions-3-assignment.less +2 -0
  107. package/test/less-bom/errors/functions-3-assignment.txt +3 -0
  108. package/test/less-bom/errors/functions-4-call.less +2 -0
  109. package/test/less-bom/errors/functions-4-call.txt +3 -0
  110. package/test/less-bom/errors/functions-5-color-2.less +1 -0
  111. package/test/less-bom/errors/functions-5-color-2.txt +2 -0
  112. package/test/less-bom/errors/functions-5-color.less +2 -0
  113. package/test/less-bom/errors/functions-5-color.txt +3 -0
  114. package/test/less-bom/errors/functions-6-condition.less +2 -0
  115. package/test/less-bom/errors/functions-6-condition.txt +3 -0
  116. package/test/less-bom/errors/functions-7-dimension.less +2 -0
  117. package/test/less-bom/errors/functions-7-dimension.txt +3 -0
  118. package/test/less-bom/errors/functions-8-element.less +2 -0
  119. package/test/less-bom/errors/functions-8-element.txt +3 -0
  120. package/test/less-bom/errors/functions-9-expression.less +2 -0
  121. package/test/less-bom/errors/functions-9-expression.txt +3 -0
  122. package/test/less-bom/errors/property-in-root.txt +1 -1
  123. package/test/less-bom/errors/property-in-root2.txt +1 -1
  124. package/test/less-bom/errors/property-in-root3.txt +1 -1
  125. package/test/less-bom/errors/root-func-undefined-1.less +1 -0
  126. package/test/less-bom/errors/root-func-undefined-1.txt +2 -0
  127. package/test/less-bom/errors/root-func-undefined-2.less +2 -0
  128. package/test/less-bom/errors/root-func-undefined-2.txt +3 -0
  129. package/test/less-bom/extend-chaining.less +1 -1
  130. package/test/less-bom/merge.less +4 -4
  131. package/test/less-bom/mixins-guards.less +1 -1
  132. package/test/less-bom/no-strict-math/no-sm-operations.less +4 -1
  133. package/test/less-bom/operations.less +1 -1
  134. package/test/less-bom/plugin/plugin-tree-nodes.js +80 -0
  135. package/test/less-bom/plugin.less +8 -0
@@ -67,13 +67,13 @@ abstractFileManager.prototype.pathDiff = function pathDiff(url, baseUrl) {
67
67
  };
68
68
  // helper function, not part of API
69
69
  abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, baseUrl) {
70
- // urlParts[1] = protocol&hostname || /
70
+ // urlParts[1] = protocol://hostname/ OR /
71
71
  // urlParts[2] = / if path relative to host base
72
72
  // urlParts[3] = directories
73
73
  // urlParts[4] = filename
74
74
  // urlParts[5] = parameters
75
75
 
76
- var urlPartsRegex = /^((?:[a-z-]+:)?\/+?(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i,
76
+ var urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i,
77
77
  urlParts = url.match(urlPartsRegex),
78
78
  returner = {}, directories = [], i, baseUrlParts;
79
79
 
@@ -237,7 +237,7 @@ colorFunctions = {
237
237
  return hsla(hsl);
238
238
  },
239
239
  //
240
- // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
240
+ // Copyright (c) 2006-2009 Hampton Catlin, Natalie Weizenbaum, and Chris Eppstein
241
241
  // http://sass-lang.com
242
242
  //
243
243
  mix: function (color1, color2, weight) {
package/lib/less/index.js CHANGED
@@ -2,7 +2,7 @@ module.exports = function(environment, fileManagers) {
2
2
  var SourceMapOutput, SourceMapBuilder, ParseTree, ImportManager, Environment;
3
3
 
4
4
  var less = {
5
- version: [2, 6, 1],
5
+ version: [2, 7, 3],
6
6
  data: require('./data'),
7
7
  tree: require('./tree'),
8
8
  Environment: (Environment = require("./environment/environment")),
@@ -40,7 +40,7 @@ module.exports = function() {
40
40
  nextNewLine = endIndex;
41
41
  }
42
42
  parserInput.i = nextNewLine;
43
- comment.text = inp.substr(comment.i, parserInput.i - comment.i);
43
+ comment.text = inp.substr(comment.index, parserInput.i - comment.index);
44
44
  parserInput.commentStore.push(comment);
45
45
  continue;
46
46
  } else if (nextChar === '*') {
@@ -217,7 +217,7 @@ module.exports = function() {
217
217
  input = str;
218
218
  parserInput.i = j = currentPos = furthest = 0;
219
219
 
220
- // chunking apparantly makes things quicker (but my tests indicate
220
+ // chunking apparently makes things quicker (but my tests indicate
221
221
  // it might actually make things slower in node at least)
222
222
  // and it is a non-perfect parse - it can't recognise
223
223
  // unquoted urls, meaning it can't distinguish comments
@@ -261,7 +261,7 @@ var Parser = function Parser(context, imports, fileInfo) {
261
261
  }
262
262
 
263
263
  node = mixin.definition() || this.rule() || this.ruleset() ||
264
- mixin.call() || this.rulesetCall() || this.directive();
264
+ mixin.call() || this.rulesetCall() || this.entities.call() || this.directive();
265
265
  if (node) {
266
266
  root.push(node);
267
267
  } else {
@@ -370,19 +370,51 @@ var Parser = function Parser(context, imports, fileInfo) {
370
370
  return new(tree.Call)(name, args, index, fileInfo);
371
371
  },
372
372
  arguments: function () {
373
- var args = [], arg;
373
+ var argsSemiColon = [], argsComma = [],
374
+ expressions = [],
375
+ isSemiColonSeparated, value, arg;
376
+
377
+ parserInput.save();
374
378
 
375
379
  while (true) {
376
- arg = this.assignment() || parsers.expression();
380
+
381
+ arg = parsers.detachedRuleset() || this.assignment() || parsers.expression();
382
+
377
383
  if (!arg) {
378
384
  break;
379
385
  }
380
- args.push(arg);
381
- if (! parserInput.$char(',')) {
382
- break;
386
+
387
+ value = arg;
388
+
389
+ if (arg.value && arg.value.length == 1) {
390
+ value = arg.value[0];
391
+ }
392
+
393
+ if (value) {
394
+ expressions.push(value);
395
+ }
396
+
397
+ argsComma.push(value);
398
+
399
+ if (parserInput.$char(',')) {
400
+ continue;
401
+ }
402
+
403
+ if (parserInput.$char(';') || isSemiColonSeparated) {
404
+
405
+ isSemiColonSeparated = true;
406
+
407
+ if (expressions.length > 1) {
408
+ value = new(tree.Value)(expressions);
409
+ }
410
+ argsSemiColon.push(value);
411
+
412
+ expressions = [];
383
413
  }
384
414
  }
385
- return args;
415
+
416
+ parserInput.forget();
417
+ return isSemiColonSeparated ? argsSemiColon : argsComma;
386
418
  },
387
419
  literal: function () {
388
420
  return this.dimension() ||
@@ -462,7 +494,7 @@ var Parser = function Parser(context, imports, fileInfo) {
462
494
  }
463
495
  },
464
496
 
465
- // A variable entity useing the protective {} e.g. @{var}
497
+ // A variable entity using the protective {} e.g. @{var}
466
498
  variableCurly: function () {
467
499
  var curly, index = parserInput.i;
468
500
 
@@ -497,7 +529,7 @@ var Parser = function Parser(context, imports, fileInfo) {
497
529
  parserInput.save();
498
530
  var autoCommentAbsorb = parserInput.autoCommentAbsorb;
499
531
  parserInput.autoCommentAbsorb = false;
500
- var k = parserInput.$re(/^[A-Za-z]+/);
532
+ var k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/);
501
533
  parserInput.autoCommentAbsorb = autoCommentAbsorb;
502
534
  if (!k) {
503
535
  parserInput.forget();
@@ -899,7 +931,7 @@ var Parser = function Parser(context, imports, fileInfo) {
899
931
  //
900
932
  // A Rule terminator. Note that we use `peek()` to check for '}',
901
933
  // because the `block` rule will be expecting it, but we still need to make sure
902
- // it's there, if ';' was ommitted.
934
+ // it's there, if ';' was omitted.
903
935
  //
904
936
  end: function () {
905
937
  return parserInput.$char(';') || parserInput.peek('}');
@@ -1321,10 +1353,10 @@ var Parser = function Parser(context, imports, fileInfo) {
1321
1353
  },
1322
1354
 
1323
1355
  media: function () {
1324
- var features, rules, media, debugInfo;
1356
+ var features, rules, media, debugInfo, index = parserInput.i;
1325
1357
 
1326
1358
  if (context.dumpLineNumbers) {
1327
- debugInfo = getDebugInfo(parserInput.i);
1359
+ debugInfo = getDebugInfo(index);
1328
1360
  }
1329
1361
 
1330
1362
  parserInput.save();
@@ -1340,7 +1372,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1340
1372
 
1341
1373
  parserInput.forget();
1342
1374
 
1343
- media = new(tree.Media)(rules, features, parserInput.i, fileInfo);
1375
+ media = new(tree.Media)(rules, features, index, fileInfo);
1344
1376
  if (context.dumpLineNumbers) {
1345
1377
  media.debugInfo = debugInfo;
1346
1378
  }
@@ -6,7 +6,7 @@ var Anonymous = function (value, index, currentFileInfo, mapLines, rulesetLike,
6
6
  this.mapLines = mapLines;
7
7
  this.currentFileInfo = currentFileInfo;
8
8
  this.rulesetLike = (typeof rulesetLike === 'undefined') ? false : rulesetLike;
9
-
9
+ this.allowRoot = true;
10
10
  this.copyVisibilityInfo(visibilityInfo);
11
11
  };
12
12
  Anonymous.prototype = new Node();
@@ -31,18 +31,21 @@ Call.prototype.eval = function (context) {
31
31
  var args = this.args.map(function (a) { return a.eval(context); }),
32
32
  result, funcCaller = new FunctionCaller(this.name, context, this.index, this.currentFileInfo);
33
33
 
34
- if (funcCaller.isValid()) { // 1.
34
+ if (funcCaller.isValid()) {
35
35
  try {
36
36
  result = funcCaller.call(args);
37
- if (result != null) {
38
- return result;
39
- }
40
37
  } catch (e) {
41
38
  throw { type: e.type || "Runtime",
42
39
  message: "error evaluating function `" + this.name + "`" +
43
40
  (e.message ? ': ' + e.message : ''),
44
41
  index: this.index, filename: this.currentFileInfo.filename };
45
42
  }
43
+
44
+ if (result != null) {
45
+ result.index = this.index;
46
+ result.currentFileInfo = this.currentFileInfo;
47
+ return result;
48
+ }
46
49
  }
47
50
 
48
51
  return new Call(this.name, args, this.index, this.currentFileInfo);
@@ -4,7 +4,9 @@ var Node = require("./node"),
4
4
  var Comment = function (value, isLineComment, index, currentFileInfo) {
5
5
  this.value = value;
6
6
  this.isLineComment = isLineComment;
7
+ this.index = index;
7
8
  this.currentFileInfo = currentFileInfo;
9
+ this.allowRoot = true;
8
10
  };
9
11
  Comment.prototype = new Node();
10
12
  Comment.prototype.type = "Comment";
@@ -23,6 +23,7 @@ var Directive = function (name, value, rules, index, currentFileInfo, debugInfo,
23
23
  this.debugInfo = debugInfo;
24
24
  this.isRooted = isRooted || false;
25
25
  this.copyVisibilityInfo(visibilityInfo);
26
+ this.allowRoot = true;
26
27
  };
27
28
 
28
29
  Directive.prototype = new Node();
@@ -9,6 +9,7 @@ var Extend = function Extend(selector, option, index, currentFileInfo, visibilit
9
9
  this.parent_ids = [this.object_id];
10
10
  this.currentFileInfo = currentFileInfo || {};
11
11
  this.copyVisibilityInfo(visibilityInfo);
12
+ this.allowRoot = true;
12
13
 
13
14
  switch(option) {
14
15
  case "all":
@@ -23,6 +23,7 @@ var Import = function (path, features, options, index, currentFileInfo, visibili
23
23
  this.path = path;
24
24
  this.features = features;
25
25
  this.currentFileInfo = currentFileInfo;
26
+ this.allowRoot = true;
26
27
 
27
28
  if (this.options.less !== undefined || this.options.inline) {
28
29
  this.css = !this.options.less || this.options.inline;
@@ -15,6 +15,7 @@ var Media = function (value, features, index, currentFileInfo, visibilityInfo) {
15
15
  this.rules = [new Ruleset(selectors, value)];
16
16
  this.rules[0].allowImports = true;
17
17
  this.copyVisibilityInfo(visibilityInfo);
18
+ this.allowRoot = true;
18
19
  };
19
20
  Media.prototype = new Directive();
20
21
  Media.prototype.type = "Media";
@@ -9,6 +9,7 @@ var MixinCall = function (elements, args, index, currentFileInfo, important) {
9
9
  this.index = index;
10
10
  this.currentFileInfo = currentFileInfo;
11
11
  this.important = important;
12
+ this.allowRoot = true;
12
13
  };
13
14
  MixinCall.prototype = new Node();
14
15
  MixinCall.prototype.type = "MixinCall";
@@ -27,6 +27,7 @@ var Definition = function (name, params, rules, condition, variadic, frames, vis
27
27
  this.optionalParameters = optionalParameters;
28
28
  this.frames = frames;
29
29
  this.copyVisibilityInfo(visibilityInfo);
30
+ this.allowRoot = true;
30
31
  };
31
32
  Definition.prototype = new Ruleset();
32
33
  Definition.prototype.type = "MixinDefinition";
@@ -12,6 +12,7 @@ var Rule = function (name, value, important, merge, index, currentFileInfo, inli
12
12
  this.inline = inline || false;
13
13
  this.variable = (variable !== undefined) ? variable
14
14
  : (name.charAt && (name.charAt(0) === '@'));
15
+ this.allowRoot = true;
15
16
  };
16
17
 
17
18
  function evalName(context, name) {
@@ -3,6 +3,7 @@ var Node = require("./node"),
3
3
 
4
4
  var RulesetCall = function (variable) {
5
5
  this.variable = variable;
6
+ this.allowRoot = true;
6
7
  };
7
8
  RulesetCall.prototype = new Node();
8
9
  RulesetCall.prototype.type = "RulesetCall";
@@ -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";
@@ -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);
@@ -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.1",
3
+ "version": "2.7.3",
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,7 +34,7 @@
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"
@@ -38,28 +42,29 @@
38
42
  "optionalDependencies": {
39
43
  "errno": "^0.1.1",
40
44
  "graceful-fs": "^4.1.2",
41
- "image-size": "~0.4.0",
45
+ "image-size": "~0.5.0",
42
46
  "mime": "^1.2.11",
43
47
  "mkdirp": "^0.5.0",
44
48
  "promise": "^7.1.1",
45
- "request": "^2.51.0",
46
- "source-map": "^0.5.3"
49
+ "source-map": "^0.5.3",
50
+ "request": "2.81.0"
47
51
  },
48
52
  "devDependencies": {
49
- "diff": "^2.2.1",
50
- "grunt": "^0.4.5",
53
+ "diff": "^2.2.2",
54
+ "grunt": "~0.4.5",
55
+ "grunt-browserify": "^5.0.0",
51
56
  "grunt-contrib-clean": "^1.0.0",
52
- "grunt-contrib-concat": "^1.0.0",
53
- "grunt-contrib-connect": "^0.11.2",
54
- "grunt-contrib-jasmine": "^1.0.0",
57
+ "grunt-contrib-concat": "^1.0.1",
58
+ "grunt-contrib-connect": "^1.0.2",
59
+ "grunt-contrib-jasmine": "^1.0.3",
55
60
  "grunt-contrib-jshint": "^1.0.0",
56
- "grunt-contrib-uglify": "^0.11.0",
57
- "grunt-jscs": "^2.7.0",
58
- "grunt-shell": "^1.1.1",
59
- "grunt-browserify": "~4.0.1",
60
- "jit-grunt": "^0.9.1",
61
- "time-grunt": "^1.0.0",
62
- "grunt-saucelabs": "^8.3.2"
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);