[Pkg-javascript-commits] [less.js] 52/285: merge in latest 1.7.1 release

Jonas Smedegaard dr at jones.dk
Mon Oct 26 23:23:37 UTC 2015


This is an automated email from the git hooks/post-receive script.

js pushed a commit to annotated tag v2.0.0
in repository less.js.

commit fdd01f6b00eee5dd18cefda33504fdad33e938cb
Merge: dcdc76f 6b126a1
Author: Luke Page <luke.a.page at gmail.com>
Date:   Tue Jun 10 19:30:21 2014 +0100

    merge in latest 1.7.1 release

 .travis.yml                                    |    1 -
 CHANGELOG.md                                   |   18 +
 CONTRIBUTING.md                                |    2 +-
 LICENSE                                        |    2 -
 README.md                                      |    6 +-
 bin/lessc                                      |    6 +-
 build/README.md                                |    2 +
 build/rhino-modules.js                         |    2 +-
 dist/less-1.7.1.js                             | 7936 ++++++++++++++++++++
 dist/less-1.7.1.min.js                         |   16 +
 dist/less-rhino-1.7.1.js                       | 9311 ++++++++++++++++++++++++
 lib/less/rhino.js => dist/lessc-rhino-1.7.1.js |   21 +-
 lib/less/browser.js                            |   19 +-
 lib/less/environment/browser.js                |    4 +-
 lib/less/environment/node.js                   |   30 +-
 lib/less/environment/node/fs.js                |   10 +
 lib/less/functions.js                          |   12 +-
 lib/less/lessc_helper.js                       |    1 +
 lib/less/parser.js                             |    5 +
 lib/less/rhino.js                              |    4 +-
 lib/less/tree/anonymous.js                     |    4 +-
 lib/less/tree/mixin-call.js                    |    5 +-
 lib/less/tree/mixin-definition.js              |    4 +-
 lib/less/tree/quoted.js                        |   10 +-
 package.json                                   |   19 +-
 test/css/mixins-guards.css                     |   17 +-
 test/less/errors/color-invalid-hex-code.less   |    3 +
 test/less/errors/color-invalid-hex-code.txt    |    4 +
 test/less/errors/color-invalid-hex-code2.less  |    3 +
 test/less/errors/color-invalid-hex-code2.txt   |    4 +
 test/less/errors/javascript-error.less         |    2 +-
 test/less/errors/javascript-error.txt          |    4 +-
 test/less/mixins-guards.less                   |   20 +-
 test/less/mixins.less                          |    3 +
 34 files changed, 17439 insertions(+), 71 deletions(-)

diff --cc CHANGELOG.md
index ce6364c,afadae2..71af7c5
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@@ -1,13 -1,20 +1,31 @@@
 +#2.0.0
 +
 +2014-??-??
 +
 + - no longer including old versions of less in the repo or npm
 + - not including test and gradle files in npm (Note: TODO may need to move some test framework into lib for core plugins)
 + - colours now output in the format they are added unless compressing, so yellow will output yellow, not its hex counterpart
 +TODO
 + - Environment Support
 + - Finalised Plugin Support
++ 
+ # 1.7.1
+ 
+ 2014-06-08
+ 
+  - Fix detection of recursive mixins
+  - Fix the paths option for later versions of node (0.10+)
+  - Fix paths joining bug
+  - Fix a number precision issue on some versions of node
+  - Fix an IE8 issue with importing css files
+  - Fix IE11 detection for xhr requests
+  - Modify var works if the last line of a less file is a comment.
+  - Better detection of valid hex colour codes
+  - Some stability fixes to support a low number of available file handles
+  - Support comparing values with different quote types e.g. "test" now === 'test'
+  - Give better error messages if accessing a url that returns a non 200 status code
+  - Fix the e() function when passed empty string
+  - Several minor bug fixes
  
  # 1.7.0
  
diff --cc CONTRIBUTING.md
index b838412,e62f432..b3e2aae
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@@ -14,8 -14,8 +14,8 @@@ We only accept issues that are bug repo
  
  1. **Search for existing issues.** We get a lot of duplicate issues, and you'd help us out a lot by first checking if someone else has reported the same issue. Moreover, the issue may have already been resolved with a fix available.
  2. **Create an isolated and reproducible test case.** Be sure the problem exists in Less.js's code with [reduced test cases](http://css-tricks.com/reduced-test-cases/) that should be included in each bug report.
 -3. **Test with the latest version**. We get a lot of issues that could be resolved by updating your version of Less.js. 
 +3. **Test with the latest version**. We get a lot of issues that could be resolved by updating your version of Less.js.
