less 3.6.0 → 3.8.1

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 (142) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/Gruntfile.js +43 -6
  3. package/bin/lessc +32 -3
  4. package/dist/less.js +2810 -326
  5. package/dist/less.min.js +7 -7
  6. package/lib/less/constants.js +13 -0
  7. package/lib/less/contexts.js +45 -10
  8. package/lib/less/default-options.js +12 -4
  9. package/lib/less/functions/color.js +84 -41
  10. package/lib/less/functions/data-uri.js +1 -1
  11. package/lib/less/functions/index.js +1 -0
  12. package/lib/less/functions/list.js +101 -0
  13. package/lib/less/functions/types.js +1 -19
  14. package/lib/less/import-manager.js +3 -3
  15. package/lib/less/index.js +1 -1
  16. package/lib/less/parse.js +3 -3
  17. package/lib/less/parser/parser.js +31 -13
  18. package/lib/less/render.js +2 -2
  19. package/lib/less/source-map-output.js +2 -2
  20. package/lib/less/tree/color.js +58 -18
  21. package/lib/less/tree/declaration.js +11 -7
  22. package/lib/less/tree/expression.js +7 -3
  23. package/lib/less/tree/import.js +9 -8
  24. package/lib/less/tree/mixin-definition.js +1 -1
  25. package/lib/less/tree/operation.js +10 -4
  26. package/lib/less/tree/url.js +12 -8
  27. package/lib/less/utils.js +54 -19
  28. package/lib/less-browser/add-default-options.js +3 -3
  29. package/lib/less-browser/index.js +9 -2
  30. package/lib/less-node/image-size.js +1 -1
  31. package/lib/less-node/lessc-helper.js +12 -4
  32. package/package.json +5 -2
  33. package/test/browser/css/rewrite-urls/urls.css +36 -0
  34. package/test/browser/css/rootpath-rewrite-urls/urls.css +35 -0
  35. package/test/browser/less/rewrite-urls/urls.less +34 -0
  36. package/test/browser/less/rootpath-rewrite-urls/urls.less +33 -0
  37. package/test/browser/less.js +2810 -326
  38. package/test/browser/runner-browser-options.js +1 -1
  39. package/test/browser/runner-errors-options.js +1 -1
  40. package/test/browser/runner-legacy-options.js +1 -1
  41. package/test/browser/runner-rewrite-urls-options.js +3 -0
  42. package/test/browser/runner-rewrite-urls-spec.js +3 -0
  43. package/test/browser/runner-rootpath-relative-spec.js +1 -1
  44. package/test/browser/runner-rootpath-rewrite-urls-options.js +4 -0
  45. package/test/browser/runner-rootpath-rewrite-urls-spec.js +3 -0
  46. package/test/css/calc.css +2 -2
  47. package/test/css/colors.css +20 -3
  48. package/test/css/css-3.css +0 -8
  49. package/test/css/css-escapes.css +3 -0
  50. package/test/css/functions-each.css +48 -0
  51. package/test/css/functions.css +6 -4
  52. package/test/css/math/parens-division/media-math.css +10 -0
  53. package/test/css/math/parens-division/mixins-args.css +169 -0
  54. package/test/css/math/parens-division/new-division.css +16 -0
  55. package/test/css/math/parens-division/parens.css +37 -0
  56. package/test/css/math/strict/css.css +95 -0
  57. package/test/css/math/strict/media-math.css +10 -0
  58. package/test/css/math/strict/mixins-args.css +169 -0
  59. package/test/css/math/strict/parens.css +37 -0
  60. package/test/css/{strict-math → math/strict-legacy}/css.css +0 -0
  61. package/test/css/math/strict-legacy/media-math.css +10 -0
  62. package/test/css/{strict-math → math/strict-legacy}/mixins-args.css +0 -0
  63. package/test/css/{strict-math → math/strict-legacy}/parens.css +5 -1
  64. package/test/css/no-strict-math/no-sm-operations.css +3 -0
  65. package/test/css/rewrite-urls-all/rewrite-urls-all.css +17 -0
  66. package/test/css/rewrite-urls-local/rewrite-urls-local.css +17 -0
  67. package/test/css/rootpath-rewrite-urls-all/rootpath-rewrite-urls-all.css +17 -0
  68. package/test/css/rootpath-rewrite-urls-local/rootpath-rewrite-urls-local.css +17 -0
  69. package/test/css/static-urls/urls.css +2 -2
  70. package/test/css/urls.css +2 -2
  71. package/test/index.js +28 -15
  72. package/test/less/colors.less +18 -0
  73. package/test/less/css-3.less +0 -9
  74. package/test/less/css-escapes.less +4 -0
  75. package/test/less/errors/color-func-invalid-color.txt +1 -1
  76. package/test/less/errors/mixin-not-defined-2.less +7 -0
  77. package/test/less/errors/mixin-not-defined-2.txt +4 -0
  78. package/test/less/functions-each.less +81 -0
  79. package/test/less/functions.less +14 -2
  80. package/test/less/math/parens-division/media-math.less +9 -0
  81. package/test/less/math/parens-division/mixins-args.less +264 -0
  82. package/test/less/math/parens-division/new-division.less +17 -0
  83. package/test/less/{strict-math → math/parens-division}/parens.less +2 -1
  84. package/test/less/math/strict/css.less +108 -0
  85. package/test/less/math/strict/media-math.less +9 -0
  86. package/test/less/math/strict/mixins-args.less +264 -0
  87. package/test/less/math/strict/parens.less +46 -0
  88. package/test/less/{strict-math → math/strict-legacy}/css.less +0 -0
  89. package/test/less/math/strict-legacy/media-math.less +9 -0
  90. package/test/less/{strict-math → math/strict-legacy}/mixins-args.less +0 -0
  91. package/test/less/math/strict-legacy/parens.less +50 -0
  92. package/test/less/no-strict-math/no-sm-operations.less +3 -0
  93. package/test/less/rewrite-urls-all/folder/file.less +8 -0
  94. package/test/less/rewrite-urls-all/rewrite-urls-all.less +11 -0
  95. package/test/less/rewrite-urls-local/folder/file.less +8 -0
  96. package/test/less/rewrite-urls-local/rewrite-urls-local.less +11 -0
  97. package/test/less/rootpath-rewrite-urls-all/folder/file.less +8 -0
  98. package/test/less/rootpath-rewrite-urls-all/rootpath-rewrite-urls-all.less +11 -0
  99. package/test/less/rootpath-rewrite-urls-local/folder/file.less +8 -0
  100. package/test/less/rootpath-rewrite-urls-local/rootpath-rewrite-urls-local.less +11 -0
  101. package/test/less/sourcemaps/custom-props.less +8 -0
  102. package/test/less-bom/colors.less +18 -0
  103. package/test/less-bom/css-3.less +0 -9
  104. package/test/less-bom/css-escapes.less +4 -0
  105. package/test/less-bom/errors/color-func-invalid-color.txt +1 -1
  106. package/test/less-bom/errors/mixin-not-defined-2.less +7 -0
  107. package/test/less-bom/errors/mixin-not-defined-2.txt +4 -0
  108. package/test/less-bom/functions-each.less +81 -0
  109. package/test/less-bom/functions.less +14 -2
  110. package/test/less-bom/math/parens-division/media-math.less +9 -0
  111. package/test/less-bom/math/parens-division/mixins-args.less +264 -0
  112. package/test/less-bom/math/parens-division/new-division.less +17 -0
  113. package/test/less-bom/{strict-math → math/parens-division}/parens.less +2 -1
  114. package/test/less-bom/math/strict/css.less +108 -0
  115. package/test/less-bom/math/strict/media-math.less +9 -0
  116. package/test/less-bom/math/strict/mixins-args.less +264 -0
  117. package/test/less-bom/math/strict/parens.less +46 -0
  118. package/test/less-bom/{strict-math → math/strict-legacy}/css.less +0 -0
  119. package/test/less-bom/math/strict-legacy/media-math.less +9 -0
  120. package/test/less-bom/{strict-math → math/strict-legacy}/mixins-args.less +0 -0
  121. package/test/less-bom/math/strict-legacy/parens.less +50 -0
  122. package/test/less-bom/no-strict-math/no-sm-operations.less +3 -0
  123. package/test/less-bom/rewrite-urls-all/folder/file.less +8 -0
  124. package/test/less-bom/rewrite-urls-all/rewrite-urls-all.less +11 -0
  125. package/test/less-bom/rewrite-urls-local/folder/file.less +8 -0
  126. package/test/less-bom/rewrite-urls-local/rewrite-urls-local.less +11 -0
  127. package/test/less-bom/rootpath-rewrite-urls-all/folder/file.less +8 -0
  128. package/test/less-bom/rootpath-rewrite-urls-all/rootpath-rewrite-urls-all.less +11 -0
  129. package/test/less-bom/rootpath-rewrite-urls-local/folder/file.less +8 -0
  130. package/test/less-bom/rootpath-rewrite-urls-local/rootpath-rewrite-urls-local.less +11 -0
  131. package/test/less-bom/sourcemaps/custom-props.less +8 -0
  132. package/test/less-test.js +26 -12
  133. package/test/sourcemaps/custom-props.json +1 -0
  134. package/.npmignore +0 -8
  135. package/test/less/errors/color-invalid-hex-code.less +0 -4
  136. package/test/less/errors/color-invalid-hex-code.txt +0 -4
  137. package/test/less/errors/color-invalid-hex-code2.less +0 -4
  138. package/test/less/errors/color-invalid-hex-code2.txt +0 -4
  139. package/test/less-bom/errors/color-invalid-hex-code.less +0 -4
  140. package/test/less-bom/errors/color-invalid-hex-code.txt +0 -4
  141. package/test/less-bom/errors/color-invalid-hex-code2.less +0 -4
  142. package/test/less-bom/errors/color-invalid-hex-code2.txt +0 -4
