diff --git a/bin/lessc b/bin/lessc index 7360ff07e..5387fb950 100755 --- a/bin/lessc +++ b/bin/lessc @@ -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; @@ -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': diff --git a/lib/less-browser/add-default-options.js b/lib/less-browser/add-default-options.js index 5155afbce..051a68dd8 100644 --- a/lib/less-browser/add-default-options.js +++ b/lib/less-browser/add-default-options.js @@ -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; - }; diff --git a/lib/less-node/lessc-helper.js b/lib/less-node/lessc-helper.js index 8b40f4fdf..fced0a56c 100644 --- a/lib/less-node/lessc-helper.js +++ b/lib/less-node/lessc-helper.js @@ -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.'); @@ -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\''); diff --git a/lib/less/contexts.js b/lib/less/contexts.js index a2f712110..69b84cacd 100644 --- a/lib/less/contexts.js +++ b/lib/less/contexts.js @@ -1,5 +1,6 @@ var contexts = {}; module.exports = contexts; +var MATH = require('./math-constants'); var copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) { if (!original) { return; } @@ -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 @@ -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) { diff --git a/lib/less/default-options.js b/lib/less/default-options.js index 09c0b3cfe..2ff9d2dc2 100644 --- a/lib/less/default-options.js +++ b/lib/less/default-options.js @@ -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, @@ -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, diff --git a/lib/less/math-constants.js b/lib/less/math-constants.js new file mode 100644 index 000000000..6b8af9299 --- /dev/null +++ b/lib/less/math-constants.js @@ -0,0 +1,6 @@ +module.exports = { + ALWAYS: 0, + PARENS_DIVISION: 1, + PARENS: 2, + STRICT_LEGACY: 3 +}; \ No newline at end of file diff --git a/lib/less/parse.js b/lib/less/parse.js index d1c4fad5d..cc254ba30 100644 --- a/lib/less/parse.js +++ b/lib/less/parse.js @@ -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) { diff --git a/lib/less/parser/parser.js b/lib/less/parser/parser.js index edb1db0ca..71abd8960 100644 --- a/lib/less/parser/parser.js +++ b/lib/less/parser/parser.js @@ -1947,7 +1947,7 @@ var Parser = function Parser(context, imports, fileInfo) { parserInput.save(); - op = parserInput.$char('/') || parserInput.$char('*'); + op = parserInput.$char('/') || parserInput.$char('*') || parserInput.$str('./'); if (!op) { parserInput.forget(); break; } diff --git a/lib/less/render.js b/lib/less/render.js index 1743f352e..8ea6f9eaa 100644 --- a/lib/less/render.js +++ b/lib/less/render.js @@ -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) { diff --git a/lib/less/tree/declaration.js b/lib/less/tree/declaration.js index 203c67c3e..c0b327d0a 100644 --- a/lib/less/tree/declaration.js +++ b/lib/less/tree/declaration.js @@ -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; @@ -41,7 +42,7 @@ 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): @@ -49,9 +50,12 @@ Declaration.prototype.eval = function (context) { 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({}); @@ -82,8 +86,8 @@ Declaration.prototype.eval = function (context) { throw e; } finally { - if (strictMathBypass) { - context.strictMath = false; + if (mathBypass) { + context.math = prevMath; } } }; diff --git a/lib/less/tree/expression.js b/lib/less/tree/expression.js index 92cad86cf..7e0ff1a04 100644 --- a/lib/less/tree/expression.js +++ b/lib/less/tree/expression.js @@ -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; @@ -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(); @@ -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; diff --git a/lib/less/tree/operation.js b/lib/less/tree/operation.js index 910c8b064..08ac152b3 100644 --- a/lib/less/tree/operation.js +++ b/lib/less/tree/operation.js @@ -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(); @@ -14,9 +15,11 @@ 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(); } @@ -24,11 +27,14 @@ Operation.prototype.eval = function (context) { 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); } diff --git a/lib/less/utils.js b/lib/less/utils.js index 1c830e7c8..ff260d632 100644 --- a/lib/less/utils.js +++ b/lib/less/utils.js @@ -1,4 +1,6 @@ /* jshint proto: true */ +var MATH = require('./math-constants'); + var utils = { getLocation: function(index, inputStream) { var n = index + 1, @@ -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) { diff --git a/package-lock.json b/package-lock.json index 0bd5290dc..5c36b9d51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "less", - "version": "3.5.2", + "version": "3.5.3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3276,9 +3276,9 @@ } }, "grunt-contrib-jasmine": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-jasmine/-/grunt-contrib-jasmine-1.1.0.tgz", - "integrity": "sha1-9oL3dX2il3Wf4+G0xl1GcMw66kk=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-jasmine/-/grunt-contrib-jasmine-1.2.0.tgz", + "integrity": "sha512-1mTRFLsHupOzP0JOSkKIROudMyFVOiBy96dX3/rHCn71z3kkpm6Ch5e71qNozeRfZgAPjf/7mDyQ/uDaS+D8IA==", "dev": true, "requires": { "chalk": "1.1.3", @@ -3408,7 +3408,7 @@ "dev": true, "requires": { "eventemitter2": "0.4.14", - "phantomjs-prebuilt": "2.1.15", + "phantomjs-prebuilt": "2.1.16", "rimraf": "2.6.2", "semver": "5.4.1", "temporary": "0.0.8" @@ -4831,9 +4831,9 @@ "dev": true }, "phantomjs-prebuilt": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.15.tgz", - "integrity": "sha1-IPhugtM0nFBZF1J3RbekEeCLOQM=", + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", + "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", "dev": true, "requires": { "es6-promise": "4.0.5", @@ -4842,146 +4842,15 @@ "hasha": "2.2.0", "kew": "0.7.0", "progress": "1.1.8", - "request": "2.81.0", + "request": "2.83.0", "request-progress": "2.0.1", - "which": "1.2.14" + "which": "1.3.1" }, "dependencies": { - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true - }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "requires": { - "boom": "2.10.1" - } - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.6", - "mime-types": "2.1.17" - } - }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", - "dev": true - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "dev": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" - } - }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", - "dev": true - }, - "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "dev": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.6", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.3", - "tunnel-agent": "0.6.0", - "uuid": "3.2.1" - } - }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, "which": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "2.0.0" diff --git a/test/browser/runner-browser-options.js b/test/browser/runner-browser-options.js index be8e3e3e1..780de3861 100644 --- a/test/browser/runner-browser-options.js +++ b/test/browser/runner-browser-options.js @@ -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 diff --git a/test/browser/runner-errors-options.js b/test/browser/runner-errors-options.js index 97b211d93..852ea5f71 100644 --- a/test/browser/runner-errors-options.js +++ b/test/browser/runner-errors-options.js @@ -1,6 +1,6 @@ var less = { strictUnits: true, - strictMath: true, + math: 'strict-legacy', logLevel: 4, javascriptEnabled: true }; diff --git a/test/browser/runner-legacy-options.js b/test/browser/runner-legacy-options.js index 66376b368..893447cef 100644 --- a/test/browser/runner-legacy-options.js +++ b/test/browser/runner-legacy-options.js @@ -1,6 +1,6 @@ var less = { logLevel: 4, errorReporting: 'console', - strictMath: false, + math: 'always', strictUnits: false }; diff --git a/test/css/calc.css b/test/css/calc.css index e8b5dcc97..9b29d7bf8 100644 --- a/test/css/calc.css +++ b/test/css/calc.css @@ -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)); diff --git a/test/css/css-3.css b/test/css/css-3.css index 5aafe04ec..5a14773a6 100644 --- a/test/css/css-3.css +++ b/test/css/css-3.css @@ -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 { diff --git a/test/css/functions.css b/test/css/functions.css index 35803f56a..37a5022cc 100644 --- a/test/css/functions.css +++ b/test/css/functions.css @@ -228,4 +228,6 @@ html { j: 8; k: 1; /* results in void */ + color: green; + color: purple; } diff --git a/test/css/math/parens-division/media-math.css b/test/css/math/parens-division/media-math.css new file mode 100644 index 000000000..0b8be1c9d --- /dev/null +++ b/test/css/math/parens-division/media-math.css @@ -0,0 +1,10 @@ +@media (min-width: 17) { + .foo { + bar: 1; + } +} +@media (min-width: 16 / 9) { + .foo { + bar: 1; + } +} diff --git a/test/css/math/parens-division/mixins-args.css b/test/css/math/parens-division/mixins-args.css new file mode 100644 index 000000000..d95021eef --- /dev/null +++ b/test/css/math/parens-division/mixins-args.css @@ -0,0 +1,169 @@ +#hidden { + color: transparent; +} +#hidden1 { + color: transparent; +} +.two-args { + color: blue; + width: 10px; + height: 99%; + depth: 99%; + border: 2px dotted black; +} +.one-arg { + width: 15px; + height: 49%; + depth: 49%; +} +.no-parens { + width: 5px; + height: 49%; + depth: 49%; +} +.no-args { + width: 5px; + height: 49%; + depth: 49%; +} +.var-args { + width: 45; + height: 8%; + depth: 18 / 2 - 1%; +} +.multi-mix { + width: 10px; + height: 29%; + depth: 29%; + margin: 4; + padding: 5; +} +body { + padding: 30px; + color: #f00; +} +.scope-mix { + width: 8; +} +.content { + width: 600px; +} +.content .column { + margin: 600px; +} +#same-var-name { + radius: 5px; +} +#var-inside { + width: 10px; +} +.arguments { + border: 1px solid black; + width: 1px; +} +.arguments2 { + border: 0px; + width: 0px; +} +.arguments3 { + border: 0px; + width: 0px; +} +.arguments4 { + border: 0 1 2 3 4; + rest: 1 2 3 4; + width: 0; +} +.edge-case { + border: "{"; + width: "{"; +} +.slash-vs-math { + border-radius: 2px/5px; + border-radius: 5px/10px; + border-radius: 6px; +} +.comma-vs-semi-colon { + one: a; + two: b, c; + one: d, e; + two: f; + one: g; + one: h; + one: i; + one: j; + one: k; + two: l; + one: m, n; + one: o, p; + two: q; + one: r, s; + two: t; +} +#named-conflict { + four: a, 11, 12, 13; + four: a, 21, 22, 23; +} +.test-mixin-default-arg { + defaults: 1px 1px 1px; + defaults: 2px 2px 2px; +} +.selector { + margin: 2, 2, 2, 2; +} +.selector2 { + margin: 2, 2, 2, 2; +} +.selector3 { + margin: 4; +} +mixins-args-expand-op-1 { + m3: 1, 2, 3; +} +mixins-args-expand-op-2 { + m3: 4, 5, 6; +} +mixins-args-expand-op-3a { + m3: a, b, c; +} +mixins-args-expand-op-3b { + m4: 0, a, b, c; +} +mixins-args-expand-op-3c { + m4: a, b, c, 4; +} +mixins-args-expand-op-4a { + m3: a, b, c, d; +} +mixins-args-expand-op-4b { + m4: 0, a, b, c, d; +} +mixins-args-expand-op-4c { + m4: a, b, c, d, 4; +} +mixins-args-expand-op-5a { + m3: 1, 2, 3; +} +mixins-args-expand-op-5b { + m4: 0, 1, 2, 3; +} +mixins-args-expand-op-5c { + m4: 1, 2, 3, 4; +} +mixins-args-expand-op-6 { + m4: 0, 1, 2, 3; +} +mixins-args-expand-op-7 { + m4: 0, 1, 2, 3; +} +mixins-args-expand-op-8 { + m4: 1, 1.5, 2, 3; +} +mixins-args-expand-op-9 { + aa: 4 5 6 1 2 3 and again 4 5 6; + a4: and; + a8: 5; +} +#test-mixin-matching-when-default-2645 { + height: 20px; +} diff --git a/test/css/math/parens-division/new-division.css b/test/css/math/parens-division/new-division.css new file mode 100644 index 000000000..7b2486d8d --- /dev/null +++ b/test/css/math/parens-division/new-division.css @@ -0,0 +1,16 @@ +.units { + font: 1.2rem/2rem; + font: 8vw/9vw; + font: 10vh/12vh; + font: 12vm/15vm; + font: 12vmin/15vmin; + font: 1.2ch/1.5ch; +} +.math { + a: 2; + b: 2px / 2; + c: 1px; + d: 1px; + e: 4px / 2; + f: 2px; +} diff --git a/test/css/math/parens-division/parens.css b/test/css/math/parens-division/parens.css new file mode 100644 index 000000000..5e61728b6 --- /dev/null +++ b/test/css/math/parens-division/parens.css @@ -0,0 +1,37 @@ +.parens { + border: 2px solid black; + margin: 1px 3px 16 3; + width: 36; + padding: 2px 36px; +} +.more-parens { + padding: 8 4 4 4px; + width-all: 96; + width-first: 96; + width-keep: 96; + height: calc(100% + (25vh - 20px)); + height-keep: 113; + height-all: 113; + height-parts: 113; + margin-keep: 12; + margin-parts: 12; + margin-all: 12; + border-radius-keep: 8px / 4 + 3px; + border-radius-parts: 8px / 7px; + border-radius-all: 5px; +} +.negative { + neg-var: -1; + neg-var-paren: -1; +} +.nested-parens { + width: 71; + height: 6; +} +.mixed-units { + margin: 2px 4em 1 5pc; + padding: 6px 1em 2px 2; +} +.test-false-negatives { + a: (; +} diff --git a/test/css/strict-math/css.css b/test/css/math/strict-legacy/css.css similarity index 100% rename from test/css/strict-math/css.css rename to test/css/math/strict-legacy/css.css diff --git a/test/css/math/strict-legacy/media-math.css b/test/css/math/strict-legacy/media-math.css new file mode 100644 index 000000000..1d2452a0a --- /dev/null +++ b/test/css/math/strict-legacy/media-math.css @@ -0,0 +1,10 @@ +@media (min-width: 16 + 1) { + .foo { + bar: 1; + } +} +@media (min-width: 16 / 9) { + .foo { + bar: 1; + } +} diff --git a/test/css/strict-math/mixins-args.css b/test/css/math/strict-legacy/mixins-args.css similarity index 100% rename from test/css/strict-math/mixins-args.css rename to test/css/math/strict-legacy/mixins-args.css diff --git a/test/css/strict-math/parens.css b/test/css/math/strict-legacy/parens.css similarity index 88% rename from test/css/strict-math/parens.css rename to test/css/math/strict-legacy/parens.css index 0e8cc7c8f..f880872fb 100644 --- a/test/css/strict-math/parens.css +++ b/test/css/math/strict-legacy/parens.css @@ -4,11 +4,15 @@ width: 36; padding: 2px 36px; } +.in-function { + value: 2 + 1; +} .more-parens { padding: 8 4 4 4px; width-all: 96; width-first: 16 * 6; width-keep: (4 * 4) * 6; + height: calc(100% + (25vh - 20px)); height-keep: (7 * 7) + (8 * 8); height-all: 113; height-parts: 49 + 64; @@ -21,7 +25,7 @@ } .negative { neg-var: -1; - neg-var-paren: -(1); + neg-var-paren: -1; } .nested-parens { width: 2 * (4 * (2 + (1 + 6))) - 1; diff --git a/test/css/math/strict/css.css b/test/css/math/strict/css.css new file mode 100644 index 000000000..633640781 --- /dev/null +++ b/test/css/math/strict/css.css @@ -0,0 +1,95 @@ +@charset "utf-8"; +div { + color: black; +} +div { + width: 99%; +} +* { + min-width: 45em; +} +h1, +h2 > a > p, +h3 { + color: none; +} +div.class { + color: blue; +} +div#id { + color: green; +} +.class#id { + color: purple; +} +.one.two.three { + color: grey; +} +@media print { + * { + font-size: 3em; + } +} +@media screen { + * { + font-size: 10px; + } +} +@font-face { + font-family: 'Garamond Pro'; +} +a:hover, +a:link { + color: #999; +} +p, +p:first-child { + text-transform: none; +} +q:lang(no) { + quotes: none; +} +p + h1 { + font-size: 2.2em; +} +#shorthands { + border: 1px solid #000; + font: 12px/16px Arial; + font: 100%/16px Arial; + margin: 1px 0; + padding: 0 auto; +} +#more-shorthands { + margin: 0; + padding: 1px 0 2px 0; + font: normal small / 20px 'Trebuchet MS', Verdana, sans-serif; + font: 0/0 a; + border-radius: 5px / 10px; +} +.misc { + -moz-border-radius: 2px; + display: -moz-inline-stack; + width: 0.1em; + background-color: #009998; + background: -webkit-gradient(linear, left top, left bottom, from(red), to(blue)); + margin: ; + filter: alpha(opacity=100); + width: auto\9; +} +.misc .nested-multiple { + multiple-semi-colons: yes; +} +#important { + color: red !important; + width: 100%!important; + height: 20px ! important; +} +@font-face { + font-family: font-a; +} +@font-face { + font-family: font-b; +} +.æøå { + margin: 0; +} diff --git a/test/css/math/strict/media-math.css b/test/css/math/strict/media-math.css new file mode 100644 index 000000000..1d2452a0a --- /dev/null +++ b/test/css/math/strict/media-math.css @@ -0,0 +1,10 @@ +@media (min-width: 16 + 1) { + .foo { + bar: 1; + } +} +@media (min-width: 16 / 9) { + .foo { + bar: 1; + } +} diff --git a/test/css/math/strict/mixins-args.css b/test/css/math/strict/mixins-args.css new file mode 100644 index 000000000..82a3fd14b --- /dev/null +++ b/test/css/math/strict/mixins-args.css @@ -0,0 +1,169 @@ +#hidden { + color: transparent; +} +#hidden1 { + color: transparent; +} +.two-args { + color: blue; + width: 10px; + height: 99%; + depth: 100% - 1%; + border: 2px dotted black; +} +.one-arg { + width: 15px; + height: 49%; + depth: 50% - 1%; +} +.no-parens { + width: 5px; + height: 49%; + depth: 50% - 1%; +} +.no-args { + width: 5px; + height: 49%; + depth: 50% - 1%; +} +.var-args { + width: 45; + height: 8%; + depth: 18 / 2 - 1%; +} +.multi-mix { + width: 10px; + height: 29%; + depth: 30% - 1%; + margin: 4; + padding: 5; +} +body { + padding: 30px; + color: #f00; +} +.scope-mix { + width: 8; +} +.content { + width: 600px; +} +.content .column { + margin: 600px; +} +#same-var-name { + radius: 5px; +} +#var-inside { + width: 10px; +} +.arguments { + border: 1px solid black; + width: 1px; +} +.arguments2 { + border: 0px; + width: 0px; +} +.arguments3 { + border: 0px; + width: 0px; +} +.arguments4 { + border: 0 1 2 3 4; + rest: 1 2 3 4; + width: 0; +} +.edge-case { + border: "{"; + width: "{"; +} +.slash-vs-math { + border-radius: 2px/5px; + border-radius: 5px/10px; + border-radius: 6px; +} +.comma-vs-semi-colon { + one: a; + two: b, c; + one: d, e; + two: f; + one: g; + one: h; + one: i; + one: j; + one: k; + two: l; + one: m, n; + one: o, p; + two: q; + one: r, s; + two: t; +} +#named-conflict { + four: a, 11, 12, 13; + four: a, 21, 22, 23; +} +.test-mixin-default-arg { + defaults: 1px 1px 1px; + defaults: 2px 2px 2px; +} +.selector { + margin: 2, 2, 2, 2; +} +.selector2 { + margin: 2, 2, 2, 2; +} +.selector3 { + margin: 4; +} +mixins-args-expand-op-1 { + m3: 1, 2, 3; +} +mixins-args-expand-op-2 { + m3: 4, 5, 6; +} +mixins-args-expand-op-3a { + m3: a, b, c; +} +mixins-args-expand-op-3b { + m4: 0, a, b, c; +} +mixins-args-expand-op-3c { + m4: a, b, c, 4; +} +mixins-args-expand-op-4a { + m3: a, b, c, d; +} +mixins-args-expand-op-4b { + m4: 0, a, b, c, d; +} +mixins-args-expand-op-4c { + m4: a, b, c, d, 4; +} +mixins-args-expand-op-5a { + m3: 1, 2, 3; +} +mixins-args-expand-op-5b { + m4: 0, 1, 2, 3; +} +mixins-args-expand-op-5c { + m4: 1, 2, 3, 4; +} +mixins-args-expand-op-6 { + m4: 0, 1, 2, 3; +} +mixins-args-expand-op-7 { + m4: 0, 1, 2, 3; +} +mixins-args-expand-op-8 { + m4: 1, 1.5, 2, 3; +} +mixins-args-expand-op-9 { + aa: 4 5 6 1 2 3 and again 4 5 6; + a4: and; + a8: 5; +} +#test-mixin-matching-when-default-2645 { + height: 20px; +} diff --git a/test/css/math/strict/parens.css b/test/css/math/strict/parens.css new file mode 100644 index 000000000..f7b8f9776 --- /dev/null +++ b/test/css/math/strict/parens.css @@ -0,0 +1,37 @@ +.parens { + border: 2px solid black; + margin: 1px 3px 16 3; + width: 36; + padding: 2px 36px; +} +.more-parens { + padding: 8 4 4 4px; + width-all: 96; + width-first: 16 * 6; + width-keep: 16 * 6; + height: calc(100% + (25vh - 20px)); + height-keep: 49 + 64; + height-all: 113; + height-parts: 49 + 64; + margin-keep: 20 - 8; + margin-parts: 20 - 8; + margin-all: 12; + border-radius-keep: 4px * 2 / 4 + 3px; + border-radius-parts: 8px / 7px; + border-radius-all: 5px; +} +.negative { + neg-var: -1; + neg-var-paren: -1; +} +.nested-parens { + width: 2 * 36 - 1; + height: 5 + 1; +} +.mixed-units { + margin: 2px 4em 1 5pc; + padding: 6px 1em 2px 2; +} +.test-false-negatives { + a: (; +} diff --git a/test/css/no-strict-math/no-sm-operations.css b/test/css/no-strict-math/no-sm-operations.css index 00c55660b..f720ffbf3 100644 --- a/test/css/no-strict-math/no-sm-operations.css +++ b/test/css/no-strict-math/no-sm-operations.css @@ -13,3 +13,6 @@ .named-colors-in-expressions-barred { a: a; } +.division { + value: 2px; +} diff --git a/test/index.js b/test/index.js index 7c1d314c5..24b9f961f 100644 --- a/test/index.js +++ b/test/index.js @@ -9,7 +9,6 @@ lessTester.prepBomTest(); var testMap = [ [{}, 'namespacing/'], [{ - strictMath: false, relativeUrls: true, silent: true, javascriptEnabled: true, @@ -17,24 +16,32 @@ var testMap = [ ieCompat: true }], [{ - strictMath: true, + math: 'strict-legacy', ieCompat: true - }, 'strict-math/'], + }, 'math/strict-legacy/'], + [{ + math: 'parens' + }, 'math/strict/'], + [{ + math: 'parens-division' + }, 'math/parens-division/'], + // Use legacy strictMath: true here to demonstrate it still works [{strictMath: true, strictUnits: true, javascriptEnabled: true}, 'errors/', lessTester.testErrors, null], - [{strictMath: true, strictUnits: true, javascriptEnabled: false}, 'no-js-errors/', + + [{math: 'strict', strictUnits: true, javascriptEnabled: false}, 'no-js-errors/', lessTester.testErrors, null], - [{strictMath: true, dumpLineNumbers: 'comments'}, 'debug/', null, + [{math: 'strict', dumpLineNumbers: 'comments'}, 'debug/', null, function(name) { return name + '-comments'; }], - [{strictMath: true, dumpLineNumbers: 'mediaquery'}, 'debug/', null, + [{math: 'strict', dumpLineNumbers: 'mediaquery'}, 'debug/', null, function(name) { return name + '-mediaquery'; }], - [{strictMath: true, dumpLineNumbers: 'all'}, 'debug/', null, + [{math: 'strict', dumpLineNumbers: 'all'}, 'debug/', null, function(name) { return name + '-all'; }], - [{strictMath: true, relativeUrls: false, rootpath: 'folder (1)/'}, 'static-urls/'], - [{strictMath: true, compress: true}, 'compression/'], - [{strictMath: false, strictUnits: true}, 'strict-units/'], + [{math: 'strict', relativeUrls: false, rootpath: 'folder (1)/'}, 'static-urls/'], + [{math: 'strict', compress: true}, 'compression/'], + [{math: 0, strictUnits: true}, 'strict-units/'], [{}, 'legacy/'], - [{strictMath: true, strictUnits: true, sourceMap: true, globalVars: true }, 'sourcemaps/', + [{math: 'strict', strictUnits: true, sourceMap: true, globalVars: true }, 'sourcemaps/', lessTester.testSourcemap, null, null, function(filename, type, baseFolder) { if (type === 'vars') { @@ -42,7 +49,7 @@ var testMap = [ } return path.join('test/sourcemaps', filename) + '.json'; }], - [{strictMath: true, strictUnits: true, sourceMap: {sourceMapFileInline: true}}, + [{math: 'strict', strictUnits: true, sourceMap: {sourceMapFileInline: true}}, 'sourcemaps-empty/', lessTester.testEmptySourcemap], [{globalVars: true, banner: '/**\n * Test\n */\n'}, 'globalVars/', null, null, null, function(name, type, baseFolder) { return path.join(baseFolder, name) + '.json'; }], @@ -62,7 +69,7 @@ testMap.forEach(function(args) { lessTester.runTestSet.apply(lessTester, args) }); lessTester.testSyncronous({syncImport: true}, 'import'); -lessTester.testSyncronous({syncImport: true}, 'strict-math/css'); +lessTester.testSyncronous({syncImport: true}, 'math/strict-legacy/css'); lessTester.testNoOptions(); lessTester.testJSImport(); lessTester.finished(); diff --git a/test/less/css-3.less b/test/less/css-3.less index 9f206791b..999e8019b 100644 --- a/test/less/css-3.less +++ b/test/less/css-3.less @@ -79,15 +79,6 @@ p::before { } } -.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 { diff --git a/test/less/functions.less b/test/less/functions.less index 0228bf0cb..8057a6649 100644 --- a/test/less/functions.less +++ b/test/less/functions.less @@ -263,5 +263,17 @@ html { j: if(not(true) and true, 6, 8); k: if(true or true, 1); - if(false, {g: 7}); /* results in void */ + if((false), {g: 7}); /* results in void */ + + @conditional: if((true), { + color: green; + }, {}); + @conditional(); + + @falsey: if((false), { + color: orange; + }, { + color: purple; + }); + @falsey(); } diff --git a/test/less/math/parens-division/media-math.less b/test/less/math/parens-division/media-math.less new file mode 100644 index 000000000..b3df9118e --- /dev/null +++ b/test/less/math/parens-division/media-math.less @@ -0,0 +1,9 @@ +@var: 16; + +@media (min-width: @var + 1) { + .foo { bar: 1; } +} + +@media (min-width: @var / 9) { + .foo { bar: 1; } +} \ No newline at end of file diff --git a/test/less/math/parens-division/mixins-args.less b/test/less/math/parens-division/mixins-args.less new file mode 100644 index 000000000..7b1bef0e0 --- /dev/null +++ b/test/less/math/parens-division/mixins-args.less @@ -0,0 +1,264 @@ +.mixin (@a: 1px, @b: 50%) { + width: (@a * 5); + height: (@b - 1%); + depth: @b - 1%; +} + +.mixina (@style, @width, @color: black) { + border: @width @style @color; +} + +.mixiny +(@a: 0, @b: 0) { + margin: @a; + padding: @b; +} + +.hidden() { + color: transparent; // asd +} + +#hidden { + .hidden; +} + +#hidden1 { + .hidden(); +} + +.two-args { + color: blue; + .mixin(2px, 100%); + .mixina(dotted, 2px); +} + +.one-arg { + .mixin(3px); +} + +.no-parens { + .mixin; +} + +.no-args { + .mixin(); +} + +.var-args { + @var: 9; + .mixin(@var, (@var * 2) / 2); +} + +.multi-mix { + .mixin(2px, 30%); + .mixiny(4, 5); +} + +.maxa(@arg1: 10, @arg2: #f00) { + padding: (@arg1 * 2px); + color: @arg2; +} + +body { + .maxa(15); +} + +@glob: 5; +.global-mixin(@a:2) { + width: (@glob + @a); +} + +.scope-mix { + .global-mixin(3); +} + +.nested-ruleset (@width: 200px) { + width: @width; + .column { margin: @width; } +} +.content { + .nested-ruleset(600px); +} + +// + +.same-var-name2(@radius) { + radius: @radius; +} +.same-var-name(@radius) { + .same-var-name2(@radius); +} +#same-var-name { + .same-var-name(5px); +} + +// + +.var-inside () { + @var: 10px; + width: @var; +} +#var-inside { .var-inside; } + +.mixin-arguments (@width: 0px, ...) { + border: @arguments; + width: @width; +} + +.arguments { + .mixin-arguments(1px, solid, black); +} +.arguments2 { + .mixin-arguments(); +} +.arguments3 { + .mixin-arguments; +} + +.mixin-arguments2 (@width, @rest...) { + border: @arguments; + rest: @rest; + width: @width; +} +.arguments4 { + .mixin-arguments2(0, 1, 2, 3, 4); +} + +// Edge cases + +.edge-case { + .mixin-arguments("{"); +} + +// Division vs. Literal Slash +.border-radius(@r: 2px/5px) { + border-radius: @r; +} +.slash-vs-math { + .border-radius(); + .border-radius(5px/10px); + .border-radius((3px * 2)); +} +// semi-colon vs comma for delimiting + +.mixin-takes-one(@a) { + one: @a; +} + +.mixin-takes-two(@a; @b) { + one: @a; + two: @b; +} + +.comma-vs-semi-colon { + .mixin-takes-two(@a : a; @b : b, c); + .mixin-takes-two(@a : d, e; @b : f); + .mixin-takes-one(@a: g); + .mixin-takes-one(@a : h;); + .mixin-takes-one(i); + .mixin-takes-one(j;); + .mixin-takes-two(k, l); + .mixin-takes-one(m, n;); + .mixin-takes-two(o, p; q); + .mixin-takes-two(r, s; t;); +} + +.mixin-conflict(@a:defA, @b:defB, @c:defC) { + three: @a, @b, @c; +} + +.mixin-conflict(@a:defA, @b:defB, @c:defC, @d:defD) { + four: @a, @b, @c, @d; +} + +#named-conflict { + .mixin-conflict(11, 12, 13, @a:a); + .mixin-conflict(@a:a, 21, 22, 23); +} +@a: 3px; +.mixin-default-arg(@a: 1px, @b: @a, @c: @b) { + defaults: 1px 1px 1px; + defaults: 2px 2px 2px; +} + +.test-mixin-default-arg { + .mixin-default-arg(); + .mixin-default-arg(2px); +} + +.mixin-comma-default1(@color; @padding; @margin: 2, 2, 2, 2) { + margin: @margin; +} +.selector { + .mixin-comma-default1(#33acfe; 4); +} +.mixin-comma-default2(@margin: 2, 2, 2, 2;) { + margin: @margin; +} +.selector2 { + .mixin-comma-default2(); +} +.mixin-comma-default3(@margin: 2, 2, 2, 2) { + margin: @margin; +} +.selector3 { + .mixin-comma-default3(4,2,2,2); +} + +.test-calling-one-arg-mixin(@a) { +} + +.test-calling-one-arg-mixin(@a, @b, @rest...) { +} + +div { + .test-calling-one-arg-mixin(1); +} + +mixins-args-expand-op- { + @x: 1, 2, 3; + @y: 4 5 6; + + &1 {.m3(@x...)} + &2 {.m3(@y...)} + &3 {.wr(a, b, c)} + &4 {.wr(a; b; c, d)} + &5 {.wr(@x...)} + &6 {.m4(0; @x...)} + &7 {.m4(@x..., @a: 0)} + &8 {.m4(@b: 1.5; @x...)} + &9 {.aa(@y, @x..., and again, @y...)} + + .m3(@a, @b, @c) { + m3: @a, @b, @c; + } + + .m4(@a, @b, @c, @d) { + m4: @a, @b, @c, @d; + } + + .wr(@a...) { + &a {.m3(@a...)} + &b {.m4(0, @a...)} + &c {.m4(@a..., 4)} + } + + .aa(@a...) { + aa: @a; + a4: extract(@a, 5); + a8: extract(@a, 8); + } +} +#test-mixin-matching-when-default-2645 { + .mixin(@height) { + height: @height; + } + + .mixin(@width, @height: 10px) { + width: @width; + + .mixin(@height: @height); + } + + .mixin(@height: 20px); +} \ No newline at end of file diff --git a/test/less/math/parens-division/new-division.less b/test/less/math/parens-division/new-division.less new file mode 100644 index 000000000..b81c26e26 --- /dev/null +++ b/test/less/math/parens-division/new-division.less @@ -0,0 +1,17 @@ +.units { + font: 1.2rem/2rem; + font: 8vw/9vw; + font: 10vh/12vh; + font: 12vm/15vm; + font: 12vmin/15vmin; + font: 1.2ch/1.5ch; +} + +.math { + a: 1 + 1; + b: 2px / 2; + c: 2px ./ 2; + d: (10px / 10px); + e: ((16px ./ 2) / 2) / 2; + f: ((16px ./ 2) / 2) ./ 2; +} \ No newline at end of file diff --git a/test/less/strict-math/parens.less b/test/less/math/parens-division/parens.less similarity index 94% rename from test/less/strict-math/parens.less rename to test/less/math/parens-division/parens.less index eeef34481..becbd04e6 100644 --- a/test/less/strict-math/parens.less +++ b/test/less/math/parens-division/parens.less @@ -12,6 +12,7 @@ width-all: ((@var * @var) * 6); width-first: ((@var * @var)) * 6; width-keep: (@var * @var) * 6; + height: calc(100% + (25vh - 20px)); height-keep: (7 * 7) + (8 * 8); height-all: ((7 * 7) + (8 * 8)); height-parts: ((7 * 7)) + ((8 * 8)); @@ -21,7 +22,7 @@ border-radius-keep: 4px * (1 + 1) / @var + 3px; border-radius-parts: ((4px * (1 + 1))) / ((@var + 3px)); border-radius-all: (4px * (1 + 1) / @var + 3px); - //margin: (6 * 6)px; + // margin: (6 * 6)px; } .negative { diff --git a/test/less/strict-math/css.less b/test/less/math/strict-legacy/css.less similarity index 100% rename from test/less/strict-math/css.less rename to test/less/math/strict-legacy/css.less diff --git a/test/less/math/strict-legacy/media-math.less b/test/less/math/strict-legacy/media-math.less new file mode 100644 index 000000000..b3df9118e --- /dev/null +++ b/test/less/math/strict-legacy/media-math.less @@ -0,0 +1,9 @@ +@var: 16; + +@media (min-width: @var + 1) { + .foo { bar: 1; } +} + +@media (min-width: @var / 9) { + .foo { bar: 1; } +} \ No newline at end of file diff --git a/test/less/strict-math/mixins-args.less b/test/less/math/strict-legacy/mixins-args.less similarity index 100% rename from test/less/strict-math/mixins-args.less rename to test/less/math/strict-legacy/mixins-args.less diff --git a/test/less/math/strict-legacy/parens.less b/test/less/math/strict-legacy/parens.less new file mode 100644 index 000000000..012142545 --- /dev/null +++ b/test/less/math/strict-legacy/parens.less @@ -0,0 +1,50 @@ +.parens { + @var: 1px; + border: (@var * 2) solid black; + margin: (@var * 1) (@var + 2) (4 * 4) 3; + width: (6 * 6); + padding: 2px (6 * 6px); +} + +.in-function { + value: min((1 + 1)) + 1; +} + +.more-parens { + @var: (2 * 2); + padding: (2 * @var) 4 4 (@var * 1px); + width-all: ((@var * @var) * 6); + width-first: ((@var * @var)) * 6; + width-keep: (@var * @var) * 6; + height: calc(100% + (25vh - 20px)); + height-keep: (7 * 7) + (8 * 8); + height-all: ((7 * 7) + (8 * 8)); + height-parts: ((7 * 7)) + ((8 * 8)); + margin-keep: (4 * (5 + 5) / 2) - (@var * 2); + margin-parts: ((4 * (5 + 5) / 2)) - ((@var * 2)); + margin-all: ((4 * (5 + 5) / 2) + (-(@var * 2))); + border-radius-keep: 4px * (1 + 1) / @var + 3px; + border-radius-parts: ((4px * (1 + 1))) / ((@var + 3px)); + border-radius-all: (4px * (1 + 1) / @var + 3px); + // margin: (6 * 6)px; +} + +.negative { + @var: 1; + neg-var: -@var; // -1 ? + neg-var-paren: -(@var); // -(1) ? +} + +.nested-parens { + width: 2 * (4 * (2 + (1 + 6))) - 1; + height: ((2 + 3) * (2 + 3) / (9 - 4)) + 1; +} + +.mixed-units { + margin: 2px 4em 1 5pc; + padding: (2px + 4px) 1em 2px 2; +} + +.test-false-negatives { + a: ~"("; +} diff --git a/test/less/math/strict/css.less b/test/less/math/strict/css.less new file mode 100644 index 000000000..0cdebae89 --- /dev/null +++ b/test/less/math/strict/css.less @@ -0,0 +1,108 @@ +@charset "utf-8"; +div { color: black; } +div { width: 99%; } + +* { + min-width: 45em; +} + +h1, h2 > a > p, h3 { + color: none; +} + +div.class { + color: blue; +} + +div#id { + color: green; +} + +.class#id { + color: purple; +} + +.one.two.three { + color: grey; +} + +@media print { + * { + font-size: 3em; + } +} + +@media screen { + * { + font-size: 10px; + } +} + +@font-face { + font-family: 'Garamond Pro'; +} + +a:hover, a:link { + color: #999; +} + +p, p:first-child { + text-transform: none; +} + +q:lang(no) { + quotes: none; +} + +p + h1 { + font-size: +2.2em; +} + +#shorthands { + border: 1px solid #000; + font: 12px/16px Arial; + font: 100%/16px Arial; + margin: 1px 0; + padding: 0 auto; +} + +#more-shorthands { + margin: 0; + padding: 1px 0 2px 0; + font: normal small/20px 'Trebuchet MS', Verdana, sans-serif; + font: 0/0 a; + border-radius: 5px / 10px; +} + +.misc { + -moz-border-radius: 2px; + display: -moz-inline-stack; + width: .1em; + background-color: #009998; + background: -webkit-gradient(linear, left top, left bottom, from(red), to(blue)); + margin: ; + .nested-multiple { + multiple-semi-colons: yes;;;;;; + }; + filter: alpha(opacity=100); + width: auto\9; +} + +#important { + color: red !important; + width: 100%!important; + height: 20px ! important; +} + +.def-font(@name) { + @font-face { + font-family: @name + } +} + +.def-font(font-a); +.def-font(font-b); + +.æøå { + margin: 0; +} diff --git a/test/less/math/strict/media-math.less b/test/less/math/strict/media-math.less new file mode 100644 index 000000000..b3df9118e --- /dev/null +++ b/test/less/math/strict/media-math.less @@ -0,0 +1,9 @@ +@var: 16; + +@media (min-width: @var + 1) { + .foo { bar: 1; } +} + +@media (min-width: @var / 9) { + .foo { bar: 1; } +} \ No newline at end of file diff --git a/test/less/math/strict/mixins-args.less b/test/less/math/strict/mixins-args.less new file mode 100644 index 000000000..7b1bef0e0 --- /dev/null +++ b/test/less/math/strict/mixins-args.less @@ -0,0 +1,264 @@ +.mixin (@a: 1px, @b: 50%) { + width: (@a * 5); + height: (@b - 1%); + depth: @b - 1%; +} + +.mixina (@style, @width, @color: black) { + border: @width @style @color; +} + +.mixiny +(@a: 0, @b: 0) { + margin: @a; + padding: @b; +} + +.hidden() { + color: transparent; // asd +} + +#hidden { + .hidden; +} + +#hidden1 { + .hidden(); +} + +.two-args { + color: blue; + .mixin(2px, 100%); + .mixina(dotted, 2px); +} + +.one-arg { + .mixin(3px); +} + +.no-parens { + .mixin; +} + +.no-args { + .mixin(); +} + +.var-args { + @var: 9; + .mixin(@var, (@var * 2) / 2); +} + +.multi-mix { + .mixin(2px, 30%); + .mixiny(4, 5); +} + +.maxa(@arg1: 10, @arg2: #f00) { + padding: (@arg1 * 2px); + color: @arg2; +} + +body { + .maxa(15); +} + +@glob: 5; +.global-mixin(@a:2) { + width: (@glob + @a); +} + +.scope-mix { + .global-mixin(3); +} + +.nested-ruleset (@width: 200px) { + width: @width; + .column { margin: @width; } +} +.content { + .nested-ruleset(600px); +} + +// + +.same-var-name2(@radius) { + radius: @radius; +} +.same-var-name(@radius) { + .same-var-name2(@radius); +} +#same-var-name { + .same-var-name(5px); +} + +// + +.var-inside () { + @var: 10px; + width: @var; +} +#var-inside { .var-inside; } + +.mixin-arguments (@width: 0px, ...) { + border: @arguments; + width: @width; +} + +.arguments { + .mixin-arguments(1px, solid, black); +} +.arguments2 { + .mixin-arguments(); +} +.arguments3 { + .mixin-arguments; +} + +.mixin-arguments2 (@width, @rest...) { + border: @arguments; + rest: @rest; + width: @width; +} +.arguments4 { + .mixin-arguments2(0, 1, 2, 3, 4); +} + +// Edge cases + +.edge-case { + .mixin-arguments("{"); +} + +// Division vs. Literal Slash +.border-radius(@r: 2px/5px) { + border-radius: @r; +} +.slash-vs-math { + .border-radius(); + .border-radius(5px/10px); + .border-radius((3px * 2)); +} +// semi-colon vs comma for delimiting + +.mixin-takes-one(@a) { + one: @a; +} + +.mixin-takes-two(@a; @b) { + one: @a; + two: @b; +} + +.comma-vs-semi-colon { + .mixin-takes-two(@a : a; @b : b, c); + .mixin-takes-two(@a : d, e; @b : f); + .mixin-takes-one(@a: g); + .mixin-takes-one(@a : h;); + .mixin-takes-one(i); + .mixin-takes-one(j;); + .mixin-takes-two(k, l); + .mixin-takes-one(m, n;); + .mixin-takes-two(o, p; q); + .mixin-takes-two(r, s; t;); +} + +.mixin-conflict(@a:defA, @b:defB, @c:defC) { + three: @a, @b, @c; +} + +.mixin-conflict(@a:defA, @b:defB, @c:defC, @d:defD) { + four: @a, @b, @c, @d; +} + +#named-conflict { + .mixin-conflict(11, 12, 13, @a:a); + .mixin-conflict(@a:a, 21, 22, 23); +} +@a: 3px; +.mixin-default-arg(@a: 1px, @b: @a, @c: @b) { + defaults: 1px 1px 1px; + defaults: 2px 2px 2px; +} + +.test-mixin-default-arg { + .mixin-default-arg(); + .mixin-default-arg(2px); +} + +.mixin-comma-default1(@color; @padding; @margin: 2, 2, 2, 2) { + margin: @margin; +} +.selector { + .mixin-comma-default1(#33acfe; 4); +} +.mixin-comma-default2(@margin: 2, 2, 2, 2;) { + margin: @margin; +} +.selector2 { + .mixin-comma-default2(); +} +.mixin-comma-default3(@margin: 2, 2, 2, 2) { + margin: @margin; +} +.selector3 { + .mixin-comma-default3(4,2,2,2); +} + +.test-calling-one-arg-mixin(@a) { +} + +.test-calling-one-arg-mixin(@a, @b, @rest...) { +} + +div { + .test-calling-one-arg-mixin(1); +} + +mixins-args-expand-op- { + @x: 1, 2, 3; + @y: 4 5 6; + + &1 {.m3(@x...)} + &2 {.m3(@y...)} + &3 {.wr(a, b, c)} + &4 {.wr(a; b; c, d)} + &5 {.wr(@x...)} + &6 {.m4(0; @x...)} + &7 {.m4(@x..., @a: 0)} + &8 {.m4(@b: 1.5; @x...)} + &9 {.aa(@y, @x..., and again, @y...)} + + .m3(@a, @b, @c) { + m3: @a, @b, @c; + } + + .m4(@a, @b, @c, @d) { + m4: @a, @b, @c, @d; + } + + .wr(@a...) { + &a {.m3(@a...)} + &b {.m4(0, @a...)} + &c {.m4(@a..., 4)} + } + + .aa(@a...) { + aa: @a; + a4: extract(@a, 5); + a8: extract(@a, 8); + } +} +#test-mixin-matching-when-default-2645 { + .mixin(@height) { + height: @height; + } + + .mixin(@width, @height: 10px) { + width: @width; + + .mixin(@height: @height); + } + + .mixin(@height: 20px); +} \ No newline at end of file diff --git a/test/less/math/strict/parens.less b/test/less/math/strict/parens.less new file mode 100644 index 000000000..becbd04e6 --- /dev/null +++ b/test/less/math/strict/parens.less @@ -0,0 +1,46 @@ +.parens { + @var: 1px; + border: (@var * 2) solid black; + margin: (@var * 1) (@var + 2) (4 * 4) 3; + width: (6 * 6); + padding: 2px (6 * 6px); +} + +.more-parens { + @var: (2 * 2); + padding: (2 * @var) 4 4 (@var * 1px); + width-all: ((@var * @var) * 6); + width-first: ((@var * @var)) * 6; + width-keep: (@var * @var) * 6; + height: calc(100% + (25vh - 20px)); + height-keep: (7 * 7) + (8 * 8); + height-all: ((7 * 7) + (8 * 8)); + height-parts: ((7 * 7)) + ((8 * 8)); + margin-keep: (4 * (5 + 5) / 2) - (@var * 2); + margin-parts: ((4 * (5 + 5) / 2)) - ((@var * 2)); + margin-all: ((4 * (5 + 5) / 2) + (-(@var * 2))); + border-radius-keep: 4px * (1 + 1) / @var + 3px; + border-radius-parts: ((4px * (1 + 1))) / ((@var + 3px)); + border-radius-all: (4px * (1 + 1) / @var + 3px); + // margin: (6 * 6)px; +} + +.negative { + @var: 1; + neg-var: -@var; // -1 ? + neg-var-paren: -(@var); // -(1) ? +} + +.nested-parens { + width: 2 * (4 * (2 + (1 + 6))) - 1; + height: ((2 + 3) * (2 + 3) / (9 - 4)) + 1; +} + +.mixed-units { + margin: 2px 4em 1 5pc; + padding: (2px + 4px) 1em 2px 2; +} + +.test-false-negatives { + a: ~"("; +} diff --git a/test/less/no-strict-math/no-sm-operations.less b/test/less/no-strict-math/no-sm-operations.less index e79d05009..d4bfdb977 100644 --- a/test/less/no-strict-math/no-sm-operations.less +++ b/test/less/no-strict-math/no-sm-operations.less @@ -11,3 +11,6 @@ color: green-black; animation: blue-change 5s infinite; } +.division { + value: ((16px ./ 2) / 2) / 2; +} \ No newline at end of file