Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #1880 - Adds two new math modes and deprecates strictMath #3274

Merged
merged 6 commits into from
Jul 11, 2018
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion bin/lessc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var path = require('path'),
fs = require('../lib/less-node/fs'),
os = require('os'),
utils = require('../lib/less/utils'),
MATH = require('../lib/less/math-constants'),
errno,
mkdirp;

Expand Down Expand Up @@ -481,8 +482,17 @@ function processPluginQueue() {
break;
case 'sm':
case 'strict-math':
console.warning('--strict-math is deprecated. Use --math=strict');
if (checkArgFunc(arg, match[2])) {
options.strictMath = checkBooleanArg(match[2]);
if (checkBooleanArg(match[2])) {
options.math = MATH.STRICT_LEGACY;
}
}
break;
case 'm':
case 'math':
if (checkArgFunc(arg, match[2])) {
options.math = match[2];
}
break;
case 'su':
Expand Down
4 changes: 0 additions & 4 deletions lib/less-browser/add-default-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,4 @@ module.exports = function(window, options) {
if (options.onReady === undefined) {
options.onReady = true;
}

// TODO: deprecate and remove 'inlineJavaScript' thing - where it came from at all?
options.javascriptEnabled = (options.javascriptEnabled || options.inlineJavaScript) ? true : false;

};
13 changes: 10 additions & 3 deletions lib/less-node/lessc-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,13 @@ var lessc_helper = {
console.log(' -rp, --rootpath=URL Sets rootpath for url rewriting in relative imports and urls');
console.log(' Works with or without the relative-urls option.');
console.log(' -ru, --relative-urls Re-writes relative urls to the base less file.');
console.log(' -sm=on|off Turns on or off strict math, where in strict mode, math.');
console.log(' --strict-math=on|off Requires brackets. This option may default to on and then');
console.log(' be removed in the future.');
console.log('');
console.log(' -m=, --math=');
console.log(' always Less will eagerly perform math operations always.');
console.log(' parens-division Math performed except for division (/) operator');
console.log(' parens | strict Math only performed inside parentheses');
console.log(' strict-legacy Parens required in very strict terms (legacy --strict-math)');
console.log('');
console.log(' -su=on|off Allows mixed units, e.g. 1px+1em or 1px*1px which have units');
console.log(' --strict-units=on|off that cannot be represented.');
console.log(' --global-var=\'VAR=VALUE\' Defines a variable that can be referenced by the file.');
Expand All @@ -64,6 +68,9 @@ var lessc_helper = {
console.log(' or --clean-css="advanced"');
console.log('');
console.log('-------------------------- Deprecated ----------------');
console.log(' -sm=on|off Legacy parens-only math. Use --math');
console.log(' --strict-math=on|off ');
console.log('');
console.log(' --line-numbers=TYPE Outputs filename and line numbers.');
console.log(' TYPE can be either \'comments\', which will output');
console.log(' the debug info within comments, \'mediaquery\'');
Expand Down
13 changes: 10 additions & 3 deletions lib/less/contexts.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var contexts = {};
module.exports = contexts;
var MATH = require('./math-constants');

var copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) {
if (!original) { return; }
Expand Down Expand Up @@ -43,7 +44,7 @@ var evalCopyProperties = [
'paths', // additional include paths
'compress', // whether to compress
'ieCompat', // whether to enforce IE compatibility (IE8 data-uri)
'strictMath', // whether math has to be within parenthesis
'math', // whether math has to be within parenthesis
'strictUnits', // whether units need to evaluate correctly
'sourceMap', // whether to output a source map
'importMultiple', // whether we are currently importing multiple copies
Expand Down Expand Up @@ -90,11 +91,17 @@ contexts.Eval.prototype.outOfParenthesis = function () {

contexts.Eval.prototype.inCalc = false;
contexts.Eval.prototype.mathOn = true;
contexts.Eval.prototype.isMathOn = function () {
contexts.Eval.prototype.isMathOn = function (op) {
if (!this.mathOn) {
return false;
}
return this.strictMath ? (this.parensStack && this.parensStack.length) : true;
if (op === '/' && this.math !== MATH.ALWAYS && (!this.parensStack || !this.parensStack.length)) {
return false;
}
if (this.math > MATH.PARENS_DIVISION) {
return this.parensStack && this.parensStack.length;
}
return true;
};

contexts.Eval.prototype.isPathRelative = function (path) {
Expand Down
14 changes: 11 additions & 3 deletions lib/less/default-options.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// Export a new default each time
module.exports = function() {
return {
/* Inline Javascript - @plugin still allowed */
javascriptEnabled: false,

/* Outputs a makefile import dependency list to stdout. */
depends: false,

/* Compress using less built-in compression.
/* (DEPRECATED) Compress using less built-in compression.
* This does an okay job but does not utilise all the tricks of
* dedicated css compression. */
compress: false,
Expand Down Expand Up @@ -44,8 +47,13 @@ module.exports = function() {
/* Compatibility with IE8. Used for limiting data-uri length */
ieCompat: false, // true until 3.0

/* Without this option on, Less will try and process all math in your css */
strictMath: false,
/* How to process math
* 0 always - eagerly try to solve all operations
* 1 parens-division - require parens for division "/"
* 2 parens | strict - require parens for all operations
* 3 strict-legacy - legacy strict behavior (super-strict)
*/
math: 0,

/* Without this option, less attempts to guess at the output unit when it does maths. */
strictUnits: false,
Expand Down
6 changes: 6 additions & 0 deletions lib/less/math-constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
ALWAYS: 0,
PARENS_DIVISION: 1,
PARENS: 2,
STRICT_LEGACY: 3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Speaking of style guides, you have any strong opinion on comma dangle?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comma dangles shouldn't go in, probably, for compatibility reasons.

};
4 changes: 2 additions & 2 deletions lib/less/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ module.exports = function(environment, ParseTree, ImportManager) {

if (typeof options === 'function') {
callback = options;
options = utils.defaults(this.options, {});
options = utils.copyOptions(this.options, {});
}
else {
options = utils.defaults(this.options, options || {});
options = utils.copyOptions(this.options, options || {});
}

if (!callback) {
Expand Down
2 changes: 1 addition & 1 deletion lib/less/parser/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1920,7 +1920,7 @@ var Parser = function Parser(context, imports, fileInfo) {

parserInput.save();

op = parserInput.$char('/') || parserInput.$char('*');
op = parserInput.$char('/') || parserInput.$char('*') || parserInput.$str('./');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love the ./ thing, by the way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


if (!op) { parserInput.forget(); break; }

Expand Down
4 changes: 2 additions & 2 deletions lib/less/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ module.exports = function(environment, ParseTree, ImportManager) {
var render = function (input, options, callback) {
if (typeof options === 'function') {
callback = options;
options = utils.defaults(this.options, {});
options = utils.copyOptions(this.options, {});
}
else {
options = utils.defaults(this.options, options || {});
options = utils.copyOptions(this.options, options || {});
}

if (!callback) {
Expand Down
18 changes: 11 additions & 7 deletions lib/less/tree/declaration.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
var Node = require('./node'),
Value = require('./value'),
Keyword = require('./keyword'),
Anonymous = require('./anonymous');
Anonymous = require('./anonymous'),
MATH = require('../math-constants');

var Declaration = function (name, value, important, merge, index, currentFileInfo, inline, variable) {
this.name = name;
Expand Down Expand Up @@ -41,17 +42,20 @@ Declaration.prototype.genCSS = function (context, output) {
output.add(this.important + ((this.inline || (context.lastRule && context.compress)) ? '' : ';'), this._fileInfo, this._index);
};
Declaration.prototype.eval = function (context) {
var strictMathBypass = false, name = this.name, evaldValue, variable = this.variable;
var mathBypass = false, prevMath, name = this.name, evaldValue, variable = this.variable;
if (typeof name !== 'string') {
// expand 'primitive' name directly to get
// things faster (~10% for benchmark.less):
name = (name.length === 1) && (name[0] instanceof Keyword) ?
name[0].value : evalName(context, name);
variable = false; // never treat expanded interpolation as new variable name
}
if (name === 'font' && !context.strictMath) {
strictMathBypass = true;
context.strictMath = true;

// @todo remove when parens-division is default
if (name === 'font' && context.math === MATH.ALWAYS) {
mathBypass = true;
prevMath = context.math;
context.math = MATH.PARENS_DIVISION;
}
try {
context.importantScope.push({});
Expand Down Expand Up @@ -82,8 +86,8 @@ Declaration.prototype.eval = function (context) {
throw e;
}
finally {
if (strictMathBypass) {
context.strictMath = false;
if (mathBypass) {
context.math = prevMath;
}
}
};
Expand Down
10 changes: 7 additions & 3 deletions lib/less/tree/expression.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
var Node = require('./node'),
Paren = require('./paren'),
Comment = require('./comment');
Comment = require('./comment'),
Dimension = require('./dimension'),
MATH = require('../math-constants');

var Expression = function (value, noSpacing) {
this.value = value;
Expand All @@ -17,7 +19,8 @@ Expression.prototype.accept = function (visitor) {
Expression.prototype.eval = function (context) {
var returnValue,
mathOn = context.isMathOn(),
inParenthesis = this.parens && !this.parensInOp,
inParenthesis = this.parens &&
(context.math !== MATH.STRICT_LEGACY || !this.parensInOp),
doubleParen = false;
if (inParenthesis) {
context.inParenthesis();
Expand All @@ -40,7 +43,8 @@ Expression.prototype.eval = function (context) {
if (inParenthesis) {
context.outOfParenthesis();
}
if (this.parens && this.parensInOp && !mathOn && !doubleParen) {
if (this.parens && this.parensInOp && !mathOn && !doubleParen
&& (!(returnValue instanceof Dimension))) {
returnValue = new Paren(returnValue);
}
return returnValue;
Expand Down
14 changes: 10 additions & 4 deletions lib/less/tree/operation.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var Node = require('./node'),
Color = require('./color'),
Dimension = require('./dimension');
Dimension = require('./dimension'),
MATH = require('../math-constants');

var Operation = function (op, operands, isSpaced) {
this.op = op.trim();
Expand All @@ -14,21 +15,26 @@ Operation.prototype.accept = function (visitor) {
};
Operation.prototype.eval = function (context) {
var a = this.operands[0].eval(context),
b = this.operands[1].eval(context);
b = this.operands[1].eval(context),
op;

if (context.isMathOn()) {
if (context.isMathOn(this.op)) {
op = this.op === './' ? '/' : this.op;
if (a instanceof Dimension && b instanceof Color) {
a = a.toColor();
}
if (b instanceof Dimension && a instanceof Color) {
b = b.toColor();
}
if (!a.operate) {
if (a instanceof Operation && a.op === '/' && context.math === MATH.PARENS_DIVISION) {
return new Operation(this.op, [a, b], this.isSpaced);
}
throw { type: 'Operation',
message: 'Operation on an invalid type' };
}

return a.operate(context, this.op, b);
return a.operate(context, op, b);
} else {
return new Operation(this.op, [a, b], this.isSpaced);
}
Expand Down
25 changes: 25 additions & 0 deletions lib/less/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/* jshint proto: true */
var MATH = require('./math-constants');

var utils = {
getLocation: function(index, inputStream) {
var n = index + 1,
Expand Down Expand Up @@ -36,6 +38,29 @@ var utils = {
}
return cloned;
},
copyOptions: function(obj1, obj2) {
var opts = utils.defaults(obj1, obj2);
if (opts.strictMath) {
opts.math = MATH.STRICT_LEGACY;
}
if (opts.hasOwnProperty('math') && typeof opts.math === 'string') {
switch (opts.math.toLowerCase()) {
case 'always':
opts.math = MATH.ALWAYS;
break;
case 'parens-division':
opts.math = MATH.PARENS_DIVISION;
break;
case 'strict':
case 'parens':
opts.math = MATH.PARENS;
break;
case 'strict-legacy':
opts.math = MATH.STRICT_LEGACY;
}
}
return opts;
},
defaults: function(obj1, obj2) {
if (!obj2._defaults || obj2._defaults !== obj1) {
for (var prop in obj1) {
Expand Down
2 changes: 1 addition & 1 deletion test/browser/runner-browser-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ var less = {
logLevel: 4,
errorReporting: 'console',
javascriptEnabled: true,
strictMath: false
math: 'always'
};

// There originally run inside describe method. However, since they have not
Expand Down
2 changes: 1 addition & 1 deletion test/browser/runner-errors-options.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var less = {
strictUnits: true,
strictMath: true,
math: 'strict-legacy',
logLevel: 4,
javascriptEnabled: true
};
2 changes: 1 addition & 1 deletion test/browser/runner-legacy-options.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var less = {
logLevel: 4,
errorReporting: 'console',
strictMath: false,
math: 'always',
strictUnits: false
};
4 changes: 2 additions & 2 deletions test/css/calc.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
root2: calc(100% - 40px);
width: calc(50% + (25vh - 20px));
height: calc(50% + (25vh - 20px));
min-height: calc((10vh) + calc(5vh));
min-height: calc(10vh + calc(5vh));
foo: 3 calc(3 + 4) 11;
bar: calc(1 + 20%);
}
.b {
one: calc(100% - (20px));
one: calc(100% - 20px);
two: calc(100% - (10px + 10px));
three: calc(100% - (3 * 1));
four: calc(100% - (3 * 1));
Expand Down
8 changes: 0 additions & 8 deletions test/css/css-3.css
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,6 @@ p::before {
font-size: 12px;
}
}
.units {
font: 1.2rem/2rem;
font: 8vw/9vw;
font: 10vh/12vh;
font: 12vm/15vm;
font: 12vmin/15vmin;
font: 1.2ch/1.5ch;
}
@supports ( box-shadow: 2px 2px 2px black ) or
( -moz-box-shadow: 2px 2px 2px black ) {
.outline {
Expand Down
2 changes: 2 additions & 0 deletions test/css/functions.css
Original file line number Diff line number Diff line change
Expand Up @@ -223,4 +223,6 @@ html {
e: ;
f: 6;
/* results in void */
color: green;
color: purple;
}
10 changes: 10 additions & 0 deletions test/css/math/parens-division/media-math.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@media (min-width: 17) {
.foo {
bar: 1;
}
}
@media (min-width: 16 / 9) {
.foo {
bar: 1;
}
}
Loading