@@ -636,15 +636,8 @@ var Parser = function Parser(context, imports, fileInfo) {
636
636
  color: function () {
637
637
  var rgb;
638
638
 
639
- if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
640
- // strip colons, brackets, whitespaces and other characters that should not
641
- // definitely be part of color string
642
- var colorCandidateString = rgb.input.match(/^#([\w]+).*/);
643
- colorCandidateString = colorCandidateString[1];
644
- if (!colorCandidateString.match(/^[A-Fa-f0-9]+$/)) { // verify if candidate consists only of allowed HEX characters
645
- error('Invalid HEX color code');
646
- }
647
- return new(tree.Color)(rgb[1], undefined, '#' + colorCandidateString);
639
+ if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})/))) {
640
+ return new(tree.Color)(rgb[1], undefined, rgb[0]);
648
641
  }
649
642
  },
650
643
 
@@ -931,7 +924,7 @@ var Parser = function Parser(context, imports, fileInfo) {
931
924
  returner = { args:null, variadic: false },
932
925
  expressions = [], argsSemiColon = [], argsComma = [],
933
926
  isSemiColonSeparated, expressionContainsNamed, name, nameLoop,
934
- value, arg, expand;
927
+ value, arg, expand, hasSep = true;
935
928
 
936
929
  parserInput.save();
937
930
 
@@ -952,7 +945,7 @@ var Parser = function Parser(context, imports, fileInfo) {
952
945
  arg = entities.variable() || entities.property() || entities.literal() || entities.keyword() || this.call(true);
953
946
  }
954
947
 
955
- if (!arg) {
948
+ if (!arg || !hasSep) {
956
949
  break;
957
950
  }
958
951
 
@@ -1018,10 +1011,12 @@ var Parser = function Parser(context, imports, fileInfo) {
1018
1011
  argsComma.push({ name:nameLoop, value:value, expand:expand });
1019
1012
 
1020
1013
  if (parserInput.$char(',')) {
1014
+ hasSep = true;
1021
1015
  continue;
1022
1016
  }
1017
+ hasSep = parserInput.$char(';') === ';';
1023
1018
 
1024
- if (parserInput.$char(';') || isSemiColonSeparated) {
1019
+ if (hasSep || isSemiColonSeparated) {
1025
1020
 
1026
1021
  if (expressionContainsNamed) {
1027
1022
  error('Cannot mix ; and , as delimiter types');
@@ -1377,10 +1372,33 @@ var Parser = function Parser(context, imports, fileInfo) {
1377
1372
  },
1378
1373
 
1379
1374
  detachedRuleset: function() {
1375
+ var argInfo, params, variadic;
1376
+
1377
+ parserInput.save();
1378
+ if (parserInput.$re(/^[.#]\(/)) {
1379
+ /**
1380
+ * DR args currently only implemented for each() function, and not
1381
+ * yet settable as `@dr: #(@arg) {}`
1382
+ * This should be done when DRs are merged with mixins.
1383
+ * See: https://github.com/less/less-meta/issues/16
1384
+ */
1385
+ argInfo = this.mixin.args(false);
1386
+ params = argInfo.args;
1387
+ variadic = argInfo.variadic;
1388
+ if (!parserInput.$char(')')) {
1389
+ parserInput.restore();
1390
+ return;
1391
+ }
1392
+ }
1380
1393
  var blockRuleset = this.blockRuleset();
1381
1394
  if (blockRuleset) {
1395
+ parserInput.forget();
1396
+ if (params) {
1397
+ return new tree.mixin.Definition(null, params, blockRuleset, null, variadic);
1398
+ }
1382
1399
  return new tree.DetachedRuleset(blockRuleset);
1383
1400
  }
1401
+ parserInput.restore();
1384
1402
  },
1385
1403
 
1386
1404
  //
@@ -1922,7 +1940,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1922
1940
 
1923
1941
  parserInput.save();
1924
1942
 
1925
- op = parserInput.$char('/') || parserInput.$char('*');
1943
+ op = parserInput.$char('/') || parserInput.$char('*') || parserInput.$str('./');
1926
1944
 
1927
1945
  if (!op) { parserInput.forget(); break; }
1928
1946
 
@@ -5,10 +5,10 @@ module.exports = function(environment, ParseTree, ImportManager) {
5
5
  var render = function (input, options, callback) {
6
6
  if (typeof options === 'function') {
7
7
  callback = options;
8
- options = utils.defaults(this.options, {});
8
+ options = utils.copyOptions(this.options, {});
9
9
  }
10
10
  else {
11
- options = utils.defaults(this.options, options || {});
11
+ options = utils.copyOptions(this.options, options || {});
12
12
  }
13
13
 
14
14
  if (!callback) {
@@ -58,7 +58,7 @@ module.exports = function (environment) {
58
58
  sourceColumns,
59
59
  i;
60
60
 
61
- if (fileInfo) {
61
+ if (fileInfo && fileInfo.filename) {
62
62
  var inputSource = this._contentsMap[fileInfo.filename];
63
63
 
64
64
  // remove vars/banner added to the top of the file
@@ -77,7 +77,7 @@ module.exports = function (environment) {
77
77
  lines = chunk.split('\n');
78
78
  columns = lines[lines.length - 1];
79
79
 
80
- if (fileInfo) {
80
+ if (fileInfo && fileInfo.filename) {
81
81
  if (!mapLines) {
82
82
  this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column},
83
83
  original: { line: sourceLines.length, column: sourceColumns.length},
@@ -5,6 +5,7 @@ var Node = require('./node'),
5
5
  // RGB Colors - #ff0014, #eee
6
6
  //
7
7
  var Color = function (rgb, a, originalForm) {
8
+ var self = this;
8
9
  //
9
10
  // The end goal here, is to parse the arguments
10
11
  // into an integer triplet, such as `128, 255, 0`
@@ -13,16 +14,26 @@ var Color = function (rgb, a, originalForm) {
13
14
  //
14
15
  if (Array.isArray(rgb)) {
15
16
  this.rgb = rgb;
16
- } else if (rgb.length == 6) {
17
- this.rgb = rgb.match(/.{2}/g).map(function (c) {
18
- return parseInt(c, 16);
17
+ } else if (rgb.length >= 6) {
18
+ this.rgb = [];
19
+ rgb.match(/.{2}/g).map(function (c, i) {
20
+ if (i < 3) {
21
+ self.rgb.push(parseInt(c, 16));
22
+ } else {
23
+ self.alpha = (parseInt(c, 16)) / 255;
24
+ }
19
25
  });
20
26
  } else {
21
- this.rgb = rgb.split('').map(function (c) {
22
- return parseInt(c + c, 16);
27
+ this.rgb = [];
28
+ rgb.split('').map(function (c, i) {
29
+ if (i < 3) {
30
+ self.rgb.push(parseInt(c + c, 16));
31
+ } else {
32
+ self.alpha = (parseInt(c + c, 16)) / 255;
33
+ }
23
34
  });
24
35
  }
25
- this.alpha = typeof a === 'number' ? a : 1;
36
+ this.alpha = this.alpha || (typeof a === 'number' ? a : 1);
26
37
  if (typeof originalForm !== 'undefined') {
27
38
  this.value = originalForm;
28
39
  }
@@ -57,25 +68,54 @@ Color.prototype.genCSS = function (context, output) {
57
68
  output.add(this.toCSS(context));
58
69
  };
59
70
  Color.prototype.toCSS = function (context, doNotCompress) {
60
- var compress = context && context.compress && !doNotCompress, color, alpha;
71
+ var compress = context && context.compress && !doNotCompress, color, alpha,
72
+ colorFunction, args = [];
61
73
 
62
74
  // `value` is set if this color was originally
63
75
  // converted from a named color string so we need
64
76
  // to respect this and try to output named color too.
77
+ alpha = this.fround(context, this.alpha);
78
+
65
79
  if (this.value) {
66
- return this.value;
80
+ if (this.value.indexOf('rgb') === 0) {
81
+ if (alpha < 1) {
82
+ colorFunction = 'rgba';
83
+ }
84
+ } else if (this.value.indexOf('hsl') === 0) {
85
+ if (alpha < 1) {
86
+ colorFunction = 'hsla';
87
+ } else {
88
+ colorFunction = 'hsl';
89
+ }
90
+ } else {
91
+ return this.value;
92
+ }
93
+ } else {
94
+ if (alpha < 1) {
95
+ colorFunction = 'rgba';
96
+ }
67
97
  }
68
98
 
69
- // If we have some transparency, the only way to represent it
70
- // is via `rgba`. Otherwise, we use the hex representation,
71
- // which has better compatibility with older browsers.
72
- // Values are capped between `0` and `255`, rounded and zero-padded.
73
- alpha = this.fround(context, this.alpha);
74
- if (alpha < 1) {
75
- return 'rgba(' + this.rgb.map(function (c) {
76
- return clamp(Math.round(c), 255);
77
- }).concat(clamp(alpha, 1))
78
- .join(',' + (compress ? '' : ' ')) + ')';
99
+ switch (colorFunction) {
100
+ case 'rgba':
101
+ args = this.rgb.map(function (c) {
102
+ return clamp(Math.round(c), 255);
103
+ }).concat(clamp(alpha, 1));
104
+ break;
105
+ case 'hsla':
106
+ args.push(clamp(alpha, 1));
107
+ case 'hsl':
108
+ color = this.toHSL();
109
+ args = [
110
+ this.fround(context, color.h),
111
+ this.fround(context, color.s * 100) + '%',
112
+ this.fround(context, color.l * 100) + '%'
113
+ ].concat(args);
114
+ }
115
+
116
+ if (colorFunction) {
117
+ // Values are capped between `0` and `255`, rounded and zero-padded.
118
+ return colorFunction + '(' + args.join(',' + (compress ? '' : ' ')) + ')';
79
119
  }
80
120
 
81
121
  color = this.toRGB();
@@ -1,7 +1,8 @@
1
1
  var Node = require('./node'),
2
2
  Value = require('./value'),
3
3
  Keyword = require('./keyword'),
4
- Anonymous = require('./anonymous');
4
+ Anonymous = require('./anonymous'),
5
+ MATH = require('../constants').Math;
5
6
 
6
7
  var Declaration = function (name, value, important, merge, index, currentFileInfo, inline, variable) {
7
8
  this.name = name;
@@ -41,7 +42,7 @@ Declaration.prototype.genCSS = function (context, output) {
41
42
  output.add(this.important + ((this.inline || (context.lastRule && context.compress)) ? '' : ';'), this._fileInfo, this._index);
42
43
  };
43
44
  Declaration.prototype.eval = function (context) {
44
- var strictMathBypass = false, name = this.name, evaldValue, variable = this.variable;
45
+ var mathBypass = false, prevMath, name = this.name, evaldValue, variable = this.variable;
45
46
  if (typeof name !== 'string') {
46
47
  // expand 'primitive' name directly to get
47
48
  // things faster (~10% for benchmark.less):
@@ -49,9 +50,12 @@ Declaration.prototype.eval = function (context) {
49
50
  name[0].value : evalName(context, name);
50
51
  variable = false; // never treat expanded interpolation as new variable name
51
52
  }
52
- if (name === 'font' && !context.strictMath) {
53
- strictMathBypass = true;
54
- context.strictMath = true;
53
+
54
+ // @todo remove when parens-division is default
55
+ if (name === 'font' && context.math === MATH.ALWAYS) {
56
+ mathBypass = true;
57
+ prevMath = context.math;
58
+ context.math = MATH.PARENS_DIVISION;
55
59
  }
56
60
  try {
57
61
  context.importantScope.push({});
@@ -82,8 +86,8 @@ Declaration.prototype.eval = function (context) {
82
86
  throw e;
83
87
  }
84
88
  finally {
85
- if (strictMathBypass) {
86
- context.strictMath = false;
89
+ if (mathBypass) {
90
+ context.math = prevMath;
87
91
  }
88
92
  }
89
93
  };
@@ -1,6 +1,8 @@
1
1
  var Node = require('./node'),
2
2
  Paren = require('./paren'),
3
- Comment = require('./comment');
3
+ Comment = require('./comment'),
4
+ Dimension = require('./dimension'),
5
+ MATH = require('../constants').Math;
4
6
 
5
7
  var Expression = function (value, noSpacing) {
6
8
  this.value = value;
@@ -17,7 +19,8 @@ Expression.prototype.accept = function (visitor) {
17
19
  Expression.prototype.eval = function (context) {
18
20
  var returnValue,
19
21
  mathOn = context.isMathOn(),
20
- inParenthesis = this.parens && !this.parensInOp,
22
+ inParenthesis = this.parens &&
23
+ (context.math !== MATH.STRICT_LEGACY || !this.parensInOp),
21
24
  doubleParen = false;
22
25
  if (inParenthesis) {
23
26
  context.inParenthesis();
@@ -40,7 +43,8 @@ Expression.prototype.eval = function (context) {
40
43
  if (inParenthesis) {
41
44
  context.outOfParenthesis();
42
45
  }
43
- if (this.parens && this.parensInOp && !mathOn && !doubleParen) {
46
+ if (this.parens && this.parensInOp && !mathOn && !doubleParen
47
+ && (!(returnValue instanceof Dimension))) {
44
48
  returnValue = new Paren(returnValue);
45
49
  }
46
50
  return returnValue;
@@ -97,17 +97,18 @@ Import.prototype.evalForImport = function (context) {
97
97
  };
98
98
  Import.prototype.evalPath = function (context) {
99
99
  var path = this.path.eval(context);
100
- var rootpath = this._fileInfo && this._fileInfo.rootpath;
100
+ var fileInfo = this._fileInfo;
101
101
 
102
102
  if (!(path instanceof URL)) {
103
- if (rootpath) {
104
- var pathValue = path.value;
105
- // Add the base path if the import is relative
106
- if (pathValue && context.isPathRelative(pathValue)) {
107
- path.value = rootpath + pathValue;
108
- }
103
+ // Add the rootpath if the URL requires a rewrite
104
+ var pathValue = path.value;
105
+ if (fileInfo &&
106
+ pathValue &&
107
+ context.pathRequiresRewrite(pathValue)) {
108
+ path.value = context.rewritePath(pathValue, fileInfo.rootpath);
109
+ } else {
110
+ path.value = context.normalizePath(path.value);
109
111
  }
110
- path.value = context.normalizePath(path.value);
111
112
  }
112
113
 
113
114
  return path;
@@ -8,7 +8,7 @@ var Selector = require('./selector'),
8
8
  utils = require('../utils');
9
9
 
10
10
  var Definition = function (name, params, rules, condition, variadic, frames, visibilityInfo) {
11
- this.name = name;
11
+ this.name = name || 'anonymous mixin';
12
12
  this.selectors = [new Selector([new Element(null, name, false, this._index, this._fileInfo)])];
13
13
  this.params = params;
14
14
  this.condition = condition;
@@ -1,6 +1,7 @@
1
1
  var Node = require('./node'),
2
2
  Color = require('./color'),
3
- Dimension = require('./dimension');
3
+ Dimension = require('./dimension'),
4
+ MATH = require('../constants').Math;
4
5
 
5
6
  var Operation = function (op, operands, isSpaced) {
6
7
  this.op = op.trim();
@@ -14,9 +15,11 @@ Operation.prototype.accept = function (visitor) {
14
15
  };
15
16
  Operation.prototype.eval = function (context) {
16
17
  var a = this.operands[0].eval(context),
17
- b = this.operands[1].eval(context);
18
+ b = this.operands[1].eval(context),
19
+ op;
18
20
 
19
- if (context.isMathOn()) {
21
+ if (context.isMathOn(this.op)) {
22
+ op = this.op === './' ? '/' : this.op;
20
23
  if (a instanceof Dimension && b instanceof Color) {
21
24
  a = a.toColor();
22
25
  }
@@ -24,11 +27,14 @@ Operation.prototype.eval = function (context) {
24
27
  b = b.toColor();
25
28
  }
26
29
  if (!a.operate) {
30
+ if (a instanceof Operation && a.op === '/' && context.math === MATH.PARENS_DIVISION) {
31
+ return new Operation(this.op, [a, b], this.isSpaced);
32
+ }
27
33
  throw { type: 'Operation',
28
34
  message: 'Operation on an invalid type' };
29
35
  }
30
36
 
31
- return a.operate(context, this.op, b);
37
+ return a.operate(context, op, b);
32
38
  } else {
33
39
  return new Operation(this.op, [a, b], this.isSpaced);
34
40
  }
@@ -21,20 +21,19 @@ URL.prototype.eval = function (context) {
21
21
  rootpath;
22
22
 
23
23
  if (!this.isEvald) {
24
- // Add the base path if the URL is relative
24
+ // Add the rootpath if the URL requires a rewrite
25
25
  rootpath = this.fileInfo() && this.fileInfo().rootpath;
26
- if (rootpath &&
26
+ if (typeof rootpath === 'string' &&
27
27
  typeof val.value === 'string' &&
28
- context.isPathRelative(val.value)) {
29
-
28
+ context.pathRequiresRewrite(val.value)) {
30
29
  if (!val.quote) {
31
- rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return '\\' + match; });
30
+ rootpath = escapePath(rootpath);
32
31
  }
33
- val.value = rootpath + val.value;
32
+ val.value = context.rewritePath(val.value, rootpath);
33
+ } else {
34
+ val.value = context.normalizePath(val.value);
34
35
  }
35
36
 
36
- val.value = context.normalizePath(val.value);
37
-
38
37
  // Add url args if enabled
39
38
  if (context.urlArgs) {
40
39
  if (!val.value.match(/^\s*data:/)) {
@@ -51,4 +50,9 @@ URL.prototype.eval = function (context) {
51
50
 
52
51
  return new URL(val, this.getIndex(), this.fileInfo(), true);
53
52
  };
53
+
54
+ function escapePath(path) {
55
+ return path.replace(/[\(\)'"\s]/g, function(match) { return '\\' + match; });
56
+ }
57
+
54
58
  module.exports = URL;
package/lib/less/utils.js CHANGED
@@ -1,4 +1,7 @@
1
1
  /* jshint proto: true */
2
+ var Constants = require('./constants');
3
+ var clone = require('clone');
4
+
2
5
  var utils = {
3
6
  getLocation: function(index, inputStream) {
4
7
  var n = index + 1,
@@ -36,27 +39,59 @@ var utils = {
36
39
  }
37
40
  return cloned;
38
41
  },
39
- defaults: function(obj1, obj2) {
40
- if (!obj2._defaults || obj2._defaults !== obj1) {
41
- for (var prop in obj1) {
42
- if (obj1.hasOwnProperty(prop)) {
43
- if (!obj2.hasOwnProperty(prop)) {
44
- obj2[prop] = obj1[prop];
45
- }
46
- else if (Array.isArray(obj1[prop])
47
- && Array.isArray(obj2[prop])) {
48
-
49
- obj1[prop].forEach(function(p) {
50
- if (obj2[prop].indexOf(p) === -1) {
51
- obj2[prop].push(p);
52
- }
53
- });
54
- }
55
- }
42
+ copyOptions: function(obj1, obj2) {
43
+ if (obj2 && obj2._defaults) {
44
+ return obj2;
45
+ }
46
+ var opts = utils.defaults(obj1, obj2);
47
+ if (opts.strictMath) {
48
+ opts.math = Constants.Math.STRICT_LEGACY;
49
+ }
50
+ // Back compat with changed relativeUrls option
51
+ if (opts.relativeUrls) {
52
+ opts.rewriteUrls = Constants.RewriteUrls.ALL;
53
+ }
54
+ if (typeof opts.math === 'string') {
55
+ switch (opts.math.toLowerCase()) {
56
+ case 'always':
57
+ opts.math = Constants.Math.ALWAYS;
58
+ break;
59
+ case 'parens-division':
60
+ opts.math = Constants.Math.PARENS_DIVISION;
61
+ break;
62
+ case 'strict':
63
+ case 'parens':
64
+ opts.math = Constants.Math.PARENS;
65
+ break;
66
+ case 'strict-legacy':
67
+ opts.math = Constants.Math.STRICT_LEGACY;
68
+ }
69
+ }
70
+ if (typeof opts.rewriteUrls === 'string') {
71
+ switch (opts.rewriteUrls.toLowerCase()) {
72
+ case 'off':
73
+ opts.rewriteUrls = Constants.RewriteUrls.OFF;
74
+ break;
75
+ case 'local':
76
+ opts.rewriteUrls = Constants.RewriteUrls.LOCAL;
77
+ break;
78
+ case 'all':
79
+ opts.rewriteUrls = Constants.RewriteUrls.ALL;
80
+ break;
56
81
  }
57
82
  }
58
- obj2._defaults = obj1;
59
- return obj2;
83
+ return opts;
84
+ },
85
+ defaults: function(obj1, obj2) {
86
+ var newObj = obj2 || {};
87
+ if (!obj2._defaults) {
88
+ newObj = {};
89
+ var defaults = clone(obj1);
90
+ newObj._defaults = defaults;
91
+ var cloned = obj2 ? clone(obj2) : {};
92
+ Object.assign(newObj, defaults, cloned);
93
+ }
94
+ return newObj;
60
95
  },
61
96
  merge: function(obj1, obj2) {
62
97
  for (var prop in obj2) {
@@ -43,7 +43,7 @@ module.exports = function(window, options) {
43
43
  options.onReady = true;
44
44
  }
45
45
 
46
- // TODO: deprecate and remove 'inlineJavaScript' thing - where it came from at all?
47
- options.javascriptEnabled = (options.javascriptEnabled || options.inlineJavaScript) ? true : false;
48
-
46
+ if (options.relativeUrls) {
47
+ options.rewriteUrls = 'all';
48
+ }
49
49
  };
@@ -30,7 +30,13 @@ module.exports = function(window, options) {
30
30
  var typePattern = /^text\/(x-)?less$/;
31
31
 
32
32
  function clone(obj) {
33
- return JSON.parse(JSON.stringify(obj || {}));
33
+ var cloned = {};
34
+ for (var prop in obj) {
35
+ if (obj.hasOwnProperty(prop)) {
36
+ cloned[prop] = obj[prop];
37
+ }
38
+ }
39
+ return cloned;
34
40
  }
35
41
 
36
42
  // only really needed for phantom
@@ -93,7 +99,8 @@ module.exports = function(window, options) {
93
99
  currentDirectory: fileManager.getPath(path),
94
100
  filename: path,
95
101
  rootFilename: path,
96
- relativeUrls: instanceOptions.relativeUrls};
102
+ rewriteUrls: instanceOptions.rewriteUrls
103
+ };
97
104
 
98
105
  newFileInfo.entryPath = newFileInfo.currentDirectory;
99
106
  newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory;
@@ -6,7 +6,7 @@ module.exports = function(environment) {
6
6
  function imageSize(functionContext, filePathNode) {
7
7
  var filePath = filePathNode.value;
8
8
  var currentFileInfo = functionContext.currentFileInfo;
9
- var currentDirectory = currentFileInfo.relativeUrls ?
9
+ var currentDirectory = currentFileInfo.rewriteUrls ?
10
10
  currentFileInfo.currentDirectory : currentFileInfo.entryPath;
11
11
 
12
12
  var fragmentStart = filePath.indexOf('#');
@@ -47,10 +47,15 @@ var lessc_helper = {
47
47
  console.log(' in generated CSS file.');
48
48
  console.log(' -rp, --rootpath=URL Sets rootpath for url rewriting in relative imports and urls');
49
49
  console.log(' Works with or without the relative-urls option.');
50
- console.log(' -ru, --relative-urls Re-writes relative urls to the base less file.');
51
- console.log(' -sm=on|off Turns on or off strict math, where in strict mode, math.');
52
- console.log(' --strict-math=on|off Requires brackets. This option may default to on and then');
53
- console.log(' be removed in the future.');
50
+ console.log(' -ru=, --rewrite-urls= Rewrites URLs to make them relative to the base less file.');
51
+ console.log(' all|local|off \'all\' rewrites all URLs, \'local\' just those starting with a \'.\'');
52
+ console.log('');
53
+ console.log(' -m=, --math=');
54
+ console.log(' always Less will eagerly perform math operations always.');
55
+ console.log(' parens-division Math performed except for division (/) operator');
56
+ console.log(' parens | strict Math only performed inside parentheses');
57
+ console.log(' strict-legacy Parens required in very strict terms (legacy --strict-math)');
58
+ console.log('');
54
59
  console.log(' -su=on|off Allows mixed units, e.g. 1px+1em or 1px*1px which have units');
55
60
  console.log(' --strict-units=on|off that cannot be represented.');
56
61
  console.log(' --global-var=\'VAR=VALUE\' Defines a variable that can be referenced by the file.');
@@ -64,6 +69,9 @@ var lessc_helper = {
64
69
  console.log(' or --clean-css="advanced"');
65
70
  console.log('');
66
71
  console.log('-------------------------- Deprecated ----------------');
72
+ console.log(' -sm=on|off Legacy parens-only math. Use --math');
73
+ console.log(' --strict-math=on|off ');
74
+ console.log('');
67
75
  console.log(' --line-numbers=TYPE Outputs filename and line numbers.');
68
76
  console.log(' TYPE can be either \'comments\', which will output');
69
77
  console.log(' the debug info within comments, \'mediaquery\'');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "less",
3
- "version": "3.6.0",
3
+ "version": "3.8.1",
4
4
  "description": "Leaner CSS",
5
5
  "homepage": "http://lesscss.org",
6
6
  "author": {
@@ -71,6 +71,7 @@
71
71
  "less-plugin-autoprefix": "^1.5.1",
72
72
  "less-plugin-clean-css": "^1.5.1",
73
73
  "performance-now": "^0.2.0",
74
+ "phantomjs-polyfill-object-assign": "0.0.2",
74
75
  "phantomjs-prebuilt": "^2.1.16",
75
76
  "phin": "^2.2.3",
76
77
  "promise": "^7.1.1",
@@ -104,5 +105,7 @@
104
105
  ],
105
106
  "rawcurrent": "https://raw.github.com/less/less.js/v",
106
107
  "sourcearchive": "https://github.com/less/less.js/archive/v",
107
- "dependencies": {}
108
+ "dependencies": {
109
+ "clone": "^2.1.2"
110
+ }
108
111
  }
@@ -0,0 +1,36 @@
1
+ @import "http://localhost:8081/test/browser/less/imports/modify-this.css";
2
+ @import "http://localhost:8081/test/browser/less/imports/modify-again.css";
3
+ .modify {
4
+ my-url: url("http://localhost:8081/test/browser/less/imports/a.png");
5
+ }
6
+ .modify {
7
+ my-url: url("http://localhost:8081/test/browser/less/imports/b.png");
8
+ }
9
+ @font-face {
10
+ src: url("/fonts/garamond-pro.ttf");
11
+ src: local(Futura-Medium), url(http://localhost:8081/test/browser/less/rewrite-urls/fonts.svg#MyGeometricModern) format("svg");
12
+ }
13
+ #shorthands {
14
+ background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
15
+ }
16
+ #misc {
17
+ background-image: url(http://localhost:8081/test/browser/less/rewrite-urls/images/image.jpg);
18
+ background: url("#inline-svg");
19
+ }
20
+ #data-uri {
21
+ background: url(data:image/png;charset=utf-8;base64,
22
+ kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
23
+ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
24
+ kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
25
+ background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
26
+ background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
27
+ }
28
+ #svg-data-uri {
29
+ background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
30
+ }
31
+ .comma-delimited {
32
+ background: url(http://localhost:8081/test/browser/less/rewrite-urls/bg.jpg) no-repeat, url(http://localhost:8081/test/browser/less/rewrite-urls/bg.png) repeat-x top left, url(http://localhost:8081/test/browser/less/rewrite-urls/bg);
33
+ }
34
+ .values {
35
+ url: url('http://localhost:8081/test/browser/less/rewrite-urls/Trebuchet');
36
+ }