calc() fix - fixes #974 (partially #1880)

This commit is contained in:
Matthew Dean
2018-02-10 16:57:53 -08:00
committed by GitHub
parent 367b46a51f
commit a48c24c4dd
21 changed files with 62 additions and 45 deletions

23
dist/less.js vendored
View File

@@ -1003,7 +1003,11 @@ contexts.Eval.prototype.outOfParenthesis = function () {
this.parensStack.pop();
};
contexts.Eval.prototype.mathOn = true;
contexts.Eval.prototype.isMathOn = function () {
if (!this.mathOn) {
return false;
}
return this.strictMath ? (this.parensStack && this.parensStack.length) : true;
};
@@ -4019,6 +4023,7 @@ var Parser = function Parser(context, imports, fileInfo) {
}
parserInput.forget();
return new(tree.Call)(name, args, index, fileInfo);
},
@@ -4194,7 +4199,7 @@ var Parser = function Parser(context, imports, fileInfo) {
}
},
// A property entity useing the protective {} e.g. @{prop}
// A property entity useing the protective {} e.g. ${prop}
propertyCurly: function () {
var curly, index = parserInput.i;
@@ -6331,6 +6336,7 @@ var Node = require("./node"),
var Call = function (name, args, index, currentFileInfo) {
this.name = name;
this.args = args;
this.mathOn = name === 'calc' ? false : true;
this._index = index;
this._fileInfo = currentFileInfo;
};
@@ -6353,8 +6359,16 @@ Call.prototype.accept = function (visitor) {
// The function should receive the value, not the variable.
//
Call.prototype.eval = function (context) {
var args = this.args.map(function (a) { return a.eval(context); }),
result, funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo());
/**
* Turn off math for calc(), and switch back on for evaluating nested functions
*/
var currentMathContext = context.mathOn;
context.mathOn = this.mathOn;
var args = this.args.map(function (a) { return a.eval(context); });
context.mathOn = currentMathContext;
var result, funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo());
if (funcCaller.isValid()) {
try {
@@ -8384,7 +8398,6 @@ module.exports = Property;
},{"./declaration":58,"./node":73}],77:[function(require,module,exports){
var Node = require("./node"),
JsEvalNode = require("./js-eval-node"),
Variable = require("./variable"),
Property = require("./property");
@@ -8441,7 +8454,7 @@ Quoted.prototype.compare = function (other) {
};
module.exports = Quoted;
},{"./js-eval-node":67,"./node":73,"./property":76,"./variable":85}],78:[function(require,module,exports){
},{"./node":73,"./property":76,"./variable":85}],78:[function(require,module,exports){
var Node = require("./node"),
Declaration = require("./declaration"),
Keyword = require("./keyword"),

10
dist/less.min.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -73,7 +73,11 @@ contexts.Eval.prototype.outOfParenthesis = function () {
this.parensStack.pop();
};
contexts.Eval.prototype.mathOn = true;
contexts.Eval.prototype.isMathOn = function () {
if (!this.mathOn) {
return false;
}
return this.strictMath ? (this.parensStack && this.parensStack.length) : true;
};

View File

@@ -421,6 +421,7 @@ var Parser = function Parser(context, imports, fileInfo) {
}
parserInput.forget();
return new(tree.Call)(name, args, index, fileInfo);
},
@@ -596,7 +597,7 @@ var Parser = function Parser(context, imports, fileInfo) {
}
},
// A property entity useing the protective {} e.g. @{prop}
// A property entity useing the protective {} e.g. ${prop}
propertyCurly: function () {
var curly, index = parserInput.i;

View File

@@ -7,6 +7,7 @@ var Node = require("./node"),
var Call = function (name, args, index, currentFileInfo) {
this.name = name;
this.args = args;
this.mathOn = name === 'calc' ? false : true;
this._index = index;
this._fileInfo = currentFileInfo;
};
@@ -29,8 +30,16 @@ Call.prototype.accept = function (visitor) {
// The function should receive the value, not the variable.
//
Call.prototype.eval = function (context) {
var args = this.args.map(function (a) { return a.eval(context); }),
result, funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo());
/**
* Turn off math for calc(), and switch back on for evaluating nested functions
*/
var currentMathContext = context.mathOn;
context.mathOn = this.mathOn;
var args = this.args.map(function (a) { return a.eval(context); });
context.mathOn = currentMathContext;
var result, funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo());
if (funcCaller.isValid()) {
try {

View File

@@ -1,12 +0,0 @@
// Backwards compatibility shim for Directive (AtRule)
var AtRule = require("./atrule");
var Directive = function () {
var args = Array.prototype.slice.call(arguments);
AtRule.apply(this, args);
};
Directive.prototype = Object.create(AtRule.prototype);
Directive.prototype.constructor = Directive;
module.exports = Directive;

View File

@@ -1,5 +1,4 @@
var Node = require("./node"),
JsEvalNode = require("./js-eval-node"),
Variable = require("./variable"),
Property = require("./property");

View File

@@ -1,12 +0,0 @@
// Backwards compatibility shim for Rule (Declaration)
var Declaration = require("./declaration");
var Rule = function () {
var args = Array.prototype.slice.call(arguments);
Declaration.apply(this, args);
};
Rule.prototype = Object.create(Declaration.prototype);
Rule.prototype.constructor = Rule;
module.exports = Rule;

View File

@@ -2,7 +2,7 @@ var less = {
logLevel: 4,
errorReporting: "console",
javascriptEnabled: true,
strictMath: true
strictMath: false
};
// There originally run inside describe method. However, since they have not

View File

@@ -2,7 +2,6 @@ var less = {
logLevel: 4,
errorReporting: "console"
};
less.strictMath = true;
less.functions = {
add: function(a, b) {
return new(less.tree.Dimension)(a.value + b.value);

5
test/css/calc.css Normal file
View File

@@ -0,0 +1,5 @@
.no-math {
width: calc(50% + (25vh - 20px));
foo: 3 calc(3 + 4) 11;
bar: calc(1 + 20%);
}

View File

@@ -8,7 +8,7 @@
.first,
.planning {
margin: 10px;
total-width: (1 * 6em * 12) + (2em * 12);
total-width: 96em;
}
.some-inline-comments {
a: yes /* comment */;

View File

@@ -8,13 +8,17 @@ console.log("\n" + stylize("Less", 'underline') + "\n");
lessTester.prepBomTest();
var testMap = [
[{
strictMath: true,
strictMath: false,
relativeUrls: true,
silent: true,
javascriptEnabled: true,
// Set explicitly for legacy tests for >3.0
ieCompat: true
}],
[{
strictMath: true,
ieCompat: true
}, "strict-math/"],
[{strictMath: true, strictUnits: true, javascriptEnabled: true}, "errors/",
lessTester.testErrors, null],
[{strictMath: true, strictUnits: true, javascriptEnabled: false}, "no-js-errors/",
@@ -56,7 +60,7 @@ testMap.forEach(function(args) {
lessTester.runTestSet.apply(lessTester, args)
});
lessTester.testSyncronous({syncImport: true}, "import");
lessTester.testSyncronous({syncImport: true}, "css");
lessTester.testSyncronous({syncImport: true}, "strict-math/css");
lessTester.testNoOptions();
lessTester.testJSImport();
lessTester.finished();

7
test/less/calc.less Normal file
View File

@@ -0,0 +1,7 @@
.no-math {
@var: 50vh/2;
width: calc(50% + (@var - 20px));
foo: 1 + 2 calc(3 + 4) 5 + 6;
@floor: floor(1 + .1);
bar: calc(@floor + 20%);
}

View File

@@ -23,7 +23,7 @@
@ratio_large: 16;
@ratio_small: 9;
@media all and (device-aspect-ratio: @ratio_large / @ratio_small) {
@media all and (device-aspect-ratio: ~"@{ratio_large} / @{ratio_small}") {
body { max-width: 800px; }
}
@@ -177,7 +177,7 @@ body {
}
}
@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2/1), (min-resolution: 2dppx), (min-resolution: 128dpcm) {
@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: ~"2/1"), (min-resolution: 2dppx), (min-resolution: 128dpcm) {
.b {
background: red;
}