- 3. **Include a live example.** Please use [less2css.org](http://less2css.org/) for sharing your isolated test cases.
+ 3. **Include an example with source.** E.g. You can use [less2css.org](http://less2css.org/) to create a short test case. 
  4. **Share as much information as possible.** Include operating system and version. Describe how you use Less. If you use it in the browser, please include browser and version, and the version of Less.js you're using. Let us know if you're using the command line (`lessc`) or an external tool. And try to include steps to reproduce the bug.
  5. If you have a solution or suggestion for how to fix the bug you're reporting, please include it, or make a pull request - don't assume the maintainers know how to fix it just because you do.
  
diff --cc lib/less/environment/browser.js
index 26b74cf,0000000..28b26c0
mode 100644,000000..100644
--- a/lib/less/environment/browser.js
+++ b/lib/less/environment/browser.js
@@@ -1,206 -1,0 +1,206 @@@
 +/*global window, XMLHttpRequest */
 +
 +module.exports = function(less, isFileProtocol, log, logLevel) {
 +
 +var fileCache = {};
 +
 +//TODOS - move log somewhere. pathDiff and doing something similiar in node. use pathDiff in the other browser file for the initial load
 +//        isFileProtocol is global
 +
 +function getXMLHttpRequest() {
-     if (window.XMLHttpRequest && (window.location.protocol !== "file:" || !window.ActiveXObject)) {
++    if (window.XMLHttpRequest && (window.location.protocol !== "file:" || !("ActiveXObject" in window))) {
 +        return new XMLHttpRequest();
 +    } else {
 +        try {
 +            /*global ActiveXObject */
 +            return new ActiveXObject("Microsoft.XMLHTTP");
 +        } catch (e) {
 +            log("browser doesn't support AJAX.", logLevel.errors);
 +            return null;
 +        }
 +    }
 +}
 +
 +return {
 +    // make generic but overriddable
 +    warn: function warn(env, msg) {
 +        console.warn(msg);
 +    },
 +    // make generic but overriddable
 +    getPath: function getPath(env, filename) {
 +        var j = filename.lastIndexOf('/');
 +        if (j < 0) {
 +            j = filename.lastIndexOf('\\');
 +        }
 +        if (j < 0) {
 +            return "";
 +        }
 +        return filename.slice(0, j + 1);
 +    },
 +    // make generic but overriddable
 +    isPathAbsolute: function isPathAbsolute(env, filename) {
 +        return /^(?:[a-z-]+:|\/|\\)/.test(filename);
 +    },
 +    alwaysMakePathsAbsolute: function alwaysMakePathsAbsolute() {
 +        return true;
 +    },
 +    getCleanCSS: function () {
 +    },
 +    supportsDataURI: function() {
 +        return false;
 +    },
 +    pathDiff: function pathDiff(url, baseUrl) {
 +        // diff between two paths to create a relative path
 +
 +        var urlParts = this.extractUrlParts(url),
 +            baseUrlParts = this.extractUrlParts(baseUrl),
 +            i, max, urlDirectories, baseUrlDirectories, diff = "";
 +        if (urlParts.hostPart !== baseUrlParts.hostPart) {
 +            return "";
 +        }
 +        max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);
 +        for(i = 0; i < max; i++) {
 +            if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; }
 +        }
 +        baseUrlDirectories = baseUrlParts.directories.slice(i);
 +        urlDirectories = urlParts.directories.slice(i);
 +        for(i = 0; i < baseUrlDirectories.length-1; i++) {
 +            diff += "../";
 +        }
 +        for(i = 0; i < urlDirectories.length-1; i++) {
 +            diff += urlDirectories[i] + "/";
 +        }
 +        return diff;
 +    },
 +    join: function join(basePath, laterPath) {
 +        if (!basePath) {
 +            return laterPath;
 +        }
 +        return this.extractUrlParts(laterPath, basePath).path;
 +    },
 +    // helper function, not part of API
 +    extractUrlParts: function extractUrlParts(url, baseUrl) {
 +        // urlParts[1] = protocol&hostname || /
 +        // urlParts[2] = / if path relative to host base
 +        // urlParts[3] = directories
 +        // urlParts[4] = filename
 +        // urlParts[5] = parameters
 +
 +        var urlPartsRegex = /^((?:[a-z-]+:)?\/+?(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i,
 +            urlParts = url.match(urlPartsRegex),
 +            returner = {}, directories = [], i, baseUrlParts;
 +
 +        if (!urlParts) {
 +            throw new Error("Could not parse sheet href - '"+url+"'");
 +        }
 +
 +        // Stylesheets in IE don't always return the full path
 +        if (!urlParts[1] || urlParts[2]) {
 +            baseUrlParts = baseUrl.match(urlPartsRegex);
 +            if (!baseUrlParts) {
 +                throw new Error("Could not parse page url - '"+baseUrl+"'");
 +            }
 +            urlParts[1] = urlParts[1] || baseUrlParts[1] || "";
 +            if (!urlParts[2]) {
 +                urlParts[3] = baseUrlParts[3] + urlParts[3];
 +            }
 +        }
 +
 +        if (urlParts[3]) {
 +            directories = urlParts[3].replace(/\\/g, "/").split("/");
 +
 +            // extract out . before .. so .. doesn't absorb a non-directory
 +            for(i = 0; i < directories.length; i++) {
 +                if (directories[i] === ".") {
 +                    directories.splice(i, 1);
 +                    i -= 1;
 +                }
 +            }
 +
 +            for(i = 0; i < directories.length; i++) {
 +                if (directories[i] === ".." && i > 0) {
 +                    directories.splice(i-1, 2);
 +                    i -= 2;
 +                }
 +            }
 +        }
 +
 +        returner.hostPart = urlParts[1];
 +        returner.directories = directories;
 +        returner.path = urlParts[1] + directories.join("/");
 +        returner.fileUrl = returner.path + (urlParts[4] || "");
 +        returner.url = returner.fileUrl + (urlParts[5] || "");
 +        return returner;
 +    },
 +    doXHR: function doXHR(url, type, callback, errback) {
 +
 +        var xhr = getXMLHttpRequest();
 +        var async = isFileProtocol ? less.fileAsync : less.async;
 +
 +        if (typeof(xhr.overrideMimeType) === 'function') {
 +            xhr.overrideMimeType('text/css');
 +        }
 +        log("XHR: Getting '" + url + "'", logLevel.debug);
 +        xhr.open('GET', url, async);
 +        xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
 +        xhr.send(null);
 +
 +        function handleResponse(xhr, callback, errback) {
 +            if (xhr.status >= 200 && xhr.status < 300) {
 +                callback(xhr.responseText,
 +                    xhr.getResponseHeader("Last-Modified"));
 +            } else if (typeof(errback) === 'function') {
 +                errback(xhr.status, url);
 +            }
 +        }
 +
 +        if (isFileProtocol && !less.fileAsync) {
 +            if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
 +                callback(xhr.responseText);
 +            } else {
 +                errback(xhr.status, url);
 +            }
 +        } else if (async) {
 +            xhr.onreadystatechange = function () {
 +                if (xhr.readyState == 4) {
 +                    handleResponse(xhr, callback, errback);
 +                }
 +            };
 +        } else {
 +            handleResponse(xhr, callback, errback);
 +        }
 +    },
 +    loadFile: function loadFile(env, filename, currentDirectory, callback) {
 +        if (currentDirectory && !this.isPathAbsolute(env, filename)) {
 +            filename = currentDirectory + filename;
 +        }
 +
 +        // sheet may be set to the stylesheet for the initial load or a collection of properties including
 +        // some env variables for imports
 +        var hrefParts = this.extractUrlParts(filename, window.location.href);
 +        var href      = hrefParts.url;
 +
 +        if (env.useFileCache && fileCache[href]) {
 +            try {
 +                var lessText = fileCache[href];
 +                callback(null, lessText, href, { lastModified: new Date() });
 +            } catch (e) {
 +                callback(e, null, href);
 +            }
 +            return;
 +        }
 +
 +        this.doXHR(href, env.mime, function doXHRCallback(data, lastModified) {
 +            // per file cache
 +            fileCache[href] = data;
 +
 +            // Use remote copy (re-parse)
 +            callback(null, data, href, { lastModified: lastModified });
 +        }, function doXHRError(status, url) {
 +            callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")" }, null, href);
 +        });
 +
 +    }
 +};
 +
- };
++};
diff --cc lib/less/environment/node.js
index b8ec45e,0000000..febae6b
mode 100644,000000..100644
--- a/lib/less/environment/node.js
+++ b/lib/less/environment/node.js
@@@ -1,209 -1,0 +1,221 @@@
 +var path = require('path'),
 +    url = require('url'),
 +    request,
-     fs = require('fs'),
++    fs = require('./node/fs'),
 +    isUrlRe = /^(?:https?:)?\/\//i;
 +
 +module.exports = {
 +    warn: function(env, msg) {
 +        console.warn(msg);
 +    },
 +    encodeBase64: function encodeBase64(env, str) {
 +        return new Buffer(str).toString('base64');
 +    },
 +    supportsDataURI: function(env) {
 +        return true;
 +    },
 +    mimeLookup: function (env, filename) {
 +        return require('mime').lookup(filename);
 +    },
 +    charsetLookup: function (env, mime) {
 +        return require('mime').charsets.lookup(mime);
 +    },
 +    readFileSync: function (filename) {
 +        return require("fs").readFileSync(filename);
 +    },
 +    getCleanCSS: function() {
 +        return require('clean-css');
 +    },
 +    getPath: function (env, filename) {
 +        var j = filename.lastIndexOf('/');
 +        if (j < 0) {
 +            j = filename.lastIndexOf('\\');
 +        }
 +        if (j < 0) {
 +            return "";
 +        }
 +        return filename.slice(0, j + 1);
 +    },
 +    isPathAbsolute: function(env, filename) {
 +        return (/^(?:[a-z-]+:|\/|\\)/).test(filename);
 +    },
 +    getAbsolutePath: function getAbsolutePath(env, filename) {
 +        return require('path').resolve(filename);
 +    },
 +    getSourceMapGenerator: function getSourceMapGenerator() {
 +        return require("source-map").SourceMapGenerator;
 +    },
 +    alwaysMakePathsAbsolute: function alwaysMakePathsAbsolute() {
 +        return false;
 +    },
 +    join: function join(basePath, laterPath) {
 +        if (!basePath) {
 +            return laterPath;
 +        }
 +        return basePath + laterPath;
 +    },
 +    pathDiff: function pathDiff(url, baseUrl) {
 +        // diff between two paths to create a relative path
 +
 +        var urlParts = this.extractUrlParts(url),
 +            baseUrlParts = this.extractUrlParts(baseUrl),
 +            i, max, urlDirectories, baseUrlDirectories, diff = "";
 +        if (urlParts.hostPart !== baseUrlParts.hostPart) {
 +            return "";
 +        }
 +        max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);
 +        for(i = 0; i < max; i++) {
 +            if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; }
 +        }
 +        baseUrlDirectories = baseUrlParts.directories.slice(i);
 +        urlDirectories = urlParts.directories.slice(i);
 +        for(i = 0; i < baseUrlDirectories.length-1; i++) {
 +            diff += "../";
 +        }
 +        for(i = 0; i < urlDirectories.length-1; i++) {
 +            diff += urlDirectories[i] + "/";
 +        }
 +        return diff;
 +    },
 +    // helper function, not part of API
 +    extractUrlParts: function extractUrlParts(url, baseUrl) {
 +        // urlParts[1] = protocol&hostname || /
 +        // urlParts[2] = / if path relative to host base
 +        // urlParts[3] = directories
 +        // urlParts[4] = filename
 +        // urlParts[5] = parameters
 +
 +        var urlPartsRegex = /^((?:[a-z-]+:)?\/+?(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i,
 +            urlParts = url.match(urlPartsRegex),
 +            returner = {}, directories = [], i, baseUrlParts;
 +
 +        if (!urlParts) {
 +            throw new Error("Could not parse sheet href - '"+url+"'");
 +        }
 +
 +        // Stylesheets in IE don't always return the full path
 +        if (baseUrl && (!urlParts[1] || urlParts[2])) {
 +            baseUrlParts = baseUrl.match(urlPartsRegex);
 +            if (!baseUrlParts) {
 +                throw new Error("Could not parse page url - '"+baseUrl+"'");
 +            }
 +            urlParts[1] = urlParts[1] || baseUrlParts[1] || "";
 +            if (!urlParts[2]) {
 +                urlParts[3] = baseUrlParts[3] + urlParts[3];
 +            }
 +        }
 +
 +        if (urlParts[3]) {
 +            directories = urlParts[3].replace(/\\/g, "/").split("/");
 +
 +            // extract out . before .. so .. doesn't absorb a non-directory
 +            for(i = 0; i < directories.length; i++) {
 +                if (directories[i] === ".") {
 +                    directories.splice(i, 1);
 +                    i -= 1;
 +                }
 +            }
 +
 +            for(i = 0; i < directories.length; i++) {
 +                if (directories[i] === ".." && i > 0) {
 +                    directories.splice(i-1, 2);
 +                    i -= 2;
 +                }
 +            }
 +        }
 +
 +        returner.hostPart = urlParts[1];
 +        returner.directories = directories;
 +        returner.path = urlParts[1] + directories.join("/");
 +        returner.fileUrl = returner.path + (urlParts[4] || "");
 +        returner.url = returner.fileUrl + (urlParts[5] || "");
 +        return returner;
 +    },
 +    loadFile: function(env, filename, currentDirectory, callback) {
 +        var fullFilename,
 +            data,
 +            isUrl = isUrlRe.test( filename );
 +
 +        if (isUrl || isUrlRe.test(currentDirectory)) {
 +            if (request === undefined) {
 +                try { request = require('request'); }
 +                catch(e) { request = null; }
 +            }
 +            if (!request) {
 +                callback({ type: 'File', message: "optional dependency 'request' required to import over http(s)\n" });
 +                return;
 +            }
 +
-             var urlStr = isUrl ? filename : url.resolve(currentDirectory, filename);
++            var urlStr = isUrl ? filename : url.resolve(currentDirectory, filename),
++                urlObj = url.parse(urlStr);
++
++            if (!urlObj.protocol) {
++                urlObj.protocol = "http";
++                urlStr = urlObj.format();
++            }
 +
 +            request.get({uri: urlStr, strictSSL: !env.insecure }, function (error, res, body) {
-                 if (res.statusCode === 404) {
++                if (error) {
++                    callback({ type: 'File', message: "resource '" + urlStr + "' gave this Error:\n  "+ error +"\n" });
++                }
++                if (res && res.statusCode === 404) {
 +                    callback({ type: 'File', message: "resource '" + urlStr + "' was not found\n" });
 +                    return;
 +                }
 +                if (!body) {
 +                    this.warn( env, 'Warning: Empty body (HTTP '+ res.statusCode + ') returned by "' + urlStr +'"');
 +                }
-                 if (error) {
-                     callback({ type: 'File', message: "resource '" + urlStr + "' gave this Error:\n  "+ error +"\n" });
-                 }
 +                fullFilename = urlStr;
 +                callback(null, body, fullFilename);
 +            });
 +        } else {
 +
-             var paths = [currentDirectory].concat(env.paths);
-             paths.push('.');
++            var paths = [currentDirectory];
++            if (env.paths) paths.push.apply(paths, env.paths);
++            if (paths.indexOf('.') === -1) paths.push('.');
 +
 +            if (env.syncImport) {
 +                for (var i = 0; i < paths.length; i++) {
 +                    try {
 +                        fullFilename = path.join(paths[i], filename);
 +                        fs.statSync(fullFilename);
 +                        break;
 +                    } catch (e) {
 +                        fullFilename = null;
 +                    }
 +                }
 +
 +                if (!fullFilename) {
 +                    callback({ type: 'File', message: "'" + filename + "' wasn't found" });
 +                    return;
 +                }
 +
 +                data = fs.readFileSync(fullFilename, 'utf-8');
 +                callback(null, data, fullFilename);
 +            } else {
 +                (function tryPathIndex(i) {
 +                    if (i < paths.length) {
 +                        fullFilename = path.join(paths[i], filename);
 +                        fs.stat(fullFilename, function (err) {
 +                            if (err) {
 +                                tryPathIndex(i + 1);
 +                            } else {
 +                                fs.readFile(fullFilename, 'utf-8', function(e, data) {
 +                                    if (e) { callback(e); }
-                                     callback(null, data, fullFilename);
++
++                                    // do processing in the next tick to allow
++                                    // file handling to dispose
++                                    process.nextTick(function() {
++                                        callback(null, data, fullFilename);
++                                    });
 +                                });
 +                            }
 +                        });
 +                    } else {
 +                        callback({ type: 'File', message: "'" + filename + "' wasn't found" });
 +                    }
 +                }(0));
 +            }
 +        }
 +    }
 +};
diff --cc lib/less/environment/node/fs.js
index 0000000,d124f84..d124f84
mode 000000,100644..100644
--- a/lib/less/environment/node/fs.js
+++ b/lib/less/environment/node/fs.js
diff --cc lib/less/functions.js
index c0c1dc5,0342591..14e0526
--- a/lib/less/functions.js
+++ b/lib/less/functions.js
@@@ -711,18 -749,13 +711,14 @@@ function clamp(val) 
  }
  
  tree.fround = function(env, value) {
-     var p;
-     if (env && (env.numPrecision != null)) {
-         p = Math.pow(10, env.numPrecision);
-         return Math.round(value * p) / p;
-     } else {
-         return value;
-     }
+     var p = env && env.numPrecision;
+     //add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999....) are properly rounded...
+     return (p == null) ? value : Number((value + 2e-16).toFixed(p));
  };
  
 -tree.functionCall = function(env, currentFileInfo) {
 +tree.functionCall = function(env, currentFileInfo, environment) {
      this.env = env;
 +    this.environment = environment;
      this.currentFileInfo = currentFileInfo;
  };
  
diff --cc lib/less/lessc_helper.js
index ce758b7,8f8b122..811895d
--- a/lib/less/lessc_helper.js
+++ b/lib/less/lessc_helper.js
@@@ -59,8 -59,13 +59,9 @@@ var lessc_helper = 
          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.");
          console.log("  --modify-var='VAR=VALUE' Modifies a variable already declared in the file.");
+         console.log("  --url-args='QUERYSTRING' Adds params into url tokens (e.g. 42, cb=42 or 'a=1&b=2')");
          console.log("");
          console.log("-------------------------- Deprecated ----------------");
 -        console.log("  -O0, -O1, -O2            Set the parser's optimization level. The lower");
 -        console.log("                           the number, the less nodes it will create in the");
 -        console.log("                           tree. This could matter for debugging, or if you");
 -        console.log("                           want to access the individual nodes in the tree.");
          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 --cc lib/less/tree/anonymous.js
index b81b351,d6e5790..16b08a2
--- a/lib/less/tree/anonymous.js
+++ b/lib/less/tree/anonymous.js
@@@ -1,7 -1,7 +1,7 @@@
 -(function (tree) {
 +module.exports = function (tree) {
  
- var Anonymous = function (string, index, currentFileInfo, mapLines) {
-     this.value = string.value || string;
 -tree.Anonymous = function (value, index, currentFileInfo, mapLines) {
++var Anonymous = function (value, index, currentFileInfo, mapLines) {
+     this.value = value;
      this.index = index;
      this.mapLines = mapLines;
      this.currentFileInfo = currentFileInfo;
diff --cc lib/less/tree/mixin-call.js
index de514e7,0000000..e8faebf
mode 100644,000000..100644
--- a/lib/less/tree/mixin-call.js
+++ b/lib/less/tree/mixin-call.js
@@@ -1,152 -1,0 +1,153 @@@
 +module.exports = function (tree) {
 +
 +var Call = function (elements, args, index, currentFileInfo, important) {
 +    this.selector = new(tree.Selector)(elements);
 +    this.arguments = (args && args.length) ? args : null;
 +    this.index = index;
 +    this.currentFileInfo = currentFileInfo;
 +    this.important = important;
 +};
 +Call.prototype = {
 +    type: "MixinCall",
 +    accept: function (visitor) {
 +        if (this.selector) {
 +            this.selector = visitor.visit(this.selector);
 +        }
 +        if (this.arguments) {
 +            this.arguments = visitor.visitArray(this.arguments);
 +        }
 +    },
 +    eval: function (env) {
 +        var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule,
 +            candidates = [], candidate, conditionResult = [], defaultFunc = tree.defaultFunc,
-             defaultResult, defNone = 0, defTrue = 1, defFalse = 2, count;
++            defaultResult, defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset;
 +
 +        args = this.arguments && this.arguments.map(function (a) {
 +            return { name: a.name, value: a.value.eval(env) };
 +        });
 +
 +        for (i = 0; i < env.frames.length; i++) {
 +            if ((mixins = env.frames[i].find(this.selector)).length > 0) {
 +                isOneFound = true;
 +
 +                // To make `default()` function independent of definition order we have two "subpasses" here.
 +                // At first we evaluate each guard *twice* (with `default() == true` and `default() == false`),
 +                // and build candidate list with corresponding flags. Then, when we know all possible matches,
 +                // we make a final decision.
 +
 +                for (m = 0; m < mixins.length; m++) {
 +                    mixin = mixins[m];
 +                    isRecursive = false;
 +                    for(f = 0; f < env.frames.length; f++) {
 +                        if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) {
 +                            isRecursive = true;
 +                            break;
 +                        }
 +                    }
 +                    if (isRecursive) {
 +                        continue;
 +                    }
 +
 +                    if (mixin.matchArgs(args, env)) {
 +                        candidate = {mixin: mixin, group: defNone};
 +
 +                        if (mixin.matchCondition) {
 +                            for (f = 0; f < 2; f++) {
 +                                defaultFunc.value(f);
 +                                conditionResult[f] = mixin.matchCondition(args, env);
 +                            }
 +                            if (conditionResult[0] || conditionResult[1]) {
 +                                if (conditionResult[0] != conditionResult[1]) {
 +                                    candidate.group = conditionResult[1] ?
 +                                        defTrue : defFalse;
 +                                }
 +
 +                                candidates.push(candidate);
 +                            }
 +                        }
 +                        else {
 +                            candidates.push(candidate);
 +                        }
 +
 +                        match = true;
 +                    }
 +                }
 +
 +                defaultFunc.reset();
 +
 +                count = [0, 0, 0];
 +                for (m = 0; m < candidates.length; m++) {
 +                    count[candidates[m].group]++;
 +                }
 +
 +                if (count[defNone] > 0) {
 +                    defaultResult = defFalse;
 +                } else {
 +                    defaultResult = defTrue;
 +                    if ((count[defTrue] + count[defFalse]) > 1) {
 +                        throw { type: 'Runtime',
 +                            message: 'Ambiguous use of `default()` found when matching for `'
 +                                + this.format(args) + '`',
 +                            index: this.index, filename: this.currentFileInfo.filename };
 +                    }
 +                }
 +
 +                for (m = 0; m < candidates.length; m++) {
 +                    candidate = candidates[m].group;
 +                    if ((candidate === defNone) || (candidate === defaultResult)) {
 +                        try {
 +                            mixin = candidates[m].mixin;
 +                            if (!(mixin instanceof tree.mixin.Definition)) {
++                                originalRuleset = mixin.originalRuleset || mixin;
 +                                mixin = new tree.mixin.Definition("", [], mixin.rules, null, false);
-                                 mixin.originalRuleset = mixins[m].originalRuleset || mixins[m];
++                                mixin.originalRuleset = originalRuleset;
 +                            }
 +                            Array.prototype.push.apply(
 +                                  rules, mixin.evalCall(env, args, this.important).rules);
 +                        } catch (e) {
 +                            throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack };
 +                        }
 +                    }
 +                }
 +
 +                if (match) {
 +                    if (!this.currentFileInfo || !this.currentFileInfo.reference) {
 +                        for (i = 0; i < rules.length; i++) {
 +                            rule = rules[i];
 +                            if (rule.markReferenced) {
 +                                rule.markReferenced();
 +                            }
 +                        }
 +                    }
 +                    return rules;
 +                }
 +            }
 +        }
 +        if (isOneFound) {
 +            throw { type:    'Runtime',
 +                    message: 'No matching definition was found for `' + this.format(args) + '`',
 +                    index:   this.index, filename: this.currentFileInfo.filename };
 +        } else {
 +            throw { type:    'Name',
 +                    message: this.selector.toCSS().trim() + " is undefined",
 +                    index:   this.index, filename: this.currentFileInfo.filename };
 +        }
 +    },
 +    format: function (args) {
 +        return this.selector.toCSS().trim() + '(' +
 +            (args ? args.map(function (a) {
 +                var argValue = "";
 +                if (a.name) {
 +                    argValue += a.name + ":";
 +                }
 +                if (a.value.toCSS) {
 +                    argValue += a.value.toCSS();
 +                } else {
 +                    argValue += "???";
 +                }
 +                return argValue;
 +            }).join(', ') : "") + ")";
 +    }
 +};
 +return Call;
 +};
diff --cc lib/less/tree/mixin-definition.js
index b661c31,0000000..7a891d6
mode 100644,000000..100644
--- a/lib/less/tree/mixin-definition.js
+++ b/lib/less/tree/mixin-definition.js
@@@ -1,165 -1,0 +1,165 @@@
 +module.exports = function (tree) {
 +
 +var Definition = function (name, params, rules, condition, variadic, frames) {
 +    this.name = name;
 +    this.selectors = [new(tree.Selector)([new(tree.Element)(null, name, this.index, this.currentFileInfo)])];
 +    this.params = params;
 +    this.condition = condition;
 +    this.variadic = variadic;
 +    this.arity = params.length;
 +    this.rules = rules;
 +    this._lookups = {};
 +    this.required = params.reduce(function (count, p) {
 +        if (!p.name || (p.name && !p.value)) { return count + 1; }
 +        else                                 { return count; }
 +    }, 0);
 +    this.parent = tree.Ruleset.prototype;
 +    this.frames = frames;
 +};
 +Definition.prototype = {
 +    type: "MixinDefinition",
 +    accept: function (visitor) {
 +        if (this.params && this.params.length) {
 +            this.params = visitor.visitArray(this.params);
 +        }
 +        this.rules = visitor.visitArray(this.rules);
 +        if (this.condition) {
 +            this.condition = visitor.visit(this.condition);
 +        }
 +    },
 +    variable:  function (name) { return this.parent.variable.call(this, name); },
 +    variables: function ()     { return this.parent.variables.call(this); },
 +    find:      function ()     { return this.parent.find.apply(this, arguments); },
 +    rulesets:  function ()     { return this.parent.rulesets.apply(this); },
 +
 +    evalParams: function (env, mixinEnv, args, evaldArguments) {
 +        /*jshint boss:true */
 +        var frame = new(tree.Ruleset)(null, null),
 +            varargs, arg,
 +            params = this.params.slice(0),
 +            i, j, val, name, isNamedFound, argIndex, argsLength = 0;
 +
 +        mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames));
 +
 +        if (args) {
 +            args = args.slice(0);
 +            argsLength = args.length;
 +
 +            for(i = 0; i < argsLength; i++) {
 +                arg = args[i];
 +                if (name = (arg && arg.name)) {
 +                    isNamedFound = false;
 +                    for(j = 0; j < params.length; j++) {
 +                        if (!evaldArguments[j] && name === params[j].name) {
 +                            evaldArguments[j] = arg.value.eval(env);
 +                            frame.prependRule(new(tree.Rule)(name, arg.value.eval(env)));
 +                            isNamedFound = true;
 +                            break;
 +                        }
 +                    }
 +                    if (isNamedFound) {
 +                        args.splice(i, 1);
 +                        i--;
 +                        continue;
 +                    } else {
 +                        throw { type: 'Runtime', message: "Named argument for " + this.name +
 +                            ' ' + args[i].name + ' not found' };
 +                    }
 +                }
 +            }
 +        }
 +        argIndex = 0;
 +        for (i = 0; i < params.length; i++) {
 +            if (evaldArguments[i]) { continue; }
 +
 +            arg = args && args[argIndex];
 +
 +            if (name = params[i].name) {
 +                if (params[i].variadic) {
 +                    varargs = [];
 +                    for (j = argIndex; j < argsLength; j++) {
 +                        varargs.push(args[j].value.eval(env));
 +                    }
 +                    frame.prependRule(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
 +                } else {
 +                    val = arg && arg.value;
 +                    if (val) {
 +                        val = val.eval(env);
 +                    } else if (params[i].value) {
 +                        val = params[i].value.eval(mixinEnv);
 +                        frame.resetCache();
 +                    } else {
 +                        throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
 +                            ' (' + argsLength + ' for ' + this.arity + ')' };
 +                    }
-                     
++
 +                    frame.prependRule(new(tree.Rule)(name, val));
 +                    evaldArguments[i] = val;
 +                }
 +            }
 +
 +            if (params[i].variadic && args) {
 +                for (j = argIndex; j < argsLength; j++) {
 +                    evaldArguments[j] = args[j].value.eval(env);
 +                }
 +            }
 +            argIndex++;
 +        }
 +
 +        return frame;
 +    },
 +    eval: function (env) {
 +        return new tree.mixin.Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || env.frames.slice(0));
 +    },
 +    evalCall: function (env, args, important) {
 +        var _arguments = [],
 +            mixinFrames = this.frames ? this.frames.concat(env.frames) : env.frames,
 +            frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments),
 +            rules, ruleset;
 +
 +        frame.prependRule(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
 +
 +        rules = this.rules.slice(0);
 +
 +        ruleset = new(tree.Ruleset)(null, rules);
 +        ruleset.originalRuleset = this;
 +        ruleset = ruleset.eval(new(tree.evalEnv)(env, [this, frame].concat(mixinFrames)));
 +        if (important) {
 +            ruleset = this.parent.makeImportant.apply(ruleset);
 +        }
 +        return ruleset;
 +    },
 +    matchCondition: function (args, env) {
 +        if (this.condition && !this.condition.eval(
 +            new(tree.evalEnv)(env,
-                 [this.evalParams(env, new(tree.evalEnv)(env, this.frames.concat(env.frames)), args, [])] // the parameter variables
++                [this.evalParams(env, new(tree.evalEnv)(env, this.frames ? this.frames.concat(env.frames) : env.frames), args, [])] // the parameter variables
 +                    .concat(this.frames) // the parent namespace/mixin frames
 +                    .concat(env.frames)))) { // the current environment frames
 +            return false;
 +        }
 +        return true;
 +    },
 +    matchArgs: function (args, env) {
 +        var argsLength = (args && args.length) || 0, len;
 +
 +        if (! this.variadic) {
 +            if (argsLength < this.required)                               { return false; }
 +            if (argsLength > this.params.length)                          { return false; }
 +        } else {
 +            if (argsLength < (this.required - 1))                         { return false; }
 +        }
 +
 +        len = Math.min(argsLength, this.arity);
 +
 +        for (var i = 0; i < len; i++) {
 +            if (!this.params[i].name && !this.params[i].variadic) {
 +                if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
 +                    return false;
 +                }
 +            }
 +        }
 +        return true;
 +    }
 +};
 +return Definition;
 +};
diff --cc package.json
index 6aa80da,b6f3821..21ce582
--- a/package.json
+++ b/package.json
@@@ -40,29 -40,27 +40,30 @@@
      "test": "grunt test"
    },
    "optionalDependencies": {
-     "mime": "1.2.x",
-     "request": ">=2.33.0",
+     "graceful-fs": "~2.0.3",
+     "mime": "~1.2.11",
+     "request": "~2.34.0",
      "mkdirp": "~0.3.5",
      "clean-css": "2.1.x",
 -    "source-map": "0.1.x"
 +    "source-map": "0.1.x",
 +    "promise": "~5.0.0"
    },
    "devDependencies": {
      "diff": "~1.0",
      "grunt": "~0.4.2",
      "grunt-contrib-clean": "~0.5.0",
-     "grunt-contrib-concat": "~0.3.0",
-     "grunt-contrib-connect": "~0.6.0",
+     "grunt-contrib-concat": "~0.4.0",
+     "grunt-contrib-connect": "~0.7.0",
      "grunt-contrib-jasmine": "~0.5.2",
-     "grunt-contrib-jshint": "~0.8.0",
-     "grunt-contrib-uglify": "~0.3.2",
-     "grunt-shell": "~0.6.4",
+     "grunt-contrib-jshint": "~0.10.0",
+     "grunt-contrib-uglify": "~0.4.0",
+     "grunt-shell": "~0.7.0",
      "http-server": "~0.6.1",
      "matchdep": "~0.3.0",
-     "time-grunt": "~0.2.9",
 -    "time-grunt": "~0.3.1"
 - },
++    "time-grunt": "~0.3.1",
 +    "browserify": "~3.30.2",
 +    "grunt-browserify": "~1.3.1"
 +  },
    "keywords": [
      "compile less",
      "css nesting",
diff --cc test/css/mixins-guards.css
index 516d254,59b6f93..7196077
--- a/test/css/mixins-guards.css
+++ b/test/css/mixins-guards.css
@@@ -62,14 -62,22 +62,22 @@@
    test: pass;
  }
  .colorguardtest {
 -  content: is #ff0000;
 -  content: is not #0000ff its #ff0000;
 -  content: is not #0000ff its #800080;
 +  content: is red;
 +  content: is not blue its red;
 +  content: is not blue its purple;
  }
  .stringguardtest {
-   content: is theme1;
-   content: is not theme2;
-   content: is theme1 no quotes;
+   content: "theme1" is "theme1";
+   content: "theme1" is not "theme2";
+   content: "theme1" is 'theme1';
+   content: "theme1" is not 'theme2';
+   content: 'theme1' is "theme1";
+   content: 'theme1' is not "theme2";
+   content: 'theme1' is 'theme1';
+   content: 'theme1' is not 'theme2';
+   content: theme1 is not "theme2";
+   content: theme1 is not 'theme2';
+   content: theme1 is theme1;
  }
  #tryNumberPx {
    catch: all;
diff --cc test/less/mixins-guards.less
index 47c3312,5aec2e5..525b815
--- a/test/less/mixins-guards.less
+++ b/test/less/mixins-guards.less
@@@ -107,23 -107,27 +107,27 @@@
    .equality-unit-test(2px);
  }
  
 -.colorguard(@col) when (@col = red)							{ content: is @col; }
 -.colorguard(@col) when not (blue = @col)					{ content: is not blue its @col; }
 -.colorguard(@col)											{}
 +.colorguard(@col) when (@col = red)                         { content: is @col; }
 +.colorguard(@col) when not (blue = @col)                    { content: is not blue its @col; }
 +.colorguard(@col)                                           {}
  .colorguardtest {
      .colorguard(red);
 -	.colorguard(blue);
 -	.colorguard(purple);
 +    .colorguard(blue);
 +    .colorguard(purple);
  }
  
- .stringguard(@str) when (@str = "theme1")                   { content: is theme1; }
- .stringguard(@str) when not ("theme2" = @str)               { content: is not theme2; }
- .stringguard(@str) when (~"theme1" = @str)                  { content: is theme1 no quotes; }
+ .stringguard(@str) when (@str = "theme1")					{ content: @str is "theme1"; }
+ .stringguard(@str) when not ("theme2" = @str)				{ content: @str is not "theme2"; }
+ .stringguard(@str) when (@str = 'theme1')					{ content: @str is 'theme1'; }
+ .stringguard(@str) when not ('theme2' = @str)				{ content: @str is not 'theme2'; }
+ .stringguard(@str) when (~"theme1" = @str)					{ content: @str is theme1; }
 -.stringguard(@str)											{}
 +.stringguard(@str)                                          {}
  .stringguardtest {
      .stringguard("theme1");
 -	.stringguard("theme2");
 +    .stringguard("theme2");
+     .stringguard('theme1');
+     .stringguard('theme2');
 -	.stringguard(theme1);
 +    .stringguard(theme1);
  }
  
  .mixin(...) {

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/less.js.git



More information about the Pkg-javascript-commits mailing list