diff --git a/.eslintignore b/.eslintignore index 433176838..940889ad1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,5 @@ Gruntfile.js -test/browser/vendor/* \ No newline at end of file +dist/* +tmp/* +test/browser/vendor/* +test/browser/less.min.js \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index 6a9e809eb..9713bafa8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,89 +1,71 @@ { - "env": { - "node": true - }, - "globals": {}, - - "rules": { - "no-eval": 2, - "no-use-before-define": [ - 2, - { - "functions": false - } - ], - "no-undef": 0, - "no-unused-vars": 1, - "no-caller": 2, - "no-eq-null": 1, - "guard-for-in": 2, - "no-implicit-coercion": [ - 2, - { - "boolean": false, - "string": true, - "number": true - } - ], - "no-with": 2, - "no-mixed-spaces-and-tabs": 2, - "no-multiple-empty-lines": 2, - "dot-location": [ - 2, - "property" - ], - "operator-linebreak": [ - 0, - "after" - ], - "keyword-spacing": [ - 2, - {} - ], - "space-unary-ops": [ - 2, - { - "words": false, - "nonwords": false - } - ], - "no-spaced-func": 2, - "space-before-function-paren": [ - 1, - { - "anonymous": "ignore", - "named": "never" - } - ], - "comma-dangle": [ - 2, - "never" - ], - "no-trailing-spaces": 0, - "max-len": [ - 2, - 160 - ], - "comma-style": [ - 2, - "last" - ], - "curly": [ - 2, - "all" - ], - "space-infix-ops": 2, - "spaced-comment": 1, - "space-before-blocks": [ - 2, - "always" - ], - "indent": [ - 2, - 4, - { - "SwitchCase": 1 - } - ] - } + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "plugins": ["@typescript-eslint"], + "env": { + "browser": true, + "node": true + }, + "globals": {}, + "rules": { + "no-eval": 2, + "no-use-before-define": [ + 2, + { + "functions": false + } + ], + "no-undef": 0, + "no-unused-vars": 1, + "no-caller": 2, + "no-eq-null": 1, + "guard-for-in": 2, + "no-implicit-coercion": [ + 2, + { + "boolean": false, + "string": true, + "number": true + } + ], + "no-with": 2, + "no-mixed-spaces-and-tabs": 2, + "no-multiple-empty-lines": 2, + "dot-location": [2, "property"], + "operator-linebreak": [0, "after"], + "keyword-spacing": [2, {}], + "space-unary-ops": [ + 2, + { + "words": false, + "nonwords": false + } + ], + "no-spaced-func": 2, + "space-before-function-paren": [ + 1, + { + "anonymous": "ignore", + "named": "never" + } + ], + "comma-dangle": [2, "never"], + "no-trailing-spaces": 0, + "max-len": [2, 160], + "comma-style": [2, "last"], + "curly": [2, "all"], + "space-infix-ops": 2, + "spaced-comment": 1, + "space-before-blocks": [2, "always"], + "indent": [ + 2, + 4, + { + "SwitchCase": 1 + } + ] + } } diff --git a/.gitignore b/.gitignore index 32a014709..1fa60cc30 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,8 @@ npm-debug.log # project-specific tmp -test/browser/less.js +test/browser/less.min.js +test/browser/less.min.js.map test/sourcemaps/**/*.map test/sourcemaps/*.map test/sourcemaps/*.css diff --git a/.npmignore b/.npmignore index 8a8fb6efb..9a66c1a0d 100644 --- a/.npmignore +++ b/.npmignore @@ -1,4 +1,6 @@ .gitattributes +.travis.yml +appveyor.yml build/ .grunt/ benchmark/ diff --git a/.travis.yml b/.travis.yml index 52f7d4e7c..0cd3fa893 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,8 @@ cache: directories: - travis-phantomjs node_js: - - "9" + - "12" + - "10" - "8" - "6" before_install: diff --git a/Gruntfile.js b/Gruntfile.js index f92ec2827..11bb961b0 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,111 +1,125 @@ -'use strict'; +"use strict"; -module.exports = function (grunt) { - - - grunt.option('stack', true) +module.exports = function(grunt) { + grunt.option("stack", true); // Report the elapsed execution time of tasks. - require('time-grunt')(grunt); + require("time-grunt")(grunt); var COMPRESS_FOR_TESTS = false; - var git = require('git-rev'); + var git = require("git-rev"); - // Sauce Labs browser + // Sauce Labs browser var browsers = [ // Desktop browsers { - browserName: 'chrome', - version: 'latest', - platform: 'Windows 7' + browserName: "chrome", + version: "latest", + platform: "Windows 7" }, { - browserName: 'firefox', - version: 'latest', - platform: 'Linux' + browserName: "firefox", + version: "latest", + platform: "Linux" }, { - browserName: 'safari', - version: '9', - platform: 'OS X 10.11' + browserName: "safari", + version: "9", + platform: "OS X 10.11" }, { - browserName: 'internet explorer', - version: '8', - platform: 'Windows XP' + browserName: "internet explorer", + version: "8", + platform: "Windows XP" }, { - browserName: 'internet explorer', - version: '11', - platform: 'Windows 8.1' + browserName: "internet explorer", + version: "11", + platform: "Windows 8.1" }, { - browserName: 'edge', - version: '13', - platform: 'Windows 10' + browserName: "edge", + version: "13", + platform: "Windows 10" }, // Mobile browsers { - browserName: 'ipad', - deviceName: 'iPad Air Simulator', - deviceOrientation: 'portrait', - version: '8.4', - platform: 'OS X 10.9' + browserName: "ipad", + deviceName: "iPad Air Simulator", + deviceOrientation: "portrait", + version: "8.4", + platform: "OS X 10.9" }, { - browserName: 'iphone', - deviceName: 'iPhone 5 Simulator', - deviceOrientation: 'portrait', - version: '9.3', - platform: 'OS X 10.11' + browserName: "iphone", + deviceName: "iPhone 5 Simulator", + deviceOrientation: "portrait", + version: "9.3", + platform: "OS X 10.11" }, { - browserName: 'android', - deviceName: 'Google Nexus 7 HD Emulator', - deviceOrientation: 'portrait', - version: '4.4', - platform: 'Linux' + browserName: "android", + deviceName: "Google Nexus 7 HD Emulator", + deviceOrientation: "portrait", + version: "4.4", + platform: "Linux" } ]; var sauceJobs = {}; - var browserTests = [ - 'filemanager-plugin', - 'visitor-plugin', - 'global-vars', - 'modify-vars', - 'production', - 'rootpath-relative', - 'rootpath-rewrite-urls', - 'rootpath', - 'relative-urls', - 'rewrite-urls', - 'browser', - 'no-js-errors', - 'legacy' + "filemanager-plugin", + "visitor-plugin", + "global-vars", + "modify-vars", + "production", + "rootpath-relative", + "rootpath-rewrite-urls", + "rootpath", + "relative-urls", + "rewrite-urls", + "browser", + "no-js-errors", + "legacy" ]; function makeJob(testName) { sauceJobs[testName] = { options: { - urls: testName === 'all' ? - browserTests.map(function(name) { - return 'http://localhost:8081/tmp/browser/test-runner-' + name + '.html'; - }) : - ['http://localhost:8081/tmp/browser/test-runner-' + testName + '.html'], - testname: testName === 'all' ? 'Unit Tests for Less.js' : testName, + urls: + testName === "all" + ? browserTests.map(function(name) { + return ( + "http://localhost:8081/tmp/browser/test-runner-" + + name + + ".html" + ); + }) + : [ + "http://localhost:8081/tmp/browser/test-runner-" + + testName + + ".html" + ], + testname: + testName === "all" ? "Unit Tests for Less.js" : testName, browsers: browsers, - public: 'public', + public: "public", recordVideo: false, videoUploadOnPass: false, - recordScreenshots: process.env.TRAVIS_BRANCH !== 'master', - build: process.env.TRAVIS_BRANCH === 'master' ? process.env.TRAVIS_JOB_ID : undefined, - tags: [process.env.TRAVIS_BUILD_NUMBER, process.env.TRAVIS_PULL_REQUEST, process.env.TRAVIS_BRANCH], + recordScreenshots: process.env.TRAVIS_BRANCH !== "master", + build: + process.env.TRAVIS_BRANCH === "master" + ? process.env.TRAVIS_JOB_ID + : undefined, + tags: [ + process.env.TRAVIS_BUILD_NUMBER, + process.env.TRAVIS_PULL_REQUEST, + process.env.TRAVIS_BRANCH + ], statusCheckAttempts: -1, sauceConfig: { - 'idle-timeout': 100 + "idle-timeout": 100 }, throttled: 5, onTestComplete: function(result, callback) { @@ -126,54 +140,46 @@ module.exports = function (grunt) { var pass = process.env.SAUCE_ACCESS_KEY; git.short(function(hash) { - require('phin')({ - method: 'PUT', - url: ['https://saucelabs.com/rest/v1', user, 'jobs', result.job_id].join('/'), - auth: { user: user, pass: pass }, - data: { - passed: result.passed, - build: 'build-' + hash - } - }, function (error, response) { - if (error) { - console.log(error); - callback(error); - } else if (response.statusCode !== 200) { - console.log(response); - callback(new Error('Unexpected response status')); - } else { - callback(null, result.passed); + require("phin")( + { + method: "PUT", + url: [ + "https://saucelabs.com/rest/v1", + user, + "jobs", + result.job_id + ].join("/"), + auth: { user: user, pass: pass }, + data: { + passed: result.passed, + build: "build-" + hash + } + }, + function(error, response) { + if (error) { + console.log(error); + callback(error); + } else if (response.statusCode !== 200) { + console.log(response); + callback( + new Error("Unexpected response status") + ); + } else { + callback(null, result.passed); + } } - }); + ); }); - } } }; } // Make the SauceLabs jobs - (['all'].concat(browserTests)).map(makeJob); + ["all"].concat(browserTests).map(makeJob); // Project configuration. grunt.initConfig({ - - pkg: grunt.file.readJSON('package.json'), - meta: { - copyright: 'Copyright (c) 2009-<%= grunt.template.today("yyyy") %>', - banner: '/*!\n' + - ' * Less - <%= pkg.description %> v<%= pkg.version %>\n' + - ' * http://lesscss.org\n' + - ' *\n' + - ' * <%= meta.copyright %>, <%= pkg.author.name %> <<%= pkg.author.email %>>\n' + - ' * Licensed under the <%= pkg.license %> License.\n' + - ' *\n' + - ' */\n\n' + - ' /**' + - ' * @license <%= pkg.license %>\n' + - ' */\n\n' - }, - shell: { options: { stdout: true, @@ -182,101 +188,69 @@ module.exports = function (grunt) { maxBuffer: Infinity } }, + build: { + command: [ + "node build/rollup.js --dist" + ].join(" && ") + }, + testbuild: { + command: [ + "node build/rollup.js --lessc --out=./tmp/lessc", + "node build/rollup.js --node --out=./tmp/less.cjs.js", + "node build/rollup.js --browser --out=./test/browser/less.min.js" + ].join(" && ") + }, test: { - command: 'node test/index.js' + command: "node test/index.js" }, benchmark: { - command: 'node benchmark/index.js' + command: "node benchmark/index.js" }, - opts: { // test running with all current options (using `opts` since `options` means something already) - command: [ // @TODO: make this more thorough + opts: { + // test running with all current options (using `opts` since `options` means something already) + command: [ + // @TODO: make this more thorough // CURRENT OPTIONS // --math - 'node bin/lessc --math=always test/less/lazy-eval.less tmp/lazy-eval.css', - 'node bin/lessc --math=parens-division test/less/lazy-eval.less tmp/lazy-eval.css', - 'node bin/lessc --math=parens test/less/lazy-eval.less tmp/lazy-eval.css', - 'node bin/lessc --math=strict test/less/lazy-eval.less tmp/lazy-eval.css', - 'node bin/lessc --math=strict-legacy test/less/lazy-eval.less tmp/lazy-eval.css', + "node tmp/lessc --math=always test/less/lazy-eval.less tmp/lazy-eval.css", + "node tmp/lessc --math=parens-division test/less/lazy-eval.less tmp/lazy-eval.css", + "node tmp/lessc --math=parens test/less/lazy-eval.less tmp/lazy-eval.css", + "node tmp/lessc --math=strict test/less/lazy-eval.less tmp/lazy-eval.css", + "node tmp/lessc --math=strict-legacy test/less/lazy-eval.less tmp/lazy-eval.css", // DEPRECATED OPTIONS // --strict-math - 'node bin/lessc --strict-math=on test/less/lazy-eval.less tmp/lazy-eval.css', - ].join(' && ') + "node tmp/lessc --strict-math=on test/less/lazy-eval.less tmp/lazy-eval.css" + ].join(" && ") }, plugin: { command: [ - 'node bin/lessc --clean-css="--s1 --advanced" test/less/lazy-eval.less tmp/lazy-eval.css', - 'cd lib', - 'node ../bin/lessc --clean-css="--s1 --advanced" ../test/less/lazy-eval.less ../tmp/lazy-eval.css', - 'cd ..', + 'node tmp/lessc --clean-css="--s1 --advanced" test/less/lazy-eval.less tmp/lazy-eval.css', + "cd lib", + 'node ../tmp/lessc --clean-css="--s1 --advanced" ../test/less/lazy-eval.less ../tmp/lazy-eval.css', + "cd ..", // Test multiple plugins - 'node bin/lessc --plugin=clean-css="--s1 --advanced" --plugin=autoprefix="ie 11,Edge >= 13,Chrome >= 47,Firefox >= 45,iOS >= 9.2,Safari >= 9" test/less/lazy-eval.less tmp/lazy-eval.css' - ].join(' && ') + 'node tmp/lessc --plugin=clean-css="--s1 --advanced" --plugin=autoprefix="ie 11,Edge >= 13,Chrome >= 47,Firefox >= 45,iOS >= 9.2,Safari >= 9" test/less/lazy-eval.less tmp/lazy-eval.css' + ].join(" && ") }, - 'sourcemap-test': { // quoted value doesn't seem to get picked up by time-grunt, or isn't output, at least; maybe just "sourcemap" is fine? + "sourcemap-test": { + // quoted value doesn't seem to get picked up by time-grunt, or isn't output, at least; maybe just "sourcemap" is fine? command: [ - 'node bin/lessc --source-map=test/sourcemaps/maps/import-map.map test/less/import.less test/sourcemaps/import.css', - 'node bin/lessc --source-map test/less/sourcemaps/basic.less test/sourcemaps/basic.css' - ].join(' && ') - }, - }, - - browserify: { - browser: { - src: ['./lib/less-browser/bootstrap.js'], - options: { - exclude: ['promise'], - browserifyOptions: { - standalone: 'less', - noParse: ['clone'] - } - }, - dest: 'tmp/less.js' - } - }, - concat: { - options: { - stripBanners: 'all', - banner: '<%= meta.banner %>' - }, - browsertest: { - src: COMPRESS_FOR_TESTS ? '<%= uglify.test.dest %>' : '<%= browserify.browser.dest %>', - dest: 'test/browser/less.js' - }, - dist: { - src: '<%= browserify.browser.dest %>', - dest: 'dist/less.js' - } - }, - - uglify: { - options: { - banner: '<%= meta.banner %>', - mangle: true, - compress: { - pure_getters: true - } - }, - dist: { - src: ['<%= concat.dist.dest %>'], - dest: 'dist/less.min.js' - }, - test: { - src: '<%= browserify.browser.dest %>', - dest: 'tmp/less.min.js' + "node tmp/lessc --source-map=test/sourcemaps/maps/import-map.map test/less/import.less test/sourcemaps/import.css", + "node tmp/lessc --source-map test/less/sourcemaps/basic.less test/sourcemaps/basic.css" + ].join(" && ") } }, eslint: { - target: ['Gruntfile.js', - 'test/**/*.js', - 'lib/less*/**/*.js', - 'bin/lessc', - '!test/browser/jasmine-jsreporter.js', - '!test/less/errors/plugin/plugin-error.js' + target: [ + "test/**/*.js", + "lib/less*/**/*.js", + "!test/less/errors/plugin/plugin-error.js" ], options: { - configFile: '.eslintrc.json' + configFile: ".eslintrc.json", + fix: true } }, @@ -291,287 +265,308 @@ module.exports = function (grunt) { jasmine: { options: { keepRunner: true, - host: 'http://localhost:8081/', + host: "http://localhost:8081/", + polyfills: [ + "./node_modules/phantomjs-polyfill-object-assign/object-assign-polyfill.js", + "test/browser/vendor/promise.js" + ], vendor: [ - './node_modules/phantomjs-polyfill-object-assign/object-assign-polyfill.js', - 'test/browser/vendor/promise.js', - 'test/browser/jasmine-jsreporter.js', - 'test/browser/common.js', - 'test/browser/less.js' + "test/browser/vendor/jasmine-jsreporter.js", + "test/browser/common.js", + "test/browser/less.min.js" ], - template: 'test/browser/test-runner-template.tmpl' + template: "test/browser/test-runner-template.tmpl" }, main: { // src is used to build list of less files to compile src: [ - 'test/less/*.less', - '!test/less/plugin-preeval.less', // uses ES6 syntax + "test/less/*.less", + "!test/less/plugin-preeval.less", // uses ES6 syntax // Don't test NPM import, obviously - '!test/less/plugin-module.less', - '!test/less/import-module.less', - '!test/less/javascript.less', - '!test/less/urls.less', - '!test/less/empty.less' + "!test/less/plugin-module.less", + "!test/less/import-module.less", + "!test/less/javascript.less", + "!test/less/urls.less", + "!test/less/empty.less" ], options: { - helpers: 'test/browser/runner-main-options.js', - specs: 'test/browser/runner-main-spec.js', - outfile: 'tmp/browser/test-runner-main.html' + helpers: "test/browser/runner-main-options.js", + specs: "test/browser/runner-main-spec.js", + outfile: "tmp/browser/test-runner-main.html" } }, legacy: { - src: ['test/less/legacy/*.less'], + src: ["test/less/legacy/*.less"], options: { - helpers: 'test/browser/runner-legacy-options.js', - specs: 'test/browser/runner-legacy-spec.js', - outfile: 'tmp/browser/test-runner-legacy.html' + helpers: "test/browser/runner-legacy-options.js", + specs: "test/browser/runner-legacy-spec.js", + outfile: "tmp/browser/test-runner-legacy.html" } }, strictUnits: { - src: ['test/less/strict-units/*.less'], + src: ["test/less/strict-units/*.less"], options: { - helpers: 'test/browser/runner-strict-units-options.js', - specs: 'test/browser/runner-strict-units-spec.js', - outfile: 'tmp/browser/test-runner-strict-units.html' + helpers: "test/browser/runner-strict-units-options.js", + specs: "test/browser/runner-strict-units-spec.js", + outfile: "tmp/browser/test-runner-strict-units.html" } }, errors: { - src: ['test/less/errors/*.less', '!test/less/errors/javascript-error.less', 'test/browser/less/errors/*.less'], + src: [ + "test/less/errors/*.less", + "!test/less/errors/javascript-error.less", + "test/browser/less/errors/*.less" + ], options: { timeout: 20000, - helpers: 'test/browser/runner-errors-options.js', - specs: 'test/browser/runner-errors-spec.js', - outfile: 'tmp/browser/test-runner-errors.html' + helpers: "test/browser/runner-errors-options.js", + specs: "test/browser/runner-errors-spec.js", + outfile: "tmp/browser/test-runner-errors.html" } }, noJsErrors: { - src: ['test/less/no-js-errors/*.less'], + src: ["test/less/no-js-errors/*.less"], options: { - helpers: 'test/browser/runner-no-js-errors-options.js', - specs: 'test/browser/runner-no-js-errors-spec.js', - outfile: 'tmp/browser/test-runner-no-js-errors.html' + helpers: "test/browser/runner-no-js-errors-options.js", + specs: "test/browser/runner-no-js-errors-spec.js", + outfile: "tmp/browser/test-runner-no-js-errors.html" } }, browser: { - src: ['test/browser/less/*.less', 'test/browser/less/plugin/*.less'], + src: [ + "test/browser/less/*.less", + "test/browser/less/plugin/*.less" + ], options: { - helpers: 'test/browser/runner-browser-options.js', - specs: 'test/browser/runner-browser-spec.js', - outfile: 'tmp/browser/test-runner-browser.html' + helpers: "test/browser/runner-browser-options.js", + specs: "test/browser/runner-browser-spec.js", + outfile: "tmp/browser/test-runner-browser.html" } }, relativeUrls: { - src: ['test/browser/less/relative-urls/*.less'], + src: ["test/browser/less/relative-urls/*.less"], options: { - helpers: 'test/browser/runner-relative-urls-options.js', - specs: 'test/browser/runner-relative-urls-spec.js', - outfile: 'tmp/browser/test-runner-relative-urls.html' + helpers: "test/browser/runner-relative-urls-options.js", + specs: "test/browser/runner-relative-urls-spec.js", + outfile: "tmp/browser/test-runner-relative-urls.html" } }, rewriteUrls: { - src: ['test/browser/less/rewrite-urls/*.less'], + src: ["test/browser/less/rewrite-urls/*.less"], options: { - helpers: 'test/browser/runner-rewrite-urls-options.js', - specs: 'test/browser/runner-rewrite-urls-spec.js', - outfile: 'tmp/browser/test-runner-rewrite-urls.html' + helpers: "test/browser/runner-rewrite-urls-options.js", + specs: "test/browser/runner-rewrite-urls-spec.js", + outfile: "tmp/browser/test-runner-rewrite-urls.html" } }, rootpath: { - src: ['test/browser/less/rootpath/*.less'], + src: ["test/browser/less/rootpath/*.less"], options: { - helpers: 'test/browser/runner-rootpath-options.js', - specs: 'test/browser/runner-rootpath-spec.js', - outfile: 'tmp/browser/test-runner-rootpath.html' + helpers: "test/browser/runner-rootpath-options.js", + specs: "test/browser/runner-rootpath-spec.js", + outfile: "tmp/browser/test-runner-rootpath.html" } }, rootpathRelative: { - src: ['test/browser/less/rootpath-relative/*.less'], + src: ["test/browser/less/rootpath-relative/*.less"], options: { - helpers: 'test/browser/runner-rootpath-relative-options.js', - specs: 'test/browser/runner-rootpath-relative-spec.js', - outfile: 'tmp/browser/test-runner-rootpath-relative.html' + helpers: "test/browser/runner-rootpath-relative-options.js", + specs: "test/browser/runner-rootpath-relative-spec.js", + outfile: "tmp/browser/test-runner-rootpath-relative.html" } }, rootpathRewriteUrls: { - src: ['test/browser/less/rootpath-rewrite-urls/*.less'], + src: ["test/browser/less/rootpath-rewrite-urls/*.less"], options: { - helpers: 'test/browser/runner-rootpath-rewrite-urls-options.js', - specs: 'test/browser/runner-rootpath-rewrite-urls-spec.js', - outfile: 'tmp/browser/test-runner-rootpath-rewrite-urls.html' + helpers: + "test/browser/runner-rootpath-rewrite-urls-options.js", + specs: "test/browser/runner-rootpath-rewrite-urls-spec.js", + outfile: + "tmp/browser/test-runner-rootpath-rewrite-urls.html" } }, production: { - src: ['test/browser/less/production/*.less'], + src: ["test/browser/less/production/*.less"], options: { - helpers: 'test/browser/runner-production-options.js', - specs: 'test/browser/runner-production-spec.js', - outfile: 'tmp/browser/test-runner-production.html' + helpers: "test/browser/runner-production-options.js", + specs: "test/browser/runner-production-spec.js", + outfile: "tmp/browser/test-runner-production.html" } }, modifyVars: { - src: ['test/browser/less/modify-vars/*.less'], + src: ["test/browser/less/modify-vars/*.less"], options: { - helpers: 'test/browser/runner-modify-vars-options.js', - specs: 'test/browser/runner-modify-vars-spec.js', - outfile: 'tmp/browser/test-runner-modify-vars.html' + helpers: "test/browser/runner-modify-vars-options.js", + specs: "test/browser/runner-modify-vars-spec.js", + outfile: "tmp/browser/test-runner-modify-vars.html" } }, globalVars: { - src: ['test/browser/less/global-vars/*.less'], + src: ["test/browser/less/global-vars/*.less"], options: { - helpers: 'test/browser/runner-global-vars-options.js', - specs: 'test/browser/runner-global-vars-spec.js', - outfile: 'tmp/browser/test-runner-global-vars.html' + helpers: "test/browser/runner-global-vars-options.js", + specs: "test/browser/runner-global-vars-spec.js", + outfile: "tmp/browser/test-runner-global-vars.html" } }, postProcessorPlugin: { - src: ['test/less/postProcessorPlugin/*.less'], + src: ["test/less/postProcessorPlugin/*.less"], options: { - helpers: ['test/plugins/postprocess/index.js','test/browser/runner-postProcessorPlugin-options.js'], - specs: 'test/browser/runner-postProcessorPlugin.js', - outfile: 'tmp/browser/test-runner-post-processor-plugin.html' + helpers: [ + "test/plugins/postprocess/index.js", + "test/browser/runner-postProcessorPlugin-options.js" + ], + specs: "test/browser/runner-postProcessorPlugin.js", + outfile: + "tmp/browser/test-runner-post-processor-plugin.html" } }, preProcessorPlugin: { - src: ['test/less/preProcessorPlugin/*.less'], + src: ["test/less/preProcessorPlugin/*.less"], options: { - helpers: ['test/plugins/preprocess/index.js','test/browser/runner-preProcessorPlugin-options.js'], - specs: 'test/browser/runner-preProcessorPlugin.js', - outfile: 'tmp/browser/test-runner-pre-processor-plugin.html' + helpers: [ + "test/plugins/preprocess/index.js", + "test/browser/runner-preProcessorPlugin-options.js" + ], + specs: "test/browser/runner-preProcessorPlugin.js", + outfile: "tmp/browser/test-runner-pre-processor-plugin.html" } }, visitorPlugin: { - src: ['test/less/visitorPlugin/*.less'], + src: ["test/less/visitorPlugin/*.less"], options: { - helpers: ['test/plugins/visitor/index.js','test/browser/runner-VisitorPlugin-options.js'], - specs: 'test/browser/runner-VisitorPlugin.js', - outfile: 'tmp/browser/test-runner-visitor-plugin.html' + helpers: [ + "test/plugins/visitor/index.js", + "test/browser/runner-VisitorPlugin-options.js" + ], + specs: "test/browser/runner-VisitorPlugin.js", + outfile: "tmp/browser/test-runner-visitor-plugin.html" } }, filemanagerPlugin: { - src: ['test/less/filemanagerPlugin/*.less'], + src: ["test/less/filemanagerPlugin/*.less"], options: { - helpers: ['test/plugins/filemanager/index.js','test/browser/runner-filemanagerPlugin-options.js'], - specs: 'test/browser/runner-filemanagerPlugin.js', - outfile: 'tmp/browser/test-runner-filemanager-plugin.html' + helpers: [ + "test/plugins/filemanager/index.js", + "test/browser/runner-filemanagerPlugin-options.js" + ], + specs: "test/browser/runner-filemanagerPlugin.js", + outfile: "tmp/browser/test-runner-filemanager-plugin.html" } } }, - 'saucelabs-jasmine': sauceJobs, - + "saucelabs-jasmine": sauceJobs, // Clean the version of less built for the tests clean: { - test: ['test/browser/less.js', 'tmp', 'test/less-bom'], - 'sourcemap-test': ['test/sourcemaps/*.css', 'test/sourcemaps/*.map'], - sauce_log: ['sc_*.log'] + test: ["test/browser/less.js", "tmp", "test/less-bom"], + "sourcemap-test": [ + "test/sourcemaps/*.css", + "test/sourcemaps/*.map" + ], + sauce_log: ["sc_*.log"] } }); // Load these plugins to provide the necessary tasks - grunt.loadNpmTasks('grunt-saucelabs'); + grunt.loadNpmTasks("grunt-saucelabs"); - require('jit-grunt')(grunt); + require("jit-grunt")(grunt); // by default, run tests - grunt.registerTask('default', [ - 'test' - ]); + grunt.registerTask("default", ["test"]); // Release - grunt.registerTask('dist', [ - 'browserify:browser', - 'concat:dist', - 'uglify:dist' + grunt.registerTask("dist", [ + "shell:build" ]); // Create the browser version of less.js - grunt.registerTask('browsertest-lessjs', [ - 'browserify:browser', - 'uglify:test', - 'concat:browsertest' + grunt.registerTask("browsertest-lessjs", [ + "shell:testbuild" ]); // Run all browser tests - grunt.registerTask('browsertest', [ - 'browsertest-lessjs', - 'connect', - 'jasmine' + grunt.registerTask("browsertest", [ + "browsertest-lessjs", + "connect", + "jasmine" ]); // setup a web server to run the browser tests in a browser rather than phantom - grunt.registerTask('browsertest-server', [ - 'browsertest-lessjs', - 'jasmine::build', - 'connect::keepalive' + grunt.registerTask("browsertest-server", [ + "browsertest-lessjs", + "jasmine::build", + "connect::keepalive" ]); - var previous_force_state = grunt.option('force'); + var previous_force_state = grunt.option("force"); - grunt.registerTask('force',function(set) { - if (set === 'on') { - grunt.option('force',true); - } - else if (set === 'off') { - grunt.option('force',false); - } - else if (set === 'restore') { - grunt.option('force',previous_force_state); + grunt.registerTask("force", function(set) { + if (set === "on") { + grunt.option("force", true); + } else if (set === "off") { + grunt.option("force", false); + } else if (set === "restore") { + grunt.option("force", previous_force_state); } }); - grunt.registerTask('sauce', [ - 'browsertest-lessjs', - 'jasmine::build', - 'connect', - 'sauce-after-setup' + grunt.registerTask("sauce", [ + "browsertest-lessjs", + "jasmine::build", + "connect", + "sauce-after-setup" ]); - grunt.registerTask('sauce-after-setup', [ - 'saucelabs-jasmine:all', - 'clean:sauce_log' + grunt.registerTask("sauce-after-setup", [ + "saucelabs-jasmine:all", + "clean:sauce_log" ]); var testTasks = [ - 'clean', - 'eslint', - 'shell:test', - 'shell:opts', - 'shell:plugin', - 'browsertest' + "clean", + "eslint", + "shell:testbuild", + "shell:test", + "shell:opts", + "shell:plugin", + "connect", + "jasmine" ]; - if (isNaN(Number(process.env.TRAVIS_PULL_REQUEST, 10)) && + if ( + isNaN(Number(process.env.TRAVIS_PULL_REQUEST, 10)) && Number(process.env.TRAVIS_NODE_VERSION) === 4 && - (process.env.TRAVIS_BRANCH === 'master' || process.env.TRAVIS_BRANCH === '3.x')) { - testTasks.push('force:on'); - testTasks.push('sauce-after-setup'); - testTasks.push('force:off'); + (process.env.TRAVIS_BRANCH === "master" || + process.env.TRAVIS_BRANCH === "3.x") + ) { + testTasks.push("force:on"); + testTasks.push("sauce-after-setup"); + testTasks.push("force:off"); } // Run all tests - grunt.registerTask('test', testTasks); + grunt.registerTask("test", testTasks); // Run shell option tests (includes deprecated options) - grunt.registerTask('shell-options', ['shell:opts']); + grunt.registerTask("shell-options", ["shell:opts"]); // Run shell plugin test - grunt.registerTask('shell-plugin', ['shell:plugin']); + grunt.registerTask("shell-plugin", ["shell:plugin"]); - // Run all tests - grunt.registerTask('quicktest', testTasks.slice(0, -1)); + // Run all tests except browsertest + grunt.registerTask("quicktest", testTasks.slice(0, -1)); // generate a good test environment for testing sourcemaps - grunt.registerTask('sourcemap-test', [ - 'clean:sourcemap-test', - 'shell:sourcemap-test', - 'connect::keepalive' + grunt.registerTask("sourcemap-test", [ + "clean:sourcemap-test", + "shell:build:lessc", + "shell:sourcemap-test", + "connect::keepalive" ]); // Run benchmark - grunt.registerTask('benchmark', [ - 'shell:benchmark' - ]); - + grunt.registerTask("benchmark", ["shell:benchmark"]); }; diff --git a/appveyor.yml b/appveyor.yml index e0bbf24cc..834e6fb61 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,10 +1,10 @@ # Test against these versions of Node.js. environment: matrix: - - nodejs_version: "4" - nodejs_version: "6" - nodejs_version: "8" - - nodejs_version: "9" + - nodejs_version: "10" + - nodejs_version: "12" # Install scripts. (runs after repo cloning) install: diff --git a/bin/lessc b/bin/lessc old mode 100755 new mode 100644 index c0dbf3e67..ed1ee781c --- a/bin/lessc +++ b/bin/lessc @@ -1,36 +1,12596 @@ #!/usr/bin/env node -var path = require('path'), - fs = require('../lib/less-node/fs'), - os = require('os'), - utils = require('../lib/less/utils'), - Constants = require('../lib/less/constants'), - errno, - mkdirp; +'use strict'; + +var path = require('path'); +var os = require('os'); +var CloneHelper = require('clone'); +var url = require('url'); + +let fs; + +try { + fs = require('graceful-fs'); +} catch (e) { + fs = require('fs'); +} + +var fs$1 = fs; + +const Math$1 = { + ALWAYS: 0, + PARENS_DIVISION: 1, + PARENS: 2, + STRICT_LEGACY: 3 +}; +const RewriteUrls = { + OFF: 0, + LOCAL: 1, + ALL: 2 +}; + +/* jshint proto: true */ +function getLocation(index, inputStream) { + let n = index + 1; + let line = null; + let column = -1; + + while (--n >= 0 && inputStream.charAt(n) !== '\n') { + column++; + } + + if (typeof index === 'number') { + line = (inputStream.slice(0, index).match(/\n/g) || '').length; + } + + return { + line, + column + }; +} +function copyArray(arr) { + let i; + const length = arr.length; + const copy = new Array(length); + + for (i = 0; i < length; i++) { + copy[i] = arr[i]; + } + + return copy; +} +function clone(obj) { + const cloned = {}; + + for (const prop in obj) { + if (obj.hasOwnProperty(prop)) { + cloned[prop] = obj[prop]; + } + } + + return cloned; +} +function defaults(obj1, obj2) { + let newObj = obj2 || {}; + + if (!obj2._defaults) { + newObj = {}; + const defaults = CloneHelper(obj1); + newObj._defaults = defaults; + const cloned = obj2 ? CloneHelper(obj2) : {}; + Object.assign(newObj, defaults, cloned); + } + + return newObj; +} +function copyOptions(obj1, obj2) { + if (obj2 && obj2._defaults) { + return obj2; + } + + const opts = defaults(obj1, obj2); + + if (opts.strictMath) { + opts.math = Math$1.STRICT_LEGACY; + } // Back compat with changed relativeUrls option + + + if (opts.relativeUrls) { + opts.rewriteUrls = RewriteUrls.ALL; + } + + if (typeof opts.math === 'string') { + switch (opts.math.toLowerCase()) { + case 'always': + opts.math = Math$1.ALWAYS; + break; + + case 'parens-division': + opts.math = Math$1.PARENS_DIVISION; + break; + + case 'strict': + case 'parens': + opts.math = Math$1.PARENS; + break; + + case 'strict-legacy': + opts.math = Math$1.STRICT_LEGACY; + } + } + + if (typeof opts.rewriteUrls === 'string') { + switch (opts.rewriteUrls.toLowerCase()) { + case 'off': + opts.rewriteUrls = RewriteUrls.OFF; + break; + + case 'local': + opts.rewriteUrls = RewriteUrls.LOCAL; + break; + + case 'all': + opts.rewriteUrls = RewriteUrls.ALL; + break; + } + } + + return opts; +} +function merge(obj1, obj2) { + for (const prop in obj2) { + if (obj2.hasOwnProperty(prop)) { + obj1[prop] = obj2[prop]; + } + } + + return obj1; +} +function flattenArray(arr, result = []) { + for (let i = 0, length = arr.length; i < length; i++) { + const value = arr[i]; + + if (Array.isArray(value)) { + flattenArray(value, result); + } else { + if (value !== undefined) { + result.push(value); + } + } + } + + return result; +} + +var utils = /*#__PURE__*/Object.freeze({ + getLocation: getLocation, + copyArray: copyArray, + clone: clone, + defaults: defaults, + copyOptions: copyOptions, + merge: merge, + flattenArray: flattenArray +}); + +var environment = { + encodeBase64: function encodeBase64(str) { + // Avoid Buffer constructor on newer versions of Node.js. + const buffer = Buffer.from ? Buffer.from(str) : new Buffer(str); + return buffer.toString('base64'); + }, + mimeLookup: function mimeLookup(filename) { + return require('mime').lookup(filename); + }, + charsetLookup: function charsetLookup(mime) { + return require('mime').charsets.lookup(mime); + }, + getSourceMapGenerator: function getSourceMapGenerator() { + return require('source-map').SourceMapGenerator; + } +}; + +class AbstractFileManager { + getPath(filename) { + let j = filename.lastIndexOf('?'); + + if (j > 0) { + filename = filename.slice(0, j); + } + + j = filename.lastIndexOf('/'); + + if (j < 0) { + j = filename.lastIndexOf('\\'); + } + + if (j < 0) { + return ''; + } + + return filename.slice(0, j + 1); + } + + tryAppendExtension(path, ext) { + return /(\.[a-z]*$)|([\?;].*)$/.test(path) ? path : path + ext; + } + + tryAppendLessExtension(path) { + return this.tryAppendExtension(path, '.less'); + } + + supportsSync() { + return false; + } + + alwaysMakePathsAbsolute() { + return false; + } + + isPathAbsolute(filename) { + return /^(?:[a-z-]+:|\/|\\|#)/i.test(filename); + } // TODO: pull out / replace? + + + join(basePath, laterPath) { + if (!basePath) { + return laterPath; + } + + return basePath + laterPath; + } + + pathDiff(url, baseUrl) { + // diff between two paths to create a relative path + const urlParts = this.extractUrlParts(url); + const baseUrlParts = this.extractUrlParts(baseUrl); + let i; + let max; + let urlDirectories; + let baseUrlDirectories; + let 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(url, baseUrl) { + // urlParts[1] = protocol://hostname/ OR / + // urlParts[2] = / if path relative to host base + // urlParts[3] = directories + // urlParts[4] = filename + // urlParts[5] = parameters + const urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i; + const urlParts = url.match(urlPartsRegex); + const returner = {}; + let rawDirectories = []; + const directories = []; + let i; + let 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]) { + rawDirectories = urlParts[3].replace(/\\/g, '/').split('/'); // collapse '..' and skip '.' + + for (i = 0; i < rawDirectories.length; i++) { + if (rawDirectories[i] === '..') { + directories.pop(); + } else if (rawDirectories[i] !== '.') { + directories.push(rawDirectories[i]); + } + } + } + + returner.hostPart = urlParts[1]; + returner.directories = directories; + returner.rawPath = (urlParts[1] || '') + rawDirectories.join('/'); + returner.path = (urlParts[1] || '') + directories.join('/'); + returner.filename = urlParts[4]; + returner.fileUrl = returner.path + (urlParts[4] || ''); + returner.url = returner.fileUrl + (urlParts[5] || ''); + return returner; + } + +} + +class FileManager extends AbstractFileManager { + constructor() { + super(); + this.contents = {}; + } + + supports(filename, currentDirectory, options, environment) { + return true; + } + + supportsSync(filename, currentDirectory, options, environment) { + return true; + } + + loadFile(filename, currentDirectory, options, environment, callback) { + let fullFilename; + const isAbsoluteFilename = this.isPathAbsolute(filename); + const filenamesTried = []; + const self = this; + const prefix = filename.slice(0, 1); + const explicit = prefix === '.' || prefix === '/'; + let result = null; + let isNodeModule = false; + const npmPrefix = 'npm://'; + options = options || {}; + const paths = isAbsoluteFilename ? [''] : [currentDirectory]; + + if (options.paths) { + paths.push(...options.paths); + } + + if (!isAbsoluteFilename && paths.indexOf('.') === -1) { + paths.push('.'); + } + + const prefixes = options.prefixes || ['']; + const fileParts = this.extractUrlParts(filename); + + if (options.syncImport) { + getFileData(returnData, returnData); + + if (callback) { + callback(result.error, result); + } else { + return result; + } + } else { + // promise is guaranteed to be asyncronous + // which helps as it allows the file handle + // to be closed before it continues with the next file + return new Promise(getFileData); + } + + function returnData(data) { + if (!data.filename) { + result = { + error: data + }; + } else { + result = data; + } + } + + function getFileData(fulfill, reject) { + (function tryPathIndex(i) { + if (i < paths.length) { + (function tryPrefix(j) { + if (j < prefixes.length) { + isNodeModule = false; + fullFilename = fileParts.rawPath + prefixes[j] + fileParts.filename; + + if (paths[i]) { + fullFilename = path.join(paths[i], fullFilename); + } + + if (!explicit && paths[i] === '.') { + try { + fullFilename = require.resolve(fullFilename); + isNodeModule = true; + } catch (e) { + filenamesTried.push(npmPrefix + fullFilename); + tryWithExtension(); + } + } else { + tryWithExtension(); + } + + function tryWithExtension() { + const extFilename = options.ext ? self.tryAppendExtension(fullFilename, options.ext) : fullFilename; + + if (extFilename !== fullFilename && !explicit && paths[i] === '.') { + try { + fullFilename = require.resolve(extFilename); + isNodeModule = true; + } catch (e) { + filenamesTried.push(npmPrefix + extFilename); + fullFilename = extFilename; + } + } else { + fullFilename = extFilename; + } + } + + let modified = false; + + if (self.contents[fullFilename]) { + try { + var stat = fs$1.statSync.apply(this, [fullFilename]); + + if (stat.mtime.getTime() === self.contents[fullFilename].mtime.getTime()) { + fulfill({ + contents: self.contents[fullFilename].data, + filename: fullFilename + }); + } else { + modified = true; + } + } catch (e) { + modified = true; + } + } + + if (modified || !self.contents[fullFilename]) { + const readFileArgs = [fullFilename]; + + if (!options.rawBuffer) { + readFileArgs.push('utf-8'); + } + + if (options.syncImport) { + try { + const data = fs$1.readFileSync.apply(this, readFileArgs); + var stat = fs$1.statSync.apply(this, [fullFilename]); + self.contents[fullFilename] = { + data, + mtime: stat.mtime + }; + fulfill({ + contents: data, + filename: fullFilename + }); + } catch (e) { + filenamesTried.push(isNodeModule ? npmPrefix + fullFilename : fullFilename); + return tryPrefix(j + 1); + } + } else { + readFileArgs.push(function (e, data) { + if (e) { + filenamesTried.push(isNodeModule ? npmPrefix + fullFilename : fullFilename); + return tryPrefix(j + 1); + } + + const stat = fs$1.statSync.apply(this, [fullFilename]); + self.contents[fullFilename] = { + data, + mtime: stat.mtime + }; + fulfill({ + contents: data, + filename: fullFilename + }); + }); + fs$1.readFile.apply(this, readFileArgs); + } + } + } else { + tryPathIndex(i + 1); + } + })(0); + } else { + reject({ + type: 'File', + message: `'${filename}' wasn't found. Tried - ${filenamesTried.join(',')}` + }); + } + })(0); + } + } + + loadFileSync(filename, currentDirectory, options, environment) { + options.syncImport = true; + return this.loadFile(filename, currentDirectory, options, environment); + } + +} + +var logger = { + error: function error(msg) { + this._fireEvent('error', msg); + }, + warn: function warn(msg) { + this._fireEvent('warn', msg); + }, + info: function info(msg) { + this._fireEvent('info', msg); + }, + debug: function debug(msg) { + this._fireEvent('debug', msg); + }, + addListener: function addListener(listener) { + this._listeners.push(listener); + }, + removeListener: function removeListener(listener) { + for (let i = 0; i < this._listeners.length; i++) { + if (this._listeners[i] === listener) { + this._listeners.splice(i, 1); + + return; + } + } + }, + _fireEvent: function _fireEvent(type, msg) { + for (let i = 0; i < this._listeners.length; i++) { + const logFunction = this._listeners[i][type]; + + if (logFunction) { + logFunction(msg); + } + } + }, + _listeners: [] +}; + +const isUrlRe = /^(?:https?:)?\/\//i; +let request; + +class UrlFileManager extends AbstractFileManager { + supports(filename, currentDirectory, options, environment) { + return isUrlRe.test(filename) || isUrlRe.test(currentDirectory); + } + + loadFile(filename, currentDirectory, options, environment) { + return new Promise((fulfill, reject) => { + if (request === undefined) { + try { + request = require('request'); + } catch (e) { + request = null; + } + } + + if (!request) { + reject({ + type: 'File', + message: 'optional dependency \'request\' required to import over http(s)\n' + }); + return; + } + + let urlStr = isUrlRe.test(filename) ? filename : url.resolve(currentDirectory, filename); + const urlObj = url.parse(urlStr); + + if (!urlObj.protocol) { + urlObj.protocol = 'http'; + urlStr = urlObj.format(); + } + + request.get({ + uri: urlStr, + strictSSL: !options.insecure + }, (error, res, body) => { + if (error) { + reject({ + type: 'File', + message: `resource '${urlStr}' gave this Error:\n ${error}\n` + }); + return; + } + + if (res && res.statusCode === 404) { + reject({ + type: 'File', + message: `resource '${urlStr}' was not found\n` + }); + return; + } + + if (!body) { + logger.warn(`Warning: Empty body (HTTP ${res.statusCode}) returned by "${urlStr}"`); + } + + fulfill({ + contents: body, + filename: urlStr + }); + }); + }); + } + +} + +var colors = { + 'aliceblue': '#f0f8ff', + 'antiquewhite': '#faebd7', + 'aqua': '#00ffff', + 'aquamarine': '#7fffd4', + 'azure': '#f0ffff', + 'beige': '#f5f5dc', + 'bisque': '#ffe4c4', + 'black': '#000000', + 'blanchedalmond': '#ffebcd', + 'blue': '#0000ff', + 'blueviolet': '#8a2be2', + 'brown': '#a52a2a', + 'burlywood': '#deb887', + 'cadetblue': '#5f9ea0', + 'chartreuse': '#7fff00', + 'chocolate': '#d2691e', + 'coral': '#ff7f50', + 'cornflowerblue': '#6495ed', + 'cornsilk': '#fff8dc', + 'crimson': '#dc143c', + 'cyan': '#00ffff', + 'darkblue': '#00008b', + 'darkcyan': '#008b8b', + 'darkgoldenrod': '#b8860b', + 'darkgray': '#a9a9a9', + 'darkgrey': '#a9a9a9', + 'darkgreen': '#006400', + 'darkkhaki': '#bdb76b', + 'darkmagenta': '#8b008b', + 'darkolivegreen': '#556b2f', + 'darkorange': '#ff8c00', + 'darkorchid': '#9932cc', + 'darkred': '#8b0000', + 'darksalmon': '#e9967a', + 'darkseagreen': '#8fbc8f', + 'darkslateblue': '#483d8b', + 'darkslategray': '#2f4f4f', + 'darkslategrey': '#2f4f4f', + 'darkturquoise': '#00ced1', + 'darkviolet': '#9400d3', + 'deeppink': '#ff1493', + 'deepskyblue': '#00bfff', + 'dimgray': '#696969', + 'dimgrey': '#696969', + 'dodgerblue': '#1e90ff', + 'firebrick': '#b22222', + 'floralwhite': '#fffaf0', + 'forestgreen': '#228b22', + 'fuchsia': '#ff00ff', + 'gainsboro': '#dcdcdc', + 'ghostwhite': '#f8f8ff', + 'gold': '#ffd700', + 'goldenrod': '#daa520', + 'gray': '#808080', + 'grey': '#808080', + 'green': '#008000', + 'greenyellow': '#adff2f', + 'honeydew': '#f0fff0', + 'hotpink': '#ff69b4', + 'indianred': '#cd5c5c', + 'indigo': '#4b0082', + 'ivory': '#fffff0', + 'khaki': '#f0e68c', + 'lavender': '#e6e6fa', + 'lavenderblush': '#fff0f5', + 'lawngreen': '#7cfc00', + 'lemonchiffon': '#fffacd', + 'lightblue': '#add8e6', + 'lightcoral': '#f08080', + 'lightcyan': '#e0ffff', + 'lightgoldenrodyellow': '#fafad2', + 'lightgray': '#d3d3d3', + 'lightgrey': '#d3d3d3', + 'lightgreen': '#90ee90', + 'lightpink': '#ffb6c1', + 'lightsalmon': '#ffa07a', + 'lightseagreen': '#20b2aa', + 'lightskyblue': '#87cefa', + 'lightslategray': '#778899', + 'lightslategrey': '#778899', + 'lightsteelblue': '#b0c4de', + 'lightyellow': '#ffffe0', + 'lime': '#00ff00', + 'limegreen': '#32cd32', + 'linen': '#faf0e6', + 'magenta': '#ff00ff', + 'maroon': '#800000', + 'mediumaquamarine': '#66cdaa', + 'mediumblue': '#0000cd', + 'mediumorchid': '#ba55d3', + 'mediumpurple': '#9370d8', + 'mediumseagreen': '#3cb371', + 'mediumslateblue': '#7b68ee', + 'mediumspringgreen': '#00fa9a', + 'mediumturquoise': '#48d1cc', + 'mediumvioletred': '#c71585', + 'midnightblue': '#191970', + 'mintcream': '#f5fffa', + 'mistyrose': '#ffe4e1', + 'moccasin': '#ffe4b5', + 'navajowhite': '#ffdead', + 'navy': '#000080', + 'oldlace': '#fdf5e6', + 'olive': '#808000', + 'olivedrab': '#6b8e23', + 'orange': '#ffa500', + 'orangered': '#ff4500', + 'orchid': '#da70d6', + 'palegoldenrod': '#eee8aa', + 'palegreen': '#98fb98', + 'paleturquoise': '#afeeee', + 'palevioletred': '#d87093', + 'papayawhip': '#ffefd5', + 'peachpuff': '#ffdab9', + 'peru': '#cd853f', + 'pink': '#ffc0cb', + 'plum': '#dda0dd', + 'powderblue': '#b0e0e6', + 'purple': '#800080', + 'rebeccapurple': '#663399', + 'red': '#ff0000', + 'rosybrown': '#bc8f8f', + 'royalblue': '#4169e1', + 'saddlebrown': '#8b4513', + 'salmon': '#fa8072', + 'sandybrown': '#f4a460', + 'seagreen': '#2e8b57', + 'seashell': '#fff5ee', + 'sienna': '#a0522d', + 'silver': '#c0c0c0', + 'skyblue': '#87ceeb', + 'slateblue': '#6a5acd', + 'slategray': '#708090', + 'slategrey': '#708090', + 'snow': '#fffafa', + 'springgreen': '#00ff7f', + 'steelblue': '#4682b4', + 'tan': '#d2b48c', + 'teal': '#008080', + 'thistle': '#d8bfd8', + 'tomato': '#ff6347', + 'turquoise': '#40e0d0', + 'violet': '#ee82ee', + 'wheat': '#f5deb3', + 'white': '#ffffff', + 'whitesmoke': '#f5f5f5', + 'yellow': '#ffff00', + 'yellowgreen': '#9acd32' +}; + +var unitConversions = { + length: { + 'm': 1, + 'cm': 0.01, + 'mm': 0.001, + 'in': 0.0254, + 'px': 0.0254 / 96, + 'pt': 0.0254 / 72, + 'pc': 0.0254 / 72 * 12 + }, + duration: { + 's': 1, + 'ms': 0.001 + }, + angle: { + 'rad': 1 / (2 * Math.PI), + 'deg': 1 / 360, + 'grad': 1 / 400, + 'turn': 1 + } +}; + +var data = { + colors, + unitConversions +}; + +class Node { + constructor() { + this.parent = null; + this.visibilityBlocks = undefined; + this.nodeVisible = undefined; + this.rootNode = null; + this.parsed = null; + const self = this; + Object.defineProperty(this, 'currentFileInfo', { + get: function get() { + return self.fileInfo(); + } + }); + Object.defineProperty(this, 'index', { + get: function get() { + return self.getIndex(); + } + }); + } + + setParent(nodes, parent) { + function set(node) { + if (node && node instanceof Node) { + node.parent = parent; + } + } + + if (Array.isArray(nodes)) { + nodes.forEach(set); + } else { + set(nodes); + } + } + + getIndex() { + return this._index || this.parent && this.parent.getIndex() || 0; + } + + fileInfo() { + return this._fileInfo || this.parent && this.parent.fileInfo() || {}; + } + + isRulesetLike() { + return false; + } + + toCSS(context) { + const strs = []; + this.genCSS(context, { + add: function add(chunk, fileInfo, index) { + strs.push(chunk); + }, + isEmpty: function isEmpty() { + return strs.length === 0; + } + }); + return strs.join(''); + } + + genCSS(context, output) { + output.add(this.value); + } + + accept(visitor) { + this.value = visitor.visit(this.value); + } + + eval() { + return this; + } + + _operate(context, op, a, b) { + switch (op) { + case '+': + return a + b; + + case '-': + return a - b; + + case '*': + return a * b; + + case '/': + return a / b; + } + } + + fround(context, value) { + const precision = context && context.numPrecision; // add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999...) are properly rounded: + + return precision ? Number((value + 2e-16).toFixed(precision)) : value; + } // Returns true if this node represents root of ast imported by reference + + + blocksVisibility() { + if (this.visibilityBlocks == null) { + this.visibilityBlocks = 0; + } + + return this.visibilityBlocks !== 0; + } + + addVisibilityBlock() { + if (this.visibilityBlocks == null) { + this.visibilityBlocks = 0; + } + + this.visibilityBlocks = this.visibilityBlocks + 1; + } + + removeVisibilityBlock() { + if (this.visibilityBlocks == null) { + this.visibilityBlocks = 0; + } + + this.visibilityBlocks = this.visibilityBlocks - 1; + } // Turns on node visibility - if called node will be shown in output regardless + // of whether it comes from import by reference or not + + + ensureVisibility() { + this.nodeVisible = true; + } // Turns off node visibility - if called node will NOT be shown in output regardless + // of whether it comes from import by reference or not + + + ensureInvisibility() { + this.nodeVisible = false; + } // return values: + // false - the node must not be visible + // true - the node must be visible + // undefined or null - the node has the same visibility as its parent + + + isVisible() { + return this.nodeVisible; + } + + visibilityInfo() { + return { + visibilityBlocks: this.visibilityBlocks, + nodeVisible: this.nodeVisible + }; + } + + copyVisibilityInfo(info) { + if (!info) { + return; + } + + this.visibilityBlocks = info.visibilityBlocks; + this.nodeVisible = info.nodeVisible; + } + +} + +Node.compare = (a, b) => { + /* returns: + -1: a < b + 0: a = b + 1: a > b + and *any* other value for a != b (e.g. undefined, NaN, -2 etc.) */ + if (a.compare && // for "symmetric results" force toCSS-based comparison + // of Quoted or Anonymous if either value is one of those + !(b.type === 'Quoted' || b.type === 'Anonymous')) { + return a.compare(b); + } else if (b.compare) { + return -b.compare(a); + } else if (a.type !== b.type) { + return undefined; + } + + a = a.value; + b = b.value; + + if (!Array.isArray(a)) { + return a === b ? 0 : undefined; + } + + if (a.length !== b.length) { + return undefined; + } + + for (let i = 0; i < a.length; i++) { + if (Node.compare(a[i], b[i]) !== 0) { + return undefined; + } + } + + return 0; +}; + +Node.numericCompare = (a, b) => a < b ? -1 : a === b ? 0 : a > b ? 1 : undefined; + +// RGB Colors - #ff0014, #eee +// + +class Color extends Node { + constructor(rgb, a, originalForm) { + super(); + const self = this; // + // The end goal here, is to parse the arguments + // into an integer triplet, such as `128, 255, 0` + // + // This facilitates operations and conversions. + // + + if (Array.isArray(rgb)) { + this.rgb = rgb; + } else if (rgb.length >= 6) { + this.rgb = []; + rgb.match(/.{2}/g).map((c, i) => { + if (i < 3) { + self.rgb.push(parseInt(c, 16)); + } else { + self.alpha = parseInt(c, 16) / 255; + } + }); + } else { + this.rgb = []; + rgb.split('').map((c, i) => { + if (i < 3) { + self.rgb.push(parseInt(c + c, 16)); + } else { + self.alpha = parseInt(c + c, 16) / 255; + } + }); + } + + this.alpha = this.alpha || (typeof a === 'number' ? a : 1); + + if (typeof originalForm !== 'undefined') { + this.value = originalForm; + } + } + + luma() { + let r = this.rgb[0] / 255; + let g = this.rgb[1] / 255; + let b = this.rgb[2] / 255; + r = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4); + g = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4); + b = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4); + return 0.2126 * r + 0.7152 * g + 0.0722 * b; + } + + genCSS(context, output) { + output.add(this.toCSS(context)); + } + + toCSS(context, doNotCompress) { + const compress = context && context.compress && !doNotCompress; + let color; + let alpha; + let colorFunction; + let args = []; // `value` is set if this color was originally + // converted from a named color string so we need + // to respect this and try to output named color too. + + alpha = this.fround(context, this.alpha); + + if (this.value) { + if (this.value.indexOf('rgb') === 0) { + if (alpha < 1) { + colorFunction = 'rgba'; + } + } else if (this.value.indexOf('hsl') === 0) { + if (alpha < 1) { + colorFunction = 'hsla'; + } else { + colorFunction = 'hsl'; + } + } else { + return this.value; + } + } else { + if (alpha < 1) { + colorFunction = 'rgba'; + } + } + + switch (colorFunction) { + case 'rgba': + args = this.rgb.map(c => clamp(Math.round(c), 255)).concat(clamp(alpha, 1)); + break; + + case 'hsla': + args.push(clamp(alpha, 1)); + + case 'hsl': + color = this.toHSL(); + args = [this.fround(context, color.h), `${this.fround(context, color.s * 100)}%`, `${this.fround(context, color.l * 100)}%`].concat(args); + } + + if (colorFunction) { + // Values are capped between `0` and `255`, rounded and zero-padded. + return `${colorFunction}(${args.join(`,${compress ? '' : ' '}`)})`; + } + + color = this.toRGB(); + + if (compress) { + const splitcolor = color.split(''); // Convert color to short format + + if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) { + color = `#${splitcolor[1]}${splitcolor[3]}${splitcolor[5]}`; + } + } + + return color; + } // + // Operations have to be done per-channel, if not, + // channels will spill onto each other. Once we have + // our result, in the form of an integer triplet, + // we create a new Color node to hold the result. + // + + + operate(context, op, other) { + const rgb = new Array(3); + const alpha = this.alpha * (1 - other.alpha) + other.alpha; + + for (let c = 0; c < 3; c++) { + rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]); + } + + return new Color(rgb, alpha); + } + + toRGB() { + return toHex(this.rgb); + } + + toHSL() { + const r = this.rgb[0] / 255; + const g = this.rgb[1] / 255; + const b = this.rgb[2] / 255; + const a = this.alpha; + const max = Math.max(r, g, b); + const min = Math.min(r, g, b); + let h; + let s; + const l = (max + min) / 2; + const d = max - min; + + if (max === min) { + h = s = 0; + } else { + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + + case g: + h = (b - r) / d + 2; + break; + + case b: + h = (r - g) / d + 4; + break; + } + + h /= 6; + } + + return { + h: h * 360, + s, + l, + a + }; + } // Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript + + + toHSV() { + const r = this.rgb[0] / 255; + const g = this.rgb[1] / 255; + const b = this.rgb[2] / 255; + const a = this.alpha; + const max = Math.max(r, g, b); + const min = Math.min(r, g, b); + let h; + let s; + const v = max; + const d = max - min; + + if (max === 0) { + s = 0; + } else { + s = d / max; + } + + if (max === min) { + h = 0; + } else { + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + + case g: + h = (b - r) / d + 2; + break; + + case b: + h = (r - g) / d + 4; + break; + } + + h /= 6; + } + + return { + h: h * 360, + s, + v, + a + }; + } + + toARGB() { + return toHex([this.alpha * 255].concat(this.rgb)); + } + + compare(x) { + return x.rgb && x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha ? 0 : undefined; + } + +} + +Color.prototype.type = 'Color'; + +function clamp(v, max) { + return Math.min(Math.max(v, 0), max); +} + +function toHex(v) { + return `#${v.map(c => { + c = clamp(Math.round(c), 255); + return (c < 16 ? '0' : '') + c.toString(16); + }).join('')}`; +} + +Color.fromKeyword = keyword => { + let c; + const key = keyword.toLowerCase(); + + if (colors.hasOwnProperty(key)) { + c = new Color(colors[key].slice(1)); + } else if (key === 'transparent') { + c = new Color([0, 0, 0], 0); + } + + if (c) { + c.value = keyword; + return c; + } +}; + +class Paren extends Node { + constructor(node) { + super(); + this.value = node; + } + + genCSS(context, output) { + output.add('('); + this.value.genCSS(context, output); + output.add(')'); + } + + eval(context) { + return new Paren(this.value.eval(context)); + } + +} + +Paren.prototype.type = 'Paren'; + +const _noSpaceCombinators = { + '': true, + ' ': true, + '|': true +}; + +class Combinator extends Node { + constructor(value) { + super(); + + if (value === ' ') { + this.value = ' '; + this.emptyOrWhitespace = true; + } else { + this.value = value ? value.trim() : ''; + this.emptyOrWhitespace = this.value === ''; + } + } + + genCSS(context, output) { + const spaceOrEmpty = context.compress || _noSpaceCombinators[this.value] ? '' : ' '; + output.add(spaceOrEmpty + this.value + spaceOrEmpty); + } + +} + +Combinator.prototype.type = 'Combinator'; + +class Element extends Node { + constructor(combinator, value, isVariable, index, currentFileInfo, visibilityInfo) { + super(); + this.combinator = combinator instanceof Combinator ? combinator : new Combinator(combinator); + + if (typeof value === 'string') { + this.value = value.trim(); + } else if (value) { + this.value = value; + } else { + this.value = ''; + } + + this.isVariable = isVariable; + this._index = index; + this._fileInfo = currentFileInfo; + this.copyVisibilityInfo(visibilityInfo); + this.setParent(this.combinator, this); + } + + accept(visitor) { + const value = this.value; + this.combinator = visitor.visit(this.combinator); + + if (typeof value === 'object') { + this.value = visitor.visit(value); + } + } + + eval(context) { + return new Element(this.combinator, this.value.eval ? this.value.eval(context) : this.value, this.isVariable, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } + + clone() { + return new Element(this.combinator, this.value, this.isVariable, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } + + genCSS(context, output) { + output.add(this.toCSS(context), this.fileInfo(), this.getIndex()); + } + + toCSS(context = {}) { + let value = this.value; + const firstSelector = context.firstSelector; + + if (value instanceof Paren) { + // selector in parens should not be affected by outer selector + // flags (breaks only interpolated selectors - see #1973) + context.firstSelector = true; + } + + value = value.toCSS ? value.toCSS(context) : value; + context.firstSelector = firstSelector; + + if (value === '' && this.combinator.value.charAt(0) === '&') { + return ''; + } else { + return this.combinator.toCSS(context) + value; + } + } + +} + +Element.prototype.type = 'Element'; + +/** + * This is a centralized class of any error that could be thrown internally (mostly by the parser). + * Besides standard .message it keeps some additional data like a path to the file where the error + * occurred along with line and column numbers. + * + * @class + * @extends Error + * @type {module.LessError} + * + * @prop {string} type + * @prop {string} filename + * @prop {number} index + * @prop {number} line + * @prop {number} column + * @prop {number} callLine + * @prop {number} callExtract + * @prop {string[]} extract + * + * @param {Object} e - An error object to wrap around or just a descriptive object + * @param {Object} fileContentMap - An object with file contents in 'contents' property (like importManager) @todo - move to fileManager? + * @param {string} [currentFilename] + */ + +const LessError = function LessError(e, fileContentMap, currentFilename) { + Error.call(this); + const filename = e.filename || currentFilename; + this.message = e.message; + this.stack = e.stack; + + if (fileContentMap && filename) { + const input = fileContentMap.contents[filename]; + const loc = getLocation(e.index, input); + const line = loc.line; + const col = loc.column; + const callLine = e.call && getLocation(e.call, input).line; + const lines = input ? input.split('\n') : ''; + this.type = e.type || 'Syntax'; + this.filename = filename; + this.index = e.index; + this.line = typeof line === 'number' ? line + 1 : null; + this.column = col; + + if (!this.line && this.stack) { + const found = this.stack.match(/(|Function):(\d+):(\d+)/); + + if (found) { + if (found[2]) { + this.line = parseInt(found[2]) - 2; + } + + if (found[3]) { + this.column = parseInt(found[3]); + } + } + } + + this.callLine = callLine + 1; + this.callExtract = lines[callLine]; + this.extract = [lines[this.line - 2], lines[this.line - 1], lines[this.line]]; + } +}; + +if (typeof Object.create === 'undefined') { + const F = () => {}; + + F.prototype = Error.prototype; + LessError.prototype = new F(); +} else { + LessError.prototype = Object.create(Error.prototype); +} + +LessError.prototype.constructor = LessError; +/** + * An overridden version of the default Object.prototype.toString + * which uses additional information to create a helpful message. + * + * @param {Object} options + * @returns {string} + */ + +LessError.prototype.toString = function (options = {}) { + let message = ''; + const extract = this.extract || []; + let error = []; + + let stylize = str => str; + + if (options.stylize) { + const type = typeof options.stylize; + + if (type !== 'function') { + throw Error(`options.stylize should be a function, got a ${type}!`); + } + + stylize = options.stylize; + } + + if (this.line !== null) { + if (typeof extract[0] === 'string') { + error.push(stylize(`${this.line - 1} ${extract[0]}`, 'grey')); + } + + if (typeof extract[1] === 'string') { + let errorTxt = `${this.line} `; + + if (extract[1]) { + errorTxt += extract[1].slice(0, this.column) + stylize(stylize(stylize(extract[1].substr(this.column, 1), 'bold') + extract[1].slice(this.column + 1), 'red'), 'inverse'); + } + + error.push(errorTxt); + } + + if (typeof extract[2] === 'string') { + error.push(stylize(`${this.line + 1} ${extract[2]}`, 'grey')); + } + + error = `${error.join('\n') + stylize('', 'reset')}\n`; + } + + message += stylize(`${this.type}Error: ${this.message}`, 'red'); + + if (this.filename) { + message += stylize(' in ', 'red') + this.filename; + } + + if (this.line) { + message += stylize(` on line ${this.line}, column ${this.column + 1}:`, 'grey'); + } + + message += `\n${error}`; + + if (this.callLine) { + message += `${stylize('from ', 'red') + (this.filename || '')}/n`; + message += `${stylize(this.callLine, 'grey')} ${this.callExtract}/n`; + } + + return message; +}; + +class Selector extends Node { + constructor(elements, extendList, condition, index, currentFileInfo, visibilityInfo) { + super(); + this.extendList = extendList; + this.condition = condition; + this.evaldCondition = !condition; + this._index = index; + this._fileInfo = currentFileInfo; + this.elements = this.getElements(elements); + this.mixinElements_ = undefined; + this.copyVisibilityInfo(visibilityInfo); + this.setParent(this.elements, this); + } + + accept(visitor) { + if (this.elements) { + this.elements = visitor.visitArray(this.elements); + } + + if (this.extendList) { + this.extendList = visitor.visitArray(this.extendList); + } + + if (this.condition) { + this.condition = visitor.visit(this.condition); + } + } + + createDerived(elements, extendList, evaldCondition) { + elements = this.getElements(elements); + const newSelector = new Selector(elements, extendList || this.extendList, null, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + newSelector.evaldCondition = evaldCondition != null ? evaldCondition : this.evaldCondition; + newSelector.mediaEmpty = this.mediaEmpty; + return newSelector; + } + + getElements(els) { + if (!els) { + return [new Element('', '&', false, this._index, this._fileInfo)]; + } + + if (typeof els === 'string') { + this.parse.parseNode(els, ['selector'], this._index, this._fileInfo, function (err, result) { + if (err) { + throw new LessError({ + index: err.index, + message: err.message + }, this.parse.imports, this._fileInfo.filename); + } + + els = result[0].elements; + }); + } + + return els; + } + + createEmptySelectors() { + const el = new Element('', '&', false, this._index, this._fileInfo); + const sels = [new Selector([el], null, null, this._index, this._fileInfo)]; + sels[0].mediaEmpty = true; + return sels; + } + + match(other) { + const elements = this.elements; + const len = elements.length; + let olen; + let i; + other = other.mixinElements(); + olen = other.length; + + if (olen === 0 || len < olen) { + return 0; + } else { + for (i = 0; i < olen; i++) { + if (elements[i].value !== other[i]) { + return 0; + } + } + } + + return olen; // return number of matched elements + } + + mixinElements() { + if (this.mixinElements_) { + return this.mixinElements_; + } + + let elements = this.elements.map(v => v.combinator.value + (v.value.value || v.value)).join('').match(/[,&#\*\.\w-]([\w-]|(\\.))*/g); + + if (elements) { + if (elements[0] === '&') { + elements.shift(); + } + } else { + elements = []; + } + + return this.mixinElements_ = elements; + } + + isJustParentSelector() { + return !this.mediaEmpty && this.elements.length === 1 && this.elements[0].value === '&' && (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === ''); + } + + eval(context) { + const evaldCondition = this.condition && this.condition.eval(context); + let elements = this.elements; + let extendList = this.extendList; + elements = elements && elements.map(e => e.eval(context)); + extendList = extendList && extendList.map(extend => extend.eval(context)); + return this.createDerived(elements, extendList, evaldCondition); + } + + genCSS(context, output) { + let i; + let element; + + if ((!context || !context.firstSelector) && this.elements[0].combinator.value === '') { + output.add(' ', this.fileInfo(), this.getIndex()); + } + + for (i = 0; i < this.elements.length; i++) { + element = this.elements[i]; + element.genCSS(context, output); + } + } + + getIsOutput() { + return this.evaldCondition; + } + +} + +Selector.prototype.type = 'Selector'; + +class Value extends Node { + constructor(value) { + super(); + + if (!value) { + throw new Error('Value requires an array argument'); + } + + if (!Array.isArray(value)) { + this.value = [value]; + } else { + this.value = value; + } + } + + accept(visitor) { + if (this.value) { + this.value = visitor.visitArray(this.value); + } + } + + eval(context) { + if (this.value.length === 1) { + return this.value[0].eval(context); + } else { + return new Value(this.value.map(v => v.eval(context))); + } + } + + genCSS(context, output) { + let i; + + for (i = 0; i < this.value.length; i++) { + this.value[i].genCSS(context, output); + + if (i + 1 < this.value.length) { + output.add(context && context.compress ? ',' : ', '); + } + } + } + +} + +Value.prototype.type = 'Value'; + +class Keyword extends Node { + constructor(value) { + super(); + this.value = value; + } + + genCSS(context, output) { + if (this.value === '%') { + throw { + type: 'Syntax', + message: 'Invalid % without number' + }; + } + + output.add(this.value); + } + +} + +Keyword.prototype.type = 'Keyword'; +Keyword.True = new Keyword('true'); +Keyword.False = new Keyword('false'); + +class Anonymous extends Node { + constructor(value, index, currentFileInfo, mapLines, rulesetLike, visibilityInfo) { + super(); + this.value = value; + this._index = index; + this._fileInfo = currentFileInfo; + this.mapLines = mapLines; + this.rulesetLike = typeof rulesetLike === 'undefined' ? false : rulesetLike; + this.allowRoot = true; + this.copyVisibilityInfo(visibilityInfo); + } + + eval() { + return new Anonymous(this.value, this._index, this._fileInfo, this.mapLines, this.rulesetLike, this.visibilityInfo()); + } + + compare(other) { + return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; + } + + isRulesetLike() { + return this.rulesetLike; + } + + genCSS(context, output) { + this.nodeVisible = Boolean(this.value); + + if (this.nodeVisible) { + output.add(this.value, this._fileInfo, this._index, this.mapLines); + } + } + +} + +Anonymous.prototype.type = 'Anonymous'; + +const MATH = Math$1; + +class Declaration extends Node { + constructor(name, value, important, merge, index, currentFileInfo, inline, variable) { + super(); + this.name = name; + this.value = value instanceof Node ? value : new Value([value ? new Anonymous(value) : null]); + this.important = important ? ` ${important.trim()}` : ''; + this.merge = merge; + this._index = index; + this._fileInfo = currentFileInfo; + this.inline = inline || false; + this.variable = variable !== undefined ? variable : name.charAt && name.charAt(0) === '@'; + this.allowRoot = true; + this.setParent(this.value, this); + } + + genCSS(context, output) { + output.add(this.name + (context.compress ? ':' : ': '), this.fileInfo(), this.getIndex()); + + try { + this.value.genCSS(context, output); + } catch (e) { + e.index = this._index; + e.filename = this._fileInfo.filename; + throw e; + } + + output.add(this.important + (this.inline || context.lastRule && context.compress ? '' : ';'), this._fileInfo, this._index); + } + + eval(context) { + let mathBypass = false; + let prevMath; + let name = this.name; + let evaldValue; + let variable = this.variable; + + if (typeof name !== 'string') { + // expand 'primitive' name directly to get + // things faster (~10% for benchmark.less): + name = name.length === 1 && name[0] instanceof Keyword ? name[0].value : evalName(context, name); + variable = false; // never treat expanded interpolation as new variable name + } // @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({}); + evaldValue = this.value.eval(context); + + if (!this.variable && evaldValue.type === 'DetachedRuleset') { + throw { + message: 'Rulesets cannot be evaluated on a property.', + index: this.getIndex(), + filename: this.fileInfo().filename + }; + } + + let important = this.important; + const importantResult = context.importantScope.pop(); + + if (!important && importantResult.important) { + important = importantResult.important; + } + + return new Declaration(name, evaldValue, important, this.merge, this.getIndex(), this.fileInfo(), this.inline, variable); + } catch (e) { + if (typeof e.index !== 'number') { + e.index = this.getIndex(); + e.filename = this.fileInfo().filename; + } + + throw e; + } finally { + if (mathBypass) { + context.math = prevMath; + } + } + } + + makeImportant() { + return new Declaration(this.name, this.value, '!important', this.merge, this.getIndex(), this.fileInfo(), this.inline); + } + +} + +function evalName(context, name) { + let value = ''; + let i; + const n = name.length; + const output = { + add: function add(s) { + value += s; + } + }; + + for (i = 0; i < n; i++) { + name[i].eval(context).genCSS(context, output); + } + + return value; +} + +Declaration.prototype.type = 'Declaration'; + +const debugInfo = (context, ctx, lineSeparator) => { + let result = ''; + + if (context.dumpLineNumbers && !context.compress) { + switch (context.dumpLineNumbers) { + case 'comments': + result = debugInfo.asComment(ctx); + break; + + case 'mediaquery': + result = debugInfo.asMediaQuery(ctx); + break; + + case 'all': + result = debugInfo.asComment(ctx) + (lineSeparator || '') + debugInfo.asMediaQuery(ctx); + break; + } + } + + return result; +}; + +debugInfo.asComment = ctx => `/* line ${ctx.debugInfo.lineNumber}, ${ctx.debugInfo.fileName} */\n`; + +debugInfo.asMediaQuery = ctx => { + let filenameWithProtocol = ctx.debugInfo.fileName; + + if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) { + filenameWithProtocol = `file://${filenameWithProtocol}`; + } + + return `@media -sass-debug-info{filename{font-family:${filenameWithProtocol.replace(/([.:\/\\])/g, a => { + if (a == '\\') { + a = '\/'; + } + + return `\\${a}`; + })}}line{font-family:\\00003${ctx.debugInfo.lineNumber}}}\n`; +}; + +class Comment extends Node { + constructor(value, isLineComment, index, currentFileInfo) { + super(); + this.value = value; + this.isLineComment = isLineComment; + this._index = index; + this._fileInfo = currentFileInfo; + this.allowRoot = true; + } + + genCSS(context, output) { + if (this.debugInfo) { + output.add(debugInfo(context, this), this.fileInfo(), this.getIndex()); + } + + output.add(this.value); + } + + isSilent(context) { + const isCompressed = context.compress && this.value[2] !== '!'; + return this.isLineComment || isCompressed; + } + +} + +Comment.prototype.type = 'Comment'; + +const contexts = {}; + +const copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) { + if (!original) { + return; + } + + for (let i = 0; i < propertiesToCopy.length; i++) { + if (original.hasOwnProperty(propertiesToCopy[i])) { + destination[propertiesToCopy[i]] = original[propertiesToCopy[i]]; + } + } +}; +/* + parse is used whilst parsing + */ + + +const parseCopyProperties = [// options +'paths', // option - unmodified - paths to search for imports on +'rewriteUrls', // option - whether to adjust URL's to be relative +'rootpath', // option - rootpath to append to URL's +'strictImports', // option - +'insecure', // option - whether to allow imports from insecure ssl hosts +'dumpLineNumbers', // option - whether to dump line numbers +'compress', // option - whether to compress +'syncImport', // option - whether to import synchronously +'chunkInput', // option - whether to chunk input. more performant but causes parse issues. +'mime', // browser only - mime type for sheet import +'useFileCache', // browser only - whether to use the per file session cache +// context +'processImports', // option & context - whether to process imports. if false then imports will not be imported. +// Used by the import manager to stop multiple import visitors being created. +'pluginManager' // Used as the plugin manager for the session +]; + +contexts.Parse = function (options) { + copyFromOriginal(options, this, parseCopyProperties); + + if (typeof this.paths === 'string') { + this.paths = [this.paths]; + } +}; + +const evalCopyProperties = ['paths', // additional include paths +'compress', // whether to compress +'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 +'urlArgs', // whether to add args into url tokens +'javascriptEnabled', // option - whether Inline JavaScript is enabled. if undefined, defaults to false +'pluginManager', // Used as the plugin manager for the session +'importantScope', // used to bubble up !important statements +'rewriteUrls' // option - whether to adjust URL's to be relative +]; + +function isPathRelative(path) { + return !/^(?:[a-z-]+:|\/|#)/i.test(path); +} + +function isPathLocalRelative(path) { + return path.charAt(0) === '.'; +} + +contexts.Eval = class { + constructor(options, frames) { + copyFromOriginal(options, this, evalCopyProperties); + + if (typeof this.paths === 'string') { + this.paths = [this.paths]; + } + + this.frames = frames || []; + this.importantScope = this.importantScope || []; + this.inCalc = false; + this.mathOn = true; + } + + enterCalc() { + if (!this.calcStack) { + this.calcStack = []; + } + + this.calcStack.push(true); + this.inCalc = true; + } + + exitCalc() { + this.calcStack.pop(); + + if (!this.calcStack) { + this.inCalc = false; + } + } + + inParenthesis() { + if (!this.parensStack) { + this.parensStack = []; + } + + this.parensStack.push(true); + } + + outOfParenthesis() { + this.parensStack.pop(); + } + + isMathOn(op) { + if (!this.mathOn) { + return false; + } + + if (op === '/' && this.math !== Math$1.ALWAYS && (!this.parensStack || !this.parensStack.length)) { + return false; + } + + if (this.math > Math$1.PARENS_DIVISION) { + return this.parensStack && this.parensStack.length; + } + + return true; + } + + pathRequiresRewrite(path) { + const isRelative = this.rewriteUrls === RewriteUrls.LOCAL ? isPathLocalRelative : isPathRelative; + return isRelative(path); + } + + rewritePath(path, rootpath) { + let newPath; + rootpath = rootpath || ''; + newPath = this.normalizePath(rootpath + path); // If a path was explicit relative and the rootpath was not an absolute path + // we must ensure that the new path is also explicit relative. + + if (isPathLocalRelative(path) && isPathRelative(rootpath) && isPathLocalRelative(newPath) === false) { + newPath = `./${newPath}`; + } + + return newPath; + } + + normalizePath(path) { + const segments = path.split('/').reverse(); + let segment; + path = []; + + while (segments.length !== 0) { + segment = segments.pop(); + + switch (segment) { + case '.': + break; + + case '..': + if (path.length === 0 || path[path.length - 1] === '..') { + path.push(segment); + } else { + path.pop(); + } + + break; + + default: + path.push(segment); + break; + } + } + + return path.join('/'); + } + +}; + +function makeRegistry(base) { + return { + _data: {}, + add: function add(name, func) { + // precautionary case conversion, as later querying of + // the registry by function-caller uses lower case as well. + name = name.toLowerCase(); + + if (this._data.hasOwnProperty(name)) ; + + this._data[name] = func; + }, + addMultiple: function addMultiple(functions) { + Object.keys(functions).forEach(name => { + this.add(name, functions[name]); + }); + }, + get: function get(name) { + return this._data[name] || base && base.get(name); + }, + getLocalFunctions: function getLocalFunctions() { + return this._data; + }, + inherit: function inherit() { + return makeRegistry(this); + }, + create: function create(base) { + return makeRegistry(base); + } + }; +} + +var functionRegistry = makeRegistry(null); + +const defaultFunc = { + eval: function _eval() { + const v = this.value_; + const e = this.error_; + + if (e) { + throw e; + } + + if (v != null) { + return v ? Keyword.True : Keyword.False; + } + }, + value: function value(v) { + this.value_ = v; + }, + error: function error(e) { + this.error_ = e; + }, + reset: function reset() { + this.value_ = this.error_ = null; + } +}; + +class Ruleset extends Node { + constructor(selectors, rules, strictImports, visibilityInfo) { + super(); + this.selectors = selectors; + this.rules = rules; + this._lookups = {}; + this._variables = null; + this._properties = null; + this.strictImports = strictImports; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + this.setParent(this.selectors, this); + this.setParent(this.rules, this); + } + + isRulesetLike() { + return true; + } + + accept(visitor) { + if (this.paths) { + this.paths = visitor.visitArray(this.paths, true); + } else if (this.selectors) { + this.selectors = visitor.visitArray(this.selectors); + } + + if (this.rules && this.rules.length) { + this.rules = visitor.visitArray(this.rules); + } + } + + eval(context) { + let selectors; + let selCnt; + let selector; + let i; + let hasVariable; + let hasOnePassingSelector = false; + + if (this.selectors && (selCnt = this.selectors.length)) { + selectors = new Array(selCnt); + defaultFunc.error({ + type: 'Syntax', + message: 'it is currently only allowed in parametric mixin guards,' + }); + + for (i = 0; i < selCnt; i++) { + selector = this.selectors[i].eval(context); + + for (var j = 0; j < selector.elements.length; j++) { + if (selector.elements[j].isVariable) { + hasVariable = true; + break; + } + } + + selectors[i] = selector; + + if (selector.evaldCondition) { + hasOnePassingSelector = true; + } + } + + if (hasVariable) { + const toParseSelectors = new Array(selCnt); + + for (i = 0; i < selCnt; i++) { + selector = selectors[i]; + toParseSelectors[i] = selector.toCSS(context); + } + + this.parse.parseNode(toParseSelectors.join(','), ["selectors"], selectors[0].getIndex(), selectors[0].fileInfo(), (err, result) => { + if (result) { + selectors = flattenArray(result); + } + }); + } + + defaultFunc.reset(); + } else { + hasOnePassingSelector = true; + } + + let rules = this.rules ? copyArray(this.rules) : null; + const ruleset = new Ruleset(selectors, rules, this.strictImports, this.visibilityInfo()); + let rule; + let subRule; + ruleset.originalRuleset = this; + ruleset.root = this.root; + ruleset.firstRoot = this.firstRoot; + ruleset.allowImports = this.allowImports; + + if (this.debugInfo) { + ruleset.debugInfo = this.debugInfo; + } + + if (!hasOnePassingSelector) { + rules.length = 0; + } // inherit a function registry from the frames stack when possible; + // otherwise from the global registry + + + ruleset.functionRegistry = (frames => { + let i = 0; + const n = frames.length; + let found; + + for (; i !== n; ++i) { + found = frames[i].functionRegistry; + + if (found) { + return found; + } + } + + return functionRegistry; + })(context.frames).inherit(); // push the current ruleset to the frames stack + + + const ctxFrames = context.frames; + ctxFrames.unshift(ruleset); // currrent selectors + + let ctxSelectors = context.selectors; + + if (!ctxSelectors) { + context.selectors = ctxSelectors = []; + } + + ctxSelectors.unshift(this.selectors); // Evaluate imports + + if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { + ruleset.evalImports(context); + } // Store the frames around mixin definitions, + // so they can be evaluated like closures when the time comes. + + + const rsRules = ruleset.rules; + + for (i = 0; rule = rsRules[i]; i++) { + if (rule.evalFirst) { + rsRules[i] = rule.eval(context); + } + } + + const mediaBlockCount = context.mediaBlocks && context.mediaBlocks.length || 0; // Evaluate mixin calls. + + for (i = 0; rule = rsRules[i]; i++) { + if (rule.type === 'MixinCall') { + /* jshint loopfunc:true */ + rules = rule.eval(context).filter(r => { + if (r instanceof Declaration && r.variable) { + // do not pollute the scope if the variable is + // already there. consider returning false here + // but we need a way to "return" variable from mixins + return !ruleset.variable(r.name); + } + + return true; + }); + rsRules.splice(...[i, 1].concat(rules)); + i += rules.length - 1; + ruleset.resetCache(); + } else if (rule.type === 'VariableCall') { + /* jshint loopfunc:true */ + rules = rule.eval(context).rules.filter(r => { + if (r instanceof Declaration && r.variable) { + // do not pollute the scope at all + return false; + } + + return true; + }); + rsRules.splice(...[i, 1].concat(rules)); + i += rules.length - 1; + ruleset.resetCache(); + } + } // Evaluate everything else + + + for (i = 0; rule = rsRules[i]; i++) { + if (!rule.evalFirst) { + rsRules[i] = rule = rule.eval ? rule.eval(context) : rule; + } + } // Evaluate everything else + + + for (i = 0; rule = rsRules[i]; i++) { + // for rulesets, check if it is a css guard and can be removed + if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) { + // check if it can be folded in (e.g. & where) + if (rule.selectors[0] && rule.selectors[0].isJustParentSelector()) { + rsRules.splice(i--, 1); + + for (var j = 0; subRule = rule.rules[j]; j++) { + if (subRule instanceof Node) { + subRule.copyVisibilityInfo(rule.visibilityInfo()); + + if (!(subRule instanceof Declaration) || !subRule.variable) { + rsRules.splice(++i, 0, subRule); + } + } + } + } + } + } // Pop the stack + + + ctxFrames.shift(); + ctxSelectors.shift(); + + if (context.mediaBlocks) { + for (i = mediaBlockCount; i < context.mediaBlocks.length; i++) { + context.mediaBlocks[i].bubbleSelectors(selectors); + } + } + + return ruleset; + } + + evalImports(context) { + const rules = this.rules; + let i; + let importRules; + + if (!rules) { + return; + } + + for (i = 0; i < rules.length; i++) { + if (rules[i].type === 'Import') { + importRules = rules[i].eval(context); + + if (importRules && (importRules.length || importRules.length === 0)) { + rules.splice(...[i, 1].concat(importRules)); + i += importRules.length - 1; + } else { + rules.splice(i, 1, importRules); + } + + this.resetCache(); + } + } + } + + makeImportant() { + const result = new Ruleset(this.selectors, this.rules.map(r => { + if (r.makeImportant) { + return r.makeImportant(); + } else { + return r; + } + }), this.strictImports, this.visibilityInfo()); + return result; + } + + matchArgs(args) { + return !args || args.length === 0; + } // lets you call a css selector with a guard + + + matchCondition(args, context) { + const lastSelector = this.selectors[this.selectors.length - 1]; + + if (!lastSelector.evaldCondition) { + return false; + } + + if (lastSelector.condition && !lastSelector.condition.eval(new contexts.Eval(context, context.frames))) { + return false; + } + + return true; + } + + resetCache() { + this._rulesets = null; + this._variables = null; + this._properties = null; + this._lookups = {}; + } + + variables() { + if (!this._variables) { + this._variables = !this.rules ? {} : this.rules.reduce((hash, r) => { + if (r instanceof Declaration && r.variable === true) { + hash[r.name] = r; + } // when evaluating variables in an import statement, imports have not been eval'd + // so we need to go inside import statements. + // guard against root being a string (in the case of inlined less) + + + if (r.type === 'Import' && r.root && r.root.variables) { + const vars = r.root.variables(); + + for (const name in vars) { + if (vars.hasOwnProperty(name)) { + hash[name] = r.root.variable(name); + } + } + } + + return hash; + }, {}); + } + + return this._variables; + } + + properties() { + if (!this._properties) { + this._properties = !this.rules ? {} : this.rules.reduce((hash, r) => { + if (r instanceof Declaration && r.variable !== true) { + const name = r.name.length === 1 && r.name[0] instanceof Keyword ? r.name[0].value : r.name; // Properties don't overwrite as they can merge + + if (!hash[`$${name}`]) { + hash[`$${name}`] = [r]; + } else { + hash[`$${name}`].push(r); + } + } + + return hash; + }, {}); + } + + return this._properties; + } + + variable(name) { + const decl = this.variables()[name]; + + if (decl) { + return this.parseValue(decl); + } + } + + property(name) { + const decl = this.properties()[name]; + + if (decl) { + return this.parseValue(decl); + } + } + + lastDeclaration() { + for (let i = this.rules.length; i > 0; i--) { + const decl = this.rules[i - 1]; + + if (decl instanceof Declaration) { + return this.parseValue(decl); + } + } + } + + parseValue(toParse) { + const self = this; + + function transformDeclaration(decl) { + if (decl.value instanceof Anonymous && !decl.parsed) { + if (typeof decl.value.value === 'string') { + this.parse.parseNode(decl.value.value, ['value', 'important'], decl.value.getIndex(), decl.fileInfo(), (err, result) => { + if (err) { + decl.parsed = true; + } + + if (result) { + decl.value = result[0]; + decl.important = result[1] || ''; + decl.parsed = true; + } + }); + } else { + decl.parsed = true; + } + + return decl; + } else { + return decl; + } + } + + if (!Array.isArray(toParse)) { + return transformDeclaration.call(self, toParse); + } else { + const nodes = []; + toParse.forEach(n => { + nodes.push(transformDeclaration.call(self, n)); + }); + return nodes; + } + } + + rulesets() { + if (!this.rules) { + return []; + } + + const filtRules = []; + const rules = this.rules; + let i; + let rule; + + for (i = 0; rule = rules[i]; i++) { + if (rule.isRuleset) { + filtRules.push(rule); + } + } + + return filtRules; + } + + prependRule(rule) { + const rules = this.rules; + + if (rules) { + rules.unshift(rule); + } else { + this.rules = [rule]; + } + + this.setParent(rule, this); + } + + find(selector, self = this, filter) { + const rules = []; + let match; + let foundMixins; + const key = selector.toCSS(); + + if (key in this._lookups) { + return this._lookups[key]; + } + + this.rulesets().forEach(rule => { + if (rule !== self) { + for (let j = 0; j < rule.selectors.length; j++) { + match = selector.match(rule.selectors[j]); + + if (match) { + if (selector.elements.length > match) { + if (!filter || filter(rule)) { + foundMixins = rule.find(new Selector(selector.elements.slice(match)), self, filter); + + for (let i = 0; i < foundMixins.length; ++i) { + foundMixins[i].path.push(rule); + } + + Array.prototype.push.apply(rules, foundMixins); + } + } else { + rules.push({ + rule, + path: [] + }); + } + + break; + } + } + } + }); + this._lookups[key] = rules; + return rules; + } + + genCSS(context, output) { + let i; + let j; + const charsetRuleNodes = []; + let ruleNodes = []; + let // Line number debugging + debugInfo$1; + let rule; + let path; + context.tabLevel = context.tabLevel || 0; + + if (!this.root) { + context.tabLevel++; + } + + const tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join(' '); + const tabSetStr = context.compress ? '' : Array(context.tabLevel).join(' '); + let sep; + let charsetNodeIndex = 0; + let importNodeIndex = 0; + + for (i = 0; rule = this.rules[i]; i++) { + if (rule instanceof Comment) { + if (importNodeIndex === i) { + importNodeIndex++; + } + + ruleNodes.push(rule); + } else if (rule.isCharset && rule.isCharset()) { + ruleNodes.splice(charsetNodeIndex, 0, rule); + charsetNodeIndex++; + importNodeIndex++; + } else if (rule.type === 'Import') { + ruleNodes.splice(importNodeIndex, 0, rule); + importNodeIndex++; + } else { + ruleNodes.push(rule); + } + } + + ruleNodes = charsetRuleNodes.concat(ruleNodes); // If this is the root node, we don't render + // a selector, or {}. + + if (!this.root) { + debugInfo$1 = debugInfo(context, this, tabSetStr); + + if (debugInfo$1) { + output.add(debugInfo$1); + output.add(tabSetStr); + } + + const paths = this.paths; + const pathCnt = paths.length; + let pathSubCnt; + sep = context.compress ? ',' : `,\n${tabSetStr}`; + + for (i = 0; i < pathCnt; i++) { + path = paths[i]; + + if (!(pathSubCnt = path.length)) { + continue; + } + + if (i > 0) { + output.add(sep); + } + + context.firstSelector = true; + path[0].genCSS(context, output); + context.firstSelector = false; + + for (j = 1; j < pathSubCnt; j++) { + path[j].genCSS(context, output); + } + } + + output.add((context.compress ? '{' : ' {\n') + tabRuleStr); + } // Compile rules and rulesets + + + for (i = 0; rule = ruleNodes[i]; i++) { + if (i + 1 === ruleNodes.length) { + context.lastRule = true; + } + + const currentLastRule = context.lastRule; + + if (rule.isRulesetLike(rule)) { + context.lastRule = false; + } + + if (rule.genCSS) { + rule.genCSS(context, output); + } else if (rule.value) { + output.add(rule.value.toString()); + } + + context.lastRule = currentLastRule; + + if (!context.lastRule && rule.isVisible()) { + output.add(context.compress ? '' : `\n${tabRuleStr}`); + } else { + context.lastRule = false; + } + } + + if (!this.root) { + output.add(context.compress ? '}' : `\n${tabSetStr}}`); + context.tabLevel--; + } + + if (!output.isEmpty() && !context.compress && this.firstRoot) { + output.add('\n'); + } + } + + joinSelectors(paths, context, selectors) { + for (let s = 0; s < selectors.length; s++) { + this.joinSelector(paths, context, selectors[s]); + } + } + + joinSelector(paths, context, selector) { + function createParenthesis(elementsToPak, originalElement) { + let replacementParen; + let j; + + if (elementsToPak.length === 0) { + replacementParen = new Paren(elementsToPak[0]); + } else { + const insideParent = new Array(elementsToPak.length); + + for (j = 0; j < elementsToPak.length; j++) { + insideParent[j] = new Element(null, elementsToPak[j], originalElement.isVariable, originalElement._index, originalElement._fileInfo); + } + + replacementParen = new Paren(new Selector(insideParent)); + } + + return replacementParen; + } + + function createSelector(containedElement, originalElement) { + let element; + let selector; + element = new Element(null, containedElement, originalElement.isVariable, originalElement._index, originalElement._fileInfo); + selector = new Selector([element]); + return selector; + } // joins selector path from `beginningPath` with selector path in `addPath` + // `replacedElement` contains element that is being replaced by `addPath` + // returns concatenated path + + + function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) { + let newSelectorPath; + let lastSelector; + let newJoinedSelector; // our new selector path + + newSelectorPath = []; // construct the joined selector - if & is the first thing this will be empty, + // if not newJoinedSelector will be the last set of elements in the selector + + if (beginningPath.length > 0) { + newSelectorPath = copyArray(beginningPath); + lastSelector = newSelectorPath.pop(); + newJoinedSelector = originalSelector.createDerived(copyArray(lastSelector.elements)); + } else { + newJoinedSelector = originalSelector.createDerived([]); + } + + if (addPath.length > 0) { + // /deep/ is a CSS4 selector - (removed, so should deprecate) + // that is valid without anything in front of it + // so if the & does not have a combinator that is "" or " " then + // and there is a combinator on the parent, then grab that. + // this also allows + a { & .b { .a & { ... though not sure why you would want to do that + let combinator = replacedElement.combinator; + const parentEl = addPath[0].elements[0]; + + if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) { + combinator = parentEl.combinator; + } // join the elements so far with the first part of the parent + + + newJoinedSelector.elements.push(new Element(combinator, parentEl.value, replacedElement.isVariable, replacedElement._index, replacedElement._fileInfo)); + newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1)); + } // now add the joined selector - but only if it is not empty + + + if (newJoinedSelector.elements.length !== 0) { + newSelectorPath.push(newJoinedSelector); + } // put together the parent selectors after the join (e.g. the rest of the parent) + + + if (addPath.length > 1) { + let restOfPath = addPath.slice(1); + restOfPath = restOfPath.map(selector => selector.createDerived(selector.elements, [])); + newSelectorPath = newSelectorPath.concat(restOfPath); + } + + return newSelectorPath; + } // joins selector path from `beginningPath` with every selector path in `addPaths` array + // `replacedElement` contains element that is being replaced by `addPath` + // returns array with all concatenated paths + + + function addAllReplacementsIntoPath(beginningPath, addPaths, replacedElement, originalSelector, result) { + let j; + + for (j = 0; j < beginningPath.length; j++) { + const newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector); + result.push(newSelectorPath); + } + + return result; + } + + function mergeElementsOnToSelectors(elements, selectors) { + let i; + let sel; + + if (elements.length === 0) { + return; + } + + if (selectors.length === 0) { + selectors.push([new Selector(elements)]); + return; + } + + for (i = 0; sel = selectors[i]; i++) { + // if the previous thing in sel is a parent this needs to join on to it + if (sel.length > 0) { + sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements)); + } else { + sel.push(new Selector(elements)); + } + } + } // replace all parent selectors inside `inSelector` by content of `context` array + // resulting selectors are returned inside `paths` array + // returns true if `inSelector` contained at least one parent selector + + + function replaceParentSelector(paths, context, inSelector) { + // The paths are [[Selector]] + // The first list is a list of comma separated selectors + // The inner list is a list of inheritance separated selectors + // e.g. + // .a, .b { + // .c { + // } + // } + // == [[.a] [.c]] [[.b] [.c]] + // + let i; + let j; + let k; + let currentElements; + let newSelectors; + let selectorsMultiplied; + let sel; + let el; + let hadParentSelector = false; + let length; + let lastSelector; + + function findNestedSelector(element) { + let maybeSelector; + + if (!(element.value instanceof Paren)) { + return null; + } + + maybeSelector = element.value.value; + + if (!(maybeSelector instanceof Selector)) { + return null; + } + + return maybeSelector; + } // the elements from the current selector so far + + + currentElements = []; // the current list of new selectors to add to the path. + // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors + // by the parents + + newSelectors = [[]]; + + for (i = 0; el = inSelector.elements[i]; i++) { + // non parent reference elements just get added + if (el.value !== '&') { + const nestedSelector = findNestedSelector(el); + + if (nestedSelector != null) { + // merge the current list of non parent selector elements + // on to the current list of selectors to add + mergeElementsOnToSelectors(currentElements, newSelectors); + const nestedPaths = []; + let replaced; + const replacedNewSelectors = []; + replaced = replaceParentSelector(nestedPaths, context, nestedSelector); + hadParentSelector = hadParentSelector || replaced; // the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors + + for (k = 0; k < nestedPaths.length; k++) { + const replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el); + addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors); + } + + newSelectors = replacedNewSelectors; + currentElements = []; + } else { + currentElements.push(el); + } + } else { + hadParentSelector = true; // the new list of selectors to add + + selectorsMultiplied = []; // merge the current list of non parent selector elements + // on to the current list of selectors to add + + mergeElementsOnToSelectors(currentElements, newSelectors); // loop through our current selectors + + for (j = 0; j < newSelectors.length; j++) { + sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used + // whether there are parents or not + + if (context.length === 0) { + // the combinator used on el should now be applied to the next element instead so that + // it is not lost + if (sel.length > 0) { + sel[0].elements.push(new Element(el.combinator, '', el.isVariable, el._index, el._fileInfo)); + } + + selectorsMultiplied.push(sel); + } else { + // and the parent selectors + for (k = 0; k < context.length; k++) { + // We need to put the current selectors + // then join the last selector's elements on to the parents selectors + const newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector); // add that to our new set of selectors + + selectorsMultiplied.push(newSelectorPath); + } + } + } // our new selectors has been multiplied, so reset the state + + + newSelectors = selectorsMultiplied; + currentElements = []; + } + } // if we have any elements left over (e.g. .a& .b == .b) + // add them on to all the current selectors + + + mergeElementsOnToSelectors(currentElements, newSelectors); + + for (i = 0; i < newSelectors.length; i++) { + length = newSelectors[i].length; + + if (length > 0) { + paths.push(newSelectors[i]); + lastSelector = newSelectors[i][length - 1]; + newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList); + } + } + + return hadParentSelector; + } + + function deriveSelector(visibilityInfo, deriveFrom) { + const newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition); + newSelector.copyVisibilityInfo(visibilityInfo); + return newSelector; + } // joinSelector code follows + + + let i; + let newPaths; + let hadParentSelector; + newPaths = []; + hadParentSelector = replaceParentSelector(newPaths, context, selector); + + if (!hadParentSelector) { + if (context.length > 0) { + newPaths = []; + + for (i = 0; i < context.length; i++) { + const concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo())); + concatenated.push(selector); + newPaths.push(concatenated); + } + } else { + newPaths = [[selector]]; + } + } + + for (i = 0; i < newPaths.length; i++) { + paths.push(newPaths[i]); + } + } + +} + +Ruleset.prototype.type = 'Ruleset'; +Ruleset.prototype.isRuleset = true; + +class AtRule extends Node { + constructor(name, value, rules, index, currentFileInfo, debugInfo, isRooted, visibilityInfo) { + super(); + let i; + this.name = name; + this.value = value instanceof Node ? value : value ? new Anonymous(value) : value; + + if (rules) { + if (Array.isArray(rules)) { + this.rules = rules; + } else { + this.rules = [rules]; + this.rules[0].selectors = new Selector([], null, null, index, currentFileInfo).createEmptySelectors(); + } + + for (i = 0; i < this.rules.length; i++) { + this.rules[i].allowImports = true; + } + + this.setParent(this.rules, this); + } + + this._index = index; + this._fileInfo = currentFileInfo; + this.debugInfo = debugInfo; + this.isRooted = isRooted || false; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + } + + accept(visitor) { + const value = this.value; + const rules = this.rules; + + if (rules) { + this.rules = visitor.visitArray(rules); + } + + if (value) { + this.value = visitor.visit(value); + } + } + + isRulesetLike() { + return this.rules || !this.isCharset(); + } + + isCharset() { + return '@charset' === this.name; + } + + genCSS(context, output) { + const value = this.value; + const rules = this.rules; + output.add(this.name, this.fileInfo(), this.getIndex()); + + if (value) { + output.add(' '); + value.genCSS(context, output); + } + + if (rules) { + this.outputRuleset(context, output, rules); + } else { + output.add(';'); + } + } + + eval(context) { + let mediaPathBackup; + let mediaBlocksBackup; + let value = this.value; + let rules = this.rules; // media stored inside other atrule should not bubble over it + // backpup media bubbling information + + mediaPathBackup = context.mediaPath; + mediaBlocksBackup = context.mediaBlocks; // deleted media bubbling information + + context.mediaPath = []; + context.mediaBlocks = []; + + if (value) { + value = value.eval(context); + } + + if (rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + rules = [rules[0].eval(context)]; + rules[0].root = true; + } // restore media bubbling information + + + context.mediaPath = mediaPathBackup; + context.mediaBlocks = mediaBlocksBackup; + return new AtRule(this.name, value, rules, this.getIndex(), this.fileInfo(), this.debugInfo, this.isRooted, this.visibilityInfo()); + } + + variable(name) { + if (this.rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + return Ruleset.prototype.variable.call(this.rules[0], name); + } + } + + find(...args) { + if (this.rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + return Ruleset.prototype.find.apply(this.rules[0], args); + } + } + + rulesets() { + if (this.rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + return Ruleset.prototype.rulesets.apply(this.rules[0]); + } + } + + outputRuleset(context, output, rules) { + const ruleCnt = rules.length; + let i; + context.tabLevel = (context.tabLevel | 0) + 1; // Compressed + + if (context.compress) { + output.add('{'); + + for (i = 0; i < ruleCnt; i++) { + rules[i].genCSS(context, output); + } + + output.add('}'); + context.tabLevel--; + return; + } // Non-compressed + + + const tabSetStr = `\n${Array(context.tabLevel).join(' ')}`; + const tabRuleStr = `${tabSetStr} `; + + if (!ruleCnt) { + output.add(` {${tabSetStr}}`); + } else { + output.add(` {${tabRuleStr}`); + rules[0].genCSS(context, output); + + for (i = 1; i < ruleCnt; i++) { + output.add(tabRuleStr); + rules[i].genCSS(context, output); + } + + output.add(`${tabSetStr}}`); + } + + context.tabLevel--; + } + +} + +AtRule.prototype.type = 'AtRule'; + +class DetachedRuleset extends Node { + constructor(ruleset, frames) { + super(); + this.ruleset = ruleset; + this.frames = frames; + this.setParent(this.ruleset, this); + } + + accept(visitor) { + this.ruleset = visitor.visit(this.ruleset); + } + + eval(context) { + const frames = this.frames || copyArray(context.frames); + return new DetachedRuleset(this.ruleset, frames); + } + + callEval(context) { + return this.ruleset.eval(this.frames ? new contexts.Eval(context, this.frames.concat(context.frames)) : context); + } + +} + +DetachedRuleset.prototype.type = 'DetachedRuleset'; +DetachedRuleset.prototype.evalFirst = true; + +class Unit extends Node { + constructor(numerator, denominator, backupUnit) { + super(); + this.numerator = numerator ? copyArray(numerator).sort() : []; + this.denominator = denominator ? copyArray(denominator).sort() : []; + + if (backupUnit) { + this.backupUnit = backupUnit; + } else if (numerator && numerator.length) { + this.backupUnit = numerator[0]; + } + } + + clone() { + return new Unit(copyArray(this.numerator), copyArray(this.denominator), this.backupUnit); + } + + genCSS(context, output) { + // Dimension checks the unit is singular and throws an error if in strict math mode. + const strictUnits = context && context.strictUnits; + + if (this.numerator.length === 1) { + output.add(this.numerator[0]); // the ideal situation + } else if (!strictUnits && this.backupUnit) { + output.add(this.backupUnit); + } else if (!strictUnits && this.denominator.length) { + output.add(this.denominator[0]); + } + } + + toString() { + let i; + let returnStr = this.numerator.join('*'); + + for (i = 0; i < this.denominator.length; i++) { + returnStr += `/${this.denominator[i]}`; + } + + return returnStr; + } + + compare(other) { + return this.is(other.toString()) ? 0 : undefined; + } + + is(unitString) { + return this.toString().toUpperCase() === unitString.toUpperCase(); + } + + isLength() { + return RegExp('^(px|em|ex|ch|rem|in|cm|mm|pc|pt|ex|vw|vh|vmin|vmax)$', 'gi').test(this.toCSS()); + } + + isEmpty() { + return this.numerator.length === 0 && this.denominator.length === 0; + } + + isSingular() { + return this.numerator.length <= 1 && this.denominator.length === 0; + } + + map(callback) { + let i; + + for (i = 0; i < this.numerator.length; i++) { + this.numerator[i] = callback(this.numerator[i], false); + } + + for (i = 0; i < this.denominator.length; i++) { + this.denominator[i] = callback(this.denominator[i], true); + } + } + + usedUnits() { + let group; + const result = {}; + let mapUnit; + let groupName; + + mapUnit = atomicUnit => { + /* jshint loopfunc:true */ + if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { + result[groupName] = atomicUnit; + } + + return atomicUnit; + }; + + for (groupName in unitConversions) { + if (unitConversions.hasOwnProperty(groupName)) { + group = unitConversions[groupName]; + this.map(mapUnit); + } + } + + return result; + } + + cancel() { + const counter = {}; + let atomicUnit; + let i; + + for (i = 0; i < this.numerator.length; i++) { + atomicUnit = this.numerator[i]; + counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; + } + + for (i = 0; i < this.denominator.length; i++) { + atomicUnit = this.denominator[i]; + counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; + } + + this.numerator = []; + this.denominator = []; + + for (atomicUnit in counter) { + if (counter.hasOwnProperty(atomicUnit)) { + const count = counter[atomicUnit]; + + if (count > 0) { + for (i = 0; i < count; i++) { + this.numerator.push(atomicUnit); + } + } else if (count < 0) { + for (i = 0; i < -count; i++) { + this.denominator.push(atomicUnit); + } + } + } + } + + this.numerator.sort(); + this.denominator.sort(); + } + +} + +Unit.prototype.type = 'Unit'; + +// A number with a unit +// + +class Dimension extends Node { + constructor(value, unit) { + super(); + this.value = parseFloat(value); + + if (isNaN(this.value)) { + throw new Error('Dimension is not a number.'); + } + + this.unit = unit && unit instanceof Unit ? unit : new Unit(unit ? [unit] : undefined); + this.setParent(this.unit, this); + } + + accept(visitor) { + this.unit = visitor.visit(this.unit); + } + + eval(context) { + return this; + } + + toColor() { + return new Color([this.value, this.value, this.value]); + } + + genCSS(context, output) { + if (context && context.strictUnits && !this.unit.isSingular()) { + throw new Error(`Multiple units in dimension. Correct the units or use the unit function. Bad unit: ${this.unit.toString()}`); + } + + const value = this.fround(context, this.value); + let strValue = String(value); + + if (value !== 0 && value < 0.000001 && value > -0.000001) { + // would be output 1e-6 etc. + strValue = value.toFixed(20).replace(/0+$/, ''); + } + + if (context && context.compress) { + // Zero values doesn't need a unit + if (value === 0 && this.unit.isLength()) { + output.add(strValue); + return; + } // Float values doesn't need a leading zero + + + if (value > 0 && value < 1) { + strValue = strValue.substr(1); + } + } + + output.add(strValue); + this.unit.genCSS(context, output); + } // In an operation between two Dimensions, + // we default to the first Dimension's unit, + // so `1px + 2` will yield `3px`. + + + operate(context, op, other) { + /* jshint noempty:false */ + let value = this._operate(context, op, this.value, other.value); + + let unit = this.unit.clone(); + + if (op === '+' || op === '-') { + if (unit.numerator.length === 0 && unit.denominator.length === 0) { + unit = other.unit.clone(); + + if (this.unit.backupUnit) { + unit.backupUnit = this.unit.backupUnit; + } + } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) ; else { + other = other.convertTo(this.unit.usedUnits()); + + if (context.strictUnits && other.unit.toString() !== unit.toString()) { + throw new Error(`Incompatible units. Change the units or use the unit function. ` + `Bad units: '${unit.toString()}' and '${other.unit.toString()}'.`); + } + + value = this._operate(context, op, this.value, other.value); + } + } else if (op === '*') { + unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); + unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); + unit.cancel(); + } else if (op === '/') { + unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); + unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); + unit.cancel(); + } + + return new Dimension(value, unit); + } + + compare(other) { + let a; + let b; + + if (!(other instanceof Dimension)) { + return undefined; + } + + if (this.unit.isEmpty() || other.unit.isEmpty()) { + a = this; + b = other; + } else { + a = this.unify(); + b = other.unify(); + + if (a.unit.compare(b.unit) !== 0) { + return undefined; + } + } + + return Node.numericCompare(a.value, b.value); + } + + unify() { + return this.convertTo({ + length: 'px', + duration: 's', + angle: 'rad' + }); + } + + convertTo(conversions) { + let value = this.value; + const unit = this.unit.clone(); + let i; + let groupName; + let group; + let targetUnit; + let derivedConversions = {}; + let applyUnit; + + if (typeof conversions === 'string') { + for (i in unitConversions) { + if (unitConversions[i].hasOwnProperty(conversions)) { + derivedConversions = {}; + derivedConversions[i] = conversions; + } + } + + conversions = derivedConversions; + } + + applyUnit = (atomicUnit, denominator) => { + /* jshint loopfunc:true */ + if (group.hasOwnProperty(atomicUnit)) { + if (denominator) { + value = value / (group[atomicUnit] / group[targetUnit]); + } else { + value = value * (group[atomicUnit] / group[targetUnit]); + } + + return targetUnit; + } + + return atomicUnit; + }; + + for (groupName in conversions) { + if (conversions.hasOwnProperty(groupName)) { + targetUnit = conversions[groupName]; + group = unitConversions[groupName]; + unit.map(applyUnit); + } + } + + unit.cancel(); + return new Dimension(value, unit); + } + +} + +Dimension.prototype.type = 'Dimension'; + +const MATH$1 = Math$1; + +class Operation extends Node { + constructor(op, operands, isSpaced) { + super(); + this.op = op.trim(); + this.operands = operands; + this.isSpaced = isSpaced; + } + + accept(visitor) { + this.operands = visitor.visitArray(this.operands); + } + + eval(context) { + let a = this.operands[0].eval(context); + let b = this.operands[1].eval(context); + let op; + + if (context.isMathOn(this.op)) { + op = this.op === './' ? '/' : this.op; + + if (a instanceof Dimension && b instanceof Color) { + a = a.toColor(); + } + + if (b instanceof Dimension && a instanceof Color) { + b = b.toColor(); + } + + if (!a.operate) { + if (a instanceof Operation && a.op === '/' && context.math === MATH$1.PARENS_DIVISION) { + return new Operation(this.op, [a, b], this.isSpaced); + } + + throw { + type: 'Operation', + message: 'Operation on an invalid type' + }; + } + + return a.operate(context, op, b); + } else { + return new Operation(this.op, [a, b], this.isSpaced); + } + } + + genCSS(context, output) { + this.operands[0].genCSS(context, output); + + if (this.isSpaced) { + output.add(' '); + } + + output.add(this.op); + + if (this.isSpaced) { + output.add(' '); + } + + this.operands[1].genCSS(context, output); + } + +} + +Operation.prototype.type = 'Operation'; + +const MATH$2 = Math$1; + +class Expression extends Node { + constructor(value, noSpacing) { + super(); + this.value = value; + this.noSpacing = noSpacing; + + if (!value) { + throw new Error('Expression requires an array parameter'); + } + } + + accept(visitor) { + this.value = visitor.visitArray(this.value); + } + + eval(context) { + let returnValue; + const mathOn = context.isMathOn(); + const inParenthesis = this.parens && (context.math !== MATH$2.STRICT_LEGACY || !this.parensInOp); + let doubleParen = false; + + if (inParenthesis) { + context.inParenthesis(); + } + + if (this.value.length > 1) { + returnValue = new Expression(this.value.map(e => { + if (!e.eval) { + return e; + } + + return e.eval(context); + }), this.noSpacing); + } else if (this.value.length === 1) { + if (this.value[0].parens && !this.value[0].parensInOp && !context.inCalc) { + doubleParen = true; + } + + returnValue = this.value[0].eval(context); + } else { + returnValue = this; + } + + if (inParenthesis) { + context.outOfParenthesis(); + } + + if (this.parens && this.parensInOp && !mathOn && !doubleParen && !(returnValue instanceof Dimension)) { + returnValue = new Paren(returnValue); + } + + return returnValue; + } + + genCSS(context, output) { + for (let i = 0; i < this.value.length; i++) { + this.value[i].genCSS(context, output); + + if (!this.noSpacing && i + 1 < this.value.length) { + output.add(' '); + } + } + } + + throwAwayComments() { + this.value = this.value.filter(v => !(v instanceof Comment)); + } + +} + +Expression.prototype.type = 'Expression'; + +class functionCaller { + constructor(name, context, index, currentFileInfo) { + this.name = name.toLowerCase(); + this.index = index; + this.context = context; + this.currentFileInfo = currentFileInfo; + this.func = context.frames[0].functionRegistry.get(this.name); + } + + isValid() { + return Boolean(this.func); + } + + call(args) { + // This code is terrible and should be replaced as per this issue... + // https://github.com/less/less.js/issues/2477 + if (Array.isArray(args)) { + args = args.filter(item => { + if (item.type === 'Comment') { + return false; + } + + return true; + }).map(item => { + if (item.type === 'Expression') { + const subNodes = item.value.filter(item => { + if (item.type === 'Comment') { + return false; + } + + return true; + }); + + if (subNodes.length === 1) { + return subNodes[0]; + } else { + return new Expression(subNodes); + } + } + + return item; + }); + } + + return this.func(...args); + } + +} + +// A function call node. +// + +class Call extends Node { + constructor(name, args, index, currentFileInfo) { + super(); + this.name = name; + this.args = args; + this.calc = name === 'calc'; + this._index = index; + this._fileInfo = currentFileInfo; + } + + accept(visitor) { + if (this.args) { + this.args = visitor.visitArray(this.args); + } + } // + // When evaluating a function call, + // we either find the function in the functionRegistry, + // in which case we call it, passing the evaluated arguments, + // if this returns null or we cannot find the function, we + // simply print it out as it appeared originally [2]. + // + // The reason why we evaluate the arguments, is in the case where + // we try to pass a variable to a function, like: `saturate(@color)`. + // The function should receive the value, not the variable. + // + + + eval(context) { + /** + * Turn off math for calc(), and switch back on for evaluating nested functions + */ + const currentMathContext = context.mathOn; + context.mathOn = !this.calc; + + if (this.calc || context.inCalc) { + context.enterCalc(); + } + + const args = this.args.map(a => a.eval(context)); + + if (this.calc || context.inCalc) { + context.exitCalc(); + } + + context.mathOn = currentMathContext; + let result; + const funcCaller = new functionCaller(this.name, context, this.getIndex(), this.fileInfo()); + + if (funcCaller.isValid()) { + try { + result = funcCaller.call(args); + } catch (e) { + throw { + type: e.type || 'Runtime', + message: `error evaluating function \`${this.name}\`${e.message ? `: ${e.message}` : ''}`, + index: this.getIndex(), + filename: this.fileInfo().filename, + line: e.lineNumber, + column: e.columnNumber + }; + } + + if (result !== null && result !== undefined) { + // Results that that are not nodes are cast as Anonymous nodes + // Falsy values or booleans are returned as empty nodes + if (!(result instanceof Node)) { + if (!result || result === true) { + result = new Anonymous(null); + } else { + result = new Anonymous(result.toString()); + } + } + + result._index = this._index; + result._fileInfo = this._fileInfo; + return result; + } + } + + return new Call(this.name, args, this.getIndex(), this.fileInfo()); + } + + genCSS(context, output) { + output.add(`${this.name}(`, this.fileInfo(), this.getIndex()); + + for (let i = 0; i < this.args.length; i++) { + this.args[i].genCSS(context, output); + + if (i + 1 < this.args.length) { + output.add(', '); + } + } + + output.add(')'); + } + +} + +Call.prototype.type = 'Call'; + +class Variable extends Node { + constructor(name, index, currentFileInfo) { + super(); + this.name = name; + this._index = index; + this._fileInfo = currentFileInfo; + } + + eval(context) { + let variable; + let name = this.name; + + if (name.indexOf('@@') === 0) { + name = `@${new Variable(name.slice(1), this.getIndex(), this.fileInfo()).eval(context).value}`; + } + + if (this.evaluating) { + throw { + type: 'Name', + message: `Recursive variable definition for ${name}`, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + + this.evaluating = true; + variable = this.find(context.frames, frame => { + const v = frame.variable(name); + + if (v) { + if (v.important) { + const importantScope = context.importantScope[context.importantScope.length - 1]; + importantScope.important = v.important; + } // If in calc, wrap vars in a function call to cascade evaluate args first + + + if (context.inCalc) { + return new Call('_SELF', [v.value]).eval(context); + } else { + return v.value.eval(context); + } + } + }); + + if (variable) { + this.evaluating = false; + return variable; + } else { + throw { + type: 'Name', + message: `variable ${name} is undefined`, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + } + + find(obj, fun) { + for (let i = 0, r; i < obj.length; i++) { + r = fun.call(obj, obj[i]); + + if (r) { + return r; + } + } + + return null; + } + +} + +Variable.prototype.type = 'Variable'; + +class Property extends Node { + constructor(name, index, currentFileInfo) { + super(); + this.name = name; + this._index = index; + this._fileInfo = currentFileInfo; + } + + eval(context) { + let property; + const name = this.name; // TODO: shorten this reference + + const mergeRules = context.pluginManager.less.visitors.ToCSSVisitor.prototype._mergeRules; + + if (this.evaluating) { + throw { + type: 'Name', + message: `Recursive property reference for ${name}`, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + + this.evaluating = true; + property = this.find(context.frames, frame => { + let v; + const vArr = frame.property(name); + + if (vArr) { + for (let i = 0; i < vArr.length; i++) { + v = vArr[i]; + vArr[i] = new Declaration(v.name, v.value, v.important, v.merge, v.index, v.currentFileInfo, v.inline, v.variable); + } + + mergeRules(vArr); + v = vArr[vArr.length - 1]; + + if (v.important) { + const importantScope = context.importantScope[context.importantScope.length - 1]; + importantScope.important = v.important; + } + + v = v.value.eval(context); + return v; + } + }); + + if (property) { + this.evaluating = false; + return property; + } else { + throw { + type: 'Name', + message: `Property '${name}' is undefined`, + filename: this.currentFileInfo.filename, + index: this.index + }; + } + } + + find(obj, fun) { + for (let i = 0, r; i < obj.length; i++) { + r = fun.call(obj, obj[i]); + + if (r) { + return r; + } + } + + return null; + } + +} + +Property.prototype.type = 'Property'; + +class Attribute extends Node { + constructor(key, op, value) { + super(); + this.key = key; + this.op = op; + this.value = value; + } + + eval(context) { + return new Attribute(this.key.eval ? this.key.eval(context) : this.key, this.op, this.value && this.value.eval ? this.value.eval(context) : this.value); + } + + genCSS(context, output) { + output.add(this.toCSS(context)); + } + + toCSS(context) { + let value = this.key.toCSS ? this.key.toCSS(context) : this.key; + + if (this.op) { + value += this.op; + value += this.value.toCSS ? this.value.toCSS(context) : this.value; + } + + return `[${value}]`; + } + +} + +Attribute.prototype.type = 'Attribute'; + +class Quoted extends Node { + constructor(str, content, escaped, index, currentFileInfo) { + super(); + this.escaped = escaped == null ? true : escaped; + this.value = content || ''; + this.quote = str.charAt(0); + this._index = index; + this._fileInfo = currentFileInfo; + this.variableRegex = /@\{([\w-]+)\}/g; + this.propRegex = /\$\{([\w-]+)\}/g; + } + + genCSS(context, output) { + if (!this.escaped) { + output.add(this.quote, this.fileInfo(), this.getIndex()); + } + + output.add(this.value); + + if (!this.escaped) { + output.add(this.quote); + } + } + + containsVariables() { + return this.value.match(this.variableRegex); + } + + eval(context) { + const that = this; + let value = this.value; + + const variableReplacement = (_, name) => { + const v = new Variable(`@${name}`, that.getIndex(), that.fileInfo()).eval(context, true); + return v instanceof Quoted ? v.value : v.toCSS(); + }; + + const propertyReplacement = (_, name) => { + const v = new Property(`$${name}`, that.getIndex(), that.fileInfo()).eval(context, true); + return v instanceof Quoted ? v.value : v.toCSS(); + }; + + function iterativeReplace(value, regexp, replacementFnc) { + let evaluatedValue = value; + + do { + value = evaluatedValue.toString(); + evaluatedValue = value.replace(regexp, replacementFnc); + } while (value !== evaluatedValue); + + return evaluatedValue; + } + + value = iterativeReplace(value, this.variableRegex, variableReplacement); + value = iterativeReplace(value, this.propRegex, propertyReplacement); + return new Quoted(this.quote + value + this.quote, value, this.escaped, this.getIndex(), this.fileInfo()); + } + + compare(other) { + // when comparing quoted strings allow the quote to differ + if (other.type === 'Quoted' && !this.escaped && !other.escaped) { + return Node.numericCompare(this.value, other.value); + } else { + return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; + } + } + +} + +Quoted.prototype.type = 'Quoted'; + +class URL extends Node { + constructor(val, index, currentFileInfo, isEvald) { + super(); + this.value = val; + this._index = index; + this._fileInfo = currentFileInfo; + this.isEvald = isEvald; + } + + accept(visitor) { + this.value = visitor.visit(this.value); + } + + genCSS(context, output) { + output.add('url('); + this.value.genCSS(context, output); + output.add(')'); + } + + eval(context) { + const val = this.value.eval(context); + let rootpath; + + if (!this.isEvald) { + // Add the rootpath if the URL requires a rewrite + rootpath = this.fileInfo() && this.fileInfo().rootpath; + + if (typeof rootpath === 'string' && typeof val.value === 'string' && context.pathRequiresRewrite(val.value)) { + if (!val.quote) { + rootpath = escapePath(rootpath); + } + + val.value = context.rewritePath(val.value, rootpath); + } else { + val.value = context.normalizePath(val.value); + } // Add url args if enabled + + + if (context.urlArgs) { + if (!val.value.match(/^\s*data:/)) { + const delimiter = val.value.indexOf('?') === -1 ? '?' : '&'; + const urlArgs = delimiter + context.urlArgs; + + if (val.value.indexOf('#') !== -1) { + val.value = val.value.replace('#', `${urlArgs}#`); + } else { + val.value += urlArgs; + } + } + } + } + + return new URL(val, this.getIndex(), this.fileInfo(), true); + } + +} + +URL.prototype.type = 'Url'; + +function escapePath(path) { + return path.replace(/[\(\)'"\s]/g, match => `\\${match}`); +} + +class Media extends AtRule { + constructor(value, features, index, currentFileInfo, visibilityInfo) { + super(); + this._index = index; + this._fileInfo = currentFileInfo; + const selectors = new Selector([], null, null, this._index, this._fileInfo).createEmptySelectors(); + this.features = new Value(features); + this.rules = [new Ruleset(selectors, value)]; + this.rules[0].allowImports = true; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + this.setParent(selectors, this); + this.setParent(this.features, this); + this.setParent(this.rules, this); + } + + isRulesetLike() { + return true; + } + + accept(visitor) { + if (this.features) { + this.features = visitor.visit(this.features); + } + + if (this.rules) { + this.rules = visitor.visitArray(this.rules); + } + } + + genCSS(context, output) { + output.add('@media ', this._fileInfo, this._index); + this.features.genCSS(context, output); + this.outputRuleset(context, output, this.rules); + } + + eval(context) { + if (!context.mediaBlocks) { + context.mediaBlocks = []; + context.mediaPath = []; + } + + const media = new Media(null, [], this._index, this._fileInfo, this.visibilityInfo()); + + if (this.debugInfo) { + this.rules[0].debugInfo = this.debugInfo; + media.debugInfo = this.debugInfo; + } + + media.features = this.features.eval(context); + context.mediaPath.push(media); + context.mediaBlocks.push(media); + this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit(); + context.frames.unshift(this.rules[0]); + media.rules = [this.rules[0].eval(context)]; + context.frames.shift(); + context.mediaPath.pop(); + return context.mediaPath.length === 0 ? media.evalTop(context) : media.evalNested(context); + } + + evalTop(context) { + let result = this; // Render all dependent Media blocks. + + if (context.mediaBlocks.length > 1) { + const selectors = new Selector([], null, null, this.getIndex(), this.fileInfo()).createEmptySelectors(); + result = new Ruleset(selectors, context.mediaBlocks); + result.multiMedia = true; + result.copyVisibilityInfo(this.visibilityInfo()); + this.setParent(result, this); + } + + delete context.mediaBlocks; + delete context.mediaPath; + return result; + } + + evalNested(context) { + let i; + let value; + const path = context.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). + + for (i = 0; i < path.length; i++) { + value = path[i].features instanceof Value ? path[i].features.value : path[i].features; + path[i] = Array.isArray(value) ? value : [value]; + } // Trace all permutations to generate the resulting media-query. + // + // (a, b and c) with nested (d, e) -> + // a and d + // a and e + // b and c and d + // b and c and e + + + this.features = new Value(this.permute(path).map(path => { + path = path.map(fragment => fragment.toCSS ? fragment : new Anonymous(fragment)); + + for (i = path.length - 1; i > 0; i--) { + path.splice(i, 0, new Anonymous('and')); + } + + return new Expression(path); + })); + this.setParent(this.features, this); // Fake a tree-node that doesn't output anything. + + return new Ruleset([], []); + } + + permute(arr) { + if (arr.length === 0) { + return []; + } else if (arr.length === 1) { + return arr[0]; + } else { + const result = []; + const rest = this.permute(arr.slice(1)); + + for (let i = 0; i < rest.length; i++) { + for (let j = 0; j < arr[0].length; j++) { + result.push([arr[0][j]].concat(rest[i])); + } + } + + return result; + } + } + + bubbleSelectors(selectors) { + if (!selectors) { + return; + } + + this.rules = [new Ruleset(copyArray(selectors), [this.rules[0]])]; + this.setParent(this.rules, this); + } + +} + +Media.prototype.type = 'Media'; + +// CSS @import node +// +// The general strategy here is that we don't want to wait +// for the parsing to be completed, before we start importing +// the file. That's because in the context of a browser, +// most of the time will be spent waiting for the server to respond. +// +// On creation, we push the import path to our import queue, though +// `import,push`, we also pass it a callback, which it'll call once +// the file has been fetched, and parsed. +// + +class Import extends Node { + constructor(path, features, options, index, currentFileInfo, visibilityInfo) { + super(); + this.options = options; + this._index = index; + this._fileInfo = currentFileInfo; + this.path = path; + this.features = features; + this.allowRoot = true; + + if (this.options.less !== undefined || this.options.inline) { + this.css = !this.options.less || this.options.inline; + } else { + const pathValue = this.getPath(); + + if (pathValue && /[#\.\&\?]css([\?;].*)?$/.test(pathValue)) { + this.css = true; + } + } + + this.copyVisibilityInfo(visibilityInfo); + this.setParent(this.features, this); + this.setParent(this.path, this); + } + + accept(visitor) { + if (this.features) { + this.features = visitor.visit(this.features); + } + + this.path = visitor.visit(this.path); + + if (!this.options.isPlugin && !this.options.inline && this.root) { + this.root = visitor.visit(this.root); + } + } + + genCSS(context, output) { + if (this.css && this.path._fileInfo.reference === undefined) { + output.add('@import ', this._fileInfo, this._index); + this.path.genCSS(context, output); + + if (this.features) { + output.add(' '); + this.features.genCSS(context, output); + } + + output.add(';'); + } + } + + getPath() { + return this.path instanceof URL ? this.path.value.value : this.path.value; + } + + isVariableImport() { + let path = this.path; + + if (path instanceof URL) { + path = path.value; + } + + if (path instanceof Quoted) { + return path.containsVariables(); + } + + return true; + } + + evalForImport(context) { + let path = this.path; + + if (path instanceof URL) { + path = path.value; + } + + return new Import(path.eval(context), this.features, this.options, this._index, this._fileInfo, this.visibilityInfo()); + } + + evalPath(context) { + const path = this.path.eval(context); + const fileInfo = this._fileInfo; + + if (!(path instanceof URL)) { + // Add the rootpath if the URL requires a rewrite + const pathValue = path.value; + + if (fileInfo && pathValue && context.pathRequiresRewrite(pathValue)) { + path.value = context.rewritePath(pathValue, fileInfo.rootpath); + } else { + path.value = context.normalizePath(path.value); + } + } + + return path; + } + + eval(context) { + const result = this.doEval(context); + + if (this.options.reference || this.blocksVisibility()) { + if (result.length || result.length === 0) { + result.forEach(node => { + node.addVisibilityBlock(); + }); + } else { + result.addVisibilityBlock(); + } + } + + return result; + } + + doEval(context) { + let ruleset; + let registry; + const features = this.features && this.features.eval(context); + + if (this.options.isPlugin) { + if (this.root && this.root.eval) { + try { + this.root.eval(context); + } catch (e) { + e.message = 'Plugin error during evaluation'; + throw new LessError(e, this.root.imports, this.root.filename); + } + } + + registry = context.frames[0] && context.frames[0].functionRegistry; + + if (registry && this.root && this.root.functions) { + registry.addMultiple(this.root.functions); + } + + return []; + } + + if (this.skip) { + if (typeof this.skip === 'function') { + this.skip = this.skip(); + } + + if (this.skip) { + return []; + } + } + + if (this.options.inline) { + const contents = new Anonymous(this.root, 0, { + filename: this.importedFilename, + reference: this.path._fileInfo && this.path._fileInfo.reference + }, true, true); + return this.features ? new Media([contents], this.features.value) : [contents]; + } else if (this.css) { + const newImport = new Import(this.evalPath(context), features, this.options, this._index); + + if (!newImport.css && this.error) { + throw this.error; + } + + return newImport; + } else { + ruleset = new Ruleset(null, copyArray(this.root.rules)); + ruleset.evalImports(context); + return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules; + } + } + +} + +Import.prototype.type = 'Import'; + +class JsEvalNode extends Node { + evaluateJavaScript(expression, context) { + let result; + const that = this; + const evalContext = {}; + + if (!context.javascriptEnabled) { + throw { + message: 'Inline JavaScript is not enabled. Is it set in your options?', + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + + expression = expression.replace(/@\{([\w-]+)\}/g, (_, name) => that.jsify(new Variable(`@${name}`, that.getIndex(), that.fileInfo()).eval(context))); + + try { + expression = new Function(`return (${expression})`); + } catch (e) { + throw { + message: `JavaScript evaluation error: ${e.message} from \`${expression}\``, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + + const variables = context.frames[0].variables(); + + for (const k in variables) { + if (variables.hasOwnProperty(k)) { + /* jshint loopfunc:true */ + evalContext[k.slice(1)] = { + value: variables[k].value, + toJS: function toJS() { + return this.value.eval(context).toCSS(); + } + }; + } + } + + try { + result = expression.call(evalContext); + } catch (e) { + throw { + message: `JavaScript evaluation error: '${e.name}: ${e.message.replace(/["]/g, '\'')}'`, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + + return result; + } + + jsify(obj) { + if (Array.isArray(obj.value) && obj.value.length > 1) { + return `[${obj.value.map(v => v.toCSS()).join(', ')}]`; + } else { + return obj.toCSS(); + } + } + +} + +class JavaScript extends JsEvalNode { + constructor(string, escaped, index, currentFileInfo) { + super(); + this.escaped = escaped; + this.expression = string; + this._index = index; + this._fileInfo = currentFileInfo; + } + + eval(context) { + const result = this.evaluateJavaScript(this.expression, context); + const type = typeof result; + + if (type === 'number' && !isNaN(result)) { + return new Dimension(result); + } else if (type === 'string') { + return new Quoted(`"${result}"`, result, this.escaped, this._index); + } else if (Array.isArray(result)) { + return new Anonymous(result.join(', ')); + } else { + return new Anonymous(result); + } + } + +} + +JavaScript.prototype.type = 'JavaScript'; + +class Assignment extends Node { + constructor(key, val) { + super(); + this.key = key; + this.value = val; + } + + accept(visitor) { + this.value = visitor.visit(this.value); + } + + eval(context) { + if (this.value.eval) { + return new Assignment(this.key, this.value.eval(context)); + } + + return this; + } + + genCSS(context, output) { + output.add(`${this.key}=`); + + if (this.value.genCSS) { + this.value.genCSS(context, output); + } else { + output.add(this.value); + } + } + +} + +Assignment.prototype.type = 'Assignment'; + +class Condition extends Node { + constructor(op, l, r, i, negate) { + super(); + this.op = op.trim(); + this.lvalue = l; + this.rvalue = r; + this._index = i; + this.negate = negate; + } + + accept(visitor) { + this.lvalue = visitor.visit(this.lvalue); + this.rvalue = visitor.visit(this.rvalue); + } + + eval(context) { + const result = ((op, a, b) => { + switch (op) { + case 'and': + return a && b; + + case 'or': + return a || b; + + default: + switch (Node.compare(a, b)) { + case -1: + return op === '<' || op === '=<' || op === '<='; + + case 0: + return op === '=' || op === '>=' || op === '=<' || op === '<='; + + case 1: + return op === '>' || op === '>='; + + default: + return false; + } + + } + })(this.op, this.lvalue.eval(context), this.rvalue.eval(context)); + + return this.negate ? !result : result; + } + +} + +Condition.prototype.type = 'Condition'; + +class UnicodeDescriptor extends Node { + constructor(value) { + super(); + this.value = value; + } + +} + +UnicodeDescriptor.prototype.type = 'UnicodeDescriptor'; + +class Negative extends Node { + constructor(node) { + super(); + this.value = node; + } + + genCSS(context, output) { + output.add('-'); + this.value.genCSS(context, output); + } + + eval(context) { + if (context.isMathOn()) { + return new Operation('*', [new Dimension(-1), this.value]).eval(context); + } + + return new Negative(this.value.eval(context)); + } + +} + +Negative.prototype.type = 'Negative'; + +class Extend extends Node { + constructor(selector, option, index, currentFileInfo, visibilityInfo) { + super(); + this.selector = selector; + this.option = option; + this.object_id = Extend.next_id++; + this.parent_ids = [this.object_id]; + this._index = index; + this._fileInfo = currentFileInfo; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + + switch (option) { + case 'all': + this.allowBefore = true; + this.allowAfter = true; + break; + + default: + this.allowBefore = false; + this.allowAfter = false; + break; + } + + this.setParent(this.selector, this); + } + + accept(visitor) { + this.selector = visitor.visit(this.selector); + } + + eval(context) { + return new Extend(this.selector.eval(context), this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } + + clone(context) { + return new Extend(this.selector, this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } // it concatenates (joins) all selectors in selector array + + + findSelfSelectors(selectors) { + let selfElements = []; + let i; + let selectorElements; + + for (i = 0; i < selectors.length; i++) { + selectorElements = selectors[i].elements; // duplicate the logic in genCSS function inside the selector node. + // future TODO - move both logics into the selector joiner visitor + + if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === '') { + selectorElements[0].combinator.value = ' '; + } + + selfElements = selfElements.concat(selectors[i].elements); + } + + this.selfSelectors = [new Selector(selfElements)]; + this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo()); + } + +} + +Extend.next_id = 0; +Extend.prototype.type = 'Extend'; + +class VariableCall extends Node { + constructor(variable, index, currentFileInfo) { + super(); + this.variable = variable; + this._index = index; + this._fileInfo = currentFileInfo; + this.allowRoot = true; + } + + eval(context) { + let rules; + let detachedRuleset = new Variable(this.variable, this.getIndex(), this.fileInfo()).eval(context); + const error = new LessError({ + message: `Could not evaluate variable call ${this.variable}` + }); + + if (!detachedRuleset.ruleset) { + if (detachedRuleset.rules) { + rules = detachedRuleset; + } else if (Array.isArray(detachedRuleset)) { + rules = new Ruleset('', detachedRuleset); + } else if (Array.isArray(detachedRuleset.value)) { + rules = new Ruleset('', detachedRuleset.value); + } else { + throw error; + } + + detachedRuleset = new DetachedRuleset(rules); + } + + if (detachedRuleset.ruleset) { + return detachedRuleset.callEval(context); + } + + throw error; + } + +} + +VariableCall.prototype.type = 'VariableCall'; + +class NamespaceValue extends Node { + constructor(ruleCall, lookups, important, index, fileInfo) { + super(); + this.value = ruleCall; + this.lookups = lookups; + this.important = important; + this._index = index; + this._fileInfo = fileInfo; + } + + eval(context) { + let i; + let name; + let rules = this.value.eval(context); + + for (i = 0; i < this.lookups.length; i++) { + name = this.lookups[i]; + /** + * Eval'd DRs return rulesets. + * Eval'd mixins return rules, so let's make a ruleset if we need it. + * We need to do this because of late parsing of values + */ + + if (Array.isArray(rules)) { + rules = new Ruleset([new Selector()], rules); + } + + if (name === '') { + rules = rules.lastDeclaration(); + } else if (name.charAt(0) === '@') { + if (name.charAt(1) === '@') { + name = `@${new Variable(name.substr(1)).eval(context).value}`; + } + + if (rules.variables) { + rules = rules.variable(name); + } + + if (!rules) { + throw { + type: 'Name', + message: `variable ${name} not found`, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + } else { + if (name.substring(0, 2) === '$@') { + name = `$${new Variable(name.substr(1)).eval(context).value}`; + } else { + name = name.charAt(0) === '$' ? name : `$${name}`; + } + + if (rules.properties) { + rules = rules.property(name); + } + + if (!rules) { + throw { + type: 'Name', + message: `property "${name.substr(1)}" not found`, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } // Properties are an array of values, since a ruleset can have multiple props. + // We pick the last one (the "cascaded" value) + + + rules = rules[rules.length - 1]; + } + + if (rules.value) { + rules = rules.eval(context).value; + } + + if (rules.ruleset) { + rules = rules.ruleset.eval(context); + } + } + + return rules; + } + +} + +NamespaceValue.prototype.type = 'NamespaceValue'; + +class Definition extends Ruleset { + constructor(name, params, rules, condition, variadic, frames, visibilityInfo) { + super(); + this.name = name || 'anonymous mixin'; + this.selectors = [new Selector([new Element(null, name, false, this._index, this._fileInfo)])]; + this.params = params; + this.condition = condition; + this.variadic = variadic; + this.arity = params.length; + this.rules = rules; + this._lookups = {}; + const optionalParameters = []; + this.required = params.reduce((count, p) => { + if (!p.name || p.name && !p.value) { + return count + 1; + } else { + optionalParameters.push(p.name); + return count; + } + }, 0); + this.optionalParameters = optionalParameters; + this.frames = frames; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + } + + accept(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); + } + } + + evalParams(context, mixinEnv, args, evaldArguments) { + /* jshint boss:true */ + const frame = new Ruleset(null, null); + let varargs; + let arg; + const params = copyArray(this.params); + let i; + let j; + let val; + let name; + let isNamedFound; + let argIndex; + let argsLength = 0; + + if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) { + frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit(); + } + + mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames)); + + if (args) { + args = copyArray(args); + 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(context); + frame.prependRule(new Declaration(name, arg.value.eval(context))); + 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(context)); + } + + frame.prependRule(new Declaration(name, new Expression(varargs).eval(context))); + } else { + val = arg && arg.value; + + if (val) { + // This was a mixin call, pass in a detached ruleset of it's eval'd rules + if (Array.isArray(val)) { + val = new DetachedRuleset(new Ruleset('', val)); + } else { + val = val.eval(context); + } + } 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 Declaration(name, val)); + evaldArguments[i] = val; + } + } + + if (params[i].variadic && args) { + for (j = argIndex; j < argsLength; j++) { + evaldArguments[j] = args[j].value.eval(context); + } + } + + argIndex++; + } + + return frame; + } + + makeImportant() { + const rules = !this.rules ? this.rules : this.rules.map(r => { + if (r.makeImportant) { + return r.makeImportant(true); + } else { + return r; + } + }); + const result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames); + return result; + } + + eval(context) { + return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || copyArray(context.frames)); + } + + evalCall(context, args, important) { + const _arguments = []; + const mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames; + const frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments); + let rules; + let ruleset; + frame.prependRule(new Declaration('@arguments', new Expression(_arguments).eval(context))); + rules = copyArray(this.rules); + ruleset = new Ruleset(null, rules); + ruleset.originalRuleset = this; + ruleset = ruleset.eval(new contexts.Eval(context, [this, frame].concat(mixinFrames))); + + if (important) { + ruleset = ruleset.makeImportant(); + } + + return ruleset; + } + + matchCondition(args, context) { + if (this.condition && !this.condition.eval(new contexts.Eval(context, [this.evalParams(context, + /* the parameter variables */ + new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])].concat(this.frames || []) // the parent namespace/mixin frames + .concat(context.frames)))) { + // the current environment frames + return false; + } + + return true; + } + + matchArgs(args, context) { + const allArgsCnt = args && args.length || 0; + let len; + const optionalParameters = this.optionalParameters; + const requiredArgsCnt = !args ? 0 : args.reduce((count, p) => { + if (optionalParameters.indexOf(p.name) < 0) { + return count + 1; + } else { + return count; + } + }, 0); + + if (!this.variadic) { + if (requiredArgsCnt < this.required) { + return false; + } + + if (allArgsCnt > this.params.length) { + return false; + } + } else { + if (requiredArgsCnt < this.required - 1) { + return false; + } + } // check patterns + + + len = Math.min(requiredArgsCnt, this.arity); + + for (let i = 0; i < len; i++) { + if (!this.params[i].name && !this.params[i].variadic) { + if (args[i].value.eval(context).toCSS() != this.params[i].value.eval(context).toCSS()) { + return false; + } + } + } + + return true; + } + +} + +Definition.prototype.type = 'MixinDefinition'; +Definition.prototype.evalFirst = true; + +class MixinCall extends Node { + constructor(elements, args, index, currentFileInfo, important) { + super(); + this.selector = new Selector(elements); + this.arguments = args || []; + this._index = index; + this._fileInfo = currentFileInfo; + this.important = important; + this.allowRoot = true; + this.setParent(this.selector, this); + } + + accept(visitor) { + if (this.selector) { + this.selector = visitor.visit(this.selector); + } + + if (this.arguments.length) { + this.arguments = visitor.visitArray(this.arguments); + } + } + + eval(context) { + let mixins; + let mixin; + let mixinPath; + const args = []; + let arg; + let argValue; + const rules = []; + let match = false; + let i; + let m; + let f; + let isRecursive; + let isOneFound; + const candidates = []; + let candidate; + const conditionResult = []; + let defaultResult; + const defFalseEitherCase = -1; + const defNone = 0; + const defTrue = 1; + const defFalse = 2; + let count; + let originalRuleset; + let noArgumentsFilter; + this.selector = this.selector.eval(context); + + function calcDefGroup(mixin, mixinPath) { + let f; + let p; + let namespace; + + for (f = 0; f < 2; f++) { + conditionResult[f] = true; + defaultFunc.value(f); + + for (p = 0; p < mixinPath.length && conditionResult[f]; p++) { + namespace = mixinPath[p]; + + if (namespace.matchCondition) { + conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, context); + } + } + + if (mixin.matchCondition) { + conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, context); + } + } + + if (conditionResult[0] || conditionResult[1]) { + if (conditionResult[0] != conditionResult[1]) { + return conditionResult[1] ? defTrue : defFalse; + } + + return defNone; + } + + return defFalseEitherCase; + } + + for (i = 0; i < this.arguments.length; i++) { + arg = this.arguments[i]; + argValue = arg.value.eval(context); + + if (arg.expand && Array.isArray(argValue.value)) { + argValue = argValue.value; + + for (m = 0; m < argValue.length; m++) { + args.push({ + value: argValue[m] + }); + } + } else { + args.push({ + name: arg.name, + value: argValue + }); + } + } + + noArgumentsFilter = rule => rule.matchArgs(null, context); + + for (i = 0; i < context.frames.length; i++) { + if ((mixins = context.frames[i].find(this.selector, null, noArgumentsFilter)).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].rule; + mixinPath = mixins[m].path; + isRecursive = false; + + for (f = 0; f < context.frames.length; f++) { + if (!(mixin instanceof Definition) && mixin === (context.frames[f].originalRuleset || context.frames[f])) { + isRecursive = true; + break; + } + } + + if (isRecursive) { + continue; + } + + if (mixin.matchArgs(args, context)) { + candidate = { + mixin, + group: calcDefGroup(mixin, mixinPath) + }; + + if (candidate.group !== defFalseEitherCase) { + 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.getIndex(), + filename: this.fileInfo().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 Definition)) { + originalRuleset = mixin.originalRuleset || mixin; + mixin = new Definition('', [], mixin.rules, null, false, null, originalRuleset.visibilityInfo()); + mixin.originalRuleset = originalRuleset; + } + + const newRules = mixin.evalCall(context, args, this.important).rules; + + this._setVisibilityToReplacement(newRules); + + Array.prototype.push.apply(rules, newRules); + } catch (e) { + throw { + message: e.message, + index: this.getIndex(), + filename: this.fileInfo().filename, + stack: e.stack + }; + } + } + } + + if (match) { + return rules; + } + } + } + + if (isOneFound) { + throw { + type: 'Runtime', + message: `No matching definition was found for \`${this.format(args)}\``, + index: this.getIndex(), + filename: this.fileInfo().filename + }; + } else { + throw { + type: 'Name', + message: `${this.selector.toCSS().trim()} is undefined`, + index: this.getIndex(), + filename: this.fileInfo().filename + }; + } + } + + _setVisibilityToReplacement(replacement) { + let i; + let rule; + + if (this.blocksVisibility()) { + for (i = 0; i < replacement.length; i++) { + rule = replacement[i]; + rule.addVisibilityBlock(); + } + } + } + + format(args) { + return `${this.selector.toCSS().trim()}(${args ? args.map(a => { + let argValue = ''; + + if (a.name) { + argValue += `${a.name}:`; + } + + if (a.value.toCSS) { + argValue += a.value.toCSS(); + } else { + argValue += '???'; + } + + return argValue; + }).join(', ') : ''})`; + } + +} + +MixinCall.prototype.type = 'MixinCall'; + +var tree = { + Node, + Color, + AtRule, + DetachedRuleset, + Operation, + Dimension, + Unit, + Keyword, + Variable, + Property, + Ruleset, + Element, + Attribute, + Combinator, + Selector, + Quoted, + Expression, + Declaration, + Call, + URL, + Import, + Comment, + Anonymous, + Value, + JavaScript, + Assignment, + Condition, + Paren, + Media, + UnicodeDescriptor, + Negative, + Extend, + VariableCall, + NamespaceValue, + mixin: { + Call: MixinCall, + Definition: Definition + } +}; + +/** + * @todo Document why this abstraction exists, and the relationship between + * environment, file managers, and plugin manager + */ + +class environment$1 { + constructor(externalEnvironment, fileManagers) { + this.fileManagers = fileManagers || []; + externalEnvironment = externalEnvironment || {}; + const optionalFunctions = ['encodeBase64', 'mimeLookup', 'charsetLookup', 'getSourceMapGenerator']; + const requiredFunctions = []; + const functions = requiredFunctions.concat(optionalFunctions); + + for (let i = 0; i < functions.length; i++) { + const propName = functions[i]; + const environmentFunc = externalEnvironment[propName]; + + if (environmentFunc) { + this[propName] = environmentFunc.bind(externalEnvironment); + } else if (i < requiredFunctions.length) { + this.warn(`missing required function in environment - ${propName}`); + } + } + } + + getFileManager(filename, currentDirectory, options, environment, isSync) { + if (!filename) { + logger.warn('getFileManager called with no filename.. Please report this issue. continuing.'); + } + + if (currentDirectory == null) { + logger.warn('getFileManager called with null directory.. Please report this issue. continuing.'); + } + + let fileManagers = this.fileManagers; + + if (options.pluginManager) { + fileManagers = [].concat(fileManagers).concat(options.pluginManager.getFileManagers()); + } + + for (let i = fileManagers.length - 1; i >= 0; i--) { + const fileManager = fileManagers[i]; + + if (fileManager[isSync ? 'supportsSync' : 'supports'](filename, currentDirectory, options, environment)) { + return fileManager; + } + } + + return null; + } + + addFileManager(fileManager) { + this.fileManagers.push(fileManager); + } + + clearFileManagers() { + this.fileManagers = []; + } + +} + +class AbstractPluginLoader { + constructor() { + // Implemented by Node.js plugin loader + this.require = () => null; + } + + evalPlugin(contents, context, imports, pluginOptions, fileInfo) { + let loader; + let registry; + let pluginObj; + let localModule; + let pluginManager; + let filename; + let result; + pluginManager = context.pluginManager; + + if (fileInfo) { + if (typeof fileInfo === 'string') { + filename = fileInfo; + } else { + filename = fileInfo.filename; + } + } + + const shortname = new this.less.FileManager().extractUrlParts(filename).filename; + + if (filename) { + pluginObj = pluginManager.get(filename); + + if (pluginObj) { + result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); + + if (result) { + return result; + } + + try { + if (pluginObj.use) { + pluginObj.use.call(this.context, pluginObj); + } + } catch (e) { + e.message = e.message || 'Error during @plugin call'; + return new LessError(e, imports, filename); + } + + return pluginObj; + } + } + + localModule = { + exports: {}, + pluginManager, + fileInfo + }; + registry = functionRegistry.create(); + + const registerPlugin = obj => { + pluginObj = obj; + }; + + try { + loader = new Function('module', 'require', 'registerPlugin', 'functions', 'tree', 'less', 'fileInfo', contents); + loader(localModule, this.require(filename), registerPlugin, registry, this.less.tree, this.less, fileInfo); + } catch (e) { + return new LessError(e, imports, filename); + } + + if (!pluginObj) { + pluginObj = localModule.exports; + } + + pluginObj = this.validatePlugin(pluginObj, filename, shortname); + + if (pluginObj instanceof LessError) { + return pluginObj; + } + + if (pluginObj) { + pluginObj.imports = imports; + pluginObj.filename = filename; // For < 3.x (or unspecified minVersion) - setOptions() before install() + + if (!pluginObj.minVersion || this.compareVersion('3.0.0', pluginObj.minVersion) < 0) { + result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); + + if (result) { + return result; + } + } // Run on first load + + + pluginManager.addPlugin(pluginObj, fileInfo.filename, registry); + pluginObj.functions = registry.getLocalFunctions(); // Need to call setOptions again because the pluginObj might have functions + + result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); + + if (result) { + return result; + } // Run every @plugin call + + + try { + if (pluginObj.use) { + pluginObj.use.call(this.context, pluginObj); + } + } catch (e) { + e.message = e.message || 'Error during @plugin call'; + return new LessError(e, imports, filename); + } + } else { + return new LessError({ + message: 'Not a valid plugin' + }, imports, filename); + } + + return pluginObj; + } + + trySetOptions(plugin, filename, name, options) { + if (options && !plugin.setOptions) { + return new LessError({ + message: `Options have been provided but the plugin ${name} does not support any options.` + }); + } + + try { + plugin.setOptions && plugin.setOptions(options); + } catch (e) { + return new LessError(e); + } + } + + validatePlugin(plugin, filename, name) { + if (plugin) { + // support plugins being a function + // so that the plugin can be more usable programmatically + if (typeof plugin === 'function') { + plugin = new plugin(); + } + + if (plugin.minVersion) { + if (this.compareVersion(plugin.minVersion, this.less.version) < 0) { + return new LessError({ + message: `Plugin ${name} requires version ${this.versionToString(plugin.minVersion)}` + }); + } + } + + return plugin; + } + + return null; + } + + compareVersion(aVersion, bVersion) { + if (typeof aVersion === 'string') { + aVersion = aVersion.match(/^(\d+)\.?(\d+)?\.?(\d+)?/); + aVersion.shift(); + } + + for (let i = 0; i < aVersion.length; i++) { + if (aVersion[i] !== bVersion[i]) { + return parseInt(aVersion[i]) > parseInt(bVersion[i]) ? -1 : 1; + } + } + + return 0; + } + + versionToString(version) { + let versionString = ''; + + for (let i = 0; i < version.length; i++) { + versionString += (versionString ? '.' : '') + version[i]; + } + + return versionString; + } + + printUsage(plugins) { + for (let i = 0; i < plugins.length; i++) { + const plugin = plugins[i]; + + if (plugin.printUsage) { + plugin.printUsage(); + } + } + } + +} + +const _visitArgs = { + visitDeeper: true +}; +let _hasIndexed = false; + +function _noop(node) { + return node; +} + +function indexNodeTypes(parent, ticker) { + // add .typeIndex to tree node types for lookup table + let key; + let child; + + for (key in parent) { + /* eslint guard-for-in: 0 */ + child = parent[key]; + + switch (typeof child) { + case 'function': + // ignore bound functions directly on tree which do not have a prototype + // or aren't nodes + if (child.prototype && child.prototype.type) { + child.prototype.typeIndex = ticker++; + } + + break; + + case 'object': + ticker = indexNodeTypes(child, ticker); + break; + } + } + + return ticker; +} + +class Visitor { + constructor(implementation) { + this._implementation = implementation; + this._visitInCache = {}; + this._visitOutCache = {}; + + if (!_hasIndexed) { + indexNodeTypes(tree, 1); + _hasIndexed = true; + } + } + + visit(node) { + if (!node) { + return node; + } + + const nodeTypeIndex = node.typeIndex; + + if (!nodeTypeIndex) { + // MixinCall args aren't a node type? + if (node.value && node.value.typeIndex) { + this.visit(node.value); + } + + return node; + } + + const impl = this._implementation; + let func = this._visitInCache[nodeTypeIndex]; + let funcOut = this._visitOutCache[nodeTypeIndex]; + const visitArgs = _visitArgs; + let fnName; + visitArgs.visitDeeper = true; + + if (!func) { + fnName = `visit${node.type}`; + func = impl[fnName] || _noop; + funcOut = impl[`${fnName}Out`] || _noop; + this._visitInCache[nodeTypeIndex] = func; + this._visitOutCache[nodeTypeIndex] = funcOut; + } + + if (func !== _noop) { + const newNode = func.call(impl, node, visitArgs); + + if (node && impl.isReplacing) { + node = newNode; + } + } + + if (visitArgs.visitDeeper && node && node.accept) { + node.accept(this); + } + + if (funcOut != _noop) { + funcOut.call(impl, node); + } + + return node; + } + + visitArray(nodes, nonReplacing) { + if (!nodes) { + return nodes; + } + + const cnt = nodes.length; + let i; // Non-replacing + + if (nonReplacing || !this._implementation.isReplacing) { + for (i = 0; i < cnt; i++) { + this.visit(nodes[i]); + } + + return nodes; + } // Replacing + + + const out = []; + + for (i = 0; i < cnt; i++) { + const evald = this.visit(nodes[i]); + + if (evald === undefined) { + continue; + } + + if (!evald.splice) { + out.push(evald); + } else if (evald.length) { + this.flatten(evald, out); + } + } + + return out; + } + + flatten(arr, out) { + if (!out) { + out = []; + } + + let cnt; + let i; + let item; + let nestedCnt; + let j; + let nestedItem; + + for (i = 0, cnt = arr.length; i < cnt; i++) { + item = arr[i]; + + if (item === undefined) { + continue; + } + + if (!item.splice) { + out.push(item); + continue; + } + + for (j = 0, nestedCnt = item.length; j < nestedCnt; j++) { + nestedItem = item[j]; + + if (nestedItem === undefined) { + continue; + } + + if (!nestedItem.splice) { + out.push(nestedItem); + } else if (nestedItem.length) { + this.flatten(nestedItem, out); + } + } + } + + return out; + } + +} + +class ImportSequencer { + constructor(onSequencerEmpty) { + this.imports = []; + this.variableImports = []; + this._onSequencerEmpty = onSequencerEmpty; + this._currentDepth = 0; + } + + addImport(callback) { + const importSequencer = this; + const importItem = { + callback, + args: null, + isReady: false + }; + this.imports.push(importItem); + return function (...args) { + importItem.args = Array.prototype.slice.call(args, 0); + importItem.isReady = true; + importSequencer.tryRun(); + }; + } + + addVariableImport(callback) { + this.variableImports.push(callback); + } + + tryRun() { + this._currentDepth++; + + try { + while (true) { + while (this.imports.length > 0) { + const importItem = this.imports[0]; + + if (!importItem.isReady) { + return; + } + + this.imports = this.imports.slice(1); + importItem.callback.apply(null, importItem.args); + } + + if (this.variableImports.length === 0) { + break; + } + + const variableImport = this.variableImports[0]; + this.variableImports = this.variableImports.slice(1); + variableImport(); + } + } finally { + this._currentDepth--; + } + + if (this._currentDepth === 0 && this._onSequencerEmpty) { + this._onSequencerEmpty(); + } + } + +} + +const ImportVisitor = function ImportVisitor(importer, finish) { + this._visitor = new Visitor(this); + this._importer = importer; + this._finish = finish; + this.context = new contexts.Eval(); + this.importCount = 0; + this.onceFileDetectionMap = {}; + this.recursionDetector = {}; + this._sequencer = new ImportSequencer(this._onSequencerEmpty.bind(this)); +}; + +ImportVisitor.prototype = { + isReplacing: false, + run: function run(root) { + try { + // process the contents + this._visitor.visit(root); + } catch (e) { + this.error = e; + } + + this.isFinished = true; + + this._sequencer.tryRun(); + }, + _onSequencerEmpty: function _onSequencerEmpty() { + if (!this.isFinished) { + return; + } + + this._finish(this.error); + }, + visitImport: function visitImport(importNode, visitArgs) { + const inlineCSS = importNode.options.inline; + + if (!importNode.css || inlineCSS) { + const context = new contexts.Eval(this.context, copyArray(this.context.frames)); + const importParent = context.frames[0]; + this.importCount++; + + if (importNode.isVariableImport()) { + this._sequencer.addVariableImport(this.processImportNode.bind(this, importNode, context, importParent)); + } else { + this.processImportNode(importNode, context, importParent); + } + } + + visitArgs.visitDeeper = false; + }, + processImportNode: function processImportNode(importNode, context, importParent) { + let evaldImportNode; + const inlineCSS = importNode.options.inline; + + try { + evaldImportNode = importNode.evalForImport(context); + } catch (e) { + if (!e.filename) { + e.index = importNode.getIndex(); + e.filename = importNode.fileInfo().filename; + } // attempt to eval properly and treat as css + + + importNode.css = true; // if that fails, this error will be thrown + + importNode.error = e; + } + + if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) { + if (evaldImportNode.options.multiple) { + context.importMultiple = true; + } // try appending if we haven't determined if it is css or not + + + const tryAppendLessExtension = evaldImportNode.css === undefined; + + for (let i = 0; i < importParent.rules.length; i++) { + if (importParent.rules[i] === importNode) { + importParent.rules[i] = evaldImportNode; + break; + } + } + + const onImported = this.onImported.bind(this, evaldImportNode, context); + + const sequencedOnImported = this._sequencer.addImport(onImported); + + this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.fileInfo(), evaldImportNode.options, sequencedOnImported); + } else { + this.importCount--; + + if (this.isFinished) { + this._sequencer.tryRun(); + } + } + }, + onImported: function onImported(importNode, context, e, root, importedAtRoot, fullPath) { + if (e) { + if (!e.filename) { + e.index = importNode.getIndex(); + e.filename = importNode.fileInfo().filename; + } + + this.error = e; + } + + const importVisitor = this; + const inlineCSS = importNode.options.inline; + const isPlugin = importNode.options.isPlugin; + const isOptional = importNode.options.optional; + const duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector; + + if (!context.importMultiple) { + if (duplicateImport) { + importNode.skip = true; + } else { + importNode.skip = () => { + if (fullPath in importVisitor.onceFileDetectionMap) { + return true; + } + + importVisitor.onceFileDetectionMap[fullPath] = true; + return false; + }; + } + } + + if (!fullPath && isOptional) { + importNode.skip = true; + } + + if (root) { + importNode.root = root; + importNode.importedFilename = fullPath; + + if (!inlineCSS && !isPlugin && (context.importMultiple || !duplicateImport)) { + importVisitor.recursionDetector[fullPath] = true; + const oldContext = this.context; + this.context = context; + + try { + this._visitor.visit(root); + } catch (e) { + this.error = e; + } + + this.context = oldContext; + } + } + + importVisitor.importCount--; + + if (importVisitor.isFinished) { + importVisitor._sequencer.tryRun(); + } + }, + visitDeclaration: function visitDeclaration(declNode, visitArgs) { + if (declNode.value.type === 'DetachedRuleset') { + this.context.frames.unshift(declNode); + } else { + visitArgs.visitDeeper = false; + } + }, + visitDeclarationOut: function visitDeclarationOut(declNode) { + if (declNode.value.type === 'DetachedRuleset') { + this.context.frames.shift(); + } + }, + visitAtRule: function visitAtRule(atRuleNode, visitArgs) { + this.context.frames.unshift(atRuleNode); + }, + visitAtRuleOut: function visitAtRuleOut(atRuleNode) { + this.context.frames.shift(); + }, + visitMixinDefinition: function visitMixinDefinition(mixinDefinitionNode, visitArgs) { + this.context.frames.unshift(mixinDefinitionNode); + }, + visitMixinDefinitionOut: function visitMixinDefinitionOut(mixinDefinitionNode) { + this.context.frames.shift(); + }, + visitRuleset: function visitRuleset(rulesetNode, visitArgs) { + this.context.frames.unshift(rulesetNode); + }, + visitRulesetOut: function visitRulesetOut(rulesetNode) { + this.context.frames.shift(); + }, + visitMedia: function visitMedia(mediaNode, visitArgs) { + this.context.frames.unshift(mediaNode.rules[0]); + }, + visitMediaOut: function visitMediaOut(mediaNode) { + this.context.frames.shift(); + } +}; + +class SetTreeVisibilityVisitor { + constructor(visible) { + this.visible = visible; + } + + run(root) { + this.visit(root); + } + + visitArray(nodes) { + if (!nodes) { + return nodes; + } + + const cnt = nodes.length; + let i; + + for (i = 0; i < cnt; i++) { + this.visit(nodes[i]); + } + + return nodes; + } + + visit(node) { + if (!node) { + return node; + } + + if (node.constructor === Array) { + return this.visitArray(node); + } + + if (!node.blocksVisibility || node.blocksVisibility()) { + return node; + } + + if (this.visible) { + node.ensureVisibility(); + } else { + node.ensureInvisibility(); + } + + node.accept(this); + return node; + } + +} + +/* jshint loopfunc:true */ + +class ExtendFinderVisitor { + constructor() { + this._visitor = new Visitor(this); + this.contexts = []; + this.allExtendsStack = [[]]; + } + + run(root) { + root = this._visitor.visit(root); + root.allExtends = this.allExtendsStack[0]; + return root; + } + + visitDeclaration(declNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitMixinDefinition(mixinDefinitionNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitRuleset(rulesetNode, visitArgs) { + if (rulesetNode.root) { + return; + } + + let i; + let j; + let extend; + const allSelectorsExtendList = []; + let extendList; // get &:extend(.a); rules which apply to all selectors in this ruleset + + const rules = rulesetNode.rules; + const ruleCnt = rules ? rules.length : 0; + + for (i = 0; i < ruleCnt; i++) { + if (rulesetNode.rules[i] instanceof tree.Extend) { + allSelectorsExtendList.push(rules[i]); + rulesetNode.extendOnEveryPath = true; + } + } // now find every selector and apply the extends that apply to all extends + // and the ones which apply to an individual extend + + + const paths = rulesetNode.paths; + + for (i = 0; i < paths.length; i++) { + const selectorPath = paths[i]; + const selector = selectorPath[selectorPath.length - 1]; + const selExtendList = selector.extendList; + extendList = selExtendList ? copyArray(selExtendList).concat(allSelectorsExtendList) : allSelectorsExtendList; + + if (extendList) { + extendList = extendList.map(allSelectorsExtend => allSelectorsExtend.clone()); + } + + for (j = 0; j < extendList.length; j++) { + this.foundExtends = true; + extend = extendList[j]; + extend.findSelfSelectors(selectorPath); + extend.ruleset = rulesetNode; + + if (j === 0) { + extend.firstExtendOnThisSelectorPath = true; + } + + this.allExtendsStack[this.allExtendsStack.length - 1].push(extend); + } + } + + this.contexts.push(rulesetNode.selectors); + } + + visitRulesetOut(rulesetNode) { + if (!rulesetNode.root) { + this.contexts.length = this.contexts.length - 1; + } + } + + visitMedia(mediaNode, visitArgs) { + mediaNode.allExtends = []; + this.allExtendsStack.push(mediaNode.allExtends); + } + + visitMediaOut(mediaNode) { + this.allExtendsStack.length = this.allExtendsStack.length - 1; + } + + visitAtRule(atRuleNode, visitArgs) { + atRuleNode.allExtends = []; + this.allExtendsStack.push(atRuleNode.allExtends); + } + + visitAtRuleOut(atRuleNode) { + this.allExtendsStack.length = this.allExtendsStack.length - 1; + } + +} + +class ProcessExtendsVisitor { + constructor() { + this._visitor = new Visitor(this); + } + + run(root) { + const extendFinder = new ExtendFinderVisitor(); + this.extendIndices = {}; + extendFinder.run(root); + + if (!extendFinder.foundExtends) { + return root; + } + + root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends)); + this.allExtendsStack = [root.allExtends]; + + const newRoot = this._visitor.visit(root); + + this.checkExtendsForNonMatched(root.allExtends); + return newRoot; + } + + checkExtendsForNonMatched(extendList) { + const indices = this.extendIndices; + extendList.filter(extend => !extend.hasFoundMatches && extend.parent_ids.length == 1).forEach(extend => { + let selector = '_unknown_'; + + try { + selector = extend.selector.toCSS({}); + } catch (_) {} + + if (!indices[`${extend.index} ${selector}`]) { + indices[`${extend.index} ${selector}`] = true; + logger.warn(`extend '${selector}' has no matches`); + } + }); + } + + doExtendChaining(extendsList, extendsListTarget, iterationCount) { + // + // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering + // and pasting the selector we would do normally, but we are also adding an extend with the same target selector + // this means this new extend can then go and alter other extends + // + // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors + // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already + // processed if we look at each selector at a time, as is done in visitRuleset + let extendIndex; + let targetExtendIndex; + let matches; + const extendsToAdd = []; + let newSelector; + const extendVisitor = this; + let selectorPath; + let extend; + let targetExtend; + let newExtend; + iterationCount = iterationCount || 0; // loop through comparing every extend with every target extend. + // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place + // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one + // and the second is the target. + // the separation into two lists allows us to process a subset of chains with a bigger set, as is the + // case when processing media queries + + for (extendIndex = 0; extendIndex < extendsList.length; extendIndex++) { + for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) { + extend = extendsList[extendIndex]; + targetExtend = extendsListTarget[targetExtendIndex]; // look for circular references + + if (extend.parent_ids.indexOf(targetExtend.object_id) >= 0) { + continue; + } // find a match in the target extends self selector (the bit before :extend) + + + selectorPath = [targetExtend.selfSelectors[0]]; + matches = extendVisitor.findMatch(extend, selectorPath); + + if (matches.length) { + extend.hasFoundMatches = true; // we found a match, so for each self selector.. + + extend.selfSelectors.forEach(selfSelector => { + const info = targetExtend.visibilityInfo(); // process the extend as usual + + newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector, extend.isVisible()); // but now we create a new extend from it + + newExtend = new tree.Extend(targetExtend.selector, targetExtend.option, 0, targetExtend.fileInfo(), info); + newExtend.selfSelectors = newSelector; // add the extend onto the list of extends for that selector + + newSelector[newSelector.length - 1].extendList = [newExtend]; // record that we need to add it. + + extendsToAdd.push(newExtend); + newExtend.ruleset = targetExtend.ruleset; // remember its parents for circular references + + newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids); // only process the selector once.. if we have :extend(.a,.b) then multiple + // extends will look at the same selector path, so when extending + // we know that any others will be duplicates in terms of what is added to the css + + if (targetExtend.firstExtendOnThisSelectorPath) { + newExtend.firstExtendOnThisSelectorPath = true; + targetExtend.ruleset.paths.push(newSelector); + } + }); + } + } + } + + if (extendsToAdd.length) { + // try to detect circular references to stop a stack overflow. + // may no longer be needed. + this.extendChainCount++; + + if (iterationCount > 100) { + let selectorOne = '{unable to calculate}'; + let selectorTwo = '{unable to calculate}'; + + try { + selectorOne = extendsToAdd[0].selfSelectors[0].toCSS(); + selectorTwo = extendsToAdd[0].selector.toCSS(); + } catch (e) {} + + throw { + message: `extend circular reference detected. One of the circular extends is currently:${selectorOne}:extend(${selectorTwo})` + }; + } // now process the new extends on the existing rules so that we can handle a extending b extending c extending + // d extending e... + + + return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1)); + } else { + return extendsToAdd; + } + } + + visitDeclaration(ruleNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitMixinDefinition(mixinDefinitionNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitSelector(selectorNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitRuleset(rulesetNode, visitArgs) { + if (rulesetNode.root) { + return; + } + + let matches; + let pathIndex; + let extendIndex; + const allExtends = this.allExtendsStack[this.allExtendsStack.length - 1]; + const selectorsToAdd = []; + const extendVisitor = this; + let selectorPath; // look at each selector path in the ruleset, find any extend matches and then copy, find and replace + + for (extendIndex = 0; extendIndex < allExtends.length; extendIndex++) { + for (pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) { + selectorPath = rulesetNode.paths[pathIndex]; // extending extends happens initially, before the main pass + + if (rulesetNode.extendOnEveryPath) { + continue; + } + + const extendList = selectorPath[selectorPath.length - 1].extendList; + + if (extendList && extendList.length) { + continue; + } + + matches = this.findMatch(allExtends[extendIndex], selectorPath); + + if (matches.length) { + allExtends[extendIndex].hasFoundMatches = true; + allExtends[extendIndex].selfSelectors.forEach(selfSelector => { + let extendedSelectors; + extendedSelectors = extendVisitor.extendSelector(matches, selectorPath, selfSelector, allExtends[extendIndex].isVisible()); + selectorsToAdd.push(extendedSelectors); + }); + } + } + } + + rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd); + } + + findMatch(extend, haystackSelectorPath) { + // + // look through the haystack selector path to try and find the needle - extend.selector + // returns an array of selector matches that can then be replaced + // + let haystackSelectorIndex; + let hackstackSelector; + let hackstackElementIndex; + let haystackElement; + let targetCombinator; + let i; + const extendVisitor = this; + const needleElements = extend.selector.elements; + const potentialMatches = []; + let potentialMatch; + const matches = []; // loop through the haystack elements + + for (haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) { + hackstackSelector = haystackSelectorPath[haystackSelectorIndex]; + + for (hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) { + haystackElement = hackstackSelector.elements[hackstackElementIndex]; // if we allow elements before our match we can add a potential match every time. otherwise only at the first element. + + if (extend.allowBefore || haystackSelectorIndex === 0 && hackstackElementIndex === 0) { + potentialMatches.push({ + pathIndex: haystackSelectorIndex, + index: hackstackElementIndex, + matched: 0, + initialCombinator: haystackElement.combinator + }); + } + + for (i = 0; i < potentialMatches.length; i++) { + potentialMatch = potentialMatches[i]; // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't + // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to + // work out what the resulting combinator will be + + targetCombinator = haystackElement.combinator.value; + + if (targetCombinator === '' && hackstackElementIndex === 0) { + targetCombinator = ' '; + } // if we don't match, null our match to indicate failure + + + if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) || potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator) { + potentialMatch = null; + } else { + potentialMatch.matched++; + } // if we are still valid and have finished, test whether we have elements after and whether these are allowed + + + if (potentialMatch) { + potentialMatch.finished = potentialMatch.matched === needleElements.length; + + if (potentialMatch.finished && !extend.allowAfter && (hackstackElementIndex + 1 < hackstackSelector.elements.length || haystackSelectorIndex + 1 < haystackSelectorPath.length)) { + potentialMatch = null; + } + } // if null we remove, if not, we are still valid, so either push as a valid match or continue + + + if (potentialMatch) { + if (potentialMatch.finished) { + potentialMatch.length = needleElements.length; + potentialMatch.endPathIndex = haystackSelectorIndex; + potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match + + potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again + + matches.push(potentialMatch); + } + } else { + potentialMatches.splice(i, 1); + i--; + } + } + } + } + + return matches; + } + + isElementValuesEqual(elementValue1, elementValue2) { + if (typeof elementValue1 === 'string' || typeof elementValue2 === 'string') { + return elementValue1 === elementValue2; + } + + if (elementValue1 instanceof tree.Attribute) { + if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) { + return false; + } + + if (!elementValue1.value || !elementValue2.value) { + if (elementValue1.value || elementValue2.value) { + return false; + } + + return true; + } + + elementValue1 = elementValue1.value.value || elementValue1.value; + elementValue2 = elementValue2.value.value || elementValue2.value; + return elementValue1 === elementValue2; + } + + elementValue1 = elementValue1.value; + elementValue2 = elementValue2.value; + + if (elementValue1 instanceof tree.Selector) { + if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) { + return false; + } + + for (let i = 0; i < elementValue1.elements.length; i++) { + if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) { + if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) { + return false; + } + } + + if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) { + return false; + } + } + + return true; + } + + return false; + } + + extendSelector(matches, selectorPath, replacementSelector, isVisible) { + // for a set of matches, replace each match with the replacement selector + let currentSelectorPathIndex = 0; + let currentSelectorPathElementIndex = 0; + let path = []; + let matchIndex; + let selector; + let firstElement; + let match; + let newElements; + + for (matchIndex = 0; matchIndex < matches.length; matchIndex++) { + match = matches[matchIndex]; + selector = selectorPath[match.pathIndex]; + firstElement = new tree.Element(match.initialCombinator, replacementSelector.elements[0].value, replacementSelector.elements[0].isVariable, replacementSelector.elements[0].getIndex(), replacementSelector.elements[0].fileInfo()); + + if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) { + path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); + currentSelectorPathElementIndex = 0; + currentSelectorPathIndex++; + } + + newElements = selector.elements.slice(currentSelectorPathElementIndex, match.index).concat([firstElement]).concat(replacementSelector.elements.slice(1)); + + if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) { + path[path.length - 1].elements = path[path.length - 1].elements.concat(newElements); + } else { + path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex)); + path.push(new tree.Selector(newElements)); + } + + currentSelectorPathIndex = match.endPathIndex; + currentSelectorPathElementIndex = match.endPathElementIndex; + + if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) { + currentSelectorPathElementIndex = 0; + currentSelectorPathIndex++; + } + } + + if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) { + path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); + currentSelectorPathIndex++; + } + + path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length)); + path = path.map(currentValue => { + // we can re-use elements here, because the visibility property matters only for selectors + const derived = currentValue.createDerived(currentValue.elements); + + if (isVisible) { + derived.ensureVisibility(); + } else { + derived.ensureInvisibility(); + } + + return derived; + }); + return path; + } + + visitMedia(mediaNode, visitArgs) { + let newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); + newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends)); + this.allExtendsStack.push(newAllExtends); + } + + visitMediaOut(mediaNode) { + const lastIndex = this.allExtendsStack.length - 1; + this.allExtendsStack.length = lastIndex; + } + + visitAtRule(atRuleNode, visitArgs) { + let newAllExtends = atRuleNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); + newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, atRuleNode.allExtends)); + this.allExtendsStack.push(newAllExtends); + } + + visitAtRuleOut(atRuleNode) { + const lastIndex = this.allExtendsStack.length - 1; + this.allExtendsStack.length = lastIndex; + } + +} + +class JoinSelectorVisitor { + constructor() { + this.contexts = [[]]; + this._visitor = new Visitor(this); + } + + run(root) { + return this._visitor.visit(root); + } + + visitDeclaration(declNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitMixinDefinition(mixinDefinitionNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitRuleset(rulesetNode, visitArgs) { + const context = this.contexts[this.contexts.length - 1]; + const paths = []; + let selectors; + this.contexts.push(paths); + + if (!rulesetNode.root) { + selectors = rulesetNode.selectors; + + if (selectors) { + selectors = selectors.filter(selector => selector.getIsOutput()); + rulesetNode.selectors = selectors.length ? selectors : selectors = null; + + if (selectors) { + rulesetNode.joinSelectors(paths, context, selectors); + } + } + + if (!selectors) { + rulesetNode.rules = null; + } + + rulesetNode.paths = paths; + } + } + + visitRulesetOut(rulesetNode) { + this.contexts.length = this.contexts.length - 1; + } + + visitMedia(mediaNode, visitArgs) { + const context = this.contexts[this.contexts.length - 1]; + mediaNode.rules[0].root = context.length === 0 || context[0].multiMedia; + } + + visitAtRule(atRuleNode, visitArgs) { + const context = this.contexts[this.contexts.length - 1]; + + if (atRuleNode.rules && atRuleNode.rules.length) { + atRuleNode.rules[0].root = atRuleNode.isRooted || context.length === 0 || null; + } + } + +} + +class CSSVisitorUtils { + constructor(context) { + this._visitor = new Visitor(this); + this._context = context; + } + + containsSilentNonBlockedChild(bodyRules) { + let rule; + + if (!bodyRules) { + return false; + } + + for (let r = 0; r < bodyRules.length; r++) { + rule = bodyRules[r]; + + if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) { + // the atrule contains something that was referenced (likely by extend) + // therefore it needs to be shown in output too + return true; + } + } + + return false; + } + + keepOnlyVisibleChilds(owner) { + if (owner && owner.rules) { + owner.rules = owner.rules.filter(thing => thing.isVisible()); + } + } + + isEmpty(owner) { + return owner && owner.rules ? owner.rules.length === 0 : true; + } + + hasVisibleSelector(rulesetNode) { + return rulesetNode && rulesetNode.paths ? rulesetNode.paths.length > 0 : false; + } + + resolveVisibility(node, originalRules) { + if (!node.blocksVisibility()) { + if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) { + return; + } + + return node; + } + + const compiledRulesBody = node.rules[0]; + this.keepOnlyVisibleChilds(compiledRulesBody); + + if (this.isEmpty(compiledRulesBody)) { + return; + } + + node.ensureVisibility(); + node.removeVisibilityBlock(); + return node; + } + + isVisibleRuleset(rulesetNode) { + if (rulesetNode.firstRoot) { + return true; + } + + if (this.isEmpty(rulesetNode)) { + return false; + } + + if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) { + return false; + } + + return true; + } + +} + +const ToCSSVisitor = function ToCSSVisitor(context) { + this._visitor = new Visitor(this); + this._context = context; + this.utils = new CSSVisitorUtils(context); +}; + +ToCSSVisitor.prototype = { + isReplacing: true, + run: function run(root) { + return this._visitor.visit(root); + }, + visitDeclaration: function visitDeclaration(declNode, visitArgs) { + if (declNode.blocksVisibility() || declNode.variable) { + return; + } + + return declNode; + }, + visitMixinDefinition: function visitMixinDefinition(mixinNode, visitArgs) { + // mixin definitions do not get eval'd - this means they keep state + // so we have to clear that state here so it isn't used if toCSS is called twice + mixinNode.frames = []; + }, + visitExtend: function visitExtend(extendNode, visitArgs) {}, + visitComment: function visitComment(commentNode, visitArgs) { + if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) { + return; + } + + return commentNode; + }, + visitMedia: function visitMedia(mediaNode, visitArgs) { + const originalRules = mediaNode.rules[0].rules; + mediaNode.accept(this._visitor); + visitArgs.visitDeeper = false; + return this.utils.resolveVisibility(mediaNode, originalRules); + }, + visitImport: function visitImport(importNode, visitArgs) { + if (importNode.blocksVisibility()) { + return; + } + + return importNode; + }, + visitAtRule: function visitAtRule(atRuleNode, visitArgs) { + if (atRuleNode.rules && atRuleNode.rules.length) { + return this.visitAtRuleWithBody(atRuleNode, visitArgs); + } else { + return this.visitAtRuleWithoutBody(atRuleNode, visitArgs); + } + }, + visitAnonymous: function visitAnonymous(anonymousNode, visitArgs) { + if (!anonymousNode.blocksVisibility()) { + anonymousNode.accept(this._visitor); + return anonymousNode; + } + }, + visitAtRuleWithBody: function visitAtRuleWithBody(atRuleNode, visitArgs) { + // if there is only one nested ruleset and that one has no path, then it is + // just fake ruleset + function hasFakeRuleset(atRuleNode) { + const bodyRules = atRuleNode.rules; + return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0); + } + + function getBodyRules(atRuleNode) { + const nodeRules = atRuleNode.rules; + + if (hasFakeRuleset(atRuleNode)) { + return nodeRules[0].rules; + } + + return nodeRules; + } // it is still true that it is only one ruleset in array + // this is last such moment + // process childs + + + const originalRules = getBodyRules(atRuleNode); + atRuleNode.accept(this._visitor); + visitArgs.visitDeeper = false; + + if (!this.utils.isEmpty(atRuleNode)) { + this._mergeRules(atRuleNode.rules[0].rules); + } + + return this.utils.resolveVisibility(atRuleNode, originalRules); + }, + visitAtRuleWithoutBody: function visitAtRuleWithoutBody(atRuleNode, visitArgs) { + if (atRuleNode.blocksVisibility()) { + return; + } + + if (atRuleNode.name === '@charset') { + // Only output the debug info together with subsequent @charset definitions + // a comment (or @media statement) before the actual @charset atrule would + // be considered illegal css as it has to be on the first line + if (this.charset) { + if (atRuleNode.debugInfo) { + const comment = new tree.Comment(`/* ${atRuleNode.toCSS(this._context).replace(/\n/g, '')} */\n`); + comment.debugInfo = atRuleNode.debugInfo; + return this._visitor.visit(comment); + } + + return; + } + + this.charset = true; + } + + return atRuleNode; + }, + checkValidNodes: function checkValidNodes(rules, isRoot) { + if (!rules) { + return; + } + + for (let i = 0; i < rules.length; i++) { + const ruleNode = rules[i]; + + if (isRoot && ruleNode instanceof tree.Declaration && !ruleNode.variable) { + throw { + message: 'Properties must be inside selector blocks. They cannot be in the root', + index: ruleNode.getIndex(), + filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename + }; + } + + if (ruleNode instanceof tree.Call) { + throw { + message: `Function '${ruleNode.name}' is undefined`, + index: ruleNode.getIndex(), + filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename + }; + } + + if (ruleNode.type && !ruleNode.allowRoot) { + throw { + message: `${ruleNode.type} node returned by a function is not valid here`, + index: ruleNode.getIndex(), + filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename + }; + } + } + }, + visitRuleset: function visitRuleset(rulesetNode, visitArgs) { + // at this point rulesets are nested into each other + let rule; + const rulesets = []; + this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot); + + if (!rulesetNode.root) { + // remove invisible paths + this._compileRulesetPaths(rulesetNode); // remove rulesets from this ruleset body and compile them separately + + + const nodeRules = rulesetNode.rules; + let nodeRuleCnt = nodeRules ? nodeRules.length : 0; + + for (let i = 0; i < nodeRuleCnt;) { + rule = nodeRules[i]; + + if (rule && rule.rules) { + // visit because we are moving them out from being a child + rulesets.push(this._visitor.visit(rule)); + nodeRules.splice(i, 1); + nodeRuleCnt--; + continue; + } + + i++; + } // accept the visitor to remove rules and refactor itself + // then we can decide nogw whether we want it or not + // compile body + + + if (nodeRuleCnt > 0) { + rulesetNode.accept(this._visitor); + } else { + rulesetNode.rules = null; + } + + visitArgs.visitDeeper = false; + } else { + // if (! rulesetNode.root) { + rulesetNode.accept(this._visitor); + visitArgs.visitDeeper = false; + } + + if (rulesetNode.rules) { + this._mergeRules(rulesetNode.rules); + + this._removeDuplicateRules(rulesetNode.rules); + } // now decide whether we keep the ruleset + + + if (this.utils.isVisibleRuleset(rulesetNode)) { + rulesetNode.ensureVisibility(); + rulesets.splice(0, 0, rulesetNode); + } + + if (rulesets.length === 1) { + return rulesets[0]; + } + + return rulesets; + }, + _compileRulesetPaths: function _compileRulesetPaths(rulesetNode) { + if (rulesetNode.paths) { + rulesetNode.paths = rulesetNode.paths.filter(p => { + let i; + + if (p[0].elements[0].combinator.value === ' ') { + p[0].elements[0].combinator = new tree.Combinator(''); + } + + for (i = 0; i < p.length; i++) { + if (p[i].isVisible() && p[i].getIsOutput()) { + return true; + } + } + + return false; + }); + } + }, + _removeDuplicateRules: function _removeDuplicateRules(rules) { + if (!rules) { + return; + } // remove duplicates + + + const ruleCache = {}; + let ruleList; + let rule; + let i; + + for (i = rules.length - 1; i >= 0; i--) { + rule = rules[i]; + + if (rule instanceof tree.Declaration) { + if (!ruleCache[rule.name]) { + ruleCache[rule.name] = rule; + } else { + ruleList = ruleCache[rule.name]; + + if (ruleList instanceof tree.Declaration) { + ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._context)]; + } + + const ruleCSS = rule.toCSS(this._context); + + if (ruleList.indexOf(ruleCSS) !== -1) { + rules.splice(i, 1); + } else { + ruleList.push(ruleCSS); + } + } + } + } + }, + _mergeRules: function _mergeRules(rules) { + if (!rules) { + return; + } + + const groups = {}; + const groupsArr = []; + + for (let i = 0; i < rules.length; i++) { + const rule = rules[i]; + + if (rule.merge) { + const key = rule.name; + groups[key] ? rules.splice(i--, 1) : groupsArr.push(groups[key] = []); + groups[key].push(rule); + } + } + + groupsArr.forEach(group => { + if (group.length > 0) { + const result = group[0]; + let space = []; + const comma = [new tree.Expression(space)]; + group.forEach(rule => { + if (rule.merge === '+' && space.length > 0) { + comma.push(new tree.Expression(space = [])); + } + + space.push(rule.value); + result.important = result.important || rule.important; + }); + result.value = new tree.Value(comma); + } + }); + } +}; + +var visitors = { + Visitor, + ImportVisitor, + MarkVisibleSelectorsVisitor: SetTreeVisibilityVisitor, + ExtendVisitor: ProcessExtendsVisitor, + JoinSelectorVisitor, + ToCSSVisitor +}; + +// Split the input into chunks. +var chunker = ((input, fail) => { + const len = input.length; + let level = 0; + let parenLevel = 0; + let lastOpening; + let lastOpeningParen; + let lastMultiComment; + let lastMultiCommentEndBrace; + const chunks = []; + let emitFrom = 0; + let chunkerCurrentIndex; + let currentChunkStartIndex; + let cc; + let cc2; + let matched; + + function emitChunk(force) { + const len = chunkerCurrentIndex - emitFrom; + + if (len < 512 && !force || !len) { + return; + } + + chunks.push(input.slice(emitFrom, chunkerCurrentIndex + 1)); + emitFrom = chunkerCurrentIndex + 1; + } + + for (chunkerCurrentIndex = 0; chunkerCurrentIndex < len; chunkerCurrentIndex++) { + cc = input.charCodeAt(chunkerCurrentIndex); + + if (cc >= 97 && cc <= 122 || cc < 34) { + // a-z or whitespace + continue; + } + + switch (cc) { + case 40: + // ( + parenLevel++; + lastOpeningParen = chunkerCurrentIndex; + continue; + + case 41: + // ) + if (--parenLevel < 0) { + return fail('missing opening `(`', chunkerCurrentIndex); + } + + continue; + + case 59: + // ; + if (!parenLevel) { + emitChunk(); + } + + continue; + + case 123: + // { + level++; + lastOpening = chunkerCurrentIndex; + continue; + + case 125: + // } + if (--level < 0) { + return fail('missing opening `{`', chunkerCurrentIndex); + } + + if (!level && !parenLevel) { + emitChunk(); + } + + continue; + + case 92: + // \ + if (chunkerCurrentIndex < len - 1) { + chunkerCurrentIndex++; + continue; + } + + return fail('unescaped `\\`', chunkerCurrentIndex); + + case 34: + case 39: + case 96: + // ", ' and ` + matched = 0; + currentChunkStartIndex = chunkerCurrentIndex; + + for (chunkerCurrentIndex = chunkerCurrentIndex + 1; chunkerCurrentIndex < len; chunkerCurrentIndex++) { + cc2 = input.charCodeAt(chunkerCurrentIndex); + + if (cc2 > 96) { + continue; + } + + if (cc2 == cc) { + matched = 1; + break; + } + + if (cc2 == 92) { + // \ + if (chunkerCurrentIndex == len - 1) { + return fail('unescaped `\\`', chunkerCurrentIndex); + } + + chunkerCurrentIndex++; + } + } + + if (matched) { + continue; + } + + return fail(`unmatched \`${String.fromCharCode(cc)}\``, currentChunkStartIndex); + + case 47: + // /, check for comment + if (parenLevel || chunkerCurrentIndex == len - 1) { + continue; + } + + cc2 = input.charCodeAt(chunkerCurrentIndex + 1); + + if (cc2 == 47) { + // //, find lnfeed + for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len; chunkerCurrentIndex++) { + cc2 = input.charCodeAt(chunkerCurrentIndex); + + if (cc2 <= 13 && (cc2 == 10 || cc2 == 13)) { + break; + } + } + } else if (cc2 == 42) { + // /*, find */ + lastMultiComment = currentChunkStartIndex = chunkerCurrentIndex; + + for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len - 1; chunkerCurrentIndex++) { + cc2 = input.charCodeAt(chunkerCurrentIndex); + + if (cc2 == 125) { + lastMultiCommentEndBrace = chunkerCurrentIndex; + } + + if (cc2 != 42) { + continue; + } + + if (input.charCodeAt(chunkerCurrentIndex + 1) == 47) { + break; + } + } + + if (chunkerCurrentIndex == len - 1) { + return fail('missing closing `*/`', currentChunkStartIndex); + } + + chunkerCurrentIndex++; + } + + continue; + + case 42: + // *, check for unmatched */ + if (chunkerCurrentIndex < len - 1 && input.charCodeAt(chunkerCurrentIndex + 1) == 47) { + return fail('unmatched `/*`', chunkerCurrentIndex); + } + + continue; + } + } + + if (level !== 0) { + if (lastMultiComment > lastOpening && lastMultiCommentEndBrace > lastMultiComment) { + return fail('missing closing `}` or `*/`', lastOpening); + } else { + return fail('missing closing `}`', lastOpening); + } + } else if (parenLevel !== 0) { + return fail('missing closing `)`', lastOpeningParen); + } + + emitChunk(true); + return chunks; +}); + +var getParserInput = (() => { + let // Less input string + input; + let // current chunk + j; + const // holds state for backtracking + saveStack = []; + let // furthest index the parser has gone to + furthest; + let // if this is furthest we got to, this is the probably cause + furthestPossibleErrorMessage; + let // chunkified input + chunks; + let // current chunk + current; + let // index of current chunk, in `input` + currentPos; + const parserInput = {}; + const CHARCODE_SPACE = 32; + const CHARCODE_TAB = 9; + const CHARCODE_LF = 10; + const CHARCODE_CR = 13; + const CHARCODE_PLUS = 43; + const CHARCODE_COMMA = 44; + const CHARCODE_FORWARD_SLASH = 47; + const CHARCODE_9 = 57; + + function skipWhitespace(length) { + const oldi = parserInput.i; + const oldj = j; + const curr = parserInput.i - currentPos; + const endIndex = parserInput.i + current.length - curr; + const mem = parserInput.i += length; + const inp = input; + let c; + let nextChar; + let comment; + + for (; parserInput.i < endIndex; parserInput.i++) { + c = inp.charCodeAt(parserInput.i); + + if (parserInput.autoCommentAbsorb && c === CHARCODE_FORWARD_SLASH) { + nextChar = inp.charAt(parserInput.i + 1); + + if (nextChar === '/') { + comment = { + index: parserInput.i, + isLineComment: true + }; + let nextNewLine = inp.indexOf('\n', parserInput.i + 2); + + if (nextNewLine < 0) { + nextNewLine = endIndex; + } + + parserInput.i = nextNewLine; + comment.text = inp.substr(comment.index, parserInput.i - comment.index); + parserInput.commentStore.push(comment); + continue; + } else if (nextChar === '*') { + const nextStarSlash = inp.indexOf('*/', parserInput.i + 2); + + if (nextStarSlash >= 0) { + comment = { + index: parserInput.i, + text: inp.substr(parserInput.i, nextStarSlash + 2 - parserInput.i), + isLineComment: false + }; + parserInput.i += comment.text.length - 1; + parserInput.commentStore.push(comment); + continue; + } + } + + break; + } + + if (c !== CHARCODE_SPACE && c !== CHARCODE_LF && c !== CHARCODE_TAB && c !== CHARCODE_CR) { + break; + } + } + + current = current.slice(length + parserInput.i - mem + curr); + currentPos = parserInput.i; + + if (!current.length) { + if (j < chunks.length - 1) { + current = chunks[++j]; + skipWhitespace(0); // skip space at the beginning of a chunk + + return true; // things changed + } + + parserInput.finished = true; + } + + return oldi !== parserInput.i || oldj !== j; + } + + parserInput.save = () => { + currentPos = parserInput.i; + saveStack.push({ + current, + i: parserInput.i, + j + }); + }; + + parserInput.restore = possibleErrorMessage => { + if (parserInput.i > furthest || parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage) { + furthest = parserInput.i; + furthestPossibleErrorMessage = possibleErrorMessage; + } + + const state = saveStack.pop(); + current = state.current; + currentPos = parserInput.i = state.i; + j = state.j; + }; + + parserInput.forget = () => { + saveStack.pop(); + }; + + parserInput.isWhitespace = offset => { + const pos = parserInput.i + (offset || 0); + const code = input.charCodeAt(pos); + return code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF; + }; // Specialization of $(tok) + + + parserInput.$re = tok => { + if (parserInput.i > currentPos) { + current = current.slice(parserInput.i - currentPos); + currentPos = parserInput.i; + } + + const m = tok.exec(current); + + if (!m) { + return null; + } + + skipWhitespace(m[0].length); + + if (typeof m === 'string') { + return m; + } + + return m.length === 1 ? m[0] : m; + }; + + parserInput.$char = tok => { + if (input.charAt(parserInput.i) !== tok) { + return null; + } + + skipWhitespace(1); + return tok; + }; + + parserInput.$str = tok => { + const tokLength = tok.length; // https://jsperf.com/string-startswith/21 + + for (let i = 0; i < tokLength; i++) { + if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { + return null; + } + } + + skipWhitespace(tokLength); + return tok; + }; + + parserInput.$quoted = loc => { + const pos = loc || parserInput.i; + const startChar = input.charAt(pos); + + if (startChar !== '\'' && startChar !== '"') { + return; + } + + const length = input.length; + const currentPosition = pos; + + for (let i = 1; i + currentPosition < length; i++) { + const nextChar = input.charAt(i + currentPosition); + + switch (nextChar) { + case '\\': + i++; + continue; + + case '\r': + case '\n': + break; + + case startChar: + const str = input.substr(currentPosition, i + 1); + + if (!loc && loc !== 0) { + skipWhitespace(i + 1); + return str; + } + + return [startChar, str]; + + default: + } + } + + return null; + }; + /** + * Permissive parsing. Ignores everything except matching {} [] () and quotes + * until matching token (outside of blocks) + */ + + + parserInput.$parseUntil = tok => { + let quote = ''; + let returnVal = null; + let inComment = false; + let blockDepth = 0; + const blockStack = []; + const parseGroups = []; + const length = input.length; + const startPos = parserInput.i; + let lastPos = parserInput.i; + let i = parserInput.i; + let loop = true; + let testChar; + + if (typeof tok === 'string') { + testChar = char => char === tok; + } else { + testChar = char => tok.test(char); + } + + do { + let nextChar = input.charAt(i); + + if (blockDepth === 0 && testChar(nextChar)) { + returnVal = input.substr(lastPos, i - lastPos); + + if (returnVal) { + parseGroups.push(returnVal); + } else { + parseGroups.push(' '); + } + + returnVal = parseGroups; + skipWhitespace(i - startPos); + loop = false; + } else { + if (inComment) { + if (nextChar === '*' && input.charAt(i + 1) === '/') { + i++; + blockDepth--; + inComment = false; + } + + i++; + continue; + } + + switch (nextChar) { + case '\\': + i++; + nextChar = input.charAt(i); + parseGroups.push(input.substr(lastPos, i - lastPos + 1)); + lastPos = i + 1; + break; + + case '/': + if (input.charAt(i + 1) === '*') { + i++; + inComment = true; + blockDepth++; + } + + break; + + case '\'': + case '"': + quote = parserInput.$quoted(i); + + if (quote) { + parseGroups.push(input.substr(lastPos, i - lastPos), quote); + i += quote[1].length - 1; + lastPos = i + 1; + } else { + skipWhitespace(i - startPos); + returnVal = nextChar; + loop = false; + } + + break; + + case '{': + blockStack.push('}'); + blockDepth++; + break; + + case '(': + blockStack.push(')'); + blockDepth++; + break; + + case '[': + blockStack.push(']'); + blockDepth++; + break; + + case '}': + case ')': + case ']': + const expected = blockStack.pop(); + + if (nextChar === expected) { + blockDepth--; + } else { + // move the parser to the error and return expected + skipWhitespace(i - startPos); + returnVal = expected; + loop = false; + } + + } + + i++; + + if (i > length) { + loop = false; + } + } + } while (loop); + + return returnVal ? returnVal : null; + }; + + parserInput.autoCommentAbsorb = true; + parserInput.commentStore = []; + parserInput.finished = false; // Same as $(), but don't change the state of the parser, + // just return the match. + + parserInput.peek = tok => { + if (typeof tok === 'string') { + // https://jsperf.com/string-startswith/21 + for (let i = 0; i < tok.length; i++) { + if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { + return false; + } + } + + return true; + } else { + return tok.test(current); + } + }; // Specialization of peek() + // TODO remove or change some currentChar calls to peekChar + + + parserInput.peekChar = tok => input.charAt(parserInput.i) === tok; + + parserInput.currentChar = () => input.charAt(parserInput.i); + + parserInput.prevChar = () => input.charAt(parserInput.i - 1); + + parserInput.getInput = () => input; + + parserInput.peekNotNumeric = () => { + const c = input.charCodeAt(parserInput.i); // Is the first char of the dimension 0-9, '.', '+' or '-' + + return c > CHARCODE_9 || c < CHARCODE_PLUS || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA; + }; + + parserInput.start = (str, chunkInput, failFunction) => { + input = str; + parserInput.i = j = currentPos = furthest = 0; // chunking apparently makes things quicker (but my tests indicate + // it might actually make things slower in node at least) + // and it is a non-perfect parse - it can't recognise + // unquoted urls, meaning it can't distinguish comments + // meaning comments with quotes or {}() in them get 'counted' + // and then lead to parse errors. + // In addition if the chunking chunks in the wrong place we might + // not be able to parse a parser statement in one go + // this is officially deprecated but can be switched on via an option + // in the case it causes too much performance issues. + + if (chunkInput) { + chunks = chunker(str, failFunction); + } else { + chunks = [str]; + } + + current = chunks[0]; + skipWhitespace(0); + }; + + parserInput.end = () => { + let message; + const isFinished = parserInput.i >= input.length; + + if (parserInput.i < furthest) { + message = furthestPossibleErrorMessage; + parserInput.i = furthest; + } + + return { + isFinished, + furthest: parserInput.i, + furthestPossibleErrorMessage: message, + furthestReachedEnd: parserInput.i >= input.length - 1, + furthestChar: input[parserInput.i] + }; + }; + + return parserInput; +}); + +// less.js - parser +// +// A relatively straight-forward predictive parser. +// There is no tokenization/lexing stage, the input is parsed +// in one sweep. +// +// To make the parser fast enough to run in the browser, several +// optimization had to be made: +// +// - Matching and slicing on a huge input is often cause of slowdowns. +// The solution is to chunkify the input into smaller strings. +// The chunks are stored in the `chunks` var, +// `j` holds the current chunk index, and `currentPos` holds +// the index of the current chunk in relation to `input`. +// This gives us an almost 4x speed-up. +// +// - In many cases, we don't need to match individual tokens; +// for example, if a value doesn't hold any variables, operations +// or dynamic references, the parser can effectively 'skip' it, +// treating it as a literal. +// An example would be '1px solid #000' - which evaluates to itself, +// we don't need to know what the individual components are. +// The drawback, of course is that you don't get the benefits of +// syntax-checking on the CSS. This gives us a 50% speed-up in the parser, +// and a smaller speed-up in the code-gen. +// +// +// Token matching is done with the `$` function, which either takes +// a terminal string or regexp, or a non-terminal function to call. +// It also takes care of moving all the indices forwards. +// + +const Parser = function Parser(context, imports, fileInfo) { + let parsers; + const parserInput = getParserInput(); + + function error(msg, type) { + throw new LessError({ + index: parserInput.i, + filename: fileInfo.filename, + type: type || 'Syntax', + message: msg + }, imports); + } + + function expect(arg, msg) { + // some older browsers return typeof 'function' for RegExp + const result = arg instanceof Function ? arg.call(parsers) : parserInput.$re(arg); + + if (result) { + return result; + } + + error(msg || (typeof arg === 'string' ? `expected '${arg}' got '${parserInput.currentChar()}'` : 'unexpected token')); + } // Specialization of expect() + + + function expectChar(arg, msg) { + if (parserInput.$char(arg)) { + return arg; + } + + error(msg || `expected '${arg}' got '${parserInput.currentChar()}'`); + } + + function getDebugInfo(index) { + const filename = fileInfo.filename; + return { + lineNumber: getLocation(index, parserInput.getInput()).line + 1, + fileName: filename + }; + } + /** + * Used after initial parsing to create nodes on the fly + * + * @param {String} str - string to parse + * @param {Array} parseList - array of parsers to run input through e.g. ["value", "important"] + * @param {Number} currentIndex - start number to begin indexing + * @param {Object} fileInfo - fileInfo to attach to created nodes + */ + + + function parseNode(str, parseList, currentIndex, fileInfo, callback) { + let result; + const returnNodes = []; + const parser = parserInput; + + try { + parser.start(str, false, function fail(msg, index) { + callback({ + message: msg, + index: index + currentIndex + }); + }); + + for (let x = 0, p, i; p = parseList[x]; x++) { + i = parser.i; + result = parsers[p](); + + if (result) { + result._index = i + currentIndex; + result._fileInfo = fileInfo; + returnNodes.push(result); + } else { + returnNodes.push(null); + } + } + + const endInfo = parser.end(); + + if (endInfo.isFinished) { + callback(null, returnNodes); + } else { + callback(true, null); + } + } catch (e) { + throw new LessError({ + index: e.index + currentIndex, + message: e.message + }, imports, fileInfo.filename); + } + } // + // The Parser + // + + + return { + parserInput, + imports, + fileInfo, + parseNode, + // + // Parse an input string into an abstract syntax tree, + // @param str A string containing 'less' markup + // @param callback call `callback` when done. + // @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply + // + parse: function parse(str, callback, additionalData) { + let root; + let error = null; + let globalVars; + let modifyVars; + let ignored; + let preText = ''; + globalVars = additionalData && additionalData.globalVars ? `${Parser.serializeVars(additionalData.globalVars)}\n` : ''; + modifyVars = additionalData && additionalData.modifyVars ? `\n${Parser.serializeVars(additionalData.modifyVars)}` : ''; + + if (context.pluginManager) { + const preProcessors = context.pluginManager.getPreProcessors(); + + for (let i = 0; i < preProcessors.length; i++) { + str = preProcessors[i].process(str, { + context, + imports, + fileInfo + }); + } + } + + if (globalVars || additionalData && additionalData.banner) { + preText = (additionalData && additionalData.banner ? additionalData.banner : '') + globalVars; + ignored = imports.contentsIgnoredChars; + ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0; + ignored[fileInfo.filename] += preText.length; + } + + str = str.replace(/\r\n?/g, '\n'); // Remove potential UTF Byte Order Mark + + str = preText + str.replace(/^\uFEFF/, '') + modifyVars; + imports.contents[fileInfo.filename] = str; // Start with the primary rule. + // The whole syntax tree is held under a Ruleset node, + // with the `root` property set to true, so no `{}` are + // output. The callback is called when the input is parsed. + + try { + parserInput.start(str, context.chunkInput, function fail(msg, index) { + throw new LessError({ + index, + type: 'Parse', + message: msg, + filename: fileInfo.filename + }, imports); + }); + tree.Node.prototype.parse = this; + root = new tree.Ruleset(null, this.parsers.primary()); + tree.Node.prototype.rootNode = root; + root.root = true; + root.firstRoot = true; + root.functionRegistry = functionRegistry.inherit(); + } catch (e) { + return callback(new LessError(e, imports, fileInfo.filename)); + } // If `i` is smaller than the `input.length - 1`, + // it means the parser wasn't able to parse the whole + // string, so we've got a parsing error. + // + // We try to extract a \n delimited string, + // showing the line where the parse error occurred. + // We split it up into two parts (the part which parsed, + // and the part which didn't), so we can color them differently. + + + const endInfo = parserInput.end(); + + if (!endInfo.isFinished) { + let message = endInfo.furthestPossibleErrorMessage; + + if (!message) { + message = 'Unrecognised input'; + + if (endInfo.furthestChar === '}') { + message += '. Possibly missing opening \'{\''; + } else if (endInfo.furthestChar === ')') { + message += '. Possibly missing opening \'(\''; + } else if (endInfo.furthestReachedEnd) { + message += '. Possibly missing something'; + } + } + + error = new LessError({ + type: 'Parse', + message, + index: endInfo.furthest, + filename: fileInfo.filename + }, imports); + } + + const finish = e => { + e = error || e || imports.error; + + if (e) { + if (!(e instanceof LessError)) { + e = new LessError(e, imports, fileInfo.filename); + } + + return callback(e); + } else { + return callback(null, root); + } + }; + + if (context.processImports !== false) { + new visitors.ImportVisitor(imports, finish).run(root); + } else { + return finish(); + } + }, + // + // Here in, the parsing rules/functions + // + // The basic structure of the syntax tree generated is as follows: + // + // Ruleset -> Declaration -> Value -> Expression -> Entity + // + // Here's some Less code: + // + // .class { + // color: #fff; + // border: 1px solid #000; + // width: @w + 4px; + // > .child {...} + // } + // + // And here's what the parse tree might look like: + // + // Ruleset (Selector '.class', [ + // Declaration ("color", Value ([Expression [Color #fff]])) + // Declaration ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) + // Declaration ("width", Value ([Expression [Operation " + " [Variable "@w"][Dimension 4px]]])) + // Ruleset (Selector [Element '>', '.child'], [...]) + // ]) + // + // In general, most rules will try to parse a token with the `$re()` function, and if the return + // value is truly, will return a new node, of the relevant type. Sometimes, we need to check + // first, before parsing, that's when we use `peek()`. + // + parsers: parsers = { + // + // The `primary` rule is the *entry* and *exit* point of the parser. + // The rules here can appear at any level of the parse tree. + // + // The recursive nature of the grammar is an interplay between the `block` + // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, + // as represented by this simplified grammar: + // + // primary → (ruleset | declaration)+ + // ruleset → selector+ block + // block → '{' primary '}' + // + // Only at one point is the primary rule not called from the + // block rule: at the root level. + // + primary: function primary() { + const mixin = this.mixin; + let root = []; + let node; + + while (true) { + while (true) { + node = this.comment(); + + if (!node) { + break; + } + + root.push(node); + } // always process comments before deciding if finished + + + if (parserInput.finished) { + break; + } + + if (parserInput.peek('}')) { + break; + } + + node = this.extendRule(); + + if (node) { + root = root.concat(node); + continue; + } + + node = mixin.definition() || this.declaration() || this.ruleset() || mixin.call(false, false) || this.variableCall() || this.entities.call() || this.atrule(); + + if (node) { + root.push(node); + } else { + let foundSemiColon = false; + + while (parserInput.$char(';')) { + foundSemiColon = true; + } + + if (!foundSemiColon) { + break; + } + } + } + + return root; + }, + // comments are collected by the main parsing mechanism and then assigned to nodes + // where the current structure allows it + comment: function comment() { + if (parserInput.commentStore.length) { + const comment = parserInput.commentStore.shift(); + return new tree.Comment(comment.text, comment.isLineComment, comment.index, fileInfo); + } + }, + // + // Entities are tokens which can be found inside an Expression + // + entities: { + mixinLookup: function mixinLookup() { + return parsers.mixin.call(true, true); + }, + // + // A string, which supports escaping " and ' + // + // "milky way" 'he\'s the one!' + // + quoted: function quoted(forceEscaped) { + let str; + const index = parserInput.i; + let isEscaped = false; + parserInput.save(); + + if (parserInput.$char('~')) { + isEscaped = true; + } else if (forceEscaped) { + parserInput.restore(); + return; + } + + str = parserInput.$quoted(); + + if (!str) { + parserInput.restore(); + return; + } + + parserInput.forget(); + return new tree.Quoted(str.charAt(0), str.substr(1, str.length - 2), isEscaped, index, fileInfo); + }, + // + // A catch-all word, such as: + // + // black border-collapse + // + keyword: function keyword() { + const k = parserInput.$char('%') || parserInput.$re(/^\[?(?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+\]?/); + + if (k) { + return tree.Color.fromKeyword(k) || new tree.Keyword(k); + } + }, + // + // A function call + // + // rgb(255, 0, 255) + // + // The arguments are parsed with the `entities.arguments` parser. + // + call: function call() { + let name; + let args; + let func; + const index = parserInput.i; // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 + + if (parserInput.peek(/^url\(/i)) { + return; + } + + parserInput.save(); + name = parserInput.$re(/^([\w-]+|%|progid:[\w\.]+)\(/); + + if (!name) { + parserInput.forget(); + return; + } + + name = name[1]; + func = this.customFuncCall(name); + + if (func) { + args = func.parse(); + + if (args && func.stop) { + parserInput.forget(); + return args; + } + } + + args = this.arguments(args); + + if (!parserInput.$char(')')) { + parserInput.restore('Could not parse call arguments or missing \')\''); + return; + } + + parserInput.forget(); + return new tree.Call(name, args, index, fileInfo); + }, + // + // Parsing rules for functions with non-standard args, e.g.: + // + // boolean(not(2 > 1)) + // + // This is a quick prototype, to be modified/improved when + // more custom-parsed funcs come (e.g. `selector(...)`) + // + customFuncCall: function customFuncCall(name) { + /* Ideally the table is to be moved out of here for faster perf., + but it's quite tricky since it relies on all these `parsers` + and `expect` available only here */ + return { + alpha: f(parsers.ieAlpha, true), + boolean: f(condition), + 'if': f(condition) + }[name.toLowerCase()]; + + function f(parse, stop) { + return { + parse, + // parsing function + stop // when true - stop after parse() and return its result, + // otherwise continue for plain args + + }; + } + + function condition() { + return [expect(parsers.condition, 'expected condition')]; + } + }, + arguments: function _arguments(prevArgs) { + let argsComma = prevArgs || []; + const argsSemiColon = []; + let isSemiColonSeparated; + let value; + parserInput.save(); + + while (true) { + if (prevArgs) { + prevArgs = false; + } else { + value = parsers.detachedRuleset() || this.assignment() || parsers.expression(); + + if (!value) { + break; + } + + if (value.value && value.value.length == 1) { + value = value.value[0]; + } + + argsComma.push(value); + } + + if (parserInput.$char(',')) { + continue; + } + + if (parserInput.$char(';') || isSemiColonSeparated) { + isSemiColonSeparated = true; + value = argsComma.length < 1 ? argsComma[0] : new tree.Value(argsComma); + argsSemiColon.push(value); + argsComma = []; + } + } + + parserInput.forget(); + return isSemiColonSeparated ? argsSemiColon : argsComma; + }, + literal: function literal() { + return this.dimension() || this.color() || this.quoted() || this.unicodeDescriptor(); + }, + // Assignments are argument entities for calls. + // They are present in ie filter properties as shown below. + // + // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) + // + assignment: function assignment() { + let key; + let value; + parserInput.save(); + key = parserInput.$re(/^\w+(?=\s?=)/i); + + if (!key) { + parserInput.restore(); + return; + } + + if (!parserInput.$char('=')) { + parserInput.restore(); + return; + } + + value = parsers.entity(); + + if (value) { + parserInput.forget(); + return new tree.Assignment(key, value); + } else { + parserInput.restore(); + } + }, + // + // Parse url() tokens + // + // We use a specific rule for urls, because they don't really behave like + // standard function calls. The difference is that the argument doesn't have + // to be enclosed within a string, so it can't be parsed as an Expression. + // + url: function url() { + let value; + const index = parserInput.i; + parserInput.autoCommentAbsorb = false; + + if (!parserInput.$str('url(')) { + parserInput.autoCommentAbsorb = true; + return; + } + + value = this.quoted() || this.variable() || this.property() || parserInput.$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ''; + parserInput.autoCommentAbsorb = true; + expectChar(')'); + return new tree.URL(value.value != null || value instanceof tree.Variable || value instanceof tree.Property ? value : new tree.Anonymous(value, index), index, fileInfo); + }, + // + // A Variable entity, such as `@fink`, in + // + // width: @fink + 2px + // + // We use a different parser for variable definitions, + // see `parsers.variable`. + // + variable: function variable() { + let ch; + let name; + const index = parserInput.i; + parserInput.save(); + + if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^@@?[\w-]+/))) { + ch = parserInput.currentChar(); + + if (ch === '(' || ch === '[' && !parserInput.prevChar().match(/^\s/)) { + // this may be a VariableCall lookup + const result = parsers.variableCall(name); + + if (result) { + parserInput.forget(); + return result; + } + } + + parserInput.forget(); + return new tree.Variable(name, index, fileInfo); + } + + parserInput.restore(); + }, + // A variable entity using the protective {} e.g. @{var} + variableCurly: function variableCurly() { + let curly; + const index = parserInput.i; + + if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\{([\w-]+)\}/))) { + return new tree.Variable(`@${curly[1]}`, index, fileInfo); + } + }, + // + // A Property accessor, such as `$color`, in + // + // background-color: $color + // + property: function property() { + let name; + const index = parserInput.i; + + if (parserInput.currentChar() === '$' && (name = parserInput.$re(/^\$[\w-]+/))) { + return new tree.Property(name, index, fileInfo); + } + }, + // A property entity useing the protective {} e.g. ${prop} + propertyCurly: function propertyCurly() { + let curly; + const index = parserInput.i; + + if (parserInput.currentChar() === '$' && (curly = parserInput.$re(/^\$\{([\w-]+)\}/))) { + return new tree.Property(`$${curly[1]}`, index, fileInfo); + } + }, + // + // A Hexadecimal color + // + // #4F3C2F + // + // `rgb` and `hsl` colors are parsed through the `entities.call` parser. + // + color: function color() { + let rgb; + parserInput.save(); + + if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})([\w.#\[])?/))) { + if (!rgb[2]) { + parserInput.forget(); + return new tree.Color(rgb[1], undefined, rgb[0]); + } + } + + parserInput.restore(); + }, + colorKeyword: function colorKeyword() { + parserInput.save(); + const autoCommentAbsorb = parserInput.autoCommentAbsorb; + parserInput.autoCommentAbsorb = false; + const k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/); + parserInput.autoCommentAbsorb = autoCommentAbsorb; + + if (!k) { + parserInput.forget(); + return; + } + + parserInput.restore(); + const color = tree.Color.fromKeyword(k); + + if (color) { + parserInput.$str(k); + return color; + } + }, + // + // A Dimension, that is, a number and a unit + // + // 0.5em 95% + // + dimension: function dimension() { + if (parserInput.peekNotNumeric()) { + return; + } + + const value = parserInput.$re(/^([+-]?\d*\.?\d+)(%|[a-z_]+)?/i); + + if (value) { + return new tree.Dimension(value[1], value[2]); + } + }, + // + // A unicode descriptor, as is used in unicode-range + // + // U+0?? or U+00A1-00A9 + // + unicodeDescriptor: function unicodeDescriptor() { + let ud; + ud = parserInput.$re(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/); + + if (ud) { + return new tree.UnicodeDescriptor(ud[0]); + } + }, + // + // JavaScript code to be evaluated + // + // `window.location.href` + // + javascript: function javascript() { + let js; + const index = parserInput.i; + parserInput.save(); + const escape = parserInput.$char('~'); + const jsQuote = parserInput.$char('`'); + + if (!jsQuote) { + parserInput.restore(); + return; + } + + js = parserInput.$re(/^[^`]*`/); + + if (js) { + parserInput.forget(); + return new tree.JavaScript(js.substr(0, js.length - 1), Boolean(escape), index, fileInfo); + } + + parserInput.restore('invalid javascript definition'); + } + }, + // + // The variable part of a variable definition. Used in the `rule` parser + // + // @fink: + // + variable: function variable() { + let name; + + if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) { + return name[1]; + } + }, + // + // Call a variable value to retrieve a detached ruleset + // or a value from a detached ruleset's rules. + // + // @fink(); + // @fink; + // color: @fink[@color]; + // + variableCall: function variableCall(parsedName) { + let lookups; + let important; + const i = parserInput.i; + const inValue = !!parsedName; + let name = parsedName; + parserInput.save(); + + if (name || parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)(\(\s*\))?/))) { + lookups = this.mixin.ruleLookups(); + + if (!lookups && (inValue && parserInput.$str('()') !== '()' || name[2] !== '()')) { + parserInput.restore('Missing \'[...]\' lookup in variable call'); + return; + } + + if (!inValue) { + name = name[1]; + } + + if (lookups && parsers.important()) { + important = true; + } + + const call = new tree.VariableCall(name, i, fileInfo); + + if (!inValue && parsers.end()) { + parserInput.forget(); + return call; + } else { + parserInput.forget(); + return new tree.NamespaceValue(call, lookups, important, i, fileInfo); + } + } + + parserInput.restore(); + }, + // + // extend syntax - used to extend selectors + // + extend: function extend(isRule) { + let elements; + let e; + const index = parserInput.i; + let option; + let extendList; + let extend; + + if (!parserInput.$str(isRule ? '&:extend(' : ':extend(')) { + return; + } + + do { + option = null; + elements = null; + + while (!(option = parserInput.$re(/^(all)(?=\s*(\)|,))/))) { + e = this.element(); + + if (!e) { + break; + } + + if (elements) { + elements.push(e); + } else { + elements = [e]; + } + } + + option = option && option[1]; + + if (!elements) { + error('Missing target selector for :extend().'); + } + + extend = new tree.Extend(new tree.Selector(elements), option, index, fileInfo); + + if (extendList) { + extendList.push(extend); + } else { + extendList = [extend]; + } + } while (parserInput.$char(',')); + + expect(/^\)/); + + if (isRule) { + expect(/^;/); + } + + return extendList; + }, + // + // extendRule - used in a rule to extend all the parent selectors + // + extendRule: function extendRule() { + return this.extend(true); + }, + // + // Mixins + // + mixin: { + // + // A Mixin call, with an optional argument list + // + // #mixins > .square(#fff); + // #mixins.square(#fff); + // .rounded(4px, black); + // .button; + // + // We can lookup / return a value using the lookup syntax: + // + // color: #mixin.square(#fff)[@color]; + // + // The `while` loop is there because mixins can be + // namespaced, but we only support the child and descendant + // selector for now. + // + call: function call(inValue, getLookup) { + const s = parserInput.currentChar(); + let important = false; + let lookups; + const index = parserInput.i; + let elements; + let args; + let hasParens; + + if (s !== '.' && s !== '#') { + return; + } + + parserInput.save(); // stop us absorbing part of an invalid selector + + elements = this.elements(); + + if (elements) { + if (parserInput.$char('(')) { + args = this.args(true).args; + expectChar(')'); + hasParens = true; + } + + if (getLookup !== false) { + lookups = this.ruleLookups(); + } + + if (getLookup === true && !lookups) { + parserInput.restore(); + return; + } + + if (inValue && !lookups && !hasParens) { + // This isn't a valid in-value mixin call + parserInput.restore(); + return; + } + + if (!inValue && parsers.important()) { + important = true; + } + + if (inValue || parsers.end()) { + parserInput.forget(); + const mixin = new tree.mixin.Call(elements, args, index, fileInfo, !lookups && important); + + if (lookups) { + return new tree.NamespaceValue(mixin, lookups, important); + } else { + return mixin; + } + } + } + + parserInput.restore(); + }, + + /** + * Matching elements for mixins + * (Start with . or # and can have > ) + */ + elements: function elements() { + let elements; + let e; + let c; + let elem; + let elemIndex; + const re = /^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/; + + while (true) { + elemIndex = parserInput.i; + e = parserInput.$re(re); + + if (!e) { + break; + } + + elem = new tree.Element(c, e, false, elemIndex, fileInfo); + + if (elements) { + elements.push(elem); + } else { + elements = [elem]; + } + + c = parserInput.$char('>'); + } + + return elements; + }, + args: function args(isCall) { + const entities = parsers.entities; + const returner = { + args: null, + variadic: false + }; + let expressions = []; + const argsSemiColon = []; + const argsComma = []; + let isSemiColonSeparated; + let expressionContainsNamed; + let name; + let nameLoop; + let value; + let arg; + let expand; + let hasSep = true; + parserInput.save(); + + while (true) { + if (isCall) { + arg = parsers.detachedRuleset() || parsers.expression(); + } else { + parserInput.commentStore.length = 0; + + if (parserInput.$str('...')) { + returner.variadic = true; + + if (parserInput.$char(';') && !isSemiColonSeparated) { + isSemiColonSeparated = true; + } + + (isSemiColonSeparated ? argsSemiColon : argsComma).push({ + variadic: true + }); + break; + } + + arg = entities.variable() || entities.property() || entities.literal() || entities.keyword() || this.call(true); + } + + if (!arg || !hasSep) { + break; + } + + nameLoop = null; + + if (arg.throwAwayComments) { + arg.throwAwayComments(); + } + + value = arg; + let val = null; + + if (isCall) { + // Variable + if (arg.value && arg.value.length == 1) { + val = arg.value[0]; + } + } else { + val = arg; + } + + if (val && (val instanceof tree.Variable || val instanceof tree.Property)) { + if (parserInput.$char(':')) { + if (expressions.length > 0) { + if (isSemiColonSeparated) { + error('Cannot mix ; and , as delimiter types'); + } + + expressionContainsNamed = true; + } + + value = parsers.detachedRuleset() || parsers.expression(); + + if (!value) { + if (isCall) { + error('could not understand value for named argument'); + } else { + parserInput.restore(); + returner.args = []; + return returner; + } + } + + nameLoop = name = val.name; + } else if (parserInput.$str('...')) { + if (!isCall) { + returner.variadic = true; + + if (parserInput.$char(';') && !isSemiColonSeparated) { + isSemiColonSeparated = true; + } + + (isSemiColonSeparated ? argsSemiColon : argsComma).push({ + name: arg.name, + variadic: true + }); + break; + } else { + expand = true; + } + } else if (!isCall) { + name = nameLoop = val.name; + value = null; + } + } + + if (value) { + expressions.push(value); + } + + argsComma.push({ + name: nameLoop, + value, + expand + }); + + if (parserInput.$char(',')) { + hasSep = true; + continue; + } + + hasSep = parserInput.$char(';') === ';'; + + if (hasSep || isSemiColonSeparated) { + if (expressionContainsNamed) { + error('Cannot mix ; and , as delimiter types'); + } + + isSemiColonSeparated = true; + + if (expressions.length > 1) { + value = new tree.Value(expressions); + } + + argsSemiColon.push({ + name, + value, + expand + }); + name = null; + expressions = []; + expressionContainsNamed = false; + } + } + + parserInput.forget(); + returner.args = isSemiColonSeparated ? argsSemiColon : argsComma; + return returner; + }, + // + // A Mixin definition, with a list of parameters + // + // .rounded (@radius: 2px, @color) { + // ... + // } + // + // Until we have a finer grained state-machine, we have to + // do a look-ahead, to make sure we don't have a mixin call. + // See the `rule` function for more information. + // + // We start by matching `.rounded (`, and then proceed on to + // the argument list, which has optional default values. + // We store the parameters in `params`, with a `value` key, + // if there is a value, such as in the case of `@radius`. + // + // Once we've got our params list, and a closing `)`, we parse + // the `{...}` block. + // + definition: function definition() { + let name; + let params = []; + let match; + let ruleset; + let cond; + let variadic = false; + + if (parserInput.currentChar() !== '.' && parserInput.currentChar() !== '#' || parserInput.peek(/^[^{]*\}/)) { + return; + } + + parserInput.save(); + match = parserInput.$re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/); + + if (match) { + name = match[1]; + const argInfo = this.args(false); + params = argInfo.args; + variadic = argInfo.variadic; // .mixincall("@{a}"); + // looks a bit like a mixin definition.. + // also + // .mixincall(@a: {rule: set;}); + // so we have to be nice and restore + + if (!parserInput.$char(')')) { + parserInput.restore('Missing closing \')\''); + return; + } + + parserInput.commentStore.length = 0; + + if (parserInput.$str('when')) { + // Guard + cond = expect(parsers.conditions, 'expected condition'); + } + + ruleset = parsers.block(); + + if (ruleset) { + parserInput.forget(); + return new tree.mixin.Definition(name, params, ruleset, cond, variadic); + } else { + parserInput.restore(); + } + } else { + parserInput.forget(); + } + }, + ruleLookups: function ruleLookups() { + let rule; + const lookups = []; + + if (parserInput.currentChar() !== '[') { + return; + } + + while (true) { + parserInput.save(); + rule = this.lookupValue(); + + if (!rule && rule !== '') { + parserInput.restore(); + break; + } + + lookups.push(rule); + parserInput.forget(); + } + + if (lookups.length > 0) { + return lookups; + } + }, + lookupValue: function lookupValue() { + parserInput.save(); + + if (!parserInput.$char('[')) { + parserInput.restore(); + return; + } + + const name = parserInput.$re(/^(?:[@$]{0,2})[_a-zA-Z0-9-]*/); + + if (!parserInput.$char(']')) { + parserInput.restore(); + return; + } + + if (name || name === '') { + parserInput.forget(); + return name; + } + + parserInput.restore(); + } + }, + // + // Entities are the smallest recognized token, + // and can be found inside a rule's value. + // + entity: function entity() { + const entities = this.entities; + return this.comment() || entities.literal() || entities.variable() || entities.url() || entities.property() || entities.call() || entities.keyword() || this.mixin.call(true) || entities.javascript(); + }, + // + // A Declaration terminator. Note that we use `peek()` to check for '}', + // because the `block` rule will be expecting it, but we still need to make sure + // it's there, if ';' was omitted. + // + end: function end() { + return parserInput.$char(';') || parserInput.peek('}'); + }, + // + // IE's alpha function + // + // alpha(opacity=88) + // + ieAlpha: function ieAlpha() { + let value; // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 + + if (!parserInput.$re(/^opacity=/i)) { + return; + } + + value = parserInput.$re(/^\d+/); + + if (!value) { + value = expect(parsers.entities.variable, 'Could not parse alpha'); + value = `@{${value.name.slice(1)}}`; + } + + expectChar(')'); + return new tree.Quoted('', `alpha(opacity=${value})`); + }, + // + // A Selector Element + // + // div + // + h1 + // #socks + // input[type="text"] + // + // Elements are the building blocks for Selectors, + // they are made out of a `Combinator` (see combinator rule), + // and an element name, such as a tag a class, or `*`. + // + element: function element() { + let e; + let c; + let v; + const index = parserInput.i; + c = this.combinator(); + e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) || parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || parserInput.$char('*') || parserInput.$char('&') || this.attribute() || parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[\.#:](?=@)/) || this.entities.variableCurly(); + + if (!e) { + parserInput.save(); + + if (parserInput.$char('(')) { + if ((v = this.selector(false)) && parserInput.$char(')')) { + e = new tree.Paren(v); + parserInput.forget(); + } else { + parserInput.restore('Missing closing \')\''); + } + } else { + parserInput.forget(); + } + } + + if (e) { + return new tree.Element(c, e, e instanceof tree.Variable, index, fileInfo); + } + }, + // + // Combinators combine elements together, in a Selector. + // + // Because our parser isn't white-space sensitive, special care + // has to be taken, when parsing the descendant combinator, ` `, + // as it's an empty space. We have to check the previous character + // in the input, to see if it's a ` ` character. More info on how + // we deal with this in *combinator.js*. + // + combinator: function combinator() { + let c = parserInput.currentChar(); + + if (c === '/') { + parserInput.save(); + const slashedCombinator = parserInput.$re(/^\/[a-z]+\//i); + + if (slashedCombinator) { + parserInput.forget(); + return new tree.Combinator(slashedCombinator); + } + + parserInput.restore(); + } + + if (c === '>' || c === '+' || c === '~' || c === '|' || c === '^') { + parserInput.i++; + + if (c === '^' && parserInput.currentChar() === '^') { + c = '^^'; + parserInput.i++; + } + + while (parserInput.isWhitespace()) { + parserInput.i++; + } + + return new tree.Combinator(c); + } else if (parserInput.isWhitespace(-1)) { + return new tree.Combinator(' '); + } else { + return new tree.Combinator(null); + } + }, + // + // A CSS Selector + // with less extensions e.g. the ability to extend and guard + // + // .class > div + h1 + // li a:hover + // + // Selectors are made out of one or more Elements, see above. + // + selector: function selector(isLess) { + const index = parserInput.i; + let elements; + let extendList; + let c; + let e; + let allExtends; + let when; + let condition; + isLess = isLess !== false; + + while (isLess && (extendList = this.extend()) || isLess && (when = parserInput.$str('when')) || (e = this.element())) { + if (when) { + condition = expect(this.conditions, 'expected condition'); + } else if (condition) { + error('CSS guard can only be used at the end of selector'); + } else if (extendList) { + if (allExtends) { + allExtends = allExtends.concat(extendList); + } else { + allExtends = extendList; + } + } else { + if (allExtends) { + error('Extend can only be used at the end of selector'); + } + + c = parserInput.currentChar(); + + if (elements) { + elements.push(e); + } else { + elements = [e]; + } + + e = null; + } + + if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { + break; + } + } + + if (elements) { + return new tree.Selector(elements, allExtends, condition, index, fileInfo); + } + + if (allExtends) { + error('Extend must be used to extend a selector, it cannot be used on its own'); + } + }, + selectors: function selectors() { + let s; + let selectors; + + while (true) { + s = this.selector(); + + if (!s) { + break; + } + + if (selectors) { + selectors.push(s); + } else { + selectors = [s]; + } + + parserInput.commentStore.length = 0; + + if (s.condition && selectors.length > 1) { + error("Guards are only currently allowed on a single selector."); + } + + if (!parserInput.$char(',')) { + break; + } + + if (s.condition) { + error("Guards are only currently allowed on a single selector."); + } + + parserInput.commentStore.length = 0; + } + + return selectors; + }, + attribute: function attribute() { + if (!parserInput.$char('[')) { + return; + } + + const entities = this.entities; + let key; + let val; + let op; + + if (!(key = entities.variableCurly())) { + key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/); + } + + op = parserInput.$re(/^[|~*$^]?=/); + + if (op) { + val = entities.quoted() || parserInput.$re(/^[0-9]+%/) || parserInput.$re(/^[\w-]+/) || entities.variableCurly(); + } + + expectChar(']'); + return new tree.Attribute(key, op, val); + }, + // + // The `block` rule is used by `ruleset` and `mixin.definition`. + // It's a wrapper around the `primary` rule, with added `{}`. + // + block: function block() { + let content; + + if (parserInput.$char('{') && (content = this.primary()) && parserInput.$char('}')) { + return content; + } + }, + blockRuleset: function blockRuleset() { + let block = this.block(); + + if (block) { + block = new tree.Ruleset(null, block); + } + + return block; + }, + detachedRuleset: function detachedRuleset() { + let argInfo; + let params; + let variadic; + parserInput.save(); + + if (parserInput.$re(/^[.#]\(/)) { + /** + * DR args currently only implemented for each() function, and not + * yet settable as `@dr: #(@arg) {}` + * This should be done when DRs are merged with mixins. + * See: https://github.com/less/less-meta/issues/16 + */ + argInfo = this.mixin.args(false); + params = argInfo.args; + variadic = argInfo.variadic; + + if (!parserInput.$char(')')) { + parserInput.restore(); + return; + } + } + + const blockRuleset = this.blockRuleset(); + + if (blockRuleset) { + parserInput.forget(); + + if (params) { + return new tree.mixin.Definition(null, params, blockRuleset, null, variadic); + } + + return new tree.DetachedRuleset(blockRuleset); + } + + parserInput.restore(); + }, + // + // div, .class, body > p {...} + // + ruleset: function ruleset() { + let selectors; + let rules; + let debugInfo; + parserInput.save(); + + if (context.dumpLineNumbers) { + debugInfo = getDebugInfo(parserInput.i); + } + + selectors = this.selectors(); + + if (selectors && (rules = this.block())) { + parserInput.forget(); + const ruleset = new tree.Ruleset(selectors, rules, context.strictImports); + + if (context.dumpLineNumbers) { + ruleset.debugInfo = debugInfo; + } + + return ruleset; + } else { + parserInput.restore(); + } + }, + declaration: function declaration() { + let name; + let value; + const index = parserInput.i; + let hasDR; + const c = parserInput.currentChar(); + let important; + let merge; + let isVariable; + + if (c === '.' || c === '#' || c === '&' || c === ':') { + return; + } + + parserInput.save(); + name = this.variable() || this.ruleProperty(); + + if (name) { + isVariable = typeof name === 'string'; + + if (isVariable) { + value = this.detachedRuleset(); + + if (value) { + hasDR = true; + } + } + + parserInput.commentStore.length = 0; + + if (!value) { + // a name returned by this.ruleProperty() is always an array of the form: + // [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"] + // where each item is a tree.Keyword or tree.Variable + merge = !isVariable && name.length > 1 && name.pop().value; // Custom property values get permissive parsing + + if (name[0].value && name[0].value.slice(0, 2) === '--') { + value = this.permissiveValue(); + } // Try to store values as anonymous + // If we need the value later we'll re-parse it in ruleset.parseValue + else { + value = this.anonymousValue(); + } + + if (value) { + parserInput.forget(); // anonymous values absorb the end ';' which is required for them to work + + return new tree.Declaration(name, value, false, merge, index, fileInfo); + } + + if (!value) { + value = this.value(); + } + + if (value) { + important = this.important(); + } else if (isVariable) { + // As a last resort, try permissiveValue + value = this.permissiveValue(); + } + } + + if (value && (this.end() || hasDR)) { + parserInput.forget(); + return new tree.Declaration(name, value, important, merge, index, fileInfo); + } else { + parserInput.restore(); + } + } else { + parserInput.restore(); + } + }, + anonymousValue: function anonymousValue() { + const index = parserInput.i; + const match = parserInput.$re(/^([^.#@\$+\/'"*`(;{}-]*);/); + + if (match) { + return new tree.Anonymous(match[1], index); + } + }, + + /** + * Used for custom properties, at-rules, and variables (as fallback) + * Parses almost anything inside of {} [] () "" blocks + * until it reaches outer-most tokens. + * + * First, it will try to parse comments and entities to reach + * the end. This is mostly like the Expression parser except no + * math is allowed. + */ + permissiveValue: function permissiveValue(untilTokens) { + let i; + let e; + let done; + let value; + const tok = untilTokens || ';'; + const index = parserInput.i; + const result = []; + + function testCurrentChar() { + const char = parserInput.currentChar(); + + if (typeof tok === 'string') { + return char === tok; + } else { + return tok.test(char); + } + } + + if (testCurrentChar()) { + return; + } + + value = []; + + do { + e = this.comment(); + + if (e) { + value.push(e); + continue; + } + + e = this.entity(); + + if (e) { + value.push(e); + } + } while (e); + + done = testCurrentChar(); + + if (value.length > 0) { + value = new tree.Expression(value); + + if (done) { + return value; + } else { + result.push(value); + } // Preserve space before $parseUntil as it will not + + + if (parserInput.prevChar() === ' ') { + result.push(new tree.Anonymous(' ', index)); + } + } + + parserInput.save(); + value = parserInput.$parseUntil(tok); + + if (value) { + if (typeof value === 'string') { + error(`Expected '${value}'`, 'Parse'); + } + + if (value.length === 1 && value[0] === ' ') { + parserInput.forget(); + return new tree.Anonymous('', index); + } + + let item; + + for (i = 0; i < value.length; i++) { + item = value[i]; + + if (Array.isArray(item)) { + // Treat actual quotes as normal quoted values + result.push(new tree.Quoted(item[0], item[1], true, index, fileInfo)); + } else { + if (i === value.length - 1) { + item = item.trim(); + } // Treat like quoted values, but replace vars like unquoted expressions + + + const quote = new tree.Quoted('\'', item, true, index, fileInfo); + quote.variableRegex = /@([\w-]+)/g; + quote.propRegex = /\$([\w-]+)/g; + result.push(quote); + } + } + + parserInput.forget(); + return new tree.Expression(result, true); + } + + parserInput.restore(); + }, + // + // An @import atrule + // + // @import "lib"; + // + // Depending on our environment, importing is done differently: + // In the browser, it's an XHR request, in Node, it would be a + // file-system operation. The function used for importing is + // stored in `import`, which we pass to the Import constructor. + // + 'import': function _import() { + let path; + let features; + const index = parserInput.i; + const dir = parserInput.$re(/^@import?\s+/); + + if (dir) { + const options = (dir ? this.importOptions() : null) || {}; + + if (path = this.entities.quoted() || this.entities.url()) { + features = this.mediaFeatures(); + + if (!parserInput.$char(';')) { + parserInput.i = index; + error('missing semi-colon or unrecognised media features on import'); + } + + features = features && new tree.Value(features); + return new tree.Import(path, features, options, index, fileInfo); + } else { + parserInput.i = index; + error('malformed import statement'); + } + } + }, + importOptions: function importOptions() { + let o; + const options = {}; + let optionName; + let value; // list of options, surrounded by parens + + if (!parserInput.$char('(')) { + return null; + } + + do { + o = this.importOption(); + + if (o) { + optionName = o; + value = true; + + switch (optionName) { + case 'css': + optionName = 'less'; + value = false; + break; + + case 'once': + optionName = 'multiple'; + value = false; + break; + } + + options[optionName] = value; + + if (!parserInput.$char(',')) { + break; + } + } + } while (o); + + expectChar(')'); + return options; + }, + importOption: function importOption() { + const opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/); + + if (opt) { + return opt[1]; + } + }, + mediaFeature: function mediaFeature() { + const entities = this.entities; + const nodes = []; + let e; + let p; + parserInput.save(); + + do { + e = entities.keyword() || entities.variable() || entities.mixinLookup(); + + if (e) { + nodes.push(e); + } else if (parserInput.$char('(')) { + p = this.property(); + e = this.value(); + + if (parserInput.$char(')')) { + if (p && e) { + nodes.push(new tree.Paren(new tree.Declaration(p, e, null, null, parserInput.i, fileInfo, true))); + } else if (e) { + nodes.push(new tree.Paren(e)); + } else { + error('badly formed media feature definition'); + } + } else { + error('Missing closing \')\'', 'Parse'); + } + } + } while (e); + + parserInput.forget(); + + if (nodes.length > 0) { + return new tree.Expression(nodes); + } + }, + mediaFeatures: function mediaFeatures() { + const entities = this.entities; + const features = []; + let e; + + do { + e = this.mediaFeature(); + + if (e) { + features.push(e); + + if (!parserInput.$char(',')) { + break; + } + } else { + e = entities.variable() || entities.mixinLookup(); + + if (e) { + features.push(e); + + if (!parserInput.$char(',')) { + break; + } + } + } + } while (e); + + return features.length > 0 ? features : null; + }, + media: function media() { + let features; + let rules; + let media; + let debugInfo; + const index = parserInput.i; + + if (context.dumpLineNumbers) { + debugInfo = getDebugInfo(index); + } + + parserInput.save(); + + if (parserInput.$str('@media')) { + features = this.mediaFeatures(); + rules = this.block(); + + if (!rules) { + error('media definitions require block statements after any features'); + } + + parserInput.forget(); + media = new tree.Media(rules, features, index, fileInfo); + + if (context.dumpLineNumbers) { + media.debugInfo = debugInfo; + } + + return media; + } + + parserInput.restore(); + }, + // + // A @plugin directive, used to import plugins dynamically. + // + // @plugin (args) "lib"; + // + plugin: function plugin() { + let path; + let args; + let options; + const index = parserInput.i; + const dir = parserInput.$re(/^@plugin?\s+/); + + if (dir) { + args = this.pluginArgs(); + + if (args) { + options = { + pluginArgs: args, + isPlugin: true + }; + } else { + options = { + isPlugin: true + }; + } + + if (path = this.entities.quoted() || this.entities.url()) { + if (!parserInput.$char(';')) { + parserInput.i = index; + error('missing semi-colon on @plugin'); + } + + return new tree.Import(path, null, options, index, fileInfo); + } else { + parserInput.i = index; + error('malformed @plugin statement'); + } + } + }, + pluginArgs: function pluginArgs() { + // list of options, surrounded by parens + parserInput.save(); + + if (!parserInput.$char('(')) { + parserInput.restore(); + return null; + } + + const args = parserInput.$re(/^\s*([^\);]+)\)\s*/); + + if (args[1]) { + parserInput.forget(); + return args[1].trim(); + } else { + parserInput.restore(); + return null; + } + }, + // + // A CSS AtRule + // + // @charset "utf-8"; + // + atrule: function atrule() { + const index = parserInput.i; + let name; + let value; + let rules; + let nonVendorSpecificName; + let hasIdentifier; + let hasExpression; + let hasUnknown; + let hasBlock = true; + let isRooted = true; + + if (parserInput.currentChar() !== '@') { + return; + } + + value = this['import']() || this.plugin() || this.media(); + + if (value) { + return value; + } + + parserInput.save(); + name = parserInput.$re(/^@[a-z-]+/); + + if (!name) { + return; + } + + nonVendorSpecificName = name; + + if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { + nonVendorSpecificName = `@${name.slice(name.indexOf('-', 2) + 1)}`; + } + + switch (nonVendorSpecificName) { + case '@charset': + hasIdentifier = true; + hasBlock = false; + break; + + case '@namespace': + hasExpression = true; + hasBlock = false; + break; + + case '@keyframes': + case '@counter-style': + hasIdentifier = true; + break; + + case '@document': + case '@supports': + hasUnknown = true; + isRooted = false; + break; + + default: + hasUnknown = true; + break; + } + + parserInput.commentStore.length = 0; + + if (hasIdentifier) { + value = this.entity(); + + if (!value) { + error(`expected ${name} identifier`); + } + } else if (hasExpression) { + value = this.expression(); + + if (!value) { + error(`expected ${name} expression`); + } + } else if (hasUnknown) { + value = this.permissiveValue(/^[{;]/); + hasBlock = parserInput.currentChar() === '{'; + + if (!value) { + if (!hasBlock && parserInput.currentChar() !== ';') { + error(`${name} rule is missing block or ending semi-colon`); + } + } else if (!value.value) { + value = null; + } + } + + if (hasBlock) { + rules = this.blockRuleset(); + } + + if (rules || !hasBlock && value && parserInput.$char(';')) { + parserInput.forget(); + return new tree.AtRule(name, value, rules, index, fileInfo, context.dumpLineNumbers ? getDebugInfo(index) : null, isRooted); + } + + parserInput.restore('at-rule options not recognised'); + }, + // + // A Value is a comma-delimited list of Expressions + // + // font-family: Baskerville, Georgia, serif; + // + // In a Rule, a Value represents everything after the `:`, + // and before the `;`. + // + value: function value() { + let e; + const expressions = []; + const index = parserInput.i; + + do { + e = this.expression(); + + if (e) { + expressions.push(e); + + if (!parserInput.$char(',')) { + break; + } + } + } while (e); + + if (expressions.length > 0) { + return new tree.Value(expressions, index); + } + }, + important: function important() { + if (parserInput.currentChar() === '!') { + return parserInput.$re(/^! *important/); + } + }, + sub: function sub() { + let a; + let e; + parserInput.save(); + + if (parserInput.$char('(')) { + a = this.addition(); + + if (a && parserInput.$char(')')) { + parserInput.forget(); + e = new tree.Expression([a]); + e.parens = true; + return e; + } + + parserInput.restore('Expected \')\''); + return; + } + + parserInput.restore(); + }, + multiplication: function multiplication() { + let m; + let a; + let op; + let operation; + let isSpaced; + m = this.operand(); + + if (m) { + isSpaced = parserInput.isWhitespace(-1); + + while (true) { + if (parserInput.peek(/^\/[*\/]/)) { + break; + } + + parserInput.save(); + op = parserInput.$char('/') || parserInput.$char('*') || parserInput.$str('./'); + + if (!op) { + parserInput.forget(); + break; + } + + a = this.operand(); + + if (!a) { + parserInput.restore(); + break; + } + + parserInput.forget(); + m.parensInOp = true; + a.parensInOp = true; + operation = new tree.Operation(op, [operation || m, a], isSpaced); + isSpaced = parserInput.isWhitespace(-1); + } + + return operation || m; + } + }, + addition: function addition() { + let m; + let a; + let op; + let operation; + let isSpaced; + m = this.multiplication(); + + if (m) { + isSpaced = parserInput.isWhitespace(-1); + + while (true) { + op = parserInput.$re(/^[-+]\s+/) || !isSpaced && (parserInput.$char('+') || parserInput.$char('-')); + + if (!op) { + break; + } + + a = this.multiplication(); + + if (!a) { + break; + } + + m.parensInOp = true; + a.parensInOp = true; + operation = new tree.Operation(op, [operation || m, a], isSpaced); + isSpaced = parserInput.isWhitespace(-1); + } + + return operation || m; + } + }, + conditions: function conditions() { + let a; + let b; + const index = parserInput.i; + let condition; + a = this.condition(true); + + if (a) { + while (true) { + if (!parserInput.peek(/^,\s*(not\s*)?\(/) || !parserInput.$char(',')) { + break; + } + + b = this.condition(true); + + if (!b) { + break; + } + + condition = new tree.Condition('or', condition || a, b, index); + } + + return condition || a; + } + }, + condition: function condition(needsParens) { + let result; + let logical; + let next; + + function or() { + return parserInput.$str('or'); + } + + result = this.conditionAnd(needsParens); + + if (!result) { + return; + } + + logical = or(); + + if (logical) { + next = this.condition(needsParens); + + if (next) { + result = new tree.Condition(logical, result, next); + } else { + return; + } + } + + return result; + }, + conditionAnd: function conditionAnd(needsParens) { + let result; + let logical; + let next; + const self = this; + + function insideCondition() { + const cond = self.negatedCondition(needsParens) || self.parenthesisCondition(needsParens); + + if (!cond && !needsParens) { + return self.atomicCondition(needsParens); + } + + return cond; + } + + function and() { + return parserInput.$str('and'); + } + + result = insideCondition(); + + if (!result) { + return; + } + + logical = and(); + + if (logical) { + next = this.conditionAnd(needsParens); + + if (next) { + result = new tree.Condition(logical, result, next); + } else { + return; + } + } + + return result; + }, + negatedCondition: function negatedCondition(needsParens) { + if (parserInput.$str('not')) { + const result = this.parenthesisCondition(needsParens); + + if (result) { + result.negate = !result.negate; + } + + return result; + } + }, + parenthesisCondition: function parenthesisCondition(needsParens) { + function tryConditionFollowedByParenthesis(me) { + let body; + parserInput.save(); + body = me.condition(needsParens); + + if (!body) { + parserInput.restore(); + return; + } + + if (!parserInput.$char(')')) { + parserInput.restore(); + return; + } + + parserInput.forget(); + return body; + } + + let body; + parserInput.save(); + + if (!parserInput.$str('(')) { + parserInput.restore(); + return; + } + + body = tryConditionFollowedByParenthesis(this); + + if (body) { + parserInput.forget(); + return body; + } + + body = this.atomicCondition(needsParens); + + if (!body) { + parserInput.restore(); + return; + } + + if (!parserInput.$char(')')) { + parserInput.restore(`expected ')' got '${parserInput.currentChar()}'`); + return; + } + + parserInput.forget(); + return body; + }, + atomicCondition: function atomicCondition(needsParens) { + const entities = this.entities; + const index = parserInput.i; + let a; + let b; + let c; + let op; + + function cond() { + return this.addition() || entities.keyword() || entities.quoted() || entities.mixinLookup(); + } + + cond = cond.bind(this); + a = cond(); + + if (a) { + if (parserInput.$char('>')) { + if (parserInput.$char('=')) { + op = '>='; + } else { + op = '>'; + } + } else if (parserInput.$char('<')) { + if (parserInput.$char('=')) { + op = '<='; + } else { + op = '<'; + } + } else if (parserInput.$char('=')) { + if (parserInput.$char('>')) { + op = '=>'; + } else if (parserInput.$char('<')) { + op = '=<'; + } else { + op = '='; + } + } + + if (op) { + b = cond(); + + if (b) { + c = new tree.Condition(op, a, b, index, false); + } else { + error('expected expression'); + } + } else { + c = new tree.Condition('=', a, new tree.Keyword('true'), index, false); + } + + return c; + } + }, + // + // An operand is anything that can be part of an operation, + // such as a Color, or a Variable + // + operand: function operand() { + const entities = this.entities; + let negate; + + if (parserInput.peek(/^-[@\$\(]/)) { + negate = parserInput.$char('-'); + } + + let o = this.sub() || entities.dimension() || entities.color() || entities.variable() || entities.property() || entities.call() || entities.quoted(true) || entities.colorKeyword() || entities.mixinLookup(); + + if (negate) { + o.parensInOp = true; + o = new tree.Negative(o); + } + + return o; + }, + // + // Expressions either represent mathematical operations, + // or white-space delimited Entities. + // + // 1px solid black + // @var * 2 + // + expression: function expression() { + const entities = []; + let e; + let delim; + const index = parserInput.i; + + do { + e = this.comment(); + + if (e) { + entities.push(e); + continue; + } + + e = this.addition() || this.entity(); + + if (e) { + entities.push(e); // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here + + if (!parserInput.peek(/^\/[\/*]/)) { + delim = parserInput.$char('/'); + + if (delim) { + entities.push(new tree.Anonymous(delim, index)); + } + } + } + } while (e); + + if (entities.length > 0) { + return new tree.Expression(entities); + } + }, + property: function property() { + const name = parserInput.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/); + + if (name) { + return name[1]; + } + }, + ruleProperty: function ruleProperty() { + let name = []; + const index = []; + let s; + let k; + parserInput.save(); + const simpleProperty = parserInput.$re(/^([_a-zA-Z0-9-]+)\s*:/); + + if (simpleProperty) { + name = [new tree.Keyword(simpleProperty[1])]; + parserInput.forget(); + return name; + } + + function match(re) { + const i = parserInput.i; + const chunk = parserInput.$re(re); + + if (chunk) { + index.push(i); + return name.push(chunk[1]); + } + } + + match(/^(\*?)/); + + while (true) { + if (!match(/^((?:[\w-]+)|(?:[@\$]\{[\w-]+\}))/)) { + break; + } + } + + if (name.length > 1 && match(/^((?:\+_|\+)?)\s*:/)) { + parserInput.forget(); // at last, we have the complete match now. move forward, + // convert name particles to tree objects and return: + + if (name[0] === '') { + name.shift(); + index.shift(); + } + + for (k = 0; k < name.length; k++) { + s = name[k]; + name[k] = s.charAt(0) !== '@' && s.charAt(0) !== '$' ? new tree.Keyword(s) : s.charAt(0) === '@' ? new tree.Variable(`@${s.slice(2, -1)}`, index[k], fileInfo) : new tree.Property(`$${s.slice(2, -1)}`, index[k], fileInfo); + } + + return name; + } + + parserInput.restore(); + } + } + }; +}; + +Parser.serializeVars = vars => { + let s = ''; + + for (const name in vars) { + if (Object.hasOwnProperty.call(vars, name)) { + const value = vars[name]; + s += `${(name[0] === '@' ? '' : '@') + name}: ${value}${String(value).slice(-1) === ';' ? '' : ';'}`; + } + } + + return s; +}; + +function boolean(condition) { + return condition ? Keyword.True : Keyword.False; +} + +function If(condition, trueValue, falseValue) { + return condition ? trueValue : falseValue || new Anonymous(); +} + +var boolean$1 = { + boolean, + 'if': If +}; + +let colorFunctions; + +function clamp$1(val) { + return Math.min(1, Math.max(0, val)); +} + +function hsla(origColor, hsl) { + const color = colorFunctions.hsla(hsl.h, hsl.s, hsl.l, hsl.a); + + if (color) { + if (origColor.value && /^(rgb|hsl)/.test(origColor.value)) { + color.value = origColor.value; + } else { + color.value = 'rgb'; + } + + return color; + } +} + +function toHSL(color) { + if (color.toHSL) { + return color.toHSL(); + } else { + throw new Error('Argument cannot be evaluated to a color'); + } +} + +function toHSV(color) { + if (color.toHSV) { + return color.toHSV(); + } else { + throw new Error('Argument cannot be evaluated to a color'); + } +} + +function number(n) { + if (n instanceof Dimension) { + return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); + } else if (typeof n === 'number') { + return n; + } else { + throw { + type: 'Argument', + message: 'color functions take numbers as parameters' + }; + } +} + +function scaled(n, size) { + if (n instanceof Dimension && n.unit.is('%')) { + return parseFloat(n.value * size / 100); + } else { + return number(n); + } +} + +colorFunctions = { + rgb: function rgb(r, g, b) { + const color = colorFunctions.rgba(r, g, b, 1.0); + + if (color) { + color.value = 'rgb'; + return color; + } + }, + rgba: function rgba(r, g, b, a) { + try { + if (r instanceof Color) { + if (g) { + a = number(g); + } else { + a = r.alpha; + } + + return new Color(r.rgb, a, 'rgba'); + } + + const rgb = [r, g, b].map(c => scaled(c, 255)); + a = number(a); + return new Color(rgb, a, 'rgba'); + } catch (e) {} + }, + hsl: function hsl(h, s, l) { + const color = colorFunctions.hsla(h, s, l, 1.0); + + if (color) { + color.value = 'hsl'; + return color; + } + }, + hsla: function hsla(h, s, l, a) { + try { + if (h instanceof Color) { + if (s) { + a = number(s); + } else { + a = h.alpha; + } + + return new Color(h.rgb, a, 'hsla'); + } + + let m1; + let m2; + + function hue(h) { + h = h < 0 ? h + 1 : h > 1 ? h - 1 : h; + + if (h * 6 < 1) { + return m1 + (m2 - m1) * h * 6; + } else if (h * 2 < 1) { + return m2; + } else if (h * 3 < 2) { + return m1 + (m2 - m1) * (2 / 3 - h) * 6; + } else { + return m1; + } + } + + h = number(h) % 360 / 360; + s = clamp$1(number(s)); + l = clamp$1(number(l)); + a = clamp$1(number(a)); + m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; + m1 = l * 2 - m2; + const rgb = [hue(h + 1 / 3) * 255, hue(h) * 255, hue(h - 1 / 3) * 255]; + a = number(a); + return new Color(rgb, a, 'hsla'); + } catch (e) {} + }, + hsv: function hsv(h, s, v) { + return colorFunctions.hsva(h, s, v, 1.0); + }, + hsva: function hsva(h, s, v, a) { + h = number(h) % 360 / 360 * 360; + s = number(s); + v = number(v); + a = number(a); + let i; + let f; + i = Math.floor(h / 60 % 6); + f = h / 60 - i; + const vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; + const perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; + return colorFunctions.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); + }, + hue: function hue(color) { + return new Dimension(toHSL(color).h); + }, + saturation: function saturation(color) { + return new Dimension(toHSL(color).s * 100, '%'); + }, + lightness: function lightness(color) { + return new Dimension(toHSL(color).l * 100, '%'); + }, + hsvhue: function hsvhue(color) { + return new Dimension(toHSV(color).h); + }, + hsvsaturation: function hsvsaturation(color) { + return new Dimension(toHSV(color).s * 100, '%'); + }, + hsvvalue: function hsvvalue(color) { + return new Dimension(toHSV(color).v * 100, '%'); + }, + red: function red(color) { + return new Dimension(color.rgb[0]); + }, + green: function green(color) { + return new Dimension(color.rgb[1]); + }, + blue: function blue(color) { + return new Dimension(color.rgb[2]); + }, + alpha: function alpha(color) { + return new Dimension(toHSL(color).a); + }, + luma: function luma(color) { + return new Dimension(color.luma() * color.alpha * 100, '%'); + }, + luminance: function luminance(color) { + const luminance = 0.2126 * color.rgb[0] / 255 + 0.7152 * color.rgb[1] / 255 + 0.0722 * color.rgb[2] / 255; + return new Dimension(luminance * color.alpha * 100, '%'); + }, + saturate: function saturate(color, amount, method) { + // filter: saturate(3.2); + // should be kept as is, so check for color + if (!color.rgb) { + return null; + } + + const hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.s += hsl.s * amount.value / 100; + } else { + hsl.s += amount.value / 100; + } + + hsl.s = clamp$1(hsl.s); + return hsla(color, hsl); + }, + desaturate: function desaturate(color, amount, method) { + const hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.s -= hsl.s * amount.value / 100; + } else { + hsl.s -= amount.value / 100; + } + + hsl.s = clamp$1(hsl.s); + return hsla(color, hsl); + }, + lighten: function lighten(color, amount, method) { + const hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.l += hsl.l * amount.value / 100; + } else { + hsl.l += amount.value / 100; + } + + hsl.l = clamp$1(hsl.l); + return hsla(color, hsl); + }, + darken: function darken(color, amount, method) { + const hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.l -= hsl.l * amount.value / 100; + } else { + hsl.l -= amount.value / 100; + } + + hsl.l = clamp$1(hsl.l); + return hsla(color, hsl); + }, + fadein: function fadein(color, amount, method) { + const hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.a += hsl.a * amount.value / 100; + } else { + hsl.a += amount.value / 100; + } + + hsl.a = clamp$1(hsl.a); + return hsla(color, hsl); + }, + fadeout: function fadeout(color, amount, method) { + const hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.a -= hsl.a * amount.value / 100; + } else { + hsl.a -= amount.value / 100; + } + + hsl.a = clamp$1(hsl.a); + return hsla(color, hsl); + }, + fade: function fade(color, amount) { + const hsl = toHSL(color); + hsl.a = amount.value / 100; + hsl.a = clamp$1(hsl.a); + return hsla(color, hsl); + }, + spin: function spin(color, amount) { + const hsl = toHSL(color); + const hue = (hsl.h + amount.value) % 360; + hsl.h = hue < 0 ? 360 + hue : hue; + return hsla(color, hsl); + }, + // + // Copyright (c) 2006-2009 Hampton Catlin, Natalie Weizenbaum, and Chris Eppstein + // http://sass-lang.com + // + mix: function mix(color1, color2, weight) { + if (!weight) { + weight = new Dimension(50); + } + + const p = weight.value / 100.0; + const w = p * 2 - 1; + const a = toHSL(color1).a - toHSL(color2).a; + const w1 = ((w * a == -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0; + const w2 = 1 - w1; + const rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; + const alpha = color1.alpha * p + color2.alpha * (1 - p); + return new Color(rgb, alpha); + }, + greyscale: function greyscale(color) { + return colorFunctions.desaturate(color, new Dimension(100)); + }, + contrast: function contrast(color, dark, light, threshold) { + // filter: contrast(3.2); + // should be kept as is, so check for color + if (!color.rgb) { + return null; + } + + if (typeof light === 'undefined') { + light = colorFunctions.rgba(255, 255, 255, 1.0); + } + + if (typeof dark === 'undefined') { + dark = colorFunctions.rgba(0, 0, 0, 1.0); + } // Figure out which is actually light and dark: + + + if (dark.luma() > light.luma()) { + const t = light; + light = dark; + dark = t; + } + + if (typeof threshold === 'undefined') { + threshold = 0.43; + } else { + threshold = number(threshold); + } + + if (color.luma() < threshold) { + return light; + } else { + return dark; + } + }, + // Changes made in 2.7.0 - Reverted in 3.0.0 + // contrast: function (color, color1, color2, threshold) { + // // Return which of `color1` and `color2` has the greatest contrast with `color` + // // according to the standard WCAG contrast ratio calculation. + // // http://www.w3.org/TR/WCAG20/#contrast-ratiodef + // // The threshold param is no longer used, in line with SASS. + // // filter: contrast(3.2); + // // should be kept as is, so check for color + // if (!color.rgb) { + // return null; + // } + // if (typeof color1 === 'undefined') { + // color1 = colorFunctions.rgba(0, 0, 0, 1.0); + // } + // if (typeof color2 === 'undefined') { + // color2 = colorFunctions.rgba(255, 255, 255, 1.0); + // } + // var contrast1, contrast2; + // var luma = color.luma(); + // var luma1 = color1.luma(); + // var luma2 = color2.luma(); + // // Calculate contrast ratios for each color + // if (luma > luma1) { + // contrast1 = (luma + 0.05) / (luma1 + 0.05); + // } else { + // contrast1 = (luma1 + 0.05) / (luma + 0.05); + // } + // if (luma > luma2) { + // contrast2 = (luma + 0.05) / (luma2 + 0.05); + // } else { + // contrast2 = (luma2 + 0.05) / (luma + 0.05); + // } + // if (contrast1 > contrast2) { + // return color1; + // } else { + // return color2; + // } + // }, + argb: function argb(color) { + return new Anonymous(color.toARGB()); + }, + color: function color(c) { + if (c instanceof Quoted && /^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})$/i.test(c.value)) { + const val = c.value.slice(1); + return new Color(val, undefined, `#${val}`); + } + + if (c instanceof Color || (c = Color.fromKeyword(c.value))) { + c.value = undefined; + return c; + } + + throw { + type: 'Argument', + message: 'argument must be a color keyword or 3|4|6|8 digit hex e.g. #FFF' + }; + }, + tint: function tint(color, amount) { + return colorFunctions.mix(colorFunctions.rgb(255, 255, 255), color, amount); + }, + shade: function shade(color, amount) { + return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount); + } +}; +var color = colorFunctions; + +// ref: http://www.w3.org/TR/compositing-1 + +function colorBlend(mode, color1, color2) { + const ab = color1.alpha; // result + + let // backdrop + cb; + const as = color2.alpha; + let // source + cs; + let ar; + let cr; + const r = []; + ar = as + ab * (1 - as); + + for (let i = 0; i < 3; i++) { + cb = color1.rgb[i] / 255; + cs = color2.rgb[i] / 255; + cr = mode(cb, cs); + + if (ar) { + cr = (as * cs + ab * (cb - as * (cb + cs - cr))) / ar; + } + + r[i] = cr * 255; + } + + return new Color(r, ar); +} + +const colorBlendModeFunctions = { + multiply: function multiply(cb, cs) { + return cb * cs; + }, + screen: function screen(cb, cs) { + return cb + cs - cb * cs; + }, + overlay: function overlay(cb, cs) { + cb *= 2; + return cb <= 1 ? colorBlendModeFunctions.multiply(cb, cs) : colorBlendModeFunctions.screen(cb - 1, cs); + }, + softlight: function softlight(cb, cs) { + let d = 1; + let e = cb; + + if (cs > 0.5) { + e = 1; + d = cb > 0.25 ? Math.sqrt(cb) : ((16 * cb - 12) * cb + 4) * cb; + } + + return cb - (1 - 2 * cs) * e * (d - cb); + }, + hardlight: function hardlight(cb, cs) { + return colorBlendModeFunctions.overlay(cs, cb); + }, + difference: function difference(cb, cs) { + return Math.abs(cb - cs); + }, + exclusion: function exclusion(cb, cs) { + return cb + cs - 2 * cb * cs; + }, + // non-w3c functions: + average: function average(cb, cs) { + return (cb + cs) / 2; + }, + negation: function negation(cb, cs) { + return 1 - Math.abs(cb + cs - 1); + } +}; + +for (const f in colorBlendModeFunctions) { + if (colorBlendModeFunctions.hasOwnProperty(f)) { + colorBlend[f] = colorBlend.bind(null, colorBlendModeFunctions[f]); + } +} + +var dataUri = (environment => { + const fallback = (functionThis, node) => new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context); + + return { + 'data-uri': function dataUri(mimetypeNode, filePathNode) { + if (!filePathNode) { + filePathNode = mimetypeNode; + mimetypeNode = null; + } + + let mimetype = mimetypeNode && mimetypeNode.value; + let filePath = filePathNode.value; + const currentFileInfo = this.currentFileInfo; + const currentDirectory = currentFileInfo.rewriteUrls ? currentFileInfo.currentDirectory : currentFileInfo.entryPath; + const fragmentStart = filePath.indexOf('#'); + let fragment = ''; + + if (fragmentStart !== -1) { + fragment = filePath.slice(fragmentStart); + filePath = filePath.slice(0, fragmentStart); + } + + const context = clone(this.context); + context.rawBuffer = true; + const fileManager = environment.getFileManager(filePath, currentDirectory, context, environment, true); + + if (!fileManager) { + return fallback(this, filePathNode); + } + + let useBase64 = false; // detect the mimetype if not given + + if (!mimetypeNode) { + mimetype = environment.mimeLookup(filePath); + + if (mimetype === 'image/svg+xml') { + useBase64 = false; + } else { + // use base 64 unless it's an ASCII or UTF-8 format + const charset = environment.charsetLookup(mimetype); + useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; + } + + if (useBase64) { + mimetype += ';base64'; + } + } else { + useBase64 = /;base64$/.test(mimetype); + } + + const fileSync = fileManager.loadFileSync(filePath, currentDirectory, context, environment); + + if (!fileSync.contents) { + logger.warn(`Skipped data-uri embedding of ${filePath} because file not found`); + return fallback(this, filePathNode || mimetypeNode); + } + + let buf = fileSync.contents; + + if (useBase64 && !environment.encodeBase64) { + return fallback(this, filePathNode); + } + + buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf); + const uri = `data:${mimetype},${buf}${fragment}`; + return new URL(new Quoted(`"${uri}"`, uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); + } + }; +}); + +const getItemsFromNode = node => { + // handle non-array values as an array of length 1 + // return 'undefined' if index is invalid + const items = Array.isArray(node.value) ? node.value : Array(node); + return items; +}; + +var list = { + _SELF: function _SELF(n) { + return n; + }, + extract: function extract(values, index) { + index = index.value - 1; // (1-based index) + + return getItemsFromNode(values)[index]; + }, + length: function length(values) { + return new Dimension(getItemsFromNode(values).length); + }, + + /** + * Creates a Less list of incremental values. + * Modeled after Lodash's range function, also exists natively in PHP + * + * @param {Dimension} [start=1] + * @param {Dimension} end - e.g. 10 or 10px - unit is added to output + * @param {Dimension} [step=1] + */ + range: function range(start, end, step) { + let from; + let to; + let stepValue = 1; + const list = []; + + if (end) { + to = end; + from = start.value; + + if (step) { + stepValue = step.value; + } + } else { + from = 1; + to = start; + } + + for (let i = from; i <= to.value; i += stepValue) { + list.push(new Dimension(i, to.unit)); + } + + return new Expression(list); + }, + each: function each(list, rs) { + const rules = []; + let newRules; + let iterator; + + if (list.value && !(list instanceof Quoted)) { + if (Array.isArray(list.value)) { + iterator = list.value; + } else { + iterator = [list.value]; + } + } else if (list.ruleset) { + iterator = list.ruleset.rules; + } else if (list.rules) { + iterator = list.rules; + } else if (Array.isArray(list)) { + iterator = list; + } else { + iterator = [list]; + } + + let valueName = '@value'; + let keyName = '@key'; + let indexName = '@index'; + + if (rs.params) { + valueName = rs.params[0] && rs.params[0].name; + keyName = rs.params[1] && rs.params[1].name; + indexName = rs.params[2] && rs.params[2].name; + rs = rs.rules; + } else { + rs = rs.ruleset; + } + + for (let i = 0; i < iterator.length; i++) { + let key; + let value; + const item = iterator[i]; + + if (item instanceof Declaration) { + key = typeof item.name === 'string' ? item.name : item.name[0].value; + value = item.value; + } else { + key = new Dimension(i + 1); + value = item; + } + + if (item instanceof Comment) { + continue; + } + + newRules = rs.rules.slice(0); + + if (valueName) { + newRules.push(new Declaration(valueName, value, false, false, this.index, this.currentFileInfo)); + } + + if (indexName) { + newRules.push(new Declaration(indexName, new Dimension(i + 1), false, false, this.index, this.currentFileInfo)); + } + + if (keyName) { + newRules.push(new Declaration(keyName, key, false, false, this.index, this.currentFileInfo)); + } + + rules.push(new Ruleset([new Selector([new Element("", '&')])], newRules, rs.strictImports, rs.visibilityInfo())); + } + + return new Ruleset([new Selector([new Element("", '&')])], rules, rs.strictImports, rs.visibilityInfo()).eval(this.context); + } +}; + +const MathHelper = (fn, unit, n) => { + if (!(n instanceof Dimension)) { + throw { + type: 'Argument', + message: 'argument must be a number' + }; + } + + if (unit == null) { + unit = n.unit; + } else { + n = n.unify(); + } + + return new Dimension(fn(parseFloat(n.value)), unit); +}; + +const mathFunctions = { + // name, unit + ceil: null, + floor: null, + sqrt: null, + abs: null, + tan: '', + sin: '', + cos: '', + atan: 'rad', + asin: 'rad', + acos: 'rad' +}; + +for (const f in mathFunctions) { + if (mathFunctions.hasOwnProperty(f)) { + mathFunctions[f] = MathHelper.bind(null, Math[f], mathFunctions[f]); + } +} + +mathFunctions.round = (n, f) => { + const fraction = typeof f === 'undefined' ? 0 : f.value; + return MathHelper(num => num.toFixed(fraction), null, n); +}; + +const minMax = function minMax(isMin, args) { + args = Array.prototype.slice.call(args); + + switch (args.length) { + case 0: + throw { + type: 'Argument', + message: 'one or more arguments required' + }; + } + + let i; // key is the unit.toString() for unified Dimension values, + + let j; + let current; + let currentUnified; + let referenceUnified; + let unit; + let unitStatic; + let unitClone; + const // elems only contains original argument values. + order = []; + const values = {}; // value is the index into the order array. + + for (i = 0; i < args.length; i++) { + current = args[i]; + + if (!(current instanceof Dimension)) { + if (Array.isArray(args[i].value)) { + Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value)); + } + + continue; + } + + currentUnified = current.unit.toString() === '' && unitClone !== undefined ? new Dimension(current.value, unitClone).unify() : current.unify(); + unit = currentUnified.unit.toString() === '' && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString(); + unitStatic = unit !== '' && unitStatic === undefined || unit !== '' && order[0].unify().unit.toString() === '' ? unit : unitStatic; + unitClone = unit !== '' && unitClone === undefined ? current.unit.toString() : unitClone; + j = values[''] !== undefined && unit !== '' && unit === unitStatic ? values[''] : values[unit]; + + if (j === undefined) { + if (unitStatic !== undefined && unit !== unitStatic) { + throw { + type: 'Argument', + message: 'incompatible types' + }; + } + + values[unit] = order.length; + order.push(current); + continue; + } + + referenceUnified = order[j].unit.toString() === '' && unitClone !== undefined ? new Dimension(order[j].value, unitClone).unify() : order[j].unify(); + + if (isMin && currentUnified.value < referenceUnified.value || !isMin && currentUnified.value > referenceUnified.value) { + order[j] = current; + } + } + + if (order.length == 1) { + return order[0]; + } + + args = order.map(function (a) { + return a.toCSS(this.context); + }).join(this.context.compress ? ',' : ', '); + return new Anonymous(`${isMin ? 'min' : 'max'}(${args})`); +}; + +var number$1 = { + min: function min(...args) { + return minMax(true, args); + }, + max: function max(...args) { + return minMax(false, args); + }, + convert: function convert(val, unit) { + return val.convertTo(unit.value); + }, + pi: function pi() { + return new Dimension(Math.PI); + }, + mod: function mod(a, b) { + return new Dimension(a.value % b.value, a.unit); + }, + pow: function pow(x, y) { + if (typeof x === 'number' && typeof y === 'number') { + x = new Dimension(x); + y = new Dimension(y); + } else if (!(x instanceof Dimension) || !(y instanceof Dimension)) { + throw { + type: 'Argument', + message: 'arguments must be numbers' + }; + } + + return new Dimension(Math.pow(x.value, y.value), x.unit); + }, + percentage: function percentage(n) { + const result = MathHelper(num => num * 100, '%', n); + return result; + } +}; + +var string = { + e: function e(str) { + return new Quoted('"', str instanceof JavaScript ? str.evaluated : str.value, true); + }, + escape: function escape(str) { + return new Anonymous(encodeURI(str.value).replace(/=/g, '%3D').replace(/:/g, '%3A').replace(/#/g, '%23').replace(/;/g, '%3B').replace(/\(/g, '%28').replace(/\)/g, '%29')); + }, + replace: function replace(string, pattern, replacement, flags) { + let result = string.value; + replacement = replacement.type === 'Quoted' ? replacement.value : replacement.toCSS(); + result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement); + return new Quoted(string.quote || '', result, string.escaped); + }, + '%': function _(string + /* arg, arg, ... */ + ) { + const args = Array.prototype.slice.call(arguments, 1); + let result = string.value; + + for (let i = 0; i < args.length; i++) { + /* jshint loopfunc:true */ + result = result.replace(/%[sda]/i, token => { + const value = args[i].type === 'Quoted' && token.match(/s/i) ? args[i].value : args[i].toCSS(); + return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; + }); + } + + result = result.replace(/%%/g, '%'); + return new Quoted(string.quote || '', result, string.escaped); + } +}; + +var svg = (environment => { + return { + 'svg-gradient': function svgGradient(direction) { + let stops; + let gradientDirectionSvg; + let gradientType = 'linear'; + let rectangleDimension = 'x="0" y="0" width="1" height="1"'; + const renderEnv = { + compress: false + }; + let returner; + const directionValue = direction.toCSS(renderEnv); + let i; + let color; + let position; + let positionValue; + let alpha; + + function throwArgumentDescriptor() { + throw { + type: 'Argument', + message: 'svg-gradient expects direction, start_color [start_position], [color position,]...,' + ' end_color [end_position] or direction, color list' + }; + } + + if (arguments.length == 2) { + if (arguments[1].value.length < 2) { + throwArgumentDescriptor(); + } + + stops = arguments[1].value; + } else if (arguments.length < 3) { + throwArgumentDescriptor(); + } else { + stops = Array.prototype.slice.call(arguments, 1); + } + + switch (directionValue) { + case 'to bottom': + gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"'; + break; + + case 'to right': + gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"'; + break; + + case 'to bottom right': + gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"'; + break; + + case 'to top right': + gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"'; + break; + + case 'ellipse': + case 'ellipse at center': + gradientType = 'radial'; + gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"'; + rectangleDimension = 'x="-50" y="-50" width="101" height="101"'; + break; + + default: + throw { + type: 'Argument', + message: 'svg-gradient direction must be \'to bottom\', \'to right\',' + ' \'to bottom right\', \'to top right\' or \'ellipse at center\'' + }; + } + + returner = `<${gradientType}Gradient id="g" ${gradientDirectionSvg}>`; + + for (i = 0; i < stops.length; i += 1) { + if (stops[i] instanceof Expression) { + color = stops[i].value[0]; + position = stops[i].value[1]; + } else { + color = stops[i]; + position = undefined; + } + + if (!(color instanceof Color) || !((i === 0 || i + 1 === stops.length) && position === undefined) && !(position instanceof Dimension)) { + throwArgumentDescriptor(); + } + + positionValue = position ? position.toCSS(renderEnv) : i === 0 ? '0%' : '100%'; + alpha = color.alpha; + returner += ``; + } + + returner += ``; + returner = encodeURIComponent(returner); + returner = `data:image/svg+xml,${returner}`; + return new URL(new Quoted(`'${returner}'`, returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); + } + }; +}); + +const isa = (n, Type) => n instanceof Type ? Keyword.True : Keyword.False; + +const isunit = (n, unit) => { + if (unit === undefined) { + throw { + type: 'Argument', + message: 'missing the required second argument to isunit.' + }; + } + + unit = typeof unit.value === 'string' ? unit.value : unit; + + if (typeof unit !== 'string') { + throw { + type: 'Argument', + message: 'Second argument to isunit should be a unit or a string.' + }; + } + + return n instanceof Dimension && n.unit.is(unit) ? Keyword.True : Keyword.False; +}; + +var types = { + isruleset: function isruleset(n) { + return isa(n, DetachedRuleset); + }, + iscolor: function iscolor(n) { + return isa(n, Color); + }, + isnumber: function isnumber(n) { + return isa(n, Dimension); + }, + isstring: function isstring(n) { + return isa(n, Quoted); + }, + iskeyword: function iskeyword(n) { + return isa(n, Keyword); + }, + isurl: function isurl(n) { + return isa(n, URL); + }, + ispixel: function ispixel(n) { + return isunit(n, 'px'); + }, + ispercentage: function ispercentage(n) { + return isunit(n, '%'); + }, + isem: function isem(n) { + return isunit(n, 'em'); + }, + isunit, + unit: function unit(val, _unit) { + if (!(val instanceof Dimension)) { + throw { + type: 'Argument', + message: `the first argument to unit must be a number${val instanceof Operation ? '. Have you forgotten parenthesis?' : ''}` + }; + } + + if (_unit) { + if (_unit instanceof Keyword) { + _unit = _unit.value; + } else { + _unit = _unit.toCSS(); + } + } else { + _unit = ''; + } + + return new Dimension(val.value, _unit); + }, + 'get-unit': function getUnit(n) { + return new Anonymous(n.unit); + } +}; + +var Functions = (environment => { + const functions = { + functionRegistry, + functionCaller + }; // register functions + + functionRegistry.addMultiple(boolean$1); + functionRegistry.add('default', defaultFunc.eval.bind(defaultFunc)); + functionRegistry.addMultiple(color); + functionRegistry.addMultiple(colorBlend); + functionRegistry.addMultiple(dataUri(environment)); + functionRegistry.addMultiple(list); + functionRegistry.addMultiple(mathFunctions); + functionRegistry.addMultiple(number$1); + functionRegistry.addMultiple(string); + functionRegistry.addMultiple(svg()); + functionRegistry.addMultiple(types); + return functions; +}); + +var sourceMapOutput = (environment => { + class SourceMapOutput { + constructor(options) { + this._css = []; + this._rootNode = options.rootNode; + this._contentsMap = options.contentsMap; + this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap; + + if (options.sourceMapFilename) { + this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/'); + } + + this._outputFilename = options.outputFilename; + this.sourceMapURL = options.sourceMapURL; + + if (options.sourceMapBasepath) { + this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/'); + } + + if (options.sourceMapRootpath) { + this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/'); + + if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') { + this._sourceMapRootpath += '/'; + } + } else { + this._sourceMapRootpath = ''; + } + + this._outputSourceFiles = options.outputSourceFiles; + this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator(); + this._lineNumber = 0; + this._column = 0; + } + + removeBasepath(path) { + if (this._sourceMapBasepath && path.indexOf(this._sourceMapBasepath) === 0) { + path = path.substring(this._sourceMapBasepath.length); + + if (path.charAt(0) === '\\' || path.charAt(0) === '/') { + path = path.substring(1); + } + } + + return path; + } + + normalizeFilename(filename) { + filename = filename.replace(/\\/g, '/'); + filename = this.removeBasepath(filename); + return (this._sourceMapRootpath || '') + filename; + } + + add(chunk, fileInfo, index, mapLines) { + // ignore adding empty strings + if (!chunk) { + return; + } + + let lines; + let sourceLines; + let columns; + let sourceColumns; + let i; + + if (fileInfo && fileInfo.filename) { + let inputSource = this._contentsMap[fileInfo.filename]; // remove vars/banner added to the top of the file + + if (this._contentsIgnoredCharsMap[fileInfo.filename]) { + // adjust the index + index -= this._contentsIgnoredCharsMap[fileInfo.filename]; + + if (index < 0) { + index = 0; + } // adjust the source + + + inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]); + } // ignore empty content + + + if (inputSource === undefined) { + return; + } + + inputSource = inputSource.substring(0, index); + sourceLines = inputSource.split('\n'); + sourceColumns = sourceLines[sourceLines.length - 1]; + } + + lines = chunk.split('\n'); + columns = lines[lines.length - 1]; + + if (fileInfo && fileInfo.filename) { + if (!mapLines) { + this._sourceMapGenerator.addMapping({ + generated: { + line: this._lineNumber + 1, + column: this._column + }, + original: { + line: sourceLines.length, + column: sourceColumns.length + }, + source: this.normalizeFilename(fileInfo.filename) + }); + } else { + for (i = 0; i < lines.length; i++) { + this._sourceMapGenerator.addMapping({ + generated: { + line: this._lineNumber + i + 1, + column: i === 0 ? this._column : 0 + }, + original: { + line: sourceLines.length + i, + column: i === 0 ? sourceColumns.length : 0 + }, + source: this.normalizeFilename(fileInfo.filename) + }); + } + } + } + + if (lines.length === 1) { + this._column += columns.length; + } else { + this._lineNumber += lines.length - 1; + this._column = columns.length; + } + + this._css.push(chunk); + } + + isEmpty() { + return this._css.length === 0; + } + + toCSS(context) { + this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ + file: this._outputFilename, + sourceRoot: null + }); + + if (this._outputSourceFiles) { + for (const filename in this._contentsMap) { + if (this._contentsMap.hasOwnProperty(filename)) { + let source = this._contentsMap[filename]; + + if (this._contentsIgnoredCharsMap[filename]) { + source = source.slice(this._contentsIgnoredCharsMap[filename]); + } + + this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source); + } + } + } + + this._rootNode.genCSS(context, this); + + if (this._css.length > 0) { + let sourceMapURL; + const sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON()); + + if (this.sourceMapURL) { + sourceMapURL = this.sourceMapURL; + } else if (this._sourceMapFilename) { + sourceMapURL = this._sourceMapFilename; + } + + this.sourceMapURL = sourceMapURL; + this.sourceMap = sourceMapContent; + } + + return this._css.join(''); + } + + } + + return SourceMapOutput; +}); + +var sourceMapBuilder = ((SourceMapOutput, environment) => { + class SourceMapBuilder { + constructor(options) { + this.options = options; + } + + toCSS(rootNode, options, imports) { + const sourceMapOutput = new SourceMapOutput({ + contentsIgnoredCharsMap: imports.contentsIgnoredChars, + rootNode, + contentsMap: imports.contents, + sourceMapFilename: this.options.sourceMapFilename, + sourceMapURL: this.options.sourceMapURL, + outputFilename: this.options.sourceMapOutputFilename, + sourceMapBasepath: this.options.sourceMapBasepath, + sourceMapRootpath: this.options.sourceMapRootpath, + outputSourceFiles: this.options.outputSourceFiles, + sourceMapGenerator: this.options.sourceMapGenerator, + sourceMapFileInline: this.options.sourceMapFileInline + }); + const css = sourceMapOutput.toCSS(options); + this.sourceMap = sourceMapOutput.sourceMap; + this.sourceMapURL = sourceMapOutput.sourceMapURL; + + if (this.options.sourceMapInputFilename) { + this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename); + } + + if (this.options.sourceMapBasepath !== undefined && this.sourceMapURL !== undefined) { + this.sourceMapURL = sourceMapOutput.removeBasepath(this.sourceMapURL); + } + + return css + this.getCSSAppendage(); + } + + getCSSAppendage() { + let sourceMapURL = this.sourceMapURL; + + if (this.options.sourceMapFileInline) { + if (this.sourceMap === undefined) { + return ''; + } + + sourceMapURL = `data:application/json;base64,${environment.encodeBase64(this.sourceMap)}`; + } + + if (sourceMapURL) { + return `/*# sourceMappingURL=${sourceMapURL} */`; + } + + return ''; + } + + getExternalSourceMap() { + return this.sourceMap; + } + + setExternalSourceMap(sourceMap) { + this.sourceMap = sourceMap; + } + + isInline() { + return this.options.sourceMapFileInline; + } + + getSourceMapURL() { + return this.sourceMapURL; + } + + getOutputFilename() { + return this.options.sourceMapOutputFilename; + } + + getInputFilename() { + return this.sourceMapInputFilename; + } + + } + + return SourceMapBuilder; +}); + +var transformTree = ((root, options = {}) => { + let evaldRoot; + let variables = options.variables; + const evalEnv = new contexts.Eval(options); // + // Allows setting variables with a hash, so: + // + // `{ color: new tree.Color('#f01') }` will become: + // + // new tree.Declaration('@color', + // new tree.Value([ + // new tree.Expression([ + // new tree.Color('#f01') + // ]) + // ]) + // ) + // + + if (typeof variables === 'object' && !Array.isArray(variables)) { + variables = Object.keys(variables).map(k => { + let value = variables[k]; + + if (!(value instanceof tree.Value)) { + if (!(value instanceof tree.Expression)) { + value = new tree.Expression([value]); + } + + value = new tree.Value([value]); + } + + return new tree.Declaration(`@${k}`, value, false, null, 0); + }); + evalEnv.frames = [new tree.Ruleset(null, variables)]; + } + + const visitors$1 = [new visitors.JoinSelectorVisitor(), new visitors.MarkVisibleSelectorsVisitor(true), new visitors.ExtendVisitor(), new visitors.ToCSSVisitor({ + compress: Boolean(options.compress) + })]; + const preEvalVisitors = []; + let v; + let visitorIterator; + /** + * first() / get() allows visitors to be added while visiting + * + * @todo Add scoping for visitors just like functions for @plugin; right now they're global + */ + + if (options.pluginManager) { + visitorIterator = options.pluginManager.visitor(); + + for (var i = 0; i < 2; i++) { + visitorIterator.first(); + + while (v = visitorIterator.get()) { + if (v.isPreEvalVisitor) { + if (i === 0 || preEvalVisitors.indexOf(v) === -1) { + preEvalVisitors.push(v); + v.run(root); + } + } else { + if (i === 0 || visitors$1.indexOf(v) === -1) { + if (v.isPreVisitor) { + visitors$1.unshift(v); + } else { + visitors$1.push(v); + } + } + } + } + } + } + + evaldRoot = root.eval(evalEnv); + + for (var i = 0; i < visitors$1.length; i++) { + visitors$1[i].run(evaldRoot); + } // Run any remaining visitors added after eval pass + + + if (options.pluginManager) { + visitorIterator.first(); + + while (v = visitorIterator.get()) { + if (visitors$1.indexOf(v) === -1 && preEvalVisitors.indexOf(v) === -1) { + v.run(evaldRoot); + } + } + } + + return evaldRoot; +}); + +var parseTree = (SourceMapBuilder => { + class ParseTree { + constructor(root, imports) { + this.root = root; + this.imports = imports; + } + + toCSS(options) { + let evaldRoot; + const result = {}; + let sourceMapBuilder; + + try { + evaldRoot = transformTree(this.root, options); + } catch (e) { + throw new LessError(e, this.imports); + } + + try { + const compress = Boolean(options.compress); + + if (compress) { + logger.warn('The compress option has been deprecated. ' + 'We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.'); + } + + const toCSSOptions = { + compress, + dumpLineNumbers: options.dumpLineNumbers, + strictUnits: Boolean(options.strictUnits), + numPrecision: 8 + }; + + if (options.sourceMap) { + sourceMapBuilder = new SourceMapBuilder(options.sourceMap); + result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports); + } else { + result.css = evaldRoot.toCSS(toCSSOptions); + } + } catch (e) { + throw new LessError(e, this.imports); + } + + if (options.pluginManager) { + const postProcessors = options.pluginManager.getPostProcessors(); + + for (let i = 0; i < postProcessors.length; i++) { + result.css = postProcessors[i].process(result.css, { + sourceMap: sourceMapBuilder, + options, + imports: this.imports + }); + } + } + + if (options.sourceMap) { + result.map = sourceMapBuilder.getExternalSourceMap(); + } + + result.imports = []; + + for (const file in this.imports.files) { + if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) { + result.imports.push(file); + } + } + + return result; + } + + } + + return ParseTree; +}); + +var importManager = (environment => { + // FileInfo = { + // 'rewriteUrls' - option - whether to adjust URL's to be relative + // 'filename' - full resolved filename of current file + // 'rootpath' - path to append to normal URLs for this node + // 'currentDirectory' - path to the current file, absolute + // 'rootFilename' - filename of the base file + // 'entryPath' - absolute path to the entry file + // 'reference' - whether the file should not be output and only output parts that are referenced + class ImportManager { + constructor(less, context, rootFileInfo) { + this.less = less; + this.rootFilename = rootFileInfo.filename; + this.paths = context.paths || []; // Search paths, when importing + + this.contents = {}; // map - filename to contents of all the files + + this.contentsIgnoredChars = {}; // map - filename to lines at the beginning of each file to ignore + + this.mime = context.mime; + this.error = null; + this.context = context; // Deprecated? Unused outside of here, could be useful. + + this.queue = []; // Files which haven't been imported yet + + this.files = {}; // Holds the imported parse trees. + } + /** + * Add an import to be imported + * @param path - the raw path + * @param tryAppendExtension - whether to try appending a file extension (.less or .js if the path has no extension) + * @param currentFileInfo - the current file info (used for instance to work out relative paths) + * @param importOptions - import options + * @param callback - callback for when it is imported + */ + + + push(path, tryAppendExtension, currentFileInfo, importOptions, callback) { + const importManager = this; + const pluginLoader = this.context.pluginManager.Loader; + this.queue.push(path); + + const fileParsedFunc = (e, root, fullPath) => { + importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue + + const importedEqualsRoot = fullPath === importManager.rootFilename; + + if (importOptions.optional && e) { + callback(null, { + rules: [] + }, false, null); + logger.info(`The file ${fullPath} was skipped because it was not found and the import was marked optional.`); + } else { + // Inline imports aren't cached here. + // If we start to cache them, please make sure they won't conflict with non-inline imports of the + // same name as they used to do before this comment and the condition below have been added. + if (!importManager.files[fullPath] && !importOptions.inline) { + importManager.files[fullPath] = { + root, + options: importOptions + }; + } + + if (e && !importManager.error) { + importManager.error = e; + } + + callback(e, root, importedEqualsRoot, fullPath); + } + }; + + const newFileInfo = { + rewriteUrls: this.context.rewriteUrls, + entryPath: currentFileInfo.entryPath, + rootpath: currentFileInfo.rootpath, + rootFilename: currentFileInfo.rootFilename + }; + const fileManager = environment.getFileManager(path, currentFileInfo.currentDirectory, this.context, environment); + + if (!fileManager) { + fileParsedFunc({ + message: `Could not find a file-manager for ${path}` + }); + return; + } + + const loadFileCallback = loadedFile => { + let plugin; + const resolvedFilename = loadedFile.filename; + const contents = loadedFile.contents.replace(/^\uFEFF/, ''); // Pass on an updated rootpath if path of imported file is relative and file + // is in a (sub|sup) directory + // + // Examples: + // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/', + // then rootpath should become 'less/module/nav/' + // - If path of imported file is '../mixins.less' and rootpath is 'less/', + // then rootpath should become 'less/../' + + newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename); + + if (newFileInfo.rewriteUrls) { + newFileInfo.rootpath = fileManager.join(importManager.context.rootpath || '', fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath)); + + if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) { + newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath); + } + } + + newFileInfo.filename = resolvedFilename; + const newEnv = new contexts.Parse(importManager.context); + newEnv.processImports = false; + importManager.contents[resolvedFilename] = contents; + + if (currentFileInfo.reference || importOptions.reference) { + newFileInfo.reference = true; + } + + if (importOptions.isPlugin) { + plugin = pluginLoader.evalPlugin(contents, newEnv, importManager, importOptions.pluginArgs, newFileInfo); + + if (plugin instanceof LessError) { + fileParsedFunc(plugin, null, resolvedFilename); + } else { + fileParsedFunc(null, plugin, resolvedFilename); + } + } else if (importOptions.inline) { + fileParsedFunc(null, contents, resolvedFilename); + } else { + // import (multiple) parse trees apparently get altered and can't be cached. + // TODO: investigate why this is + if (importManager.files[resolvedFilename] && !importManager.files[resolvedFilename].options.multiple && !importOptions.multiple) { + fileParsedFunc(null, importManager.files[resolvedFilename].root, resolvedFilename); + } else { + new Parser(newEnv, importManager, newFileInfo).parse(contents, (e, root) => { + fileParsedFunc(e, root, resolvedFilename); + }); + } + } + }; + + let promise; + const context = clone(this.context); + + if (tryAppendExtension) { + context.ext = importOptions.isPlugin ? '.js' : '.less'; + } + + if (importOptions.isPlugin) { + context.mime = 'application/javascript'; + promise = pluginLoader.loadPlugin(path, currentFileInfo.currentDirectory, context, environment, fileManager); + } else { + promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, context, environment, (err, loadedFile) => { + if (err) { + fileParsedFunc(err); + } else { + loadFileCallback(loadedFile); + } + }); + } + + if (promise) { + promise.then(loadFileCallback, fileParsedFunc); + } + } + + } + + return ImportManager; +}); + +var Render = ((environment, ParseTree, ImportManager) => { + const render = function render(input, options, callback) { + if (typeof options === 'function') { + callback = options; + options = copyOptions(this.options, {}); + } else { + options = copyOptions(this.options, options || {}); + } + + if (!callback) { + const self = this; + return new Promise((resolve, reject) => { + render.call(self, input, options, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + }); + }); + } else { + this.parse(input, options, (err, root, imports, options) => { + if (err) { + return callback(err); + } + + let result; + + try { + const parseTree = new ParseTree(root, imports); + result = parseTree.toCSS(options); + } catch (err) { + return callback(err); + } + + callback(null, result); + }); + } + }; + + return render; +}); + +/** + * Plugin Manager + */ +class PluginManager { + constructor(less) { + this.less = less; + this.visitors = []; + this.preProcessors = []; + this.postProcessors = []; + this.installedPlugins = []; + this.fileManagers = []; + this.iterator = -1; + this.pluginCache = {}; + this.Loader = new less.PluginLoader(less); + } + /** + * Adds all the plugins in the array + * @param {Array} plugins + */ + + + addPlugins(plugins) { + if (plugins) { + for (let i = 0; i < plugins.length; i++) { + this.addPlugin(plugins[i]); + } + } + } + /** + * + * @param plugin + * @param {String} filename + */ + + + addPlugin(plugin, filename, functionRegistry) { + this.installedPlugins.push(plugin); + + if (filename) { + this.pluginCache[filename] = plugin; + } + + if (plugin.install) { + plugin.install(this.less, this, functionRegistry || this.less.functions.functionRegistry); + } + } + /** + * + * @param filename + */ + + + get(filename) { + return this.pluginCache[filename]; + } + /** + * Adds a visitor. The visitor object has options on itself to determine + * when it should run. + * @param visitor + */ + + + addVisitor(visitor) { + this.visitors.push(visitor); + } + /** + * Adds a pre processor object + * @param {object} preProcessor + * @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import + */ + + + addPreProcessor(preProcessor, priority) { + let indexToInsertAt; + + for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) { + if (this.preProcessors[indexToInsertAt].priority >= priority) { + break; + } + } + + this.preProcessors.splice(indexToInsertAt, 0, { + preProcessor, + priority + }); + } + /** + * Adds a post processor object + * @param {object} postProcessor + * @param {number} priority - guidelines 1 = before compression, 1000 = compression, 2000 = after compression + */ + + + addPostProcessor(postProcessor, priority) { + let indexToInsertAt; + + for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) { + if (this.postProcessors[indexToInsertAt].priority >= priority) { + break; + } + } + + this.postProcessors.splice(indexToInsertAt, 0, { + postProcessor, + priority + }); + } + /** + * + * @param manager + */ + + + addFileManager(manager) { + this.fileManagers.push(manager); + } + /** + * + * @returns {Array} + * @private + */ + + + getPreProcessors() { + const preProcessors = []; + + for (let i = 0; i < this.preProcessors.length; i++) { + preProcessors.push(this.preProcessors[i].preProcessor); + } + + return preProcessors; + } + /** + * + * @returns {Array} + * @private + */ + + + getPostProcessors() { + const postProcessors = []; + + for (let i = 0; i < this.postProcessors.length; i++) { + postProcessors.push(this.postProcessors[i].postProcessor); + } + + return postProcessors; + } + /** + * + * @returns {Array} + * @private + */ + + + getVisitors() { + return this.visitors; + } + + visitor() { + const self = this; + return { + first: function first() { + self.iterator = -1; + return self.visitors[self.iterator]; + }, + get: function get() { + self.iterator += 1; + return self.visitors[self.iterator]; + } + }; + } + /** + * + * @returns {Array} + * @private + */ + + + getFileManagers() { + return this.fileManagers; + } + +} + +let pm; + +function PluginManagerFactory(less, newFactory) { + if (newFactory || !pm) { + pm = new PluginManager(less); + } + + return pm; +} + +var Parse = ((environment, ParseTree, ImportManager) => { + const parse = function parse(input, options, callback) { + if (typeof options === 'function') { + callback = options; + options = copyOptions(this.options, {}); + } else { + options = copyOptions(this.options, options || {}); + } + + if (!callback) { + const self = this; + return new Promise((resolve, reject) => { + parse.call(self, input, options, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + }); + }); + } else { + let context; + let rootFileInfo; + const pluginManager = new PluginManagerFactory(this, !options.reUsePluginManager); + options.pluginManager = pluginManager; + context = new contexts.Parse(options); + + if (options.rootFileInfo) { + rootFileInfo = options.rootFileInfo; + } else { + const filename = options.filename || 'input'; + const entryPath = filename.replace(/[^\/\\]*$/, ''); + rootFileInfo = { + filename, + rewriteUrls: context.rewriteUrls, + rootpath: context.rootpath || '', + currentDirectory: entryPath, + entryPath, + rootFilename: filename + }; // add in a missing trailing slash + + if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== '/') { + rootFileInfo.rootpath += '/'; + } + } + + const imports = new ImportManager(this, context, rootFileInfo); + this.importManager = imports; // TODO: allow the plugins to be just a list of paths or names + // Do an async plugin queue like lessc + + if (options.plugins) { + options.plugins.forEach(plugin => { + let evalResult; + let contents; + + if (plugin.fileContent) { + contents = plugin.fileContent.replace(/^\uFEFF/, ''); + evalResult = pluginManager.Loader.evalPlugin(contents, context, imports, plugin.options, plugin.filename); + + if (evalResult instanceof LessError) { + return callback(evalResult); + } + } else { + pluginManager.addPlugin(plugin); + } + }); + } + + new Parser(context, imports, rootFileInfo).parse(input, (e, root) => { + if (e) { + return callback(e); + } + + callback(null, root, imports, options); + }, options); + } + }; + + return parse; +}); + +var createFromEnvironment = ((environment, fileManagers) => { + /** + * @todo + * This original code could be improved quite a bit. + * Many classes / modules currently add side-effects / mutations to passed in objects, + * which makes it hard to refactor and reason about. + */ + environment = new environment$1(environment, fileManagers); + const SourceMapOutput = sourceMapOutput(environment); + const SourceMapBuilder = sourceMapBuilder(SourceMapOutput, environment); + const ParseTree = parseTree(SourceMapBuilder); + const ImportManager = importManager(environment); + const render = Render(environment, ParseTree); + const parse = Parse(environment, ParseTree, ImportManager); + const functions = Functions(environment); + /** + * @todo + * This root properties / methods need to be organized. + * It's not clear what should / must be public and why. + */ + + const initial = { + version: [3, 10, 0], + data, + tree, + Environment: environment$1, + AbstractFileManager, + AbstractPluginLoader, + environment, + visitors, + Parser, + functions, + contexts, + SourceMapOutput, + SourceMapBuilder, + ParseTree, + ImportManager, + render, + parse, + LessError, + transformTree, + utils, + PluginManager: PluginManagerFactory, + logger + }; // Create a public API + + const ctor = t => function (...args) { + return new t(...args); + }; + + let t; + const api = Object.create(initial); + + for (const n in initial.tree) { + /* eslint guard-for-in: 0 */ + t = initial.tree[n]; + + if (typeof t === 'function') { + api[n.toLowerCase()] = ctor(t); + } else { + api[n] = Object.create(null); + + for (const o in t) { + /* eslint guard-for-in: 0 */ + api[n][o.toLowerCase()] = ctor(t[o]); + } + } + } + + return api; +}); + +function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; +} + +var lesscHelper = createCommonjsModule(function (module, exports) { + // lessc_helper.js + // + // helper functions for lessc + const lessc_helper = { + // Stylize a string + stylize: function stylize(str, style) { + const styles = { + 'reset': [0, 0], + 'bold': [1, 22], + 'inverse': [7, 27], + 'underline': [4, 24], + 'yellow': [33, 39], + 'green': [32, 39], + 'red': [31, 39], + 'grey': [90, 39] + }; + return `\x1b[${styles[style][0]}m${str}\x1b[${styles[style][1]}m`; + }, + // Print command line options + printUsage: function printUsage() { + console.log('usage: lessc [option option=parameter ...] [destination]'); + console.log(''); + console.log('If source is set to `-\' (dash or hyphen-minus), input is read from stdin.'); + console.log(''); + console.log('options:'); + console.log(' -h, --help Prints help (this message) and exit.'); + console.log(' --include-path=PATHS Sets include paths. Separated by `:\'. `;\' also supported on windows.'); + console.log(' -M, --depends Outputs a makefile import dependency list to stdout.'); + console.log(' --no-color Disables colorized output.'); + console.log(' --ie-compat Enables IE8 compatibility checks.'); + console.log(' --js Enables inline JavaScript in less files'); + console.log(' -l, --lint Syntax check only (lint).'); + console.log(' -s, --silent Suppresses output of error messages.'); + console.log(' --strict-imports Forces evaluation of imports.'); + console.log(' --insecure Allows imports from insecure https hosts.'); + console.log(' -v, --version Prints version number and exit.'); + console.log(' --verbose Be verbose.'); + console.log(' --source-map[=FILENAME] Outputs a v3 sourcemap to the filename (or output filename.map).'); + console.log(' --source-map-rootpath=X Adds this path onto the sourcemap filename and less file paths.'); + console.log(' --source-map-basepath=X Sets sourcemap base path, defaults to current working directory.'); + console.log(' --source-map-include-source Puts the less files into the map instead of referencing them.'); + console.log(' --source-map-inline Puts the map (and any less files) as a base64 data uri into the output css file.'); + console.log(' --source-map-url=URL Sets a custom URL to map file, for sourceMappingURL comment'); + console.log(' in generated CSS file.'); + 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=, --rewrite-urls= Rewrites URLs to make them relative to the base less file.'); + console.log(' all|local|off \'all\' rewrites all URLs, \'local\' just those starting with a \'.\''); + 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.'); + 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(' --plugin=PLUGIN=OPTIONS Loads a plugin. You can also omit the --plugin= if the plugin begins'); + console.log(' less-plugin. E.g. the clean css plugin is called less-plugin-clean-css'); + console.log(' once installed (npm install less-plugin-clean-css), use either with'); + console.log(' --plugin=less-plugin-clean-css or just --clean-css'); + console.log(' specify options afterwards e.g. --plugin=less-plugin-clean-css="advanced"'); + 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\''); + console.log(' that will output the information within a fake'); + console.log(' media query which is compatible with the SASS'); + console.log(' format, and \'all\' which will do both.'); + console.log(' -x, --compress Compresses output by removing some whitespaces.'); + console.log(' We recommend you use a dedicated minifer like less-plugin-clean-css'); + console.log(''); + console.log('Report bugs to: http://github.com/less/less.js/issues'); + console.log('Home page: '); + } + }; // Exports helper functions + + for (const h in lessc_helper) { + if (lessc_helper.hasOwnProperty(h)) { + exports[h] = lessc_helper[h]; + } + } +}); + +/** + * Node Plugin Loader + */ + +class PluginLoader extends AbstractPluginLoader { + constructor(less) { + super(); + this.less = less; + + this.require = prefix => { + prefix = path.dirname(prefix); + return id => { + const str = id.substr(0, 2); + + if (str === '..' || str === './') { + return require(path.join(prefix, id)); + } else { + return require(id); + } + }; + }; + } + + loadPlugin(filename, basePath, context, environment, fileManager) { + const prefix = filename.slice(0, 1); + const explicit = prefix === '.' || prefix === '/' || filename.slice(-3).toLowerCase() === '.js'; + + if (!explicit) { + context.prefixes = ['less-plugin-', '']; + } + + return new Promise((fulfill, reject) => { + fileManager.loadFile(filename, basePath, context, environment).then(data => { + try { + fulfill(data); + } catch (e) { + console.log(e); + reject(e); + } + }).catch(err => { + reject(err); + }); + }); + } + +} + +// Export a new default each time +var defaultOptions = (() => ({ + /* Inline Javascript - @plugin still allowed */ + javascriptEnabled: false, + + /* Outputs a makefile import dependency list to stdout. */ + depends: false, + + /* (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, + + /* Runs the less parser and just reports errors without any output. */ + lint: false, + + /* Sets available include paths. + * If the file in an @import rule does not exist at that exact location, + * less will look for it at the location(s) passed to this option. + * You might use this for instance to specify a path to a library which + * you want to be referenced simply and relatively in the less files. */ + paths: [], + + /* color output in the terminal */ + color: true, + + /* The strictImports controls whether the compiler will allow an @import inside of either + * @media blocks or (a later addition) other selector blocks. + * See: https://github.com/less/less.js/issues/656 */ + strictImports: false, + + /* Allow Imports from Insecure HTTPS Hosts */ + insecure: false, + + /* Allows you to add a path to every generated import and url in your css. + * This does not affect less import statements that are processed, just ones + * that are left in the output css. */ + rootpath: '', + + /* By default URLs are kept as-is, so if you import a file in a sub-directory + * that references an image, exactly the same URL will be output in the css. + * This option allows you to re-write URL's in imported files so that the + * URL is always relative to the base imported file */ + rewriteUrls: 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, + + /* Effectively the declaration is put at the top of your base Less file, + * meaning it can be used but it also can be overridden if this variable + * is defined in the file. */ + globalVars: null, + + /* As opposed to the global variable option, this puts the declaration at the + * end of your base file, meaning it will override anything defined in your Less file. */ + modifyVars: null, + + /* This option allows you to specify a argument to go on to every URL. */ + urlArgs: '' +})); + +var imageSize = (environment => { + function _imageSize(functionContext, filePathNode) { + let filePath = filePathNode.value; + const currentFileInfo = functionContext.currentFileInfo; + const currentDirectory = currentFileInfo.rewriteUrls ? currentFileInfo.currentDirectory : currentFileInfo.entryPath; + const fragmentStart = filePath.indexOf('#'); + let fragment = ''; + + if (fragmentStart !== -1) { + fragment = filePath.slice(fragmentStart); + filePath = filePath.slice(0, fragmentStart); + } + + const fileManager = environment.getFileManager(filePath, currentDirectory, functionContext.context, environment, true); + + if (!fileManager) { + throw { + type: 'File', + message: `Can not set up FileManager for ${filePathNode}` + }; + } + + const fileSync = fileManager.loadFileSync(filePath, currentDirectory, functionContext.context, environment); + + if (fileSync.error) { + throw fileSync.error; + } + + const sizeOf = require('image-size'); + + return sizeOf(fileSync.filename); + } + + const imageFunctions = { + 'image-size': function imageSize(filePathNode) { + const size = _imageSize(this, filePathNode); + + return new Expression([new Dimension(size.width, 'px'), new Dimension(size.height, 'px')]); + }, + 'image-width': function imageWidth(filePathNode) { + const size = _imageSize(this, filePathNode); + + return new Dimension(size.width, 'px'); + }, + 'image-height': function imageHeight(filePathNode) { + const size = _imageSize(this, filePathNode); + + return new Dimension(size.height, 'px'); + } + }; + functionRegistry.addMultiple(imageFunctions); +}); + +const less = createFromEnvironment(environment, [new FileManager(), new UrlFileManager()]); // allow people to create less with their own environment + +less.createFromEnvironment = createFromEnvironment; +less.lesscHelper = lesscHelper; +less.PluginLoader = PluginLoader; +less.fs = fs$1; +less.FileManager = FileManager; +less.UrlFileManager = UrlFileManager; // Set up options + +less.options = defaultOptions(); // provide image-size functionality + +imageSize(less.environment); + +let errno; +let mkdirp; try { - errno = require('errno'); + errno = require('errno'); } catch (err) { - errno = null; + errno = null; } - -var less = require('../lib/less-node'), - pluginManager = new less.PluginManager(less), - fileManager = new less.FileManager(), - plugins = [], - queuePlugins = [], - args = process.argv.slice(1), - silent = false, - verbose = false, - options = less.options; - +const pluginManager = new less.PluginManager(less); +const fileManager = new less.FileManager(); +const plugins = []; +const queuePlugins = []; +let args = process.argv.slice(1); +let silent = false; +let verbose = false; +const options = less.options; options.plugins = plugins; options.reUsePluginManager = true; - -var sourceMapOptions = {}; -var continueProcessing = true; - -// Calling process.exit does not flush stdout always. Instead of exiting the process, we set the process' exitCode, +const sourceMapOptions = {}; +let continueProcessing = true; // Calling process.exit does not flush stdout always. Instead of exiting the process, we set the process' exitCode, // close all handles and wait for the event loop to exit the process. // @see https://github.com/nodejs/node/issues/6409 // Unfortunately, node 0.10.x does not support setting process.exitCode, so we need to call reallyExit() explicitly. @@ -38,527 +12598,595 @@ var continueProcessing = true; // Additionally we also need to make sure that uncaughtExceptions are never swallowed. // @see https://github.com/less/less.js/issues/2881 // This code can safely be removed if node 0.10.x is not supported anymore. -process.on('exit', function() { process.reallyExit(process.exitCode); }); -process.on('uncaughtException', function(err) { - console.error(err); - process.exitCode = 1; + +process.on('exit', () => { + process.reallyExit(process.exitCode); }); -// This code will still be required because otherwise rejected promises would not be reported to the user -process.on('unhandledRejection', function(err) { - console.error(err); - process.exitCode = 1; +process.on('uncaughtException', err => { + console.error(err); + process.exitCode = 1; +}); // This code will still be required because otherwise rejected promises would not be reported to the user + +process.on('unhandledRejection', err => { + console.error(err); + process.exitCode = 1; }); -var checkArgFunc = function(arg, option) { - if (!option) { - console.error(arg + ' option requires a parameter'); - continueProcessing = false; - process.exitCode = 1; - return false; - } - return true; +const checkArgFunc = (arg, option) => { + if (!option) { + console.error(`${arg} option requires a parameter`); + continueProcessing = false; + process.exitCode = 1; + return false; + } + + return true; }; -var checkBooleanArg = function(arg) { - var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg); - if (!onOff) { - console.error(' unable to parse ' + arg + ' as a boolean. use one of on/t/true/y/yes/off/f/false/n/no'); - continueProcessing = false; - process.exitCode = 1; - return false; - } - return Boolean(onOff[2]); +const checkBooleanArg = arg => { + const onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg); + + if (!onOff) { + console.error(` unable to parse ${arg} as a boolean. use one of on/t/true/y/yes/off/f/false/n/no`); + continueProcessing = false; + process.exitCode = 1; + return false; + } + + return Boolean(onOff[2]); }; -var parseVariableOption = function(option, variables) { - var parts = option.split('=', 2); - variables[parts[0]] = parts[1]; +const parseVariableOption = (option, variables) => { + const parts = option.split('=', 2); + variables[parts[0]] = parts[1]; }; -var sourceMapFileInline = false; +let sourceMapFileInline = false; function printUsage() { - less.lesscHelper.printUsage(); - pluginManager.Loader.printUsage(plugins); - continueProcessing = false; + less.lesscHelper.printUsage(); + pluginManager.Loader.printUsage(plugins); + continueProcessing = false; } + function render() { + if (!continueProcessing) { + return; + } + + let input = args[1]; - if (!continueProcessing) { + if (input && input != '-') { + input = path.resolve(process.cwd(), input); + } + + let output = args[2]; + const outputbase = args[2]; + + if (output) { + output = path.resolve(process.cwd(), output); + } + + if (options.sourceMap) { + sourceMapOptions.sourceMapInputFilename = input; + + if (!sourceMapOptions.sourceMapFullFilename) { + if (!output && !sourceMapFileInline) { + console.error('the sourcemap option only has an optional filename if the css filename is given'); + console.error('consider adding --source-map-map-inline which embeds the sourcemap into the css'); + process.exitCode = 1; return; - } + } // its in the same directory, so always just the basename - var input = args[1]; - if (input && input != '-') { - input = path.resolve(process.cwd(), input); - } - var output = args[2]; - var outputbase = args[2]; - if (output) { - output = path.resolve(process.cwd(), output); + + if (output) { + sourceMapOptions.sourceMapOutputFilename = path.basename(output); + sourceMapOptions.sourceMapFullFilename = `${output}.map`; + } // its in the same directory, so always just the basename + + + if ('sourceMapFullFilename' in sourceMapOptions) { + sourceMapOptions.sourceMapFilename = path.basename(sourceMapOptions.sourceMapFullFilename); + } + } else if (options.sourceMap && !sourceMapFileInline) { + const mapFilename = path.resolve(process.cwd(), sourceMapOptions.sourceMapFullFilename); + const mapDir = path.dirname(mapFilename); + const outputDir = path.dirname(output); // find the path from the map to the output file + + sourceMapOptions.sourceMapOutputFilename = path.join(path.relative(mapDir, outputDir), path.basename(output)); // make the sourcemap filename point to the sourcemap relative to the css file output directory + + sourceMapOptions.sourceMapFilename = path.join(path.relative(outputDir, mapDir), path.basename(sourceMapOptions.sourceMapFullFilename)); } + } - if (options.sourceMap) { + if (sourceMapOptions.sourceMapBasepath === undefined) { + sourceMapOptions.sourceMapBasepath = input ? path.dirname(input) : process.cwd(); + } - sourceMapOptions.sourceMapInputFilename = input; - if (!sourceMapOptions.sourceMapFullFilename) { - if (!output && !sourceMapFileInline) { - console.error('the sourcemap option only has an optional filename if the css filename is given'); - console.error('consider adding --source-map-map-inline which embeds the sourcemap into the css'); - process.exitCode = 1; - return; - } - // its in the same directory, so always just the basename - if (output) { - sourceMapOptions.sourceMapOutputFilename = path.basename(output); - sourceMapOptions.sourceMapFullFilename = output + '.map'; - } - // its in the same directory, so always just the basename - if ('sourceMapFullFilename' in sourceMapOptions) { - sourceMapOptions.sourceMapFilename = path.basename(sourceMapOptions.sourceMapFullFilename); - } - } else if (options.sourceMap && !sourceMapFileInline) { - var mapFilename = path.resolve(process.cwd(), sourceMapOptions.sourceMapFullFilename), - mapDir = path.dirname(mapFilename), - outputDir = path.dirname(output); - // find the path from the map to the output file - sourceMapOptions.sourceMapOutputFilename = path.join( - path.relative(mapDir, outputDir), path.basename(output)); + if (sourceMapOptions.sourceMapRootpath === undefined) { + const pathToMap = path.dirname((sourceMapFileInline ? output : sourceMapOptions.sourceMapFullFilename) || '.'); + const pathToInput = path.dirname(sourceMapOptions.sourceMapInputFilename || '.'); + sourceMapOptions.sourceMapRootpath = path.relative(pathToMap, pathToInput); + } - // make the sourcemap filename point to the sourcemap relative to the css file output directory - sourceMapOptions.sourceMapFilename = path.join( - path.relative(outputDir, mapDir), path.basename(sourceMapOptions.sourceMapFullFilename)); + if (!input) { + console.error('lessc: no input files'); + console.error(''); + printUsage(); + process.exitCode = 1; + return; + } + + const ensureDirectory = filepath => { + const dir = path.dirname(filepath); + let cmd; + const existsSync = fs$1.existsSync || path.existsSync; + + if (!existsSync(dir)) { + if (mkdirp === undefined) { + try { + mkdirp = require('mkdirp'); + } catch (e) { + mkdirp = null; } - } + } - if (sourceMapOptions.sourceMapBasepath === undefined) { - sourceMapOptions.sourceMapBasepath = input ? path.dirname(input) : process.cwd(); + cmd = mkdirp && mkdirp.sync || fs$1.mkdirSync; + cmd(dir); } + }; - if (sourceMapOptions.sourceMapRootpath === undefined) { - var pathToMap = path.dirname((sourceMapFileInline ? output : sourceMapOptions.sourceMapFullFilename) || '.'), - pathToInput = path.dirname(sourceMapOptions.sourceMapInputFilename || '.'); - sourceMapOptions.sourceMapRootpath = path.relative(pathToMap, pathToInput); + if (options.depends) { + if (!outputbase) { + console.error('option --depends requires an output path to be specified'); + process.exitCode = 1; + return; } + process.stdout.write(`${outputbase}: `); + } - if (!input) { - console.error('lessc: no input files'); - console.error(''); - printUsage(); - process.exitCode = 1; - return; - } + if (!sourceMapFileInline) { + var writeSourceMap = (output = '', onDone) => { + const filename = sourceMapOptions.sourceMapFullFilename; + ensureDirectory(filename); + fs$1.writeFile(filename, output, 'utf8', err => { + if (err) { + let description = 'Error: '; - var ensureDirectory = function (filepath) { - var dir = path.dirname(filepath), - cmd, - existsSync = fs.existsSync || path.existsSync; - if (!existsSync(dir)) { - if (mkdirp === undefined) { - try {mkdirp = require('mkdirp');} - catch (e) { mkdirp = null; } - } - cmd = mkdirp && mkdirp.sync || fs.mkdirSync; - cmd(dir); + if (errno && errno.errno[err.errno]) { + description += errno.errno[err.errno].description; + } else { + description += `${err.code} ${err.message}`; + } + + console.error(`lessc: failed to create file ${filename}`); + console.error(description); + process.exitCode = 1; + } else { + less.logger.info(`lessc: wrote ${filename}`); } + + onDone(); + }); }; + } + const writeSourceMapIfNeeded = (output, onDone) => { + if (options.sourceMap && !sourceMapFileInline) { + writeSourceMap(output, onDone); + } else { + onDone(); + } + }; + + const writeOutput = (output, result, onSuccess) => { if (options.depends) { - if (!outputbase) { - console.error('option --depends requires an output path to be specified'); - process.exitCode = 1; - return; + onSuccess(); + } else if (output) { + ensureDirectory(output); + fs$1.writeFile(output, result.css, { + encoding: 'utf8' + }, err => { + if (err) { + let description = 'Error: '; + + if (errno && errno.errno[err.errno]) { + description += errno.errno[err.errno].description; + } else { + description += `${err.code} ${err.message}`; + } + + console.error(`lessc: failed to create file ${output}`); + console.error(description); + process.exitCode = 1; + } else { + less.logger.info(`lessc: wrote ${output}`); + onSuccess(); } - process.stdout.write(outputbase + ': '); - } - - if (!sourceMapFileInline) { - var writeSourceMap = function(output, onDone) { - output = output || ''; - var filename = sourceMapOptions.sourceMapFullFilename; - ensureDirectory(filename); - fs.writeFile(filename, output, 'utf8', function (err) { - if (err) { - var description = 'Error: '; - if (errno && errno.errno[err.errno]) { - description += errno.errno[err.errno].description; - } else { - description += err.code + ' ' + err.message; - } - console.error('lessc: failed to create file ' + filename); - console.error(description); - process.exitCode = 1; - } else { - less.logger.info('lessc: wrote ' + filename); - } - onDone(); - }); - }; + }); + } else if (!options.depends) { + process.stdout.write(result.css); + onSuccess(); } + }; - var writeSourceMapIfNeeded = function(output, onDone) { - if (options.sourceMap && !sourceMapFileInline) { - writeSourceMap(output, onDone); - } else { - onDone(); + const logDependencies = (options, result) => { + if (options.depends) { + let depends = ''; + + for (let i = 0; i < result.imports.length; i++) { + depends += `${result.imports[i]} `; + } + + console.log(depends); + } + }; + + const parseLessFile = (e, data) => { + if (e) { + console.error(`lessc: ${e.message}`); + process.exitCode = 1; + return; + } + + data = data.replace(/^\uFEFF/, ''); + options.paths = [path.dirname(input)].concat(options.paths); + options.filename = input; + + if (options.lint) { + options.sourceMap = false; + } + + sourceMapOptions.sourceMapFileInline = sourceMapFileInline; + + if (options.sourceMap) { + options.sourceMap = sourceMapOptions; + } + + less.logger.addListener({ + info: function info(msg) { + if (verbose) { + console.log(msg); } - }; + }, + warn: function warn(msg) { + // do not show warning if the silent option is used + if (!silent) { + console.warn(msg); + } + }, + error: function error(msg) { + console.error(msg); + } + }); + less.render(data, options).then(result => { + if (!options.lint) { + writeOutput(output, result, () => { + writeSourceMapIfNeeded(result.map, () => { + logDependencies(options, result); + }); + }); + } + }, err => { + if (!options.silent) { + console.error(err.toString({ + stylize: options.color && less.lesscHelper.stylize + })); + } - var writeOutput = function(output, result, onSuccess) { - if (options.depends) { - onSuccess(); - } else if (output) { - ensureDirectory(output); - fs.writeFile(output, result.css, {encoding: 'utf8'}, function (err) { - if (err) { - var description = 'Error: '; - if (errno && errno.errno[err.errno]) { - description += errno.errno[err.errno].description; - } else { - description += err.code + ' ' + err.message; - } - console.error('lessc: failed to create file ' + output); - console.error(description); - process.exitCode = 1; - } else { - less.logger.info('lessc: wrote ' + output); - onSuccess(); - } - }); - } else if (!options.depends) { - process.stdout.write(result.css); - onSuccess(); + process.exitCode = 1; + }); + }; + + if (input != '-') { + fs$1.readFile(input, 'utf8', parseLessFile); + } else { + process.stdin.resume(); + process.stdin.setEncoding('utf8'); + let buffer = ''; + process.stdin.on('data', data => { + buffer += data; + }); + process.stdin.on('end', () => { + parseLessFile(false, buffer); + }); + } +} + +function processPluginQueue() { + let x = 0; + + function pluginError(name) { + console.error(`Unable to load plugin ${name} please make sure that it is installed under or at the same level as less`); + process.exitCode = 1; + } + + function pluginFinished(plugin) { + x++; + plugins.push(plugin); + + if (x === queuePlugins.length) { + render(); + } + } + + queuePlugins.forEach(queue => { + const context = clone(options); + pluginManager.Loader.loadPlugin(queue.name, process.cwd(), context, less.environment, fileManager).then(data => { + pluginFinished({ + fileContent: data.contents, + filename: data.filename, + options: queue.options + }); + }).catch(() => { + pluginError(queue.name); + }); + }); +} // self executing function so we can return + + +(() => { + args = args.filter(arg => { + let match; + match = arg.match(/^-I(.+)$/); + + if (match) { + options.paths.push(match[1]); + return false; + } + + match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i); + + if (match) { + arg = match[1]; + } else { + return arg; + } + + switch (arg) { + case 'v': + case 'version': + console.log(`lessc ${less.version.join('.')} (Less Compiler) [JavaScript]`); + continueProcessing = false; + break; + + case 'verbose': + verbose = true; + break; + + case 's': + case 'silent': + silent = true; + break; + + case 'l': + case 'lint': + options.lint = true; + break; + + case 'strict-imports': + options.strictImports = true; + break; + + case 'h': + case 'help': + printUsage(); + break; + + case 'x': + case 'compress': + options.compress = true; + break; + + case 'insecure': + options.insecure = true; + break; + + case 'M': + case 'depends': + options.depends = true; + break; + + case 'max-line-len': + if (checkArgFunc(arg, match[2])) { + options.maxLineLen = parseInt(match[2], 10); + + if (options.maxLineLen <= 0) { + options.maxLineLen = -1; + } } - }; - var logDependencies = function(options, result) { - if (options.depends) { - var depends = ''; - for (var i = 0; i < result.imports.length; i++) { - depends += result.imports[i] + ' '; + break; + + case 'no-color': + options.color = false; + break; + + case 'js': + options.javascriptEnabled = true; + break; + + case 'no-js': + console.error('The "--no-js" argument is deprecated, as inline JavaScript ' + 'is disabled by default. Use "--js" to enable inline JavaScript (not recommended).'); + break; + + case 'include-path': + if (checkArgFunc(arg, match[2])) { + // ; supported on windows. + // : supported on windows and linux, excluding a drive letter like C:\ so C:\file:D:\file parses to 2 + options.paths = match[2].split(os.type().match(/Windows/) ? /:(?!\\)|;/ : ':').map(p => { + if (p) { + return path.resolve(process.cwd(), p); } - console.log(depends); + }); } - }; - var parseLessFile = function (e, data) { - if (e) { - console.error('lessc: ' + e.message); - process.exitCode = 1; - return; + break; + + case 'line-numbers': + if (checkArgFunc(arg, match[2])) { + options.dumpLineNumbers = match[2]; } - data = data.replace(/^\uFEFF/, ''); + break; - options.paths = [path.dirname(input)].concat(options.paths); - options.filename = input; + case 'source-map': + options.sourceMap = true; - if (options.lint) { - options.sourceMap = false; + if (match[2]) { + sourceMapOptions.sourceMapFullFilename = match[2]; } - sourceMapOptions.sourceMapFileInline = sourceMapFileInline; - if (options.sourceMap) { - options.sourceMap = sourceMapOptions; - } + break; - less.logger.addListener({ - info: function(msg) { - if (verbose) { - console.log(msg); - } - }, - warn: function(msg) { - // do not show warning if the silent option is used - if (!silent) { - console.warn(msg); - } - }, - error: function(msg) { - console.error(msg); - } - }); + case 'source-map-rootpath': + if (checkArgFunc(arg, match[2])) { + sourceMapOptions.sourceMapRootpath = match[2]; + } - less.render(data, options) - .then(function(result) { - if (!options.lint) { - writeOutput(output, result, function() { - writeSourceMapIfNeeded(result.map, function() { - logDependencies(options, result); - }); - }); - } - }, - function(err) { - if (!options.silent) { - console.error(err.toString({ - stylize: options.color && less.lesscHelper.stylize - })); - } - process.exitCode = 1; - }); - }; + break; - if (input != '-') { - fs.readFile(input, 'utf8', parseLessFile); - } else { - process.stdin.resume(); - process.stdin.setEncoding('utf8'); + case 'source-map-basepath': + if (checkArgFunc(arg, match[2])) { + sourceMapOptions.sourceMapBasepath = match[2]; + } - var buffer = ''; - process.stdin.on('data', function(data) { - buffer += data; - }); + break; - process.stdin.on('end', function() { - parseLessFile(false, buffer); - }); - } -} + case 'source-map-inline': + case 'source-map-map-inline': + sourceMapFileInline = true; + options.sourceMap = true; + break; -function processPluginQueue() { - var x = 0; + case 'source-map-include-source': + case 'source-map-less-inline': + sourceMapOptions.outputSourceFiles = true; + break; - function pluginError(name) { - console.error('Unable to load plugin ' + name + - ' please make sure that it is installed under or at the same level as less'); - process.exitCode = 1; - } - function pluginFinished(plugin) { - x++; - plugins.push(plugin); - if (x === queuePlugins.length) { - render(); - } - } - queuePlugins.forEach(function(queue) { - var context = utils.clone(options); - pluginManager.Loader.loadPlugin(queue.name, process.cwd(), context, less.environment, fileManager) - .then(function(data) { - pluginFinished({ - fileContent: data.contents, - filename: data.filename, - options: queue.options - }); - }) - .catch(function() { - pluginError(queue.name); - }); - }); -} + case 'source-map-url': + if (checkArgFunc(arg, match[2])) { + sourceMapOptions.sourceMapURL = match[2]; + } -// self executing function so we can return -(function() { - args = args.filter(function (arg) { - var match; + break; - match = arg.match(/^-I(.+)$/); - if (match) { - options.paths.push(match[1]); - return false; + case 'rp': + case 'rootpath': + if (checkArgFunc(arg, match[2])) { + options.rootpath = match[2].replace(/\\/g, '/'); } - match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i); - if (match) { - arg = match[1]; + break; + + case 'relative-urls': + console.warn('The --relative-urls option has been deprecated. Use --rewrite-urls=all.'); + options.rewriteUrls = RewriteUrls.ALL; + break; + + case 'ru': + case 'rewrite-urls': + const m = match[2]; + + if (m) { + if (m === 'local') { + options.rewriteUrls = RewriteUrls.LOCAL; + } else if (m === 'off') { + options.rewriteUrls = RewriteUrls.OFF; + } else if (m === 'all') { + options.rewriteUrls = RewriteUrls.ALL; + } else { + console.error(`Unknown rewrite-urls argument ${m}`); + continueProcessing = false; + process.exitCode = 1; + } } else { - return arg; + options.rewriteUrls = RewriteUrls.ALL; } - switch (arg) { - case 'v': - case 'version': - console.log('lessc ' + less.version.join('.') + ' (Less Compiler) [JavaScript]'); - continueProcessing = false; - break; - case 'verbose': - verbose = true; - break; - case 's': - case 'silent': - silent = true; - break; - case 'l': - case 'lint': - options.lint = true; - break; - case 'strict-imports': - options.strictImports = true; - break; - case 'h': - case 'help': - printUsage(); - break; - case 'x': - case 'compress': - options.compress = true; - break; - case 'insecure': - options.insecure = true; - break; - case 'M': - case 'depends': - options.depends = true; - break; - case 'max-line-len': - if (checkArgFunc(arg, match[2])) { - options.maxLineLen = parseInt(match[2], 10); - if (options.maxLineLen <= 0) { - options.maxLineLen = -1; - } - } - break; - case 'no-color': - options.color = false; - break; - case 'ie-compat': - options.ieCompat = true; - break; - case 'js': - options.javascriptEnabled = true; - break; - case 'no-js': - console.error('The "--no-js" argument is deprecated, as inline JavaScript ' + - 'is disabled by default. Use "--js" to enable inline JavaScript (not recommended).'); - break; - case 'include-path': - if (checkArgFunc(arg, match[2])) { - // ; supported on windows. - // : supported on windows and linux, excluding a drive letter like C:\ so C:\file:D:\file parses to 2 - options.paths = match[2] - .split(os.type().match(/Windows/) ? /:(?!\\)|;/ : ':') - .map(function(p) { - if (p) { - return path.resolve(process.cwd(), p); - } - }); - } - break; - case 'line-numbers': - if (checkArgFunc(arg, match[2])) { - options.dumpLineNumbers = match[2]; - } - break; - case 'source-map': - options.sourceMap = true; - if (match[2]) { - sourceMapOptions.sourceMapFullFilename = match[2]; - } - break; - case 'source-map-rootpath': - if (checkArgFunc(arg, match[2])) { - sourceMapOptions.sourceMapRootpath = match[2]; - } - break; - case 'source-map-basepath': - if (checkArgFunc(arg, match[2])) { - sourceMapOptions.sourceMapBasepath = match[2]; - } - break; - case 'source-map-inline': - case 'source-map-map-inline': - sourceMapFileInline = true; - options.sourceMap = true; - break; - case 'source-map-include-source': - case 'source-map-less-inline': - sourceMapOptions.outputSourceFiles = true; - break; - case 'source-map-url': - if (checkArgFunc(arg, match[2])) { - sourceMapOptions.sourceMapURL = match[2]; - } - break; - case 'rp': - case 'rootpath': - if (checkArgFunc(arg, match[2])) { - options.rootpath = match[2].replace(/\\/g, '/'); - } - break; - case 'relative-urls': - console.warn('The --relative-urls option has been deprecated. Use --rewrite-urls=all.'); - options.rewriteUrls = Constants.RewriteUrls.ALL; - break; - case 'ru': - case 'rewrite-urls': - var m = match[2]; - if (m) { - if (m === 'local') { - options.rewriteUrls = Constants.RewriteUrls.LOCAL; - } else if (m === 'off') { - options.rewriteUrls = Constants.RewriteUrls.OFF; - } else if (m === 'all') { - options.rewriteUrls = Constants.RewriteUrls.ALL; - } else { - console.error('Unknown rewrite-urls argument ' + m); - continueProcessing = false; - process.exitCode = 1; - } - } else { - options.rewriteUrls = Constants.RewriteUrls.ALL; - } - break; - case 'sm': - case 'strict-math': - console.warn('The --strict-math option has been deprecated. Use --math=strict.'); - if (checkArgFunc(arg, match[2])) { - if (checkBooleanArg(match[2])) { - options.math = Constants.Math.STRICT_LEGACY; - } - } - break; - case 'm': - case 'math': - if (checkArgFunc(arg, match[2])) { - options.math = match[2]; - } - break; - case 'su': - case 'strict-units': - if (checkArgFunc(arg, match[2])) { - options.strictUnits = checkBooleanArg(match[2]); - } - break; - case 'global-var': - if (checkArgFunc(arg, match[2])) { - if (!options.globalVars) { - options.globalVars = {}; - } - parseVariableOption(match[2], options.globalVars); - } - break; - case 'modify-var': - if (checkArgFunc(arg, match[2])) { - if (!options.modifyVars) { - options.modifyVars = {}; - } + break; - parseVariableOption(match[2], options.modifyVars); - } - break; - case 'url-args': - if (checkArgFunc(arg, match[2])) { - options.urlArgs = match[2]; - } - break; - case 'plugin': - var splitupArg = match[2].match(/^([^=]+)(=(.*))?/), - name = splitupArg[1], - pluginOptions = splitupArg[3]; - queuePlugins.push({ name: name, options: pluginOptions }); - break; - default: - queuePlugins.push({ name: arg, options: match[2], default: true }); - break; + case 'sm': + case 'strict-math': + console.warn('The --strict-math option has been deprecated. Use --math=strict.'); + + if (checkArgFunc(arg, match[2])) { + if (checkBooleanArg(match[2])) { + options.math = Math$1.STRICT_LEGACY; + } } - }); - if (queuePlugins.length > 0) { - processPluginQueue(); - } - else { - render(); + break; + + case 'm': + case 'math': + if (checkArgFunc(arg, match[2])) { + options.math = match[2]; + } + + break; + + case 'su': + case 'strict-units': + if (checkArgFunc(arg, match[2])) { + options.strictUnits = checkBooleanArg(match[2]); + } + + break; + + case 'global-var': + if (checkArgFunc(arg, match[2])) { + if (!options.globalVars) { + options.globalVars = {}; + } + + parseVariableOption(match[2], options.globalVars); + } + + break; + + case 'modify-var': + if (checkArgFunc(arg, match[2])) { + if (!options.modifyVars) { + options.modifyVars = {}; + } + + parseVariableOption(match[2], options.modifyVars); + } + + break; + + case 'url-args': + if (checkArgFunc(arg, match[2])) { + options.urlArgs = match[2]; + } + + break; + + case 'plugin': + const splitupArg = match[2].match(/^([^=]+)(=(.*))?/); + const name = splitupArg[1]; + const pluginOptions = splitupArg[3]; + queuePlugins.push({ + name, + options: pluginOptions + }); + break; + + default: + queuePlugins.push({ + name: arg, + options: match[2], + default: true + }); + break; } + }); + if (queuePlugins.length > 0) { + processPluginQueue(); + } else { + render(); + } })(); diff --git a/browser.js b/browser.js deleted file mode 100644 index d2170641f..000000000 --- a/browser.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./lib/less-browser'); diff --git a/build/banner.js b/build/banner.js new file mode 100644 index 000000000..44074aac6 --- /dev/null +++ b/build/banner.js @@ -0,0 +1,13 @@ +const pkg = require('./../package.json'); + +module.exports = +`/** + * Less - ${ pkg.description } v${ pkg.version } + * http://lesscss.org + * + * Copyright (c) 2009-${new Date().getFullYear()}, ${ pkg.author.name } <${ pkg.author.email }> + * Licensed under the ${ pkg.license } License. + * + * @license ${ pkg.license } + */ +`; diff --git a/build/lebab-convert.js b/build/lebab-convert.js new file mode 100644 index 000000000..236ad0bd3 --- /dev/null +++ b/build/lebab-convert.js @@ -0,0 +1,35 @@ +/** @todo - REMOVE - original script to convert project to ES6 */ + +const transform = require("lebab").transform; +const readGlob = require("read-glob"); +const fs = require("fs"); +const path = require("path"); + +readGlob("./../bin/lessc").subscribe({ + next(result) { + if (result.path.indexOf("source-map/") === -1) { + try { + const { code, warnings } = transform( + result.contents.toString(), + [ + "arrow", + "arrow-return", + "arg-rest", + "arg-spread", + "obj-shorthand", + "multi-var", + "let", + "class", + "commonjs", + "template", + "default-param" + ] + ); + + fs.writeFileSync(path.join(result.cwd, result.path), code); + } catch (e) { + console.error(e); + } + } + } +}); diff --git a/build/rollup.js b/build/rollup.js new file mode 100644 index 000000000..1a3956dbe --- /dev/null +++ b/build/rollup.js @@ -0,0 +1,152 @@ +const rollup = require('rollup'); +const babel = require('rollup-plugin-babel'); +const resolve = require('rollup-plugin-node-resolve'); +const commonjs = require('rollup-plugin-commonjs'); +const terser = require('rollup-plugin-terser').terser; +const banner = require('./banner'); +const path = require('path'); + +const rootPath = path.join(__dirname, '..'); + +const args = require('minimist')(process.argv.slice(2)); + +let outDir = args.dist ? './dist' : './tmp'; + +async function buildBrowser() { + let bundle = await rollup.rollup({ + input: './lib/less-browser/bootstrap.js', + output: [ + { + file: 'less.js', + format: 'umd' + }, + { + file: 'less.min.js', + format: 'umd' + } + ], + plugins: [ + resolve(), + commonjs(), + babel({ + exclude: 'node_modules/**', // only transpile our source code + presets: [["@babel/env", { + targets: '> 0.25%, not dead' + }]] + }), + terser({ + include: [/^.+\.min\.js$/], + output: { + comments: function(node, comment) { + if (comment.type == "comment2") { + // preserve banner + return /@license/i.test(comment.value); + } + } + } + }) + ] + }); + + if (!args.out || args.out.indexOf('less.js') > -1) { + const file = args.out || `${outDir}/less.js`; + console.log(`Writing ${file}...`); + await bundle.write({ + file: path.join(rootPath, file), + format: 'umd', + name: 'less', + banner + }); + } + + if (!args.out || args.out.indexOf('less.min.js') > -1) { + const file = args.out || `${outDir}/less.min.js`; + console.log(`Writing ${file}...`); + await bundle.write({ + file: path.join(rootPath, file), + format: 'umd', + name: 'less', + sourcemap: true, + banner + }); + } +} + +async function buildNode() { + let bundle = await rollup.rollup({ + input: './lib/less-node/index.js', + external(id) { + return /^[^.]/.test(id) + }, + plugins: [ + resolve(), + commonjs(), + babel({ + exclude: 'node_modules/**', // only transpile our source code + presets: [["@babel/env", { + targets: { + node: '6' + } + }]] + }) + ] + }); + + const file = args.out || './dist/less.cjs.js'; + console.log(`Writing ${file}...`); + + await bundle.write({ + file: path.join(rootPath, file), + format: 'cjs', + interop: false + }); +} + +async function buildLessC() { + let bundle = await rollup.rollup({ + input: './lib/lessc.js', + external(id) { + return /^[^.]/.test(id) + }, + plugins: [ + resolve(), + commonjs(), + babel({ + exclude: 'node_modules/**', // only transpile our source code + presets: [["@babel/env", { + targets: { + node: '6' + } + }]] + }) + ] + }); + + const file = args.out || './bin/lessc'; + console.log(`Writing ${file}...`); + + await bundle.write({ + file: path.join(rootPath, file), + banner: '#!/usr/bin/env node\n', + format: 'cjs', + interop: false + }); +} + +async function build() { + if (args.dist || args.lessc) { + await buildLessC(); + } + if (args.dist || args.browser) { + await buildBrowser(); + } + if (args.dist || args.node) { + await buildNode(); + } +} +try { + build(); +} +catch (e) { + throw e; +} \ No newline at end of file diff --git a/dist/less.cjs.js b/dist/less.cjs.js new file mode 100644 index 000000000..41b017427 --- /dev/null +++ b/dist/less.cjs.js @@ -0,0 +1,12571 @@ +'use strict'; + +var path = require('path'); +var url = require('url'); +var CloneHelper = require('clone'); + +var environment = { + encodeBase64: function encodeBase64(str) { + // Avoid Buffer constructor on newer versions of Node.js. + const buffer = Buffer.from ? Buffer.from(str) : new Buffer(str); + return buffer.toString('base64'); + }, + mimeLookup: function mimeLookup(filename) { + return require('mime').lookup(filename); + }, + charsetLookup: function charsetLookup(mime) { + return require('mime').charsets.lookup(mime); + }, + getSourceMapGenerator: function getSourceMapGenerator() { + return require('source-map').SourceMapGenerator; + } +}; + +let fs; + +try { + fs = require('graceful-fs'); +} catch (e) { + fs = require('fs'); +} + +var fs$1 = fs; + +class AbstractFileManager { + getPath(filename) { + let j = filename.lastIndexOf('?'); + + if (j > 0) { + filename = filename.slice(0, j); + } + + j = filename.lastIndexOf('/'); + + if (j < 0) { + j = filename.lastIndexOf('\\'); + } + + if (j < 0) { + return ''; + } + + return filename.slice(0, j + 1); + } + + tryAppendExtension(path, ext) { + return /(\.[a-z]*$)|([\?;].*)$/.test(path) ? path : path + ext; + } + + tryAppendLessExtension(path) { + return this.tryAppendExtension(path, '.less'); + } + + supportsSync() { + return false; + } + + alwaysMakePathsAbsolute() { + return false; + } + + isPathAbsolute(filename) { + return /^(?:[a-z-]+:|\/|\\|#)/i.test(filename); + } // TODO: pull out / replace? + + + join(basePath, laterPath) { + if (!basePath) { + return laterPath; + } + + return basePath + laterPath; + } + + pathDiff(url, baseUrl) { + // diff between two paths to create a relative path + const urlParts = this.extractUrlParts(url); + const baseUrlParts = this.extractUrlParts(baseUrl); + let i; + let max; + let urlDirectories; + let baseUrlDirectories; + let 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(url, baseUrl) { + // urlParts[1] = protocol://hostname/ OR / + // urlParts[2] = / if path relative to host base + // urlParts[3] = directories + // urlParts[4] = filename + // urlParts[5] = parameters + const urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i; + const urlParts = url.match(urlPartsRegex); + const returner = {}; + let rawDirectories = []; + const directories = []; + let i; + let 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]) { + rawDirectories = urlParts[3].replace(/\\/g, '/').split('/'); // collapse '..' and skip '.' + + for (i = 0; i < rawDirectories.length; i++) { + if (rawDirectories[i] === '..') { + directories.pop(); + } else if (rawDirectories[i] !== '.') { + directories.push(rawDirectories[i]); + } + } + } + + returner.hostPart = urlParts[1]; + returner.directories = directories; + returner.rawPath = (urlParts[1] || '') + rawDirectories.join('/'); + returner.path = (urlParts[1] || '') + directories.join('/'); + returner.filename = urlParts[4]; + returner.fileUrl = returner.path + (urlParts[4] || ''); + returner.url = returner.fileUrl + (urlParts[5] || ''); + return returner; + } + +} + +class FileManager extends AbstractFileManager { + constructor() { + super(); + this.contents = {}; + } + + supports(filename, currentDirectory, options, environment) { + return true; + } + + supportsSync(filename, currentDirectory, options, environment) { + return true; + } + + loadFile(filename, currentDirectory, options, environment, callback) { + let fullFilename; + const isAbsoluteFilename = this.isPathAbsolute(filename); + const filenamesTried = []; + const self = this; + const prefix = filename.slice(0, 1); + const explicit = prefix === '.' || prefix === '/'; + let result = null; + let isNodeModule = false; + const npmPrefix = 'npm://'; + options = options || {}; + const paths = isAbsoluteFilename ? [''] : [currentDirectory]; + + if (options.paths) { + paths.push(...options.paths); + } + + if (!isAbsoluteFilename && paths.indexOf('.') === -1) { + paths.push('.'); + } + + const prefixes = options.prefixes || ['']; + const fileParts = this.extractUrlParts(filename); + + if (options.syncImport) { + getFileData(returnData, returnData); + + if (callback) { + callback(result.error, result); + } else { + return result; + } + } else { + // promise is guaranteed to be asyncronous + // which helps as it allows the file handle + // to be closed before it continues with the next file + return new Promise(getFileData); + } + + function returnData(data) { + if (!data.filename) { + result = { + error: data + }; + } else { + result = data; + } + } + + function getFileData(fulfill, reject) { + (function tryPathIndex(i) { + if (i < paths.length) { + (function tryPrefix(j) { + if (j < prefixes.length) { + isNodeModule = false; + fullFilename = fileParts.rawPath + prefixes[j] + fileParts.filename; + + if (paths[i]) { + fullFilename = path.join(paths[i], fullFilename); + } + + if (!explicit && paths[i] === '.') { + try { + fullFilename = require.resolve(fullFilename); + isNodeModule = true; + } catch (e) { + filenamesTried.push(npmPrefix + fullFilename); + tryWithExtension(); + } + } else { + tryWithExtension(); + } + + function tryWithExtension() { + const extFilename = options.ext ? self.tryAppendExtension(fullFilename, options.ext) : fullFilename; + + if (extFilename !== fullFilename && !explicit && paths[i] === '.') { + try { + fullFilename = require.resolve(extFilename); + isNodeModule = true; + } catch (e) { + filenamesTried.push(npmPrefix + extFilename); + fullFilename = extFilename; + } + } else { + fullFilename = extFilename; + } + } + + let modified = false; + + if (self.contents[fullFilename]) { + try { + var stat = fs$1.statSync.apply(this, [fullFilename]); + + if (stat.mtime.getTime() === self.contents[fullFilename].mtime.getTime()) { + fulfill({ + contents: self.contents[fullFilename].data, + filename: fullFilename + }); + } else { + modified = true; + } + } catch (e) { + modified = true; + } + } + + if (modified || !self.contents[fullFilename]) { + const readFileArgs = [fullFilename]; + + if (!options.rawBuffer) { + readFileArgs.push('utf-8'); + } + + if (options.syncImport) { + try { + const data = fs$1.readFileSync.apply(this, readFileArgs); + var stat = fs$1.statSync.apply(this, [fullFilename]); + self.contents[fullFilename] = { + data, + mtime: stat.mtime + }; + fulfill({ + contents: data, + filename: fullFilename + }); + } catch (e) { + filenamesTried.push(isNodeModule ? npmPrefix + fullFilename : fullFilename); + return tryPrefix(j + 1); + } + } else { + readFileArgs.push(function (e, data) { + if (e) { + filenamesTried.push(isNodeModule ? npmPrefix + fullFilename : fullFilename); + return tryPrefix(j + 1); + } + + const stat = fs$1.statSync.apply(this, [fullFilename]); + self.contents[fullFilename] = { + data, + mtime: stat.mtime + }; + fulfill({ + contents: data, + filename: fullFilename + }); + }); + fs$1.readFile.apply(this, readFileArgs); + } + } + } else { + tryPathIndex(i + 1); + } + })(0); + } else { + reject({ + type: 'File', + message: `'${filename}' wasn't found. Tried - ${filenamesTried.join(',')}` + }); + } + })(0); + } + } + + loadFileSync(filename, currentDirectory, options, environment) { + options.syncImport = true; + return this.loadFile(filename, currentDirectory, options, environment); + } + +} + +var logger = { + error: function error(msg) { + this._fireEvent('error', msg); + }, + warn: function warn(msg) { + this._fireEvent('warn', msg); + }, + info: function info(msg) { + this._fireEvent('info', msg); + }, + debug: function debug(msg) { + this._fireEvent('debug', msg); + }, + addListener: function addListener(listener) { + this._listeners.push(listener); + }, + removeListener: function removeListener(listener) { + for (let i = 0; i < this._listeners.length; i++) { + if (this._listeners[i] === listener) { + this._listeners.splice(i, 1); + + return; + } + } + }, + _fireEvent: function _fireEvent(type, msg) { + for (let i = 0; i < this._listeners.length; i++) { + const logFunction = this._listeners[i][type]; + + if (logFunction) { + logFunction(msg); + } + } + }, + _listeners: [] +}; + +const isUrlRe = /^(?:https?:)?\/\//i; +let request; + +class UrlFileManager extends AbstractFileManager { + supports(filename, currentDirectory, options, environment) { + return isUrlRe.test(filename) || isUrlRe.test(currentDirectory); + } + + loadFile(filename, currentDirectory, options, environment) { + return new Promise((fulfill, reject) => { + if (request === undefined) { + try { + request = require('request'); + } catch (e) { + request = null; + } + } + + if (!request) { + reject({ + type: 'File', + message: 'optional dependency \'request\' required to import over http(s)\n' + }); + return; + } + + let urlStr = isUrlRe.test(filename) ? filename : url.resolve(currentDirectory, filename); + const urlObj = url.parse(urlStr); + + if (!urlObj.protocol) { + urlObj.protocol = 'http'; + urlStr = urlObj.format(); + } + + request.get({ + uri: urlStr, + strictSSL: !options.insecure + }, (error, res, body) => { + if (error) { + reject({ + type: 'File', + message: `resource '${urlStr}' gave this Error:\n ${error}\n` + }); + return; + } + + if (res && res.statusCode === 404) { + reject({ + type: 'File', + message: `resource '${urlStr}' was not found\n` + }); + return; + } + + if (!body) { + logger.warn(`Warning: Empty body (HTTP ${res.statusCode}) returned by "${urlStr}"`); + } + + fulfill({ + contents: body, + filename: urlStr + }); + }); + }); + } + +} + +var colors = { + 'aliceblue': '#f0f8ff', + 'antiquewhite': '#faebd7', + 'aqua': '#00ffff', + 'aquamarine': '#7fffd4', + 'azure': '#f0ffff', + 'beige': '#f5f5dc', + 'bisque': '#ffe4c4', + 'black': '#000000', + 'blanchedalmond': '#ffebcd', + 'blue': '#0000ff', + 'blueviolet': '#8a2be2', + 'brown': '#a52a2a', + 'burlywood': '#deb887', + 'cadetblue': '#5f9ea0', + 'chartreuse': '#7fff00', + 'chocolate': '#d2691e', + 'coral': '#ff7f50', + 'cornflowerblue': '#6495ed', + 'cornsilk': '#fff8dc', + 'crimson': '#dc143c', + 'cyan': '#00ffff', + 'darkblue': '#00008b', + 'darkcyan': '#008b8b', + 'darkgoldenrod': '#b8860b', + 'darkgray': '#a9a9a9', + 'darkgrey': '#a9a9a9', + 'darkgreen': '#006400', + 'darkkhaki': '#bdb76b', + 'darkmagenta': '#8b008b', + 'darkolivegreen': '#556b2f', + 'darkorange': '#ff8c00', + 'darkorchid': '#9932cc', + 'darkred': '#8b0000', + 'darksalmon': '#e9967a', + 'darkseagreen': '#8fbc8f', + 'darkslateblue': '#483d8b', + 'darkslategray': '#2f4f4f', + 'darkslategrey': '#2f4f4f', + 'darkturquoise': '#00ced1', + 'darkviolet': '#9400d3', + 'deeppink': '#ff1493', + 'deepskyblue': '#00bfff', + 'dimgray': '#696969', + 'dimgrey': '#696969', + 'dodgerblue': '#1e90ff', + 'firebrick': '#b22222', + 'floralwhite': '#fffaf0', + 'forestgreen': '#228b22', + 'fuchsia': '#ff00ff', + 'gainsboro': '#dcdcdc', + 'ghostwhite': '#f8f8ff', + 'gold': '#ffd700', + 'goldenrod': '#daa520', + 'gray': '#808080', + 'grey': '#808080', + 'green': '#008000', + 'greenyellow': '#adff2f', + 'honeydew': '#f0fff0', + 'hotpink': '#ff69b4', + 'indianred': '#cd5c5c', + 'indigo': '#4b0082', + 'ivory': '#fffff0', + 'khaki': '#f0e68c', + 'lavender': '#e6e6fa', + 'lavenderblush': '#fff0f5', + 'lawngreen': '#7cfc00', + 'lemonchiffon': '#fffacd', + 'lightblue': '#add8e6', + 'lightcoral': '#f08080', + 'lightcyan': '#e0ffff', + 'lightgoldenrodyellow': '#fafad2', + 'lightgray': '#d3d3d3', + 'lightgrey': '#d3d3d3', + 'lightgreen': '#90ee90', + 'lightpink': '#ffb6c1', + 'lightsalmon': '#ffa07a', + 'lightseagreen': '#20b2aa', + 'lightskyblue': '#87cefa', + 'lightslategray': '#778899', + 'lightslategrey': '#778899', + 'lightsteelblue': '#b0c4de', + 'lightyellow': '#ffffe0', + 'lime': '#00ff00', + 'limegreen': '#32cd32', + 'linen': '#faf0e6', + 'magenta': '#ff00ff', + 'maroon': '#800000', + 'mediumaquamarine': '#66cdaa', + 'mediumblue': '#0000cd', + 'mediumorchid': '#ba55d3', + 'mediumpurple': '#9370d8', + 'mediumseagreen': '#3cb371', + 'mediumslateblue': '#7b68ee', + 'mediumspringgreen': '#00fa9a', + 'mediumturquoise': '#48d1cc', + 'mediumvioletred': '#c71585', + 'midnightblue': '#191970', + 'mintcream': '#f5fffa', + 'mistyrose': '#ffe4e1', + 'moccasin': '#ffe4b5', + 'navajowhite': '#ffdead', + 'navy': '#000080', + 'oldlace': '#fdf5e6', + 'olive': '#808000', + 'olivedrab': '#6b8e23', + 'orange': '#ffa500', + 'orangered': '#ff4500', + 'orchid': '#da70d6', + 'palegoldenrod': '#eee8aa', + 'palegreen': '#98fb98', + 'paleturquoise': '#afeeee', + 'palevioletred': '#d87093', + 'papayawhip': '#ffefd5', + 'peachpuff': '#ffdab9', + 'peru': '#cd853f', + 'pink': '#ffc0cb', + 'plum': '#dda0dd', + 'powderblue': '#b0e0e6', + 'purple': '#800080', + 'rebeccapurple': '#663399', + 'red': '#ff0000', + 'rosybrown': '#bc8f8f', + 'royalblue': '#4169e1', + 'saddlebrown': '#8b4513', + 'salmon': '#fa8072', + 'sandybrown': '#f4a460', + 'seagreen': '#2e8b57', + 'seashell': '#fff5ee', + 'sienna': '#a0522d', + 'silver': '#c0c0c0', + 'skyblue': '#87ceeb', + 'slateblue': '#6a5acd', + 'slategray': '#708090', + 'slategrey': '#708090', + 'snow': '#fffafa', + 'springgreen': '#00ff7f', + 'steelblue': '#4682b4', + 'tan': '#d2b48c', + 'teal': '#008080', + 'thistle': '#d8bfd8', + 'tomato': '#ff6347', + 'turquoise': '#40e0d0', + 'violet': '#ee82ee', + 'wheat': '#f5deb3', + 'white': '#ffffff', + 'whitesmoke': '#f5f5f5', + 'yellow': '#ffff00', + 'yellowgreen': '#9acd32' +}; + +var unitConversions = { + length: { + 'm': 1, + 'cm': 0.01, + 'mm': 0.001, + 'in': 0.0254, + 'px': 0.0254 / 96, + 'pt': 0.0254 / 72, + 'pc': 0.0254 / 72 * 12 + }, + duration: { + 's': 1, + 'ms': 0.001 + }, + angle: { + 'rad': 1 / (2 * Math.PI), + 'deg': 1 / 360, + 'grad': 1 / 400, + 'turn': 1 + } +}; + +var data = { + colors, + unitConversions +}; + +class Node { + constructor() { + this.parent = null; + this.visibilityBlocks = undefined; + this.nodeVisible = undefined; + this.rootNode = null; + this.parsed = null; + const self = this; + Object.defineProperty(this, 'currentFileInfo', { + get: function get() { + return self.fileInfo(); + } + }); + Object.defineProperty(this, 'index', { + get: function get() { + return self.getIndex(); + } + }); + } + + setParent(nodes, parent) { + function set(node) { + if (node && node instanceof Node) { + node.parent = parent; + } + } + + if (Array.isArray(nodes)) { + nodes.forEach(set); + } else { + set(nodes); + } + } + + getIndex() { + return this._index || this.parent && this.parent.getIndex() || 0; + } + + fileInfo() { + return this._fileInfo || this.parent && this.parent.fileInfo() || {}; + } + + isRulesetLike() { + return false; + } + + toCSS(context) { + const strs = []; + this.genCSS(context, { + add: function add(chunk, fileInfo, index) { + strs.push(chunk); + }, + isEmpty: function isEmpty() { + return strs.length === 0; + } + }); + return strs.join(''); + } + + genCSS(context, output) { + output.add(this.value); + } + + accept(visitor) { + this.value = visitor.visit(this.value); + } + + eval() { + return this; + } + + _operate(context, op, a, b) { + switch (op) { + case '+': + return a + b; + + case '-': + return a - b; + + case '*': + return a * b; + + case '/': + return a / b; + } + } + + fround(context, value) { + const precision = context && context.numPrecision; // add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999...) are properly rounded: + + return precision ? Number((value + 2e-16).toFixed(precision)) : value; + } // Returns true if this node represents root of ast imported by reference + + + blocksVisibility() { + if (this.visibilityBlocks == null) { + this.visibilityBlocks = 0; + } + + return this.visibilityBlocks !== 0; + } + + addVisibilityBlock() { + if (this.visibilityBlocks == null) { + this.visibilityBlocks = 0; + } + + this.visibilityBlocks = this.visibilityBlocks + 1; + } + + removeVisibilityBlock() { + if (this.visibilityBlocks == null) { + this.visibilityBlocks = 0; + } + + this.visibilityBlocks = this.visibilityBlocks - 1; + } // Turns on node visibility - if called node will be shown in output regardless + // of whether it comes from import by reference or not + + + ensureVisibility() { + this.nodeVisible = true; + } // Turns off node visibility - if called node will NOT be shown in output regardless + // of whether it comes from import by reference or not + + + ensureInvisibility() { + this.nodeVisible = false; + } // return values: + // false - the node must not be visible + // true - the node must be visible + // undefined or null - the node has the same visibility as its parent + + + isVisible() { + return this.nodeVisible; + } + + visibilityInfo() { + return { + visibilityBlocks: this.visibilityBlocks, + nodeVisible: this.nodeVisible + }; + } + + copyVisibilityInfo(info) { + if (!info) { + return; + } + + this.visibilityBlocks = info.visibilityBlocks; + this.nodeVisible = info.nodeVisible; + } + +} + +Node.compare = (a, b) => { + /* returns: + -1: a < b + 0: a = b + 1: a > b + and *any* other value for a != b (e.g. undefined, NaN, -2 etc.) */ + if (a.compare && // for "symmetric results" force toCSS-based comparison + // of Quoted or Anonymous if either value is one of those + !(b.type === 'Quoted' || b.type === 'Anonymous')) { + return a.compare(b); + } else if (b.compare) { + return -b.compare(a); + } else if (a.type !== b.type) { + return undefined; + } + + a = a.value; + b = b.value; + + if (!Array.isArray(a)) { + return a === b ? 0 : undefined; + } + + if (a.length !== b.length) { + return undefined; + } + + for (let i = 0; i < a.length; i++) { + if (Node.compare(a[i], b[i]) !== 0) { + return undefined; + } + } + + return 0; +}; + +Node.numericCompare = (a, b) => a < b ? -1 : a === b ? 0 : a > b ? 1 : undefined; + +// RGB Colors - #ff0014, #eee +// + +class Color extends Node { + constructor(rgb, a, originalForm) { + super(); + const self = this; // + // The end goal here, is to parse the arguments + // into an integer triplet, such as `128, 255, 0` + // + // This facilitates operations and conversions. + // + + if (Array.isArray(rgb)) { + this.rgb = rgb; + } else if (rgb.length >= 6) { + this.rgb = []; + rgb.match(/.{2}/g).map((c, i) => { + if (i < 3) { + self.rgb.push(parseInt(c, 16)); + } else { + self.alpha = parseInt(c, 16) / 255; + } + }); + } else { + this.rgb = []; + rgb.split('').map((c, i) => { + if (i < 3) { + self.rgb.push(parseInt(c + c, 16)); + } else { + self.alpha = parseInt(c + c, 16) / 255; + } + }); + } + + this.alpha = this.alpha || (typeof a === 'number' ? a : 1); + + if (typeof originalForm !== 'undefined') { + this.value = originalForm; + } + } + + luma() { + let r = this.rgb[0] / 255; + let g = this.rgb[1] / 255; + let b = this.rgb[2] / 255; + r = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4); + g = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4); + b = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4); + return 0.2126 * r + 0.7152 * g + 0.0722 * b; + } + + genCSS(context, output) { + output.add(this.toCSS(context)); + } + + toCSS(context, doNotCompress) { + const compress = context && context.compress && !doNotCompress; + let color; + let alpha; + let colorFunction; + let args = []; // `value` is set if this color was originally + // converted from a named color string so we need + // to respect this and try to output named color too. + + alpha = this.fround(context, this.alpha); + + if (this.value) { + if (this.value.indexOf('rgb') === 0) { + if (alpha < 1) { + colorFunction = 'rgba'; + } + } else if (this.value.indexOf('hsl') === 0) { + if (alpha < 1) { + colorFunction = 'hsla'; + } else { + colorFunction = 'hsl'; + } + } else { + return this.value; + } + } else { + if (alpha < 1) { + colorFunction = 'rgba'; + } + } + + switch (colorFunction) { + case 'rgba': + args = this.rgb.map(c => clamp(Math.round(c), 255)).concat(clamp(alpha, 1)); + break; + + case 'hsla': + args.push(clamp(alpha, 1)); + + case 'hsl': + color = this.toHSL(); + args = [this.fround(context, color.h), `${this.fround(context, color.s * 100)}%`, `${this.fround(context, color.l * 100)}%`].concat(args); + } + + if (colorFunction) { + // Values are capped between `0` and `255`, rounded and zero-padded. + return `${colorFunction}(${args.join(`,${compress ? '' : ' '}`)})`; + } + + color = this.toRGB(); + + if (compress) { + const splitcolor = color.split(''); // Convert color to short format + + if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) { + color = `#${splitcolor[1]}${splitcolor[3]}${splitcolor[5]}`; + } + } + + return color; + } // + // Operations have to be done per-channel, if not, + // channels will spill onto each other. Once we have + // our result, in the form of an integer triplet, + // we create a new Color node to hold the result. + // + + + operate(context, op, other) { + const rgb = new Array(3); + const alpha = this.alpha * (1 - other.alpha) + other.alpha; + + for (let c = 0; c < 3; c++) { + rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]); + } + + return new Color(rgb, alpha); + } + + toRGB() { + return toHex(this.rgb); + } + + toHSL() { + const r = this.rgb[0] / 255; + const g = this.rgb[1] / 255; + const b = this.rgb[2] / 255; + const a = this.alpha; + const max = Math.max(r, g, b); + const min = Math.min(r, g, b); + let h; + let s; + const l = (max + min) / 2; + const d = max - min; + + if (max === min) { + h = s = 0; + } else { + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + + case g: + h = (b - r) / d + 2; + break; + + case b: + h = (r - g) / d + 4; + break; + } + + h /= 6; + } + + return { + h: h * 360, + s, + l, + a + }; + } // Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript + + + toHSV() { + const r = this.rgb[0] / 255; + const g = this.rgb[1] / 255; + const b = this.rgb[2] / 255; + const a = this.alpha; + const max = Math.max(r, g, b); + const min = Math.min(r, g, b); + let h; + let s; + const v = max; + const d = max - min; + + if (max === 0) { + s = 0; + } else { + s = d / max; + } + + if (max === min) { + h = 0; + } else { + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + + case g: + h = (b - r) / d + 2; + break; + + case b: + h = (r - g) / d + 4; + break; + } + + h /= 6; + } + + return { + h: h * 360, + s, + v, + a + }; + } + + toARGB() { + return toHex([this.alpha * 255].concat(this.rgb)); + } + + compare(x) { + return x.rgb && x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha ? 0 : undefined; + } + +} + +Color.prototype.type = 'Color'; + +function clamp(v, max) { + return Math.min(Math.max(v, 0), max); +} + +function toHex(v) { + return `#${v.map(c => { + c = clamp(Math.round(c), 255); + return (c < 16 ? '0' : '') + c.toString(16); + }).join('')}`; +} + +Color.fromKeyword = keyword => { + let c; + const key = keyword.toLowerCase(); + + if (colors.hasOwnProperty(key)) { + c = new Color(colors[key].slice(1)); + } else if (key === 'transparent') { + c = new Color([0, 0, 0], 0); + } + + if (c) { + c.value = keyword; + return c; + } +}; + +class Paren extends Node { + constructor(node) { + super(); + this.value = node; + } + + genCSS(context, output) { + output.add('('); + this.value.genCSS(context, output); + output.add(')'); + } + + eval(context) { + return new Paren(this.value.eval(context)); + } + +} + +Paren.prototype.type = 'Paren'; + +const _noSpaceCombinators = { + '': true, + ' ': true, + '|': true +}; + +class Combinator extends Node { + constructor(value) { + super(); + + if (value === ' ') { + this.value = ' '; + this.emptyOrWhitespace = true; + } else { + this.value = value ? value.trim() : ''; + this.emptyOrWhitespace = this.value === ''; + } + } + + genCSS(context, output) { + const spaceOrEmpty = context.compress || _noSpaceCombinators[this.value] ? '' : ' '; + output.add(spaceOrEmpty + this.value + spaceOrEmpty); + } + +} + +Combinator.prototype.type = 'Combinator'; + +class Element extends Node { + constructor(combinator, value, isVariable, index, currentFileInfo, visibilityInfo) { + super(); + this.combinator = combinator instanceof Combinator ? combinator : new Combinator(combinator); + + if (typeof value === 'string') { + this.value = value.trim(); + } else if (value) { + this.value = value; + } else { + this.value = ''; + } + + this.isVariable = isVariable; + this._index = index; + this._fileInfo = currentFileInfo; + this.copyVisibilityInfo(visibilityInfo); + this.setParent(this.combinator, this); + } + + accept(visitor) { + const value = this.value; + this.combinator = visitor.visit(this.combinator); + + if (typeof value === 'object') { + this.value = visitor.visit(value); + } + } + + eval(context) { + return new Element(this.combinator, this.value.eval ? this.value.eval(context) : this.value, this.isVariable, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } + + clone() { + return new Element(this.combinator, this.value, this.isVariable, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } + + genCSS(context, output) { + output.add(this.toCSS(context), this.fileInfo(), this.getIndex()); + } + + toCSS(context = {}) { + let value = this.value; + const firstSelector = context.firstSelector; + + if (value instanceof Paren) { + // selector in parens should not be affected by outer selector + // flags (breaks only interpolated selectors - see #1973) + context.firstSelector = true; + } + + value = value.toCSS ? value.toCSS(context) : value; + context.firstSelector = firstSelector; + + if (value === '' && this.combinator.value.charAt(0) === '&') { + return ''; + } else { + return this.combinator.toCSS(context) + value; + } + } + +} + +Element.prototype.type = 'Element'; + +const Math$1 = { + ALWAYS: 0, + PARENS_DIVISION: 1, + PARENS: 2, + STRICT_LEGACY: 3 +}; +const RewriteUrls = { + OFF: 0, + LOCAL: 1, + ALL: 2 +}; + +/* jshint proto: true */ +function getLocation(index, inputStream) { + let n = index + 1; + let line = null; + let column = -1; + + while (--n >= 0 && inputStream.charAt(n) !== '\n') { + column++; + } + + if (typeof index === 'number') { + line = (inputStream.slice(0, index).match(/\n/g) || '').length; + } + + return { + line, + column + }; +} +function copyArray(arr) { + let i; + const length = arr.length; + const copy = new Array(length); + + for (i = 0; i < length; i++) { + copy[i] = arr[i]; + } + + return copy; +} +function clone(obj) { + const cloned = {}; + + for (const prop in obj) { + if (obj.hasOwnProperty(prop)) { + cloned[prop] = obj[prop]; + } + } + + return cloned; +} +function defaults(obj1, obj2) { + let newObj = obj2 || {}; + + if (!obj2._defaults) { + newObj = {}; + const defaults = CloneHelper(obj1); + newObj._defaults = defaults; + const cloned = obj2 ? CloneHelper(obj2) : {}; + Object.assign(newObj, defaults, cloned); + } + + return newObj; +} +function copyOptions(obj1, obj2) { + if (obj2 && obj2._defaults) { + return obj2; + } + + const opts = defaults(obj1, obj2); + + if (opts.strictMath) { + opts.math = Math$1.STRICT_LEGACY; + } // Back compat with changed relativeUrls option + + + if (opts.relativeUrls) { + opts.rewriteUrls = RewriteUrls.ALL; + } + + if (typeof opts.math === 'string') { + switch (opts.math.toLowerCase()) { + case 'always': + opts.math = Math$1.ALWAYS; + break; + + case 'parens-division': + opts.math = Math$1.PARENS_DIVISION; + break; + + case 'strict': + case 'parens': + opts.math = Math$1.PARENS; + break; + + case 'strict-legacy': + opts.math = Math$1.STRICT_LEGACY; + } + } + + if (typeof opts.rewriteUrls === 'string') { + switch (opts.rewriteUrls.toLowerCase()) { + case 'off': + opts.rewriteUrls = RewriteUrls.OFF; + break; + + case 'local': + opts.rewriteUrls = RewriteUrls.LOCAL; + break; + + case 'all': + opts.rewriteUrls = RewriteUrls.ALL; + break; + } + } + + return opts; +} +function merge(obj1, obj2) { + for (const prop in obj2) { + if (obj2.hasOwnProperty(prop)) { + obj1[prop] = obj2[prop]; + } + } + + return obj1; +} +function flattenArray(arr, result = []) { + for (let i = 0, length = arr.length; i < length; i++) { + const value = arr[i]; + + if (Array.isArray(value)) { + flattenArray(value, result); + } else { + if (value !== undefined) { + result.push(value); + } + } + } + + return result; +} + +var utils = /*#__PURE__*/Object.freeze({ + getLocation: getLocation, + copyArray: copyArray, + clone: clone, + defaults: defaults, + copyOptions: copyOptions, + merge: merge, + flattenArray: flattenArray +}); + +/** + * This is a centralized class of any error that could be thrown internally (mostly by the parser). + * Besides standard .message it keeps some additional data like a path to the file where the error + * occurred along with line and column numbers. + * + * @class + * @extends Error + * @type {module.LessError} + * + * @prop {string} type + * @prop {string} filename + * @prop {number} index + * @prop {number} line + * @prop {number} column + * @prop {number} callLine + * @prop {number} callExtract + * @prop {string[]} extract + * + * @param {Object} e - An error object to wrap around or just a descriptive object + * @param {Object} fileContentMap - An object with file contents in 'contents' property (like importManager) @todo - move to fileManager? + * @param {string} [currentFilename] + */ + +const LessError = function LessError(e, fileContentMap, currentFilename) { + Error.call(this); + const filename = e.filename || currentFilename; + this.message = e.message; + this.stack = e.stack; + + if (fileContentMap && filename) { + const input = fileContentMap.contents[filename]; + const loc = getLocation(e.index, input); + const line = loc.line; + const col = loc.column; + const callLine = e.call && getLocation(e.call, input).line; + const lines = input ? input.split('\n') : ''; + this.type = e.type || 'Syntax'; + this.filename = filename; + this.index = e.index; + this.line = typeof line === 'number' ? line + 1 : null; + this.column = col; + + if (!this.line && this.stack) { + const found = this.stack.match(/(|Function):(\d+):(\d+)/); + + if (found) { + if (found[2]) { + this.line = parseInt(found[2]) - 2; + } + + if (found[3]) { + this.column = parseInt(found[3]); + } + } + } + + this.callLine = callLine + 1; + this.callExtract = lines[callLine]; + this.extract = [lines[this.line - 2], lines[this.line - 1], lines[this.line]]; + } +}; + +if (typeof Object.create === 'undefined') { + const F = () => {}; + + F.prototype = Error.prototype; + LessError.prototype = new F(); +} else { + LessError.prototype = Object.create(Error.prototype); +} + +LessError.prototype.constructor = LessError; +/** + * An overridden version of the default Object.prototype.toString + * which uses additional information to create a helpful message. + * + * @param {Object} options + * @returns {string} + */ + +LessError.prototype.toString = function (options = {}) { + let message = ''; + const extract = this.extract || []; + let error = []; + + let stylize = str => str; + + if (options.stylize) { + const type = typeof options.stylize; + + if (type !== 'function') { + throw Error(`options.stylize should be a function, got a ${type}!`); + } + + stylize = options.stylize; + } + + if (this.line !== null) { + if (typeof extract[0] === 'string') { + error.push(stylize(`${this.line - 1} ${extract[0]}`, 'grey')); + } + + if (typeof extract[1] === 'string') { + let errorTxt = `${this.line} `; + + if (extract[1]) { + errorTxt += extract[1].slice(0, this.column) + stylize(stylize(stylize(extract[1].substr(this.column, 1), 'bold') + extract[1].slice(this.column + 1), 'red'), 'inverse'); + } + + error.push(errorTxt); + } + + if (typeof extract[2] === 'string') { + error.push(stylize(`${this.line + 1} ${extract[2]}`, 'grey')); + } + + error = `${error.join('\n') + stylize('', 'reset')}\n`; + } + + message += stylize(`${this.type}Error: ${this.message}`, 'red'); + + if (this.filename) { + message += stylize(' in ', 'red') + this.filename; + } + + if (this.line) { + message += stylize(` on line ${this.line}, column ${this.column + 1}:`, 'grey'); + } + + message += `\n${error}`; + + if (this.callLine) { + message += `${stylize('from ', 'red') + (this.filename || '')}/n`; + message += `${stylize(this.callLine, 'grey')} ${this.callExtract}/n`; + } + + return message; +}; + +class Selector extends Node { + constructor(elements, extendList, condition, index, currentFileInfo, visibilityInfo) { + super(); + this.extendList = extendList; + this.condition = condition; + this.evaldCondition = !condition; + this._index = index; + this._fileInfo = currentFileInfo; + this.elements = this.getElements(elements); + this.mixinElements_ = undefined; + this.copyVisibilityInfo(visibilityInfo); + this.setParent(this.elements, this); + } + + accept(visitor) { + if (this.elements) { + this.elements = visitor.visitArray(this.elements); + } + + if (this.extendList) { + this.extendList = visitor.visitArray(this.extendList); + } + + if (this.condition) { + this.condition = visitor.visit(this.condition); + } + } + + createDerived(elements, extendList, evaldCondition) { + elements = this.getElements(elements); + const newSelector = new Selector(elements, extendList || this.extendList, null, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + newSelector.evaldCondition = evaldCondition != null ? evaldCondition : this.evaldCondition; + newSelector.mediaEmpty = this.mediaEmpty; + return newSelector; + } + + getElements(els) { + if (!els) { + return [new Element('', '&', false, this._index, this._fileInfo)]; + } + + if (typeof els === 'string') { + this.parse.parseNode(els, ['selector'], this._index, this._fileInfo, function (err, result) { + if (err) { + throw new LessError({ + index: err.index, + message: err.message + }, this.parse.imports, this._fileInfo.filename); + } + + els = result[0].elements; + }); + } + + return els; + } + + createEmptySelectors() { + const el = new Element('', '&', false, this._index, this._fileInfo); + const sels = [new Selector([el], null, null, this._index, this._fileInfo)]; + sels[0].mediaEmpty = true; + return sels; + } + + match(other) { + const elements = this.elements; + const len = elements.length; + let olen; + let i; + other = other.mixinElements(); + olen = other.length; + + if (olen === 0 || len < olen) { + return 0; + } else { + for (i = 0; i < olen; i++) { + if (elements[i].value !== other[i]) { + return 0; + } + } + } + + return olen; // return number of matched elements + } + + mixinElements() { + if (this.mixinElements_) { + return this.mixinElements_; + } + + let elements = this.elements.map(v => v.combinator.value + (v.value.value || v.value)).join('').match(/[,&#\*\.\w-]([\w-]|(\\.))*/g); + + if (elements) { + if (elements[0] === '&') { + elements.shift(); + } + } else { + elements = []; + } + + return this.mixinElements_ = elements; + } + + isJustParentSelector() { + return !this.mediaEmpty && this.elements.length === 1 && this.elements[0].value === '&' && (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === ''); + } + + eval(context) { + const evaldCondition = this.condition && this.condition.eval(context); + let elements = this.elements; + let extendList = this.extendList; + elements = elements && elements.map(e => e.eval(context)); + extendList = extendList && extendList.map(extend => extend.eval(context)); + return this.createDerived(elements, extendList, evaldCondition); + } + + genCSS(context, output) { + let i; + let element; + + if ((!context || !context.firstSelector) && this.elements[0].combinator.value === '') { + output.add(' ', this.fileInfo(), this.getIndex()); + } + + for (i = 0; i < this.elements.length; i++) { + element = this.elements[i]; + element.genCSS(context, output); + } + } + + getIsOutput() { + return this.evaldCondition; + } + +} + +Selector.prototype.type = 'Selector'; + +class Value extends Node { + constructor(value) { + super(); + + if (!value) { + throw new Error('Value requires an array argument'); + } + + if (!Array.isArray(value)) { + this.value = [value]; + } else { + this.value = value; + } + } + + accept(visitor) { + if (this.value) { + this.value = visitor.visitArray(this.value); + } + } + + eval(context) { + if (this.value.length === 1) { + return this.value[0].eval(context); + } else { + return new Value(this.value.map(v => v.eval(context))); + } + } + + genCSS(context, output) { + let i; + + for (i = 0; i < this.value.length; i++) { + this.value[i].genCSS(context, output); + + if (i + 1 < this.value.length) { + output.add(context && context.compress ? ',' : ', '); + } + } + } + +} + +Value.prototype.type = 'Value'; + +class Keyword extends Node { + constructor(value) { + super(); + this.value = value; + } + + genCSS(context, output) { + if (this.value === '%') { + throw { + type: 'Syntax', + message: 'Invalid % without number' + }; + } + + output.add(this.value); + } + +} + +Keyword.prototype.type = 'Keyword'; +Keyword.True = new Keyword('true'); +Keyword.False = new Keyword('false'); + +class Anonymous extends Node { + constructor(value, index, currentFileInfo, mapLines, rulesetLike, visibilityInfo) { + super(); + this.value = value; + this._index = index; + this._fileInfo = currentFileInfo; + this.mapLines = mapLines; + this.rulesetLike = typeof rulesetLike === 'undefined' ? false : rulesetLike; + this.allowRoot = true; + this.copyVisibilityInfo(visibilityInfo); + } + + eval() { + return new Anonymous(this.value, this._index, this._fileInfo, this.mapLines, this.rulesetLike, this.visibilityInfo()); + } + + compare(other) { + return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; + } + + isRulesetLike() { + return this.rulesetLike; + } + + genCSS(context, output) { + this.nodeVisible = Boolean(this.value); + + if (this.nodeVisible) { + output.add(this.value, this._fileInfo, this._index, this.mapLines); + } + } + +} + +Anonymous.prototype.type = 'Anonymous'; + +const MATH = Math$1; + +class Declaration extends Node { + constructor(name, value, important, merge, index, currentFileInfo, inline, variable) { + super(); + this.name = name; + this.value = value instanceof Node ? value : new Value([value ? new Anonymous(value) : null]); + this.important = important ? ` ${important.trim()}` : ''; + this.merge = merge; + this._index = index; + this._fileInfo = currentFileInfo; + this.inline = inline || false; + this.variable = variable !== undefined ? variable : name.charAt && name.charAt(0) === '@'; + this.allowRoot = true; + this.setParent(this.value, this); + } + + genCSS(context, output) { + output.add(this.name + (context.compress ? ':' : ': '), this.fileInfo(), this.getIndex()); + + try { + this.value.genCSS(context, output); + } catch (e) { + e.index = this._index; + e.filename = this._fileInfo.filename; + throw e; + } + + output.add(this.important + (this.inline || context.lastRule && context.compress ? '' : ';'), this._fileInfo, this._index); + } + + eval(context) { + let mathBypass = false; + let prevMath; + let name = this.name; + let evaldValue; + let variable = this.variable; + + if (typeof name !== 'string') { + // expand 'primitive' name directly to get + // things faster (~10% for benchmark.less): + name = name.length === 1 && name[0] instanceof Keyword ? name[0].value : evalName(context, name); + variable = false; // never treat expanded interpolation as new variable name + } // @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({}); + evaldValue = this.value.eval(context); + + if (!this.variable && evaldValue.type === 'DetachedRuleset') { + throw { + message: 'Rulesets cannot be evaluated on a property.', + index: this.getIndex(), + filename: this.fileInfo().filename + }; + } + + let important = this.important; + const importantResult = context.importantScope.pop(); + + if (!important && importantResult.important) { + important = importantResult.important; + } + + return new Declaration(name, evaldValue, important, this.merge, this.getIndex(), this.fileInfo(), this.inline, variable); + } catch (e) { + if (typeof e.index !== 'number') { + e.index = this.getIndex(); + e.filename = this.fileInfo().filename; + } + + throw e; + } finally { + if (mathBypass) { + context.math = prevMath; + } + } + } + + makeImportant() { + return new Declaration(this.name, this.value, '!important', this.merge, this.getIndex(), this.fileInfo(), this.inline); + } + +} + +function evalName(context, name) { + let value = ''; + let i; + const n = name.length; + const output = { + add: function add(s) { + value += s; + } + }; + + for (i = 0; i < n; i++) { + name[i].eval(context).genCSS(context, output); + } + + return value; +} + +Declaration.prototype.type = 'Declaration'; + +const debugInfo = (context, ctx, lineSeparator) => { + let result = ''; + + if (context.dumpLineNumbers && !context.compress) { + switch (context.dumpLineNumbers) { + case 'comments': + result = debugInfo.asComment(ctx); + break; + + case 'mediaquery': + result = debugInfo.asMediaQuery(ctx); + break; + + case 'all': + result = debugInfo.asComment(ctx) + (lineSeparator || '') + debugInfo.asMediaQuery(ctx); + break; + } + } + + return result; +}; + +debugInfo.asComment = ctx => `/* line ${ctx.debugInfo.lineNumber}, ${ctx.debugInfo.fileName} */\n`; + +debugInfo.asMediaQuery = ctx => { + let filenameWithProtocol = ctx.debugInfo.fileName; + + if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) { + filenameWithProtocol = `file://${filenameWithProtocol}`; + } + + return `@media -sass-debug-info{filename{font-family:${filenameWithProtocol.replace(/([.:\/\\])/g, a => { + if (a == '\\') { + a = '\/'; + } + + return `\\${a}`; + })}}line{font-family:\\00003${ctx.debugInfo.lineNumber}}}\n`; +}; + +class Comment extends Node { + constructor(value, isLineComment, index, currentFileInfo) { + super(); + this.value = value; + this.isLineComment = isLineComment; + this._index = index; + this._fileInfo = currentFileInfo; + this.allowRoot = true; + } + + genCSS(context, output) { + if (this.debugInfo) { + output.add(debugInfo(context, this), this.fileInfo(), this.getIndex()); + } + + output.add(this.value); + } + + isSilent(context) { + const isCompressed = context.compress && this.value[2] !== '!'; + return this.isLineComment || isCompressed; + } + +} + +Comment.prototype.type = 'Comment'; + +const contexts = {}; + +const copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) { + if (!original) { + return; + } + + for (let i = 0; i < propertiesToCopy.length; i++) { + if (original.hasOwnProperty(propertiesToCopy[i])) { + destination[propertiesToCopy[i]] = original[propertiesToCopy[i]]; + } + } +}; +/* + parse is used whilst parsing + */ + + +const parseCopyProperties = [// options +'paths', // option - unmodified - paths to search for imports on +'rewriteUrls', // option - whether to adjust URL's to be relative +'rootpath', // option - rootpath to append to URL's +'strictImports', // option - +'insecure', // option - whether to allow imports from insecure ssl hosts +'dumpLineNumbers', // option - whether to dump line numbers +'compress', // option - whether to compress +'syncImport', // option - whether to import synchronously +'chunkInput', // option - whether to chunk input. more performant but causes parse issues. +'mime', // browser only - mime type for sheet import +'useFileCache', // browser only - whether to use the per file session cache +// context +'processImports', // option & context - whether to process imports. if false then imports will not be imported. +// Used by the import manager to stop multiple import visitors being created. +'pluginManager' // Used as the plugin manager for the session +]; + +contexts.Parse = function (options) { + copyFromOriginal(options, this, parseCopyProperties); + + if (typeof this.paths === 'string') { + this.paths = [this.paths]; + } +}; + +const evalCopyProperties = ['paths', // additional include paths +'compress', // whether to compress +'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 +'urlArgs', // whether to add args into url tokens +'javascriptEnabled', // option - whether Inline JavaScript is enabled. if undefined, defaults to false +'pluginManager', // Used as the plugin manager for the session +'importantScope', // used to bubble up !important statements +'rewriteUrls' // option - whether to adjust URL's to be relative +]; + +function isPathRelative(path) { + return !/^(?:[a-z-]+:|\/|#)/i.test(path); +} + +function isPathLocalRelative(path) { + return path.charAt(0) === '.'; +} + +contexts.Eval = class { + constructor(options, frames) { + copyFromOriginal(options, this, evalCopyProperties); + + if (typeof this.paths === 'string') { + this.paths = [this.paths]; + } + + this.frames = frames || []; + this.importantScope = this.importantScope || []; + this.inCalc = false; + this.mathOn = true; + } + + enterCalc() { + if (!this.calcStack) { + this.calcStack = []; + } + + this.calcStack.push(true); + this.inCalc = true; + } + + exitCalc() { + this.calcStack.pop(); + + if (!this.calcStack) { + this.inCalc = false; + } + } + + inParenthesis() { + if (!this.parensStack) { + this.parensStack = []; + } + + this.parensStack.push(true); + } + + outOfParenthesis() { + this.parensStack.pop(); + } + + isMathOn(op) { + if (!this.mathOn) { + return false; + } + + if (op === '/' && this.math !== Math$1.ALWAYS && (!this.parensStack || !this.parensStack.length)) { + return false; + } + + if (this.math > Math$1.PARENS_DIVISION) { + return this.parensStack && this.parensStack.length; + } + + return true; + } + + pathRequiresRewrite(path) { + const isRelative = this.rewriteUrls === RewriteUrls.LOCAL ? isPathLocalRelative : isPathRelative; + return isRelative(path); + } + + rewritePath(path, rootpath) { + let newPath; + rootpath = rootpath || ''; + newPath = this.normalizePath(rootpath + path); // If a path was explicit relative and the rootpath was not an absolute path + // we must ensure that the new path is also explicit relative. + + if (isPathLocalRelative(path) && isPathRelative(rootpath) && isPathLocalRelative(newPath) === false) { + newPath = `./${newPath}`; + } + + return newPath; + } + + normalizePath(path) { + const segments = path.split('/').reverse(); + let segment; + path = []; + + while (segments.length !== 0) { + segment = segments.pop(); + + switch (segment) { + case '.': + break; + + case '..': + if (path.length === 0 || path[path.length - 1] === '..') { + path.push(segment); + } else { + path.pop(); + } + + break; + + default: + path.push(segment); + break; + } + } + + return path.join('/'); + } + +}; + +function makeRegistry(base) { + return { + _data: {}, + add: function add(name, func) { + // precautionary case conversion, as later querying of + // the registry by function-caller uses lower case as well. + name = name.toLowerCase(); + + if (this._data.hasOwnProperty(name)) ; + + this._data[name] = func; + }, + addMultiple: function addMultiple(functions) { + Object.keys(functions).forEach(name => { + this.add(name, functions[name]); + }); + }, + get: function get(name) { + return this._data[name] || base && base.get(name); + }, + getLocalFunctions: function getLocalFunctions() { + return this._data; + }, + inherit: function inherit() { + return makeRegistry(this); + }, + create: function create(base) { + return makeRegistry(base); + } + }; +} + +var functionRegistry = makeRegistry(null); + +const defaultFunc = { + eval: function _eval() { + const v = this.value_; + const e = this.error_; + + if (e) { + throw e; + } + + if (v != null) { + return v ? Keyword.True : Keyword.False; + } + }, + value: function value(v) { + this.value_ = v; + }, + error: function error(e) { + this.error_ = e; + }, + reset: function reset() { + this.value_ = this.error_ = null; + } +}; + +class Ruleset extends Node { + constructor(selectors, rules, strictImports, visibilityInfo) { + super(); + this.selectors = selectors; + this.rules = rules; + this._lookups = {}; + this._variables = null; + this._properties = null; + this.strictImports = strictImports; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + this.setParent(this.selectors, this); + this.setParent(this.rules, this); + } + + isRulesetLike() { + return true; + } + + accept(visitor) { + if (this.paths) { + this.paths = visitor.visitArray(this.paths, true); + } else if (this.selectors) { + this.selectors = visitor.visitArray(this.selectors); + } + + if (this.rules && this.rules.length) { + this.rules = visitor.visitArray(this.rules); + } + } + + eval(context) { + let selectors; + let selCnt; + let selector; + let i; + let hasVariable; + let hasOnePassingSelector = false; + + if (this.selectors && (selCnt = this.selectors.length)) { + selectors = new Array(selCnt); + defaultFunc.error({ + type: 'Syntax', + message: 'it is currently only allowed in parametric mixin guards,' + }); + + for (i = 0; i < selCnt; i++) { + selector = this.selectors[i].eval(context); + + for (var j = 0; j < selector.elements.length; j++) { + if (selector.elements[j].isVariable) { + hasVariable = true; + break; + } + } + + selectors[i] = selector; + + if (selector.evaldCondition) { + hasOnePassingSelector = true; + } + } + + if (hasVariable) { + const toParseSelectors = new Array(selCnt); + + for (i = 0; i < selCnt; i++) { + selector = selectors[i]; + toParseSelectors[i] = selector.toCSS(context); + } + + this.parse.parseNode(toParseSelectors.join(','), ["selectors"], selectors[0].getIndex(), selectors[0].fileInfo(), (err, result) => { + if (result) { + selectors = flattenArray(result); + } + }); + } + + defaultFunc.reset(); + } else { + hasOnePassingSelector = true; + } + + let rules = this.rules ? copyArray(this.rules) : null; + const ruleset = new Ruleset(selectors, rules, this.strictImports, this.visibilityInfo()); + let rule; + let subRule; + ruleset.originalRuleset = this; + ruleset.root = this.root; + ruleset.firstRoot = this.firstRoot; + ruleset.allowImports = this.allowImports; + + if (this.debugInfo) { + ruleset.debugInfo = this.debugInfo; + } + + if (!hasOnePassingSelector) { + rules.length = 0; + } // inherit a function registry from the frames stack when possible; + // otherwise from the global registry + + + ruleset.functionRegistry = (frames => { + let i = 0; + const n = frames.length; + let found; + + for (; i !== n; ++i) { + found = frames[i].functionRegistry; + + if (found) { + return found; + } + } + + return functionRegistry; + })(context.frames).inherit(); // push the current ruleset to the frames stack + + + const ctxFrames = context.frames; + ctxFrames.unshift(ruleset); // currrent selectors + + let ctxSelectors = context.selectors; + + if (!ctxSelectors) { + context.selectors = ctxSelectors = []; + } + + ctxSelectors.unshift(this.selectors); // Evaluate imports + + if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { + ruleset.evalImports(context); + } // Store the frames around mixin definitions, + // so they can be evaluated like closures when the time comes. + + + const rsRules = ruleset.rules; + + for (i = 0; rule = rsRules[i]; i++) { + if (rule.evalFirst) { + rsRules[i] = rule.eval(context); + } + } + + const mediaBlockCount = context.mediaBlocks && context.mediaBlocks.length || 0; // Evaluate mixin calls. + + for (i = 0; rule = rsRules[i]; i++) { + if (rule.type === 'MixinCall') { + /* jshint loopfunc:true */ + rules = rule.eval(context).filter(r => { + if (r instanceof Declaration && r.variable) { + // do not pollute the scope if the variable is + // already there. consider returning false here + // but we need a way to "return" variable from mixins + return !ruleset.variable(r.name); + } + + return true; + }); + rsRules.splice(...[i, 1].concat(rules)); + i += rules.length - 1; + ruleset.resetCache(); + } else if (rule.type === 'VariableCall') { + /* jshint loopfunc:true */ + rules = rule.eval(context).rules.filter(r => { + if (r instanceof Declaration && r.variable) { + // do not pollute the scope at all + return false; + } + + return true; + }); + rsRules.splice(...[i, 1].concat(rules)); + i += rules.length - 1; + ruleset.resetCache(); + } + } // Evaluate everything else + + + for (i = 0; rule = rsRules[i]; i++) { + if (!rule.evalFirst) { + rsRules[i] = rule = rule.eval ? rule.eval(context) : rule; + } + } // Evaluate everything else + + + for (i = 0; rule = rsRules[i]; i++) { + // for rulesets, check if it is a css guard and can be removed + if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) { + // check if it can be folded in (e.g. & where) + if (rule.selectors[0] && rule.selectors[0].isJustParentSelector()) { + rsRules.splice(i--, 1); + + for (var j = 0; subRule = rule.rules[j]; j++) { + if (subRule instanceof Node) { + subRule.copyVisibilityInfo(rule.visibilityInfo()); + + if (!(subRule instanceof Declaration) || !subRule.variable) { + rsRules.splice(++i, 0, subRule); + } + } + } + } + } + } // Pop the stack + + + ctxFrames.shift(); + ctxSelectors.shift(); + + if (context.mediaBlocks) { + for (i = mediaBlockCount; i < context.mediaBlocks.length; i++) { + context.mediaBlocks[i].bubbleSelectors(selectors); + } + } + + return ruleset; + } + + evalImports(context) { + const rules = this.rules; + let i; + let importRules; + + if (!rules) { + return; + } + + for (i = 0; i < rules.length; i++) { + if (rules[i].type === 'Import') { + importRules = rules[i].eval(context); + + if (importRules && (importRules.length || importRules.length === 0)) { + rules.splice(...[i, 1].concat(importRules)); + i += importRules.length - 1; + } else { + rules.splice(i, 1, importRules); + } + + this.resetCache(); + } + } + } + + makeImportant() { + const result = new Ruleset(this.selectors, this.rules.map(r => { + if (r.makeImportant) { + return r.makeImportant(); + } else { + return r; + } + }), this.strictImports, this.visibilityInfo()); + return result; + } + + matchArgs(args) { + return !args || args.length === 0; + } // lets you call a css selector with a guard + + + matchCondition(args, context) { + const lastSelector = this.selectors[this.selectors.length - 1]; + + if (!lastSelector.evaldCondition) { + return false; + } + + if (lastSelector.condition && !lastSelector.condition.eval(new contexts.Eval(context, context.frames))) { + return false; + } + + return true; + } + + resetCache() { + this._rulesets = null; + this._variables = null; + this._properties = null; + this._lookups = {}; + } + + variables() { + if (!this._variables) { + this._variables = !this.rules ? {} : this.rules.reduce((hash, r) => { + if (r instanceof Declaration && r.variable === true) { + hash[r.name] = r; + } // when evaluating variables in an import statement, imports have not been eval'd + // so we need to go inside import statements. + // guard against root being a string (in the case of inlined less) + + + if (r.type === 'Import' && r.root && r.root.variables) { + const vars = r.root.variables(); + + for (const name in vars) { + if (vars.hasOwnProperty(name)) { + hash[name] = r.root.variable(name); + } + } + } + + return hash; + }, {}); + } + + return this._variables; + } + + properties() { + if (!this._properties) { + this._properties = !this.rules ? {} : this.rules.reduce((hash, r) => { + if (r instanceof Declaration && r.variable !== true) { + const name = r.name.length === 1 && r.name[0] instanceof Keyword ? r.name[0].value : r.name; // Properties don't overwrite as they can merge + + if (!hash[`$${name}`]) { + hash[`$${name}`] = [r]; + } else { + hash[`$${name}`].push(r); + } + } + + return hash; + }, {}); + } + + return this._properties; + } + + variable(name) { + const decl = this.variables()[name]; + + if (decl) { + return this.parseValue(decl); + } + } + + property(name) { + const decl = this.properties()[name]; + + if (decl) { + return this.parseValue(decl); + } + } + + lastDeclaration() { + for (let i = this.rules.length; i > 0; i--) { + const decl = this.rules[i - 1]; + + if (decl instanceof Declaration) { + return this.parseValue(decl); + } + } + } + + parseValue(toParse) { + const self = this; + + function transformDeclaration(decl) { + if (decl.value instanceof Anonymous && !decl.parsed) { + if (typeof decl.value.value === 'string') { + this.parse.parseNode(decl.value.value, ['value', 'important'], decl.value.getIndex(), decl.fileInfo(), (err, result) => { + if (err) { + decl.parsed = true; + } + + if (result) { + decl.value = result[0]; + decl.important = result[1] || ''; + decl.parsed = true; + } + }); + } else { + decl.parsed = true; + } + + return decl; + } else { + return decl; + } + } + + if (!Array.isArray(toParse)) { + return transformDeclaration.call(self, toParse); + } else { + const nodes = []; + toParse.forEach(n => { + nodes.push(transformDeclaration.call(self, n)); + }); + return nodes; + } + } + + rulesets() { + if (!this.rules) { + return []; + } + + const filtRules = []; + const rules = this.rules; + let i; + let rule; + + for (i = 0; rule = rules[i]; i++) { + if (rule.isRuleset) { + filtRules.push(rule); + } + } + + return filtRules; + } + + prependRule(rule) { + const rules = this.rules; + + if (rules) { + rules.unshift(rule); + } else { + this.rules = [rule]; + } + + this.setParent(rule, this); + } + + find(selector, self = this, filter) { + const rules = []; + let match; + let foundMixins; + const key = selector.toCSS(); + + if (key in this._lookups) { + return this._lookups[key]; + } + + this.rulesets().forEach(rule => { + if (rule !== self) { + for (let j = 0; j < rule.selectors.length; j++) { + match = selector.match(rule.selectors[j]); + + if (match) { + if (selector.elements.length > match) { + if (!filter || filter(rule)) { + foundMixins = rule.find(new Selector(selector.elements.slice(match)), self, filter); + + for (let i = 0; i < foundMixins.length; ++i) { + foundMixins[i].path.push(rule); + } + + Array.prototype.push.apply(rules, foundMixins); + } + } else { + rules.push({ + rule, + path: [] + }); + } + + break; + } + } + } + }); + this._lookups[key] = rules; + return rules; + } + + genCSS(context, output) { + let i; + let j; + const charsetRuleNodes = []; + let ruleNodes = []; + let // Line number debugging + debugInfo$1; + let rule; + let path; + context.tabLevel = context.tabLevel || 0; + + if (!this.root) { + context.tabLevel++; + } + + const tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join(' '); + const tabSetStr = context.compress ? '' : Array(context.tabLevel).join(' '); + let sep; + let charsetNodeIndex = 0; + let importNodeIndex = 0; + + for (i = 0; rule = this.rules[i]; i++) { + if (rule instanceof Comment) { + if (importNodeIndex === i) { + importNodeIndex++; + } + + ruleNodes.push(rule); + } else if (rule.isCharset && rule.isCharset()) { + ruleNodes.splice(charsetNodeIndex, 0, rule); + charsetNodeIndex++; + importNodeIndex++; + } else if (rule.type === 'Import') { + ruleNodes.splice(importNodeIndex, 0, rule); + importNodeIndex++; + } else { + ruleNodes.push(rule); + } + } + + ruleNodes = charsetRuleNodes.concat(ruleNodes); // If this is the root node, we don't render + // a selector, or {}. + + if (!this.root) { + debugInfo$1 = debugInfo(context, this, tabSetStr); + + if (debugInfo$1) { + output.add(debugInfo$1); + output.add(tabSetStr); + } + + const paths = this.paths; + const pathCnt = paths.length; + let pathSubCnt; + sep = context.compress ? ',' : `,\n${tabSetStr}`; + + for (i = 0; i < pathCnt; i++) { + path = paths[i]; + + if (!(pathSubCnt = path.length)) { + continue; + } + + if (i > 0) { + output.add(sep); + } + + context.firstSelector = true; + path[0].genCSS(context, output); + context.firstSelector = false; + + for (j = 1; j < pathSubCnt; j++) { + path[j].genCSS(context, output); + } + } + + output.add((context.compress ? '{' : ' {\n') + tabRuleStr); + } // Compile rules and rulesets + + + for (i = 0; rule = ruleNodes[i]; i++) { + if (i + 1 === ruleNodes.length) { + context.lastRule = true; + } + + const currentLastRule = context.lastRule; + + if (rule.isRulesetLike(rule)) { + context.lastRule = false; + } + + if (rule.genCSS) { + rule.genCSS(context, output); + } else if (rule.value) { + output.add(rule.value.toString()); + } + + context.lastRule = currentLastRule; + + if (!context.lastRule && rule.isVisible()) { + output.add(context.compress ? '' : `\n${tabRuleStr}`); + } else { + context.lastRule = false; + } + } + + if (!this.root) { + output.add(context.compress ? '}' : `\n${tabSetStr}}`); + context.tabLevel--; + } + + if (!output.isEmpty() && !context.compress && this.firstRoot) { + output.add('\n'); + } + } + + joinSelectors(paths, context, selectors) { + for (let s = 0; s < selectors.length; s++) { + this.joinSelector(paths, context, selectors[s]); + } + } + + joinSelector(paths, context, selector) { + function createParenthesis(elementsToPak, originalElement) { + let replacementParen; + let j; + + if (elementsToPak.length === 0) { + replacementParen = new Paren(elementsToPak[0]); + } else { + const insideParent = new Array(elementsToPak.length); + + for (j = 0; j < elementsToPak.length; j++) { + insideParent[j] = new Element(null, elementsToPak[j], originalElement.isVariable, originalElement._index, originalElement._fileInfo); + } + + replacementParen = new Paren(new Selector(insideParent)); + } + + return replacementParen; + } + + function createSelector(containedElement, originalElement) { + let element; + let selector; + element = new Element(null, containedElement, originalElement.isVariable, originalElement._index, originalElement._fileInfo); + selector = new Selector([element]); + return selector; + } // joins selector path from `beginningPath` with selector path in `addPath` + // `replacedElement` contains element that is being replaced by `addPath` + // returns concatenated path + + + function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) { + let newSelectorPath; + let lastSelector; + let newJoinedSelector; // our new selector path + + newSelectorPath = []; // construct the joined selector - if & is the first thing this will be empty, + // if not newJoinedSelector will be the last set of elements in the selector + + if (beginningPath.length > 0) { + newSelectorPath = copyArray(beginningPath); + lastSelector = newSelectorPath.pop(); + newJoinedSelector = originalSelector.createDerived(copyArray(lastSelector.elements)); + } else { + newJoinedSelector = originalSelector.createDerived([]); + } + + if (addPath.length > 0) { + // /deep/ is a CSS4 selector - (removed, so should deprecate) + // that is valid without anything in front of it + // so if the & does not have a combinator that is "" or " " then + // and there is a combinator on the parent, then grab that. + // this also allows + a { & .b { .a & { ... though not sure why you would want to do that + let combinator = replacedElement.combinator; + const parentEl = addPath[0].elements[0]; + + if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) { + combinator = parentEl.combinator; + } // join the elements so far with the first part of the parent + + + newJoinedSelector.elements.push(new Element(combinator, parentEl.value, replacedElement.isVariable, replacedElement._index, replacedElement._fileInfo)); + newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1)); + } // now add the joined selector - but only if it is not empty + + + if (newJoinedSelector.elements.length !== 0) { + newSelectorPath.push(newJoinedSelector); + } // put together the parent selectors after the join (e.g. the rest of the parent) + + + if (addPath.length > 1) { + let restOfPath = addPath.slice(1); + restOfPath = restOfPath.map(selector => selector.createDerived(selector.elements, [])); + newSelectorPath = newSelectorPath.concat(restOfPath); + } + + return newSelectorPath; + } // joins selector path from `beginningPath` with every selector path in `addPaths` array + // `replacedElement` contains element that is being replaced by `addPath` + // returns array with all concatenated paths + + + function addAllReplacementsIntoPath(beginningPath, addPaths, replacedElement, originalSelector, result) { + let j; + + for (j = 0; j < beginningPath.length; j++) { + const newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector); + result.push(newSelectorPath); + } + + return result; + } + + function mergeElementsOnToSelectors(elements, selectors) { + let i; + let sel; + + if (elements.length === 0) { + return; + } + + if (selectors.length === 0) { + selectors.push([new Selector(elements)]); + return; + } + + for (i = 0; sel = selectors[i]; i++) { + // if the previous thing in sel is a parent this needs to join on to it + if (sel.length > 0) { + sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements)); + } else { + sel.push(new Selector(elements)); + } + } + } // replace all parent selectors inside `inSelector` by content of `context` array + // resulting selectors are returned inside `paths` array + // returns true if `inSelector` contained at least one parent selector + + + function replaceParentSelector(paths, context, inSelector) { + // The paths are [[Selector]] + // The first list is a list of comma separated selectors + // The inner list is a list of inheritance separated selectors + // e.g. + // .a, .b { + // .c { + // } + // } + // == [[.a] [.c]] [[.b] [.c]] + // + let i; + let j; + let k; + let currentElements; + let newSelectors; + let selectorsMultiplied; + let sel; + let el; + let hadParentSelector = false; + let length; + let lastSelector; + + function findNestedSelector(element) { + let maybeSelector; + + if (!(element.value instanceof Paren)) { + return null; + } + + maybeSelector = element.value.value; + + if (!(maybeSelector instanceof Selector)) { + return null; + } + + return maybeSelector; + } // the elements from the current selector so far + + + currentElements = []; // the current list of new selectors to add to the path. + // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors + // by the parents + + newSelectors = [[]]; + + for (i = 0; el = inSelector.elements[i]; i++) { + // non parent reference elements just get added + if (el.value !== '&') { + const nestedSelector = findNestedSelector(el); + + if (nestedSelector != null) { + // merge the current list of non parent selector elements + // on to the current list of selectors to add + mergeElementsOnToSelectors(currentElements, newSelectors); + const nestedPaths = []; + let replaced; + const replacedNewSelectors = []; + replaced = replaceParentSelector(nestedPaths, context, nestedSelector); + hadParentSelector = hadParentSelector || replaced; // the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors + + for (k = 0; k < nestedPaths.length; k++) { + const replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el); + addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors); + } + + newSelectors = replacedNewSelectors; + currentElements = []; + } else { + currentElements.push(el); + } + } else { + hadParentSelector = true; // the new list of selectors to add + + selectorsMultiplied = []; // merge the current list of non parent selector elements + // on to the current list of selectors to add + + mergeElementsOnToSelectors(currentElements, newSelectors); // loop through our current selectors + + for (j = 0; j < newSelectors.length; j++) { + sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used + // whether there are parents or not + + if (context.length === 0) { + // the combinator used on el should now be applied to the next element instead so that + // it is not lost + if (sel.length > 0) { + sel[0].elements.push(new Element(el.combinator, '', el.isVariable, el._index, el._fileInfo)); + } + + selectorsMultiplied.push(sel); + } else { + // and the parent selectors + for (k = 0; k < context.length; k++) { + // We need to put the current selectors + // then join the last selector's elements on to the parents selectors + const newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector); // add that to our new set of selectors + + selectorsMultiplied.push(newSelectorPath); + } + } + } // our new selectors has been multiplied, so reset the state + + + newSelectors = selectorsMultiplied; + currentElements = []; + } + } // if we have any elements left over (e.g. .a& .b == .b) + // add them on to all the current selectors + + + mergeElementsOnToSelectors(currentElements, newSelectors); + + for (i = 0; i < newSelectors.length; i++) { + length = newSelectors[i].length; + + if (length > 0) { + paths.push(newSelectors[i]); + lastSelector = newSelectors[i][length - 1]; + newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList); + } + } + + return hadParentSelector; + } + + function deriveSelector(visibilityInfo, deriveFrom) { + const newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition); + newSelector.copyVisibilityInfo(visibilityInfo); + return newSelector; + } // joinSelector code follows + + + let i; + let newPaths; + let hadParentSelector; + newPaths = []; + hadParentSelector = replaceParentSelector(newPaths, context, selector); + + if (!hadParentSelector) { + if (context.length > 0) { + newPaths = []; + + for (i = 0; i < context.length; i++) { + const concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo())); + concatenated.push(selector); + newPaths.push(concatenated); + } + } else { + newPaths = [[selector]]; + } + } + + for (i = 0; i < newPaths.length; i++) { + paths.push(newPaths[i]); + } + } + +} + +Ruleset.prototype.type = 'Ruleset'; +Ruleset.prototype.isRuleset = true; + +class AtRule extends Node { + constructor(name, value, rules, index, currentFileInfo, debugInfo, isRooted, visibilityInfo) { + super(); + let i; + this.name = name; + this.value = value instanceof Node ? value : value ? new Anonymous(value) : value; + + if (rules) { + if (Array.isArray(rules)) { + this.rules = rules; + } else { + this.rules = [rules]; + this.rules[0].selectors = new Selector([], null, null, index, currentFileInfo).createEmptySelectors(); + } + + for (i = 0; i < this.rules.length; i++) { + this.rules[i].allowImports = true; + } + + this.setParent(this.rules, this); + } + + this._index = index; + this._fileInfo = currentFileInfo; + this.debugInfo = debugInfo; + this.isRooted = isRooted || false; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + } + + accept(visitor) { + const value = this.value; + const rules = this.rules; + + if (rules) { + this.rules = visitor.visitArray(rules); + } + + if (value) { + this.value = visitor.visit(value); + } + } + + isRulesetLike() { + return this.rules || !this.isCharset(); + } + + isCharset() { + return '@charset' === this.name; + } + + genCSS(context, output) { + const value = this.value; + const rules = this.rules; + output.add(this.name, this.fileInfo(), this.getIndex()); + + if (value) { + output.add(' '); + value.genCSS(context, output); + } + + if (rules) { + this.outputRuleset(context, output, rules); + } else { + output.add(';'); + } + } + + eval(context) { + let mediaPathBackup; + let mediaBlocksBackup; + let value = this.value; + let rules = this.rules; // media stored inside other atrule should not bubble over it + // backpup media bubbling information + + mediaPathBackup = context.mediaPath; + mediaBlocksBackup = context.mediaBlocks; // deleted media bubbling information + + context.mediaPath = []; + context.mediaBlocks = []; + + if (value) { + value = value.eval(context); + } + + if (rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + rules = [rules[0].eval(context)]; + rules[0].root = true; + } // restore media bubbling information + + + context.mediaPath = mediaPathBackup; + context.mediaBlocks = mediaBlocksBackup; + return new AtRule(this.name, value, rules, this.getIndex(), this.fileInfo(), this.debugInfo, this.isRooted, this.visibilityInfo()); + } + + variable(name) { + if (this.rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + return Ruleset.prototype.variable.call(this.rules[0], name); + } + } + + find(...args) { + if (this.rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + return Ruleset.prototype.find.apply(this.rules[0], args); + } + } + + rulesets() { + if (this.rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + return Ruleset.prototype.rulesets.apply(this.rules[0]); + } + } + + outputRuleset(context, output, rules) { + const ruleCnt = rules.length; + let i; + context.tabLevel = (context.tabLevel | 0) + 1; // Compressed + + if (context.compress) { + output.add('{'); + + for (i = 0; i < ruleCnt; i++) { + rules[i].genCSS(context, output); + } + + output.add('}'); + context.tabLevel--; + return; + } // Non-compressed + + + const tabSetStr = `\n${Array(context.tabLevel).join(' ')}`; + const tabRuleStr = `${tabSetStr} `; + + if (!ruleCnt) { + output.add(` {${tabSetStr}}`); + } else { + output.add(` {${tabRuleStr}`); + rules[0].genCSS(context, output); + + for (i = 1; i < ruleCnt; i++) { + output.add(tabRuleStr); + rules[i].genCSS(context, output); + } + + output.add(`${tabSetStr}}`); + } + + context.tabLevel--; + } + +} + +AtRule.prototype.type = 'AtRule'; + +class DetachedRuleset extends Node { + constructor(ruleset, frames) { + super(); + this.ruleset = ruleset; + this.frames = frames; + this.setParent(this.ruleset, this); + } + + accept(visitor) { + this.ruleset = visitor.visit(this.ruleset); + } + + eval(context) { + const frames = this.frames || copyArray(context.frames); + return new DetachedRuleset(this.ruleset, frames); + } + + callEval(context) { + return this.ruleset.eval(this.frames ? new contexts.Eval(context, this.frames.concat(context.frames)) : context); + } + +} + +DetachedRuleset.prototype.type = 'DetachedRuleset'; +DetachedRuleset.prototype.evalFirst = true; + +class Unit extends Node { + constructor(numerator, denominator, backupUnit) { + super(); + this.numerator = numerator ? copyArray(numerator).sort() : []; + this.denominator = denominator ? copyArray(denominator).sort() : []; + + if (backupUnit) { + this.backupUnit = backupUnit; + } else if (numerator && numerator.length) { + this.backupUnit = numerator[0]; + } + } + + clone() { + return new Unit(copyArray(this.numerator), copyArray(this.denominator), this.backupUnit); + } + + genCSS(context, output) { + // Dimension checks the unit is singular and throws an error if in strict math mode. + const strictUnits = context && context.strictUnits; + + if (this.numerator.length === 1) { + output.add(this.numerator[0]); // the ideal situation + } else if (!strictUnits && this.backupUnit) { + output.add(this.backupUnit); + } else if (!strictUnits && this.denominator.length) { + output.add(this.denominator[0]); + } + } + + toString() { + let i; + let returnStr = this.numerator.join('*'); + + for (i = 0; i < this.denominator.length; i++) { + returnStr += `/${this.denominator[i]}`; + } + + return returnStr; + } + + compare(other) { + return this.is(other.toString()) ? 0 : undefined; + } + + is(unitString) { + return this.toString().toUpperCase() === unitString.toUpperCase(); + } + + isLength() { + return RegExp('^(px|em|ex|ch|rem|in|cm|mm|pc|pt|ex|vw|vh|vmin|vmax)$', 'gi').test(this.toCSS()); + } + + isEmpty() { + return this.numerator.length === 0 && this.denominator.length === 0; + } + + isSingular() { + return this.numerator.length <= 1 && this.denominator.length === 0; + } + + map(callback) { + let i; + + for (i = 0; i < this.numerator.length; i++) { + this.numerator[i] = callback(this.numerator[i], false); + } + + for (i = 0; i < this.denominator.length; i++) { + this.denominator[i] = callback(this.denominator[i], true); + } + } + + usedUnits() { + let group; + const result = {}; + let mapUnit; + let groupName; + + mapUnit = atomicUnit => { + /* jshint loopfunc:true */ + if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { + result[groupName] = atomicUnit; + } + + return atomicUnit; + }; + + for (groupName in unitConversions) { + if (unitConversions.hasOwnProperty(groupName)) { + group = unitConversions[groupName]; + this.map(mapUnit); + } + } + + return result; + } + + cancel() { + const counter = {}; + let atomicUnit; + let i; + + for (i = 0; i < this.numerator.length; i++) { + atomicUnit = this.numerator[i]; + counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; + } + + for (i = 0; i < this.denominator.length; i++) { + atomicUnit = this.denominator[i]; + counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; + } + + this.numerator = []; + this.denominator = []; + + for (atomicUnit in counter) { + if (counter.hasOwnProperty(atomicUnit)) { + const count = counter[atomicUnit]; + + if (count > 0) { + for (i = 0; i < count; i++) { + this.numerator.push(atomicUnit); + } + } else if (count < 0) { + for (i = 0; i < -count; i++) { + this.denominator.push(atomicUnit); + } + } + } + } + + this.numerator.sort(); + this.denominator.sort(); + } + +} + +Unit.prototype.type = 'Unit'; + +// A number with a unit +// + +class Dimension extends Node { + constructor(value, unit) { + super(); + this.value = parseFloat(value); + + if (isNaN(this.value)) { + throw new Error('Dimension is not a number.'); + } + + this.unit = unit && unit instanceof Unit ? unit : new Unit(unit ? [unit] : undefined); + this.setParent(this.unit, this); + } + + accept(visitor) { + this.unit = visitor.visit(this.unit); + } + + eval(context) { + return this; + } + + toColor() { + return new Color([this.value, this.value, this.value]); + } + + genCSS(context, output) { + if (context && context.strictUnits && !this.unit.isSingular()) { + throw new Error(`Multiple units in dimension. Correct the units or use the unit function. Bad unit: ${this.unit.toString()}`); + } + + const value = this.fround(context, this.value); + let strValue = String(value); + + if (value !== 0 && value < 0.000001 && value > -0.000001) { + // would be output 1e-6 etc. + strValue = value.toFixed(20).replace(/0+$/, ''); + } + + if (context && context.compress) { + // Zero values doesn't need a unit + if (value === 0 && this.unit.isLength()) { + output.add(strValue); + return; + } // Float values doesn't need a leading zero + + + if (value > 0 && value < 1) { + strValue = strValue.substr(1); + } + } + + output.add(strValue); + this.unit.genCSS(context, output); + } // In an operation between two Dimensions, + // we default to the first Dimension's unit, + // so `1px + 2` will yield `3px`. + + + operate(context, op, other) { + /* jshint noempty:false */ + let value = this._operate(context, op, this.value, other.value); + + let unit = this.unit.clone(); + + if (op === '+' || op === '-') { + if (unit.numerator.length === 0 && unit.denominator.length === 0) { + unit = other.unit.clone(); + + if (this.unit.backupUnit) { + unit.backupUnit = this.unit.backupUnit; + } + } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) ; else { + other = other.convertTo(this.unit.usedUnits()); + + if (context.strictUnits && other.unit.toString() !== unit.toString()) { + throw new Error(`Incompatible units. Change the units or use the unit function. ` + `Bad units: '${unit.toString()}' and '${other.unit.toString()}'.`); + } + + value = this._operate(context, op, this.value, other.value); + } + } else if (op === '*') { + unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); + unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); + unit.cancel(); + } else if (op === '/') { + unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); + unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); + unit.cancel(); + } + + return new Dimension(value, unit); + } + + compare(other) { + let a; + let b; + + if (!(other instanceof Dimension)) { + return undefined; + } + + if (this.unit.isEmpty() || other.unit.isEmpty()) { + a = this; + b = other; + } else { + a = this.unify(); + b = other.unify(); + + if (a.unit.compare(b.unit) !== 0) { + return undefined; + } + } + + return Node.numericCompare(a.value, b.value); + } + + unify() { + return this.convertTo({ + length: 'px', + duration: 's', + angle: 'rad' + }); + } + + convertTo(conversions) { + let value = this.value; + const unit = this.unit.clone(); + let i; + let groupName; + let group; + let targetUnit; + let derivedConversions = {}; + let applyUnit; + + if (typeof conversions === 'string') { + for (i in unitConversions) { + if (unitConversions[i].hasOwnProperty(conversions)) { + derivedConversions = {}; + derivedConversions[i] = conversions; + } + } + + conversions = derivedConversions; + } + + applyUnit = (atomicUnit, denominator) => { + /* jshint loopfunc:true */ + if (group.hasOwnProperty(atomicUnit)) { + if (denominator) { + value = value / (group[atomicUnit] / group[targetUnit]); + } else { + value = value * (group[atomicUnit] / group[targetUnit]); + } + + return targetUnit; + } + + return atomicUnit; + }; + + for (groupName in conversions) { + if (conversions.hasOwnProperty(groupName)) { + targetUnit = conversions[groupName]; + group = unitConversions[groupName]; + unit.map(applyUnit); + } + } + + unit.cancel(); + return new Dimension(value, unit); + } + +} + +Dimension.prototype.type = 'Dimension'; + +const MATH$1 = Math$1; + +class Operation extends Node { + constructor(op, operands, isSpaced) { + super(); + this.op = op.trim(); + this.operands = operands; + this.isSpaced = isSpaced; + } + + accept(visitor) { + this.operands = visitor.visitArray(this.operands); + } + + eval(context) { + let a = this.operands[0].eval(context); + let b = this.operands[1].eval(context); + let op; + + if (context.isMathOn(this.op)) { + op = this.op === './' ? '/' : this.op; + + if (a instanceof Dimension && b instanceof Color) { + a = a.toColor(); + } + + if (b instanceof Dimension && a instanceof Color) { + b = b.toColor(); + } + + if (!a.operate) { + if (a instanceof Operation && a.op === '/' && context.math === MATH$1.PARENS_DIVISION) { + return new Operation(this.op, [a, b], this.isSpaced); + } + + throw { + type: 'Operation', + message: 'Operation on an invalid type' + }; + } + + return a.operate(context, op, b); + } else { + return new Operation(this.op, [a, b], this.isSpaced); + } + } + + genCSS(context, output) { + this.operands[0].genCSS(context, output); + + if (this.isSpaced) { + output.add(' '); + } + + output.add(this.op); + + if (this.isSpaced) { + output.add(' '); + } + + this.operands[1].genCSS(context, output); + } + +} + +Operation.prototype.type = 'Operation'; + +const MATH$2 = Math$1; + +class Expression extends Node { + constructor(value, noSpacing) { + super(); + this.value = value; + this.noSpacing = noSpacing; + + if (!value) { + throw new Error('Expression requires an array parameter'); + } + } + + accept(visitor) { + this.value = visitor.visitArray(this.value); + } + + eval(context) { + let returnValue; + const mathOn = context.isMathOn(); + const inParenthesis = this.parens && (context.math !== MATH$2.STRICT_LEGACY || !this.parensInOp); + let doubleParen = false; + + if (inParenthesis) { + context.inParenthesis(); + } + + if (this.value.length > 1) { + returnValue = new Expression(this.value.map(e => { + if (!e.eval) { + return e; + } + + return e.eval(context); + }), this.noSpacing); + } else if (this.value.length === 1) { + if (this.value[0].parens && !this.value[0].parensInOp && !context.inCalc) { + doubleParen = true; + } + + returnValue = this.value[0].eval(context); + } else { + returnValue = this; + } + + if (inParenthesis) { + context.outOfParenthesis(); + } + + if (this.parens && this.parensInOp && !mathOn && !doubleParen && !(returnValue instanceof Dimension)) { + returnValue = new Paren(returnValue); + } + + return returnValue; + } + + genCSS(context, output) { + for (let i = 0; i < this.value.length; i++) { + this.value[i].genCSS(context, output); + + if (!this.noSpacing && i + 1 < this.value.length) { + output.add(' '); + } + } + } + + throwAwayComments() { + this.value = this.value.filter(v => !(v instanceof Comment)); + } + +} + +Expression.prototype.type = 'Expression'; + +class functionCaller { + constructor(name, context, index, currentFileInfo) { + this.name = name.toLowerCase(); + this.index = index; + this.context = context; + this.currentFileInfo = currentFileInfo; + this.func = context.frames[0].functionRegistry.get(this.name); + } + + isValid() { + return Boolean(this.func); + } + + call(args) { + // This code is terrible and should be replaced as per this issue... + // https://github.com/less/less.js/issues/2477 + if (Array.isArray(args)) { + args = args.filter(item => { + if (item.type === 'Comment') { + return false; + } + + return true; + }).map(item => { + if (item.type === 'Expression') { + const subNodes = item.value.filter(item => { + if (item.type === 'Comment') { + return false; + } + + return true; + }); + + if (subNodes.length === 1) { + return subNodes[0]; + } else { + return new Expression(subNodes); + } + } + + return item; + }); + } + + return this.func(...args); + } + +} + +// A function call node. +// + +class Call extends Node { + constructor(name, args, index, currentFileInfo) { + super(); + this.name = name; + this.args = args; + this.calc = name === 'calc'; + this._index = index; + this._fileInfo = currentFileInfo; + } + + accept(visitor) { + if (this.args) { + this.args = visitor.visitArray(this.args); + } + } // + // When evaluating a function call, + // we either find the function in the functionRegistry, + // in which case we call it, passing the evaluated arguments, + // if this returns null or we cannot find the function, we + // simply print it out as it appeared originally [2]. + // + // The reason why we evaluate the arguments, is in the case where + // we try to pass a variable to a function, like: `saturate(@color)`. + // The function should receive the value, not the variable. + // + + + eval(context) { + /** + * Turn off math for calc(), and switch back on for evaluating nested functions + */ + const currentMathContext = context.mathOn; + context.mathOn = !this.calc; + + if (this.calc || context.inCalc) { + context.enterCalc(); + } + + const args = this.args.map(a => a.eval(context)); + + if (this.calc || context.inCalc) { + context.exitCalc(); + } + + context.mathOn = currentMathContext; + let result; + const funcCaller = new functionCaller(this.name, context, this.getIndex(), this.fileInfo()); + + if (funcCaller.isValid()) { + try { + result = funcCaller.call(args); + } catch (e) { + throw { + type: e.type || 'Runtime', + message: `error evaluating function \`${this.name}\`${e.message ? `: ${e.message}` : ''}`, + index: this.getIndex(), + filename: this.fileInfo().filename, + line: e.lineNumber, + column: e.columnNumber + }; + } + + if (result !== null && result !== undefined) { + // Results that that are not nodes are cast as Anonymous nodes + // Falsy values or booleans are returned as empty nodes + if (!(result instanceof Node)) { + if (!result || result === true) { + result = new Anonymous(null); + } else { + result = new Anonymous(result.toString()); + } + } + + result._index = this._index; + result._fileInfo = this._fileInfo; + return result; + } + } + + return new Call(this.name, args, this.getIndex(), this.fileInfo()); + } + + genCSS(context, output) { + output.add(`${this.name}(`, this.fileInfo(), this.getIndex()); + + for (let i = 0; i < this.args.length; i++) { + this.args[i].genCSS(context, output); + + if (i + 1 < this.args.length) { + output.add(', '); + } + } + + output.add(')'); + } + +} + +Call.prototype.type = 'Call'; + +class Variable extends Node { + constructor(name, index, currentFileInfo) { + super(); + this.name = name; + this._index = index; + this._fileInfo = currentFileInfo; + } + + eval(context) { + let variable; + let name = this.name; + + if (name.indexOf('@@') === 0) { + name = `@${new Variable(name.slice(1), this.getIndex(), this.fileInfo()).eval(context).value}`; + } + + if (this.evaluating) { + throw { + type: 'Name', + message: `Recursive variable definition for ${name}`, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + + this.evaluating = true; + variable = this.find(context.frames, frame => { + const v = frame.variable(name); + + if (v) { + if (v.important) { + const importantScope = context.importantScope[context.importantScope.length - 1]; + importantScope.important = v.important; + } // If in calc, wrap vars in a function call to cascade evaluate args first + + + if (context.inCalc) { + return new Call('_SELF', [v.value]).eval(context); + } else { + return v.value.eval(context); + } + } + }); + + if (variable) { + this.evaluating = false; + return variable; + } else { + throw { + type: 'Name', + message: `variable ${name} is undefined`, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + } + + find(obj, fun) { + for (let i = 0, r; i < obj.length; i++) { + r = fun.call(obj, obj[i]); + + if (r) { + return r; + } + } + + return null; + } + +} + +Variable.prototype.type = 'Variable'; + +class Property extends Node { + constructor(name, index, currentFileInfo) { + super(); + this.name = name; + this._index = index; + this._fileInfo = currentFileInfo; + } + + eval(context) { + let property; + const name = this.name; // TODO: shorten this reference + + const mergeRules = context.pluginManager.less.visitors.ToCSSVisitor.prototype._mergeRules; + + if (this.evaluating) { + throw { + type: 'Name', + message: `Recursive property reference for ${name}`, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + + this.evaluating = true; + property = this.find(context.frames, frame => { + let v; + const vArr = frame.property(name); + + if (vArr) { + for (let i = 0; i < vArr.length; i++) { + v = vArr[i]; + vArr[i] = new Declaration(v.name, v.value, v.important, v.merge, v.index, v.currentFileInfo, v.inline, v.variable); + } + + mergeRules(vArr); + v = vArr[vArr.length - 1]; + + if (v.important) { + const importantScope = context.importantScope[context.importantScope.length - 1]; + importantScope.important = v.important; + } + + v = v.value.eval(context); + return v; + } + }); + + if (property) { + this.evaluating = false; + return property; + } else { + throw { + type: 'Name', + message: `Property '${name}' is undefined`, + filename: this.currentFileInfo.filename, + index: this.index + }; + } + } + + find(obj, fun) { + for (let i = 0, r; i < obj.length; i++) { + r = fun.call(obj, obj[i]); + + if (r) { + return r; + } + } + + return null; + } + +} + +Property.prototype.type = 'Property'; + +class Attribute extends Node { + constructor(key, op, value) { + super(); + this.key = key; + this.op = op; + this.value = value; + } + + eval(context) { + return new Attribute(this.key.eval ? this.key.eval(context) : this.key, this.op, this.value && this.value.eval ? this.value.eval(context) : this.value); + } + + genCSS(context, output) { + output.add(this.toCSS(context)); + } + + toCSS(context) { + let value = this.key.toCSS ? this.key.toCSS(context) : this.key; + + if (this.op) { + value += this.op; + value += this.value.toCSS ? this.value.toCSS(context) : this.value; + } + + return `[${value}]`; + } + +} + +Attribute.prototype.type = 'Attribute'; + +class Quoted extends Node { + constructor(str, content, escaped, index, currentFileInfo) { + super(); + this.escaped = escaped == null ? true : escaped; + this.value = content || ''; + this.quote = str.charAt(0); + this._index = index; + this._fileInfo = currentFileInfo; + this.variableRegex = /@\{([\w-]+)\}/g; + this.propRegex = /\$\{([\w-]+)\}/g; + } + + genCSS(context, output) { + if (!this.escaped) { + output.add(this.quote, this.fileInfo(), this.getIndex()); + } + + output.add(this.value); + + if (!this.escaped) { + output.add(this.quote); + } + } + + containsVariables() { + return this.value.match(this.variableRegex); + } + + eval(context) { + const that = this; + let value = this.value; + + const variableReplacement = (_, name) => { + const v = new Variable(`@${name}`, that.getIndex(), that.fileInfo()).eval(context, true); + return v instanceof Quoted ? v.value : v.toCSS(); + }; + + const propertyReplacement = (_, name) => { + const v = new Property(`$${name}`, that.getIndex(), that.fileInfo()).eval(context, true); + return v instanceof Quoted ? v.value : v.toCSS(); + }; + + function iterativeReplace(value, regexp, replacementFnc) { + let evaluatedValue = value; + + do { + value = evaluatedValue.toString(); + evaluatedValue = value.replace(regexp, replacementFnc); + } while (value !== evaluatedValue); + + return evaluatedValue; + } + + value = iterativeReplace(value, this.variableRegex, variableReplacement); + value = iterativeReplace(value, this.propRegex, propertyReplacement); + return new Quoted(this.quote + value + this.quote, value, this.escaped, this.getIndex(), this.fileInfo()); + } + + compare(other) { + // when comparing quoted strings allow the quote to differ + if (other.type === 'Quoted' && !this.escaped && !other.escaped) { + return Node.numericCompare(this.value, other.value); + } else { + return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; + } + } + +} + +Quoted.prototype.type = 'Quoted'; + +class URL extends Node { + constructor(val, index, currentFileInfo, isEvald) { + super(); + this.value = val; + this._index = index; + this._fileInfo = currentFileInfo; + this.isEvald = isEvald; + } + + accept(visitor) { + this.value = visitor.visit(this.value); + } + + genCSS(context, output) { + output.add('url('); + this.value.genCSS(context, output); + output.add(')'); + } + + eval(context) { + const val = this.value.eval(context); + let rootpath; + + if (!this.isEvald) { + // Add the rootpath if the URL requires a rewrite + rootpath = this.fileInfo() && this.fileInfo().rootpath; + + if (typeof rootpath === 'string' && typeof val.value === 'string' && context.pathRequiresRewrite(val.value)) { + if (!val.quote) { + rootpath = escapePath(rootpath); + } + + val.value = context.rewritePath(val.value, rootpath); + } else { + val.value = context.normalizePath(val.value); + } // Add url args if enabled + + + if (context.urlArgs) { + if (!val.value.match(/^\s*data:/)) { + const delimiter = val.value.indexOf('?') === -1 ? '?' : '&'; + const urlArgs = delimiter + context.urlArgs; + + if (val.value.indexOf('#') !== -1) { + val.value = val.value.replace('#', `${urlArgs}#`); + } else { + val.value += urlArgs; + } + } + } + } + + return new URL(val, this.getIndex(), this.fileInfo(), true); + } + +} + +URL.prototype.type = 'Url'; + +function escapePath(path) { + return path.replace(/[\(\)'"\s]/g, match => `\\${match}`); +} + +class Media extends AtRule { + constructor(value, features, index, currentFileInfo, visibilityInfo) { + super(); + this._index = index; + this._fileInfo = currentFileInfo; + const selectors = new Selector([], null, null, this._index, this._fileInfo).createEmptySelectors(); + this.features = new Value(features); + this.rules = [new Ruleset(selectors, value)]; + this.rules[0].allowImports = true; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + this.setParent(selectors, this); + this.setParent(this.features, this); + this.setParent(this.rules, this); + } + + isRulesetLike() { + return true; + } + + accept(visitor) { + if (this.features) { + this.features = visitor.visit(this.features); + } + + if (this.rules) { + this.rules = visitor.visitArray(this.rules); + } + } + + genCSS(context, output) { + output.add('@media ', this._fileInfo, this._index); + this.features.genCSS(context, output); + this.outputRuleset(context, output, this.rules); + } + + eval(context) { + if (!context.mediaBlocks) { + context.mediaBlocks = []; + context.mediaPath = []; + } + + const media = new Media(null, [], this._index, this._fileInfo, this.visibilityInfo()); + + if (this.debugInfo) { + this.rules[0].debugInfo = this.debugInfo; + media.debugInfo = this.debugInfo; + } + + media.features = this.features.eval(context); + context.mediaPath.push(media); + context.mediaBlocks.push(media); + this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit(); + context.frames.unshift(this.rules[0]); + media.rules = [this.rules[0].eval(context)]; + context.frames.shift(); + context.mediaPath.pop(); + return context.mediaPath.length === 0 ? media.evalTop(context) : media.evalNested(context); + } + + evalTop(context) { + let result = this; // Render all dependent Media blocks. + + if (context.mediaBlocks.length > 1) { + const selectors = new Selector([], null, null, this.getIndex(), this.fileInfo()).createEmptySelectors(); + result = new Ruleset(selectors, context.mediaBlocks); + result.multiMedia = true; + result.copyVisibilityInfo(this.visibilityInfo()); + this.setParent(result, this); + } + + delete context.mediaBlocks; + delete context.mediaPath; + return result; + } + + evalNested(context) { + let i; + let value; + const path = context.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). + + for (i = 0; i < path.length; i++) { + value = path[i].features instanceof Value ? path[i].features.value : path[i].features; + path[i] = Array.isArray(value) ? value : [value]; + } // Trace all permutations to generate the resulting media-query. + // + // (a, b and c) with nested (d, e) -> + // a and d + // a and e + // b and c and d + // b and c and e + + + this.features = new Value(this.permute(path).map(path => { + path = path.map(fragment => fragment.toCSS ? fragment : new Anonymous(fragment)); + + for (i = path.length - 1; i > 0; i--) { + path.splice(i, 0, new Anonymous('and')); + } + + return new Expression(path); + })); + this.setParent(this.features, this); // Fake a tree-node that doesn't output anything. + + return new Ruleset([], []); + } + + permute(arr) { + if (arr.length === 0) { + return []; + } else if (arr.length === 1) { + return arr[0]; + } else { + const result = []; + const rest = this.permute(arr.slice(1)); + + for (let i = 0; i < rest.length; i++) { + for (let j = 0; j < arr[0].length; j++) { + result.push([arr[0][j]].concat(rest[i])); + } + } + + return result; + } + } + + bubbleSelectors(selectors) { + if (!selectors) { + return; + } + + this.rules = [new Ruleset(copyArray(selectors), [this.rules[0]])]; + this.setParent(this.rules, this); + } + +} + +Media.prototype.type = 'Media'; + +// CSS @import node +// +// The general strategy here is that we don't want to wait +// for the parsing to be completed, before we start importing +// the file. That's because in the context of a browser, +// most of the time will be spent waiting for the server to respond. +// +// On creation, we push the import path to our import queue, though +// `import,push`, we also pass it a callback, which it'll call once +// the file has been fetched, and parsed. +// + +class Import extends Node { + constructor(path, features, options, index, currentFileInfo, visibilityInfo) { + super(); + this.options = options; + this._index = index; + this._fileInfo = currentFileInfo; + this.path = path; + this.features = features; + this.allowRoot = true; + + if (this.options.less !== undefined || this.options.inline) { + this.css = !this.options.less || this.options.inline; + } else { + const pathValue = this.getPath(); + + if (pathValue && /[#\.\&\?]css([\?;].*)?$/.test(pathValue)) { + this.css = true; + } + } + + this.copyVisibilityInfo(visibilityInfo); + this.setParent(this.features, this); + this.setParent(this.path, this); + } + + accept(visitor) { + if (this.features) { + this.features = visitor.visit(this.features); + } + + this.path = visitor.visit(this.path); + + if (!this.options.isPlugin && !this.options.inline && this.root) { + this.root = visitor.visit(this.root); + } + } + + genCSS(context, output) { + if (this.css && this.path._fileInfo.reference === undefined) { + output.add('@import ', this._fileInfo, this._index); + this.path.genCSS(context, output); + + if (this.features) { + output.add(' '); + this.features.genCSS(context, output); + } + + output.add(';'); + } + } + + getPath() { + return this.path instanceof URL ? this.path.value.value : this.path.value; + } + + isVariableImport() { + let path = this.path; + + if (path instanceof URL) { + path = path.value; + } + + if (path instanceof Quoted) { + return path.containsVariables(); + } + + return true; + } + + evalForImport(context) { + let path = this.path; + + if (path instanceof URL) { + path = path.value; + } + + return new Import(path.eval(context), this.features, this.options, this._index, this._fileInfo, this.visibilityInfo()); + } + + evalPath(context) { + const path = this.path.eval(context); + const fileInfo = this._fileInfo; + + if (!(path instanceof URL)) { + // Add the rootpath if the URL requires a rewrite + const pathValue = path.value; + + if (fileInfo && pathValue && context.pathRequiresRewrite(pathValue)) { + path.value = context.rewritePath(pathValue, fileInfo.rootpath); + } else { + path.value = context.normalizePath(path.value); + } + } + + return path; + } + + eval(context) { + const result = this.doEval(context); + + if (this.options.reference || this.blocksVisibility()) { + if (result.length || result.length === 0) { + result.forEach(node => { + node.addVisibilityBlock(); + }); + } else { + result.addVisibilityBlock(); + } + } + + return result; + } + + doEval(context) { + let ruleset; + let registry; + const features = this.features && this.features.eval(context); + + if (this.options.isPlugin) { + if (this.root && this.root.eval) { + try { + this.root.eval(context); + } catch (e) { + e.message = 'Plugin error during evaluation'; + throw new LessError(e, this.root.imports, this.root.filename); + } + } + + registry = context.frames[0] && context.frames[0].functionRegistry; + + if (registry && this.root && this.root.functions) { + registry.addMultiple(this.root.functions); + } + + return []; + } + + if (this.skip) { + if (typeof this.skip === 'function') { + this.skip = this.skip(); + } + + if (this.skip) { + return []; + } + } + + if (this.options.inline) { + const contents = new Anonymous(this.root, 0, { + filename: this.importedFilename, + reference: this.path._fileInfo && this.path._fileInfo.reference + }, true, true); + return this.features ? new Media([contents], this.features.value) : [contents]; + } else if (this.css) { + const newImport = new Import(this.evalPath(context), features, this.options, this._index); + + if (!newImport.css && this.error) { + throw this.error; + } + + return newImport; + } else { + ruleset = new Ruleset(null, copyArray(this.root.rules)); + ruleset.evalImports(context); + return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules; + } + } + +} + +Import.prototype.type = 'Import'; + +class JsEvalNode extends Node { + evaluateJavaScript(expression, context) { + let result; + const that = this; + const evalContext = {}; + + if (!context.javascriptEnabled) { + throw { + message: 'Inline JavaScript is not enabled. Is it set in your options?', + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + + expression = expression.replace(/@\{([\w-]+)\}/g, (_, name) => that.jsify(new Variable(`@${name}`, that.getIndex(), that.fileInfo()).eval(context))); + + try { + expression = new Function(`return (${expression})`); + } catch (e) { + throw { + message: `JavaScript evaluation error: ${e.message} from \`${expression}\``, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + + const variables = context.frames[0].variables(); + + for (const k in variables) { + if (variables.hasOwnProperty(k)) { + /* jshint loopfunc:true */ + evalContext[k.slice(1)] = { + value: variables[k].value, + toJS: function toJS() { + return this.value.eval(context).toCSS(); + } + }; + } + } + + try { + result = expression.call(evalContext); + } catch (e) { + throw { + message: `JavaScript evaluation error: '${e.name}: ${e.message.replace(/["]/g, '\'')}'`, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + + return result; + } + + jsify(obj) { + if (Array.isArray(obj.value) && obj.value.length > 1) { + return `[${obj.value.map(v => v.toCSS()).join(', ')}]`; + } else { + return obj.toCSS(); + } + } + +} + +class JavaScript extends JsEvalNode { + constructor(string, escaped, index, currentFileInfo) { + super(); + this.escaped = escaped; + this.expression = string; + this._index = index; + this._fileInfo = currentFileInfo; + } + + eval(context) { + const result = this.evaluateJavaScript(this.expression, context); + const type = typeof result; + + if (type === 'number' && !isNaN(result)) { + return new Dimension(result); + } else if (type === 'string') { + return new Quoted(`"${result}"`, result, this.escaped, this._index); + } else if (Array.isArray(result)) { + return new Anonymous(result.join(', ')); + } else { + return new Anonymous(result); + } + } + +} + +JavaScript.prototype.type = 'JavaScript'; + +class Assignment extends Node { + constructor(key, val) { + super(); + this.key = key; + this.value = val; + } + + accept(visitor) { + this.value = visitor.visit(this.value); + } + + eval(context) { + if (this.value.eval) { + return new Assignment(this.key, this.value.eval(context)); + } + + return this; + } + + genCSS(context, output) { + output.add(`${this.key}=`); + + if (this.value.genCSS) { + this.value.genCSS(context, output); + } else { + output.add(this.value); + } + } + +} + +Assignment.prototype.type = 'Assignment'; + +class Condition extends Node { + constructor(op, l, r, i, negate) { + super(); + this.op = op.trim(); + this.lvalue = l; + this.rvalue = r; + this._index = i; + this.negate = negate; + } + + accept(visitor) { + this.lvalue = visitor.visit(this.lvalue); + this.rvalue = visitor.visit(this.rvalue); + } + + eval(context) { + const result = ((op, a, b) => { + switch (op) { + case 'and': + return a && b; + + case 'or': + return a || b; + + default: + switch (Node.compare(a, b)) { + case -1: + return op === '<' || op === '=<' || op === '<='; + + case 0: + return op === '=' || op === '>=' || op === '=<' || op === '<='; + + case 1: + return op === '>' || op === '>='; + + default: + return false; + } + + } + })(this.op, this.lvalue.eval(context), this.rvalue.eval(context)); + + return this.negate ? !result : result; + } + +} + +Condition.prototype.type = 'Condition'; + +class UnicodeDescriptor extends Node { + constructor(value) { + super(); + this.value = value; + } + +} + +UnicodeDescriptor.prototype.type = 'UnicodeDescriptor'; + +class Negative extends Node { + constructor(node) { + super(); + this.value = node; + } + + genCSS(context, output) { + output.add('-'); + this.value.genCSS(context, output); + } + + eval(context) { + if (context.isMathOn()) { + return new Operation('*', [new Dimension(-1), this.value]).eval(context); + } + + return new Negative(this.value.eval(context)); + } + +} + +Negative.prototype.type = 'Negative'; + +class Extend extends Node { + constructor(selector, option, index, currentFileInfo, visibilityInfo) { + super(); + this.selector = selector; + this.option = option; + this.object_id = Extend.next_id++; + this.parent_ids = [this.object_id]; + this._index = index; + this._fileInfo = currentFileInfo; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + + switch (option) { + case 'all': + this.allowBefore = true; + this.allowAfter = true; + break; + + default: + this.allowBefore = false; + this.allowAfter = false; + break; + } + + this.setParent(this.selector, this); + } + + accept(visitor) { + this.selector = visitor.visit(this.selector); + } + + eval(context) { + return new Extend(this.selector.eval(context), this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } + + clone(context) { + return new Extend(this.selector, this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } // it concatenates (joins) all selectors in selector array + + + findSelfSelectors(selectors) { + let selfElements = []; + let i; + let selectorElements; + + for (i = 0; i < selectors.length; i++) { + selectorElements = selectors[i].elements; // duplicate the logic in genCSS function inside the selector node. + // future TODO - move both logics into the selector joiner visitor + + if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === '') { + selectorElements[0].combinator.value = ' '; + } + + selfElements = selfElements.concat(selectors[i].elements); + } + + this.selfSelectors = [new Selector(selfElements)]; + this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo()); + } + +} + +Extend.next_id = 0; +Extend.prototype.type = 'Extend'; + +class VariableCall extends Node { + constructor(variable, index, currentFileInfo) { + super(); + this.variable = variable; + this._index = index; + this._fileInfo = currentFileInfo; + this.allowRoot = true; + } + + eval(context) { + let rules; + let detachedRuleset = new Variable(this.variable, this.getIndex(), this.fileInfo()).eval(context); + const error = new LessError({ + message: `Could not evaluate variable call ${this.variable}` + }); + + if (!detachedRuleset.ruleset) { + if (detachedRuleset.rules) { + rules = detachedRuleset; + } else if (Array.isArray(detachedRuleset)) { + rules = new Ruleset('', detachedRuleset); + } else if (Array.isArray(detachedRuleset.value)) { + rules = new Ruleset('', detachedRuleset.value); + } else { + throw error; + } + + detachedRuleset = new DetachedRuleset(rules); + } + + if (detachedRuleset.ruleset) { + return detachedRuleset.callEval(context); + } + + throw error; + } + +} + +VariableCall.prototype.type = 'VariableCall'; + +class NamespaceValue extends Node { + constructor(ruleCall, lookups, important, index, fileInfo) { + super(); + this.value = ruleCall; + this.lookups = lookups; + this.important = important; + this._index = index; + this._fileInfo = fileInfo; + } + + eval(context) { + let i; + let name; + let rules = this.value.eval(context); + + for (i = 0; i < this.lookups.length; i++) { + name = this.lookups[i]; + /** + * Eval'd DRs return rulesets. + * Eval'd mixins return rules, so let's make a ruleset if we need it. + * We need to do this because of late parsing of values + */ + + if (Array.isArray(rules)) { + rules = new Ruleset([new Selector()], rules); + } + + if (name === '') { + rules = rules.lastDeclaration(); + } else if (name.charAt(0) === '@') { + if (name.charAt(1) === '@') { + name = `@${new Variable(name.substr(1)).eval(context).value}`; + } + + if (rules.variables) { + rules = rules.variable(name); + } + + if (!rules) { + throw { + type: 'Name', + message: `variable ${name} not found`, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } + } else { + if (name.substring(0, 2) === '$@') { + name = `$${new Variable(name.substr(1)).eval(context).value}`; + } else { + name = name.charAt(0) === '$' ? name : `$${name}`; + } + + if (rules.properties) { + rules = rules.property(name); + } + + if (!rules) { + throw { + type: 'Name', + message: `property "${name.substr(1)}" not found`, + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } // Properties are an array of values, since a ruleset can have multiple props. + // We pick the last one (the "cascaded" value) + + + rules = rules[rules.length - 1]; + } + + if (rules.value) { + rules = rules.eval(context).value; + } + + if (rules.ruleset) { + rules = rules.ruleset.eval(context); + } + } + + return rules; + } + +} + +NamespaceValue.prototype.type = 'NamespaceValue'; + +class Definition extends Ruleset { + constructor(name, params, rules, condition, variadic, frames, visibilityInfo) { + super(); + this.name = name || 'anonymous mixin'; + this.selectors = [new Selector([new Element(null, name, false, this._index, this._fileInfo)])]; + this.params = params; + this.condition = condition; + this.variadic = variadic; + this.arity = params.length; + this.rules = rules; + this._lookups = {}; + const optionalParameters = []; + this.required = params.reduce((count, p) => { + if (!p.name || p.name && !p.value) { + return count + 1; + } else { + optionalParameters.push(p.name); + return count; + } + }, 0); + this.optionalParameters = optionalParameters; + this.frames = frames; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + } + + accept(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); + } + } + + evalParams(context, mixinEnv, args, evaldArguments) { + /* jshint boss:true */ + const frame = new Ruleset(null, null); + let varargs; + let arg; + const params = copyArray(this.params); + let i; + let j; + let val; + let name; + let isNamedFound; + let argIndex; + let argsLength = 0; + + if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) { + frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit(); + } + + mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames)); + + if (args) { + args = copyArray(args); + 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(context); + frame.prependRule(new Declaration(name, arg.value.eval(context))); + 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(context)); + } + + frame.prependRule(new Declaration(name, new Expression(varargs).eval(context))); + } else { + val = arg && arg.value; + + if (val) { + // This was a mixin call, pass in a detached ruleset of it's eval'd rules + if (Array.isArray(val)) { + val = new DetachedRuleset(new Ruleset('', val)); + } else { + val = val.eval(context); + } + } 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 Declaration(name, val)); + evaldArguments[i] = val; + } + } + + if (params[i].variadic && args) { + for (j = argIndex; j < argsLength; j++) { + evaldArguments[j] = args[j].value.eval(context); + } + } + + argIndex++; + } + + return frame; + } + + makeImportant() { + const rules = !this.rules ? this.rules : this.rules.map(r => { + if (r.makeImportant) { + return r.makeImportant(true); + } else { + return r; + } + }); + const result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames); + return result; + } + + eval(context) { + return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || copyArray(context.frames)); + } + + evalCall(context, args, important) { + const _arguments = []; + const mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames; + const frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments); + let rules; + let ruleset; + frame.prependRule(new Declaration('@arguments', new Expression(_arguments).eval(context))); + rules = copyArray(this.rules); + ruleset = new Ruleset(null, rules); + ruleset.originalRuleset = this; + ruleset = ruleset.eval(new contexts.Eval(context, [this, frame].concat(mixinFrames))); + + if (important) { + ruleset = ruleset.makeImportant(); + } + + return ruleset; + } + + matchCondition(args, context) { + if (this.condition && !this.condition.eval(new contexts.Eval(context, [this.evalParams(context, + /* the parameter variables */ + new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])].concat(this.frames || []) // the parent namespace/mixin frames + .concat(context.frames)))) { + // the current environment frames + return false; + } + + return true; + } + + matchArgs(args, context) { + const allArgsCnt = args && args.length || 0; + let len; + const optionalParameters = this.optionalParameters; + const requiredArgsCnt = !args ? 0 : args.reduce((count, p) => { + if (optionalParameters.indexOf(p.name) < 0) { + return count + 1; + } else { + return count; + } + }, 0); + + if (!this.variadic) { + if (requiredArgsCnt < this.required) { + return false; + } + + if (allArgsCnt > this.params.length) { + return false; + } + } else { + if (requiredArgsCnt < this.required - 1) { + return false; + } + } // check patterns + + + len = Math.min(requiredArgsCnt, this.arity); + + for (let i = 0; i < len; i++) { + if (!this.params[i].name && !this.params[i].variadic) { + if (args[i].value.eval(context).toCSS() != this.params[i].value.eval(context).toCSS()) { + return false; + } + } + } + + return true; + } + +} + +Definition.prototype.type = 'MixinDefinition'; +Definition.prototype.evalFirst = true; + +class MixinCall extends Node { + constructor(elements, args, index, currentFileInfo, important) { + super(); + this.selector = new Selector(elements); + this.arguments = args || []; + this._index = index; + this._fileInfo = currentFileInfo; + this.important = important; + this.allowRoot = true; + this.setParent(this.selector, this); + } + + accept(visitor) { + if (this.selector) { + this.selector = visitor.visit(this.selector); + } + + if (this.arguments.length) { + this.arguments = visitor.visitArray(this.arguments); + } + } + + eval(context) { + let mixins; + let mixin; + let mixinPath; + const args = []; + let arg; + let argValue; + const rules = []; + let match = false; + let i; + let m; + let f; + let isRecursive; + let isOneFound; + const candidates = []; + let candidate; + const conditionResult = []; + let defaultResult; + const defFalseEitherCase = -1; + const defNone = 0; + const defTrue = 1; + const defFalse = 2; + let count; + let originalRuleset; + let noArgumentsFilter; + this.selector = this.selector.eval(context); + + function calcDefGroup(mixin, mixinPath) { + let f; + let p; + let namespace; + + for (f = 0; f < 2; f++) { + conditionResult[f] = true; + defaultFunc.value(f); + + for (p = 0; p < mixinPath.length && conditionResult[f]; p++) { + namespace = mixinPath[p]; + + if (namespace.matchCondition) { + conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, context); + } + } + + if (mixin.matchCondition) { + conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, context); + } + } + + if (conditionResult[0] || conditionResult[1]) { + if (conditionResult[0] != conditionResult[1]) { + return conditionResult[1] ? defTrue : defFalse; + } + + return defNone; + } + + return defFalseEitherCase; + } + + for (i = 0; i < this.arguments.length; i++) { + arg = this.arguments[i]; + argValue = arg.value.eval(context); + + if (arg.expand && Array.isArray(argValue.value)) { + argValue = argValue.value; + + for (m = 0; m < argValue.length; m++) { + args.push({ + value: argValue[m] + }); + } + } else { + args.push({ + name: arg.name, + value: argValue + }); + } + } + + noArgumentsFilter = rule => rule.matchArgs(null, context); + + for (i = 0; i < context.frames.length; i++) { + if ((mixins = context.frames[i].find(this.selector, null, noArgumentsFilter)).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].rule; + mixinPath = mixins[m].path; + isRecursive = false; + + for (f = 0; f < context.frames.length; f++) { + if (!(mixin instanceof Definition) && mixin === (context.frames[f].originalRuleset || context.frames[f])) { + isRecursive = true; + break; + } + } + + if (isRecursive) { + continue; + } + + if (mixin.matchArgs(args, context)) { + candidate = { + mixin, + group: calcDefGroup(mixin, mixinPath) + }; + + if (candidate.group !== defFalseEitherCase) { + 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.getIndex(), + filename: this.fileInfo().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 Definition)) { + originalRuleset = mixin.originalRuleset || mixin; + mixin = new Definition('', [], mixin.rules, null, false, null, originalRuleset.visibilityInfo()); + mixin.originalRuleset = originalRuleset; + } + + const newRules = mixin.evalCall(context, args, this.important).rules; + + this._setVisibilityToReplacement(newRules); + + Array.prototype.push.apply(rules, newRules); + } catch (e) { + throw { + message: e.message, + index: this.getIndex(), + filename: this.fileInfo().filename, + stack: e.stack + }; + } + } + } + + if (match) { + return rules; + } + } + } + + if (isOneFound) { + throw { + type: 'Runtime', + message: `No matching definition was found for \`${this.format(args)}\``, + index: this.getIndex(), + filename: this.fileInfo().filename + }; + } else { + throw { + type: 'Name', + message: `${this.selector.toCSS().trim()} is undefined`, + index: this.getIndex(), + filename: this.fileInfo().filename + }; + } + } + + _setVisibilityToReplacement(replacement) { + let i; + let rule; + + if (this.blocksVisibility()) { + for (i = 0; i < replacement.length; i++) { + rule = replacement[i]; + rule.addVisibilityBlock(); + } + } + } + + format(args) { + return `${this.selector.toCSS().trim()}(${args ? args.map(a => { + let argValue = ''; + + if (a.name) { + argValue += `${a.name}:`; + } + + if (a.value.toCSS) { + argValue += a.value.toCSS(); + } else { + argValue += '???'; + } + + return argValue; + }).join(', ') : ''})`; + } + +} + +MixinCall.prototype.type = 'MixinCall'; + +var tree = { + Node, + Color, + AtRule, + DetachedRuleset, + Operation, + Dimension, + Unit, + Keyword, + Variable, + Property, + Ruleset, + Element, + Attribute, + Combinator, + Selector, + Quoted, + Expression, + Declaration, + Call, + URL, + Import, + Comment, + Anonymous, + Value, + JavaScript, + Assignment, + Condition, + Paren, + Media, + UnicodeDescriptor, + Negative, + Extend, + VariableCall, + NamespaceValue, + mixin: { + Call: MixinCall, + Definition: Definition + } +}; + +/** + * @todo Document why this abstraction exists, and the relationship between + * environment, file managers, and plugin manager + */ + +class environment$1 { + constructor(externalEnvironment, fileManagers) { + this.fileManagers = fileManagers || []; + externalEnvironment = externalEnvironment || {}; + const optionalFunctions = ['encodeBase64', 'mimeLookup', 'charsetLookup', 'getSourceMapGenerator']; + const requiredFunctions = []; + const functions = requiredFunctions.concat(optionalFunctions); + + for (let i = 0; i < functions.length; i++) { + const propName = functions[i]; + const environmentFunc = externalEnvironment[propName]; + + if (environmentFunc) { + this[propName] = environmentFunc.bind(externalEnvironment); + } else if (i < requiredFunctions.length) { + this.warn(`missing required function in environment - ${propName}`); + } + } + } + + getFileManager(filename, currentDirectory, options, environment, isSync) { + if (!filename) { + logger.warn('getFileManager called with no filename.. Please report this issue. continuing.'); + } + + if (currentDirectory == null) { + logger.warn('getFileManager called with null directory.. Please report this issue. continuing.'); + } + + let fileManagers = this.fileManagers; + + if (options.pluginManager) { + fileManagers = [].concat(fileManagers).concat(options.pluginManager.getFileManagers()); + } + + for (let i = fileManagers.length - 1; i >= 0; i--) { + const fileManager = fileManagers[i]; + + if (fileManager[isSync ? 'supportsSync' : 'supports'](filename, currentDirectory, options, environment)) { + return fileManager; + } + } + + return null; + } + + addFileManager(fileManager) { + this.fileManagers.push(fileManager); + } + + clearFileManagers() { + this.fileManagers = []; + } + +} + +class AbstractPluginLoader { + constructor() { + // Implemented by Node.js plugin loader + this.require = () => null; + } + + evalPlugin(contents, context, imports, pluginOptions, fileInfo) { + let loader; + let registry; + let pluginObj; + let localModule; + let pluginManager; + let filename; + let result; + pluginManager = context.pluginManager; + + if (fileInfo) { + if (typeof fileInfo === 'string') { + filename = fileInfo; + } else { + filename = fileInfo.filename; + } + } + + const shortname = new this.less.FileManager().extractUrlParts(filename).filename; + + if (filename) { + pluginObj = pluginManager.get(filename); + + if (pluginObj) { + result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); + + if (result) { + return result; + } + + try { + if (pluginObj.use) { + pluginObj.use.call(this.context, pluginObj); + } + } catch (e) { + e.message = e.message || 'Error during @plugin call'; + return new LessError(e, imports, filename); + } + + return pluginObj; + } + } + + localModule = { + exports: {}, + pluginManager, + fileInfo + }; + registry = functionRegistry.create(); + + const registerPlugin = obj => { + pluginObj = obj; + }; + + try { + loader = new Function('module', 'require', 'registerPlugin', 'functions', 'tree', 'less', 'fileInfo', contents); + loader(localModule, this.require(filename), registerPlugin, registry, this.less.tree, this.less, fileInfo); + } catch (e) { + return new LessError(e, imports, filename); + } + + if (!pluginObj) { + pluginObj = localModule.exports; + } + + pluginObj = this.validatePlugin(pluginObj, filename, shortname); + + if (pluginObj instanceof LessError) { + return pluginObj; + } + + if (pluginObj) { + pluginObj.imports = imports; + pluginObj.filename = filename; // For < 3.x (or unspecified minVersion) - setOptions() before install() + + if (!pluginObj.minVersion || this.compareVersion('3.0.0', pluginObj.minVersion) < 0) { + result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); + + if (result) { + return result; + } + } // Run on first load + + + pluginManager.addPlugin(pluginObj, fileInfo.filename, registry); + pluginObj.functions = registry.getLocalFunctions(); // Need to call setOptions again because the pluginObj might have functions + + result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); + + if (result) { + return result; + } // Run every @plugin call + + + try { + if (pluginObj.use) { + pluginObj.use.call(this.context, pluginObj); + } + } catch (e) { + e.message = e.message || 'Error during @plugin call'; + return new LessError(e, imports, filename); + } + } else { + return new LessError({ + message: 'Not a valid plugin' + }, imports, filename); + } + + return pluginObj; + } + + trySetOptions(plugin, filename, name, options) { + if (options && !plugin.setOptions) { + return new LessError({ + message: `Options have been provided but the plugin ${name} does not support any options.` + }); + } + + try { + plugin.setOptions && plugin.setOptions(options); + } catch (e) { + return new LessError(e); + } + } + + validatePlugin(plugin, filename, name) { + if (plugin) { + // support plugins being a function + // so that the plugin can be more usable programmatically + if (typeof plugin === 'function') { + plugin = new plugin(); + } + + if (plugin.minVersion) { + if (this.compareVersion(plugin.minVersion, this.less.version) < 0) { + return new LessError({ + message: `Plugin ${name} requires version ${this.versionToString(plugin.minVersion)}` + }); + } + } + + return plugin; + } + + return null; + } + + compareVersion(aVersion, bVersion) { + if (typeof aVersion === 'string') { + aVersion = aVersion.match(/^(\d+)\.?(\d+)?\.?(\d+)?/); + aVersion.shift(); + } + + for (let i = 0; i < aVersion.length; i++) { + if (aVersion[i] !== bVersion[i]) { + return parseInt(aVersion[i]) > parseInt(bVersion[i]) ? -1 : 1; + } + } + + return 0; + } + + versionToString(version) { + let versionString = ''; + + for (let i = 0; i < version.length; i++) { + versionString += (versionString ? '.' : '') + version[i]; + } + + return versionString; + } + + printUsage(plugins) { + for (let i = 0; i < plugins.length; i++) { + const plugin = plugins[i]; + + if (plugin.printUsage) { + plugin.printUsage(); + } + } + } + +} + +const _visitArgs = { + visitDeeper: true +}; +let _hasIndexed = false; + +function _noop(node) { + return node; +} + +function indexNodeTypes(parent, ticker) { + // add .typeIndex to tree node types for lookup table + let key; + let child; + + for (key in parent) { + /* eslint guard-for-in: 0 */ + child = parent[key]; + + switch (typeof child) { + case 'function': + // ignore bound functions directly on tree which do not have a prototype + // or aren't nodes + if (child.prototype && child.prototype.type) { + child.prototype.typeIndex = ticker++; + } + + break; + + case 'object': + ticker = indexNodeTypes(child, ticker); + break; + } + } + + return ticker; +} + +class Visitor { + constructor(implementation) { + this._implementation = implementation; + this._visitInCache = {}; + this._visitOutCache = {}; + + if (!_hasIndexed) { + indexNodeTypes(tree, 1); + _hasIndexed = true; + } + } + + visit(node) { + if (!node) { + return node; + } + + const nodeTypeIndex = node.typeIndex; + + if (!nodeTypeIndex) { + // MixinCall args aren't a node type? + if (node.value && node.value.typeIndex) { + this.visit(node.value); + } + + return node; + } + + const impl = this._implementation; + let func = this._visitInCache[nodeTypeIndex]; + let funcOut = this._visitOutCache[nodeTypeIndex]; + const visitArgs = _visitArgs; + let fnName; + visitArgs.visitDeeper = true; + + if (!func) { + fnName = `visit${node.type}`; + func = impl[fnName] || _noop; + funcOut = impl[`${fnName}Out`] || _noop; + this._visitInCache[nodeTypeIndex] = func; + this._visitOutCache[nodeTypeIndex] = funcOut; + } + + if (func !== _noop) { + const newNode = func.call(impl, node, visitArgs); + + if (node && impl.isReplacing) { + node = newNode; + } + } + + if (visitArgs.visitDeeper && node && node.accept) { + node.accept(this); + } + + if (funcOut != _noop) { + funcOut.call(impl, node); + } + + return node; + } + + visitArray(nodes, nonReplacing) { + if (!nodes) { + return nodes; + } + + const cnt = nodes.length; + let i; // Non-replacing + + if (nonReplacing || !this._implementation.isReplacing) { + for (i = 0; i < cnt; i++) { + this.visit(nodes[i]); + } + + return nodes; + } // Replacing + + + const out = []; + + for (i = 0; i < cnt; i++) { + const evald = this.visit(nodes[i]); + + if (evald === undefined) { + continue; + } + + if (!evald.splice) { + out.push(evald); + } else if (evald.length) { + this.flatten(evald, out); + } + } + + return out; + } + + flatten(arr, out) { + if (!out) { + out = []; + } + + let cnt; + let i; + let item; + let nestedCnt; + let j; + let nestedItem; + + for (i = 0, cnt = arr.length; i < cnt; i++) { + item = arr[i]; + + if (item === undefined) { + continue; + } + + if (!item.splice) { + out.push(item); + continue; + } + + for (j = 0, nestedCnt = item.length; j < nestedCnt; j++) { + nestedItem = item[j]; + + if (nestedItem === undefined) { + continue; + } + + if (!nestedItem.splice) { + out.push(nestedItem); + } else if (nestedItem.length) { + this.flatten(nestedItem, out); + } + } + } + + return out; + } + +} + +class ImportSequencer { + constructor(onSequencerEmpty) { + this.imports = []; + this.variableImports = []; + this._onSequencerEmpty = onSequencerEmpty; + this._currentDepth = 0; + } + + addImport(callback) { + const importSequencer = this; + const importItem = { + callback, + args: null, + isReady: false + }; + this.imports.push(importItem); + return function (...args) { + importItem.args = Array.prototype.slice.call(args, 0); + importItem.isReady = true; + importSequencer.tryRun(); + }; + } + + addVariableImport(callback) { + this.variableImports.push(callback); + } + + tryRun() { + this._currentDepth++; + + try { + while (true) { + while (this.imports.length > 0) { + const importItem = this.imports[0]; + + if (!importItem.isReady) { + return; + } + + this.imports = this.imports.slice(1); + importItem.callback.apply(null, importItem.args); + } + + if (this.variableImports.length === 0) { + break; + } + + const variableImport = this.variableImports[0]; + this.variableImports = this.variableImports.slice(1); + variableImport(); + } + } finally { + this._currentDepth--; + } + + if (this._currentDepth === 0 && this._onSequencerEmpty) { + this._onSequencerEmpty(); + } + } + +} + +const ImportVisitor = function ImportVisitor(importer, finish) { + this._visitor = new Visitor(this); + this._importer = importer; + this._finish = finish; + this.context = new contexts.Eval(); + this.importCount = 0; + this.onceFileDetectionMap = {}; + this.recursionDetector = {}; + this._sequencer = new ImportSequencer(this._onSequencerEmpty.bind(this)); +}; + +ImportVisitor.prototype = { + isReplacing: false, + run: function run(root) { + try { + // process the contents + this._visitor.visit(root); + } catch (e) { + this.error = e; + } + + this.isFinished = true; + + this._sequencer.tryRun(); + }, + _onSequencerEmpty: function _onSequencerEmpty() { + if (!this.isFinished) { + return; + } + + this._finish(this.error); + }, + visitImport: function visitImport(importNode, visitArgs) { + const inlineCSS = importNode.options.inline; + + if (!importNode.css || inlineCSS) { + const context = new contexts.Eval(this.context, copyArray(this.context.frames)); + const importParent = context.frames[0]; + this.importCount++; + + if (importNode.isVariableImport()) { + this._sequencer.addVariableImport(this.processImportNode.bind(this, importNode, context, importParent)); + } else { + this.processImportNode(importNode, context, importParent); + } + } + + visitArgs.visitDeeper = false; + }, + processImportNode: function processImportNode(importNode, context, importParent) { + let evaldImportNode; + const inlineCSS = importNode.options.inline; + + try { + evaldImportNode = importNode.evalForImport(context); + } catch (e) { + if (!e.filename) { + e.index = importNode.getIndex(); + e.filename = importNode.fileInfo().filename; + } // attempt to eval properly and treat as css + + + importNode.css = true; // if that fails, this error will be thrown + + importNode.error = e; + } + + if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) { + if (evaldImportNode.options.multiple) { + context.importMultiple = true; + } // try appending if we haven't determined if it is css or not + + + const tryAppendLessExtension = evaldImportNode.css === undefined; + + for (let i = 0; i < importParent.rules.length; i++) { + if (importParent.rules[i] === importNode) { + importParent.rules[i] = evaldImportNode; + break; + } + } + + const onImported = this.onImported.bind(this, evaldImportNode, context); + + const sequencedOnImported = this._sequencer.addImport(onImported); + + this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.fileInfo(), evaldImportNode.options, sequencedOnImported); + } else { + this.importCount--; + + if (this.isFinished) { + this._sequencer.tryRun(); + } + } + }, + onImported: function onImported(importNode, context, e, root, importedAtRoot, fullPath) { + if (e) { + if (!e.filename) { + e.index = importNode.getIndex(); + e.filename = importNode.fileInfo().filename; + } + + this.error = e; + } + + const importVisitor = this; + const inlineCSS = importNode.options.inline; + const isPlugin = importNode.options.isPlugin; + const isOptional = importNode.options.optional; + const duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector; + + if (!context.importMultiple) { + if (duplicateImport) { + importNode.skip = true; + } else { + importNode.skip = () => { + if (fullPath in importVisitor.onceFileDetectionMap) { + return true; + } + + importVisitor.onceFileDetectionMap[fullPath] = true; + return false; + }; + } + } + + if (!fullPath && isOptional) { + importNode.skip = true; + } + + if (root) { + importNode.root = root; + importNode.importedFilename = fullPath; + + if (!inlineCSS && !isPlugin && (context.importMultiple || !duplicateImport)) { + importVisitor.recursionDetector[fullPath] = true; + const oldContext = this.context; + this.context = context; + + try { + this._visitor.visit(root); + } catch (e) { + this.error = e; + } + + this.context = oldContext; + } + } + + importVisitor.importCount--; + + if (importVisitor.isFinished) { + importVisitor._sequencer.tryRun(); + } + }, + visitDeclaration: function visitDeclaration(declNode, visitArgs) { + if (declNode.value.type === 'DetachedRuleset') { + this.context.frames.unshift(declNode); + } else { + visitArgs.visitDeeper = false; + } + }, + visitDeclarationOut: function visitDeclarationOut(declNode) { + if (declNode.value.type === 'DetachedRuleset') { + this.context.frames.shift(); + } + }, + visitAtRule: function visitAtRule(atRuleNode, visitArgs) { + this.context.frames.unshift(atRuleNode); + }, + visitAtRuleOut: function visitAtRuleOut(atRuleNode) { + this.context.frames.shift(); + }, + visitMixinDefinition: function visitMixinDefinition(mixinDefinitionNode, visitArgs) { + this.context.frames.unshift(mixinDefinitionNode); + }, + visitMixinDefinitionOut: function visitMixinDefinitionOut(mixinDefinitionNode) { + this.context.frames.shift(); + }, + visitRuleset: function visitRuleset(rulesetNode, visitArgs) { + this.context.frames.unshift(rulesetNode); + }, + visitRulesetOut: function visitRulesetOut(rulesetNode) { + this.context.frames.shift(); + }, + visitMedia: function visitMedia(mediaNode, visitArgs) { + this.context.frames.unshift(mediaNode.rules[0]); + }, + visitMediaOut: function visitMediaOut(mediaNode) { + this.context.frames.shift(); + } +}; + +class SetTreeVisibilityVisitor { + constructor(visible) { + this.visible = visible; + } + + run(root) { + this.visit(root); + } + + visitArray(nodes) { + if (!nodes) { + return nodes; + } + + const cnt = nodes.length; + let i; + + for (i = 0; i < cnt; i++) { + this.visit(nodes[i]); + } + + return nodes; + } + + visit(node) { + if (!node) { + return node; + } + + if (node.constructor === Array) { + return this.visitArray(node); + } + + if (!node.blocksVisibility || node.blocksVisibility()) { + return node; + } + + if (this.visible) { + node.ensureVisibility(); + } else { + node.ensureInvisibility(); + } + + node.accept(this); + return node; + } + +} + +/* jshint loopfunc:true */ + +class ExtendFinderVisitor { + constructor() { + this._visitor = new Visitor(this); + this.contexts = []; + this.allExtendsStack = [[]]; + } + + run(root) { + root = this._visitor.visit(root); + root.allExtends = this.allExtendsStack[0]; + return root; + } + + visitDeclaration(declNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitMixinDefinition(mixinDefinitionNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitRuleset(rulesetNode, visitArgs) { + if (rulesetNode.root) { + return; + } + + let i; + let j; + let extend; + const allSelectorsExtendList = []; + let extendList; // get &:extend(.a); rules which apply to all selectors in this ruleset + + const rules = rulesetNode.rules; + const ruleCnt = rules ? rules.length : 0; + + for (i = 0; i < ruleCnt; i++) { + if (rulesetNode.rules[i] instanceof tree.Extend) { + allSelectorsExtendList.push(rules[i]); + rulesetNode.extendOnEveryPath = true; + } + } // now find every selector and apply the extends that apply to all extends + // and the ones which apply to an individual extend + + + const paths = rulesetNode.paths; + + for (i = 0; i < paths.length; i++) { + const selectorPath = paths[i]; + const selector = selectorPath[selectorPath.length - 1]; + const selExtendList = selector.extendList; + extendList = selExtendList ? copyArray(selExtendList).concat(allSelectorsExtendList) : allSelectorsExtendList; + + if (extendList) { + extendList = extendList.map(allSelectorsExtend => allSelectorsExtend.clone()); + } + + for (j = 0; j < extendList.length; j++) { + this.foundExtends = true; + extend = extendList[j]; + extend.findSelfSelectors(selectorPath); + extend.ruleset = rulesetNode; + + if (j === 0) { + extend.firstExtendOnThisSelectorPath = true; + } + + this.allExtendsStack[this.allExtendsStack.length - 1].push(extend); + } + } + + this.contexts.push(rulesetNode.selectors); + } + + visitRulesetOut(rulesetNode) { + if (!rulesetNode.root) { + this.contexts.length = this.contexts.length - 1; + } + } + + visitMedia(mediaNode, visitArgs) { + mediaNode.allExtends = []; + this.allExtendsStack.push(mediaNode.allExtends); + } + + visitMediaOut(mediaNode) { + this.allExtendsStack.length = this.allExtendsStack.length - 1; + } + + visitAtRule(atRuleNode, visitArgs) { + atRuleNode.allExtends = []; + this.allExtendsStack.push(atRuleNode.allExtends); + } + + visitAtRuleOut(atRuleNode) { + this.allExtendsStack.length = this.allExtendsStack.length - 1; + } + +} + +class ProcessExtendsVisitor { + constructor() { + this._visitor = new Visitor(this); + } + + run(root) { + const extendFinder = new ExtendFinderVisitor(); + this.extendIndices = {}; + extendFinder.run(root); + + if (!extendFinder.foundExtends) { + return root; + } + + root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends)); + this.allExtendsStack = [root.allExtends]; + + const newRoot = this._visitor.visit(root); + + this.checkExtendsForNonMatched(root.allExtends); + return newRoot; + } + + checkExtendsForNonMatched(extendList) { + const indices = this.extendIndices; + extendList.filter(extend => !extend.hasFoundMatches && extend.parent_ids.length == 1).forEach(extend => { + let selector = '_unknown_'; + + try { + selector = extend.selector.toCSS({}); + } catch (_) {} + + if (!indices[`${extend.index} ${selector}`]) { + indices[`${extend.index} ${selector}`] = true; + logger.warn(`extend '${selector}' has no matches`); + } + }); + } + + doExtendChaining(extendsList, extendsListTarget, iterationCount) { + // + // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering + // and pasting the selector we would do normally, but we are also adding an extend with the same target selector + // this means this new extend can then go and alter other extends + // + // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors + // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already + // processed if we look at each selector at a time, as is done in visitRuleset + let extendIndex; + let targetExtendIndex; + let matches; + const extendsToAdd = []; + let newSelector; + const extendVisitor = this; + let selectorPath; + let extend; + let targetExtend; + let newExtend; + iterationCount = iterationCount || 0; // loop through comparing every extend with every target extend. + // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place + // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one + // and the second is the target. + // the separation into two lists allows us to process a subset of chains with a bigger set, as is the + // case when processing media queries + + for (extendIndex = 0; extendIndex < extendsList.length; extendIndex++) { + for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) { + extend = extendsList[extendIndex]; + targetExtend = extendsListTarget[targetExtendIndex]; // look for circular references + + if (extend.parent_ids.indexOf(targetExtend.object_id) >= 0) { + continue; + } // find a match in the target extends self selector (the bit before :extend) + + + selectorPath = [targetExtend.selfSelectors[0]]; + matches = extendVisitor.findMatch(extend, selectorPath); + + if (matches.length) { + extend.hasFoundMatches = true; // we found a match, so for each self selector.. + + extend.selfSelectors.forEach(selfSelector => { + const info = targetExtend.visibilityInfo(); // process the extend as usual + + newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector, extend.isVisible()); // but now we create a new extend from it + + newExtend = new tree.Extend(targetExtend.selector, targetExtend.option, 0, targetExtend.fileInfo(), info); + newExtend.selfSelectors = newSelector; // add the extend onto the list of extends for that selector + + newSelector[newSelector.length - 1].extendList = [newExtend]; // record that we need to add it. + + extendsToAdd.push(newExtend); + newExtend.ruleset = targetExtend.ruleset; // remember its parents for circular references + + newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids); // only process the selector once.. if we have :extend(.a,.b) then multiple + // extends will look at the same selector path, so when extending + // we know that any others will be duplicates in terms of what is added to the css + + if (targetExtend.firstExtendOnThisSelectorPath) { + newExtend.firstExtendOnThisSelectorPath = true; + targetExtend.ruleset.paths.push(newSelector); + } + }); + } + } + } + + if (extendsToAdd.length) { + // try to detect circular references to stop a stack overflow. + // may no longer be needed. + this.extendChainCount++; + + if (iterationCount > 100) { + let selectorOne = '{unable to calculate}'; + let selectorTwo = '{unable to calculate}'; + + try { + selectorOne = extendsToAdd[0].selfSelectors[0].toCSS(); + selectorTwo = extendsToAdd[0].selector.toCSS(); + } catch (e) {} + + throw { + message: `extend circular reference detected. One of the circular extends is currently:${selectorOne}:extend(${selectorTwo})` + }; + } // now process the new extends on the existing rules so that we can handle a extending b extending c extending + // d extending e... + + + return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1)); + } else { + return extendsToAdd; + } + } + + visitDeclaration(ruleNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitMixinDefinition(mixinDefinitionNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitSelector(selectorNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitRuleset(rulesetNode, visitArgs) { + if (rulesetNode.root) { + return; + } + + let matches; + let pathIndex; + let extendIndex; + const allExtends = this.allExtendsStack[this.allExtendsStack.length - 1]; + const selectorsToAdd = []; + const extendVisitor = this; + let selectorPath; // look at each selector path in the ruleset, find any extend matches and then copy, find and replace + + for (extendIndex = 0; extendIndex < allExtends.length; extendIndex++) { + for (pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) { + selectorPath = rulesetNode.paths[pathIndex]; // extending extends happens initially, before the main pass + + if (rulesetNode.extendOnEveryPath) { + continue; + } + + const extendList = selectorPath[selectorPath.length - 1].extendList; + + if (extendList && extendList.length) { + continue; + } + + matches = this.findMatch(allExtends[extendIndex], selectorPath); + + if (matches.length) { + allExtends[extendIndex].hasFoundMatches = true; + allExtends[extendIndex].selfSelectors.forEach(selfSelector => { + let extendedSelectors; + extendedSelectors = extendVisitor.extendSelector(matches, selectorPath, selfSelector, allExtends[extendIndex].isVisible()); + selectorsToAdd.push(extendedSelectors); + }); + } + } + } + + rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd); + } + + findMatch(extend, haystackSelectorPath) { + // + // look through the haystack selector path to try and find the needle - extend.selector + // returns an array of selector matches that can then be replaced + // + let haystackSelectorIndex; + let hackstackSelector; + let hackstackElementIndex; + let haystackElement; + let targetCombinator; + let i; + const extendVisitor = this; + const needleElements = extend.selector.elements; + const potentialMatches = []; + let potentialMatch; + const matches = []; // loop through the haystack elements + + for (haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) { + hackstackSelector = haystackSelectorPath[haystackSelectorIndex]; + + for (hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) { + haystackElement = hackstackSelector.elements[hackstackElementIndex]; // if we allow elements before our match we can add a potential match every time. otherwise only at the first element. + + if (extend.allowBefore || haystackSelectorIndex === 0 && hackstackElementIndex === 0) { + potentialMatches.push({ + pathIndex: haystackSelectorIndex, + index: hackstackElementIndex, + matched: 0, + initialCombinator: haystackElement.combinator + }); + } + + for (i = 0; i < potentialMatches.length; i++) { + potentialMatch = potentialMatches[i]; // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't + // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to + // work out what the resulting combinator will be + + targetCombinator = haystackElement.combinator.value; + + if (targetCombinator === '' && hackstackElementIndex === 0) { + targetCombinator = ' '; + } // if we don't match, null our match to indicate failure + + + if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) || potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator) { + potentialMatch = null; + } else { + potentialMatch.matched++; + } // if we are still valid and have finished, test whether we have elements after and whether these are allowed + + + if (potentialMatch) { + potentialMatch.finished = potentialMatch.matched === needleElements.length; + + if (potentialMatch.finished && !extend.allowAfter && (hackstackElementIndex + 1 < hackstackSelector.elements.length || haystackSelectorIndex + 1 < haystackSelectorPath.length)) { + potentialMatch = null; + } + } // if null we remove, if not, we are still valid, so either push as a valid match or continue + + + if (potentialMatch) { + if (potentialMatch.finished) { + potentialMatch.length = needleElements.length; + potentialMatch.endPathIndex = haystackSelectorIndex; + potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match + + potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again + + matches.push(potentialMatch); + } + } else { + potentialMatches.splice(i, 1); + i--; + } + } + } + } + + return matches; + } + + isElementValuesEqual(elementValue1, elementValue2) { + if (typeof elementValue1 === 'string' || typeof elementValue2 === 'string') { + return elementValue1 === elementValue2; + } + + if (elementValue1 instanceof tree.Attribute) { + if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) { + return false; + } + + if (!elementValue1.value || !elementValue2.value) { + if (elementValue1.value || elementValue2.value) { + return false; + } + + return true; + } + + elementValue1 = elementValue1.value.value || elementValue1.value; + elementValue2 = elementValue2.value.value || elementValue2.value; + return elementValue1 === elementValue2; + } + + elementValue1 = elementValue1.value; + elementValue2 = elementValue2.value; + + if (elementValue1 instanceof tree.Selector) { + if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) { + return false; + } + + for (let i = 0; i < elementValue1.elements.length; i++) { + if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) { + if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) { + return false; + } + } + + if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) { + return false; + } + } + + return true; + } + + return false; + } + + extendSelector(matches, selectorPath, replacementSelector, isVisible) { + // for a set of matches, replace each match with the replacement selector + let currentSelectorPathIndex = 0; + let currentSelectorPathElementIndex = 0; + let path = []; + let matchIndex; + let selector; + let firstElement; + let match; + let newElements; + + for (matchIndex = 0; matchIndex < matches.length; matchIndex++) { + match = matches[matchIndex]; + selector = selectorPath[match.pathIndex]; + firstElement = new tree.Element(match.initialCombinator, replacementSelector.elements[0].value, replacementSelector.elements[0].isVariable, replacementSelector.elements[0].getIndex(), replacementSelector.elements[0].fileInfo()); + + if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) { + path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); + currentSelectorPathElementIndex = 0; + currentSelectorPathIndex++; + } + + newElements = selector.elements.slice(currentSelectorPathElementIndex, match.index).concat([firstElement]).concat(replacementSelector.elements.slice(1)); + + if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) { + path[path.length - 1].elements = path[path.length - 1].elements.concat(newElements); + } else { + path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex)); + path.push(new tree.Selector(newElements)); + } + + currentSelectorPathIndex = match.endPathIndex; + currentSelectorPathElementIndex = match.endPathElementIndex; + + if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) { + currentSelectorPathElementIndex = 0; + currentSelectorPathIndex++; + } + } + + if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) { + path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); + currentSelectorPathIndex++; + } + + path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length)); + path = path.map(currentValue => { + // we can re-use elements here, because the visibility property matters only for selectors + const derived = currentValue.createDerived(currentValue.elements); + + if (isVisible) { + derived.ensureVisibility(); + } else { + derived.ensureInvisibility(); + } + + return derived; + }); + return path; + } + + visitMedia(mediaNode, visitArgs) { + let newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); + newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends)); + this.allExtendsStack.push(newAllExtends); + } + + visitMediaOut(mediaNode) { + const lastIndex = this.allExtendsStack.length - 1; + this.allExtendsStack.length = lastIndex; + } + + visitAtRule(atRuleNode, visitArgs) { + let newAllExtends = atRuleNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); + newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, atRuleNode.allExtends)); + this.allExtendsStack.push(newAllExtends); + } + + visitAtRuleOut(atRuleNode) { + const lastIndex = this.allExtendsStack.length - 1; + this.allExtendsStack.length = lastIndex; + } + +} + +class JoinSelectorVisitor { + constructor() { + this.contexts = [[]]; + this._visitor = new Visitor(this); + } + + run(root) { + return this._visitor.visit(root); + } + + visitDeclaration(declNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitMixinDefinition(mixinDefinitionNode, visitArgs) { + visitArgs.visitDeeper = false; + } + + visitRuleset(rulesetNode, visitArgs) { + const context = this.contexts[this.contexts.length - 1]; + const paths = []; + let selectors; + this.contexts.push(paths); + + if (!rulesetNode.root) { + selectors = rulesetNode.selectors; + + if (selectors) { + selectors = selectors.filter(selector => selector.getIsOutput()); + rulesetNode.selectors = selectors.length ? selectors : selectors = null; + + if (selectors) { + rulesetNode.joinSelectors(paths, context, selectors); + } + } + + if (!selectors) { + rulesetNode.rules = null; + } + + rulesetNode.paths = paths; + } + } + + visitRulesetOut(rulesetNode) { + this.contexts.length = this.contexts.length - 1; + } + + visitMedia(mediaNode, visitArgs) { + const context = this.contexts[this.contexts.length - 1]; + mediaNode.rules[0].root = context.length === 0 || context[0].multiMedia; + } + + visitAtRule(atRuleNode, visitArgs) { + const context = this.contexts[this.contexts.length - 1]; + + if (atRuleNode.rules && atRuleNode.rules.length) { + atRuleNode.rules[0].root = atRuleNode.isRooted || context.length === 0 || null; + } + } + +} + +class CSSVisitorUtils { + constructor(context) { + this._visitor = new Visitor(this); + this._context = context; + } + + containsSilentNonBlockedChild(bodyRules) { + let rule; + + if (!bodyRules) { + return false; + } + + for (let r = 0; r < bodyRules.length; r++) { + rule = bodyRules[r]; + + if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) { + // the atrule contains something that was referenced (likely by extend) + // therefore it needs to be shown in output too + return true; + } + } + + return false; + } + + keepOnlyVisibleChilds(owner) { + if (owner && owner.rules) { + owner.rules = owner.rules.filter(thing => thing.isVisible()); + } + } + + isEmpty(owner) { + return owner && owner.rules ? owner.rules.length === 0 : true; + } + + hasVisibleSelector(rulesetNode) { + return rulesetNode && rulesetNode.paths ? rulesetNode.paths.length > 0 : false; + } + + resolveVisibility(node, originalRules) { + if (!node.blocksVisibility()) { + if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) { + return; + } + + return node; + } + + const compiledRulesBody = node.rules[0]; + this.keepOnlyVisibleChilds(compiledRulesBody); + + if (this.isEmpty(compiledRulesBody)) { + return; + } + + node.ensureVisibility(); + node.removeVisibilityBlock(); + return node; + } + + isVisibleRuleset(rulesetNode) { + if (rulesetNode.firstRoot) { + return true; + } + + if (this.isEmpty(rulesetNode)) { + return false; + } + + if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) { + return false; + } + + return true; + } + +} + +const ToCSSVisitor = function ToCSSVisitor(context) { + this._visitor = new Visitor(this); + this._context = context; + this.utils = new CSSVisitorUtils(context); +}; + +ToCSSVisitor.prototype = { + isReplacing: true, + run: function run(root) { + return this._visitor.visit(root); + }, + visitDeclaration: function visitDeclaration(declNode, visitArgs) { + if (declNode.blocksVisibility() || declNode.variable) { + return; + } + + return declNode; + }, + visitMixinDefinition: function visitMixinDefinition(mixinNode, visitArgs) { + // mixin definitions do not get eval'd - this means they keep state + // so we have to clear that state here so it isn't used if toCSS is called twice + mixinNode.frames = []; + }, + visitExtend: function visitExtend(extendNode, visitArgs) {}, + visitComment: function visitComment(commentNode, visitArgs) { + if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) { + return; + } + + return commentNode; + }, + visitMedia: function visitMedia(mediaNode, visitArgs) { + const originalRules = mediaNode.rules[0].rules; + mediaNode.accept(this._visitor); + visitArgs.visitDeeper = false; + return this.utils.resolveVisibility(mediaNode, originalRules); + }, + visitImport: function visitImport(importNode, visitArgs) { + if (importNode.blocksVisibility()) { + return; + } + + return importNode; + }, + visitAtRule: function visitAtRule(atRuleNode, visitArgs) { + if (atRuleNode.rules && atRuleNode.rules.length) { + return this.visitAtRuleWithBody(atRuleNode, visitArgs); + } else { + return this.visitAtRuleWithoutBody(atRuleNode, visitArgs); + } + }, + visitAnonymous: function visitAnonymous(anonymousNode, visitArgs) { + if (!anonymousNode.blocksVisibility()) { + anonymousNode.accept(this._visitor); + return anonymousNode; + } + }, + visitAtRuleWithBody: function visitAtRuleWithBody(atRuleNode, visitArgs) { + // if there is only one nested ruleset and that one has no path, then it is + // just fake ruleset + function hasFakeRuleset(atRuleNode) { + const bodyRules = atRuleNode.rules; + return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0); + } + + function getBodyRules(atRuleNode) { + const nodeRules = atRuleNode.rules; + + if (hasFakeRuleset(atRuleNode)) { + return nodeRules[0].rules; + } + + return nodeRules; + } // it is still true that it is only one ruleset in array + // this is last such moment + // process childs + + + const originalRules = getBodyRules(atRuleNode); + atRuleNode.accept(this._visitor); + visitArgs.visitDeeper = false; + + if (!this.utils.isEmpty(atRuleNode)) { + this._mergeRules(atRuleNode.rules[0].rules); + } + + return this.utils.resolveVisibility(atRuleNode, originalRules); + }, + visitAtRuleWithoutBody: function visitAtRuleWithoutBody(atRuleNode, visitArgs) { + if (atRuleNode.blocksVisibility()) { + return; + } + + if (atRuleNode.name === '@charset') { + // Only output the debug info together with subsequent @charset definitions + // a comment (or @media statement) before the actual @charset atrule would + // be considered illegal css as it has to be on the first line + if (this.charset) { + if (atRuleNode.debugInfo) { + const comment = new tree.Comment(`/* ${atRuleNode.toCSS(this._context).replace(/\n/g, '')} */\n`); + comment.debugInfo = atRuleNode.debugInfo; + return this._visitor.visit(comment); + } + + return; + } + + this.charset = true; + } + + return atRuleNode; + }, + checkValidNodes: function checkValidNodes(rules, isRoot) { + if (!rules) { + return; + } + + for (let i = 0; i < rules.length; i++) { + const ruleNode = rules[i]; + + if (isRoot && ruleNode instanceof tree.Declaration && !ruleNode.variable) { + throw { + message: 'Properties must be inside selector blocks. They cannot be in the root', + index: ruleNode.getIndex(), + filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename + }; + } + + if (ruleNode instanceof tree.Call) { + throw { + message: `Function '${ruleNode.name}' is undefined`, + index: ruleNode.getIndex(), + filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename + }; + } + + if (ruleNode.type && !ruleNode.allowRoot) { + throw { + message: `${ruleNode.type} node returned by a function is not valid here`, + index: ruleNode.getIndex(), + filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename + }; + } + } + }, + visitRuleset: function visitRuleset(rulesetNode, visitArgs) { + // at this point rulesets are nested into each other + let rule; + const rulesets = []; + this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot); + + if (!rulesetNode.root) { + // remove invisible paths + this._compileRulesetPaths(rulesetNode); // remove rulesets from this ruleset body and compile them separately + + + const nodeRules = rulesetNode.rules; + let nodeRuleCnt = nodeRules ? nodeRules.length : 0; + + for (let i = 0; i < nodeRuleCnt;) { + rule = nodeRules[i]; + + if (rule && rule.rules) { + // visit because we are moving them out from being a child + rulesets.push(this._visitor.visit(rule)); + nodeRules.splice(i, 1); + nodeRuleCnt--; + continue; + } + + i++; + } // accept the visitor to remove rules and refactor itself + // then we can decide nogw whether we want it or not + // compile body + + + if (nodeRuleCnt > 0) { + rulesetNode.accept(this._visitor); + } else { + rulesetNode.rules = null; + } + + visitArgs.visitDeeper = false; + } else { + // if (! rulesetNode.root) { + rulesetNode.accept(this._visitor); + visitArgs.visitDeeper = false; + } + + if (rulesetNode.rules) { + this._mergeRules(rulesetNode.rules); + + this._removeDuplicateRules(rulesetNode.rules); + } // now decide whether we keep the ruleset + + + if (this.utils.isVisibleRuleset(rulesetNode)) { + rulesetNode.ensureVisibility(); + rulesets.splice(0, 0, rulesetNode); + } + + if (rulesets.length === 1) { + return rulesets[0]; + } + + return rulesets; + }, + _compileRulesetPaths: function _compileRulesetPaths(rulesetNode) { + if (rulesetNode.paths) { + rulesetNode.paths = rulesetNode.paths.filter(p => { + let i; + + if (p[0].elements[0].combinator.value === ' ') { + p[0].elements[0].combinator = new tree.Combinator(''); + } + + for (i = 0; i < p.length; i++) { + if (p[i].isVisible() && p[i].getIsOutput()) { + return true; + } + } + + return false; + }); + } + }, + _removeDuplicateRules: function _removeDuplicateRules(rules) { + if (!rules) { + return; + } // remove duplicates + + + const ruleCache = {}; + let ruleList; + let rule; + let i; + + for (i = rules.length - 1; i >= 0; i--) { + rule = rules[i]; + + if (rule instanceof tree.Declaration) { + if (!ruleCache[rule.name]) { + ruleCache[rule.name] = rule; + } else { + ruleList = ruleCache[rule.name]; + + if (ruleList instanceof tree.Declaration) { + ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._context)]; + } + + const ruleCSS = rule.toCSS(this._context); + + if (ruleList.indexOf(ruleCSS) !== -1) { + rules.splice(i, 1); + } else { + ruleList.push(ruleCSS); + } + } + } + } + }, + _mergeRules: function _mergeRules(rules) { + if (!rules) { + return; + } + + const groups = {}; + const groupsArr = []; + + for (let i = 0; i < rules.length; i++) { + const rule = rules[i]; + + if (rule.merge) { + const key = rule.name; + groups[key] ? rules.splice(i--, 1) : groupsArr.push(groups[key] = []); + groups[key].push(rule); + } + } + + groupsArr.forEach(group => { + if (group.length > 0) { + const result = group[0]; + let space = []; + const comma = [new tree.Expression(space)]; + group.forEach(rule => { + if (rule.merge === '+' && space.length > 0) { + comma.push(new tree.Expression(space = [])); + } + + space.push(rule.value); + result.important = result.important || rule.important; + }); + result.value = new tree.Value(comma); + } + }); + } +}; + +var visitors = { + Visitor, + ImportVisitor, + MarkVisibleSelectorsVisitor: SetTreeVisibilityVisitor, + ExtendVisitor: ProcessExtendsVisitor, + JoinSelectorVisitor, + ToCSSVisitor +}; + +// Split the input into chunks. +var chunker = ((input, fail) => { + const len = input.length; + let level = 0; + let parenLevel = 0; + let lastOpening; + let lastOpeningParen; + let lastMultiComment; + let lastMultiCommentEndBrace; + const chunks = []; + let emitFrom = 0; + let chunkerCurrentIndex; + let currentChunkStartIndex; + let cc; + let cc2; + let matched; + + function emitChunk(force) { + const len = chunkerCurrentIndex - emitFrom; + + if (len < 512 && !force || !len) { + return; + } + + chunks.push(input.slice(emitFrom, chunkerCurrentIndex + 1)); + emitFrom = chunkerCurrentIndex + 1; + } + + for (chunkerCurrentIndex = 0; chunkerCurrentIndex < len; chunkerCurrentIndex++) { + cc = input.charCodeAt(chunkerCurrentIndex); + + if (cc >= 97 && cc <= 122 || cc < 34) { + // a-z or whitespace + continue; + } + + switch (cc) { + case 40: + // ( + parenLevel++; + lastOpeningParen = chunkerCurrentIndex; + continue; + + case 41: + // ) + if (--parenLevel < 0) { + return fail('missing opening `(`', chunkerCurrentIndex); + } + + continue; + + case 59: + // ; + if (!parenLevel) { + emitChunk(); + } + + continue; + + case 123: + // { + level++; + lastOpening = chunkerCurrentIndex; + continue; + + case 125: + // } + if (--level < 0) { + return fail('missing opening `{`', chunkerCurrentIndex); + } + + if (!level && !parenLevel) { + emitChunk(); + } + + continue; + + case 92: + // \ + if (chunkerCurrentIndex < len - 1) { + chunkerCurrentIndex++; + continue; + } + + return fail('unescaped `\\`', chunkerCurrentIndex); + + case 34: + case 39: + case 96: + // ", ' and ` + matched = 0; + currentChunkStartIndex = chunkerCurrentIndex; + + for (chunkerCurrentIndex = chunkerCurrentIndex + 1; chunkerCurrentIndex < len; chunkerCurrentIndex++) { + cc2 = input.charCodeAt(chunkerCurrentIndex); + + if (cc2 > 96) { + continue; + } + + if (cc2 == cc) { + matched = 1; + break; + } + + if (cc2 == 92) { + // \ + if (chunkerCurrentIndex == len - 1) { + return fail('unescaped `\\`', chunkerCurrentIndex); + } + + chunkerCurrentIndex++; + } + } + + if (matched) { + continue; + } + + return fail(`unmatched \`${String.fromCharCode(cc)}\``, currentChunkStartIndex); + + case 47: + // /, check for comment + if (parenLevel || chunkerCurrentIndex == len - 1) { + continue; + } + + cc2 = input.charCodeAt(chunkerCurrentIndex + 1); + + if (cc2 == 47) { + // //, find lnfeed + for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len; chunkerCurrentIndex++) { + cc2 = input.charCodeAt(chunkerCurrentIndex); + + if (cc2 <= 13 && (cc2 == 10 || cc2 == 13)) { + break; + } + } + } else if (cc2 == 42) { + // /*, find */ + lastMultiComment = currentChunkStartIndex = chunkerCurrentIndex; + + for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len - 1; chunkerCurrentIndex++) { + cc2 = input.charCodeAt(chunkerCurrentIndex); + + if (cc2 == 125) { + lastMultiCommentEndBrace = chunkerCurrentIndex; + } + + if (cc2 != 42) { + continue; + } + + if (input.charCodeAt(chunkerCurrentIndex + 1) == 47) { + break; + } + } + + if (chunkerCurrentIndex == len - 1) { + return fail('missing closing `*/`', currentChunkStartIndex); + } + + chunkerCurrentIndex++; + } + + continue; + + case 42: + // *, check for unmatched */ + if (chunkerCurrentIndex < len - 1 && input.charCodeAt(chunkerCurrentIndex + 1) == 47) { + return fail('unmatched `/*`', chunkerCurrentIndex); + } + + continue; + } + } + + if (level !== 0) { + if (lastMultiComment > lastOpening && lastMultiCommentEndBrace > lastMultiComment) { + return fail('missing closing `}` or `*/`', lastOpening); + } else { + return fail('missing closing `}`', lastOpening); + } + } else if (parenLevel !== 0) { + return fail('missing closing `)`', lastOpeningParen); + } + + emitChunk(true); + return chunks; +}); + +var getParserInput = (() => { + let // Less input string + input; + let // current chunk + j; + const // holds state for backtracking + saveStack = []; + let // furthest index the parser has gone to + furthest; + let // if this is furthest we got to, this is the probably cause + furthestPossibleErrorMessage; + let // chunkified input + chunks; + let // current chunk + current; + let // index of current chunk, in `input` + currentPos; + const parserInput = {}; + const CHARCODE_SPACE = 32; + const CHARCODE_TAB = 9; + const CHARCODE_LF = 10; + const CHARCODE_CR = 13; + const CHARCODE_PLUS = 43; + const CHARCODE_COMMA = 44; + const CHARCODE_FORWARD_SLASH = 47; + const CHARCODE_9 = 57; + + function skipWhitespace(length) { + const oldi = parserInput.i; + const oldj = j; + const curr = parserInput.i - currentPos; + const endIndex = parserInput.i + current.length - curr; + const mem = parserInput.i += length; + const inp = input; + let c; + let nextChar; + let comment; + + for (; parserInput.i < endIndex; parserInput.i++) { + c = inp.charCodeAt(parserInput.i); + + if (parserInput.autoCommentAbsorb && c === CHARCODE_FORWARD_SLASH) { + nextChar = inp.charAt(parserInput.i + 1); + + if (nextChar === '/') { + comment = { + index: parserInput.i, + isLineComment: true + }; + let nextNewLine = inp.indexOf('\n', parserInput.i + 2); + + if (nextNewLine < 0) { + nextNewLine = endIndex; + } + + parserInput.i = nextNewLine; + comment.text = inp.substr(comment.index, parserInput.i - comment.index); + parserInput.commentStore.push(comment); + continue; + } else if (nextChar === '*') { + const nextStarSlash = inp.indexOf('*/', parserInput.i + 2); + + if (nextStarSlash >= 0) { + comment = { + index: parserInput.i, + text: inp.substr(parserInput.i, nextStarSlash + 2 - parserInput.i), + isLineComment: false + }; + parserInput.i += comment.text.length - 1; + parserInput.commentStore.push(comment); + continue; + } + } + + break; + } + + if (c !== CHARCODE_SPACE && c !== CHARCODE_LF && c !== CHARCODE_TAB && c !== CHARCODE_CR) { + break; + } + } + + current = current.slice(length + parserInput.i - mem + curr); + currentPos = parserInput.i; + + if (!current.length) { + if (j < chunks.length - 1) { + current = chunks[++j]; + skipWhitespace(0); // skip space at the beginning of a chunk + + return true; // things changed + } + + parserInput.finished = true; + } + + return oldi !== parserInput.i || oldj !== j; + } + + parserInput.save = () => { + currentPos = parserInput.i; + saveStack.push({ + current, + i: parserInput.i, + j + }); + }; + + parserInput.restore = possibleErrorMessage => { + if (parserInput.i > furthest || parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage) { + furthest = parserInput.i; + furthestPossibleErrorMessage = possibleErrorMessage; + } + + const state = saveStack.pop(); + current = state.current; + currentPos = parserInput.i = state.i; + j = state.j; + }; + + parserInput.forget = () => { + saveStack.pop(); + }; + + parserInput.isWhitespace = offset => { + const pos = parserInput.i + (offset || 0); + const code = input.charCodeAt(pos); + return code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF; + }; // Specialization of $(tok) + + + parserInput.$re = tok => { + if (parserInput.i > currentPos) { + current = current.slice(parserInput.i - currentPos); + currentPos = parserInput.i; + } + + const m = tok.exec(current); + + if (!m) { + return null; + } + + skipWhitespace(m[0].length); + + if (typeof m === 'string') { + return m; + } + + return m.length === 1 ? m[0] : m; + }; + + parserInput.$char = tok => { + if (input.charAt(parserInput.i) !== tok) { + return null; + } + + skipWhitespace(1); + return tok; + }; + + parserInput.$str = tok => { + const tokLength = tok.length; // https://jsperf.com/string-startswith/21 + + for (let i = 0; i < tokLength; i++) { + if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { + return null; + } + } + + skipWhitespace(tokLength); + return tok; + }; + + parserInput.$quoted = loc => { + const pos = loc || parserInput.i; + const startChar = input.charAt(pos); + + if (startChar !== '\'' && startChar !== '"') { + return; + } + + const length = input.length; + const currentPosition = pos; + + for (let i = 1; i + currentPosition < length; i++) { + const nextChar = input.charAt(i + currentPosition); + + switch (nextChar) { + case '\\': + i++; + continue; + + case '\r': + case '\n': + break; + + case startChar: + const str = input.substr(currentPosition, i + 1); + + if (!loc && loc !== 0) { + skipWhitespace(i + 1); + return str; + } + + return [startChar, str]; + + default: + } + } + + return null; + }; + /** + * Permissive parsing. Ignores everything except matching {} [] () and quotes + * until matching token (outside of blocks) + */ + + + parserInput.$parseUntil = tok => { + let quote = ''; + let returnVal = null; + let inComment = false; + let blockDepth = 0; + const blockStack = []; + const parseGroups = []; + const length = input.length; + const startPos = parserInput.i; + let lastPos = parserInput.i; + let i = parserInput.i; + let loop = true; + let testChar; + + if (typeof tok === 'string') { + testChar = char => char === tok; + } else { + testChar = char => tok.test(char); + } + + do { + let nextChar = input.charAt(i); + + if (blockDepth === 0 && testChar(nextChar)) { + returnVal = input.substr(lastPos, i - lastPos); + + if (returnVal) { + parseGroups.push(returnVal); + } else { + parseGroups.push(' '); + } + + returnVal = parseGroups; + skipWhitespace(i - startPos); + loop = false; + } else { + if (inComment) { + if (nextChar === '*' && input.charAt(i + 1) === '/') { + i++; + blockDepth--; + inComment = false; + } + + i++; + continue; + } + + switch (nextChar) { + case '\\': + i++; + nextChar = input.charAt(i); + parseGroups.push(input.substr(lastPos, i - lastPos + 1)); + lastPos = i + 1; + break; + + case '/': + if (input.charAt(i + 1) === '*') { + i++; + inComment = true; + blockDepth++; + } + + break; + + case '\'': + case '"': + quote = parserInput.$quoted(i); + + if (quote) { + parseGroups.push(input.substr(lastPos, i - lastPos), quote); + i += quote[1].length - 1; + lastPos = i + 1; + } else { + skipWhitespace(i - startPos); + returnVal = nextChar; + loop = false; + } + + break; + + case '{': + blockStack.push('}'); + blockDepth++; + break; + + case '(': + blockStack.push(')'); + blockDepth++; + break; + + case '[': + blockStack.push(']'); + blockDepth++; + break; + + case '}': + case ')': + case ']': + const expected = blockStack.pop(); + + if (nextChar === expected) { + blockDepth--; + } else { + // move the parser to the error and return expected + skipWhitespace(i - startPos); + returnVal = expected; + loop = false; + } + + } + + i++; + + if (i > length) { + loop = false; + } + } + } while (loop); + + return returnVal ? returnVal : null; + }; + + parserInput.autoCommentAbsorb = true; + parserInput.commentStore = []; + parserInput.finished = false; // Same as $(), but don't change the state of the parser, + // just return the match. + + parserInput.peek = tok => { + if (typeof tok === 'string') { + // https://jsperf.com/string-startswith/21 + for (let i = 0; i < tok.length; i++) { + if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { + return false; + } + } + + return true; + } else { + return tok.test(current); + } + }; // Specialization of peek() + // TODO remove or change some currentChar calls to peekChar + + + parserInput.peekChar = tok => input.charAt(parserInput.i) === tok; + + parserInput.currentChar = () => input.charAt(parserInput.i); + + parserInput.prevChar = () => input.charAt(parserInput.i - 1); + + parserInput.getInput = () => input; + + parserInput.peekNotNumeric = () => { + const c = input.charCodeAt(parserInput.i); // Is the first char of the dimension 0-9, '.', '+' or '-' + + return c > CHARCODE_9 || c < CHARCODE_PLUS || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA; + }; + + parserInput.start = (str, chunkInput, failFunction) => { + input = str; + parserInput.i = j = currentPos = furthest = 0; // chunking apparently makes things quicker (but my tests indicate + // it might actually make things slower in node at least) + // and it is a non-perfect parse - it can't recognise + // unquoted urls, meaning it can't distinguish comments + // meaning comments with quotes or {}() in them get 'counted' + // and then lead to parse errors. + // In addition if the chunking chunks in the wrong place we might + // not be able to parse a parser statement in one go + // this is officially deprecated but can be switched on via an option + // in the case it causes too much performance issues. + + if (chunkInput) { + chunks = chunker(str, failFunction); + } else { + chunks = [str]; + } + + current = chunks[0]; + skipWhitespace(0); + }; + + parserInput.end = () => { + let message; + const isFinished = parserInput.i >= input.length; + + if (parserInput.i < furthest) { + message = furthestPossibleErrorMessage; + parserInput.i = furthest; + } + + return { + isFinished, + furthest: parserInput.i, + furthestPossibleErrorMessage: message, + furthestReachedEnd: parserInput.i >= input.length - 1, + furthestChar: input[parserInput.i] + }; + }; + + return parserInput; +}); + +// less.js - parser +// +// A relatively straight-forward predictive parser. +// There is no tokenization/lexing stage, the input is parsed +// in one sweep. +// +// To make the parser fast enough to run in the browser, several +// optimization had to be made: +// +// - Matching and slicing on a huge input is often cause of slowdowns. +// The solution is to chunkify the input into smaller strings. +// The chunks are stored in the `chunks` var, +// `j` holds the current chunk index, and `currentPos` holds +// the index of the current chunk in relation to `input`. +// This gives us an almost 4x speed-up. +// +// - In many cases, we don't need to match individual tokens; +// for example, if a value doesn't hold any variables, operations +// or dynamic references, the parser can effectively 'skip' it, +// treating it as a literal. +// An example would be '1px solid #000' - which evaluates to itself, +// we don't need to know what the individual components are. +// The drawback, of course is that you don't get the benefits of +// syntax-checking on the CSS. This gives us a 50% speed-up in the parser, +// and a smaller speed-up in the code-gen. +// +// +// Token matching is done with the `$` function, which either takes +// a terminal string or regexp, or a non-terminal function to call. +// It also takes care of moving all the indices forwards. +// + +const Parser = function Parser(context, imports, fileInfo) { + let parsers; + const parserInput = getParserInput(); + + function error(msg, type) { + throw new LessError({ + index: parserInput.i, + filename: fileInfo.filename, + type: type || 'Syntax', + message: msg + }, imports); + } + + function expect(arg, msg) { + // some older browsers return typeof 'function' for RegExp + const result = arg instanceof Function ? arg.call(parsers) : parserInput.$re(arg); + + if (result) { + return result; + } + + error(msg || (typeof arg === 'string' ? `expected '${arg}' got '${parserInput.currentChar()}'` : 'unexpected token')); + } // Specialization of expect() + + + function expectChar(arg, msg) { + if (parserInput.$char(arg)) { + return arg; + } + + error(msg || `expected '${arg}' got '${parserInput.currentChar()}'`); + } + + function getDebugInfo(index) { + const filename = fileInfo.filename; + return { + lineNumber: getLocation(index, parserInput.getInput()).line + 1, + fileName: filename + }; + } + /** + * Used after initial parsing to create nodes on the fly + * + * @param {String} str - string to parse + * @param {Array} parseList - array of parsers to run input through e.g. ["value", "important"] + * @param {Number} currentIndex - start number to begin indexing + * @param {Object} fileInfo - fileInfo to attach to created nodes + */ + + + function parseNode(str, parseList, currentIndex, fileInfo, callback) { + let result; + const returnNodes = []; + const parser = parserInput; + + try { + parser.start(str, false, function fail(msg, index) { + callback({ + message: msg, + index: index + currentIndex + }); + }); + + for (let x = 0, p, i; p = parseList[x]; x++) { + i = parser.i; + result = parsers[p](); + + if (result) { + result._index = i + currentIndex; + result._fileInfo = fileInfo; + returnNodes.push(result); + } else { + returnNodes.push(null); + } + } + + const endInfo = parser.end(); + + if (endInfo.isFinished) { + callback(null, returnNodes); + } else { + callback(true, null); + } + } catch (e) { + throw new LessError({ + index: e.index + currentIndex, + message: e.message + }, imports, fileInfo.filename); + } + } // + // The Parser + // + + + return { + parserInput, + imports, + fileInfo, + parseNode, + // + // Parse an input string into an abstract syntax tree, + // @param str A string containing 'less' markup + // @param callback call `callback` when done. + // @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply + // + parse: function parse(str, callback, additionalData) { + let root; + let error = null; + let globalVars; + let modifyVars; + let ignored; + let preText = ''; + globalVars = additionalData && additionalData.globalVars ? `${Parser.serializeVars(additionalData.globalVars)}\n` : ''; + modifyVars = additionalData && additionalData.modifyVars ? `\n${Parser.serializeVars(additionalData.modifyVars)}` : ''; + + if (context.pluginManager) { + const preProcessors = context.pluginManager.getPreProcessors(); + + for (let i = 0; i < preProcessors.length; i++) { + str = preProcessors[i].process(str, { + context, + imports, + fileInfo + }); + } + } + + if (globalVars || additionalData && additionalData.banner) { + preText = (additionalData && additionalData.banner ? additionalData.banner : '') + globalVars; + ignored = imports.contentsIgnoredChars; + ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0; + ignored[fileInfo.filename] += preText.length; + } + + str = str.replace(/\r\n?/g, '\n'); // Remove potential UTF Byte Order Mark + + str = preText + str.replace(/^\uFEFF/, '') + modifyVars; + imports.contents[fileInfo.filename] = str; // Start with the primary rule. + // The whole syntax tree is held under a Ruleset node, + // with the `root` property set to true, so no `{}` are + // output. The callback is called when the input is parsed. + + try { + parserInput.start(str, context.chunkInput, function fail(msg, index) { + throw new LessError({ + index, + type: 'Parse', + message: msg, + filename: fileInfo.filename + }, imports); + }); + tree.Node.prototype.parse = this; + root = new tree.Ruleset(null, this.parsers.primary()); + tree.Node.prototype.rootNode = root; + root.root = true; + root.firstRoot = true; + root.functionRegistry = functionRegistry.inherit(); + } catch (e) { + return callback(new LessError(e, imports, fileInfo.filename)); + } // If `i` is smaller than the `input.length - 1`, + // it means the parser wasn't able to parse the whole + // string, so we've got a parsing error. + // + // We try to extract a \n delimited string, + // showing the line where the parse error occurred. + // We split it up into two parts (the part which parsed, + // and the part which didn't), so we can color them differently. + + + const endInfo = parserInput.end(); + + if (!endInfo.isFinished) { + let message = endInfo.furthestPossibleErrorMessage; + + if (!message) { + message = 'Unrecognised input'; + + if (endInfo.furthestChar === '}') { + message += '. Possibly missing opening \'{\''; + } else if (endInfo.furthestChar === ')') { + message += '. Possibly missing opening \'(\''; + } else if (endInfo.furthestReachedEnd) { + message += '. Possibly missing something'; + } + } + + error = new LessError({ + type: 'Parse', + message, + index: endInfo.furthest, + filename: fileInfo.filename + }, imports); + } + + const finish = e => { + e = error || e || imports.error; + + if (e) { + if (!(e instanceof LessError)) { + e = new LessError(e, imports, fileInfo.filename); + } + + return callback(e); + } else { + return callback(null, root); + } + }; + + if (context.processImports !== false) { + new visitors.ImportVisitor(imports, finish).run(root); + } else { + return finish(); + } + }, + // + // Here in, the parsing rules/functions + // + // The basic structure of the syntax tree generated is as follows: + // + // Ruleset -> Declaration -> Value -> Expression -> Entity + // + // Here's some Less code: + // + // .class { + // color: #fff; + // border: 1px solid #000; + // width: @w + 4px; + // > .child {...} + // } + // + // And here's what the parse tree might look like: + // + // Ruleset (Selector '.class', [ + // Declaration ("color", Value ([Expression [Color #fff]])) + // Declaration ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) + // Declaration ("width", Value ([Expression [Operation " + " [Variable "@w"][Dimension 4px]]])) + // Ruleset (Selector [Element '>', '.child'], [...]) + // ]) + // + // In general, most rules will try to parse a token with the `$re()` function, and if the return + // value is truly, will return a new node, of the relevant type. Sometimes, we need to check + // first, before parsing, that's when we use `peek()`. + // + parsers: parsers = { + // + // The `primary` rule is the *entry* and *exit* point of the parser. + // The rules here can appear at any level of the parse tree. + // + // The recursive nature of the grammar is an interplay between the `block` + // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, + // as represented by this simplified grammar: + // + // primary → (ruleset | declaration)+ + // ruleset → selector+ block + // block → '{' primary '}' + // + // Only at one point is the primary rule not called from the + // block rule: at the root level. + // + primary: function primary() { + const mixin = this.mixin; + let root = []; + let node; + + while (true) { + while (true) { + node = this.comment(); + + if (!node) { + break; + } + + root.push(node); + } // always process comments before deciding if finished + + + if (parserInput.finished) { + break; + } + + if (parserInput.peek('}')) { + break; + } + + node = this.extendRule(); + + if (node) { + root = root.concat(node); + continue; + } + + node = mixin.definition() || this.declaration() || this.ruleset() || mixin.call(false, false) || this.variableCall() || this.entities.call() || this.atrule(); + + if (node) { + root.push(node); + } else { + let foundSemiColon = false; + + while (parserInput.$char(';')) { + foundSemiColon = true; + } + + if (!foundSemiColon) { + break; + } + } + } + + return root; + }, + // comments are collected by the main parsing mechanism and then assigned to nodes + // where the current structure allows it + comment: function comment() { + if (parserInput.commentStore.length) { + const comment = parserInput.commentStore.shift(); + return new tree.Comment(comment.text, comment.isLineComment, comment.index, fileInfo); + } + }, + // + // Entities are tokens which can be found inside an Expression + // + entities: { + mixinLookup: function mixinLookup() { + return parsers.mixin.call(true, true); + }, + // + // A string, which supports escaping " and ' + // + // "milky way" 'he\'s the one!' + // + quoted: function quoted(forceEscaped) { + let str; + const index = parserInput.i; + let isEscaped = false; + parserInput.save(); + + if (parserInput.$char('~')) { + isEscaped = true; + } else if (forceEscaped) { + parserInput.restore(); + return; + } + + str = parserInput.$quoted(); + + if (!str) { + parserInput.restore(); + return; + } + + parserInput.forget(); + return new tree.Quoted(str.charAt(0), str.substr(1, str.length - 2), isEscaped, index, fileInfo); + }, + // + // A catch-all word, such as: + // + // black border-collapse + // + keyword: function keyword() { + const k = parserInput.$char('%') || parserInput.$re(/^\[?(?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+\]?/); + + if (k) { + return tree.Color.fromKeyword(k) || new tree.Keyword(k); + } + }, + // + // A function call + // + // rgb(255, 0, 255) + // + // The arguments are parsed with the `entities.arguments` parser. + // + call: function call() { + let name; + let args; + let func; + const index = parserInput.i; // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 + + if (parserInput.peek(/^url\(/i)) { + return; + } + + parserInput.save(); + name = parserInput.$re(/^([\w-]+|%|progid:[\w\.]+)\(/); + + if (!name) { + parserInput.forget(); + return; + } + + name = name[1]; + func = this.customFuncCall(name); + + if (func) { + args = func.parse(); + + if (args && func.stop) { + parserInput.forget(); + return args; + } + } + + args = this.arguments(args); + + if (!parserInput.$char(')')) { + parserInput.restore('Could not parse call arguments or missing \')\''); + return; + } + + parserInput.forget(); + return new tree.Call(name, args, index, fileInfo); + }, + // + // Parsing rules for functions with non-standard args, e.g.: + // + // boolean(not(2 > 1)) + // + // This is a quick prototype, to be modified/improved when + // more custom-parsed funcs come (e.g. `selector(...)`) + // + customFuncCall: function customFuncCall(name) { + /* Ideally the table is to be moved out of here for faster perf., + but it's quite tricky since it relies on all these `parsers` + and `expect` available only here */ + return { + alpha: f(parsers.ieAlpha, true), + boolean: f(condition), + 'if': f(condition) + }[name.toLowerCase()]; + + function f(parse, stop) { + return { + parse, + // parsing function + stop // when true - stop after parse() and return its result, + // otherwise continue for plain args + + }; + } + + function condition() { + return [expect(parsers.condition, 'expected condition')]; + } + }, + arguments: function _arguments(prevArgs) { + let argsComma = prevArgs || []; + const argsSemiColon = []; + let isSemiColonSeparated; + let value; + parserInput.save(); + + while (true) { + if (prevArgs) { + prevArgs = false; + } else { + value = parsers.detachedRuleset() || this.assignment() || parsers.expression(); + + if (!value) { + break; + } + + if (value.value && value.value.length == 1) { + value = value.value[0]; + } + + argsComma.push(value); + } + + if (parserInput.$char(',')) { + continue; + } + + if (parserInput.$char(';') || isSemiColonSeparated) { + isSemiColonSeparated = true; + value = argsComma.length < 1 ? argsComma[0] : new tree.Value(argsComma); + argsSemiColon.push(value); + argsComma = []; + } + } + + parserInput.forget(); + return isSemiColonSeparated ? argsSemiColon : argsComma; + }, + literal: function literal() { + return this.dimension() || this.color() || this.quoted() || this.unicodeDescriptor(); + }, + // Assignments are argument entities for calls. + // They are present in ie filter properties as shown below. + // + // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) + // + assignment: function assignment() { + let key; + let value; + parserInput.save(); + key = parserInput.$re(/^\w+(?=\s?=)/i); + + if (!key) { + parserInput.restore(); + return; + } + + if (!parserInput.$char('=')) { + parserInput.restore(); + return; + } + + value = parsers.entity(); + + if (value) { + parserInput.forget(); + return new tree.Assignment(key, value); + } else { + parserInput.restore(); + } + }, + // + // Parse url() tokens + // + // We use a specific rule for urls, because they don't really behave like + // standard function calls. The difference is that the argument doesn't have + // to be enclosed within a string, so it can't be parsed as an Expression. + // + url: function url() { + let value; + const index = parserInput.i; + parserInput.autoCommentAbsorb = false; + + if (!parserInput.$str('url(')) { + parserInput.autoCommentAbsorb = true; + return; + } + + value = this.quoted() || this.variable() || this.property() || parserInput.$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ''; + parserInput.autoCommentAbsorb = true; + expectChar(')'); + return new tree.URL(value.value != null || value instanceof tree.Variable || value instanceof tree.Property ? value : new tree.Anonymous(value, index), index, fileInfo); + }, + // + // A Variable entity, such as `@fink`, in + // + // width: @fink + 2px + // + // We use a different parser for variable definitions, + // see `parsers.variable`. + // + variable: function variable() { + let ch; + let name; + const index = parserInput.i; + parserInput.save(); + + if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^@@?[\w-]+/))) { + ch = parserInput.currentChar(); + + if (ch === '(' || ch === '[' && !parserInput.prevChar().match(/^\s/)) { + // this may be a VariableCall lookup + const result = parsers.variableCall(name); + + if (result) { + parserInput.forget(); + return result; + } + } + + parserInput.forget(); + return new tree.Variable(name, index, fileInfo); + } + + parserInput.restore(); + }, + // A variable entity using the protective {} e.g. @{var} + variableCurly: function variableCurly() { + let curly; + const index = parserInput.i; + + if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\{([\w-]+)\}/))) { + return new tree.Variable(`@${curly[1]}`, index, fileInfo); + } + }, + // + // A Property accessor, such as `$color`, in + // + // background-color: $color + // + property: function property() { + let name; + const index = parserInput.i; + + if (parserInput.currentChar() === '$' && (name = parserInput.$re(/^\$[\w-]+/))) { + return new tree.Property(name, index, fileInfo); + } + }, + // A property entity useing the protective {} e.g. ${prop} + propertyCurly: function propertyCurly() { + let curly; + const index = parserInput.i; + + if (parserInput.currentChar() === '$' && (curly = parserInput.$re(/^\$\{([\w-]+)\}/))) { + return new tree.Property(`$${curly[1]}`, index, fileInfo); + } + }, + // + // A Hexadecimal color + // + // #4F3C2F + // + // `rgb` and `hsl` colors are parsed through the `entities.call` parser. + // + color: function color() { + let rgb; + parserInput.save(); + + if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})([\w.#\[])?/))) { + if (!rgb[2]) { + parserInput.forget(); + return new tree.Color(rgb[1], undefined, rgb[0]); + } + } + + parserInput.restore(); + }, + colorKeyword: function colorKeyword() { + parserInput.save(); + const autoCommentAbsorb = parserInput.autoCommentAbsorb; + parserInput.autoCommentAbsorb = false; + const k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/); + parserInput.autoCommentAbsorb = autoCommentAbsorb; + + if (!k) { + parserInput.forget(); + return; + } + + parserInput.restore(); + const color = tree.Color.fromKeyword(k); + + if (color) { + parserInput.$str(k); + return color; + } + }, + // + // A Dimension, that is, a number and a unit + // + // 0.5em 95% + // + dimension: function dimension() { + if (parserInput.peekNotNumeric()) { + return; + } + + const value = parserInput.$re(/^([+-]?\d*\.?\d+)(%|[a-z_]+)?/i); + + if (value) { + return new tree.Dimension(value[1], value[2]); + } + }, + // + // A unicode descriptor, as is used in unicode-range + // + // U+0?? or U+00A1-00A9 + // + unicodeDescriptor: function unicodeDescriptor() { + let ud; + ud = parserInput.$re(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/); + + if (ud) { + return new tree.UnicodeDescriptor(ud[0]); + } + }, + // + // JavaScript code to be evaluated + // + // `window.location.href` + // + javascript: function javascript() { + let js; + const index = parserInput.i; + parserInput.save(); + const escape = parserInput.$char('~'); + const jsQuote = parserInput.$char('`'); + + if (!jsQuote) { + parserInput.restore(); + return; + } + + js = parserInput.$re(/^[^`]*`/); + + if (js) { + parserInput.forget(); + return new tree.JavaScript(js.substr(0, js.length - 1), Boolean(escape), index, fileInfo); + } + + parserInput.restore('invalid javascript definition'); + } + }, + // + // The variable part of a variable definition. Used in the `rule` parser + // + // @fink: + // + variable: function variable() { + let name; + + if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) { + return name[1]; + } + }, + // + // Call a variable value to retrieve a detached ruleset + // or a value from a detached ruleset's rules. + // + // @fink(); + // @fink; + // color: @fink[@color]; + // + variableCall: function variableCall(parsedName) { + let lookups; + let important; + const i = parserInput.i; + const inValue = !!parsedName; + let name = parsedName; + parserInput.save(); + + if (name || parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)(\(\s*\))?/))) { + lookups = this.mixin.ruleLookups(); + + if (!lookups && (inValue && parserInput.$str('()') !== '()' || name[2] !== '()')) { + parserInput.restore('Missing \'[...]\' lookup in variable call'); + return; + } + + if (!inValue) { + name = name[1]; + } + + if (lookups && parsers.important()) { + important = true; + } + + const call = new tree.VariableCall(name, i, fileInfo); + + if (!inValue && parsers.end()) { + parserInput.forget(); + return call; + } else { + parserInput.forget(); + return new tree.NamespaceValue(call, lookups, important, i, fileInfo); + } + } + + parserInput.restore(); + }, + // + // extend syntax - used to extend selectors + // + extend: function extend(isRule) { + let elements; + let e; + const index = parserInput.i; + let option; + let extendList; + let extend; + + if (!parserInput.$str(isRule ? '&:extend(' : ':extend(')) { + return; + } + + do { + option = null; + elements = null; + + while (!(option = parserInput.$re(/^(all)(?=\s*(\)|,))/))) { + e = this.element(); + + if (!e) { + break; + } + + if (elements) { + elements.push(e); + } else { + elements = [e]; + } + } + + option = option && option[1]; + + if (!elements) { + error('Missing target selector for :extend().'); + } + + extend = new tree.Extend(new tree.Selector(elements), option, index, fileInfo); + + if (extendList) { + extendList.push(extend); + } else { + extendList = [extend]; + } + } while (parserInput.$char(',')); + + expect(/^\)/); + + if (isRule) { + expect(/^;/); + } + + return extendList; + }, + // + // extendRule - used in a rule to extend all the parent selectors + // + extendRule: function extendRule() { + return this.extend(true); + }, + // + // Mixins + // + mixin: { + // + // A Mixin call, with an optional argument list + // + // #mixins > .square(#fff); + // #mixins.square(#fff); + // .rounded(4px, black); + // .button; + // + // We can lookup / return a value using the lookup syntax: + // + // color: #mixin.square(#fff)[@color]; + // + // The `while` loop is there because mixins can be + // namespaced, but we only support the child and descendant + // selector for now. + // + call: function call(inValue, getLookup) { + const s = parserInput.currentChar(); + let important = false; + let lookups; + const index = parserInput.i; + let elements; + let args; + let hasParens; + + if (s !== '.' && s !== '#') { + return; + } + + parserInput.save(); // stop us absorbing part of an invalid selector + + elements = this.elements(); + + if (elements) { + if (parserInput.$char('(')) { + args = this.args(true).args; + expectChar(')'); + hasParens = true; + } + + if (getLookup !== false) { + lookups = this.ruleLookups(); + } + + if (getLookup === true && !lookups) { + parserInput.restore(); + return; + } + + if (inValue && !lookups && !hasParens) { + // This isn't a valid in-value mixin call + parserInput.restore(); + return; + } + + if (!inValue && parsers.important()) { + important = true; + } + + if (inValue || parsers.end()) { + parserInput.forget(); + const mixin = new tree.mixin.Call(elements, args, index, fileInfo, !lookups && important); + + if (lookups) { + return new tree.NamespaceValue(mixin, lookups, important); + } else { + return mixin; + } + } + } + + parserInput.restore(); + }, + + /** + * Matching elements for mixins + * (Start with . or # and can have > ) + */ + elements: function elements() { + let elements; + let e; + let c; + let elem; + let elemIndex; + const re = /^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/; + + while (true) { + elemIndex = parserInput.i; + e = parserInput.$re(re); + + if (!e) { + break; + } + + elem = new tree.Element(c, e, false, elemIndex, fileInfo); + + if (elements) { + elements.push(elem); + } else { + elements = [elem]; + } + + c = parserInput.$char('>'); + } + + return elements; + }, + args: function args(isCall) { + const entities = parsers.entities; + const returner = { + args: null, + variadic: false + }; + let expressions = []; + const argsSemiColon = []; + const argsComma = []; + let isSemiColonSeparated; + let expressionContainsNamed; + let name; + let nameLoop; + let value; + let arg; + let expand; + let hasSep = true; + parserInput.save(); + + while (true) { + if (isCall) { + arg = parsers.detachedRuleset() || parsers.expression(); + } else { + parserInput.commentStore.length = 0; + + if (parserInput.$str('...')) { + returner.variadic = true; + + if (parserInput.$char(';') && !isSemiColonSeparated) { + isSemiColonSeparated = true; + } + + (isSemiColonSeparated ? argsSemiColon : argsComma).push({ + variadic: true + }); + break; + } + + arg = entities.variable() || entities.property() || entities.literal() || entities.keyword() || this.call(true); + } + + if (!arg || !hasSep) { + break; + } + + nameLoop = null; + + if (arg.throwAwayComments) { + arg.throwAwayComments(); + } + + value = arg; + let val = null; + + if (isCall) { + // Variable + if (arg.value && arg.value.length == 1) { + val = arg.value[0]; + } + } else { + val = arg; + } + + if (val && (val instanceof tree.Variable || val instanceof tree.Property)) { + if (parserInput.$char(':')) { + if (expressions.length > 0) { + if (isSemiColonSeparated) { + error('Cannot mix ; and , as delimiter types'); + } + + expressionContainsNamed = true; + } + + value = parsers.detachedRuleset() || parsers.expression(); + + if (!value) { + if (isCall) { + error('could not understand value for named argument'); + } else { + parserInput.restore(); + returner.args = []; + return returner; + } + } + + nameLoop = name = val.name; + } else if (parserInput.$str('...')) { + if (!isCall) { + returner.variadic = true; + + if (parserInput.$char(';') && !isSemiColonSeparated) { + isSemiColonSeparated = true; + } + + (isSemiColonSeparated ? argsSemiColon : argsComma).push({ + name: arg.name, + variadic: true + }); + break; + } else { + expand = true; + } + } else if (!isCall) { + name = nameLoop = val.name; + value = null; + } + } + + if (value) { + expressions.push(value); + } + + argsComma.push({ + name: nameLoop, + value, + expand + }); + + if (parserInput.$char(',')) { + hasSep = true; + continue; + } + + hasSep = parserInput.$char(';') === ';'; + + if (hasSep || isSemiColonSeparated) { + if (expressionContainsNamed) { + error('Cannot mix ; and , as delimiter types'); + } + + isSemiColonSeparated = true; + + if (expressions.length > 1) { + value = new tree.Value(expressions); + } + + argsSemiColon.push({ + name, + value, + expand + }); + name = null; + expressions = []; + expressionContainsNamed = false; + } + } + + parserInput.forget(); + returner.args = isSemiColonSeparated ? argsSemiColon : argsComma; + return returner; + }, + // + // A Mixin definition, with a list of parameters + // + // .rounded (@radius: 2px, @color) { + // ... + // } + // + // Until we have a finer grained state-machine, we have to + // do a look-ahead, to make sure we don't have a mixin call. + // See the `rule` function for more information. + // + // We start by matching `.rounded (`, and then proceed on to + // the argument list, which has optional default values. + // We store the parameters in `params`, with a `value` key, + // if there is a value, such as in the case of `@radius`. + // + // Once we've got our params list, and a closing `)`, we parse + // the `{...}` block. + // + definition: function definition() { + let name; + let params = []; + let match; + let ruleset; + let cond; + let variadic = false; + + if (parserInput.currentChar() !== '.' && parserInput.currentChar() !== '#' || parserInput.peek(/^[^{]*\}/)) { + return; + } + + parserInput.save(); + match = parserInput.$re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/); + + if (match) { + name = match[1]; + const argInfo = this.args(false); + params = argInfo.args; + variadic = argInfo.variadic; // .mixincall("@{a}"); + // looks a bit like a mixin definition.. + // also + // .mixincall(@a: {rule: set;}); + // so we have to be nice and restore + + if (!parserInput.$char(')')) { + parserInput.restore('Missing closing \')\''); + return; + } + + parserInput.commentStore.length = 0; + + if (parserInput.$str('when')) { + // Guard + cond = expect(parsers.conditions, 'expected condition'); + } + + ruleset = parsers.block(); + + if (ruleset) { + parserInput.forget(); + return new tree.mixin.Definition(name, params, ruleset, cond, variadic); + } else { + parserInput.restore(); + } + } else { + parserInput.forget(); + } + }, + ruleLookups: function ruleLookups() { + let rule; + const lookups = []; + + if (parserInput.currentChar() !== '[') { + return; + } + + while (true) { + parserInput.save(); + rule = this.lookupValue(); + + if (!rule && rule !== '') { + parserInput.restore(); + break; + } + + lookups.push(rule); + parserInput.forget(); + } + + if (lookups.length > 0) { + return lookups; + } + }, + lookupValue: function lookupValue() { + parserInput.save(); + + if (!parserInput.$char('[')) { + parserInput.restore(); + return; + } + + const name = parserInput.$re(/^(?:[@$]{0,2})[_a-zA-Z0-9-]*/); + + if (!parserInput.$char(']')) { + parserInput.restore(); + return; + } + + if (name || name === '') { + parserInput.forget(); + return name; + } + + parserInput.restore(); + } + }, + // + // Entities are the smallest recognized token, + // and can be found inside a rule's value. + // + entity: function entity() { + const entities = this.entities; + return this.comment() || entities.literal() || entities.variable() || entities.url() || entities.property() || entities.call() || entities.keyword() || this.mixin.call(true) || entities.javascript(); + }, + // + // A Declaration terminator. Note that we use `peek()` to check for '}', + // because the `block` rule will be expecting it, but we still need to make sure + // it's there, if ';' was omitted. + // + end: function end() { + return parserInput.$char(';') || parserInput.peek('}'); + }, + // + // IE's alpha function + // + // alpha(opacity=88) + // + ieAlpha: function ieAlpha() { + let value; // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 + + if (!parserInput.$re(/^opacity=/i)) { + return; + } + + value = parserInput.$re(/^\d+/); + + if (!value) { + value = expect(parsers.entities.variable, 'Could not parse alpha'); + value = `@{${value.name.slice(1)}}`; + } + + expectChar(')'); + return new tree.Quoted('', `alpha(opacity=${value})`); + }, + // + // A Selector Element + // + // div + // + h1 + // #socks + // input[type="text"] + // + // Elements are the building blocks for Selectors, + // they are made out of a `Combinator` (see combinator rule), + // and an element name, such as a tag a class, or `*`. + // + element: function element() { + let e; + let c; + let v; + const index = parserInput.i; + c = this.combinator(); + e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) || parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || parserInput.$char('*') || parserInput.$char('&') || this.attribute() || parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[\.#:](?=@)/) || this.entities.variableCurly(); + + if (!e) { + parserInput.save(); + + if (parserInput.$char('(')) { + if ((v = this.selector(false)) && parserInput.$char(')')) { + e = new tree.Paren(v); + parserInput.forget(); + } else { + parserInput.restore('Missing closing \')\''); + } + } else { + parserInput.forget(); + } + } + + if (e) { + return new tree.Element(c, e, e instanceof tree.Variable, index, fileInfo); + } + }, + // + // Combinators combine elements together, in a Selector. + // + // Because our parser isn't white-space sensitive, special care + // has to be taken, when parsing the descendant combinator, ` `, + // as it's an empty space. We have to check the previous character + // in the input, to see if it's a ` ` character. More info on how + // we deal with this in *combinator.js*. + // + combinator: function combinator() { + let c = parserInput.currentChar(); + + if (c === '/') { + parserInput.save(); + const slashedCombinator = parserInput.$re(/^\/[a-z]+\//i); + + if (slashedCombinator) { + parserInput.forget(); + return new tree.Combinator(slashedCombinator); + } + + parserInput.restore(); + } + + if (c === '>' || c === '+' || c === '~' || c === '|' || c === '^') { + parserInput.i++; + + if (c === '^' && parserInput.currentChar() === '^') { + c = '^^'; + parserInput.i++; + } + + while (parserInput.isWhitespace()) { + parserInput.i++; + } + + return new tree.Combinator(c); + } else if (parserInput.isWhitespace(-1)) { + return new tree.Combinator(' '); + } else { + return new tree.Combinator(null); + } + }, + // + // A CSS Selector + // with less extensions e.g. the ability to extend and guard + // + // .class > div + h1 + // li a:hover + // + // Selectors are made out of one or more Elements, see above. + // + selector: function selector(isLess) { + const index = parserInput.i; + let elements; + let extendList; + let c; + let e; + let allExtends; + let when; + let condition; + isLess = isLess !== false; + + while (isLess && (extendList = this.extend()) || isLess && (when = parserInput.$str('when')) || (e = this.element())) { + if (when) { + condition = expect(this.conditions, 'expected condition'); + } else if (condition) { + error('CSS guard can only be used at the end of selector'); + } else if (extendList) { + if (allExtends) { + allExtends = allExtends.concat(extendList); + } else { + allExtends = extendList; + } + } else { + if (allExtends) { + error('Extend can only be used at the end of selector'); + } + + c = parserInput.currentChar(); + + if (elements) { + elements.push(e); + } else { + elements = [e]; + } + + e = null; + } + + if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { + break; + } + } + + if (elements) { + return new tree.Selector(elements, allExtends, condition, index, fileInfo); + } + + if (allExtends) { + error('Extend must be used to extend a selector, it cannot be used on its own'); + } + }, + selectors: function selectors() { + let s; + let selectors; + + while (true) { + s = this.selector(); + + if (!s) { + break; + } + + if (selectors) { + selectors.push(s); + } else { + selectors = [s]; + } + + parserInput.commentStore.length = 0; + + if (s.condition && selectors.length > 1) { + error("Guards are only currently allowed on a single selector."); + } + + if (!parserInput.$char(',')) { + break; + } + + if (s.condition) { + error("Guards are only currently allowed on a single selector."); + } + + parserInput.commentStore.length = 0; + } + + return selectors; + }, + attribute: function attribute() { + if (!parserInput.$char('[')) { + return; + } + + const entities = this.entities; + let key; + let val; + let op; + + if (!(key = entities.variableCurly())) { + key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/); + } + + op = parserInput.$re(/^[|~*$^]?=/); + + if (op) { + val = entities.quoted() || parserInput.$re(/^[0-9]+%/) || parserInput.$re(/^[\w-]+/) || entities.variableCurly(); + } + + expectChar(']'); + return new tree.Attribute(key, op, val); + }, + // + // The `block` rule is used by `ruleset` and `mixin.definition`. + // It's a wrapper around the `primary` rule, with added `{}`. + // + block: function block() { + let content; + + if (parserInput.$char('{') && (content = this.primary()) && parserInput.$char('}')) { + return content; + } + }, + blockRuleset: function blockRuleset() { + let block = this.block(); + + if (block) { + block = new tree.Ruleset(null, block); + } + + return block; + }, + detachedRuleset: function detachedRuleset() { + let argInfo; + let params; + let variadic; + parserInput.save(); + + if (parserInput.$re(/^[.#]\(/)) { + /** + * DR args currently only implemented for each() function, and not + * yet settable as `@dr: #(@arg) {}` + * This should be done when DRs are merged with mixins. + * See: https://github.com/less/less-meta/issues/16 + */ + argInfo = this.mixin.args(false); + params = argInfo.args; + variadic = argInfo.variadic; + + if (!parserInput.$char(')')) { + parserInput.restore(); + return; + } + } + + const blockRuleset = this.blockRuleset(); + + if (blockRuleset) { + parserInput.forget(); + + if (params) { + return new tree.mixin.Definition(null, params, blockRuleset, null, variadic); + } + + return new tree.DetachedRuleset(blockRuleset); + } + + parserInput.restore(); + }, + // + // div, .class, body > p {...} + // + ruleset: function ruleset() { + let selectors; + let rules; + let debugInfo; + parserInput.save(); + + if (context.dumpLineNumbers) { + debugInfo = getDebugInfo(parserInput.i); + } + + selectors = this.selectors(); + + if (selectors && (rules = this.block())) { + parserInput.forget(); + const ruleset = new tree.Ruleset(selectors, rules, context.strictImports); + + if (context.dumpLineNumbers) { + ruleset.debugInfo = debugInfo; + } + + return ruleset; + } else { + parserInput.restore(); + } + }, + declaration: function declaration() { + let name; + let value; + const index = parserInput.i; + let hasDR; + const c = parserInput.currentChar(); + let important; + let merge; + let isVariable; + + if (c === '.' || c === '#' || c === '&' || c === ':') { + return; + } + + parserInput.save(); + name = this.variable() || this.ruleProperty(); + + if (name) { + isVariable = typeof name === 'string'; + + if (isVariable) { + value = this.detachedRuleset(); + + if (value) { + hasDR = true; + } + } + + parserInput.commentStore.length = 0; + + if (!value) { + // a name returned by this.ruleProperty() is always an array of the form: + // [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"] + // where each item is a tree.Keyword or tree.Variable + merge = !isVariable && name.length > 1 && name.pop().value; // Custom property values get permissive parsing + + if (name[0].value && name[0].value.slice(0, 2) === '--') { + value = this.permissiveValue(); + } // Try to store values as anonymous + // If we need the value later we'll re-parse it in ruleset.parseValue + else { + value = this.anonymousValue(); + } + + if (value) { + parserInput.forget(); // anonymous values absorb the end ';' which is required for them to work + + return new tree.Declaration(name, value, false, merge, index, fileInfo); + } + + if (!value) { + value = this.value(); + } + + if (value) { + important = this.important(); + } else if (isVariable) { + // As a last resort, try permissiveValue + value = this.permissiveValue(); + } + } + + if (value && (this.end() || hasDR)) { + parserInput.forget(); + return new tree.Declaration(name, value, important, merge, index, fileInfo); + } else { + parserInput.restore(); + } + } else { + parserInput.restore(); + } + }, + anonymousValue: function anonymousValue() { + const index = parserInput.i; + const match = parserInput.$re(/^([^.#@\$+\/'"*`(;{}-]*);/); + + if (match) { + return new tree.Anonymous(match[1], index); + } + }, + + /** + * Used for custom properties, at-rules, and variables (as fallback) + * Parses almost anything inside of {} [] () "" blocks + * until it reaches outer-most tokens. + * + * First, it will try to parse comments and entities to reach + * the end. This is mostly like the Expression parser except no + * math is allowed. + */ + permissiveValue: function permissiveValue(untilTokens) { + let i; + let e; + let done; + let value; + const tok = untilTokens || ';'; + const index = parserInput.i; + const result = []; + + function testCurrentChar() { + const char = parserInput.currentChar(); + + if (typeof tok === 'string') { + return char === tok; + } else { + return tok.test(char); + } + } + + if (testCurrentChar()) { + return; + } + + value = []; + + do { + e = this.comment(); + + if (e) { + value.push(e); + continue; + } + + e = this.entity(); + + if (e) { + value.push(e); + } + } while (e); + + done = testCurrentChar(); + + if (value.length > 0) { + value = new tree.Expression(value); + + if (done) { + return value; + } else { + result.push(value); + } // Preserve space before $parseUntil as it will not + + + if (parserInput.prevChar() === ' ') { + result.push(new tree.Anonymous(' ', index)); + } + } + + parserInput.save(); + value = parserInput.$parseUntil(tok); + + if (value) { + if (typeof value === 'string') { + error(`Expected '${value}'`, 'Parse'); + } + + if (value.length === 1 && value[0] === ' ') { + parserInput.forget(); + return new tree.Anonymous('', index); + } + + let item; + + for (i = 0; i < value.length; i++) { + item = value[i]; + + if (Array.isArray(item)) { + // Treat actual quotes as normal quoted values + result.push(new tree.Quoted(item[0], item[1], true, index, fileInfo)); + } else { + if (i === value.length - 1) { + item = item.trim(); + } // Treat like quoted values, but replace vars like unquoted expressions + + + const quote = new tree.Quoted('\'', item, true, index, fileInfo); + quote.variableRegex = /@([\w-]+)/g; + quote.propRegex = /\$([\w-]+)/g; + result.push(quote); + } + } + + parserInput.forget(); + return new tree.Expression(result, true); + } + + parserInput.restore(); + }, + // + // An @import atrule + // + // @import "lib"; + // + // Depending on our environment, importing is done differently: + // In the browser, it's an XHR request, in Node, it would be a + // file-system operation. The function used for importing is + // stored in `import`, which we pass to the Import constructor. + // + 'import': function _import() { + let path; + let features; + const index = parserInput.i; + const dir = parserInput.$re(/^@import?\s+/); + + if (dir) { + const options = (dir ? this.importOptions() : null) || {}; + + if (path = this.entities.quoted() || this.entities.url()) { + features = this.mediaFeatures(); + + if (!parserInput.$char(';')) { + parserInput.i = index; + error('missing semi-colon or unrecognised media features on import'); + } + + features = features && new tree.Value(features); + return new tree.Import(path, features, options, index, fileInfo); + } else { + parserInput.i = index; + error('malformed import statement'); + } + } + }, + importOptions: function importOptions() { + let o; + const options = {}; + let optionName; + let value; // list of options, surrounded by parens + + if (!parserInput.$char('(')) { + return null; + } + + do { + o = this.importOption(); + + if (o) { + optionName = o; + value = true; + + switch (optionName) { + case 'css': + optionName = 'less'; + value = false; + break; + + case 'once': + optionName = 'multiple'; + value = false; + break; + } + + options[optionName] = value; + + if (!parserInput.$char(',')) { + break; + } + } + } while (o); + + expectChar(')'); + return options; + }, + importOption: function importOption() { + const opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/); + + if (opt) { + return opt[1]; + } + }, + mediaFeature: function mediaFeature() { + const entities = this.entities; + const nodes = []; + let e; + let p; + parserInput.save(); + + do { + e = entities.keyword() || entities.variable() || entities.mixinLookup(); + + if (e) { + nodes.push(e); + } else if (parserInput.$char('(')) { + p = this.property(); + e = this.value(); + + if (parserInput.$char(')')) { + if (p && e) { + nodes.push(new tree.Paren(new tree.Declaration(p, e, null, null, parserInput.i, fileInfo, true))); + } else if (e) { + nodes.push(new tree.Paren(e)); + } else { + error('badly formed media feature definition'); + } + } else { + error('Missing closing \')\'', 'Parse'); + } + } + } while (e); + + parserInput.forget(); + + if (nodes.length > 0) { + return new tree.Expression(nodes); + } + }, + mediaFeatures: function mediaFeatures() { + const entities = this.entities; + const features = []; + let e; + + do { + e = this.mediaFeature(); + + if (e) { + features.push(e); + + if (!parserInput.$char(',')) { + break; + } + } else { + e = entities.variable() || entities.mixinLookup(); + + if (e) { + features.push(e); + + if (!parserInput.$char(',')) { + break; + } + } + } + } while (e); + + return features.length > 0 ? features : null; + }, + media: function media() { + let features; + let rules; + let media; + let debugInfo; + const index = parserInput.i; + + if (context.dumpLineNumbers) { + debugInfo = getDebugInfo(index); + } + + parserInput.save(); + + if (parserInput.$str('@media')) { + features = this.mediaFeatures(); + rules = this.block(); + + if (!rules) { + error('media definitions require block statements after any features'); + } + + parserInput.forget(); + media = new tree.Media(rules, features, index, fileInfo); + + if (context.dumpLineNumbers) { + media.debugInfo = debugInfo; + } + + return media; + } + + parserInput.restore(); + }, + // + // A @plugin directive, used to import plugins dynamically. + // + // @plugin (args) "lib"; + // + plugin: function plugin() { + let path; + let args; + let options; + const index = parserInput.i; + const dir = parserInput.$re(/^@plugin?\s+/); + + if (dir) { + args = this.pluginArgs(); + + if (args) { + options = { + pluginArgs: args, + isPlugin: true + }; + } else { + options = { + isPlugin: true + }; + } + + if (path = this.entities.quoted() || this.entities.url()) { + if (!parserInput.$char(';')) { + parserInput.i = index; + error('missing semi-colon on @plugin'); + } + + return new tree.Import(path, null, options, index, fileInfo); + } else { + parserInput.i = index; + error('malformed @plugin statement'); + } + } + }, + pluginArgs: function pluginArgs() { + // list of options, surrounded by parens + parserInput.save(); + + if (!parserInput.$char('(')) { + parserInput.restore(); + return null; + } + + const args = parserInput.$re(/^\s*([^\);]+)\)\s*/); + + if (args[1]) { + parserInput.forget(); + return args[1].trim(); + } else { + parserInput.restore(); + return null; + } + }, + // + // A CSS AtRule + // + // @charset "utf-8"; + // + atrule: function atrule() { + const index = parserInput.i; + let name; + let value; + let rules; + let nonVendorSpecificName; + let hasIdentifier; + let hasExpression; + let hasUnknown; + let hasBlock = true; + let isRooted = true; + + if (parserInput.currentChar() !== '@') { + return; + } + + value = this['import']() || this.plugin() || this.media(); + + if (value) { + return value; + } + + parserInput.save(); + name = parserInput.$re(/^@[a-z-]+/); + + if (!name) { + return; + } + + nonVendorSpecificName = name; + + if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { + nonVendorSpecificName = `@${name.slice(name.indexOf('-', 2) + 1)}`; + } + + switch (nonVendorSpecificName) { + case '@charset': + hasIdentifier = true; + hasBlock = false; + break; + + case '@namespace': + hasExpression = true; + hasBlock = false; + break; + + case '@keyframes': + case '@counter-style': + hasIdentifier = true; + break; + + case '@document': + case '@supports': + hasUnknown = true; + isRooted = false; + break; + + default: + hasUnknown = true; + break; + } + + parserInput.commentStore.length = 0; + + if (hasIdentifier) { + value = this.entity(); + + if (!value) { + error(`expected ${name} identifier`); + } + } else if (hasExpression) { + value = this.expression(); + + if (!value) { + error(`expected ${name} expression`); + } + } else if (hasUnknown) { + value = this.permissiveValue(/^[{;]/); + hasBlock = parserInput.currentChar() === '{'; + + if (!value) { + if (!hasBlock && parserInput.currentChar() !== ';') { + error(`${name} rule is missing block or ending semi-colon`); + } + } else if (!value.value) { + value = null; + } + } + + if (hasBlock) { + rules = this.blockRuleset(); + } + + if (rules || !hasBlock && value && parserInput.$char(';')) { + parserInput.forget(); + return new tree.AtRule(name, value, rules, index, fileInfo, context.dumpLineNumbers ? getDebugInfo(index) : null, isRooted); + } + + parserInput.restore('at-rule options not recognised'); + }, + // + // A Value is a comma-delimited list of Expressions + // + // font-family: Baskerville, Georgia, serif; + // + // In a Rule, a Value represents everything after the `:`, + // and before the `;`. + // + value: function value() { + let e; + const expressions = []; + const index = parserInput.i; + + do { + e = this.expression(); + + if (e) { + expressions.push(e); + + if (!parserInput.$char(',')) { + break; + } + } + } while (e); + + if (expressions.length > 0) { + return new tree.Value(expressions, index); + } + }, + important: function important() { + if (parserInput.currentChar() === '!') { + return parserInput.$re(/^! *important/); + } + }, + sub: function sub() { + let a; + let e; + parserInput.save(); + + if (parserInput.$char('(')) { + a = this.addition(); + + if (a && parserInput.$char(')')) { + parserInput.forget(); + e = new tree.Expression([a]); + e.parens = true; + return e; + } + + parserInput.restore('Expected \')\''); + return; + } + + parserInput.restore(); + }, + multiplication: function multiplication() { + let m; + let a; + let op; + let operation; + let isSpaced; + m = this.operand(); + + if (m) { + isSpaced = parserInput.isWhitespace(-1); + + while (true) { + if (parserInput.peek(/^\/[*\/]/)) { + break; + } + + parserInput.save(); + op = parserInput.$char('/') || parserInput.$char('*') || parserInput.$str('./'); + + if (!op) { + parserInput.forget(); + break; + } + + a = this.operand(); + + if (!a) { + parserInput.restore(); + break; + } + + parserInput.forget(); + m.parensInOp = true; + a.parensInOp = true; + operation = new tree.Operation(op, [operation || m, a], isSpaced); + isSpaced = parserInput.isWhitespace(-1); + } + + return operation || m; + } + }, + addition: function addition() { + let m; + let a; + let op; + let operation; + let isSpaced; + m = this.multiplication(); + + if (m) { + isSpaced = parserInput.isWhitespace(-1); + + while (true) { + op = parserInput.$re(/^[-+]\s+/) || !isSpaced && (parserInput.$char('+') || parserInput.$char('-')); + + if (!op) { + break; + } + + a = this.multiplication(); + + if (!a) { + break; + } + + m.parensInOp = true; + a.parensInOp = true; + operation = new tree.Operation(op, [operation || m, a], isSpaced); + isSpaced = parserInput.isWhitespace(-1); + } + + return operation || m; + } + }, + conditions: function conditions() { + let a; + let b; + const index = parserInput.i; + let condition; + a = this.condition(true); + + if (a) { + while (true) { + if (!parserInput.peek(/^,\s*(not\s*)?\(/) || !parserInput.$char(',')) { + break; + } + + b = this.condition(true); + + if (!b) { + break; + } + + condition = new tree.Condition('or', condition || a, b, index); + } + + return condition || a; + } + }, + condition: function condition(needsParens) { + let result; + let logical; + let next; + + function or() { + return parserInput.$str('or'); + } + + result = this.conditionAnd(needsParens); + + if (!result) { + return; + } + + logical = or(); + + if (logical) { + next = this.condition(needsParens); + + if (next) { + result = new tree.Condition(logical, result, next); + } else { + return; + } + } + + return result; + }, + conditionAnd: function conditionAnd(needsParens) { + let result; + let logical; + let next; + const self = this; + + function insideCondition() { + const cond = self.negatedCondition(needsParens) || self.parenthesisCondition(needsParens); + + if (!cond && !needsParens) { + return self.atomicCondition(needsParens); + } + + return cond; + } + + function and() { + return parserInput.$str('and'); + } + + result = insideCondition(); + + if (!result) { + return; + } + + logical = and(); + + if (logical) { + next = this.conditionAnd(needsParens); + + if (next) { + result = new tree.Condition(logical, result, next); + } else { + return; + } + } + + return result; + }, + negatedCondition: function negatedCondition(needsParens) { + if (parserInput.$str('not')) { + const result = this.parenthesisCondition(needsParens); + + if (result) { + result.negate = !result.negate; + } + + return result; + } + }, + parenthesisCondition: function parenthesisCondition(needsParens) { + function tryConditionFollowedByParenthesis(me) { + let body; + parserInput.save(); + body = me.condition(needsParens); + + if (!body) { + parserInput.restore(); + return; + } + + if (!parserInput.$char(')')) { + parserInput.restore(); + return; + } + + parserInput.forget(); + return body; + } + + let body; + parserInput.save(); + + if (!parserInput.$str('(')) { + parserInput.restore(); + return; + } + + body = tryConditionFollowedByParenthesis(this); + + if (body) { + parserInput.forget(); + return body; + } + + body = this.atomicCondition(needsParens); + + if (!body) { + parserInput.restore(); + return; + } + + if (!parserInput.$char(')')) { + parserInput.restore(`expected ')' got '${parserInput.currentChar()}'`); + return; + } + + parserInput.forget(); + return body; + }, + atomicCondition: function atomicCondition(needsParens) { + const entities = this.entities; + const index = parserInput.i; + let a; + let b; + let c; + let op; + + function cond() { + return this.addition() || entities.keyword() || entities.quoted() || entities.mixinLookup(); + } + + cond = cond.bind(this); + a = cond(); + + if (a) { + if (parserInput.$char('>')) { + if (parserInput.$char('=')) { + op = '>='; + } else { + op = '>'; + } + } else if (parserInput.$char('<')) { + if (parserInput.$char('=')) { + op = '<='; + } else { + op = '<'; + } + } else if (parserInput.$char('=')) { + if (parserInput.$char('>')) { + op = '=>'; + } else if (parserInput.$char('<')) { + op = '=<'; + } else { + op = '='; + } + } + + if (op) { + b = cond(); + + if (b) { + c = new tree.Condition(op, a, b, index, false); + } else { + error('expected expression'); + } + } else { + c = new tree.Condition('=', a, new tree.Keyword('true'), index, false); + } + + return c; + } + }, + // + // An operand is anything that can be part of an operation, + // such as a Color, or a Variable + // + operand: function operand() { + const entities = this.entities; + let negate; + + if (parserInput.peek(/^-[@\$\(]/)) { + negate = parserInput.$char('-'); + } + + let o = this.sub() || entities.dimension() || entities.color() || entities.variable() || entities.property() || entities.call() || entities.quoted(true) || entities.colorKeyword() || entities.mixinLookup(); + + if (negate) { + o.parensInOp = true; + o = new tree.Negative(o); + } + + return o; + }, + // + // Expressions either represent mathematical operations, + // or white-space delimited Entities. + // + // 1px solid black + // @var * 2 + // + expression: function expression() { + const entities = []; + let e; + let delim; + const index = parserInput.i; + + do { + e = this.comment(); + + if (e) { + entities.push(e); + continue; + } + + e = this.addition() || this.entity(); + + if (e) { + entities.push(e); // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here + + if (!parserInput.peek(/^\/[\/*]/)) { + delim = parserInput.$char('/'); + + if (delim) { + entities.push(new tree.Anonymous(delim, index)); + } + } + } + } while (e); + + if (entities.length > 0) { + return new tree.Expression(entities); + } + }, + property: function property() { + const name = parserInput.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/); + + if (name) { + return name[1]; + } + }, + ruleProperty: function ruleProperty() { + let name = []; + const index = []; + let s; + let k; + parserInput.save(); + const simpleProperty = parserInput.$re(/^([_a-zA-Z0-9-]+)\s*:/); + + if (simpleProperty) { + name = [new tree.Keyword(simpleProperty[1])]; + parserInput.forget(); + return name; + } + + function match(re) { + const i = parserInput.i; + const chunk = parserInput.$re(re); + + if (chunk) { + index.push(i); + return name.push(chunk[1]); + } + } + + match(/^(\*?)/); + + while (true) { + if (!match(/^((?:[\w-]+)|(?:[@\$]\{[\w-]+\}))/)) { + break; + } + } + + if (name.length > 1 && match(/^((?:\+_|\+)?)\s*:/)) { + parserInput.forget(); // at last, we have the complete match now. move forward, + // convert name particles to tree objects and return: + + if (name[0] === '') { + name.shift(); + index.shift(); + } + + for (k = 0; k < name.length; k++) { + s = name[k]; + name[k] = s.charAt(0) !== '@' && s.charAt(0) !== '$' ? new tree.Keyword(s) : s.charAt(0) === '@' ? new tree.Variable(`@${s.slice(2, -1)}`, index[k], fileInfo) : new tree.Property(`$${s.slice(2, -1)}`, index[k], fileInfo); + } + + return name; + } + + parserInput.restore(); + } + } + }; +}; + +Parser.serializeVars = vars => { + let s = ''; + + for (const name in vars) { + if (Object.hasOwnProperty.call(vars, name)) { + const value = vars[name]; + s += `${(name[0] === '@' ? '' : '@') + name}: ${value}${String(value).slice(-1) === ';' ? '' : ';'}`; + } + } + + return s; +}; + +function boolean(condition) { + return condition ? Keyword.True : Keyword.False; +} + +function If(condition, trueValue, falseValue) { + return condition ? trueValue : falseValue || new Anonymous(); +} + +var boolean$1 = { + boolean, + 'if': If +}; + +let colorFunctions; + +function clamp$1(val) { + return Math.min(1, Math.max(0, val)); +} + +function hsla(origColor, hsl) { + const color = colorFunctions.hsla(hsl.h, hsl.s, hsl.l, hsl.a); + + if (color) { + if (origColor.value && /^(rgb|hsl)/.test(origColor.value)) { + color.value = origColor.value; + } else { + color.value = 'rgb'; + } + + return color; + } +} + +function toHSL(color) { + if (color.toHSL) { + return color.toHSL(); + } else { + throw new Error('Argument cannot be evaluated to a color'); + } +} + +function toHSV(color) { + if (color.toHSV) { + return color.toHSV(); + } else { + throw new Error('Argument cannot be evaluated to a color'); + } +} + +function number(n) { + if (n instanceof Dimension) { + return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); + } else if (typeof n === 'number') { + return n; + } else { + throw { + type: 'Argument', + message: 'color functions take numbers as parameters' + }; + } +} + +function scaled(n, size) { + if (n instanceof Dimension && n.unit.is('%')) { + return parseFloat(n.value * size / 100); + } else { + return number(n); + } +} + +colorFunctions = { + rgb: function rgb(r, g, b) { + const color = colorFunctions.rgba(r, g, b, 1.0); + + if (color) { + color.value = 'rgb'; + return color; + } + }, + rgba: function rgba(r, g, b, a) { + try { + if (r instanceof Color) { + if (g) { + a = number(g); + } else { + a = r.alpha; + } + + return new Color(r.rgb, a, 'rgba'); + } + + const rgb = [r, g, b].map(c => scaled(c, 255)); + a = number(a); + return new Color(rgb, a, 'rgba'); + } catch (e) {} + }, + hsl: function hsl(h, s, l) { + const color = colorFunctions.hsla(h, s, l, 1.0); + + if (color) { + color.value = 'hsl'; + return color; + } + }, + hsla: function hsla(h, s, l, a) { + try { + if (h instanceof Color) { + if (s) { + a = number(s); + } else { + a = h.alpha; + } + + return new Color(h.rgb, a, 'hsla'); + } + + let m1; + let m2; + + function hue(h) { + h = h < 0 ? h + 1 : h > 1 ? h - 1 : h; + + if (h * 6 < 1) { + return m1 + (m2 - m1) * h * 6; + } else if (h * 2 < 1) { + return m2; + } else if (h * 3 < 2) { + return m1 + (m2 - m1) * (2 / 3 - h) * 6; + } else { + return m1; + } + } + + h = number(h) % 360 / 360; + s = clamp$1(number(s)); + l = clamp$1(number(l)); + a = clamp$1(number(a)); + m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; + m1 = l * 2 - m2; + const rgb = [hue(h + 1 / 3) * 255, hue(h) * 255, hue(h - 1 / 3) * 255]; + a = number(a); + return new Color(rgb, a, 'hsla'); + } catch (e) {} + }, + hsv: function hsv(h, s, v) { + return colorFunctions.hsva(h, s, v, 1.0); + }, + hsva: function hsva(h, s, v, a) { + h = number(h) % 360 / 360 * 360; + s = number(s); + v = number(v); + a = number(a); + let i; + let f; + i = Math.floor(h / 60 % 6); + f = h / 60 - i; + const vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; + const perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; + return colorFunctions.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); + }, + hue: function hue(color) { + return new Dimension(toHSL(color).h); + }, + saturation: function saturation(color) { + return new Dimension(toHSL(color).s * 100, '%'); + }, + lightness: function lightness(color) { + return new Dimension(toHSL(color).l * 100, '%'); + }, + hsvhue: function hsvhue(color) { + return new Dimension(toHSV(color).h); + }, + hsvsaturation: function hsvsaturation(color) { + return new Dimension(toHSV(color).s * 100, '%'); + }, + hsvvalue: function hsvvalue(color) { + return new Dimension(toHSV(color).v * 100, '%'); + }, + red: function red(color) { + return new Dimension(color.rgb[0]); + }, + green: function green(color) { + return new Dimension(color.rgb[1]); + }, + blue: function blue(color) { + return new Dimension(color.rgb[2]); + }, + alpha: function alpha(color) { + return new Dimension(toHSL(color).a); + }, + luma: function luma(color) { + return new Dimension(color.luma() * color.alpha * 100, '%'); + }, + luminance: function luminance(color) { + const luminance = 0.2126 * color.rgb[0] / 255 + 0.7152 * color.rgb[1] / 255 + 0.0722 * color.rgb[2] / 255; + return new Dimension(luminance * color.alpha * 100, '%'); + }, + saturate: function saturate(color, amount, method) { + // filter: saturate(3.2); + // should be kept as is, so check for color + if (!color.rgb) { + return null; + } + + const hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.s += hsl.s * amount.value / 100; + } else { + hsl.s += amount.value / 100; + } + + hsl.s = clamp$1(hsl.s); + return hsla(color, hsl); + }, + desaturate: function desaturate(color, amount, method) { + const hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.s -= hsl.s * amount.value / 100; + } else { + hsl.s -= amount.value / 100; + } + + hsl.s = clamp$1(hsl.s); + return hsla(color, hsl); + }, + lighten: function lighten(color, amount, method) { + const hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.l += hsl.l * amount.value / 100; + } else { + hsl.l += amount.value / 100; + } + + hsl.l = clamp$1(hsl.l); + return hsla(color, hsl); + }, + darken: function darken(color, amount, method) { + const hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.l -= hsl.l * amount.value / 100; + } else { + hsl.l -= amount.value / 100; + } + + hsl.l = clamp$1(hsl.l); + return hsla(color, hsl); + }, + fadein: function fadein(color, amount, method) { + const hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.a += hsl.a * amount.value / 100; + } else { + hsl.a += amount.value / 100; + } + + hsl.a = clamp$1(hsl.a); + return hsla(color, hsl); + }, + fadeout: function fadeout(color, amount, method) { + const hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.a -= hsl.a * amount.value / 100; + } else { + hsl.a -= amount.value / 100; + } + + hsl.a = clamp$1(hsl.a); + return hsla(color, hsl); + }, + fade: function fade(color, amount) { + const hsl = toHSL(color); + hsl.a = amount.value / 100; + hsl.a = clamp$1(hsl.a); + return hsla(color, hsl); + }, + spin: function spin(color, amount) { + const hsl = toHSL(color); + const hue = (hsl.h + amount.value) % 360; + hsl.h = hue < 0 ? 360 + hue : hue; + return hsla(color, hsl); + }, + // + // Copyright (c) 2006-2009 Hampton Catlin, Natalie Weizenbaum, and Chris Eppstein + // http://sass-lang.com + // + mix: function mix(color1, color2, weight) { + if (!weight) { + weight = new Dimension(50); + } + + const p = weight.value / 100.0; + const w = p * 2 - 1; + const a = toHSL(color1).a - toHSL(color2).a; + const w1 = ((w * a == -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0; + const w2 = 1 - w1; + const rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; + const alpha = color1.alpha * p + color2.alpha * (1 - p); + return new Color(rgb, alpha); + }, + greyscale: function greyscale(color) { + return colorFunctions.desaturate(color, new Dimension(100)); + }, + contrast: function contrast(color, dark, light, threshold) { + // filter: contrast(3.2); + // should be kept as is, so check for color + if (!color.rgb) { + return null; + } + + if (typeof light === 'undefined') { + light = colorFunctions.rgba(255, 255, 255, 1.0); + } + + if (typeof dark === 'undefined') { + dark = colorFunctions.rgba(0, 0, 0, 1.0); + } // Figure out which is actually light and dark: + + + if (dark.luma() > light.luma()) { + const t = light; + light = dark; + dark = t; + } + + if (typeof threshold === 'undefined') { + threshold = 0.43; + } else { + threshold = number(threshold); + } + + if (color.luma() < threshold) { + return light; + } else { + return dark; + } + }, + // Changes made in 2.7.0 - Reverted in 3.0.0 + // contrast: function (color, color1, color2, threshold) { + // // Return which of `color1` and `color2` has the greatest contrast with `color` + // // according to the standard WCAG contrast ratio calculation. + // // http://www.w3.org/TR/WCAG20/#contrast-ratiodef + // // The threshold param is no longer used, in line with SASS. + // // filter: contrast(3.2); + // // should be kept as is, so check for color + // if (!color.rgb) { + // return null; + // } + // if (typeof color1 === 'undefined') { + // color1 = colorFunctions.rgba(0, 0, 0, 1.0); + // } + // if (typeof color2 === 'undefined') { + // color2 = colorFunctions.rgba(255, 255, 255, 1.0); + // } + // var contrast1, contrast2; + // var luma = color.luma(); + // var luma1 = color1.luma(); + // var luma2 = color2.luma(); + // // Calculate contrast ratios for each color + // if (luma > luma1) { + // contrast1 = (luma + 0.05) / (luma1 + 0.05); + // } else { + // contrast1 = (luma1 + 0.05) / (luma + 0.05); + // } + // if (luma > luma2) { + // contrast2 = (luma + 0.05) / (luma2 + 0.05); + // } else { + // contrast2 = (luma2 + 0.05) / (luma + 0.05); + // } + // if (contrast1 > contrast2) { + // return color1; + // } else { + // return color2; + // } + // }, + argb: function argb(color) { + return new Anonymous(color.toARGB()); + }, + color: function color(c) { + if (c instanceof Quoted && /^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})$/i.test(c.value)) { + const val = c.value.slice(1); + return new Color(val, undefined, `#${val}`); + } + + if (c instanceof Color || (c = Color.fromKeyword(c.value))) { + c.value = undefined; + return c; + } + + throw { + type: 'Argument', + message: 'argument must be a color keyword or 3|4|6|8 digit hex e.g. #FFF' + }; + }, + tint: function tint(color, amount) { + return colorFunctions.mix(colorFunctions.rgb(255, 255, 255), color, amount); + }, + shade: function shade(color, amount) { + return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount); + } +}; +var color = colorFunctions; + +// ref: http://www.w3.org/TR/compositing-1 + +function colorBlend(mode, color1, color2) { + const ab = color1.alpha; // result + + let // backdrop + cb; + const as = color2.alpha; + let // source + cs; + let ar; + let cr; + const r = []; + ar = as + ab * (1 - as); + + for (let i = 0; i < 3; i++) { + cb = color1.rgb[i] / 255; + cs = color2.rgb[i] / 255; + cr = mode(cb, cs); + + if (ar) { + cr = (as * cs + ab * (cb - as * (cb + cs - cr))) / ar; + } + + r[i] = cr * 255; + } + + return new Color(r, ar); +} + +const colorBlendModeFunctions = { + multiply: function multiply(cb, cs) { + return cb * cs; + }, + screen: function screen(cb, cs) { + return cb + cs - cb * cs; + }, + overlay: function overlay(cb, cs) { + cb *= 2; + return cb <= 1 ? colorBlendModeFunctions.multiply(cb, cs) : colorBlendModeFunctions.screen(cb - 1, cs); + }, + softlight: function softlight(cb, cs) { + let d = 1; + let e = cb; + + if (cs > 0.5) { + e = 1; + d = cb > 0.25 ? Math.sqrt(cb) : ((16 * cb - 12) * cb + 4) * cb; + } + + return cb - (1 - 2 * cs) * e * (d - cb); + }, + hardlight: function hardlight(cb, cs) { + return colorBlendModeFunctions.overlay(cs, cb); + }, + difference: function difference(cb, cs) { + return Math.abs(cb - cs); + }, + exclusion: function exclusion(cb, cs) { + return cb + cs - 2 * cb * cs; + }, + // non-w3c functions: + average: function average(cb, cs) { + return (cb + cs) / 2; + }, + negation: function negation(cb, cs) { + return 1 - Math.abs(cb + cs - 1); + } +}; + +for (const f in colorBlendModeFunctions) { + if (colorBlendModeFunctions.hasOwnProperty(f)) { + colorBlend[f] = colorBlend.bind(null, colorBlendModeFunctions[f]); + } +} + +var dataUri = (environment => { + const fallback = (functionThis, node) => new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context); + + return { + 'data-uri': function dataUri(mimetypeNode, filePathNode) { + if (!filePathNode) { + filePathNode = mimetypeNode; + mimetypeNode = null; + } + + let mimetype = mimetypeNode && mimetypeNode.value; + let filePath = filePathNode.value; + const currentFileInfo = this.currentFileInfo; + const currentDirectory = currentFileInfo.rewriteUrls ? currentFileInfo.currentDirectory : currentFileInfo.entryPath; + const fragmentStart = filePath.indexOf('#'); + let fragment = ''; + + if (fragmentStart !== -1) { + fragment = filePath.slice(fragmentStart); + filePath = filePath.slice(0, fragmentStart); + } + + const context = clone(this.context); + context.rawBuffer = true; + const fileManager = environment.getFileManager(filePath, currentDirectory, context, environment, true); + + if (!fileManager) { + return fallback(this, filePathNode); + } + + let useBase64 = false; // detect the mimetype if not given + + if (!mimetypeNode) { + mimetype = environment.mimeLookup(filePath); + + if (mimetype === 'image/svg+xml') { + useBase64 = false; + } else { + // use base 64 unless it's an ASCII or UTF-8 format + const charset = environment.charsetLookup(mimetype); + useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; + } + + if (useBase64) { + mimetype += ';base64'; + } + } else { + useBase64 = /;base64$/.test(mimetype); + } + + const fileSync = fileManager.loadFileSync(filePath, currentDirectory, context, environment); + + if (!fileSync.contents) { + logger.warn(`Skipped data-uri embedding of ${filePath} because file not found`); + return fallback(this, filePathNode || mimetypeNode); + } + + let buf = fileSync.contents; + + if (useBase64 && !environment.encodeBase64) { + return fallback(this, filePathNode); + } + + buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf); + const uri = `data:${mimetype},${buf}${fragment}`; + return new URL(new Quoted(`"${uri}"`, uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); + } + }; +}); + +const getItemsFromNode = node => { + // handle non-array values as an array of length 1 + // return 'undefined' if index is invalid + const items = Array.isArray(node.value) ? node.value : Array(node); + return items; +}; + +var list = { + _SELF: function _SELF(n) { + return n; + }, + extract: function extract(values, index) { + index = index.value - 1; // (1-based index) + + return getItemsFromNode(values)[index]; + }, + length: function length(values) { + return new Dimension(getItemsFromNode(values).length); + }, + + /** + * Creates a Less list of incremental values. + * Modeled after Lodash's range function, also exists natively in PHP + * + * @param {Dimension} [start=1] + * @param {Dimension} end - e.g. 10 or 10px - unit is added to output + * @param {Dimension} [step=1] + */ + range: function range(start, end, step) { + let from; + let to; + let stepValue = 1; + const list = []; + + if (end) { + to = end; + from = start.value; + + if (step) { + stepValue = step.value; + } + } else { + from = 1; + to = start; + } + + for (let i = from; i <= to.value; i += stepValue) { + list.push(new Dimension(i, to.unit)); + } + + return new Expression(list); + }, + each: function each(list, rs) { + const rules = []; + let newRules; + let iterator; + + if (list.value && !(list instanceof Quoted)) { + if (Array.isArray(list.value)) { + iterator = list.value; + } else { + iterator = [list.value]; + } + } else if (list.ruleset) { + iterator = list.ruleset.rules; + } else if (list.rules) { + iterator = list.rules; + } else if (Array.isArray(list)) { + iterator = list; + } else { + iterator = [list]; + } + + let valueName = '@value'; + let keyName = '@key'; + let indexName = '@index'; + + if (rs.params) { + valueName = rs.params[0] && rs.params[0].name; + keyName = rs.params[1] && rs.params[1].name; + indexName = rs.params[2] && rs.params[2].name; + rs = rs.rules; + } else { + rs = rs.ruleset; + } + + for (let i = 0; i < iterator.length; i++) { + let key; + let value; + const item = iterator[i]; + + if (item instanceof Declaration) { + key = typeof item.name === 'string' ? item.name : item.name[0].value; + value = item.value; + } else { + key = new Dimension(i + 1); + value = item; + } + + if (item instanceof Comment) { + continue; + } + + newRules = rs.rules.slice(0); + + if (valueName) { + newRules.push(new Declaration(valueName, value, false, false, this.index, this.currentFileInfo)); + } + + if (indexName) { + newRules.push(new Declaration(indexName, new Dimension(i + 1), false, false, this.index, this.currentFileInfo)); + } + + if (keyName) { + newRules.push(new Declaration(keyName, key, false, false, this.index, this.currentFileInfo)); + } + + rules.push(new Ruleset([new Selector([new Element("", '&')])], newRules, rs.strictImports, rs.visibilityInfo())); + } + + return new Ruleset([new Selector([new Element("", '&')])], rules, rs.strictImports, rs.visibilityInfo()).eval(this.context); + } +}; + +const MathHelper = (fn, unit, n) => { + if (!(n instanceof Dimension)) { + throw { + type: 'Argument', + message: 'argument must be a number' + }; + } + + if (unit == null) { + unit = n.unit; + } else { + n = n.unify(); + } + + return new Dimension(fn(parseFloat(n.value)), unit); +}; + +const mathFunctions = { + // name, unit + ceil: null, + floor: null, + sqrt: null, + abs: null, + tan: '', + sin: '', + cos: '', + atan: 'rad', + asin: 'rad', + acos: 'rad' +}; + +for (const f in mathFunctions) { + if (mathFunctions.hasOwnProperty(f)) { + mathFunctions[f] = MathHelper.bind(null, Math[f], mathFunctions[f]); + } +} + +mathFunctions.round = (n, f) => { + const fraction = typeof f === 'undefined' ? 0 : f.value; + return MathHelper(num => num.toFixed(fraction), null, n); +}; + +const minMax = function minMax(isMin, args) { + args = Array.prototype.slice.call(args); + + switch (args.length) { + case 0: + throw { + type: 'Argument', + message: 'one or more arguments required' + }; + } + + let i; // key is the unit.toString() for unified Dimension values, + + let j; + let current; + let currentUnified; + let referenceUnified; + let unit; + let unitStatic; + let unitClone; + const // elems only contains original argument values. + order = []; + const values = {}; // value is the index into the order array. + + for (i = 0; i < args.length; i++) { + current = args[i]; + + if (!(current instanceof Dimension)) { + if (Array.isArray(args[i].value)) { + Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value)); + } + + continue; + } + + currentUnified = current.unit.toString() === '' && unitClone !== undefined ? new Dimension(current.value, unitClone).unify() : current.unify(); + unit = currentUnified.unit.toString() === '' && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString(); + unitStatic = unit !== '' && unitStatic === undefined || unit !== '' && order[0].unify().unit.toString() === '' ? unit : unitStatic; + unitClone = unit !== '' && unitClone === undefined ? current.unit.toString() : unitClone; + j = values[''] !== undefined && unit !== '' && unit === unitStatic ? values[''] : values[unit]; + + if (j === undefined) { + if (unitStatic !== undefined && unit !== unitStatic) { + throw { + type: 'Argument', + message: 'incompatible types' + }; + } + + values[unit] = order.length; + order.push(current); + continue; + } + + referenceUnified = order[j].unit.toString() === '' && unitClone !== undefined ? new Dimension(order[j].value, unitClone).unify() : order[j].unify(); + + if (isMin && currentUnified.value < referenceUnified.value || !isMin && currentUnified.value > referenceUnified.value) { + order[j] = current; + } + } + + if (order.length == 1) { + return order[0]; + } + + args = order.map(function (a) { + return a.toCSS(this.context); + }).join(this.context.compress ? ',' : ', '); + return new Anonymous(`${isMin ? 'min' : 'max'}(${args})`); +}; + +var number$1 = { + min: function min(...args) { + return minMax(true, args); + }, + max: function max(...args) { + return minMax(false, args); + }, + convert: function convert(val, unit) { + return val.convertTo(unit.value); + }, + pi: function pi() { + return new Dimension(Math.PI); + }, + mod: function mod(a, b) { + return new Dimension(a.value % b.value, a.unit); + }, + pow: function pow(x, y) { + if (typeof x === 'number' && typeof y === 'number') { + x = new Dimension(x); + y = new Dimension(y); + } else if (!(x instanceof Dimension) || !(y instanceof Dimension)) { + throw { + type: 'Argument', + message: 'arguments must be numbers' + }; + } + + return new Dimension(Math.pow(x.value, y.value), x.unit); + }, + percentage: function percentage(n) { + const result = MathHelper(num => num * 100, '%', n); + return result; + } +}; + +var string = { + e: function e(str) { + return new Quoted('"', str instanceof JavaScript ? str.evaluated : str.value, true); + }, + escape: function escape(str) { + return new Anonymous(encodeURI(str.value).replace(/=/g, '%3D').replace(/:/g, '%3A').replace(/#/g, '%23').replace(/;/g, '%3B').replace(/\(/g, '%28').replace(/\)/g, '%29')); + }, + replace: function replace(string, pattern, replacement, flags) { + let result = string.value; + replacement = replacement.type === 'Quoted' ? replacement.value : replacement.toCSS(); + result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement); + return new Quoted(string.quote || '', result, string.escaped); + }, + '%': function _(string + /* arg, arg, ... */ + ) { + const args = Array.prototype.slice.call(arguments, 1); + let result = string.value; + + for (let i = 0; i < args.length; i++) { + /* jshint loopfunc:true */ + result = result.replace(/%[sda]/i, token => { + const value = args[i].type === 'Quoted' && token.match(/s/i) ? args[i].value : args[i].toCSS(); + return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; + }); + } + + result = result.replace(/%%/g, '%'); + return new Quoted(string.quote || '', result, string.escaped); + } +}; + +var svg = (environment => { + return { + 'svg-gradient': function svgGradient(direction) { + let stops; + let gradientDirectionSvg; + let gradientType = 'linear'; + let rectangleDimension = 'x="0" y="0" width="1" height="1"'; + const renderEnv = { + compress: false + }; + let returner; + const directionValue = direction.toCSS(renderEnv); + let i; + let color; + let position; + let positionValue; + let alpha; + + function throwArgumentDescriptor() { + throw { + type: 'Argument', + message: 'svg-gradient expects direction, start_color [start_position], [color position,]...,' + ' end_color [end_position] or direction, color list' + }; + } + + if (arguments.length == 2) { + if (arguments[1].value.length < 2) { + throwArgumentDescriptor(); + } + + stops = arguments[1].value; + } else if (arguments.length < 3) { + throwArgumentDescriptor(); + } else { + stops = Array.prototype.slice.call(arguments, 1); + } + + switch (directionValue) { + case 'to bottom': + gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"'; + break; + + case 'to right': + gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"'; + break; + + case 'to bottom right': + gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"'; + break; + + case 'to top right': + gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"'; + break; + + case 'ellipse': + case 'ellipse at center': + gradientType = 'radial'; + gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"'; + rectangleDimension = 'x="-50" y="-50" width="101" height="101"'; + break; + + default: + throw { + type: 'Argument', + message: 'svg-gradient direction must be \'to bottom\', \'to right\',' + ' \'to bottom right\', \'to top right\' or \'ellipse at center\'' + }; + } + + returner = `<${gradientType}Gradient id="g" ${gradientDirectionSvg}>`; + + for (i = 0; i < stops.length; i += 1) { + if (stops[i] instanceof Expression) { + color = stops[i].value[0]; + position = stops[i].value[1]; + } else { + color = stops[i]; + position = undefined; + } + + if (!(color instanceof Color) || !((i === 0 || i + 1 === stops.length) && position === undefined) && !(position instanceof Dimension)) { + throwArgumentDescriptor(); + } + + positionValue = position ? position.toCSS(renderEnv) : i === 0 ? '0%' : '100%'; + alpha = color.alpha; + returner += ``; + } + + returner += ``; + returner = encodeURIComponent(returner); + returner = `data:image/svg+xml,${returner}`; + return new URL(new Quoted(`'${returner}'`, returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); + } + }; +}); + +const isa = (n, Type) => n instanceof Type ? Keyword.True : Keyword.False; + +const isunit = (n, unit) => { + if (unit === undefined) { + throw { + type: 'Argument', + message: 'missing the required second argument to isunit.' + }; + } + + unit = typeof unit.value === 'string' ? unit.value : unit; + + if (typeof unit !== 'string') { + throw { + type: 'Argument', + message: 'Second argument to isunit should be a unit or a string.' + }; + } + + return n instanceof Dimension && n.unit.is(unit) ? Keyword.True : Keyword.False; +}; + +var types = { + isruleset: function isruleset(n) { + return isa(n, DetachedRuleset); + }, + iscolor: function iscolor(n) { + return isa(n, Color); + }, + isnumber: function isnumber(n) { + return isa(n, Dimension); + }, + isstring: function isstring(n) { + return isa(n, Quoted); + }, + iskeyword: function iskeyword(n) { + return isa(n, Keyword); + }, + isurl: function isurl(n) { + return isa(n, URL); + }, + ispixel: function ispixel(n) { + return isunit(n, 'px'); + }, + ispercentage: function ispercentage(n) { + return isunit(n, '%'); + }, + isem: function isem(n) { + return isunit(n, 'em'); + }, + isunit, + unit: function unit(val, _unit) { + if (!(val instanceof Dimension)) { + throw { + type: 'Argument', + message: `the first argument to unit must be a number${val instanceof Operation ? '. Have you forgotten parenthesis?' : ''}` + }; + } + + if (_unit) { + if (_unit instanceof Keyword) { + _unit = _unit.value; + } else { + _unit = _unit.toCSS(); + } + } else { + _unit = ''; + } + + return new Dimension(val.value, _unit); + }, + 'get-unit': function getUnit(n) { + return new Anonymous(n.unit); + } +}; + +var Functions = (environment => { + const functions = { + functionRegistry, + functionCaller + }; // register functions + + functionRegistry.addMultiple(boolean$1); + functionRegistry.add('default', defaultFunc.eval.bind(defaultFunc)); + functionRegistry.addMultiple(color); + functionRegistry.addMultiple(colorBlend); + functionRegistry.addMultiple(dataUri(environment)); + functionRegistry.addMultiple(list); + functionRegistry.addMultiple(mathFunctions); + functionRegistry.addMultiple(number$1); + functionRegistry.addMultiple(string); + functionRegistry.addMultiple(svg()); + functionRegistry.addMultiple(types); + return functions; +}); + +var sourceMapOutput = (environment => { + class SourceMapOutput { + constructor(options) { + this._css = []; + this._rootNode = options.rootNode; + this._contentsMap = options.contentsMap; + this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap; + + if (options.sourceMapFilename) { + this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/'); + } + + this._outputFilename = options.outputFilename; + this.sourceMapURL = options.sourceMapURL; + + if (options.sourceMapBasepath) { + this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/'); + } + + if (options.sourceMapRootpath) { + this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/'); + + if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') { + this._sourceMapRootpath += '/'; + } + } else { + this._sourceMapRootpath = ''; + } + + this._outputSourceFiles = options.outputSourceFiles; + this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator(); + this._lineNumber = 0; + this._column = 0; + } + + removeBasepath(path) { + if (this._sourceMapBasepath && path.indexOf(this._sourceMapBasepath) === 0) { + path = path.substring(this._sourceMapBasepath.length); + + if (path.charAt(0) === '\\' || path.charAt(0) === '/') { + path = path.substring(1); + } + } + + return path; + } + + normalizeFilename(filename) { + filename = filename.replace(/\\/g, '/'); + filename = this.removeBasepath(filename); + return (this._sourceMapRootpath || '') + filename; + } + + add(chunk, fileInfo, index, mapLines) { + // ignore adding empty strings + if (!chunk) { + return; + } + + let lines; + let sourceLines; + let columns; + let sourceColumns; + let i; + + if (fileInfo && fileInfo.filename) { + let inputSource = this._contentsMap[fileInfo.filename]; // remove vars/banner added to the top of the file + + if (this._contentsIgnoredCharsMap[fileInfo.filename]) { + // adjust the index + index -= this._contentsIgnoredCharsMap[fileInfo.filename]; + + if (index < 0) { + index = 0; + } // adjust the source + + + inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]); + } // ignore empty content + + + if (inputSource === undefined) { + return; + } + + inputSource = inputSource.substring(0, index); + sourceLines = inputSource.split('\n'); + sourceColumns = sourceLines[sourceLines.length - 1]; + } + + lines = chunk.split('\n'); + columns = lines[lines.length - 1]; + + if (fileInfo && fileInfo.filename) { + if (!mapLines) { + this._sourceMapGenerator.addMapping({ + generated: { + line: this._lineNumber + 1, + column: this._column + }, + original: { + line: sourceLines.length, + column: sourceColumns.length + }, + source: this.normalizeFilename(fileInfo.filename) + }); + } else { + for (i = 0; i < lines.length; i++) { + this._sourceMapGenerator.addMapping({ + generated: { + line: this._lineNumber + i + 1, + column: i === 0 ? this._column : 0 + }, + original: { + line: sourceLines.length + i, + column: i === 0 ? sourceColumns.length : 0 + }, + source: this.normalizeFilename(fileInfo.filename) + }); + } + } + } + + if (lines.length === 1) { + this._column += columns.length; + } else { + this._lineNumber += lines.length - 1; + this._column = columns.length; + } + + this._css.push(chunk); + } + + isEmpty() { + return this._css.length === 0; + } + + toCSS(context) { + this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ + file: this._outputFilename, + sourceRoot: null + }); + + if (this._outputSourceFiles) { + for (const filename in this._contentsMap) { + if (this._contentsMap.hasOwnProperty(filename)) { + let source = this._contentsMap[filename]; + + if (this._contentsIgnoredCharsMap[filename]) { + source = source.slice(this._contentsIgnoredCharsMap[filename]); + } + + this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source); + } + } + } + + this._rootNode.genCSS(context, this); + + if (this._css.length > 0) { + let sourceMapURL; + const sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON()); + + if (this.sourceMapURL) { + sourceMapURL = this.sourceMapURL; + } else if (this._sourceMapFilename) { + sourceMapURL = this._sourceMapFilename; + } + + this.sourceMapURL = sourceMapURL; + this.sourceMap = sourceMapContent; + } + + return this._css.join(''); + } + + } + + return SourceMapOutput; +}); + +var sourceMapBuilder = ((SourceMapOutput, environment) => { + class SourceMapBuilder { + constructor(options) { + this.options = options; + } + + toCSS(rootNode, options, imports) { + const sourceMapOutput = new SourceMapOutput({ + contentsIgnoredCharsMap: imports.contentsIgnoredChars, + rootNode, + contentsMap: imports.contents, + sourceMapFilename: this.options.sourceMapFilename, + sourceMapURL: this.options.sourceMapURL, + outputFilename: this.options.sourceMapOutputFilename, + sourceMapBasepath: this.options.sourceMapBasepath, + sourceMapRootpath: this.options.sourceMapRootpath, + outputSourceFiles: this.options.outputSourceFiles, + sourceMapGenerator: this.options.sourceMapGenerator, + sourceMapFileInline: this.options.sourceMapFileInline + }); + const css = sourceMapOutput.toCSS(options); + this.sourceMap = sourceMapOutput.sourceMap; + this.sourceMapURL = sourceMapOutput.sourceMapURL; + + if (this.options.sourceMapInputFilename) { + this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename); + } + + if (this.options.sourceMapBasepath !== undefined && this.sourceMapURL !== undefined) { + this.sourceMapURL = sourceMapOutput.removeBasepath(this.sourceMapURL); + } + + return css + this.getCSSAppendage(); + } + + getCSSAppendage() { + let sourceMapURL = this.sourceMapURL; + + if (this.options.sourceMapFileInline) { + if (this.sourceMap === undefined) { + return ''; + } + + sourceMapURL = `data:application/json;base64,${environment.encodeBase64(this.sourceMap)}`; + } + + if (sourceMapURL) { + return `/*# sourceMappingURL=${sourceMapURL} */`; + } + + return ''; + } + + getExternalSourceMap() { + return this.sourceMap; + } + + setExternalSourceMap(sourceMap) { + this.sourceMap = sourceMap; + } + + isInline() { + return this.options.sourceMapFileInline; + } + + getSourceMapURL() { + return this.sourceMapURL; + } + + getOutputFilename() { + return this.options.sourceMapOutputFilename; + } + + getInputFilename() { + return this.sourceMapInputFilename; + } + + } + + return SourceMapBuilder; +}); + +var transformTree = ((root, options = {}) => { + let evaldRoot; + let variables = options.variables; + const evalEnv = new contexts.Eval(options); // + // Allows setting variables with a hash, so: + // + // `{ color: new tree.Color('#f01') }` will become: + // + // new tree.Declaration('@color', + // new tree.Value([ + // new tree.Expression([ + // new tree.Color('#f01') + // ]) + // ]) + // ) + // + + if (typeof variables === 'object' && !Array.isArray(variables)) { + variables = Object.keys(variables).map(k => { + let value = variables[k]; + + if (!(value instanceof tree.Value)) { + if (!(value instanceof tree.Expression)) { + value = new tree.Expression([value]); + } + + value = new tree.Value([value]); + } + + return new tree.Declaration(`@${k}`, value, false, null, 0); + }); + evalEnv.frames = [new tree.Ruleset(null, variables)]; + } + + const visitors$1 = [new visitors.JoinSelectorVisitor(), new visitors.MarkVisibleSelectorsVisitor(true), new visitors.ExtendVisitor(), new visitors.ToCSSVisitor({ + compress: Boolean(options.compress) + })]; + const preEvalVisitors = []; + let v; + let visitorIterator; + /** + * first() / get() allows visitors to be added while visiting + * + * @todo Add scoping for visitors just like functions for @plugin; right now they're global + */ + + if (options.pluginManager) { + visitorIterator = options.pluginManager.visitor(); + + for (var i = 0; i < 2; i++) { + visitorIterator.first(); + + while (v = visitorIterator.get()) { + if (v.isPreEvalVisitor) { + if (i === 0 || preEvalVisitors.indexOf(v) === -1) { + preEvalVisitors.push(v); + v.run(root); + } + } else { + if (i === 0 || visitors$1.indexOf(v) === -1) { + if (v.isPreVisitor) { + visitors$1.unshift(v); + } else { + visitors$1.push(v); + } + } + } + } + } + } + + evaldRoot = root.eval(evalEnv); + + for (var i = 0; i < visitors$1.length; i++) { + visitors$1[i].run(evaldRoot); + } // Run any remaining visitors added after eval pass + + + if (options.pluginManager) { + visitorIterator.first(); + + while (v = visitorIterator.get()) { + if (visitors$1.indexOf(v) === -1 && preEvalVisitors.indexOf(v) === -1) { + v.run(evaldRoot); + } + } + } + + return evaldRoot; +}); + +var parseTree = (SourceMapBuilder => { + class ParseTree { + constructor(root, imports) { + this.root = root; + this.imports = imports; + } + + toCSS(options) { + let evaldRoot; + const result = {}; + let sourceMapBuilder; + + try { + evaldRoot = transformTree(this.root, options); + } catch (e) { + throw new LessError(e, this.imports); + } + + try { + const compress = Boolean(options.compress); + + if (compress) { + logger.warn('The compress option has been deprecated. ' + 'We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.'); + } + + const toCSSOptions = { + compress, + dumpLineNumbers: options.dumpLineNumbers, + strictUnits: Boolean(options.strictUnits), + numPrecision: 8 + }; + + if (options.sourceMap) { + sourceMapBuilder = new SourceMapBuilder(options.sourceMap); + result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports); + } else { + result.css = evaldRoot.toCSS(toCSSOptions); + } + } catch (e) { + throw new LessError(e, this.imports); + } + + if (options.pluginManager) { + const postProcessors = options.pluginManager.getPostProcessors(); + + for (let i = 0; i < postProcessors.length; i++) { + result.css = postProcessors[i].process(result.css, { + sourceMap: sourceMapBuilder, + options, + imports: this.imports + }); + } + } + + if (options.sourceMap) { + result.map = sourceMapBuilder.getExternalSourceMap(); + } + + result.imports = []; + + for (const file in this.imports.files) { + if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) { + result.imports.push(file); + } + } + + return result; + } + + } + + return ParseTree; +}); + +var importManager = (environment => { + // FileInfo = { + // 'rewriteUrls' - option - whether to adjust URL's to be relative + // 'filename' - full resolved filename of current file + // 'rootpath' - path to append to normal URLs for this node + // 'currentDirectory' - path to the current file, absolute + // 'rootFilename' - filename of the base file + // 'entryPath' - absolute path to the entry file + // 'reference' - whether the file should not be output and only output parts that are referenced + class ImportManager { + constructor(less, context, rootFileInfo) { + this.less = less; + this.rootFilename = rootFileInfo.filename; + this.paths = context.paths || []; // Search paths, when importing + + this.contents = {}; // map - filename to contents of all the files + + this.contentsIgnoredChars = {}; // map - filename to lines at the beginning of each file to ignore + + this.mime = context.mime; + this.error = null; + this.context = context; // Deprecated? Unused outside of here, could be useful. + + this.queue = []; // Files which haven't been imported yet + + this.files = {}; // Holds the imported parse trees. + } + /** + * Add an import to be imported + * @param path - the raw path + * @param tryAppendExtension - whether to try appending a file extension (.less or .js if the path has no extension) + * @param currentFileInfo - the current file info (used for instance to work out relative paths) + * @param importOptions - import options + * @param callback - callback for when it is imported + */ + + + push(path, tryAppendExtension, currentFileInfo, importOptions, callback) { + const importManager = this; + const pluginLoader = this.context.pluginManager.Loader; + this.queue.push(path); + + const fileParsedFunc = (e, root, fullPath) => { + importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue + + const importedEqualsRoot = fullPath === importManager.rootFilename; + + if (importOptions.optional && e) { + callback(null, { + rules: [] + }, false, null); + logger.info(`The file ${fullPath} was skipped because it was not found and the import was marked optional.`); + } else { + // Inline imports aren't cached here. + // If we start to cache them, please make sure they won't conflict with non-inline imports of the + // same name as they used to do before this comment and the condition below have been added. + if (!importManager.files[fullPath] && !importOptions.inline) { + importManager.files[fullPath] = { + root, + options: importOptions + }; + } + + if (e && !importManager.error) { + importManager.error = e; + } + + callback(e, root, importedEqualsRoot, fullPath); + } + }; + + const newFileInfo = { + rewriteUrls: this.context.rewriteUrls, + entryPath: currentFileInfo.entryPath, + rootpath: currentFileInfo.rootpath, + rootFilename: currentFileInfo.rootFilename + }; + const fileManager = environment.getFileManager(path, currentFileInfo.currentDirectory, this.context, environment); + + if (!fileManager) { + fileParsedFunc({ + message: `Could not find a file-manager for ${path}` + }); + return; + } + + const loadFileCallback = loadedFile => { + let plugin; + const resolvedFilename = loadedFile.filename; + const contents = loadedFile.contents.replace(/^\uFEFF/, ''); // Pass on an updated rootpath if path of imported file is relative and file + // is in a (sub|sup) directory + // + // Examples: + // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/', + // then rootpath should become 'less/module/nav/' + // - If path of imported file is '../mixins.less' and rootpath is 'less/', + // then rootpath should become 'less/../' + + newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename); + + if (newFileInfo.rewriteUrls) { + newFileInfo.rootpath = fileManager.join(importManager.context.rootpath || '', fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath)); + + if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) { + newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath); + } + } + + newFileInfo.filename = resolvedFilename; + const newEnv = new contexts.Parse(importManager.context); + newEnv.processImports = false; + importManager.contents[resolvedFilename] = contents; + + if (currentFileInfo.reference || importOptions.reference) { + newFileInfo.reference = true; + } + + if (importOptions.isPlugin) { + plugin = pluginLoader.evalPlugin(contents, newEnv, importManager, importOptions.pluginArgs, newFileInfo); + + if (plugin instanceof LessError) { + fileParsedFunc(plugin, null, resolvedFilename); + } else { + fileParsedFunc(null, plugin, resolvedFilename); + } + } else if (importOptions.inline) { + fileParsedFunc(null, contents, resolvedFilename); + } else { + // import (multiple) parse trees apparently get altered and can't be cached. + // TODO: investigate why this is + if (importManager.files[resolvedFilename] && !importManager.files[resolvedFilename].options.multiple && !importOptions.multiple) { + fileParsedFunc(null, importManager.files[resolvedFilename].root, resolvedFilename); + } else { + new Parser(newEnv, importManager, newFileInfo).parse(contents, (e, root) => { + fileParsedFunc(e, root, resolvedFilename); + }); + } + } + }; + + let promise; + const context = clone(this.context); + + if (tryAppendExtension) { + context.ext = importOptions.isPlugin ? '.js' : '.less'; + } + + if (importOptions.isPlugin) { + context.mime = 'application/javascript'; + promise = pluginLoader.loadPlugin(path, currentFileInfo.currentDirectory, context, environment, fileManager); + } else { + promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, context, environment, (err, loadedFile) => { + if (err) { + fileParsedFunc(err); + } else { + loadFileCallback(loadedFile); + } + }); + } + + if (promise) { + promise.then(loadFileCallback, fileParsedFunc); + } + } + + } + + return ImportManager; +}); + +var Render = ((environment, ParseTree, ImportManager) => { + const render = function render(input, options, callback) { + if (typeof options === 'function') { + callback = options; + options = copyOptions(this.options, {}); + } else { + options = copyOptions(this.options, options || {}); + } + + if (!callback) { + const self = this; + return new Promise((resolve, reject) => { + render.call(self, input, options, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + }); + }); + } else { + this.parse(input, options, (err, root, imports, options) => { + if (err) { + return callback(err); + } + + let result; + + try { + const parseTree = new ParseTree(root, imports); + result = parseTree.toCSS(options); + } catch (err) { + return callback(err); + } + + callback(null, result); + }); + } + }; + + return render; +}); + +/** + * Plugin Manager + */ +class PluginManager { + constructor(less) { + this.less = less; + this.visitors = []; + this.preProcessors = []; + this.postProcessors = []; + this.installedPlugins = []; + this.fileManagers = []; + this.iterator = -1; + this.pluginCache = {}; + this.Loader = new less.PluginLoader(less); + } + /** + * Adds all the plugins in the array + * @param {Array} plugins + */ + + + addPlugins(plugins) { + if (plugins) { + for (let i = 0; i < plugins.length; i++) { + this.addPlugin(plugins[i]); + } + } + } + /** + * + * @param plugin + * @param {String} filename + */ + + + addPlugin(plugin, filename, functionRegistry) { + this.installedPlugins.push(plugin); + + if (filename) { + this.pluginCache[filename] = plugin; + } + + if (plugin.install) { + plugin.install(this.less, this, functionRegistry || this.less.functions.functionRegistry); + } + } + /** + * + * @param filename + */ + + + get(filename) { + return this.pluginCache[filename]; + } + /** + * Adds a visitor. The visitor object has options on itself to determine + * when it should run. + * @param visitor + */ + + + addVisitor(visitor) { + this.visitors.push(visitor); + } + /** + * Adds a pre processor object + * @param {object} preProcessor + * @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import + */ + + + addPreProcessor(preProcessor, priority) { + let indexToInsertAt; + + for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) { + if (this.preProcessors[indexToInsertAt].priority >= priority) { + break; + } + } + + this.preProcessors.splice(indexToInsertAt, 0, { + preProcessor, + priority + }); + } + /** + * Adds a post processor object + * @param {object} postProcessor + * @param {number} priority - guidelines 1 = before compression, 1000 = compression, 2000 = after compression + */ + + + addPostProcessor(postProcessor, priority) { + let indexToInsertAt; + + for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) { + if (this.postProcessors[indexToInsertAt].priority >= priority) { + break; + } + } + + this.postProcessors.splice(indexToInsertAt, 0, { + postProcessor, + priority + }); + } + /** + * + * @param manager + */ + + + addFileManager(manager) { + this.fileManagers.push(manager); + } + /** + * + * @returns {Array} + * @private + */ + + + getPreProcessors() { + const preProcessors = []; + + for (let i = 0; i < this.preProcessors.length; i++) { + preProcessors.push(this.preProcessors[i].preProcessor); + } + + return preProcessors; + } + /** + * + * @returns {Array} + * @private + */ + + + getPostProcessors() { + const postProcessors = []; + + for (let i = 0; i < this.postProcessors.length; i++) { + postProcessors.push(this.postProcessors[i].postProcessor); + } + + return postProcessors; + } + /** + * + * @returns {Array} + * @private + */ + + + getVisitors() { + return this.visitors; + } + + visitor() { + const self = this; + return { + first: function first() { + self.iterator = -1; + return self.visitors[self.iterator]; + }, + get: function get() { + self.iterator += 1; + return self.visitors[self.iterator]; + } + }; + } + /** + * + * @returns {Array} + * @private + */ + + + getFileManagers() { + return this.fileManagers; + } + +} + +let pm; + +function PluginManagerFactory(less, newFactory) { + if (newFactory || !pm) { + pm = new PluginManager(less); + } + + return pm; +} + +var Parse = ((environment, ParseTree, ImportManager) => { + const parse = function parse(input, options, callback) { + if (typeof options === 'function') { + callback = options; + options = copyOptions(this.options, {}); + } else { + options = copyOptions(this.options, options || {}); + } + + if (!callback) { + const self = this; + return new Promise((resolve, reject) => { + parse.call(self, input, options, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + }); + }); + } else { + let context; + let rootFileInfo; + const pluginManager = new PluginManagerFactory(this, !options.reUsePluginManager); + options.pluginManager = pluginManager; + context = new contexts.Parse(options); + + if (options.rootFileInfo) { + rootFileInfo = options.rootFileInfo; + } else { + const filename = options.filename || 'input'; + const entryPath = filename.replace(/[^\/\\]*$/, ''); + rootFileInfo = { + filename, + rewriteUrls: context.rewriteUrls, + rootpath: context.rootpath || '', + currentDirectory: entryPath, + entryPath, + rootFilename: filename + }; // add in a missing trailing slash + + if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== '/') { + rootFileInfo.rootpath += '/'; + } + } + + const imports = new ImportManager(this, context, rootFileInfo); + this.importManager = imports; // TODO: allow the plugins to be just a list of paths or names + // Do an async plugin queue like lessc + + if (options.plugins) { + options.plugins.forEach(plugin => { + let evalResult; + let contents; + + if (plugin.fileContent) { + contents = plugin.fileContent.replace(/^\uFEFF/, ''); + evalResult = pluginManager.Loader.evalPlugin(contents, context, imports, plugin.options, plugin.filename); + + if (evalResult instanceof LessError) { + return callback(evalResult); + } + } else { + pluginManager.addPlugin(plugin); + } + }); + } + + new Parser(context, imports, rootFileInfo).parse(input, (e, root) => { + if (e) { + return callback(e); + } + + callback(null, root, imports, options); + }, options); + } + }; + + return parse; +}); + +var createFromEnvironment = ((environment, fileManagers) => { + /** + * @todo + * This original code could be improved quite a bit. + * Many classes / modules currently add side-effects / mutations to passed in objects, + * which makes it hard to refactor and reason about. + */ + environment = new environment$1(environment, fileManagers); + const SourceMapOutput = sourceMapOutput(environment); + const SourceMapBuilder = sourceMapBuilder(SourceMapOutput, environment); + const ParseTree = parseTree(SourceMapBuilder); + const ImportManager = importManager(environment); + const render = Render(environment, ParseTree); + const parse = Parse(environment, ParseTree, ImportManager); + const functions = Functions(environment); + /** + * @todo + * This root properties / methods need to be organized. + * It's not clear what should / must be public and why. + */ + + const initial = { + version: [3, 10, 0], + data, + tree, + Environment: environment$1, + AbstractFileManager, + AbstractPluginLoader, + environment, + visitors, + Parser, + functions, + contexts, + SourceMapOutput, + SourceMapBuilder, + ParseTree, + ImportManager, + render, + parse, + LessError, + transformTree, + utils, + PluginManager: PluginManagerFactory, + logger + }; // Create a public API + + const ctor = t => function (...args) { + return new t(...args); + }; + + let t; + const api = Object.create(initial); + + for (const n in initial.tree) { + /* eslint guard-for-in: 0 */ + t = initial.tree[n]; + + if (typeof t === 'function') { + api[n.toLowerCase()] = ctor(t); + } else { + api[n] = Object.create(null); + + for (const o in t) { + /* eslint guard-for-in: 0 */ + api[n][o.toLowerCase()] = ctor(t[o]); + } + } + } + + return api; +}); + +function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; +} + +var lesscHelper = createCommonjsModule(function (module, exports) { + // lessc_helper.js + // + // helper functions for lessc + const lessc_helper = { + // Stylize a string + stylize: function stylize(str, style) { + const styles = { + 'reset': [0, 0], + 'bold': [1, 22], + 'inverse': [7, 27], + 'underline': [4, 24], + 'yellow': [33, 39], + 'green': [32, 39], + 'red': [31, 39], + 'grey': [90, 39] + }; + return `\x1b[${styles[style][0]}m${str}\x1b[${styles[style][1]}m`; + }, + // Print command line options + printUsage: function printUsage() { + console.log('usage: lessc [option option=parameter ...] [destination]'); + console.log(''); + console.log('If source is set to `-\' (dash or hyphen-minus), input is read from stdin.'); + console.log(''); + console.log('options:'); + console.log(' -h, --help Prints help (this message) and exit.'); + console.log(' --include-path=PATHS Sets include paths. Separated by `:\'. `;\' also supported on windows.'); + console.log(' -M, --depends Outputs a makefile import dependency list to stdout.'); + console.log(' --no-color Disables colorized output.'); + console.log(' --ie-compat Enables IE8 compatibility checks.'); + console.log(' --js Enables inline JavaScript in less files'); + console.log(' -l, --lint Syntax check only (lint).'); + console.log(' -s, --silent Suppresses output of error messages.'); + console.log(' --strict-imports Forces evaluation of imports.'); + console.log(' --insecure Allows imports from insecure https hosts.'); + console.log(' -v, --version Prints version number and exit.'); + console.log(' --verbose Be verbose.'); + console.log(' --source-map[=FILENAME] Outputs a v3 sourcemap to the filename (or output filename.map).'); + console.log(' --source-map-rootpath=X Adds this path onto the sourcemap filename and less file paths.'); + console.log(' --source-map-basepath=X Sets sourcemap base path, defaults to current working directory.'); + console.log(' --source-map-include-source Puts the less files into the map instead of referencing them.'); + console.log(' --source-map-inline Puts the map (and any less files) as a base64 data uri into the output css file.'); + console.log(' --source-map-url=URL Sets a custom URL to map file, for sourceMappingURL comment'); + console.log(' in generated CSS file.'); + 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=, --rewrite-urls= Rewrites URLs to make them relative to the base less file.'); + console.log(' all|local|off \'all\' rewrites all URLs, \'local\' just those starting with a \'.\''); + 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.'); + 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(' --plugin=PLUGIN=OPTIONS Loads a plugin. You can also omit the --plugin= if the plugin begins'); + console.log(' less-plugin. E.g. the clean css plugin is called less-plugin-clean-css'); + console.log(' once installed (npm install less-plugin-clean-css), use either with'); + console.log(' --plugin=less-plugin-clean-css or just --clean-css'); + console.log(' specify options afterwards e.g. --plugin=less-plugin-clean-css="advanced"'); + 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\''); + console.log(' that will output the information within a fake'); + console.log(' media query which is compatible with the SASS'); + console.log(' format, and \'all\' which will do both.'); + console.log(' -x, --compress Compresses output by removing some whitespaces.'); + console.log(' We recommend you use a dedicated minifer like less-plugin-clean-css'); + console.log(''); + console.log('Report bugs to: http://github.com/less/less.js/issues'); + console.log('Home page: '); + } + }; // Exports helper functions + + for (const h in lessc_helper) { + if (lessc_helper.hasOwnProperty(h)) { + exports[h] = lessc_helper[h]; + } + } +}); + +/** + * Node Plugin Loader + */ + +class PluginLoader extends AbstractPluginLoader { + constructor(less) { + super(); + this.less = less; + + this.require = prefix => { + prefix = path.dirname(prefix); + return id => { + const str = id.substr(0, 2); + + if (str === '..' || str === './') { + return require(path.join(prefix, id)); + } else { + return require(id); + } + }; + }; + } + + loadPlugin(filename, basePath, context, environment, fileManager) { + const prefix = filename.slice(0, 1); + const explicit = prefix === '.' || prefix === '/' || filename.slice(-3).toLowerCase() === '.js'; + + if (!explicit) { + context.prefixes = ['less-plugin-', '']; + } + + return new Promise((fulfill, reject) => { + fileManager.loadFile(filename, basePath, context, environment).then(data => { + try { + fulfill(data); + } catch (e) { + console.log(e); + reject(e); + } + }).catch(err => { + reject(err); + }); + }); + } + +} + +// Export a new default each time +var defaultOptions = (() => ({ + /* Inline Javascript - @plugin still allowed */ + javascriptEnabled: false, + + /* Outputs a makefile import dependency list to stdout. */ + depends: false, + + /* (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, + + /* Runs the less parser and just reports errors without any output. */ + lint: false, + + /* Sets available include paths. + * If the file in an @import rule does not exist at that exact location, + * less will look for it at the location(s) passed to this option. + * You might use this for instance to specify a path to a library which + * you want to be referenced simply and relatively in the less files. */ + paths: [], + + /* color output in the terminal */ + color: true, + + /* The strictImports controls whether the compiler will allow an @import inside of either + * @media blocks or (a later addition) other selector blocks. + * See: https://github.com/less/less.js/issues/656 */ + strictImports: false, + + /* Allow Imports from Insecure HTTPS Hosts */ + insecure: false, + + /* Allows you to add a path to every generated import and url in your css. + * This does not affect less import statements that are processed, just ones + * that are left in the output css. */ + rootpath: '', + + /* By default URLs are kept as-is, so if you import a file in a sub-directory + * that references an image, exactly the same URL will be output in the css. + * This option allows you to re-write URL's in imported files so that the + * URL is always relative to the base imported file */ + rewriteUrls: 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, + + /* Effectively the declaration is put at the top of your base Less file, + * meaning it can be used but it also can be overridden if this variable + * is defined in the file. */ + globalVars: null, + + /* As opposed to the global variable option, this puts the declaration at the + * end of your base file, meaning it will override anything defined in your Less file. */ + modifyVars: null, + + /* This option allows you to specify a argument to go on to every URL. */ + urlArgs: '' +})); + +var imageSize = (environment => { + function _imageSize(functionContext, filePathNode) { + let filePath = filePathNode.value; + const currentFileInfo = functionContext.currentFileInfo; + const currentDirectory = currentFileInfo.rewriteUrls ? currentFileInfo.currentDirectory : currentFileInfo.entryPath; + const fragmentStart = filePath.indexOf('#'); + let fragment = ''; + + if (fragmentStart !== -1) { + fragment = filePath.slice(fragmentStart); + filePath = filePath.slice(0, fragmentStart); + } + + const fileManager = environment.getFileManager(filePath, currentDirectory, functionContext.context, environment, true); + + if (!fileManager) { + throw { + type: 'File', + message: `Can not set up FileManager for ${filePathNode}` + }; + } + + const fileSync = fileManager.loadFileSync(filePath, currentDirectory, functionContext.context, environment); + + if (fileSync.error) { + throw fileSync.error; + } + + const sizeOf = require('image-size'); + + return sizeOf(fileSync.filename); + } + + const imageFunctions = { + 'image-size': function imageSize(filePathNode) { + const size = _imageSize(this, filePathNode); + + return new Expression([new Dimension(size.width, 'px'), new Dimension(size.height, 'px')]); + }, + 'image-width': function imageWidth(filePathNode) { + const size = _imageSize(this, filePathNode); + + return new Dimension(size.width, 'px'); + }, + 'image-height': function imageHeight(filePathNode) { + const size = _imageSize(this, filePathNode); + + return new Dimension(size.height, 'px'); + } + }; + functionRegistry.addMultiple(imageFunctions); +}); + +const less = createFromEnvironment(environment, [new FileManager(), new UrlFileManager()]); // allow people to create less with their own environment + +less.createFromEnvironment = createFromEnvironment; +less.lesscHelper = lesscHelper; +less.PluginLoader = PluginLoader; +less.fs = fs$1; +less.FileManager = FileManager; +less.UrlFileManager = UrlFileManager; // Set up options + +less.options = defaultOptions(); // provide image-size functionality + +imageSize(less.environment); + +module.exports = less; diff --git a/dist/less.js b/dist/less.js index 83267e652..c8cc1907e 100644 --- a/dist/less.js +++ b/dist/less.js @@ -1,10846 +1,7423 @@ -/*! - * Less - Leaner CSS v3.9.0 +/** + * Less - Leaner CSS v3.10.0 * http://lesscss.org - * - * Copyright (c) 2009-2018, Alexis Sellier + * + * Copyright (c) 2009-2019, Alexis Sellier * Licensed under the Apache-2.0 License. * + * @license Apache-2.0 */ - /** * @license Apache-2.0 - */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = global || self, global.less = factory()); +}(this, function () { 'use strict'; + + // Export a new default each time + var defaultOptions = (function () { + return { + /* Inline Javascript - @plugin still allowed */ + javascriptEnabled: false, + + /* Outputs a makefile import dependency list to stdout. */ + depends: false, + + /* (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, + + /* Runs the less parser and just reports errors without any output. */ + lint: false, + + /* Sets available include paths. + * If the file in an @import rule does not exist at that exact location, + * less will look for it at the location(s) passed to this option. + * You might use this for instance to specify a path to a library which + * you want to be referenced simply and relatively in the less files. */ + paths: [], + + /* color output in the terminal */ + color: true, + + /* The strictImports controls whether the compiler will allow an @import inside of either + * @media blocks or (a later addition) other selector blocks. + * See: https://github.com/less/less.js/issues/656 */ + strictImports: false, + + /* Allow Imports from Insecure HTTPS Hosts */ + insecure: false, + + /* Allows you to add a path to every generated import and url in your css. + * This does not affect less import statements that are processed, just ones + * that are left in the output css. */ + rootpath: '', + + /* By default URLs are kept as-is, so if you import a file in a sub-directory + * that references an image, exactly the same URL will be output in the css. + * This option allows you to re-write URL's in imported files so that the + * URL is always relative to the base imported file */ + rewriteUrls: 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, + + /* Effectively the declaration is put at the top of your base Less file, + * meaning it can be used but it also can be overridden if this variable + * is defined in the file. */ + globalVars: null, + + /* As opposed to the global variable option, this puts the declaration at the + * end of your base file, meaning it will override anything defined in your Less file. */ + modifyVars: null, + + /* This option allows you to specify a argument to go on to every URL. */ + urlArgs: '' + }; + }); + + function extractId(href) { + return href.replace(/^[a-z-]+:\/+?[^\/]+/, '') // Remove protocol & domain + .replace(/[\?\&]livereload=\w+/, '') // Remove LiveReload cachebuster + .replace(/^\//, '') // Remove root / + .replace(/\.[a-zA-Z]+$/, '') // Remove simple extension + .replace(/[^\.\w-]+/g, '-') // Replace illegal characters + .replace(/\./g, ':'); // Replace dots with colons(for valid id) + } + function addDataAttr(options, tag) { + for (var opt in tag.dataset) { + if (tag.dataset.hasOwnProperty(opt)) { + if (opt === 'env' || opt === 'dumpLineNumbers' || opt === 'rootpath' || opt === 'errorReporting') { + options[opt] = tag.dataset[opt]; + } else { + try { + options[opt] = JSON.parse(tag.dataset[opt]); + } catch (_) {} + } + } + } + } + + var browser = { + createCSS: function createCSS(document, styles, sheet) { + // Strip the query-string + var href = sheet.href || ''; // If there is no title set, use the filename, minus the extension + + var id = "less:".concat(sheet.title || extractId(href)); // If this has already been inserted into the DOM, we may need to replace it -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.less = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0 && styleNode.childNodes.length > 0 && oldStyleNode.firstChild.nodeValue === styleNode.firstChild.nodeValue; + } + + var head = document.getElementsByTagName('head')[0]; // If there is no oldStyleNode, just append; otherwise, only append if we need + // to replace oldStyleNode with an updated stylesheet + + if (oldStyleNode === null || keepOldStyleNode === false) { + var nextEl = sheet && sheet.nextSibling || null; + + if (nextEl) { + nextEl.parentNode.insertBefore(styleNode, nextEl); + } else { + head.appendChild(styleNode); + } + } + + if (oldStyleNode && keepOldStyleNode === false) { + oldStyleNode.parentNode.removeChild(oldStyleNode); + } // For IE. + // This needs to happen *after* the style element is added to the DOM, otherwise IE 7 and 8 may crash. + // See http://social.msdn.microsoft.com/Forums/en-US/7e081b65-878a-4c22-8e68-c10d39c2ed32/internet-explorer-crashes-appending-style-element-to-head + + + if (styleNode.styleSheet) { + try { + styleNode.styleSheet.cssText = styles; + } catch (e) { + throw new Error('Couldn\'t reassign styleSheet.cssText.'); + } + } + }, + currentScript: function currentScript(window) { + var document = window.document; + return document.currentScript || function () { + var scripts = document.getElementsByTagName('script'); + return scripts[scripts.length - 1]; + }(); + } + }; + var addDefaultOptions = (function (window, options) { // use options from the current script tag data attribues addDataAttr(options, browser.currentScript(window)); if (options.isFileProtocol === undefined) { - options.isFileProtocol = /^(file|(chrome|safari)(-extension)?|resource|qrc|app):/.test(window.location.protocol); - } - - // Load styles asynchronously (default: false) + options.isFileProtocol = /^(file|(chrome|safari)(-extension)?|resource|qrc|app):/.test(window.location.protocol); + } // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // - options.async = options.async || false; - options.fileAsync = options.fileAsync || false; - // Interval between watch polls - options.poll = options.poll || (options.isFileProtocol ? 1000 : 1500); - options.env = options.env || (window.location.hostname == '127.0.0.1' || - window.location.hostname == '0.0.0.0' || - window.location.hostname == 'localhost' || - (window.location.port && - window.location.port.length > 0) || - options.isFileProtocol ? 'development' - : 'production'); + options.async = options.async || false; + options.fileAsync = options.fileAsync || false; // Interval between watch polls + options.poll = options.poll || (options.isFileProtocol ? 1000 : 1500); + options.env = options.env || (window.location.hostname == '127.0.0.1' || window.location.hostname == '0.0.0.0' || window.location.hostname == 'localhost' || window.location.port && window.location.port.length > 0 || options.isFileProtocol ? 'development' : 'production'); var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(window.location.hash); + if (dumpLineNumbers) { - options.dumpLineNumbers = dumpLineNumbers[1]; + options.dumpLineNumbers = dumpLineNumbers[1]; } if (options.useFileCache === undefined) { - options.useFileCache = true; + options.useFileCache = true; } if (options.onReady === undefined) { - options.onReady = true; + options.onReady = true; } if (options.relativeUrls) { - options.rewriteUrls = 'all'; + options.rewriteUrls = 'all'; } -}; + }); -},{"./browser":3,"./utils":11}],2:[function(require,module,exports){ -/** - * Kicks off less and compiles any stylesheets - * used in the browser distributed version of less - * to kick-start less using the browser api - */ -/* global window, document */ + function _typeof(obj) { + if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { + _typeof = function (obj) { + return typeof obj; + }; + } else { + _typeof = function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + } -// TODO - consider switching this out for a recommendation for this polyfill? -// -// Browsers have good Promise support -require('promise/polyfill'); + return _typeof(obj); + } -var options = require('../less/default-options')(); + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } -if (window.less) { - for (key in window.less) { - if (window.less.hasOwnProperty(key)) { - options[key] = window.less[key]; - } + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); } -} -require('./add-default-options')(window, options); + } -options.plugins = options.plugins || []; + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; + } -if (window.LESS_PLUGINS) { - options.plugins = options.plugins.concat(window.LESS_PLUGINS); -} + function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function"); + } -var less = module.exports = require('./index')(window, options); + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + writable: true, + configurable: true + } + }); + if (superClass) _setPrototypeOf(subClass, superClass); + } -window.less = less; + function _getPrototypeOf(o) { + _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { + return o.__proto__ || Object.getPrototypeOf(o); + }; + return _getPrototypeOf(o); + } -var css, head, style; + function _setPrototypeOf(o, p) { + _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { + o.__proto__ = p; + return o; + }; -// Always restore page visibility -function resolveOrReject(data) { - if (data.filename) { - console.warn(data); - } - if (!options.async) { - head.removeChild(style); + return _setPrototypeOf(o, p); + } + + function isNativeReflectConstruct() { + if (typeof Reflect === "undefined" || !Reflect.construct) return false; + if (Reflect.construct.sham) return false; + if (typeof Proxy === "function") return true; + + try { + Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); + return true; + } catch (e) { + return false; } -} + } -if (options.onReady) { - if (/!watch/.test(window.location.hash)) { - less.watch(); + function _construct(Parent, args, Class) { + if (isNativeReflectConstruct()) { + _construct = Reflect.construct; + } else { + _construct = function _construct(Parent, args, Class) { + var a = [null]; + a.push.apply(a, args); + var Constructor = Function.bind.apply(Parent, a); + var instance = new Constructor(); + if (Class) _setPrototypeOf(instance, Class.prototype); + return instance; + }; } - // Simulate synchronous stylesheet loading by hiding page rendering - if (!options.async) { - css = 'body { display: none !important }'; - head = document.head || document.getElementsByTagName('head')[0]; - style = document.createElement('style'); - style.type = 'text/css'; - if (style.styleSheet) { - style.styleSheet.cssText = css; - } else { - style.appendChild(document.createTextNode(css)); - } + return _construct.apply(null, arguments); + } - head.appendChild(style); + function _assertThisInitialized(self) { + if (self === void 0) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } - less.registerStylesheetsImmediately(); - less.pageLoadFinished = less.refresh(less.env === 'development').then(resolveOrReject, resolveOrReject); -} -},{"../less/default-options":17,"./add-default-options":1,"./index":8,"promise/polyfill":104}],3:[function(require,module,exports){ -var utils = require('./utils'); -module.exports = { - createCSS: function (document, styles, sheet) { - // Strip the query-string - var href = sheet.href || ''; + return self; + } + + function _possibleConstructorReturn(self, call) { + if (call && (typeof call === "object" || typeof call === "function")) { + return call; + } - // If there is no title set, use the filename, minus the extension - var id = 'less:' + (sheet.title || utils.extractId(href)); + return _assertThisInitialized(self); + } - // If this has already been inserted into the DOM, we may need to replace it - var oldStyleNode = document.getElementById(id); - var keepOldStyleNode = false; + function _toConsumableArray(arr) { + return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); + } - // Create a new stylesheet node for insertion or (if necessary) replacement - var styleNode = document.createElement('style'); - styleNode.setAttribute('type', 'text/css'); - if (sheet.media) { - styleNode.setAttribute('media', sheet.media); - } - styleNode.id = id; + function _arrayWithoutHoles(arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - if (!styleNode.styleSheet) { - styleNode.appendChild(document.createTextNode(styles)); + return arr2; + } + } - // If new contents match contents of oldStyleNode, don't replace oldStyleNode - keepOldStyleNode = (oldStyleNode !== null && oldStyleNode.childNodes.length > 0 && styleNode.childNodes.length > 0 && - oldStyleNode.firstChild.nodeValue === styleNode.firstChild.nodeValue); - } + function _iterableToArray(iter) { + if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); + } - var head = document.getElementsByTagName('head')[0]; + function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance"); + } - // If there is no oldStyleNode, just append; otherwise, only append if we need - // to replace oldStyleNode with an updated stylesheet - if (oldStyleNode === null || keepOldStyleNode === false) { - var nextEl = sheet && sheet.nextSibling || null; - if (nextEl) { - nextEl.parentNode.insertBefore(styleNode, nextEl); - } else { - head.appendChild(styleNode); - } + var colors = { + 'aliceblue': '#f0f8ff', + 'antiquewhite': '#faebd7', + 'aqua': '#00ffff', + 'aquamarine': '#7fffd4', + 'azure': '#f0ffff', + 'beige': '#f5f5dc', + 'bisque': '#ffe4c4', + 'black': '#000000', + 'blanchedalmond': '#ffebcd', + 'blue': '#0000ff', + 'blueviolet': '#8a2be2', + 'brown': '#a52a2a', + 'burlywood': '#deb887', + 'cadetblue': '#5f9ea0', + 'chartreuse': '#7fff00', + 'chocolate': '#d2691e', + 'coral': '#ff7f50', + 'cornflowerblue': '#6495ed', + 'cornsilk': '#fff8dc', + 'crimson': '#dc143c', + 'cyan': '#00ffff', + 'darkblue': '#00008b', + 'darkcyan': '#008b8b', + 'darkgoldenrod': '#b8860b', + 'darkgray': '#a9a9a9', + 'darkgrey': '#a9a9a9', + 'darkgreen': '#006400', + 'darkkhaki': '#bdb76b', + 'darkmagenta': '#8b008b', + 'darkolivegreen': '#556b2f', + 'darkorange': '#ff8c00', + 'darkorchid': '#9932cc', + 'darkred': '#8b0000', + 'darksalmon': '#e9967a', + 'darkseagreen': '#8fbc8f', + 'darkslateblue': '#483d8b', + 'darkslategray': '#2f4f4f', + 'darkslategrey': '#2f4f4f', + 'darkturquoise': '#00ced1', + 'darkviolet': '#9400d3', + 'deeppink': '#ff1493', + 'deepskyblue': '#00bfff', + 'dimgray': '#696969', + 'dimgrey': '#696969', + 'dodgerblue': '#1e90ff', + 'firebrick': '#b22222', + 'floralwhite': '#fffaf0', + 'forestgreen': '#228b22', + 'fuchsia': '#ff00ff', + 'gainsboro': '#dcdcdc', + 'ghostwhite': '#f8f8ff', + 'gold': '#ffd700', + 'goldenrod': '#daa520', + 'gray': '#808080', + 'grey': '#808080', + 'green': '#008000', + 'greenyellow': '#adff2f', + 'honeydew': '#f0fff0', + 'hotpink': '#ff69b4', + 'indianred': '#cd5c5c', + 'indigo': '#4b0082', + 'ivory': '#fffff0', + 'khaki': '#f0e68c', + 'lavender': '#e6e6fa', + 'lavenderblush': '#fff0f5', + 'lawngreen': '#7cfc00', + 'lemonchiffon': '#fffacd', + 'lightblue': '#add8e6', + 'lightcoral': '#f08080', + 'lightcyan': '#e0ffff', + 'lightgoldenrodyellow': '#fafad2', + 'lightgray': '#d3d3d3', + 'lightgrey': '#d3d3d3', + 'lightgreen': '#90ee90', + 'lightpink': '#ffb6c1', + 'lightsalmon': '#ffa07a', + 'lightseagreen': '#20b2aa', + 'lightskyblue': '#87cefa', + 'lightslategray': '#778899', + 'lightslategrey': '#778899', + 'lightsteelblue': '#b0c4de', + 'lightyellow': '#ffffe0', + 'lime': '#00ff00', + 'limegreen': '#32cd32', + 'linen': '#faf0e6', + 'magenta': '#ff00ff', + 'maroon': '#800000', + 'mediumaquamarine': '#66cdaa', + 'mediumblue': '#0000cd', + 'mediumorchid': '#ba55d3', + 'mediumpurple': '#9370d8', + 'mediumseagreen': '#3cb371', + 'mediumslateblue': '#7b68ee', + 'mediumspringgreen': '#00fa9a', + 'mediumturquoise': '#48d1cc', + 'mediumvioletred': '#c71585', + 'midnightblue': '#191970', + 'mintcream': '#f5fffa', + 'mistyrose': '#ffe4e1', + 'moccasin': '#ffe4b5', + 'navajowhite': '#ffdead', + 'navy': '#000080', + 'oldlace': '#fdf5e6', + 'olive': '#808000', + 'olivedrab': '#6b8e23', + 'orange': '#ffa500', + 'orangered': '#ff4500', + 'orchid': '#da70d6', + 'palegoldenrod': '#eee8aa', + 'palegreen': '#98fb98', + 'paleturquoise': '#afeeee', + 'palevioletred': '#d87093', + 'papayawhip': '#ffefd5', + 'peachpuff': '#ffdab9', + 'peru': '#cd853f', + 'pink': '#ffc0cb', + 'plum': '#dda0dd', + 'powderblue': '#b0e0e6', + 'purple': '#800080', + 'rebeccapurple': '#663399', + 'red': '#ff0000', + 'rosybrown': '#bc8f8f', + 'royalblue': '#4169e1', + 'saddlebrown': '#8b4513', + 'salmon': '#fa8072', + 'sandybrown': '#f4a460', + 'seagreen': '#2e8b57', + 'seashell': '#fff5ee', + 'sienna': '#a0522d', + 'silver': '#c0c0c0', + 'skyblue': '#87ceeb', + 'slateblue': '#6a5acd', + 'slategray': '#708090', + 'slategrey': '#708090', + 'snow': '#fffafa', + 'springgreen': '#00ff7f', + 'steelblue': '#4682b4', + 'tan': '#d2b48c', + 'teal': '#008080', + 'thistle': '#d8bfd8', + 'tomato': '#ff6347', + 'turquoise': '#40e0d0', + 'violet': '#ee82ee', + 'wheat': '#f5deb3', + 'white': '#ffffff', + 'whitesmoke': '#f5f5f5', + 'yellow': '#ffff00', + 'yellowgreen': '#9acd32' + }; + + var unitConversions = { + length: { + 'm': 1, + 'cm': 0.01, + 'mm': 0.001, + 'in': 0.0254, + 'px': 0.0254 / 96, + 'pt': 0.0254 / 72, + 'pc': 0.0254 / 72 * 12 + }, + duration: { + 's': 1, + 'ms': 0.001 + }, + angle: { + 'rad': 1 / (2 * Math.PI), + 'deg': 1 / 360, + 'grad': 1 / 400, + 'turn': 1 + } + }; + + var data = { + colors: colors, + unitConversions: unitConversions + }; + + var Node = + /*#__PURE__*/ + function () { + function Node() { + _classCallCheck(this, Node); + + this.parent = null; + this.visibilityBlocks = undefined; + this.nodeVisible = undefined; + this.rootNode = null; + this.parsed = null; + var self = this; + Object.defineProperty(this, 'currentFileInfo', { + get: function get() { + return self.fileInfo(); } - if (oldStyleNode && keepOldStyleNode === false) { - oldStyleNode.parentNode.removeChild(oldStyleNode); + }); + Object.defineProperty(this, 'index', { + get: function get() { + return self.getIndex(); } + }); + } - // For IE. - // This needs to happen *after* the style element is added to the DOM, otherwise IE 7 and 8 may crash. - // See http://social.msdn.microsoft.com/Forums/en-US/7e081b65-878a-4c22-8e68-c10d39c2ed32/internet-explorer-crashes-appending-style-element-to-head - if (styleNode.styleSheet) { - try { - styleNode.styleSheet.cssText = styles; - } catch (e) { - throw new Error('Couldn\'t reassign styleSheet.cssText.'); - } + _createClass(Node, [{ + key: "setParent", + value: function setParent(nodes, parent) { + function set(node) { + if (node && node instanceof Node) { + node.parent = parent; + } } - }, - currentScript: function(window) { - var document = window.document; - return document.currentScript || (function() { - var scripts = document.getElementsByTagName('script'); - return scripts[scripts.length - 1]; - })(); - } -}; -},{"./utils":11}],4:[function(require,module,exports){ -// Cache system is a bit outdated and could do with work + if (Array.isArray(nodes)) { + nodes.forEach(set); + } else { + set(nodes); + } + } + }, { + key: "getIndex", + value: function getIndex() { + return this._index || this.parent && this.parent.getIndex() || 0; + } + }, { + key: "fileInfo", + value: function fileInfo() { + return this._fileInfo || this.parent && this.parent.fileInfo() || {}; + } + }, { + key: "isRulesetLike", + value: function isRulesetLike() { + return false; + } + }, { + key: "toCSS", + value: function toCSS(context) { + var strs = []; + this.genCSS(context, { + add: function add(chunk, fileInfo, index) { + strs.push(chunk); + }, + isEmpty: function isEmpty() { + return strs.length === 0; + } + }); + return strs.join(''); + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + output.add(this.value); + } + }, { + key: "accept", + value: function accept(visitor) { + this.value = visitor.visit(this.value); + } + }, { + key: "eval", + value: function _eval() { + return this; + } + }, { + key: "_operate", + value: function _operate(context, op, a, b) { + switch (op) { + case '+': + return a + b; -module.exports = function(window, options, logger) { - var cache = null; - if (options.env !== 'development') { - try { - cache = (typeof window.localStorage === 'undefined') ? null : window.localStorage; - } catch (_) {} - } - return { - setCSS: function(path, lastModified, modifyVars, styles) { - if (cache) { - logger.info('saving ' + path + ' to cache.'); - try { - cache.setItem(path, styles); - cache.setItem(path + ':timestamp', lastModified); - if (modifyVars) { - cache.setItem(path + ':vars', JSON.stringify(modifyVars)); - } - } catch (e) { - // TODO - could do with adding more robust error handling - logger.error('failed to save "' + path + '" to local storage for caching.'); - } - } - }, - getCSS: function(path, webInfo, modifyVars) { - var css = cache && cache.getItem(path), - timestamp = cache && cache.getItem(path + ':timestamp'), - vars = cache && cache.getItem(path + ':vars'); + case '-': + return a - b; - modifyVars = modifyVars || {}; - vars = vars || "{}"; // if not set, treat as the JSON representation of an empty object + case '*': + return a * b; - if (timestamp && webInfo.lastModified && - (new Date(webInfo.lastModified).valueOf() === - new Date(timestamp).valueOf()) && - JSON.stringify(modifyVars) === vars) { - // Use local copy - return css; - } + case '/': + return a / b; } - }; -}; + } + }, { + key: "fround", + value: function fround(context, value) { + var precision = context && context.numPrecision; // add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999...) are properly rounded: -},{}],5:[function(require,module,exports){ -var utils = require('./utils'), - browser = require('./browser'); + return precision ? Number((value + 2e-16).toFixed(precision)) : value; + } // Returns true if this node represents root of ast imported by reference -module.exports = function(window, less, options) { + }, { + key: "blocksVisibility", + value: function blocksVisibility() { + if (this.visibilityBlocks == null) { + this.visibilityBlocks = 0; + } - function errorHTML(e, rootHref) { - var id = 'less-error-message:' + utils.extractId(rootHref || ''); - var template = '
  • {content}
  • '; - var elem = window.document.createElement('div'), timer, content, errors = []; - var filename = e.filename || rootHref; - var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; + return this.visibilityBlocks !== 0; + } + }, { + key: "addVisibilityBlock", + value: function addVisibilityBlock() { + if (this.visibilityBlocks == null) { + this.visibilityBlocks = 0; + } - elem.id = id; - elem.className = 'less-error-message'; + this.visibilityBlocks = this.visibilityBlocks + 1; + } + }, { + key: "removeVisibilityBlock", + value: function removeVisibilityBlock() { + if (this.visibilityBlocks == null) { + this.visibilityBlocks = 0; + } + + this.visibilityBlocks = this.visibilityBlocks - 1; + } // Turns on node visibility - if called node will be shown in output regardless + // of whether it comes from import by reference or not + + }, { + key: "ensureVisibility", + value: function ensureVisibility() { + this.nodeVisible = true; + } // Turns off node visibility - if called node will NOT be shown in output regardless + // of whether it comes from import by reference or not + + }, { + key: "ensureInvisibility", + value: function ensureInvisibility() { + this.nodeVisible = false; + } // return values: + // false - the node must not be visible + // true - the node must be visible + // undefined or null - the node has the same visibility as its parent + + }, { + key: "isVisible", + value: function isVisible() { + return this.nodeVisible; + } + }, { + key: "visibilityInfo", + value: function visibilityInfo() { + return { + visibilityBlocks: this.visibilityBlocks, + nodeVisible: this.nodeVisible + }; + } + }, { + key: "copyVisibilityInfo", + value: function copyVisibilityInfo(info) { + if (!info) { + return; + } - content = '

    ' + (e.type || 'Syntax') + 'Error: ' + (e.message || 'There is an error in your .less file') + - '

    ' + '

    in ' + filenameNoPath + ' '; + this.visibilityBlocks = info.visibilityBlocks; + this.nodeVisible = info.nodeVisible; + } + }]); - var errorline = function (e, i, classname) { - if (e.extract[i] !== undefined) { - errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1)) - .replace(/\{class\}/, classname) - .replace(/\{content\}/, e.extract[i])); - } - }; + return Node; + }(); - if (e.line) { - errorline(e, 0, ''); - errorline(e, 1, 'line'); - errorline(e, 2, ''); - content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + - '
      ' + errors.join('') + '
    '; - } - if (e.stack && (e.extract || options.logLevel >= 4)) { - content += '
    Stack Trace
    ' + e.stack.split('\n').slice(1).join('
    '); - } - elem.innerHTML = content; - - // CSS for error messages - browser.createCSS(window.document, [ - '.less-error-message ul, .less-error-message li {', - 'list-style-type: none;', - 'margin-right: 15px;', - 'padding: 4px 0;', - 'margin: 0;', - '}', - '.less-error-message label {', - 'font-size: 12px;', - 'margin-right: 15px;', - 'padding: 4px 0;', - 'color: #cc7777;', - '}', - '.less-error-message pre {', - 'color: #dd6666;', - 'padding: 4px 0;', - 'margin: 0;', - 'display: inline-block;', - '}', - '.less-error-message pre.line {', - 'color: #ff0000;', - '}', - '.less-error-message h3 {', - 'font-size: 20px;', - 'font-weight: bold;', - 'padding: 15px 0 5px 0;', - 'margin: 0;', - '}', - '.less-error-message a {', - 'color: #10a', - '}', - '.less-error-message .error {', - 'color: red;', - 'font-weight: bold;', - 'padding-bottom: 2px;', - 'border-bottom: 1px dashed red;', - '}' - ].join('\n'), { title: 'error-message' }); - - elem.style.cssText = [ - 'font-family: Arial, sans-serif', - 'border: 1px solid #e00', - 'background-color: #eee', - 'border-radius: 5px', - '-webkit-border-radius: 5px', - '-moz-border-radius: 5px', - 'color: #e00', - 'padding: 15px', - 'margin-bottom: 15px' - ].join(';'); - - if (options.env === 'development') { - timer = setInterval(function () { - var document = window.document, - body = document.body; - if (body) { - if (document.getElementById(id)) { - body.replaceChild(elem, document.getElementById(id)); - } else { - body.insertBefore(elem, body.firstChild); - } - clearInterval(timer); - } - }, 10); - } + Node.compare = function (a, b) { + /* returns: + -1: a < b + 0: a = b + 1: a > b + and *any* other value for a != b (e.g. undefined, NaN, -2 etc.) */ + if (a.compare && // for "symmetric results" force toCSS-based comparison + // of Quoted or Anonymous if either value is one of those + !(b.type === 'Quoted' || b.type === 'Anonymous')) { + return a.compare(b); + } else if (b.compare) { + return -b.compare(a); + } else if (a.type !== b.type) { + return undefined; } - function removeErrorHTML(path) { - var node = window.document.getElementById('less-error-message:' + utils.extractId(path)); - if (node) { - node.parentNode.removeChild(node); - } + a = a.value; + b = b.value; + + if (!Array.isArray(a)) { + return a === b ? 0 : undefined; } - function removeErrorConsole(path) { - // no action + if (a.length !== b.length) { + return undefined; } - function removeError(path) { - if (!options.errorReporting || options.errorReporting === 'html') { - removeErrorHTML(path); - } else if (options.errorReporting === 'console') { - removeErrorConsole(path); - } else if (typeof options.errorReporting === 'function') { - options.errorReporting('remove', path); - } + for (var i = 0; i < a.length; i++) { + if (Node.compare(a[i], b[i]) !== 0) { + return undefined; + } } - function errorConsole(e, rootHref) { - var template = '{line} {content}'; - var filename = e.filename || rootHref; - var errors = []; - var content = (e.type || 'Syntax') + 'Error: ' + (e.message || 'There is an error in your .less file') + - ' in ' + filename; - - var errorline = function (e, i, classname) { - if (e.extract[i] !== undefined) { - errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1)) - .replace(/\{class\}/, classname) - .replace(/\{content\}/, e.extract[i])); - } - }; + return 0; + }; - if (e.line) { - errorline(e, 0, ''); - errorline(e, 1, 'line'); - errorline(e, 2, ''); - content += ' on line ' + e.line + ', column ' + (e.column + 1) + ':\n' + - errors.join('\n'); - } - if (e.stack && (e.extract || options.logLevel >= 4)) { - content += '\nStack Trace\n' + e.stack; - } - less.logger.error(content); - } + Node.numericCompare = function (a, b) { + return a < b ? -1 : a === b ? 0 : a > b ? 1 : undefined; + }; - function error(e, rootHref) { - if (!options.errorReporting || options.errorReporting === 'html') { - errorHTML(e, rootHref); - } else if (options.errorReporting === 'console') { - errorConsole(e, rootHref); - } else if (typeof options.errorReporting === 'function') { - options.errorReporting('add', e, rootHref); - } - } + // RGB Colors - #ff0014, #eee + // - return { - add: error, - remove: removeError - }; -}; + var Color = + /*#__PURE__*/ + function (_Node) { + _inherits(Color, _Node); -},{"./browser":3,"./utils":11}],6:[function(require,module,exports){ -/* global window, XMLHttpRequest */ + function Color(rgb, a, originalForm) { + var _this; -module.exports = function(options, logger) { + _classCallCheck(this, Color); - var AbstractFileManager = require('../less/environment/abstract-file-manager.js'); + _this = _possibleConstructorReturn(this, _getPrototypeOf(Color).call(this)); - var fileCache = {}; + var self = _assertThisInitialized(_this); // + // The end goal here, is to parse the arguments + // into an integer triplet, such as `128, 255, 0` + // + // This facilitates operations and conversions. + // - // TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load - var FileManager = function() { - }; - FileManager.prototype = new AbstractFileManager(); + if (Array.isArray(rgb)) { + _this.rgb = rgb; + } else if (rgb.length >= 6) { + _this.rgb = []; + rgb.match(/.{2}/g).map(function (c, i) { + if (i < 3) { + self.rgb.push(parseInt(c, 16)); + } else { + self.alpha = parseInt(c, 16) / 255; + } + }); + } else { + _this.rgb = []; + rgb.split('').map(function (c, i) { + if (i < 3) { + self.rgb.push(parseInt(c + c, 16)); + } else { + self.alpha = parseInt(c + c, 16) / 255; + } + }); + } - FileManager.prototype.alwaysMakePathsAbsolute = function alwaysMakePathsAbsolute() { - return true; - }; - FileManager.prototype.join = function join(basePath, laterPath) { - if (!basePath) { - return laterPath; - } - return this.extractUrlParts(laterPath, basePath).path; - }; - FileManager.prototype.doXHR = function doXHR(url, type, callback, errback) { + _this.alpha = _this.alpha || (typeof a === 'number' ? a : 1); - var xhr = new XMLHttpRequest(); - var async = options.isFileProtocol ? options.fileAsync : true; + if (typeof originalForm !== 'undefined') { + _this.value = originalForm; + } - if (typeof xhr.overrideMimeType === 'function') { - xhr.overrideMimeType('text/css'); - } - logger.debug('XHR: Getting \'' + url + '\''); - xhr.open('GET', url, async); - xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); - xhr.send(null); + return _this; + } - 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); + _createClass(Color, [{ + key: "luma", + value: function luma() { + var r = this.rgb[0] / 255; + var g = this.rgb[1] / 255; + var b = this.rgb[2] / 255; + r = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4); + g = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4); + b = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4); + return 0.2126 * r + 0.7152 * g + 0.0722 * b; + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + output.add(this.toCSS(context)); + } + }, { + key: "toCSS", + value: function toCSS(context, doNotCompress) { + var compress = context && context.compress && !doNotCompress; + var color; + var alpha; + var colorFunction; + var args = []; // `value` is set if this color was originally + // converted from a named color string so we need + // to respect this and try to output named color too. + + alpha = this.fround(context, this.alpha); + + if (this.value) { + if (this.value.indexOf('rgb') === 0) { + if (alpha < 1) { + colorFunction = 'rgba'; } - } - - if (options.isFileProtocol && !options.fileAsync) { - if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { - callback(xhr.responseText); + } else if (this.value.indexOf('hsl') === 0) { + if (alpha < 1) { + colorFunction = 'hsla'; } else { - errback(xhr.status, url); + colorFunction = 'hsl'; } - } else if (async) { - xhr.onreadystatechange = function () { - if (xhr.readyState == 4) { - handleResponse(xhr, callback, errback); - } - }; + } else { + return this.value; + } } else { - handleResponse(xhr, callback, errback); + if (alpha < 1) { + colorFunction = 'rgba'; + } } - }; - FileManager.prototype.supports = function(filename, currentDirectory, options, environment) { - return true; - }; - FileManager.prototype.clearFileCache = function() { - fileCache = {}; - }; + switch (colorFunction) { + case 'rgba': + args = this.rgb.map(function (c) { + return clamp(Math.round(c), 255); + }).concat(clamp(alpha, 1)); + break; - FileManager.prototype.loadFile = function loadFile(filename, currentDirectory, options, environment) { - // TODO: Add prefix support like less-node? - // What about multiple paths? + case 'hsla': + args.push(clamp(alpha, 1)); - if (currentDirectory && !this.isPathAbsolute(filename)) { - filename = currentDirectory + filename; + case 'hsl': + color = this.toHSL(); + args = [this.fround(context, color.h), "".concat(this.fround(context, color.s * 100), "%"), "".concat(this.fround(context, color.l * 100), "%")].concat(args); } - filename = options.ext ? this.tryAppendExtension(filename, options.ext) : filename; - - options = options || {}; + if (colorFunction) { + // Values are capped between `0` and `255`, rounded and zero-padded. + return "".concat(colorFunction, "(").concat(args.join(",".concat(compress ? '' : ' ')), ")"); + } - // sheet may be set to the stylesheet for the initial load or a collection of properties including - // some context variables for imports - var hrefParts = this.extractUrlParts(filename, window.location.href); - var href = hrefParts.url; - var self = this; - - return new Promise(function(resolve, reject) { - if (options.useFileCache && fileCache[href]) { - try { - var lessText = fileCache[href]; - return resolve({ contents: lessText, filename: href, webInfo: { lastModified: new Date() }}); - } catch (e) { - return reject({ filename: href, message: 'Error loading file ' + href + ' error was ' + e.message }); - } - } + color = this.toRGB(); - self.doXHR(href, options.mime, function doXHRCallback(data, lastModified) { - // per file cache - fileCache[href] = data; + if (compress) { + var splitcolor = color.split(''); // Convert color to short format - // Use remote copy (re-parse) - resolve({ contents: data, filename: href, webInfo: { lastModified: lastModified }}); - }, function doXHRError(status, url) { - reject({ type: 'File', message: '\'' + url + '\' wasn\'t found (' + status + ')', href: href }); - }); - }); - }; + if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) { + color = "#".concat(splitcolor[1]).concat(splitcolor[3]).concat(splitcolor[5]); + } + } - return FileManager; -}; + return color; + } // + // Operations have to be done per-channel, if not, + // channels will spill onto each other. Once we have + // our result, in the form of an integer triplet, + // we create a new Color node to hold the result. + // -},{"../less/environment/abstract-file-manager.js":18}],7:[function(require,module,exports){ -module.exports = function() { + }, { + key: "operate", + value: function operate(context, op, other) { + var rgb = new Array(3); + var alpha = this.alpha * (1 - other.alpha) + other.alpha; - var functionRegistry = require('./../less/functions/function-registry'); + for (var c = 0; c < 3; c++) { + rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]); + } - function imageSize() { - throw { - type: 'Runtime', - message: 'Image size functions are not supported in browser version of less' + return new Color(rgb, alpha); + } + }, { + key: "toRGB", + value: function toRGB() { + return toHex(this.rgb); + } + }, { + key: "toHSL", + value: function toHSL() { + var r = this.rgb[0] / 255; + var g = this.rgb[1] / 255; + var b = this.rgb[2] / 255; + var a = this.alpha; + var max = Math.max(r, g, b); + var min = Math.min(r, g, b); + var h; + var s; + var l = (max + min) / 2; + var d = max - min; + + if (max === min) { + h = s = 0; + } else { + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + + case g: + h = (b - r) / d + 2; + break; + + case b: + h = (r - g) / d + 4; + break; + } + + h /= 6; + } + + return { + h: h * 360, + s: s, + l: l, + a: a }; - } + } // Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript + + }, { + key: "toHSV", + value: function toHSV() { + var r = this.rgb[0] / 255; + var g = this.rgb[1] / 255; + var b = this.rgb[2] / 255; + var a = this.alpha; + var max = Math.max(r, g, b); + var min = Math.min(r, g, b); + var h; + var s; + var v = max; + var d = max - min; + + if (max === 0) { + s = 0; + } else { + s = d / max; + } - var imageFunctions = { - 'image-size': function(filePathNode) { - imageSize(this, filePathNode); - return -1; - }, - 'image-width': function(filePathNode) { - imageSize(this, filePathNode); - return -1; - }, - 'image-height': function(filePathNode) { - imageSize(this, filePathNode); - return -1; + if (max === min) { + h = 0; + } else { + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + + case g: + h = (b - r) / d + 2; + break; + + case b: + h = (r - g) / d + 4; + break; + } + + h /= 6; } - }; - functionRegistry.addMultiple(imageFunctions); -}; + return { + h: h * 360, + s: s, + v: v, + a: a + }; + } + }, { + key: "toARGB", + value: function toARGB() { + return toHex([this.alpha * 255].concat(this.rgb)); + } + }, { + key: "compare", + value: function compare(x) { + return x.rgb && x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha ? 0 : undefined; + } + }]); -},{"./../less/functions/function-registry":27}],8:[function(require,module,exports){ -// -// index.js -// Should expose the additional browser functions on to the less object -// -var addDataAttr = require('./utils').addDataAttr, - browser = require('./browser'); + return Color; + }(Node); -module.exports = function(window, options) { - var document = window.document; - var less = require('../less')(); - - less.options = options; - var environment = less.environment, - FileManager = require('./file-manager')(options, less.logger), - fileManager = new FileManager(); - environment.addFileManager(fileManager); - less.FileManager = FileManager; - less.PluginLoader = require('./plugin-loader'); + Color.prototype.type = 'Color'; - require('./log-listener')(less, options); - var errors = require('./error-reporting')(window, less, options); - var cache = less.cache = options.cache || require('./cache')(window, options, less.logger); - require('./image-size')(less.environment); + function clamp(v, max) { + return Math.min(Math.max(v, 0), max); + } - // Setup user functions - Deprecate? - if (options.functions) { - less.functions.functionRegistry.addMultiple(options.functions); - } + function toHex(v) { + return "#".concat(v.map(function (c) { + c = clamp(Math.round(c), 255); + return (c < 16 ? '0' : '') + c.toString(16); + }).join('')); + } - var typePattern = /^text\/(x-)?less$/; + Color.fromKeyword = function (keyword) { + var c; + var key = keyword.toLowerCase(); - function clone(obj) { - var cloned = {}; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - cloned[prop] = obj[prop]; - } - } - return cloned; + if (colors.hasOwnProperty(key)) { + c = new Color(colors[key].slice(1)); + } else if (key === 'transparent') { + c = new Color([0, 0, 0], 0); } - // only really needed for phantom - function bind(func, thisArg) { - var curryArgs = Array.prototype.slice.call(arguments, 2); - return function() { - var args = curryArgs.concat(Array.prototype.slice.call(arguments, 0)); - return func.apply(thisArg, args); - }; + if (c) { + c.value = keyword; + return c; } + }; - function loadStyles(modifyVars) { - var styles = document.getElementsByTagName('style'), - style; - - for (var i = 0; i < styles.length; i++) { - style = styles[i]; - if (style.type.match(typePattern)) { - var instanceOptions = clone(options); - instanceOptions.modifyVars = modifyVars; - var lessText = style.innerHTML || ''; - instanceOptions.filename = document.location.href.replace(/#.*$/, ''); - - /* jshint loopfunc:true */ - // use closure to store current style - less.render(lessText, instanceOptions, - bind(function(style, e, result) { - if (e) { - errors.add(e, 'inline'); - } else { - style.type = 'text/css'; - if (style.styleSheet) { - style.styleSheet.cssText = result.css; - } else { - style.innerHTML = result.css; - } - } - }, null, style)); - } - } + var Paren = + /*#__PURE__*/ + function (_Node) { + _inherits(Paren, _Node); + + function Paren(node) { + var _this; + + _classCallCheck(this, Paren); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(Paren).call(this)); + _this.value = node; + return _this; } - function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) { + _createClass(Paren, [{ + key: "genCSS", + value: function genCSS(context, output) { + output.add('('); + this.value.genCSS(context, output); + output.add(')'); + } + }, { + key: "eval", + value: function _eval(context) { + return new Paren(this.value.eval(context)); + } + }]); - var instanceOptions = clone(options); - addDataAttr(instanceOptions, sheet); - instanceOptions.mime = sheet.type; + return Paren; + }(Node); - if (modifyVars) { - instanceOptions.modifyVars = modifyVars; - } + Paren.prototype.type = 'Paren'; - function loadInitialFileCallback(loadedFile) { + var _noSpaceCombinators = { + '': true, + ' ': true, + '|': true + }; - var data = loadedFile.contents, - path = loadedFile.filename, - webInfo = loadedFile.webInfo; + var Combinator = + /*#__PURE__*/ + function (_Node) { + _inherits(Combinator, _Node); - var newFileInfo = { - currentDirectory: fileManager.getPath(path), - filename: path, - rootFilename: path, - rewriteUrls: instanceOptions.rewriteUrls - }; + function Combinator(value) { + var _this; - newFileInfo.entryPath = newFileInfo.currentDirectory; - newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory; + _classCallCheck(this, Combinator); - if (webInfo) { - webInfo.remaining = remaining; + _this = _possibleConstructorReturn(this, _getPrototypeOf(Combinator).call(this)); - var css = cache.getCSS(path, webInfo, instanceOptions.modifyVars); - if (!reload && css) { - webInfo.local = true; - callback(null, css, data, sheet, webInfo, path); - return; - } + if (value === ' ') { + _this.value = ' '; + _this.emptyOrWhitespace = true; + } else { + _this.value = value ? value.trim() : ''; + _this.emptyOrWhitespace = _this.value === ''; + } - } + return _this; + } - // TODO add tests around how this behaves when reloading - errors.remove(path); + _createClass(Combinator, [{ + key: "genCSS", + value: function genCSS(context, output) { + var spaceOrEmpty = context.compress || _noSpaceCombinators[this.value] ? '' : ' '; + output.add(spaceOrEmpty + this.value + spaceOrEmpty); + } + }]); - instanceOptions.rootFileInfo = newFileInfo; - less.render(data, instanceOptions, function(e, result) { - if (e) { - e.href = path; - callback(e); - } else { - cache.setCSS(sheet.href, webInfo.lastModified, instanceOptions.modifyVars, result.css); - callback(null, result.css, data, sheet, webInfo, path); - } - }); - } + return Combinator; + }(Node); - fileManager.loadFile(sheet.href, null, instanceOptions, environment) - .then(function(loadedFile) { - loadInitialFileCallback(loadedFile); - }).catch(function(err) { - console.log(err); - callback(err); - }); + Combinator.prototype.type = 'Combinator'; - } + var Element = + /*#__PURE__*/ + function (_Node) { + _inherits(Element, _Node); - function loadStyleSheets(callback, reload, modifyVars) { - for (var i = 0; i < less.sheets.length; i++) { - loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars); - } - } + function Element(combinator, value, isVariable, index, currentFileInfo, visibilityInfo) { + var _this; - function initRunningMode() { - if (less.env === 'development') { - less.watchTimer = setInterval(function () { - if (less.watchMode) { - fileManager.clearFileCache(); - loadStyleSheets(function (e, css, _, sheet, webInfo) { - if (e) { - errors.add(e, e.href || sheet.href); - } else if (css) { - browser.createCSS(window.document, css, sheet); - } - }); - } - }, options.poll); - } - } + _classCallCheck(this, Element); - // - // Watch mode - // - less.watch = function () { - if (!less.watchMode ) { - less.env = 'development'; - initRunningMode(); - } - this.watchMode = true; - return true; - }; + _this = _possibleConstructorReturn(this, _getPrototypeOf(Element).call(this)); + _this.combinator = combinator instanceof Combinator ? combinator : new Combinator(combinator); - less.unwatch = function () {clearInterval(less.watchTimer); this.watchMode = false; return false; }; + if (typeof value === 'string') { + _this.value = value.trim(); + } else if (value) { + _this.value = value; + } else { + _this.value = ''; + } - // - // Synchronously get all tags with the 'rel' attribute set to - // "stylesheet/less". - // - less.registerStylesheetsImmediately = function() { - var links = document.getElementsByTagName('link'); - less.sheets = []; + _this.isVariable = isVariable; + _this._index = index; + _this._fileInfo = currentFileInfo; - for (var i = 0; i < links.length; i++) { - if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && - (links[i].type.match(typePattern)))) { - less.sheets.push(links[i]); - } - } - }; + _this.copyVisibilityInfo(visibilityInfo); - // - // Asynchronously get all tags with the 'rel' attribute set to - // "stylesheet/less", returning a Promise. - // - less.registerStylesheets = function() { - return new Promise(function(resolve, reject) { - less.registerStylesheetsImmediately(); - resolve(); - }); - }; + _this.setParent(_this.combinator, _assertThisInitialized(_this)); - // - // With this function, it's possible to alter variables and re-render - // CSS without reloading less-files - // - less.modifyVars = function(record) { - return less.refresh(true, record, false); - }; + return _this; + } - less.refresh = function (reload, modifyVars, clearFileCache) { - if ((reload || clearFileCache) && clearFileCache !== false) { - fileManager.clearFileCache(); + _createClass(Element, [{ + key: "accept", + value: function accept(visitor) { + var value = this.value; + this.combinator = visitor.visit(this.combinator); + + if (_typeof(value) === 'object') { + this.value = visitor.visit(value); } - return new Promise(function (resolve, reject) { - var startTime, endTime, totalMilliseconds, remainingSheets; - startTime = endTime = new Date(); + } + }, { + key: "eval", + value: function _eval(context) { + return new Element(this.combinator, this.value.eval ? this.value.eval(context) : this.value, this.isVariable, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } + }, { + key: "clone", + value: function clone() { + return new Element(this.combinator, this.value, this.isVariable, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + output.add(this.toCSS(context), this.fileInfo(), this.getIndex()); + } + }, { + key: "toCSS", + value: function toCSS() { + var context = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var value = this.value; + var firstSelector = context.firstSelector; - // Set counter for remaining unprocessed sheets - remainingSheets = less.sheets.length; + if (value instanceof Paren) { + // selector in parens should not be affected by outer selector + // flags (breaks only interpolated selectors - see #1973) + context.firstSelector = true; + } - if (remainingSheets === 0) { + value = value.toCSS ? value.toCSS(context) : value; + context.firstSelector = firstSelector; - endTime = new Date(); - totalMilliseconds = endTime - startTime; - less.logger.info('Less has finished and no sheets were loaded.'); - resolve({ - startTime: startTime, - endTime: endTime, - totalMilliseconds: totalMilliseconds, - sheets: less.sheets.length - }); + if (value === '' && this.combinator.value.charAt(0) === '&') { + return ''; + } else { + return this.combinator.toCSS(context) + value; + } + } + }]); + + return Element; + }(Node); + + Element.prototype.type = 'Element'; + + var Math$1 = { + ALWAYS: 0, + PARENS_DIVISION: 1, + PARENS: 2, + STRICT_LEGACY: 3 + }; + var RewriteUrls = { + OFF: 0, + LOCAL: 1, + ALL: 2 + }; + + function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; + } - } else { - // Relies on less.sheets array, callback seems to be guaranteed to be called for every element of the array - loadStyleSheets(function (e, css, _, sheet, webInfo) { - if (e) { - errors.add(e, e.href || sheet.href); - reject(e); - return; - } - if (webInfo.local) { - less.logger.info('Loading ' + sheet.href + ' from cache.'); - } else { - less.logger.info('Rendered ' + sheet.href + ' successfully.'); - } - browser.createCSS(window.document, css, sheet); - less.logger.info('CSS for ' + sheet.href + ' generated in ' + (new Date() - endTime) + 'ms'); - - // Count completed sheet - remainingSheets--; - - // Check if the last remaining sheet was processed and then call the promise - if (remainingSheets === 0) { - totalMilliseconds = new Date() - startTime; - less.logger.info('Less has finished. CSS generated in ' + totalMilliseconds + 'ms'); - resolve({ - startTime: startTime, - endTime: endTime, - totalMilliseconds: totalMilliseconds, - sheets: less.sheets.length - }); - } - endTime = new Date(); - }, reload, modifyVars); - } + var clone_1 = createCommonjsModule(function (module) { + var clone = (function() { - loadStyles(modifyVars); - }); - }; + function _instanceof(obj, type) { + return type != null && obj instanceof type; + } - less.refreshStyles = loadStyles; - return less; -}; + var nativeMap; + try { + nativeMap = Map; + } catch(_) { + // maybe a reference error because no `Map`. Give it a dummy value that no + // value will ever be an instanceof. + nativeMap = function() {}; + } -},{"../less":37,"./browser":3,"./cache":4,"./error-reporting":5,"./file-manager":6,"./image-size":7,"./log-listener":9,"./plugin-loader":10,"./utils":11}],9:[function(require,module,exports){ -module.exports = function(less, options) { + var nativeSet; + try { + nativeSet = Set; + } catch(_) { + nativeSet = function() {}; + } - var logLevel_debug = 4, - logLevel_info = 3, - logLevel_warn = 2, - logLevel_error = 1; + var nativePromise; + try { + nativePromise = Promise; + } catch(_) { + nativePromise = function() {}; + } - // The amount of logging in the javascript console. - // 3 - Debug, information and errors - // 2 - Information and errors - // 1 - Errors - // 0 - None - // Defaults to 2 - options.logLevel = typeof options.logLevel !== 'undefined' ? options.logLevel : (options.env === 'development' ? logLevel_info : logLevel_error); + /** + * Clones (copies) an Object using deep copying. + * + * This function supports circular references by default, but if you are certain + * there are no circular references in your object, you can save some CPU time + * by calling clone(obj, false). + * + * Caution: if `circular` is false and `parent` contains circular references, + * your program may enter an infinite loop and crash. + * + * @param `parent` - the object to be cloned + * @param `circular` - set to true if the object to be cloned may contain + * circular references. (optional - true by default) + * @param `depth` - set to a number if the object is only to be cloned to + * a particular depth. (optional - defaults to Infinity) + * @param `prototype` - sets the prototype to be used when cloning an object. + * (optional - defaults to parent prototype). + * @param `includeNonEnumerable` - set to true if the non-enumerable properties + * should be cloned as well. Non-enumerable properties on the prototype + * chain will be ignored. (optional - false by default) + */ + function clone(parent, circular, depth, prototype, includeNonEnumerable) { + if (typeof circular === 'object') { + depth = circular.depth; + prototype = circular.prototype; + includeNonEnumerable = circular.includeNonEnumerable; + circular = circular.circular; + } + // maintain two arrays for circular references, where corresponding parents + // and children have the same index + var allParents = []; + var allChildren = []; + + var useBuffer = typeof Buffer != 'undefined'; + + if (typeof circular == 'undefined') + circular = true; + + if (typeof depth == 'undefined') + depth = Infinity; + + // recurse this function so we don't reset allParents and allChildren + function _clone(parent, depth) { + // cloning null always returns null + if (parent === null) + return null; - if (!options.loggers) { - options.loggers = [{ - debug: function(msg) { - if (options.logLevel >= logLevel_debug) { - console.log(msg); - } - }, - info: function(msg) { - if (options.logLevel >= logLevel_info) { - console.log(msg); - } - }, - warn: function(msg) { - if (options.logLevel >= logLevel_warn) { - console.warn(msg); - } - }, - error: function(msg) { - if (options.logLevel >= logLevel_error) { - console.error(msg); - } - } - }]; - } - for (var i = 0; i < options.loggers.length; i++) { - less.logger.addListener(options.loggers[i]); - } -}; + if (depth === 0) + return parent; -},{}],10:[function(require,module,exports){ -// TODO: Add tests for browser @plugin -/* global window */ + var child; + var proto; + if (typeof parent != 'object') { + return parent; + } -var AbstractPluginLoader = require('../less/environment/abstract-plugin-loader.js'); + if (_instanceof(parent, nativeMap)) { + child = new nativeMap(); + } else if (_instanceof(parent, nativeSet)) { + child = new nativeSet(); + } else if (_instanceof(parent, nativePromise)) { + child = new nativePromise(function (resolve, reject) { + parent.then(function(value) { + resolve(_clone(value, depth - 1)); + }, function(err) { + reject(_clone(err, depth - 1)); + }); + }); + } else if (clone.__isArray(parent)) { + child = []; + } else if (clone.__isRegExp(parent)) { + child = new RegExp(parent.source, __getRegExpFlags(parent)); + if (parent.lastIndex) child.lastIndex = parent.lastIndex; + } else if (clone.__isDate(parent)) { + child = new Date(parent.getTime()); + } else if (useBuffer && Buffer.isBuffer(parent)) { + if (Buffer.allocUnsafe) { + // Node.js >= 4.5.0 + child = Buffer.allocUnsafe(parent.length); + } else { + // Older Node.js versions + child = new Buffer(parent.length); + } + parent.copy(child); + return child; + } else if (_instanceof(parent, Error)) { + child = Object.create(parent); + } else { + if (typeof prototype == 'undefined') { + proto = Object.getPrototypeOf(parent); + child = Object.create(proto); + } + else { + child = Object.create(prototype); + proto = prototype; + } + } -/** - * Browser Plugin Loader - */ -var PluginLoader = function(less) { - this.less = less; - // Should we shim this.require for browser? Probably not? -}; + if (circular) { + var index = allParents.indexOf(parent); -PluginLoader.prototype = new AbstractPluginLoader(); + if (index != -1) { + return allChildren[index]; + } + allParents.push(parent); + allChildren.push(child); + } -PluginLoader.prototype.loadPlugin = function(filename, basePath, context, environment, fileManager) { - return new Promise(function(fulfill, reject) { - fileManager.loadFile(filename, basePath, context, environment) - .then(fulfill).catch(reject); - }); -}; + if (_instanceof(parent, nativeMap)) { + parent.forEach(function(value, key) { + var keyChild = _clone(key, depth - 1); + var valueChild = _clone(value, depth - 1); + child.set(keyChild, valueChild); + }); + } + if (_instanceof(parent, nativeSet)) { + parent.forEach(function(value) { + var entryChild = _clone(value, depth - 1); + child.add(entryChild); + }); + } -module.exports = PluginLoader; + for (var i in parent) { + var attrs; + if (proto) { + attrs = Object.getOwnPropertyDescriptor(proto, i); + } + if (attrs && attrs.set == null) { + continue; + } + child[i] = _clone(parent[i], depth - 1); + } -},{"../less/environment/abstract-plugin-loader.js":19}],11:[function(require,module,exports){ -module.exports = { - extractId: function(href) { - return href.replace(/^[a-z-]+:\/+?[^\/]+/, '') // Remove protocol & domain - .replace(/[\?\&]livereload=\w+/, '') // Remove LiveReload cachebuster - .replace(/^\//, '') // Remove root / - .replace(/\.[a-zA-Z]+$/, '') // Remove simple extension - .replace(/[^\.\w-]+/g, '-') // Replace illegal characters - .replace(/\./g, ':'); // Replace dots with colons(for valid id) - }, - addDataAttr: function(options, tag) { - for (var opt in tag.dataset) { - if (tag.dataset.hasOwnProperty(opt)) { - if (opt === 'env' || opt === 'dumpLineNumbers' || opt === 'rootpath' || opt === 'errorReporting') { - options[opt] = tag.dataset[opt]; - } else { - try { - options[opt] = JSON.parse(tag.dataset[opt]); - } - catch (_) {} - } - } + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(parent); + for (var i = 0; i < symbols.length; i++) { + // Don't need to worry about cloning a symbol because it is a primitive, + // like a number or string. + var symbol = symbols[i]; + var descriptor = Object.getOwnPropertyDescriptor(parent, symbol); + if (descriptor && !descriptor.enumerable && !includeNonEnumerable) { + continue; + } + child[symbol] = _clone(parent[symbol], depth - 1); + if (!descriptor.enumerable) { + Object.defineProperty(child, symbol, { + enumerable: false + }); + } } - } -}; + } -},{}],12:[function(require,module,exports){ -module.exports = { - Math: { - ALWAYS: 0, - PARENS_DIVISION: 1, - PARENS: 2, - STRICT_LEGACY: 3 - }, - RewriteUrls: { - OFF: 0, - LOCAL: 1, - ALL: 2 + if (includeNonEnumerable) { + var allPropertyNames = Object.getOwnPropertyNames(parent); + for (var i = 0; i < allPropertyNames.length; i++) { + var propertyName = allPropertyNames[i]; + var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName); + if (descriptor && descriptor.enumerable) { + continue; + } + child[propertyName] = _clone(parent[propertyName], depth - 1); + Object.defineProperty(child, propertyName, { + enumerable: false + }); + } + } + + return child; } -}; -},{}],13:[function(require,module,exports){ -var contexts = {}; -module.exports = contexts; -var Constants = require('./constants'); -var copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) { - if (!original) { return; } + return _clone(parent, depth); + } - for (var i = 0; i < propertiesToCopy.length; i++) { - if (original.hasOwnProperty(propertiesToCopy[i])) { - destination[propertiesToCopy[i]] = original[propertiesToCopy[i]]; - } - } -}; + /** + * Simple flat clone using prototype, accepts only objects, usefull for property + * override on FLAT configuration object (no nested props). + * + * USE WITH CAUTION! This may not behave as you wish if you do not know how this + * works. + */ + clone.clonePrototype = function clonePrototype(parent) { + if (parent === null) + return null; -/* - parse is used whilst parsing - */ -var parseCopyProperties = [ - // options - 'paths', // option - unmodified - paths to search for imports on - 'rewriteUrls', // option - whether to adjust URL's to be relative - 'rootpath', // option - rootpath to append to URL's - 'strictImports', // option - - 'insecure', // option - whether to allow imports from insecure ssl hosts - 'dumpLineNumbers', // option - whether to dump line numbers - 'compress', // option - whether to compress - 'syncImport', // option - whether to import synchronously - 'chunkInput', // option - whether to chunk input. more performant but causes parse issues. - 'mime', // browser only - mime type for sheet import - 'useFileCache', // browser only - whether to use the per file session cache - // context - 'processImports', // option & context - whether to process imports. if false then imports will not be imported. - // Used by the import manager to stop multiple import visitors being created. - 'pluginManager' // Used as the plugin manager for the session -]; - -contexts.Parse = function(options) { - copyFromOriginal(options, this, parseCopyProperties); + var c = function () {}; + c.prototype = parent; + return new c(); + }; - if (typeof this.paths === 'string') { this.paths = [this.paths]; } -}; - -var evalCopyProperties = [ - 'paths', // additional include paths - 'compress', // whether to compress - 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri) - '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 - 'urlArgs', // whether to add args into url tokens - 'javascriptEnabled', // option - whether Inline JavaScript is enabled. if undefined, defaults to false - 'pluginManager', // Used as the plugin manager for the session - 'importantScope', // used to bubble up !important statements - 'rewriteUrls' // option - whether to adjust URL's to be relative -]; - -contexts.Eval = function(options, frames) { - copyFromOriginal(options, this, evalCopyProperties); - - if (typeof this.paths === 'string') { this.paths = [this.paths]; } - - this.frames = frames || []; - this.importantScope = this.importantScope || []; -}; - -contexts.Eval.prototype.enterCalc = function () { - if (!this.calcStack) { - this.calcStack = []; - } - this.calcStack.push(true); - this.inCalc = true; -}; - -contexts.Eval.prototype.exitCalc = function () { - this.calcStack.pop(); - if (!this.calcStack) { - this.inCalc = false; - } -}; - -contexts.Eval.prototype.inParenthesis = function () { - if (!this.parensStack) { - this.parensStack = []; - } - this.parensStack.push(true); -}; - -contexts.Eval.prototype.outOfParenthesis = function () { - this.parensStack.pop(); -}; - -contexts.Eval.prototype.inCalc = false; -contexts.Eval.prototype.mathOn = true; -contexts.Eval.prototype.isMathOn = function (op) { - if (!this.mathOn) { - return false; - } - if (op === '/' && this.math !== Constants.Math.ALWAYS && (!this.parensStack || !this.parensStack.length)) { - return false; - } - if (this.math > Constants.Math.PARENS_DIVISION) { - return this.parensStack && this.parensStack.length; - } - return true; -}; + // private utility functions -contexts.Eval.prototype.pathRequiresRewrite = function (path) { - var isRelative = this.rewriteUrls === Constants.RewriteUrls.LOCAL ? isPathLocalRelative : isPathRelative; + function __objToStr(o) { + return Object.prototype.toString.call(o); + } + clone.__objToStr = __objToStr; - return isRelative(path); -}; + function __isDate(o) { + return typeof o === 'object' && __objToStr(o) === '[object Date]'; + } + clone.__isDate = __isDate; -contexts.Eval.prototype.rewritePath = function (path, rootpath) { - var newPath; + function __isArray(o) { + return typeof o === 'object' && __objToStr(o) === '[object Array]'; + } + clone.__isArray = __isArray; - rootpath = rootpath || ''; - newPath = this.normalizePath(rootpath + path); + function __isRegExp(o) { + return typeof o === 'object' && __objToStr(o) === '[object RegExp]'; + } + clone.__isRegExp = __isRegExp; + + function __getRegExpFlags(re) { + var flags = ''; + if (re.global) flags += 'g'; + if (re.ignoreCase) flags += 'i'; + if (re.multiline) flags += 'm'; + return flags; + } + clone.__getRegExpFlags = __getRegExpFlags; - // If a path was explicit relative and the rootpath was not an absolute path - // we must ensure that the new path is also explicit relative. - if (isPathLocalRelative(path) && - isPathRelative(rootpath) && - isPathLocalRelative(newPath) === false) { - newPath = './' + newPath; - } + return clone; + })(); - return newPath; -}; + if ( module.exports) { + module.exports = clone; + } + }); -contexts.Eval.prototype.normalizePath = function (path) { - var - segments = path.split('/').reverse(), - segment; + /* jshint proto: true */ + function getLocation(index, inputStream) { + var n = index + 1; + var line = null; + var column = -1; - path = []; - while (segments.length !== 0) { - segment = segments.pop(); - switch ( segment ) { - case '.': - break; - case '..': - if ((path.length === 0) || (path[path.length - 1] === '..')) { - path.push( segment ); - } else { - path.pop(); - } - break; - default: - path.push(segment); - break; - } + while (--n >= 0 && inputStream.charAt(n) !== '\n') { + column++; } - return path.join('/'); -}; - -function isPathRelative(path) { - return !/^(?:[a-z-]+:|\/|#)/i.test(path); -} + if (typeof index === 'number') { + line = (inputStream.slice(0, index).match(/\n/g) || '').length; + } -function isPathLocalRelative(path) { - return path.charAt(0) === '.'; -} - -// todo - do the same for the toCSS ? - -},{"./constants":12}],14:[function(require,module,exports){ -module.exports = { - 'aliceblue':'#f0f8ff', - 'antiquewhite':'#faebd7', - 'aqua':'#00ffff', - 'aquamarine':'#7fffd4', - 'azure':'#f0ffff', - 'beige':'#f5f5dc', - 'bisque':'#ffe4c4', - 'black':'#000000', - 'blanchedalmond':'#ffebcd', - 'blue':'#0000ff', - 'blueviolet':'#8a2be2', - 'brown':'#a52a2a', - 'burlywood':'#deb887', - 'cadetblue':'#5f9ea0', - 'chartreuse':'#7fff00', - 'chocolate':'#d2691e', - 'coral':'#ff7f50', - 'cornflowerblue':'#6495ed', - 'cornsilk':'#fff8dc', - 'crimson':'#dc143c', - 'cyan':'#00ffff', - 'darkblue':'#00008b', - 'darkcyan':'#008b8b', - 'darkgoldenrod':'#b8860b', - 'darkgray':'#a9a9a9', - 'darkgrey':'#a9a9a9', - 'darkgreen':'#006400', - 'darkkhaki':'#bdb76b', - 'darkmagenta':'#8b008b', - 'darkolivegreen':'#556b2f', - 'darkorange':'#ff8c00', - 'darkorchid':'#9932cc', - 'darkred':'#8b0000', - 'darksalmon':'#e9967a', - 'darkseagreen':'#8fbc8f', - 'darkslateblue':'#483d8b', - 'darkslategray':'#2f4f4f', - 'darkslategrey':'#2f4f4f', - 'darkturquoise':'#00ced1', - 'darkviolet':'#9400d3', - 'deeppink':'#ff1493', - 'deepskyblue':'#00bfff', - 'dimgray':'#696969', - 'dimgrey':'#696969', - 'dodgerblue':'#1e90ff', - 'firebrick':'#b22222', - 'floralwhite':'#fffaf0', - 'forestgreen':'#228b22', - 'fuchsia':'#ff00ff', - 'gainsboro':'#dcdcdc', - 'ghostwhite':'#f8f8ff', - 'gold':'#ffd700', - 'goldenrod':'#daa520', - 'gray':'#808080', - 'grey':'#808080', - 'green':'#008000', - 'greenyellow':'#adff2f', - 'honeydew':'#f0fff0', - 'hotpink':'#ff69b4', - 'indianred':'#cd5c5c', - 'indigo':'#4b0082', - 'ivory':'#fffff0', - 'khaki':'#f0e68c', - 'lavender':'#e6e6fa', - 'lavenderblush':'#fff0f5', - 'lawngreen':'#7cfc00', - 'lemonchiffon':'#fffacd', - 'lightblue':'#add8e6', - 'lightcoral':'#f08080', - 'lightcyan':'#e0ffff', - 'lightgoldenrodyellow':'#fafad2', - 'lightgray':'#d3d3d3', - 'lightgrey':'#d3d3d3', - 'lightgreen':'#90ee90', - 'lightpink':'#ffb6c1', - 'lightsalmon':'#ffa07a', - 'lightseagreen':'#20b2aa', - 'lightskyblue':'#87cefa', - 'lightslategray':'#778899', - 'lightslategrey':'#778899', - 'lightsteelblue':'#b0c4de', - 'lightyellow':'#ffffe0', - 'lime':'#00ff00', - 'limegreen':'#32cd32', - 'linen':'#faf0e6', - 'magenta':'#ff00ff', - 'maroon':'#800000', - 'mediumaquamarine':'#66cdaa', - 'mediumblue':'#0000cd', - 'mediumorchid':'#ba55d3', - 'mediumpurple':'#9370d8', - 'mediumseagreen':'#3cb371', - 'mediumslateblue':'#7b68ee', - 'mediumspringgreen':'#00fa9a', - 'mediumturquoise':'#48d1cc', - 'mediumvioletred':'#c71585', - 'midnightblue':'#191970', - 'mintcream':'#f5fffa', - 'mistyrose':'#ffe4e1', - 'moccasin':'#ffe4b5', - 'navajowhite':'#ffdead', - 'navy':'#000080', - 'oldlace':'#fdf5e6', - 'olive':'#808000', - 'olivedrab':'#6b8e23', - 'orange':'#ffa500', - 'orangered':'#ff4500', - 'orchid':'#da70d6', - 'palegoldenrod':'#eee8aa', - 'palegreen':'#98fb98', - 'paleturquoise':'#afeeee', - 'palevioletred':'#d87093', - 'papayawhip':'#ffefd5', - 'peachpuff':'#ffdab9', - 'peru':'#cd853f', - 'pink':'#ffc0cb', - 'plum':'#dda0dd', - 'powderblue':'#b0e0e6', - 'purple':'#800080', - 'rebeccapurple':'#663399', - 'red':'#ff0000', - 'rosybrown':'#bc8f8f', - 'royalblue':'#4169e1', - 'saddlebrown':'#8b4513', - 'salmon':'#fa8072', - 'sandybrown':'#f4a460', - 'seagreen':'#2e8b57', - 'seashell':'#fff5ee', - 'sienna':'#a0522d', - 'silver':'#c0c0c0', - 'skyblue':'#87ceeb', - 'slateblue':'#6a5acd', - 'slategray':'#708090', - 'slategrey':'#708090', - 'snow':'#fffafa', - 'springgreen':'#00ff7f', - 'steelblue':'#4682b4', - 'tan':'#d2b48c', - 'teal':'#008080', - 'thistle':'#d8bfd8', - 'tomato':'#ff6347', - 'turquoise':'#40e0d0', - 'violet':'#ee82ee', - 'wheat':'#f5deb3', - 'white':'#ffffff', - 'whitesmoke':'#f5f5f5', - 'yellow':'#ffff00', - 'yellowgreen':'#9acd32' -}; -},{}],15:[function(require,module,exports){ -module.exports = { - colors: require('./colors'), - unitConversions: require('./unit-conversions') -}; - -},{"./colors":14,"./unit-conversions":16}],16:[function(require,module,exports){ -module.exports = { - length: { - 'm': 1, - 'cm': 0.01, - 'mm': 0.001, - 'in': 0.0254, - 'px': 0.0254 / 96, - 'pt': 0.0254 / 72, - 'pc': 0.0254 / 72 * 12 - }, - duration: { - 's': 1, - 'ms': 0.001 - }, - angle: { - 'rad': 1 / (2 * Math.PI), - 'deg': 1 / 360, - 'grad': 1 / 400, - 'turn': 1 - } -}; -},{}],17:[function(require,module,exports){ -// 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, - - /* (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, - - /* Runs the less parser and just reports errors without any output. */ - lint: false, - - /* Sets available include paths. - * If the file in an @import rule does not exist at that exact location, - * less will look for it at the location(s) passed to this option. - * You might use this for instance to specify a path to a library which - * you want to be referenced simply and relatively in the less files. */ - paths: [], - - /* color output in the terminal */ - color: true, - - /* The strictImports controls whether the compiler will allow an @import inside of either - * @media blocks or (a later addition) other selector blocks. - * See: https://github.com/less/less.js/issues/656 */ - strictImports: false, - - /* Allow Imports from Insecure HTTPS Hosts */ - insecure: false, - - /* Allows you to add a path to every generated import and url in your css. - * This does not affect less import statements that are processed, just ones - * that are left in the output css. */ - rootpath: '', - - /* By default URLs are kept as-is, so if you import a file in a sub-directory - * that references an image, exactly the same URL will be output in the css. - * This option allows you to re-write URL's in imported files so that the - * URL is always relative to the base imported file */ - rewriteUrls: false, - - /* Compatibility with IE8. Used for limiting data-uri length */ - ieCompat: false, // true until 3.0 - - /* 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, - - /* Effectively the declaration is put at the top of your base Less file, - * meaning it can be used but it also can be overridden if this variable - * is defined in the file. */ - globalVars: null, - - /* As opposed to the global variable option, this puts the declaration at the - * end of your base file, meaning it will override anything defined in your Less file. */ - modifyVars: null, - - /* This option allows you to specify a argument to go on to every URL. */ - urlArgs: '' - } -} -},{}],18:[function(require,module,exports){ -var abstractFileManager = function() { -}; - -abstractFileManager.prototype.getPath = function (filename) { - var j = filename.lastIndexOf('?'); - if (j > 0) { - filename = filename.slice(0, j); - } - j = filename.lastIndexOf('/'); - if (j < 0) { - j = filename.lastIndexOf('\\'); - } - if (j < 0) { - return ''; - } - return filename.slice(0, j + 1); -}; - -abstractFileManager.prototype.tryAppendExtension = function(path, ext) { - return /(\.[a-z]*$)|([\?;].*)$/.test(path) ? path : path + ext; -}; - -abstractFileManager.prototype.tryAppendLessExtension = function(path) { - return this.tryAppendExtension(path, '.less'); -}; - -abstractFileManager.prototype.supportsSync = function() { - return false; -}; - -abstractFileManager.prototype.alwaysMakePathsAbsolute = function() { - return false; -}; - -abstractFileManager.prototype.isPathAbsolute = function(filename) { - return (/^(?:[a-z-]+:|\/|\\|#)/i).test(filename); -}; -// TODO: pull out / replace? -abstractFileManager.prototype.join = function(basePath, laterPath) { - if (!basePath) { - return laterPath; - } - return basePath + laterPath; -}; - -abstractFileManager.prototype.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 -abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, baseUrl) { - // urlParts[1] = protocol://hostname/ OR / - // urlParts[2] = / if path relative to host base - // urlParts[3] = directories - // urlParts[4] = filename - // urlParts[5] = parameters - - var urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i, - urlParts = url.match(urlPartsRegex), - returner = {}, rawDirectories = [], 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]; - } - } + line: line, + column: column + }; + } + function copyArray(arr) { + var i; + var length = arr.length; + var copy = new Array(length); - if (urlParts[3]) { - rawDirectories = urlParts[3].replace(/\\/g, '/').split('/'); + for (i = 0; i < length; i++) { + copy[i] = arr[i]; + } - // collapse '..' and skip '.' - for (i = 0; i < rawDirectories.length; i++) { + return copy; + } + function clone(obj) { + var cloned = {}; - if (rawDirectories[i] === '..') { - directories.pop(); - } - else if (rawDirectories[i] !== '.') { - directories.push(rawDirectories[i]); - } - - } + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + cloned[prop] = obj[prop]; + } } - returner.hostPart = urlParts[1]; - returner.directories = directories; - returner.rawPath = (urlParts[1] || '') + rawDirectories.join('/'); - returner.path = (urlParts[1] || '') + directories.join('/'); - returner.filename = urlParts[4]; - returner.fileUrl = returner.path + (urlParts[4] || ''); - returner.url = returner.fileUrl + (urlParts[5] || ''); - return returner; -}; + return cloned; + } + function defaults(obj1, obj2) { + var newObj = obj2 || {}; -module.exports = abstractFileManager; + if (!obj2._defaults) { + newObj = {}; -},{}],19:[function(require,module,exports){ -var functionRegistry = require('../functions/function-registry'), - LessError = require('../less-error'); + var _defaults = clone_1(obj1); -var AbstractPluginLoader = function() { - // Implemented by Node.js plugin loader - this.require = function() { - return null; + newObj._defaults = _defaults; + var cloned = obj2 ? clone_1(obj2) : {}; + Object.assign(newObj, _defaults, cloned); } -}; -AbstractPluginLoader.prototype.evalPlugin = function(contents, context, imports, pluginOptions, fileInfo) { + return newObj; + } + function copyOptions(obj1, obj2) { + if (obj2 && obj2._defaults) { + return obj2; + } - var loader, - registry, - pluginObj, - localModule, - pluginManager, - filename, - result; + var opts = defaults(obj1, obj2); - pluginManager = context.pluginManager; + if (opts.strictMath) { + opts.math = Math$1.STRICT_LEGACY; + } // Back compat with changed relativeUrls option - if (fileInfo) { - if (typeof fileInfo === 'string') { - filename = fileInfo; - } - else { - filename = fileInfo.filename; - } + + if (opts.relativeUrls) { + opts.rewriteUrls = RewriteUrls.ALL; } - var shortname = (new this.less.FileManager()).extractUrlParts(filename).filename; - if (filename) { - pluginObj = pluginManager.get(filename); + if (typeof opts.math === 'string') { + switch (opts.math.toLowerCase()) { + case 'always': + opts.math = Math$1.ALWAYS; + break; - if (pluginObj) { - result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); - if (result) { - return result; - } - try { - if (pluginObj.use) { - pluginObj.use.call(this.context, pluginObj); - } - } - catch (e) { - e.message = e.message || 'Error during @plugin call'; - return new LessError(e, imports, filename); - } - return pluginObj; - } - } - localModule = { - exports: {}, - pluginManager: pluginManager, - fileInfo: fileInfo - }; - registry = functionRegistry.create(); + case 'parens-division': + opts.math = Math$1.PARENS_DIVISION; + break; - var registerPlugin = function(obj) { - pluginObj = obj; - }; + case 'strict': + case 'parens': + opts.math = Math$1.PARENS; + break; - try { - loader = new Function('module', 'require', 'registerPlugin', 'functions', 'tree', 'less', 'fileInfo', contents); - loader(localModule, this.require(filename), registerPlugin, registry, this.less.tree, this.less, fileInfo); - } - catch (e) { - return new LessError(e, imports, filename); + case 'strict-legacy': + opts.math = Math$1.STRICT_LEGACY; + } } - if (!pluginObj) { - pluginObj = localModule.exports; + if (typeof opts.rewriteUrls === 'string') { + switch (opts.rewriteUrls.toLowerCase()) { + case 'off': + opts.rewriteUrls = RewriteUrls.OFF; + break; + + case 'local': + opts.rewriteUrls = RewriteUrls.LOCAL; + break; + + case 'all': + opts.rewriteUrls = RewriteUrls.ALL; + break; + } } - pluginObj = this.validatePlugin(pluginObj, filename, shortname); - if (pluginObj instanceof LessError) { - return pluginObj; + return opts; + } + function merge(obj1, obj2) { + for (var prop in obj2) { + if (obj2.hasOwnProperty(prop)) { + obj1[prop] = obj2[prop]; + } } - if (pluginObj) { - pluginObj.imports = imports; - pluginObj.filename = filename; + return obj1; + } + function flattenArray(arr) { + var result = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; - // For < 3.x (or unspecified minVersion) - setOptions() before install() - if (!pluginObj.minVersion || this.compareVersion('3.0.0', pluginObj.minVersion) < 0) { - result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); + for (var i = 0, length = arr.length; i < length; i++) { + var value = arr[i]; - if (result) { - return result; - } + if (Array.isArray(value)) { + flattenArray(value, result); + } else { + if (value !== undefined) { + result.push(value); } + } + } - // Run on first load - pluginManager.addPlugin(pluginObj, fileInfo.filename, registry); - pluginObj.functions = registry.getLocalFunctions(); + return result; + } - // Need to call setOptions again because the pluginObj might have functions - result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); - if (result) { - return result; - } + var utils = /*#__PURE__*/Object.freeze({ + getLocation: getLocation, + copyArray: copyArray, + clone: clone, + defaults: defaults, + copyOptions: copyOptions, + merge: merge, + flattenArray: flattenArray + }); - // Run every @plugin call - try { - if (pluginObj.use) { - pluginObj.use.call(this.context, pluginObj); - } - } - catch (e) { - e.message = e.message || 'Error during @plugin call'; - return new LessError(e, imports, filename); + /** + * This is a centralized class of any error that could be thrown internally (mostly by the parser). + * Besides standard .message it keeps some additional data like a path to the file where the error + * occurred along with line and column numbers. + * + * @class + * @extends Error + * @type {module.LessError} + * + * @prop {string} type + * @prop {string} filename + * @prop {number} index + * @prop {number} line + * @prop {number} column + * @prop {number} callLine + * @prop {number} callExtract + * @prop {string[]} extract + * + * @param {Object} e - An error object to wrap around or just a descriptive object + * @param {Object} fileContentMap - An object with file contents in 'contents' property (like importManager) @todo - move to fileManager? + * @param {string} [currentFilename] + */ + + var LessError = function LessError(e, fileContentMap, currentFilename) { + Error.call(this); + var filename = e.filename || currentFilename; + this.message = e.message; + this.stack = e.stack; + + if (fileContentMap && filename) { + var input = fileContentMap.contents[filename]; + var loc = getLocation(e.index, input); + var line = loc.line; + var col = loc.column; + var callLine = e.call && getLocation(e.call, input).line; + var lines = input ? input.split('\n') : ''; + this.type = e.type || 'Syntax'; + this.filename = filename; + this.index = e.index; + this.line = typeof line === 'number' ? line + 1 : null; + this.column = col; + + if (!this.line && this.stack) { + var found = this.stack.match(/(|Function):(\d+):(\d+)/); + + if (found) { + if (found[2]) { + this.line = parseInt(found[2]) - 2; + } + + if (found[3]) { + this.column = parseInt(found[3]); + } } + } + this.callLine = callLine + 1; + this.callExtract = lines[callLine]; + this.extract = [lines[this.line - 2], lines[this.line - 1], lines[this.line]]; } - else { - return new LessError({ message: 'Not a valid plugin' }, imports, filename); - } + }; - return pluginObj; + if (typeof Object.create === 'undefined') { + var F = function F() {}; -}; + F.prototype = Error.prototype; + LessError.prototype = new F(); + } else { + LessError.prototype = Object.create(Error.prototype); + } -AbstractPluginLoader.prototype.trySetOptions = function(plugin, filename, name, options) { - if (options && !plugin.setOptions) { - return new LessError({ - message: 'Options have been provided but the plugin ' + - name + ' does not support any options.' - }); - } - try { - plugin.setOptions && plugin.setOptions(options); - } - catch (e) { - return new LessError(e); - } -}; + LessError.prototype.constructor = LessError; + /** + * An overridden version of the default Object.prototype.toString + * which uses additional information to create a helpful message. + * + * @param {Object} options + * @returns {string} + */ + + LessError.prototype.toString = function () { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var message = ''; + var extract = this.extract || []; + var error = []; -AbstractPluginLoader.prototype.validatePlugin = function(plugin, filename, name) { - if (plugin) { - // support plugins being a function - // so that the plugin can be more usable programmatically - if (typeof plugin === 'function') { - plugin = new plugin(); - } + var stylize = function stylize(str) { + return str; + }; - if (plugin.minVersion) { - if (this.compareVersion(plugin.minVersion, this.less.version) < 0) { - return new LessError({ - message: 'Plugin ' + name + ' requires version ' + - this.versionToString(plugin.minVersion) - }); - } - } - return plugin; - } - return null; -}; + if (options.stylize) { + var type = _typeof(options.stylize); -AbstractPluginLoader.prototype.compareVersion = function(aVersion, bVersion) { - if (typeof aVersion === 'string') { - aVersion = aVersion.match(/^(\d+)\.?(\d+)?\.?(\d+)?/); - aVersion.shift(); - } - for (var i = 0; i < aVersion.length; i++) { - if (aVersion[i] !== bVersion[i]) { - return parseInt(aVersion[i]) > parseInt(bVersion[i]) ? -1 : 1; - } - } - return 0; -}; -AbstractPluginLoader.prototype.versionToString = function(version) { - var versionString = ''; - for (var i = 0; i < version.length; i++) { - versionString += (versionString ? '.' : '') + version[i]; - } - return versionString; -}; -AbstractPluginLoader.prototype.printUsage = function(plugins) { - for (var i = 0; i < plugins.length; i++) { - var plugin = plugins[i]; - if (plugin.printUsage) { - plugin.printUsage(); - } + if (type !== 'function') { + throw Error("options.stylize should be a function, got a ".concat(type, "!")); + } + + stylize = options.stylize; } -}; -module.exports = AbstractPluginLoader; + if (this.line !== null) { + if (typeof extract[0] === 'string') { + error.push(stylize("".concat(this.line - 1, " ").concat(extract[0]), 'grey')); + } + if (typeof extract[1] === 'string') { + var errorTxt = "".concat(this.line, " "); -},{"../functions/function-registry":27,"../less-error":38}],20:[function(require,module,exports){ -/** - * @todo Document why this abstraction exists, and the relationship between - * environment, file managers, and plugin manager - */ + if (extract[1]) { + errorTxt += extract[1].slice(0, this.column) + stylize(stylize(stylize(extract[1].substr(this.column, 1), 'bold') + extract[1].slice(this.column + 1), 'red'), 'inverse'); + } -var logger = require('../logger'); -var environment = function(externalEnvironment, fileManagers) { - this.fileManagers = fileManagers || []; - externalEnvironment = externalEnvironment || {}; + error.push(errorTxt); + } - var optionalFunctions = ['encodeBase64', 'mimeLookup', 'charsetLookup', 'getSourceMapGenerator'], - requiredFunctions = [], - functions = requiredFunctions.concat(optionalFunctions); + if (typeof extract[2] === 'string') { + error.push(stylize("".concat(this.line + 1, " ").concat(extract[2]), 'grey')); + } - for (var i = 0; i < functions.length; i++) { - var propName = functions[i], - environmentFunc = externalEnvironment[propName]; - if (environmentFunc) { - this[propName] = environmentFunc.bind(externalEnvironment); - } else if (i < requiredFunctions.length) { - this.warn('missing required function in environment - ' + propName); - } + error = "".concat(error.join('\n') + stylize('', 'reset'), "\n"); } -}; -environment.prototype.getFileManager = function (filename, currentDirectory, options, environment, isSync) { + message += stylize("".concat(this.type, "Error: ").concat(this.message), 'red'); - if (!filename) { - logger.warn('getFileManager called with no filename.. Please report this issue. continuing.'); - } - if (currentDirectory == null) { - logger.warn('getFileManager called with null directory.. Please report this issue. continuing.'); + if (this.filename) { + message += stylize(' in ', 'red') + this.filename; } - var fileManagers = this.fileManagers; - if (options.pluginManager) { - fileManagers = [].concat(fileManagers).concat(options.pluginManager.getFileManagers()); - } - for (var i = fileManagers.length - 1; i >= 0 ; i--) { - var fileManager = fileManagers[i]; - if (fileManager[isSync ? 'supportsSync' : 'supports'](filename, currentDirectory, options, environment)) { - return fileManager; - } + if (this.line) { + message += stylize(" on line ".concat(this.line, ", column ").concat(this.column + 1, ":"), 'grey'); } - return null; -}; -environment.prototype.addFileManager = function (fileManager) { - this.fileManagers.push(fileManager); -}; + message += "\n".concat(error); -environment.prototype.clearFileManagers = function () { - this.fileManagers = []; -}; + if (this.callLine) { + message += "".concat(stylize('from ', 'red') + (this.filename || ''), "/n"); + message += "".concat(stylize(this.callLine, 'grey'), " ").concat(this.callExtract, "/n"); + } -module.exports = environment; + return message; + }; -},{"../logger":39}],21:[function(require,module,exports){ + var Selector = + /*#__PURE__*/ + function (_Node) { + _inherits(Selector, _Node); -var functionRegistry = require('./function-registry'), - Anonymous = require('../tree/anonymous'), - Keyword = require('../tree/keyword'); + function Selector(elements, extendList, condition, index, currentFileInfo, visibilityInfo) { + var _this; -functionRegistry.addMultiple({ - boolean: function(condition) { - return condition ? Keyword.True : Keyword.False; - }, + _classCallCheck(this, Selector); - 'if': function(condition, trueValue, falseValue) { - return condition ? trueValue - : (falseValue || new Anonymous); - } -}); + _this = _possibleConstructorReturn(this, _getPrototypeOf(Selector).call(this)); + _this.extendList = extendList; + _this.condition = condition; + _this.evaldCondition = !condition; + _this._index = index; + _this._fileInfo = currentFileInfo; + _this.elements = _this.getElements(elements); + _this.mixinElements_ = undefined; -},{"../tree/anonymous":50,"../tree/keyword":70,"./function-registry":27}],22:[function(require,module,exports){ -var Color = require('../tree/color'), - functionRegistry = require('./function-registry'); + _this.copyVisibilityInfo(visibilityInfo); -// Color Blending -// ref: http://www.w3.org/TR/compositing-1 + _this.setParent(_this.elements, _assertThisInitialized(_this)); -function colorBlend(mode, color1, color2) { - var ab = color1.alpha, cb, // backdrop - as = color2.alpha, cs, // source - ar, cr, r = []; // result + return _this; + } - ar = as + ab * (1 - as); - for (var i = 0; i < 3; i++) { - cb = color1.rgb[i] / 255; - cs = color2.rgb[i] / 255; - cr = mode(cb, cs); - if (ar) { - cr = (as * cs + ab * (cb - - as * (cb + cs - cr))) / ar; + _createClass(Selector, [{ + key: "accept", + value: function accept(visitor) { + if (this.elements) { + this.elements = visitor.visitArray(this.elements); } - r[i] = cr * 255; - } - return new Color(r, ar); -} + if (this.extendList) { + this.extendList = visitor.visitArray(this.extendList); + } -var colorBlendModeFunctions = { - multiply: function(cb, cs) { - return cb * cs; - }, - screen: function(cb, cs) { - return cb + cs - cb * cs; - }, - overlay: function(cb, cs) { - cb *= 2; - return (cb <= 1) ? - colorBlendModeFunctions.multiply(cb, cs) : - colorBlendModeFunctions.screen(cb - 1, cs); - }, - softlight: function(cb, cs) { - var d = 1, e = cb; - if (cs > 0.5) { - e = 1; - d = (cb > 0.25) ? Math.sqrt(cb) - : ((16 * cb - 12) * cb + 4) * cb; - } - return cb - (1 - 2 * cs) * e * (d - cb); - }, - hardlight: function(cb, cs) { - return colorBlendModeFunctions.overlay(cs, cb); - }, - difference: function(cb, cs) { - return Math.abs(cb - cs); - }, - exclusion: function(cb, cs) { - return cb + cs - 2 * cb * cs; - }, + if (this.condition) { + this.condition = visitor.visit(this.condition); + } + } + }, { + key: "createDerived", + value: function createDerived(elements, extendList, evaldCondition) { + elements = this.getElements(elements); + var newSelector = new Selector(elements, extendList || this.extendList, null, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + newSelector.evaldCondition = evaldCondition != null ? evaldCondition : this.evaldCondition; + newSelector.mediaEmpty = this.mediaEmpty; + return newSelector; + } + }, { + key: "getElements", + value: function getElements(els) { + if (!els) { + return [new Element('', '&', false, this._index, this._fileInfo)]; + } - // non-w3c functions: - average: function(cb, cs) { - return (cb + cs) / 2; - }, - negation: function(cb, cs) { - return 1 - Math.abs(cb + cs - 1); - } -}; + if (typeof els === 'string') { + this.parse.parseNode(els, ['selector'], this._index, this._fileInfo, function (err, result) { + if (err) { + throw new LessError({ + index: err.index, + message: err.message + }, this.parse.imports, this._fileInfo.filename); + } -for (var f in colorBlendModeFunctions) { - if (colorBlendModeFunctions.hasOwnProperty(f)) { - colorBlend[f] = colorBlend.bind(null, colorBlendModeFunctions[f]); - } -} + els = result[0].elements; + }); + } + + return els; + } + }, { + key: "createEmptySelectors", + value: function createEmptySelectors() { + var el = new Element('', '&', false, this._index, this._fileInfo); + var sels = [new Selector([el], null, null, this._index, this._fileInfo)]; + sels[0].mediaEmpty = true; + return sels; + } + }, { + key: "match", + value: function match(other) { + var elements = this.elements; + var len = elements.length; + var olen; + var i; + other = other.mixinElements(); + olen = other.length; + + if (olen === 0 || len < olen) { + return 0; + } else { + for (i = 0; i < olen; i++) { + if (elements[i].value !== other[i]) { + return 0; + } + } + } -functionRegistry.addMultiple(colorBlend); + return olen; // return number of matched elements + } + }, { + key: "mixinElements", + value: function mixinElements() { + if (this.mixinElements_) { + return this.mixinElements_; + } -},{"../tree/color":55,"./function-registry":27}],23:[function(require,module,exports){ -var Dimension = require('../tree/dimension'), - Color = require('../tree/color'), - Quoted = require('../tree/quoted'), - Anonymous = require('../tree/anonymous'), - functionRegistry = require('./function-registry'), - colorFunctions; + var elements = this.elements.map(function (v) { + return v.combinator.value + (v.value.value || v.value); + }).join('').match(/[,&#\*\.\w-]([\w-]|(\\.))*/g); -function clamp(val) { - return Math.min(1, Math.max(0, val)); -} -function hsla(origColor, hsl) { - var color = colorFunctions.hsla(hsl.h, hsl.s, hsl.l, hsl.a); - if (color) { - if (origColor.value && - /^(rgb|hsl)/.test(origColor.value)) { - color.value = origColor.value; + if (elements) { + if (elements[0] === '&') { + elements.shift(); + } } else { - color.value = 'rgb'; - } - return color; - } -} -function number(n) { - if (n instanceof Dimension) { - return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); - } else if (typeof n === 'number') { - return n; - } else { - throw { - type: 'Argument', - message: 'color functions take numbers as parameters' - }; - } -} -function scaled(n, size) { - if (n instanceof Dimension && n.unit.is('%')) { - return parseFloat(n.value * size / 100); - } else { - return number(n); - } -} -colorFunctions = { - rgb: function (r, g, b) { - var color = colorFunctions.rgba(r, g, b, 1.0); - if (color) { - color.value = 'rgb'; - return color; + elements = []; } - }, - rgba: function (r, g, b, a) { - try { - if (r instanceof Color) { - if (g) { - a = number(g); - } else { - a = r.alpha; - } - return new Color(r.rgb, a, 'rgba'); - } - var rgb = [r, g, b].map(function (c) { return scaled(c, 255); }); - a = number(a); - return new Color(rgb, a, 'rgba'); + + return this.mixinElements_ = elements; + } + }, { + key: "isJustParentSelector", + value: function isJustParentSelector() { + return !this.mediaEmpty && this.elements.length === 1 && this.elements[0].value === '&' && (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === ''); + } + }, { + key: "eval", + value: function _eval(context) { + var evaldCondition = this.condition && this.condition.eval(context); + var elements = this.elements; + var extendList = this.extendList; + elements = elements && elements.map(function (e) { + return e.eval(context); + }); + extendList = extendList && extendList.map(function (extend) { + return extend.eval(context); + }); + return this.createDerived(elements, extendList, evaldCondition); + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + var i; + var element; + + if ((!context || !context.firstSelector) && this.elements[0].combinator.value === '') { + output.add(' ', this.fileInfo(), this.getIndex()); } - catch (e) {} - }, - hsl: function (h, s, l) { - var color = colorFunctions.hsla(h, s, l, 1.0); - if (color) { - color.value = 'hsl'; - return color; + + for (i = 0; i < this.elements.length; i++) { + element = this.elements[i]; + element.genCSS(context, output); } - }, - hsla: function (h, s, l, a) { - try { - if (h instanceof Color) { - if (s) { - a = number(s); - } else { - a = h.alpha; - } - return new Color(h.rgb, a, 'hsla'); - } + } + }, { + key: "getIsOutput", + value: function getIsOutput() { + return this.evaldCondition; + } + }]); - var m1, m2; + return Selector; + }(Node); - function hue(h) { - h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); - if (h * 6 < 1) { - return m1 + (m2 - m1) * h * 6; - } - else if (h * 2 < 1) { - return m2; - } - else if (h * 3 < 2) { - return m1 + (m2 - m1) * (2 / 3 - h) * 6; - } - else { - return m1; - } - } + Selector.prototype.type = 'Selector'; - h = (number(h) % 360) / 360; - s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a)); + var Value = + /*#__PURE__*/ + function (_Node) { + _inherits(Value, _Node); - m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; - m1 = l * 2 - m2; + function Value(value) { + var _this; - var rgb = [ - hue(h + 1 / 3) * 255, - hue(h) * 255, - hue(h - 1 / 3) * 255 - ]; - a = number(a); - return new Color(rgb, a, 'hsla'); - } - catch (e) {} - }, + _classCallCheck(this, Value); - hsv: function(h, s, v) { - return colorFunctions.hsva(h, s, v, 1.0); - }, + _this = _possibleConstructorReturn(this, _getPrototypeOf(Value).call(this)); - hsva: function(h, s, v, a) { - h = ((number(h) % 360) / 360) * 360; - s = number(s); v = number(v); a = number(a); - - var i, f; - i = Math.floor((h / 60) % 6); - f = (h / 60) - i; - - var vs = [v, - v * (1 - s), - v * (1 - f * s), - v * (1 - (1 - f) * s)]; - var perm = [[0, 3, 1], - [2, 0, 1], - [1, 0, 3], - [1, 2, 0], - [3, 1, 0], - [0, 1, 2]]; - - return colorFunctions.rgba(vs[perm[i][0]] * 255, - vs[perm[i][1]] * 255, - vs[perm[i][2]] * 255, - a); - }, + if (!value) { + throw new Error('Value requires an array argument'); + } - hue: function (color) { - return new Dimension(color.toHSL().h); - }, - saturation: function (color) { - return new Dimension(color.toHSL().s * 100, '%'); - }, - lightness: function (color) { - return new Dimension(color.toHSL().l * 100, '%'); - }, - hsvhue: function(color) { - return new Dimension(color.toHSV().h); - }, - hsvsaturation: function (color) { - return new Dimension(color.toHSV().s * 100, '%'); - }, - hsvvalue: function (color) { - return new Dimension(color.toHSV().v * 100, '%'); - }, - red: function (color) { - return new Dimension(color.rgb[0]); - }, - green: function (color) { - return new Dimension(color.rgb[1]); - }, - blue: function (color) { - return new Dimension(color.rgb[2]); - }, - alpha: function (color) { - return new Dimension(color.toHSL().a); - }, - luma: function (color) { - return new Dimension(color.luma() * color.alpha * 100, '%'); - }, - luminance: function (color) { - var luminance = - (0.2126 * color.rgb[0] / 255) + - (0.7152 * color.rgb[1] / 255) + - (0.0722 * color.rgb[2] / 255); + if (!Array.isArray(value)) { + _this.value = [value]; + } else { + _this.value = value; + } - return new Dimension(luminance * color.alpha * 100, '%'); - }, - saturate: function (color, amount, method) { - // filter: saturate(3.2); - // should be kept as is, so check for color - if (!color.rgb) { - return null; - } - var hsl = color.toHSL(); + return _this; + } - if (typeof method !== 'undefined' && method.value === 'relative') { - hsl.s += hsl.s * amount.value / 100; + _createClass(Value, [{ + key: "accept", + value: function accept(visitor) { + if (this.value) { + this.value = visitor.visitArray(this.value); } - else { - hsl.s += amount.value / 100; + } + }, { + key: "eval", + value: function _eval(context) { + if (this.value.length === 1) { + return this.value[0].eval(context); + } else { + return new Value(this.value.map(function (v) { + return v.eval(context); + })); } - hsl.s = clamp(hsl.s); - return hsla(color, hsl); - }, - desaturate: function (color, amount, method) { - var hsl = color.toHSL(); + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + var i; - if (typeof method !== 'undefined' && method.value === 'relative') { - hsl.s -= hsl.s * amount.value / 100; - } - else { - hsl.s -= amount.value / 100; - } - hsl.s = clamp(hsl.s); - return hsla(color, hsl); - }, - lighten: function (color, amount, method) { - var hsl = color.toHSL(); + for (i = 0; i < this.value.length; i++) { + this.value[i].genCSS(context, output); - if (typeof method !== 'undefined' && method.value === 'relative') { - hsl.l += hsl.l * amount.value / 100; - } - else { - hsl.l += amount.value / 100; + if (i + 1 < this.value.length) { + output.add(context && context.compress ? ',' : ', '); + } } - hsl.l = clamp(hsl.l); - return hsla(color, hsl); - }, - darken: function (color, amount, method) { - var hsl = color.toHSL(); + } + }]); - if (typeof method !== 'undefined' && method.value === 'relative') { - hsl.l -= hsl.l * amount.value / 100; - } - else { - hsl.l -= amount.value / 100; - } - hsl.l = clamp(hsl.l); - return hsla(color, hsl); - }, - fadein: function (color, amount, method) { - var hsl = color.toHSL(); + return Value; + }(Node); - if (typeof method !== 'undefined' && method.value === 'relative') { - hsl.a += hsl.a * amount.value / 100; - } - else { - hsl.a += amount.value / 100; - } - hsl.a = clamp(hsl.a); - return hsla(color, hsl); - }, - fadeout: function (color, amount, method) { - var hsl = color.toHSL(); + Value.prototype.type = 'Value'; - if (typeof method !== 'undefined' && method.value === 'relative') { - hsl.a -= hsl.a * amount.value / 100; - } - else { - hsl.a -= amount.value / 100; - } - hsl.a = clamp(hsl.a); - return hsla(color, hsl); - }, - fade: function (color, amount) { - var hsl = color.toHSL(); + var Keyword = + /*#__PURE__*/ + function (_Node) { + _inherits(Keyword, _Node); - hsl.a = amount.value / 100; - hsl.a = clamp(hsl.a); - return hsla(color, hsl); - }, - spin: function (color, amount) { - var hsl = color.toHSL(); - var hue = (hsl.h + amount.value) % 360; + function Keyword(value) { + var _this; - hsl.h = hue < 0 ? 360 + hue : hue; + _classCallCheck(this, Keyword); - return hsla(color, hsl); - }, - // - // Copyright (c) 2006-2009 Hampton Catlin, Natalie Weizenbaum, and Chris Eppstein - // http://sass-lang.com - // - mix: function (color1, color2, weight) { - if (!color1.toHSL || !color2.toHSL) { - console.log(color2.type); - console.dir(color2); - } - if (!weight) { - weight = new Dimension(50); + _this = _possibleConstructorReturn(this, _getPrototypeOf(Keyword).call(this)); + _this.value = value; + return _this; + } + + _createClass(Keyword, [{ + key: "genCSS", + value: function genCSS(context, output) { + if (this.value === '%') { + throw { + type: 'Syntax', + message: 'Invalid % without number' + }; } - var p = weight.value / 100.0; - var w = p * 2 - 1; - var a = color1.toHSL().a - color2.toHSL().a; - var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; - var w2 = 1 - w1; + output.add(this.value); + } + }]); - var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, - color1.rgb[1] * w1 + color2.rgb[1] * w2, - color1.rgb[2] * w1 + color2.rgb[2] * w2]; + return Keyword; + }(Node); - var alpha = color1.alpha * p + color2.alpha * (1 - p); + Keyword.prototype.type = 'Keyword'; + Keyword.True = new Keyword('true'); + Keyword.False = new Keyword('false'); - return new Color(rgb, alpha); - }, - greyscale: function (color) { - return colorFunctions.desaturate(color, new Dimension(100)); - }, - contrast: function (color, dark, light, threshold) { - // filter: contrast(3.2); - // should be kept as is, so check for color - if (!color.rgb) { - return null; - } - if (typeof light === 'undefined') { - light = colorFunctions.rgba(255, 255, 255, 1.0); - } - if (typeof dark === 'undefined') { - dark = colorFunctions.rgba(0, 0, 0, 1.0); - } - // Figure out which is actually light and dark: - if (dark.luma() > light.luma()) { - var t = light; - light = dark; - dark = t; - } - if (typeof threshold === 'undefined') { - threshold = 0.43; - } else { - threshold = number(threshold); - } - if (color.luma() < threshold) { - return light; - } else { - return dark; - } - }, - // Changes made in 2.7.0 - Reverted in 3.0.0 - // contrast: function (color, color1, color2, threshold) { - // // Return which of `color1` and `color2` has the greatest contrast with `color` - // // according to the standard WCAG contrast ratio calculation. - // // http://www.w3.org/TR/WCAG20/#contrast-ratiodef - // // The threshold param is no longer used, in line with SASS. - // // filter: contrast(3.2); - // // should be kept as is, so check for color - // if (!color.rgb) { - // return null; - // } - // if (typeof color1 === 'undefined') { - // color1 = colorFunctions.rgba(0, 0, 0, 1.0); - // } - // if (typeof color2 === 'undefined') { - // color2 = colorFunctions.rgba(255, 255, 255, 1.0); - // } - // var contrast1, contrast2; - // var luma = color.luma(); - // var luma1 = color1.luma(); - // var luma2 = color2.luma(); - // // Calculate contrast ratios for each color - // if (luma > luma1) { - // contrast1 = (luma + 0.05) / (luma1 + 0.05); - // } else { - // contrast1 = (luma1 + 0.05) / (luma + 0.05); - // } - // if (luma > luma2) { - // contrast2 = (luma + 0.05) / (luma2 + 0.05); - // } else { - // contrast2 = (luma2 + 0.05) / (luma + 0.05); - // } - // if (contrast1 > contrast2) { - // return color1; - // } else { - // return color2; - // } - // }, - argb: function (color) { - return new Anonymous(color.toARGB()); - }, - color: function(c) { - if ((c instanceof Quoted) && - (/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})$/i.test(c.value))) { - var val = c.value.slice(1); - return new Color(val, undefined, '#' + val); - } - if ((c instanceof Color) || (c = Color.fromKeyword(c.value))) { - c.value = undefined; - return c; - } - throw { - type: 'Argument', - message: 'argument must be a color keyword or 3|4|6|8 digit hex e.g. #FFF' - }; - }, - tint: function(color, amount) { - return colorFunctions.mix(colorFunctions.rgb(255, 255, 255), color, amount); - }, - shade: function(color, amount) { - return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount); - } -}; -functionRegistry.addMultiple(colorFunctions); - -},{"../tree/anonymous":50,"../tree/color":55,"../tree/dimension":62,"../tree/quoted":80,"./function-registry":27}],24:[function(require,module,exports){ -module.exports = function(environment) { - var Quoted = require('../tree/quoted'), - URL = require('../tree/url'), - utils = require('../utils'), - functionRegistry = require('./function-registry'), - fallback = function(functionThis, node) { - return new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context); - }, - logger = require('../logger'); + var Anonymous = + /*#__PURE__*/ + function (_Node) { + _inherits(Anonymous, _Node); - functionRegistry.add('data-uri', function(mimetypeNode, filePathNode) { + function Anonymous(value, index, currentFileInfo, mapLines, rulesetLike, visibilityInfo) { + var _this; - if (!filePathNode) { - filePathNode = mimetypeNode; - mimetypeNode = null; - } + _classCallCheck(this, Anonymous); - var mimetype = mimetypeNode && mimetypeNode.value; - var filePath = filePathNode.value; - var currentFileInfo = this.currentFileInfo; - var currentDirectory = currentFileInfo.rewriteUrls ? - currentFileInfo.currentDirectory : currentFileInfo.entryPath; + _this = _possibleConstructorReturn(this, _getPrototypeOf(Anonymous).call(this)); + _this.value = value; + _this._index = index; + _this._fileInfo = currentFileInfo; + _this.mapLines = mapLines; + _this.rulesetLike = typeof rulesetLike === 'undefined' ? false : rulesetLike; + _this.allowRoot = true; - var fragmentStart = filePath.indexOf('#'); - var fragment = ''; - if (fragmentStart !== -1) { - fragment = filePath.slice(fragmentStart); - filePath = filePath.slice(0, fragmentStart); - } - var context = utils.clone(this.context); - context.rawBuffer = true; + _this.copyVisibilityInfo(visibilityInfo); - var fileManager = environment.getFileManager(filePath, currentDirectory, context, environment, true); + return _this; + } - if (!fileManager) { - return fallback(this, filePathNode); + _createClass(Anonymous, [{ + key: "eval", + value: function _eval() { + return new Anonymous(this.value, this._index, this._fileInfo, this.mapLines, this.rulesetLike, this.visibilityInfo()); + } + }, { + key: "compare", + value: function compare(other) { + return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; + } + }, { + key: "isRulesetLike", + value: function isRulesetLike() { + return this.rulesetLike; + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + this.nodeVisible = Boolean(this.value); + + if (this.nodeVisible) { + output.add(this.value, this._fileInfo, this._index, this.mapLines); } + } + }]); - var useBase64 = false; + return Anonymous; + }(Node); - // detect the mimetype if not given - if (!mimetypeNode) { + Anonymous.prototype.type = 'Anonymous'; - mimetype = environment.mimeLookup(filePath); + var MATH = Math$1; - if (mimetype === 'image/svg+xml') { - useBase64 = false; - } else { - // use base 64 unless it's an ASCII or UTF-8 format - var charset = environment.charsetLookup(mimetype); - useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; - } - if (useBase64) { mimetype += ';base64'; } - } - else { - useBase64 = /;base64$/.test(mimetype); - } + var Declaration = + /*#__PURE__*/ + function (_Node) { + _inherits(Declaration, _Node); - var fileSync = fileManager.loadFileSync(filePath, currentDirectory, context, environment); - if (!fileSync.contents) { - logger.warn('Skipped data-uri embedding of ' + filePath + ' because file not found'); - return fallback(this, filePathNode || mimetypeNode); - } - var buf = fileSync.contents; - if (useBase64 && !environment.encodeBase64) { - return fallback(this, filePathNode); - } + function Declaration(name, value, important, merge, index, currentFileInfo, inline, variable) { + var _this; - buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf); + _classCallCheck(this, Declaration); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(Declaration).call(this)); + _this.name = name; + _this.value = value instanceof Node ? value : new Value([value ? new Anonymous(value) : null]); + _this.important = important ? " ".concat(important.trim()) : ''; + _this.merge = merge; + _this._index = index; + _this._fileInfo = currentFileInfo; + _this.inline = inline || false; + _this.variable = variable !== undefined ? variable : name.charAt && name.charAt(0) === '@'; + _this.allowRoot = true; - var uri = 'data:' + mimetype + ',' + buf + fragment; + _this.setParent(_this.value, _assertThisInitialized(_this)); - // IE8 cannot handle a data-uri larger than 32,768 characters. If this is exceeded - // and the --ieCompat flag is enabled, return a normal url() instead. - var DATA_URI_MAX = 32768; - if (uri.length >= DATA_URI_MAX) { + return _this; + } - if (this.context.ieCompat !== false) { - logger.warn('Skipped data-uri embedding of ' + filePath + ' because its size (' + uri.length + - ' characters) exceeds IE8-safe ' + DATA_URI_MAX + ' characters!'); + _createClass(Declaration, [{ + key: "genCSS", + value: function genCSS(context, output) { + output.add(this.name + (context.compress ? ':' : ': '), this.fileInfo(), this.getIndex()); - return fallback(this, filePathNode || mimetypeNode); - } + try { + this.value.genCSS(context, output); + } catch (e) { + e.index = this._index; + e.filename = this._fileInfo.filename; + throw e; } - return new URL(new Quoted('"' + uri + '"', uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); - }); -}; + output.add(this.important + (this.inline || context.lastRule && context.compress ? '' : ';'), this._fileInfo, this._index); + } + }, { + key: "eval", + value: function _eval(context) { + var mathBypass = false; + var prevMath; + var name = this.name; + var evaldValue; + var variable = this.variable; -},{"../logger":39,"../tree/quoted":80,"../tree/url":85,"../utils":89,"./function-registry":27}],25:[function(require,module,exports){ -var Keyword = require('../tree/keyword'), - functionRegistry = require('./function-registry'); + if (typeof name !== 'string') { + // expand 'primitive' name directly to get + // things faster (~10% for benchmark.less): + name = name.length === 1 && name[0] instanceof Keyword ? name[0].value : evalName(context, name); + variable = false; // never treat expanded interpolation as new variable name + } // @todo remove when parens-division is default -var defaultFunc = { - eval: function () { - var v = this.value_, e = this.error_; - if (e) { - throw e; - } - if (v != null) { - return v ? Keyword.True : Keyword.False; + + if (name === 'font' && context.math === MATH.ALWAYS) { + mathBypass = true; + prevMath = context.math; + context.math = MATH.PARENS_DIVISION; } - }, - value: function (v) { - this.value_ = v; - }, - error: function (e) { - this.error_ = e; - }, - reset: function () { - this.value_ = this.error_ = null; - } -}; -functionRegistry.add('default', defaultFunc.eval.bind(defaultFunc)); + try { + context.importantScope.push({}); + evaldValue = this.value.eval(context); + + if (!this.variable && evaldValue.type === 'DetachedRuleset') { + throw { + message: 'Rulesets cannot be evaluated on a property.', + index: this.getIndex(), + filename: this.fileInfo().filename + }; + } + + var important = this.important; + var importantResult = context.importantScope.pop(); -module.exports = defaultFunc; + if (!important && importantResult.important) { + important = importantResult.important; + } -},{"../tree/keyword":70,"./function-registry":27}],26:[function(require,module,exports){ -var Expression = require('../tree/expression'); + return new Declaration(name, evaldValue, important, this.merge, this.getIndex(), this.fileInfo(), this.inline, variable); + } catch (e) { + if (typeof e.index !== 'number') { + e.index = this.getIndex(); + e.filename = this.fileInfo().filename; + } -var functionCaller = function(name, context, index, currentFileInfo) { - this.name = name.toLowerCase(); - this.index = index; - this.context = context; - this.currentFileInfo = currentFileInfo; + throw e; + } finally { + if (mathBypass) { + context.math = prevMath; + } + } + } + }, { + key: "makeImportant", + value: function makeImportant() { + return new Declaration(this.name, this.value, '!important', this.merge, this.getIndex(), this.fileInfo(), this.inline); + } + }]); - this.func = context.frames[0].functionRegistry.get(this.name); -}; -functionCaller.prototype.isValid = function() { - return Boolean(this.func); -}; + return Declaration; + }(Node); -functionCaller.prototype.call = function(args) { - // This code is terrible and should be replaced as per this issue... - // https://github.com/less/less.js/issues/2477 - if (Array.isArray(args)) { - args = args.filter(function (item) { - if (item.type === 'Comment') { - return false; - } - return true; - }) - .map(function(item) { - if (item.type === 'Expression') { - var subNodes = item.value.filter(function (item) { - if (item.type === 'Comment') { - return false; - } - return true; - }); - if (subNodes.length === 1) { - return subNodes[0]; - } else { - return new Expression(subNodes); - } - } - return item; - }); + function evalName(context, name) { + var value = ''; + var i; + var n = name.length; + var output = { + add: function add(s) { + value += s; + } + }; + + for (i = 0; i < n; i++) { + name[i].eval(context).genCSS(context, output); } - return this.func.apply(this, args); -}; + return value; + } -module.exports = functionCaller; + Declaration.prototype.type = 'Declaration'; -},{"../tree/expression":64}],27:[function(require,module,exports){ -function makeRegistry( base ) { - return { - _data: {}, - add: function(name, func) { - // precautionary case conversion, as later querying of - // the registry by function-caller uses lower case as well. - name = name.toLowerCase(); + var debugInfo = function debugInfo(context, ctx, lineSeparator) { + var result = ''; - if (this._data.hasOwnProperty(name)) { - // TODO warn - } - this._data[name] = func; - }, - addMultiple: function(functions) { - Object.keys(functions).forEach( - function(name) { - this.add(name, functions[name]); - }.bind(this)); - }, - get: function(name) { - return this._data[name] || ( base && base.get( name )); - }, - getLocalFunctions: function() { - return this._data; - }, - inherit: function() { - return makeRegistry( this ); - }, - create: function(base) { - return makeRegistry(base); - } - }; -} + if (context.dumpLineNumbers && !context.compress) { + switch (context.dumpLineNumbers) { + case 'comments': + result = debugInfo.asComment(ctx); + break; -module.exports = makeRegistry( null ); -},{}],28:[function(require,module,exports){ -module.exports = function(environment) { - var functions = { - functionRegistry: require('./function-registry'), - functionCaller: require('./function-caller') - }; + case 'mediaquery': + result = debugInfo.asMediaQuery(ctx); + break; - // register functions - require('./boolean'); - require('./default'); - require('./color'); - require('./color-blending'); - require('./data-uri')(environment); - require('./list'); - require('./math'); - require('./number'); - require('./string'); - require('./svg')(environment); - require('./types'); + case 'all': + result = debugInfo.asComment(ctx) + (lineSeparator || '') + debugInfo.asMediaQuery(ctx); + break; + } + } - return functions; -}; - -},{"./boolean":21,"./color":23,"./color-blending":22,"./data-uri":24,"./default":25,"./function-caller":26,"./function-registry":27,"./list":29,"./math":31,"./number":32,"./string":33,"./svg":34,"./types":35}],29:[function(require,module,exports){ -var Comment = require('../tree/comment'), - Dimension = require('../tree/dimension'), - Declaration = require('../tree/declaration'), - Expression = require('../tree/expression'), - Ruleset = require('../tree/ruleset'), - Selector = require('../tree/selector'), - Element = require('../tree/element'), - functionRegistry = require('./function-registry'); - -var getItemsFromNode = function(node) { - // handle non-array values as an array of length 1 - // return 'undefined' if index is invalid - var items = Array.isArray(node.value) ? - node.value : Array(node); + return result; + }; - return items; -}; + debugInfo.asComment = function (ctx) { + return "/* line ".concat(ctx.debugInfo.lineNumber, ", ").concat(ctx.debugInfo.fileName, " */\n"); + }; -functionRegistry.addMultiple({ - _SELF: function(n) { - return n; - }, - extract: function(values, index) { - index = index.value - 1; // (1-based index) + debugInfo.asMediaQuery = function (ctx) { + var filenameWithProtocol = ctx.debugInfo.fileName; - return getItemsFromNode(values)[index]; - }, - length: function(values) { - return new Dimension(getItemsFromNode(values).length); - }, - /** - * Creates a Less list of incremental values. - * Modeled after Lodash's range function, also exists natively in PHP - * - * @param {Dimension} [start=1] - * @param {Dimension} end - e.g. 10 or 10px - unit is added to output - * @param {Dimension} [step=1] - */ - range: function(start, end, step) { - var from, to, stepValue = 1, list = []; - if (end) { - to = end; - from = start.value; - if (step) { - stepValue = step.value; - } - } - else { - from = 1; - to = start; - } + if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) { + filenameWithProtocol = "file://".concat(filenameWithProtocol); + } - for (var i = from; i <= to.value; i += stepValue) { - list.push(new Dimension(i, to.unit)); - } + return "@media -sass-debug-info{filename{font-family:".concat(filenameWithProtocol.replace(/([.:\/\\])/g, function (a) { + if (a == '\\') { + a = '\/'; + } - return new Expression(list); - }, - each: function(list, rs) { - var rules = [], newRules, iterator; + return "\\".concat(a); + }), "}line{font-family:\\00003").concat(ctx.debugInfo.lineNumber, "}}\n"); + }; - if (list.value) { - if (Array.isArray(list.value)) { - iterator = list.value; - } else { - iterator = [list.value]; - } - } else if (list.ruleset) { - iterator = list.ruleset.rules; - } else if (list.rules) { - iterator = list.rules; - } else if (Array.isArray(list)) { - iterator = list; - } else { - iterator = [list]; - } + var Comment = + /*#__PURE__*/ + function (_Node) { + _inherits(Comment, _Node); - var valueName = '@value', - keyName = '@key', - indexName = '@index'; + function Comment(value, isLineComment, index, currentFileInfo) { + var _this; - if (rs.params) { - valueName = rs.params[0] && rs.params[0].name; - keyName = rs.params[1] && rs.params[1].name; - indexName = rs.params[2] && rs.params[2].name; - rs = rs.rules; - } else { - rs = rs.ruleset; - } + _classCallCheck(this, Comment); - for (var i = 0; i < iterator.length; i++) { - var key, value, item = iterator[i]; - if (item instanceof Declaration) { - key = typeof item.name === 'string' ? item.name : item.name[0].value; - value = item.value; - } else { - key = new Dimension(i + 1); - value = item; - } - - if (item instanceof Comment) { - continue; - } + _this = _possibleConstructorReturn(this, _getPrototypeOf(Comment).call(this)); + _this.value = value; + _this.isLineComment = isLineComment; + _this._index = index; + _this._fileInfo = currentFileInfo; + _this.allowRoot = true; + return _this; + } - newRules = rs.rules.slice(0); - if (valueName) { - newRules.push(new Declaration(valueName, - value, - false, false, this.index, this.currentFileInfo)); - } - if (indexName) { - newRules.push(new Declaration(indexName, - new Dimension(i + 1), - false, false, this.index, this.currentFileInfo)); - } - if (keyName) { - newRules.push(new Declaration(keyName, - key, - false, false, this.index, this.currentFileInfo)); - } - - rules.push(new Ruleset([ new(Selector)([ new Element("", '&') ]) ], - newRules, - rs.strictImports, - rs.visibilityInfo() - )); + _createClass(Comment, [{ + key: "genCSS", + value: function genCSS(context, output) { + if (this.debugInfo) { + output.add(debugInfo(context, this), this.fileInfo(), this.getIndex()); } - return new Ruleset([ new(Selector)([ new Element("", '&') ]) ], - rules, - rs.strictImports, - rs.visibilityInfo() - ).eval(this.context); + output.add(this.value); + } + }, { + key: "isSilent", + value: function isSilent(context) { + var isCompressed = context.compress && this.value[2] !== '!'; + return this.isLineComment || isCompressed; + } + }]); + + return Comment; + }(Node); - } -}); + Comment.prototype.type = 'Comment'; -},{"../tree/comment":57,"../tree/declaration":60,"../tree/dimension":62,"../tree/element":63,"../tree/expression":64,"../tree/ruleset":81,"../tree/selector":82,"./function-registry":27}],30:[function(require,module,exports){ -var Dimension = require('../tree/dimension'); + var contexts = {}; -var MathHelper = function() { -}; -MathHelper._math = function (fn, unit, n) { - if (!(n instanceof Dimension)) { - throw { type: 'Argument', message: 'argument must be a number' }; + var copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) { + if (!original) { + return; } - if (unit == null) { - unit = n.unit; - } else { - n = n.unify(); + + for (var i = 0; i < propertiesToCopy.length; i++) { + if (original.hasOwnProperty(propertiesToCopy[i])) { + destination[propertiesToCopy[i]] = original[propertiesToCopy[i]]; + } } - return new Dimension(fn(parseFloat(n.value)), unit); -}; -module.exports = MathHelper; -},{"../tree/dimension":62}],31:[function(require,module,exports){ -var functionRegistry = require('./function-registry'), - mathHelper = require('./math-helper.js'); + }; + /* + parse is used whilst parsing + */ + + + var parseCopyProperties = [// options + 'paths', // option - unmodified - paths to search for imports on + 'rewriteUrls', // option - whether to adjust URL's to be relative + 'rootpath', // option - rootpath to append to URL's + 'strictImports', // option - + 'insecure', // option - whether to allow imports from insecure ssl hosts + 'dumpLineNumbers', // option - whether to dump line numbers + 'compress', // option - whether to compress + 'syncImport', // option - whether to import synchronously + 'chunkInput', // option - whether to chunk input. more performant but causes parse issues. + 'mime', // browser only - mime type for sheet import + 'useFileCache', // browser only - whether to use the per file session cache + // context + 'processImports', // option & context - whether to process imports. if false then imports will not be imported. + // Used by the import manager to stop multiple import visitors being created. + 'pluginManager' // Used as the plugin manager for the session + ]; + + contexts.Parse = function (options) { + copyFromOriginal(options, this, parseCopyProperties); -var mathFunctions = { - // name, unit - ceil: null, - floor: null, - sqrt: null, - abs: null, - tan: '', - sin: '', - cos: '', - atan: 'rad', - asin: 'rad', - acos: 'rad' -}; - -for (var f in mathFunctions) { - if (mathFunctions.hasOwnProperty(f)) { - mathFunctions[f] = mathHelper._math.bind(null, Math[f], mathFunctions[f]); - } -} - -mathFunctions.round = function (n, f) { - var fraction = typeof f === 'undefined' ? 0 : f.value; - return mathHelper._math(function(num) { return num.toFixed(fraction); }, null, n); -}; + if (typeof this.paths === 'string') { + this.paths = [this.paths]; + } + }; + + var evalCopyProperties = ['paths', // additional include paths + 'compress', // whether to compress + '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 + 'urlArgs', // whether to add args into url tokens + 'javascriptEnabled', // option - whether Inline JavaScript is enabled. if undefined, defaults to false + 'pluginManager', // Used as the plugin manager for the session + 'importantScope', // used to bubble up !important statements + 'rewriteUrls' // option - whether to adjust URL's to be relative + ]; + + function isPathRelative(path) { + return !/^(?:[a-z-]+:|\/|#)/i.test(path); + } -functionRegistry.addMultiple(mathFunctions); + function isPathLocalRelative(path) { + return path.charAt(0) === '.'; + } -},{"./function-registry":27,"./math-helper.js":30}],32:[function(require,module,exports){ -var Dimension = require('../tree/dimension'), - Anonymous = require('../tree/anonymous'), - functionRegistry = require('./function-registry'), - mathHelper = require('./math-helper.js'); + contexts.Eval = + /*#__PURE__*/ + function () { + function _class(options, frames) { + _classCallCheck(this, _class); -var minMax = function (isMin, args) { - args = Array.prototype.slice.call(args); - switch (args.length) { - case 0: throw { type: 'Argument', message: 'one or more arguments required' }; + copyFromOriginal(options, this, evalCopyProperties); + + if (typeof this.paths === 'string') { + this.paths = [this.paths]; + } + + this.frames = frames || []; + this.importantScope = this.importantScope || []; + this.inCalc = false; + this.mathOn = true; } - var i, j, current, currentUnified, referenceUnified, unit, unitStatic, unitClone, - order = [], // elems only contains original argument values. - values = {}; // key is the unit.toString() for unified Dimension values, - // value is the index into the order array. - for (i = 0; i < args.length; i++) { - current = args[i]; - if (!(current instanceof Dimension)) { - if (Array.isArray(args[i].value)) { - Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value)); - } - continue; - } - currentUnified = current.unit.toString() === '' && unitClone !== undefined ? new Dimension(current.value, unitClone).unify() : current.unify(); - unit = currentUnified.unit.toString() === '' && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString(); - unitStatic = unit !== '' && unitStatic === undefined || unit !== '' && order[0].unify().unit.toString() === '' ? unit : unitStatic; - unitClone = unit !== '' && unitClone === undefined ? current.unit.toString() : unitClone; - j = values[''] !== undefined && unit !== '' && unit === unitStatic ? values[''] : values[unit]; - if (j === undefined) { - if (unitStatic !== undefined && unit !== unitStatic) { - throw { type: 'Argument', message: 'incompatible types' }; - } - values[unit] = order.length; - order.push(current); - continue; + + _createClass(_class, [{ + key: "enterCalc", + value: function enterCalc() { + if (!this.calcStack) { + this.calcStack = []; } - referenceUnified = order[j].unit.toString() === '' && unitClone !== undefined ? new Dimension(order[j].value, unitClone).unify() : order[j].unify(); - if ( isMin && currentUnified.value < referenceUnified.value || - !isMin && currentUnified.value > referenceUnified.value) { - order[j] = current; + + this.calcStack.push(true); + this.inCalc = true; + } + }, { + key: "exitCalc", + value: function exitCalc() { + this.calcStack.pop(); + + if (!this.calcStack) { + this.inCalc = false; } - } - if (order.length == 1) { - return order[0]; - } - args = order.map(function (a) { return a.toCSS(this.context); }).join(this.context.compress ? ',' : ', '); - return new Anonymous((isMin ? 'min' : 'max') + '(' + args + ')'); -}; -functionRegistry.addMultiple({ - min: function () { - return minMax(true, arguments); - }, - max: function () { - return minMax(false, arguments); - }, - convert: function (val, unit) { - return val.convertTo(unit.value); - }, - pi: function () { - return new Dimension(Math.PI); - }, - mod: function(a, b) { - return new Dimension(a.value % b.value, a.unit); - }, - pow: function(x, y) { - if (typeof x === 'number' && typeof y === 'number') { - x = new Dimension(x); - y = new Dimension(y); - } else if (!(x instanceof Dimension) || !(y instanceof Dimension)) { - throw { type: 'Argument', message: 'arguments must be numbers' }; + } + }, { + key: "inParenthesis", + value: function inParenthesis() { + if (!this.parensStack) { + this.parensStack = []; } - return new Dimension(Math.pow(x.value, y.value), x.unit); - }, - percentage: function (n) { - var result = mathHelper._math(function(num) { - return num * 100; - }, '%', n); + this.parensStack.push(true); + } + }, { + key: "outOfParenthesis", + value: function outOfParenthesis() { + this.parensStack.pop(); + } + }, { + key: "isMathOn", + value: function isMathOn(op) { + if (!this.mathOn) { + return false; + } - return result; - } -}); + if (op === '/' && this.math !== Math$1.ALWAYS && (!this.parensStack || !this.parensStack.length)) { + return false; + } -},{"../tree/anonymous":50,"../tree/dimension":62,"./function-registry":27,"./math-helper.js":30}],33:[function(require,module,exports){ -var Quoted = require('../tree/quoted'), - Anonymous = require('../tree/anonymous'), - JavaScript = require('../tree/javascript'), - functionRegistry = require('./function-registry'); + if (this.math > Math$1.PARENS_DIVISION) { + return this.parensStack && this.parensStack.length; + } -functionRegistry.addMultiple({ - e: function (str) { - return new Anonymous(str instanceof JavaScript ? str.evaluated : str.value); - }, - escape: function (str) { - return new Anonymous( - encodeURI(str.value).replace(/=/g, '%3D').replace(/:/g, '%3A').replace(/#/g, '%23').replace(/;/g, '%3B') - .replace(/\(/g, '%28').replace(/\)/g, '%29')); - }, - replace: function (string, pattern, replacement, flags) { - var result = string.value; - replacement = (replacement.type === 'Quoted') ? - replacement.value : replacement.toCSS(); - result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement); - return new Quoted(string.quote || '', result, string.escaped); - }, - '%': function (string /* arg, arg, ... */) { - var args = Array.prototype.slice.call(arguments, 1), - result = string.value; + return true; + } + }, { + key: "pathRequiresRewrite", + value: function pathRequiresRewrite(path) { + var isRelative = this.rewriteUrls === RewriteUrls.LOCAL ? isPathLocalRelative : isPathRelative; + return isRelative(path); + } + }, { + key: "rewritePath", + value: function rewritePath(path, rootpath) { + var newPath; + rootpath = rootpath || ''; + newPath = this.normalizePath(rootpath + path); // If a path was explicit relative and the rootpath was not an absolute path + // we must ensure that the new path is also explicit relative. - for (var i = 0; i < args.length; i++) { - /* jshint loopfunc:true */ - result = result.replace(/%[sda]/i, function(token) { - var value = ((args[i].type === 'Quoted') && - token.match(/s/i)) ? args[i].value : args[i].toCSS(); - return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; - }); + if (isPathLocalRelative(path) && isPathRelative(rootpath) && isPathLocalRelative(newPath) === false) { + newPath = "./".concat(newPath); } - result = result.replace(/%%/g, '%'); - return new Quoted(string.quote || '', result, string.escaped); - } -}); -},{"../tree/anonymous":50,"../tree/javascript":68,"../tree/quoted":80,"./function-registry":27}],34:[function(require,module,exports){ -module.exports = function(environment) { - var Dimension = require('../tree/dimension'), - Color = require('../tree/color'), - Expression = require('../tree/expression'), - Quoted = require('../tree/quoted'), - URL = require('../tree/url'), - functionRegistry = require('./function-registry'); + return newPath; + } + }, { + key: "normalizePath", + value: function normalizePath(path) { + var segments = path.split('/').reverse(); + var segment; + path = []; - functionRegistry.add('svg-gradient', function(direction) { + while (segments.length !== 0) { + segment = segments.pop(); - var stops, - gradientDirectionSvg, - gradientType = 'linear', - rectangleDimension = 'x="0" y="0" width="1" height="1"', - renderEnv = {compress: false}, - returner, - directionValue = direction.toCSS(renderEnv), - i, color, position, positionValue, alpha; + switch (segment) { + case '.': + break; - function throwArgumentDescriptor() { - throw { type: 'Argument', - message: 'svg-gradient expects direction, start_color [start_position], [color position,]...,' + - ' end_color [end_position] or direction, color list' }; - } + case '..': + if (path.length === 0 || path[path.length - 1] === '..') { + path.push(segment); + } else { + path.pop(); + } - if (arguments.length == 2) { - if (arguments[1].value.length < 2) { - throwArgumentDescriptor(); - } - stops = arguments[1].value; - } else if (arguments.length < 3) { - throwArgumentDescriptor(); - } else { - stops = Array.prototype.slice.call(arguments, 1); - } + break; - switch (directionValue) { - case 'to bottom': - gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"'; - break; - case 'to right': - gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"'; - break; - case 'to bottom right': - gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"'; - break; - case 'to top right': - gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"'; - break; - case 'ellipse': - case 'ellipse at center': - gradientType = 'radial'; - gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"'; - rectangleDimension = 'x="-50" y="-50" width="101" height="101"'; - break; default: - throw { type: 'Argument', message: 'svg-gradient direction must be \'to bottom\', \'to right\',' + - ' \'to bottom right\', \'to top right\' or \'ellipse at center\'' }; + path.push(segment); + break; + } } - returner = '' + - '<' + gradientType + 'Gradient id="g" ' + gradientDirectionSvg + '>'; - for (i = 0; i < stops.length; i += 1) { - if (stops[i] instanceof Expression) { - color = stops[i].value[0]; - position = stops[i].value[1]; - } else { - color = stops[i]; - position = undefined; - } + return path.join('/'); + } + }]); - if (!(color instanceof Color) || (!((i === 0 || i + 1 === stops.length) && position === undefined) && !(position instanceof Dimension))) { - throwArgumentDescriptor(); - } - positionValue = position ? position.toCSS(renderEnv) : i === 0 ? '0%' : '100%'; - alpha = color.alpha; - returner += ''; - } - returner += '' + - ''; + return _class; + }(); - returner = encodeURIComponent(returner); + function makeRegistry(base) { + return { + _data: {}, + add: function add(name, func) { + // precautionary case conversion, as later querying of + // the registry by function-caller uses lower case as well. + name = name.toLowerCase(); - returner = 'data:image/svg+xml,' + returner; - return new URL(new Quoted('\'' + returner + '\'', returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); - }); -}; - -},{"../tree/color":55,"../tree/dimension":62,"../tree/expression":64,"../tree/quoted":80,"../tree/url":85,"./function-registry":27}],35:[function(require,module,exports){ -var Keyword = require('../tree/keyword'), - DetachedRuleset = require('../tree/detached-ruleset'), - Dimension = require('../tree/dimension'), - Color = require('../tree/color'), - Quoted = require('../tree/quoted'), - Anonymous = require('../tree/anonymous'), - URL = require('../tree/url'), - Operation = require('../tree/operation'), - functionRegistry = require('./function-registry'); - -var isa = function (n, Type) { - return (n instanceof Type) ? Keyword.True : Keyword.False; - }, - isunit = function (n, unit) { - if (unit === undefined) { - throw { type: 'Argument', message: 'missing the required second argument to isunit.' }; - } - unit = typeof unit.value === 'string' ? unit.value : unit; - if (typeof unit !== 'string') { - throw { type: 'Argument', message: 'Second argument to isunit should be a unit or a string.' }; - } - return (n instanceof Dimension) && n.unit.is(unit) ? Keyword.True : Keyword.False; + if (this._data.hasOwnProperty(name)) ; + + this._data[name] = func; + }, + addMultiple: function addMultiple(functions) { + var _this = this; + + Object.keys(functions).forEach(function (name) { + _this.add(name, functions[name]); + }); + }, + get: function get(name) { + return this._data[name] || base && base.get(name); + }, + getLocalFunctions: function getLocalFunctions() { + return this._data; + }, + inherit: function inherit() { + return makeRegistry(this); + }, + create: function create(base) { + return makeRegistry(base); + } }; + } -functionRegistry.addMultiple({ - isruleset: function (n) { - return isa(n, DetachedRuleset); - }, - iscolor: function (n) { - return isa(n, Color); - }, - isnumber: function (n) { - return isa(n, Dimension); - }, - isstring: function (n) { - return isa(n, Quoted); - }, - iskeyword: function (n) { - return isa(n, Keyword); - }, - isurl: function (n) { - return isa(n, URL); - }, - ispixel: function (n) { - return isunit(n, 'px'); - }, - ispercentage: function (n) { - return isunit(n, '%'); + var functionRegistry = makeRegistry(null); + + var defaultFunc = { + eval: function _eval() { + var v = this.value_; + var e = this.error_; + + if (e) { + throw e; + } + + if (v != null) { + return v ? Keyword.True : Keyword.False; + } }, - isem: function (n) { - return isunit(n, 'em'); + value: function value(v) { + this.value_ = v; }, - isunit: isunit, - unit: function (val, unit) { - if (!(val instanceof Dimension)) { - throw { type: 'Argument', - message: 'the first argument to unit must be a number' + - (val instanceof Operation ? '. Have you forgotten parenthesis?' : '') }; - } - if (unit) { - if (unit instanceof Keyword) { - unit = unit.value; - } else { - unit = unit.toCSS(); - } - } else { - unit = ''; - } - return new Dimension(val.value, unit); + error: function error(e) { + this.error_ = e; }, - 'get-unit': function (n) { - return new Anonymous(n.unit); + reset: function reset() { + this.value_ = this.error_ = null; } -}); - -},{"../tree/anonymous":50,"../tree/color":55,"../tree/detached-ruleset":61,"../tree/dimension":62,"../tree/keyword":70,"../tree/operation":77,"../tree/quoted":80,"../tree/url":85,"./function-registry":27}],36:[function(require,module,exports){ -var contexts = require('./contexts'), - Parser = require('./parser/parser'), - LessError = require('./less-error'), - utils = require('./utils'), - PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise, - logger = require('./logger'); + }; -module.exports = function(environment) { + var Ruleset = + /*#__PURE__*/ + function (_Node) { + _inherits(Ruleset, _Node); - // FileInfo = { - // 'rewriteUrls' - option - whether to adjust URL's to be relative - // 'filename' - full resolved filename of current file - // 'rootpath' - path to append to normal URLs for this node - // 'currentDirectory' - path to the current file, absolute - // 'rootFilename' - filename of the base file - // 'entryPath' - absolute path to the entry file - // 'reference' - whether the file should not be output and only output parts that are referenced + function Ruleset(selectors, rules, strictImports, visibilityInfo) { + var _this; - var ImportManager = function(less, context, rootFileInfo) { - this.less = less; - this.rootFilename = rootFileInfo.filename; - this.paths = context.paths || []; // Search paths, when importing - this.contents = {}; // map - filename to contents of all the files - this.contentsIgnoredChars = {}; // map - filename to lines at the beginning of each file to ignore - this.mime = context.mime; - this.error = null; - this.context = context; - // Deprecated? Unused outside of here, could be useful. - this.queue = []; // Files which haven't been imported yet - this.files = {}; // Holds the imported parse trees. - }; + _classCallCheck(this, Ruleset); - /** - * Add an import to be imported - * @param path - the raw path - * @param tryAppendExtension - whether to try appending a file extension (.less or .js if the path has no extension) - * @param currentFileInfo - the current file info (used for instance to work out relative paths) - * @param importOptions - import options - * @param callback - callback for when it is imported - */ - ImportManager.prototype.push = function (path, tryAppendExtension, currentFileInfo, importOptions, callback) { - var importManager = this, - pluginLoader = this.context.pluginManager.Loader; + _this = _possibleConstructorReturn(this, _getPrototypeOf(Ruleset).call(this)); + _this.selectors = selectors; + _this.rules = rules; + _this._lookups = {}; + _this._variables = null; + _this._properties = null; + _this.strictImports = strictImports; - this.queue.push(path); + _this.copyVisibilityInfo(visibilityInfo); - var fileParsedFunc = function (e, root, fullPath) { - importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue + _this.allowRoot = true; - var importedEqualsRoot = fullPath === importManager.rootFilename; - if (importOptions.optional && e) { - callback(null, {rules:[]}, false, null); - logger.info('The file ' + fullPath + ' was skipped because it was not found and the import was marked optional.'); - } - else { - // Inline imports aren't cached here. - // If we start to cache them, please make sure they won't conflict with non-inline imports of the - // same name as they used to do before this comment and the condition below have been added. - if (!importManager.files[fullPath] && !importOptions.inline) { - importManager.files[fullPath] = { root: root, options: importOptions }; - } - if (e && !importManager.error) { importManager.error = e; } - callback(e, root, importedEqualsRoot, fullPath); - } - }; + _this.setParent(_this.selectors, _assertThisInitialized(_this)); - var newFileInfo = { - rewriteUrls: this.context.rewriteUrls, - entryPath: currentFileInfo.entryPath, - rootpath: currentFileInfo.rootpath, - rootFilename: currentFileInfo.rootFilename - }; + _this.setParent(_this.rules, _assertThisInitialized(_this)); - var fileManager = environment.getFileManager(path, currentFileInfo.currentDirectory, this.context, environment); + return _this; + } - if (!fileManager) { - fileParsedFunc({ message: 'Could not find a file-manager for ' + path }); - return; + _createClass(Ruleset, [{ + key: "isRulesetLike", + value: function isRulesetLike() { + return true; + } + }, { + key: "accept", + value: function accept(visitor) { + if (this.paths) { + this.paths = visitor.visitArray(this.paths, true); + } else if (this.selectors) { + this.selectors = visitor.visitArray(this.selectors); } - var loadFileCallback = function(loadedFile) { - var plugin, - resolvedFilename = loadedFile.filename, - contents = loadedFile.contents.replace(/^\uFEFF/, ''); + if (this.rules && this.rules.length) { + this.rules = visitor.visitArray(this.rules); + } + } + }, { + key: "eval", + value: function _eval(context) { + var selectors; + var selCnt; + var selector; + var i; + var hasVariable; + var hasOnePassingSelector = false; + + if (this.selectors && (selCnt = this.selectors.length)) { + selectors = new Array(selCnt); + defaultFunc.error({ + type: 'Syntax', + message: 'it is currently only allowed in parametric mixin guards,' + }); - // Pass on an updated rootpath if path of imported file is relative and file - // is in a (sub|sup) directory - // - // Examples: - // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/', - // then rootpath should become 'less/module/nav/' - // - If path of imported file is '../mixins.less' and rootpath is 'less/', - // then rootpath should become 'less/../' - newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename); - if (newFileInfo.rewriteUrls) { - newFileInfo.rootpath = fileManager.join( - (importManager.context.rootpath || ''), - fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath)); + for (i = 0; i < selCnt; i++) { + selector = this.selectors[i].eval(context); - if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) { - newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath); - } + for (var j = 0; j < selector.elements.length; j++) { + if (selector.elements[j].isVariable) { + hasVariable = true; + break; + } } - newFileInfo.filename = resolvedFilename; - var newEnv = new contexts.Parse(importManager.context); - - newEnv.processImports = false; - importManager.contents[resolvedFilename] = contents; + selectors[i] = selector; - if (currentFileInfo.reference || importOptions.reference) { - newFileInfo.reference = true; + if (selector.evaldCondition) { + hasOnePassingSelector = true; } + } - if (importOptions.isPlugin) { - plugin = pluginLoader.evalPlugin(contents, newEnv, importManager, importOptions.pluginArgs, newFileInfo); - if (plugin instanceof LessError) { - fileParsedFunc(plugin, null, resolvedFilename); - } - else { - fileParsedFunc(null, plugin, resolvedFilename); - } - } else if (importOptions.inline) { - fileParsedFunc(null, contents, resolvedFilename); - } else { - - // import (multiple) parse trees apparently get altered and can't be cached. - // TODO: investigate why this is - if (importManager.files[resolvedFilename] - && !importManager.files[resolvedFilename].options.multiple - && !importOptions.multiple) { + if (hasVariable) { + var toParseSelectors = new Array(selCnt); - fileParsedFunc(null, importManager.files[resolvedFilename].root, resolvedFilename); - } - else { - new Parser(newEnv, importManager, newFileInfo).parse(contents, function (e, root) { - fileParsedFunc(e, root, resolvedFilename); - }); - } + for (i = 0; i < selCnt; i++) { + selector = selectors[i]; + toParseSelectors[i] = selector.toCSS(context); } - }; - var promise, context = utils.clone(this.context); - if (tryAppendExtension) { - context.ext = importOptions.isPlugin ? '.js' : '.less'; - } + this.parse.parseNode(toParseSelectors.join(','), ["selectors"], selectors[0].getIndex(), selectors[0].fileInfo(), function (err, result) { + if (result) { + selectors = flattenArray(result); + } + }); + } - if (importOptions.isPlugin) { - promise = pluginLoader.loadPlugin(path, currentFileInfo.currentDirectory, context, environment, fileManager); - } - else { - promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, context, environment, - function(err, loadedFile) { - if (err) { - fileParsedFunc(err); - } else { - loadFileCallback(loadedFile); - } - }); - } - if (promise) { - promise.then(loadFileCallback, fileParsedFunc); + defaultFunc.reset(); + } else { + hasOnePassingSelector = true; } - }; - return ImportManager; -}; - -},{"./contexts":13,"./less-error":38,"./logger":39,"./parser/parser":44,"./utils":89,"promise":undefined}],37:[function(require,module,exports){ -module.exports = function(environment, fileManagers) { - var SourceMapOutput, SourceMapBuilder, ParseTree, ImportManager, Environment; - - var initial = { - version: [3, 9, 0], - data: require('./data'), - tree: require('./tree'), - Environment: (Environment = require('./environment/environment')), - AbstractFileManager: require('./environment/abstract-file-manager'), - AbstractPluginLoader: require('./environment/abstract-plugin-loader'), - environment: (environment = new Environment(environment, fileManagers)), - visitors: require('./visitors'), - Parser: require('./parser/parser'), - functions: require('./functions')(environment), - contexts: require('./contexts'), - SourceMapOutput: (SourceMapOutput = require('./source-map-output')(environment)), - SourceMapBuilder: (SourceMapBuilder = require('./source-map-builder')(SourceMapOutput, environment)), - ParseTree: (ParseTree = require('./parse-tree')(SourceMapBuilder)), - ImportManager: (ImportManager = require('./import-manager')(environment)), - render: require('./render')(environment, ParseTree, ImportManager), - parse: require('./parse')(environment, ParseTree, ImportManager), - LessError: require('./less-error'), - transformTree: require('./transform-tree'), - utils: require('./utils'), - PluginManager: require('./plugin-manager'), - logger: require('./logger') - }; - - // Create a public API + var rules = this.rules ? copyArray(this.rules) : null; + var ruleset = new Ruleset(selectors, rules, this.strictImports, this.visibilityInfo()); + var rule; + var subRule; + ruleset.originalRuleset = this; + ruleset.root = this.root; + ruleset.firstRoot = this.firstRoot; + ruleset.allowImports = this.allowImports; - var ctor = function(t) { - return function() { - var obj = Object.create(t.prototype); - t.apply(obj, Array.prototype.slice.call(arguments, 0)); - return obj; - }; - }; - var t, api = Object.create(initial); - for (var n in initial.tree) { - /* eslint guard-for-in: 0 */ - t = initial.tree[n]; - if (typeof t === 'function') { - api[n.toLowerCase()] = ctor(t); + if (this.debugInfo) { + ruleset.debugInfo = this.debugInfo; } - else { - api[n] = Object.create(null); - for (var o in t) { - /* eslint guard-for-in: 0 */ - api[n][o.toLowerCase()] = ctor(t[o]); - } - } - } - return api; -}; - -},{"./contexts":13,"./data":15,"./environment/abstract-file-manager":18,"./environment/abstract-plugin-loader":19,"./environment/environment":20,"./functions":28,"./import-manager":36,"./less-error":38,"./logger":39,"./parse":41,"./parse-tree":40,"./parser/parser":44,"./plugin-manager":45,"./render":46,"./source-map-builder":47,"./source-map-output":48,"./transform-tree":49,"./tree":67,"./utils":89,"./visitors":93}],38:[function(require,module,exports){ -var utils = require('./utils'); -/** - * This is a centralized class of any error that could be thrown internally (mostly by the parser). - * Besides standard .message it keeps some additional data like a path to the file where the error - * occurred along with line and column numbers. - * - * @class - * @extends Error - * @type {module.LessError} - * - * @prop {string} type - * @prop {string} filename - * @prop {number} index - * @prop {number} line - * @prop {number} column - * @prop {number} callLine - * @prop {number} callExtract - * @prop {string[]} extract - * - * @param {Object} e - An error object to wrap around or just a descriptive object - * @param {Object} fileContentMap - An object with file contents in 'contents' property (like importManager) @todo - move to fileManager? - * @param {string} [currentFilename] - */ -var LessError = module.exports = function LessError(e, fileContentMap, currentFilename) { - Error.call(this); + if (!hasOnePassingSelector) { + rules.length = 0; + } // inherit a function registry from the frames stack when possible; + // otherwise from the global registry - var filename = e.filename || currentFilename; - this.message = e.message; - this.stack = e.stack; + ruleset.functionRegistry = function (frames) { + var i = 0; + var n = frames.length; + var found; - if (fileContentMap && filename) { - var input = fileContentMap.contents[filename], - loc = utils.getLocation(e.index, input), - line = loc.line, - col = loc.column, - callLine = e.call && utils.getLocation(e.call, input).line, - lines = input ? input.split('\n') : ''; - - this.type = e.type || 'Syntax'; - this.filename = filename; - this.index = e.index; - this.line = typeof line === 'number' ? line + 1 : null; - this.column = col; - - if (!this.line && this.stack) { - var found = this.stack.match(/(|Function):(\d+):(\d+)/); + for (; i !== n; ++i) { + found = frames[i].functionRegistry; if (found) { - if (found[2]) { - this.line = parseInt(found[2]) - 2; - } - if (found[3]) { - this.column = parseInt(found[3]); - } + return found; } - } + } - this.callLine = callLine + 1; - this.callExtract = lines[callLine]; + return functionRegistry; + }(context.frames).inherit(); // push the current ruleset to the frames stack - this.extract = [ - lines[this.line - 2], - lines[this.line - 1], - lines[this.line] - ]; - } + var ctxFrames = context.frames; + ctxFrames.unshift(ruleset); // currrent selectors -}; + var ctxSelectors = context.selectors; -if (typeof Object.create === 'undefined') { - var F = function () {}; - F.prototype = Error.prototype; - LessError.prototype = new F(); -} else { - LessError.prototype = Object.create(Error.prototype); -} + if (!ctxSelectors) { + context.selectors = ctxSelectors = []; + } -LessError.prototype.constructor = LessError; + ctxSelectors.unshift(this.selectors); // Evaluate imports -/** - * An overridden version of the default Object.prototype.toString - * which uses additional information to create a helpful message. - * - * @param {Object} options - * @returns {string} - */ -LessError.prototype.toString = function(options) { - options = options || {}; + if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { + ruleset.evalImports(context); + } // Store the frames around mixin definitions, + // so they can be evaluated like closures when the time comes. - var message = ''; - var extract = this.extract || []; - var error = []; - var stylize = function (str) { return str; }; - if (options.stylize) { - var type = typeof options.stylize; - if (type !== 'function') { - throw Error('options.stylize should be a function, got a ' + type + '!'); - } - stylize = options.stylize; - } - if (this.line !== null) { - if (typeof extract[0] === 'string') { - error.push(stylize((this.line - 1) + ' ' + extract[0], 'grey')); - } + var rsRules = ruleset.rules; - if (typeof extract[1] === 'string') { - var errorTxt = this.line + ' '; - if (extract[1]) { - errorTxt += extract[1].slice(0, this.column) + - stylize(stylize(stylize(extract[1].substr(this.column, 1), 'bold') + - extract[1].slice(this.column + 1), 'red'), 'inverse'); - } - error.push(errorTxt); + for (i = 0; rule = rsRules[i]; i++) { + if (rule.evalFirst) { + rsRules[i] = rule.eval(context); + } } - if (typeof extract[2] === 'string') { - error.push(stylize((this.line + 1) + ' ' + extract[2], 'grey')); - } - error = error.join('\n') + stylize('', 'reset') + '\n'; - } + var mediaBlockCount = context.mediaBlocks && context.mediaBlocks.length || 0; // Evaluate mixin calls. - message += stylize(this.type + 'Error: ' + this.message, 'red'); - if (this.filename) { - message += stylize(' in ', 'red') + this.filename; - } - if (this.line) { - message += stylize(' on line ' + this.line + ', column ' + (this.column + 1) + ':', 'grey'); - } + for (i = 0; rule = rsRules[i]; i++) { + if (rule.type === 'MixinCall') { + /* jshint loopfunc:true */ + rules = rule.eval(context).filter(function (r) { + if (r instanceof Declaration && r.variable) { + // do not pollute the scope if the variable is + // already there. consider returning false here + // but we need a way to "return" variable from mixins + return !ruleset.variable(r.name); + } + + return true; + }); + rsRules.splice.apply(rsRules, _toConsumableArray([i, 1].concat(rules))); + i += rules.length - 1; + ruleset.resetCache(); + } else if (rule.type === 'VariableCall') { + /* jshint loopfunc:true */ + rules = rule.eval(context).rules.filter(function (r) { + if (r instanceof Declaration && r.variable) { + // do not pollute the scope at all + return false; + } - message += '\n' + error; + return true; + }); + rsRules.splice.apply(rsRules, _toConsumableArray([i, 1].concat(rules))); + i += rules.length - 1; + ruleset.resetCache(); + } + } // Evaluate everything else - if (this.callLine) { - message += stylize('from ', 'red') + (this.filename || '') + '/n'; - message += stylize(this.callLine, 'grey') + ' ' + this.callExtract + '/n'; - } - return message; -}; + for (i = 0; rule = rsRules[i]; i++) { + if (!rule.evalFirst) { + rsRules[i] = rule = rule.eval ? rule.eval(context) : rule; + } + } // Evaluate everything else -},{"./utils":89}],39:[function(require,module,exports){ -module.exports = { - error: function(msg) { - this._fireEvent('error', msg); - }, - warn: function(msg) { - this._fireEvent('warn', msg); - }, - info: function(msg) { - this._fireEvent('info', msg); - }, - debug: function(msg) { - this._fireEvent('debug', msg); - }, - addListener: function(listener) { - this._listeners.push(listener); - }, - removeListener: function(listener) { - for (var i = 0; i < this._listeners.length; i++) { - if (this._listeners[i] === listener) { - this._listeners.splice(i, 1); - return; - } - } - }, - _fireEvent: function(type, msg) { - for (var i = 0; i < this._listeners.length; i++) { - var logFunction = this._listeners[i][type]; - if (logFunction) { - logFunction(msg); + + for (i = 0; rule = rsRules[i]; i++) { + // for rulesets, check if it is a css guard and can be removed + if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) { + // check if it can be folded in (e.g. & where) + if (rule.selectors[0] && rule.selectors[0].isJustParentSelector()) { + rsRules.splice(i--, 1); + + for (var j = 0; subRule = rule.rules[j]; j++) { + if (subRule instanceof Node) { + subRule.copyVisibilityInfo(rule.visibilityInfo()); + + if (!(subRule instanceof Declaration) || !subRule.variable) { + rsRules.splice(++i, 0, subRule); + } + } + } } - } - }, - _listeners: [] -}; + } + } // Pop the stack -},{}],40:[function(require,module,exports){ -var LessError = require('./less-error'), - transformTree = require('./transform-tree'), - logger = require('./logger'); -module.exports = function(SourceMapBuilder) { - var ParseTree = function(root, imports) { - this.root = root; - this.imports = imports; - }; + ctxFrames.shift(); + ctxSelectors.shift(); - ParseTree.prototype.toCSS = function(options) { - var evaldRoot, result = {}, sourceMapBuilder; - try { - evaldRoot = transformTree(this.root, options); - } catch (e) { - throw new LessError(e, this.imports); + if (context.mediaBlocks) { + for (i = mediaBlockCount; i < context.mediaBlocks.length; i++) { + context.mediaBlocks[i].bubbleSelectors(selectors); + } } - try { - var compress = Boolean(options.compress); - if (compress) { - logger.warn('The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.'); - } + return ruleset; + } + }, { + key: "evalImports", + value: function evalImports(context) { + var rules = this.rules; + var i; + var importRules; - var toCSSOptions = { - compress: compress, - dumpLineNumbers: options.dumpLineNumbers, - strictUnits: Boolean(options.strictUnits), - numPrecision: 8}; + if (!rules) { + return; + } - if (options.sourceMap) { - sourceMapBuilder = new SourceMapBuilder(options.sourceMap); - result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports); + for (i = 0; i < rules.length; i++) { + if (rules[i].type === 'Import') { + importRules = rules[i].eval(context); + + if (importRules && (importRules.length || importRules.length === 0)) { + rules.splice.apply(rules, _toConsumableArray([i, 1].concat(importRules))); + i += importRules.length - 1; } else { - result.css = evaldRoot.toCSS(toCSSOptions); + rules.splice(i, 1, importRules); } - } catch (e) { - throw new LessError(e, this.imports); - } - if (options.pluginManager) { - var postProcessors = options.pluginManager.getPostProcessors(); - for (var i = 0; i < postProcessors.length; i++) { - result.css = postProcessors[i].process(result.css, { sourceMap: sourceMapBuilder, options: options, imports: this.imports }); - } - } - if (options.sourceMap) { - result.map = sourceMapBuilder.getExternalSourceMap(); - } - - result.imports = []; - for (var file in this.imports.files) { - if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) { - result.imports.push(file); - } + this.resetCache(); + } } + } + }, { + key: "makeImportant", + value: function makeImportant() { + var result = new Ruleset(this.selectors, this.rules.map(function (r) { + if (r.makeImportant) { + return r.makeImportant(); + } else { + return r; + } + }), this.strictImports, this.visibilityInfo()); return result; - }; - return ParseTree; -}; - -},{"./less-error":38,"./logger":39,"./transform-tree":49}],41:[function(require,module,exports){ -var PromiseConstructor, - contexts = require('./contexts'), - Parser = require('./parser/parser'), - PluginManager = require('./plugin-manager'), - LessError = require('./less-error'), - utils = require('./utils'); + } + }, { + key: "matchArgs", + value: function matchArgs(args) { + return !args || args.length === 0; + } // lets you call a css selector with a guard -module.exports = function(environment, ParseTree, ImportManager) { - var parse = function (input, options, callback) { + }, { + key: "matchCondition", + value: function matchCondition(args, context) { + var lastSelector = this.selectors[this.selectors.length - 1]; - if (typeof options === 'function') { - callback = options; - options = utils.copyOptions(this.options, {}); + if (!lastSelector.evaldCondition) { + return false; } - else { - options = utils.copyOptions(this.options, options || {}); + + if (lastSelector.condition && !lastSelector.condition.eval(new contexts.Eval(context, context.frames))) { + return false; } - if (!callback) { - if (!PromiseConstructor) { - PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise; - } - var self = this; - return new PromiseConstructor(function (resolve, reject) { - parse.call(self, input, options, function(err, output) { - if (err) { - reject(err); - } else { - resolve(output); - } - }); - }); - } else { - var context, - rootFileInfo, - pluginManager = new PluginManager(this, !options.reUsePluginManager); + return true; + } + }, { + key: "resetCache", + value: function resetCache() { + this._rulesets = null; + this._variables = null; + this._properties = null; + this._lookups = {}; + } + }, { + key: "variables", + value: function variables() { + if (!this._variables) { + this._variables = !this.rules ? {} : this.rules.reduce(function (hash, r) { + if (r instanceof Declaration && r.variable === true) { + hash[r.name] = r; + } // when evaluating variables in an import statement, imports have not been eval'd + // so we need to go inside import statements. + // guard against root being a string (in the case of inlined less) - options.pluginManager = pluginManager; - context = new contexts.Parse(options); + if (r.type === 'Import' && r.root && r.root.variables) { + var vars = r.root.variables(); - if (options.rootFileInfo) { - rootFileInfo = options.rootFileInfo; - } else { - var filename = options.filename || 'input'; - var entryPath = filename.replace(/[^\/\\]*$/, ''); - rootFileInfo = { - filename: filename, - rewriteUrls: context.rewriteUrls, - rootpath: context.rootpath || '', - currentDirectory: entryPath, - entryPath: entryPath, - rootFilename: filename - }; - // add in a missing trailing slash - if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== '/') { - rootFileInfo.rootpath += '/'; + for (var name in vars) { + if (vars.hasOwnProperty(name)) { + hash[name] = r.root.variable(name); } + } } - var imports = new ImportManager(this, context, rootFileInfo); - this.importManager = imports; + return hash; + }, {}); + } - // TODO: allow the plugins to be just a list of paths or names - // Do an async plugin queue like lessc + return this._variables; + } + }, { + key: "properties", + value: function properties() { + if (!this._properties) { + this._properties = !this.rules ? {} : this.rules.reduce(function (hash, r) { + if (r instanceof Declaration && r.variable !== true) { + var name = r.name.length === 1 && r.name[0] instanceof Keyword ? r.name[0].value : r.name; // Properties don't overwrite as they can merge - if (options.plugins) { - options.plugins.forEach(function(plugin) { - var evalResult, contents; - if (plugin.fileContent) { - contents = plugin.fileContent.replace(/^\uFEFF/, ''); - evalResult = pluginManager.Loader.evalPlugin(contents, context, imports, plugin.options, plugin.filename); - if (evalResult instanceof LessError) { - return callback(evalResult); - } - } - else { - pluginManager.addPlugin(plugin); - } - }); + if (!hash["$".concat(name)]) { + hash["$".concat(name)] = [r]; + } else { + hash["$".concat(name)].push(r); + } } - new Parser(context, imports, rootFileInfo) - .parse(input, function (e, root) { - if (e) { return callback(e); } - callback(null, root, imports, options); - }, options); + return hash; + }, {}); } - }; - return parse; -}; -},{"./contexts":13,"./less-error":38,"./parser/parser":44,"./plugin-manager":45,"./utils":89,"promise":undefined}],42:[function(require,module,exports){ -// Split the input into chunks. -module.exports = function (input, fail) { - var len = input.length, level = 0, parenLevel = 0, - lastOpening, lastOpeningParen, lastMultiComment, lastMultiCommentEndBrace, - chunks = [], emitFrom = 0, - chunkerCurrentIndex, currentChunkStartIndex, cc, cc2, matched; + return this._properties; + } + }, { + key: "variable", + value: function variable(name) { + var decl = this.variables()[name]; - function emitChunk(force) { - var len = chunkerCurrentIndex - emitFrom; - if (((len < 512) && !force) || !len) { - return; + if (decl) { + return this.parseValue(decl); } - chunks.push(input.slice(emitFrom, chunkerCurrentIndex + 1)); - emitFrom = chunkerCurrentIndex + 1; - } + } + }, { + key: "property", + value: function property(name) { + var decl = this.properties()[name]; - for (chunkerCurrentIndex = 0; chunkerCurrentIndex < len; chunkerCurrentIndex++) { - cc = input.charCodeAt(chunkerCurrentIndex); - if (((cc >= 97) && (cc <= 122)) || (cc < 34)) { - // a-z or whitespace - continue; + if (decl) { + return this.parseValue(decl); } + } + }, { + key: "lastDeclaration", + value: function lastDeclaration() { + for (var i = this.rules.length; i > 0; i--) { + var decl = this.rules[i - 1]; - switch (cc) { - case 40: // ( - parenLevel++; - lastOpeningParen = chunkerCurrentIndex; - continue; - case 41: // ) - if (--parenLevel < 0) { - return fail('missing opening `(`', chunkerCurrentIndex); - } - continue; - case 59: // ; - if (!parenLevel) { emitChunk(); } - continue; - case 123: // { - level++; - lastOpening = chunkerCurrentIndex; - continue; - case 125: // } - if (--level < 0) { - return fail('missing opening `{`', chunkerCurrentIndex); - } - if (!level && !parenLevel) { emitChunk(); } - continue; - case 92: // \ - if (chunkerCurrentIndex < len - 1) { chunkerCurrentIndex++; continue; } - return fail('unescaped `\\`', chunkerCurrentIndex); - case 34: - case 39: - case 96: // ", ' and ` - matched = 0; - currentChunkStartIndex = chunkerCurrentIndex; - for (chunkerCurrentIndex = chunkerCurrentIndex + 1; chunkerCurrentIndex < len; chunkerCurrentIndex++) { - cc2 = input.charCodeAt(chunkerCurrentIndex); - if (cc2 > 96) { continue; } - if (cc2 == cc) { matched = 1; break; } - if (cc2 == 92) { // \ - if (chunkerCurrentIndex == len - 1) { - return fail('unescaped `\\`', chunkerCurrentIndex); - } - chunkerCurrentIndex++; - } - } - if (matched) { continue; } - return fail('unmatched `' + String.fromCharCode(cc) + '`', currentChunkStartIndex); - case 47: // /, check for comment - if (parenLevel || (chunkerCurrentIndex == len - 1)) { continue; } - cc2 = input.charCodeAt(chunkerCurrentIndex + 1); - if (cc2 == 47) { - // //, find lnfeed - for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len; chunkerCurrentIndex++) { - cc2 = input.charCodeAt(chunkerCurrentIndex); - if ((cc2 <= 13) && ((cc2 == 10) || (cc2 == 13))) { break; } - } - } else if (cc2 == 42) { - // /*, find */ - lastMultiComment = currentChunkStartIndex = chunkerCurrentIndex; - for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len - 1; chunkerCurrentIndex++) { - cc2 = input.charCodeAt(chunkerCurrentIndex); - if (cc2 == 125) { lastMultiCommentEndBrace = chunkerCurrentIndex; } - if (cc2 != 42) { continue; } - if (input.charCodeAt(chunkerCurrentIndex + 1) == 47) { break; } - } - if (chunkerCurrentIndex == len - 1) { - return fail('missing closing `*/`', currentChunkStartIndex); - } - chunkerCurrentIndex++; + if (decl instanceof Declaration) { + return this.parseValue(decl); + } + } + } + }, { + key: "parseValue", + value: function parseValue(toParse) { + var self = this; + + function transformDeclaration(decl) { + if (decl.value instanceof Anonymous && !decl.parsed) { + if (typeof decl.value.value === 'string') { + this.parse.parseNode(decl.value.value, ['value', 'important'], decl.value.getIndex(), decl.fileInfo(), function (err, result) { + if (err) { + decl.parsed = true; } - continue; - case 42: // *, check for unmatched */ - if ((chunkerCurrentIndex < len - 1) && (input.charCodeAt(chunkerCurrentIndex + 1) == 47)) { - return fail('unmatched `/*`', chunkerCurrentIndex); + + if (result) { + decl.value = result[0]; + decl.important = result[1] || ''; + decl.parsed = true; } - continue; + }); + } else { + decl.parsed = true; + } + + return decl; + } else { + return decl; + } } - } - if (level !== 0) { - if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) { - return fail('missing closing `}` or `*/`', lastOpening); + if (!Array.isArray(toParse)) { + return transformDeclaration.call(self, toParse); } else { - return fail('missing closing `}`', lastOpening); + var nodes = []; + toParse.forEach(function (n) { + nodes.push(transformDeclaration.call(self, n)); + }); + return nodes; + } + } + }, { + key: "rulesets", + value: function rulesets() { + if (!this.rules) { + return []; } - } else if (parenLevel !== 0) { - return fail('missing closing `)`', lastOpeningParen); - } - emitChunk(true); - return chunks; -}; - -},{}],43:[function(require,module,exports){ -var chunker = require('./chunker'); - -module.exports = function() { - var input, // Less input string - j, // current chunk - saveStack = [], // holds state for backtracking - furthest, // furthest index the parser has gone to - furthestPossibleErrorMessage, // if this is furthest we got to, this is the probably cause - chunks, // chunkified input - current, // current chunk - currentPos, // index of current chunk, in `input` - parserInput = {}; - - var CHARCODE_SPACE = 32, - CHARCODE_TAB = 9, - CHARCODE_LF = 10, - CHARCODE_CR = 13, - CHARCODE_PLUS = 43, - CHARCODE_COMMA = 44, - CHARCODE_FORWARD_SLASH = 47, - CHARCODE_9 = 57; + var filtRules = []; + var rules = this.rules; + var i; + var rule; - function skipWhitespace(length) { - var oldi = parserInput.i, oldj = j, - curr = parserInput.i - currentPos, - endIndex = parserInput.i + current.length - curr, - mem = (parserInput.i += length), - inp = input, - c, nextChar, comment; - - for (; parserInput.i < endIndex; parserInput.i++) { - c = inp.charCodeAt(parserInput.i); - - if (parserInput.autoCommentAbsorb && c === CHARCODE_FORWARD_SLASH) { - nextChar = inp.charAt(parserInput.i + 1); - if (nextChar === '/') { - comment = {index: parserInput.i, isLineComment: true}; - var nextNewLine = inp.indexOf('\n', parserInput.i + 2); - if (nextNewLine < 0) { - nextNewLine = endIndex; - } - parserInput.i = nextNewLine; - comment.text = inp.substr(comment.index, parserInput.i - comment.index); - parserInput.commentStore.push(comment); - continue; - } else if (nextChar === '*') { - var nextStarSlash = inp.indexOf('*/', parserInput.i + 2); - if (nextStarSlash >= 0) { - comment = { - index: parserInput.i, - text: inp.substr(parserInput.i, nextStarSlash + 2 - parserInput.i), - isLineComment: false - }; - parserInput.i += comment.text.length - 1; - parserInput.commentStore.push(comment); - continue; + for (i = 0; rule = rules[i]; i++) { + if (rule.isRuleset) { + filtRules.push(rule); + } + } + + return filtRules; + } + }, { + key: "prependRule", + value: function prependRule(rule) { + var rules = this.rules; + + if (rules) { + rules.unshift(rule); + } else { + this.rules = [rule]; + } + + this.setParent(rule, this); + } + }, { + key: "find", + value: function find(selector) { + var self = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this; + var filter = arguments.length > 2 ? arguments[2] : undefined; + var rules = []; + var match; + var foundMixins; + var key = selector.toCSS(); + + if (key in this._lookups) { + return this._lookups[key]; + } + + this.rulesets().forEach(function (rule) { + if (rule !== self) { + for (var j = 0; j < rule.selectors.length; j++) { + match = selector.match(rule.selectors[j]); + + if (match) { + if (selector.elements.length > match) { + if (!filter || filter(rule)) { + foundMixins = rule.find(new Selector(selector.elements.slice(match)), self, filter); + + for (var i = 0; i < foundMixins.length; ++i) { + foundMixins[i].path.push(rule); } + + Array.prototype.push.apply(rules, foundMixins); + } + } else { + rules.push({ + rule: rule, + path: [] + }); } - break; - } - if ((c !== CHARCODE_SPACE) && (c !== CHARCODE_LF) && (c !== CHARCODE_TAB) && (c !== CHARCODE_CR)) { break; + } } + } + }); + this._lookups[key] = rules; + return rules; + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + var i; + var j; + var charsetRuleNodes = []; + var ruleNodes = []; + var // Line number debugging + debugInfo$1; + var rule; + var path; + context.tabLevel = context.tabLevel || 0; + + if (!this.root) { + context.tabLevel++; } - current = current.slice(length + parserInput.i - mem + curr); - currentPos = parserInput.i; + var tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join(' '); + var tabSetStr = context.compress ? '' : Array(context.tabLevel).join(' '); + var sep; + var charsetNodeIndex = 0; + var importNodeIndex = 0; - if (!current.length) { - if (j < chunks.length - 1) { - current = chunks[++j]; - skipWhitespace(0); // skip space at the beginning of a chunk - return true; // things changed + for (i = 0; rule = this.rules[i]; i++) { + if (rule instanceof Comment) { + if (importNodeIndex === i) { + importNodeIndex++; } - parserInput.finished = true; - } - return oldi !== parserInput.i || oldj !== j; - } + ruleNodes.push(rule); + } else if (rule.isCharset && rule.isCharset()) { + ruleNodes.splice(charsetNodeIndex, 0, rule); + charsetNodeIndex++; + importNodeIndex++; + } else if (rule.type === 'Import') { + ruleNodes.splice(importNodeIndex, 0, rule); + importNodeIndex++; + } else { + ruleNodes.push(rule); + } + } - parserInput.save = function() { - currentPos = parserInput.i; - saveStack.push( { current: current, i: parserInput.i, j: j }); - }; - parserInput.restore = function(possibleErrorMessage) { + ruleNodes = charsetRuleNodes.concat(ruleNodes); // If this is the root node, we don't render + // a selector, or {}. - if (parserInput.i > furthest || (parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage)) { - furthest = parserInput.i; - furthestPossibleErrorMessage = possibleErrorMessage; - } - var state = saveStack.pop(); - current = state.current; - currentPos = parserInput.i = state.i; - j = state.j; - }; - parserInput.forget = function() { - saveStack.pop(); - }; - parserInput.isWhitespace = function (offset) { - var pos = parserInput.i + (offset || 0), - code = input.charCodeAt(pos); - return (code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF); - }; + if (!this.root) { + debugInfo$1 = debugInfo(context, this, tabSetStr); - // Specialization of $(tok) - parserInput.$re = function(tok) { - if (parserInput.i > currentPos) { - current = current.slice(parserInput.i - currentPos); - currentPos = parserInput.i; - } + if (debugInfo$1) { + output.add(debugInfo$1); + output.add(tabSetStr); + } - var m = tok.exec(current); - if (!m) { - return null; - } + var paths = this.paths; + var pathCnt = paths.length; + var pathSubCnt; + sep = context.compress ? ',' : ",\n".concat(tabSetStr); - skipWhitespace(m[0].length); - if (typeof m === 'string') { - return m; - } + for (i = 0; i < pathCnt; i++) { + path = paths[i]; - return m.length === 1 ? m[0] : m; - }; + if (!(pathSubCnt = path.length)) { + continue; + } - parserInput.$char = function(tok) { - if (input.charAt(parserInput.i) !== tok) { - return null; - } - skipWhitespace(1); - return tok; - }; + if (i > 0) { + output.add(sep); + } - parserInput.$str = function(tok) { - var tokLength = tok.length; + context.firstSelector = true; + path[0].genCSS(context, output); + context.firstSelector = false; - // https://jsperf.com/string-startswith/21 - for (var i = 0; i < tokLength; i++) { - if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { - return null; + for (j = 1; j < pathSubCnt; j++) { + path[j].genCSS(context, output); } - } + } - skipWhitespace(tokLength); - return tok; - }; + output.add((context.compress ? '{' : ' {\n') + tabRuleStr); + } // Compile rules and rulesets - parserInput.$quoted = function(loc) { - var pos = loc || parserInput.i, - startChar = input.charAt(pos); - if (startChar !== '\'' && startChar !== '"') { - return; + for (i = 0; rule = ruleNodes[i]; i++) { + if (i + 1 === ruleNodes.length) { + context.lastRule = true; + } + + var currentLastRule = context.lastRule; + + if (rule.isRulesetLike(rule)) { + context.lastRule = false; + } + + if (rule.genCSS) { + rule.genCSS(context, output); + } else if (rule.value) { + output.add(rule.value.toString()); + } + + context.lastRule = currentLastRule; + + if (!context.lastRule && rule.isVisible()) { + output.add(context.compress ? '' : "\n".concat(tabRuleStr)); + } else { + context.lastRule = false; + } } - var length = input.length, - currentPosition = pos; - - for (var i = 1; i + currentPosition < length; i++) { - var nextChar = input.charAt(i + currentPosition); - switch (nextChar) { - case '\\': - i++; - continue; - case '\r': - case '\n': - break; - case startChar: - var str = input.substr(currentPosition, i + 1); - if (!loc && loc !== 0) { - skipWhitespace(i + 1); - return str - } - return [startChar, str]; - default: - } + + if (!this.root) { + output.add(context.compress ? '}' : "\n".concat(tabSetStr, "}")); + context.tabLevel--; } - return null; - }; - /** - * Permissive parsing. Ignores everything except matching {} [] () and quotes - * until matching token (outside of blocks) - */ - parserInput.$parseUntil = function(tok) { - var quote = '', - returnVal = null, - inComment = false, - blockDepth = 0, - blockStack = [], - parseGroups = [], - length = input.length, - startPos = parserInput.i, - lastPos = parserInput.i, - i = parserInput.i, - loop = true, - testChar; - - if (typeof tok === 'string') { - testChar = function(char) { - return char === tok; - } - } else { - testChar = function(char) { - return tok.test(char); - } + if (!output.isEmpty() && !context.compress && this.firstRoot) { + output.add('\n'); + } + } + }, { + key: "joinSelectors", + value: function joinSelectors(paths, context, selectors) { + for (var s = 0; s < selectors.length; s++) { + this.joinSelector(paths, context, selectors[s]); } + } + }, { + key: "joinSelector", + value: function joinSelector(paths, context, selector) { + function createParenthesis(elementsToPak, originalElement) { + var replacementParen; + var j; + + if (elementsToPak.length === 0) { + replacementParen = new Paren(elementsToPak[0]); + } else { + var insideParent = new Array(elementsToPak.length); - do { - var prevChar, nextChar = input.charAt(i); - if (blockDepth === 0 && testChar(nextChar)) { - returnVal = input.substr(lastPos, i - lastPos); - if (returnVal) { - parseGroups.push(returnVal); - } - else { - parseGroups.push(' '); - } - returnVal = parseGroups; - skipWhitespace(i - startPos); - loop = false - } else { - if (inComment) { - if (nextChar === '*' && - input.charAt(i + 1) === '/') { - i++; - blockDepth--; - inComment = false; - } - i++; - continue; - } - switch (nextChar) { - case '\\': - i++; - nextChar = input.charAt(i); - parseGroups.push(input.substr(lastPos, i - lastPos + 1)); - lastPos = i + 1; - break; - case '/': - if (input.charAt(i + 1) === '*') { - i++; - inComment = true; - blockDepth++; - } - break; - case '\'': - case '"': - quote = parserInput.$quoted(i); - if (quote) { - parseGroups.push(input.substr(lastPos, i - lastPos), quote); - i += quote[1].length - 1; - lastPos = i + 1; - } - else { - skipWhitespace(i - startPos); - returnVal = nextChar; - loop = false; - } - break; - case '{': - blockStack.push('}'); - blockDepth++; - break; - case '(': - blockStack.push(')'); - blockDepth++; - break; - case '[': - blockStack.push(']'); - blockDepth++; - break; - case '}': - case ')': - case ']': - var expected = blockStack.pop(); - if (nextChar === expected) { - blockDepth--; - } else { - // move the parser to the error and return expected - skipWhitespace(i - startPos); - returnVal = expected; - loop = false; - } - } - i++; - if (i > length) { - loop = false; - } + for (j = 0; j < elementsToPak.length; j++) { + insideParent[j] = new Element(null, elementsToPak[j], originalElement.isVariable, originalElement._index, originalElement._fileInfo); } - prevChar = nextChar; - } while (loop); - - return returnVal ? returnVal : null; - } - parserInput.autoCommentAbsorb = true; - parserInput.commentStore = []; - parserInput.finished = false; + replacementParen = new Paren(new Selector(insideParent)); + } - // Same as $(), but don't change the state of the parser, - // just return the match. - parserInput.peek = function(tok) { - if (typeof tok === 'string') { - // https://jsperf.com/string-startswith/21 - for (var i = 0; i < tok.length; i++) { - if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { - return false; - } - } - return true; - } else { - return tok.test(current); + return replacementParen; } - }; - // Specialization of peek() - // TODO remove or change some currentChar calls to peekChar - parserInput.peekChar = function(tok) { - return input.charAt(parserInput.i) === tok; - }; + function createSelector(containedElement, originalElement) { + var element; + var selector; + element = new Element(null, containedElement, originalElement.isVariable, originalElement._index, originalElement._fileInfo); + selector = new Selector([element]); + return selector; + } // joins selector path from `beginningPath` with selector path in `addPath` + // `replacedElement` contains element that is being replaced by `addPath` + // returns concatenated path - parserInput.currentChar = function() { - return input.charAt(parserInput.i); - }; - parserInput.prevChar = function() { - return input.charAt(parserInput.i - 1); - }; + function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) { + var newSelectorPath; + var lastSelector; + var newJoinedSelector; // our new selector path - parserInput.getInput = function() { - return input; - }; + newSelectorPath = []; // construct the joined selector - if & is the first thing this will be empty, + // if not newJoinedSelector will be the last set of elements in the selector - parserInput.peekNotNumeric = function() { - var c = input.charCodeAt(parserInput.i); - // Is the first char of the dimension 0-9, '.', '+' or '-' - return (c > CHARCODE_9 || c < CHARCODE_PLUS) || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA; - }; + if (beginningPath.length > 0) { + newSelectorPath = copyArray(beginningPath); + lastSelector = newSelectorPath.pop(); + newJoinedSelector = originalSelector.createDerived(copyArray(lastSelector.elements)); + } else { + newJoinedSelector = originalSelector.createDerived([]); + } - parserInput.start = function(str, chunkInput, failFunction) { - input = str; - parserInput.i = j = currentPos = furthest = 0; - - // chunking apparently makes things quicker (but my tests indicate - // it might actually make things slower in node at least) - // and it is a non-perfect parse - it can't recognise - // unquoted urls, meaning it can't distinguish comments - // meaning comments with quotes or {}() in them get 'counted' - // and then lead to parse errors. - // In addition if the chunking chunks in the wrong place we might - // not be able to parse a parser statement in one go - // this is officially deprecated but can be switched on via an option - // in the case it causes too much performance issues. - if (chunkInput) { - chunks = chunker(str, failFunction); - } else { - chunks = [str]; - } + if (addPath.length > 0) { + // /deep/ is a CSS4 selector - (removed, so should deprecate) + // that is valid without anything in front of it + // so if the & does not have a combinator that is "" or " " then + // and there is a combinator on the parent, then grab that. + // this also allows + a { & .b { .a & { ... though not sure why you would want to do that + var combinator = replacedElement.combinator; + var parentEl = addPath[0].elements[0]; - current = chunks[0]; + if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) { + combinator = parentEl.combinator; + } // join the elements so far with the first part of the parent - skipWhitespace(0); - }; - parserInput.end = function() { - var message, - isFinished = parserInput.i >= input.length; + newJoinedSelector.elements.push(new Element(combinator, parentEl.value, replacedElement.isVariable, replacedElement._index, replacedElement._fileInfo)); + newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1)); + } // now add the joined selector - but only if it is not empty - if (parserInput.i < furthest) { - message = furthestPossibleErrorMessage; - parserInput.i = furthest; - } - return { - isFinished: isFinished, - furthest: parserInput.i, - furthestPossibleErrorMessage: message, - furthestReachedEnd: parserInput.i >= input.length - 1, - furthestChar: input[parserInput.i] - }; - }; - return parserInput; -}; - -},{"./chunker":42}],44:[function(require,module,exports){ -var LessError = require('../less-error'), - tree = require('../tree'), - visitors = require('../visitors'), - getParserInput = require('./parser-input'), - utils = require('../utils'), - functionRegistry = require('../functions/function-registry'); - -// -// less.js - parser -// -// A relatively straight-forward predictive parser. -// There is no tokenization/lexing stage, the input is parsed -// in one sweep. -// -// To make the parser fast enough to run in the browser, several -// optimization had to be made: -// -// - Matching and slicing on a huge input is often cause of slowdowns. -// The solution is to chunkify the input into smaller strings. -// The chunks are stored in the `chunks` var, -// `j` holds the current chunk index, and `currentPos` holds -// the index of the current chunk in relation to `input`. -// This gives us an almost 4x speed-up. -// -// - In many cases, we don't need to match individual tokens; -// for example, if a value doesn't hold any variables, operations -// or dynamic references, the parser can effectively 'skip' it, -// treating it as a literal. -// An example would be '1px solid #000' - which evaluates to itself, -// we don't need to know what the individual components are. -// The drawback, of course is that you don't get the benefits of -// syntax-checking on the CSS. This gives us a 50% speed-up in the parser, -// and a smaller speed-up in the code-gen. -// -// -// Token matching is done with the `$` function, which either takes -// a terminal string or regexp, or a non-terminal function to call. -// It also takes care of moving all the indices forwards. -// - -var Parser = function Parser(context, imports, fileInfo) { - var parsers, - parserInput = getParserInput(); + if (newJoinedSelector.elements.length !== 0) { + newSelectorPath.push(newJoinedSelector); + } // put together the parent selectors after the join (e.g. the rest of the parent) - function error(msg, type) { - throw new LessError( - { - index: parserInput.i, - filename: fileInfo.filename, - type: type || 'Syntax', - message: msg - }, - imports - ); - } - function expect(arg, msg) { - // some older browsers return typeof 'function' for RegExp - var result = (arg instanceof Function) ? arg.call(parsers) : parserInput.$re(arg); - if (result) { - return result; - } - - error(msg || (typeof arg === 'string' - ? 'expected \'' + arg + '\' got \'' + parserInput.currentChar() + '\'' - : 'unexpected token')); - } + if (addPath.length > 1) { + var restOfPath = addPath.slice(1); + restOfPath = restOfPath.map(function (selector) { + return selector.createDerived(selector.elements, []); + }); + newSelectorPath = newSelectorPath.concat(restOfPath); + } - // Specialization of expect() - function expectChar(arg, msg) { - if (parserInput.$char(arg)) { - return arg; - } - error(msg || 'expected \'' + arg + '\' got \'' + parserInput.currentChar() + '\''); - } + return newSelectorPath; + } // joins selector path from `beginningPath` with every selector path in `addPaths` array + // `replacedElement` contains element that is being replaced by `addPath` + // returns array with all concatenated paths - function getDebugInfo(index) { - var filename = fileInfo.filename; - return { - lineNumber: utils.getLocation(index, parserInput.getInput()).line + 1, - fileName: filename - }; - } + function addAllReplacementsIntoPath(beginningPath, addPaths, replacedElement, originalSelector, result) { + var j; - /** - * Used after initial parsing to create nodes on the fly - * - * @param {String} str - string to parse - * @param {Array} parseList - array of parsers to run input through e.g. ["value", "important"] - * @param {Number} currentIndex - start number to begin indexing - * @param {Object} fileInfo - fileInfo to attach to created nodes - */ - function parseNode(str, parseList, currentIndex, fileInfo, callback) { - var result, returnNodes = []; - var parser = parserInput; - - try { - parser.start(str, false, function fail(msg, index) { - callback({ - message: msg, - index: index + currentIndex - }); - }); - for (var x = 0, p, i; (p = parseList[x]); x++) { - i = parser.i; - result = parsers[p](); - if (result) { - result._index = i + currentIndex; - result._fileInfo = fileInfo; - returnNodes.push(result); - } - else { - returnNodes.push(null); - } - } + for (j = 0; j < beginningPath.length; j++) { + var newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector); + result.push(newSelectorPath); + } - var endInfo = parser.end(); - if (endInfo.isFinished) { - callback(null, returnNodes); - } - else { - callback(true, null); - } - } catch (e) { - throw new LessError({ - index: e.index + currentIndex, - message: e.message - }, imports, fileInfo.filename); + return result; } - } - - // - // The Parser - // - return { - parserInput: parserInput, - imports: imports, - fileInfo: fileInfo, - parseNode: parseNode, - // - // Parse an input string into an abstract syntax tree, - // @param str A string containing 'less' markup - // @param callback call `callback` when done. - // @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply - // - parse: function (str, callback, additionalData) { - var root, error = null, globalVars, modifyVars, ignored, preText = ''; - globalVars = (additionalData && additionalData.globalVars) ? Parser.serializeVars(additionalData.globalVars) + '\n' : ''; - modifyVars = (additionalData && additionalData.modifyVars) ? '\n' + Parser.serializeVars(additionalData.modifyVars) : ''; + function mergeElementsOnToSelectors(elements, selectors) { + var i; + var sel; - if (context.pluginManager) { - var preProcessors = context.pluginManager.getPreProcessors(); - for (var i = 0; i < preProcessors.length; i++) { - str = preProcessors[i].process(str, { context: context, imports: imports, fileInfo: fileInfo }); - } - } + if (elements.length === 0) { + return; + } + + if (selectors.length === 0) { + selectors.push([new Selector(elements)]); + return; + } - if (globalVars || (additionalData && additionalData.banner)) { - preText = ((additionalData && additionalData.banner) ? additionalData.banner : '') + globalVars; - ignored = imports.contentsIgnoredChars; - ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0; - ignored[fileInfo.filename] += preText.length; + for (i = 0; sel = selectors[i]; i++) { + // if the previous thing in sel is a parent this needs to join on to it + if (sel.length > 0) { + sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements)); + } else { + sel.push(new Selector(elements)); } + } + } // replace all parent selectors inside `inSelector` by content of `context` array + // resulting selectors are returned inside `paths` array + // returns true if `inSelector` contained at least one parent selector + + + function replaceParentSelector(paths, context, inSelector) { + // The paths are [[Selector]] + // The first list is a list of comma separated selectors + // The inner list is a list of inheritance separated selectors + // e.g. + // .a, .b { + // .c { + // } + // } + // == [[.a] [.c]] [[.b] [.c]] + // + var i; + var j; + var k; + var currentElements; + var newSelectors; + var selectorsMultiplied; + var sel; + var el; + var hadParentSelector = false; + var length; + var lastSelector; + + function findNestedSelector(element) { + var maybeSelector; - str = str.replace(/\r\n?/g, '\n'); - // Remove potential UTF Byte Order Mark - str = preText + str.replace(/^\uFEFF/, '') + modifyVars; - imports.contents[fileInfo.filename] = str; + if (!(element.value instanceof Paren)) { + return null; + } - // Start with the primary rule. - // The whole syntax tree is held under a Ruleset node, - // with the `root` property set to true, so no `{}` are - // output. The callback is called when the input is parsed. - try { - parserInput.start(str, context.chunkInput, function fail(msg, index) { - throw new LessError({ - index: index, - type: 'Parse', - message: msg, - filename: fileInfo.filename - }, imports); - }); + maybeSelector = element.value.value; - tree.Node.prototype.parse = this; - root = new tree.Ruleset(null, this.parsers.primary()); - tree.Node.prototype.rootNode = root; - root.root = true; - root.firstRoot = true; - root.functionRegistry = functionRegistry.inherit(); - - } catch (e) { - return callback(new LessError(e, imports, fileInfo.filename)); + if (!(maybeSelector instanceof Selector)) { + return null; } - // If `i` is smaller than the `input.length - 1`, - // it means the parser wasn't able to parse the whole - // string, so we've got a parsing error. - // - // We try to extract a \n delimited string, - // showing the line where the parse error occurred. - // We split it up into two parts (the part which parsed, - // and the part which didn't), so we can color them differently. - var endInfo = parserInput.end(); - if (!endInfo.isFinished) { - - var message = endInfo.furthestPossibleErrorMessage; - - if (!message) { - message = 'Unrecognised input'; - if (endInfo.furthestChar === '}') { - message += '. Possibly missing opening \'{\''; - } else if (endInfo.furthestChar === ')') { - message += '. Possibly missing opening \'(\''; - } else if (endInfo.furthestReachedEnd) { - message += '. Possibly missing something'; - } - } + return maybeSelector; + } // the elements from the current selector so far - error = new LessError({ - type: 'Parse', - message: message, - index: endInfo.furthest, - filename: fileInfo.filename - }, imports); - } - var finish = function (e) { - e = error || e || imports.error; + currentElements = []; // the current list of new selectors to add to the path. + // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors + // by the parents - if (e) { - if (!(e instanceof LessError)) { - e = new LessError(e, imports, fileInfo.filename); - } + newSelectors = [[]]; - return callback(e); - } - else { - return callback(null, root); + for (i = 0; el = inSelector.elements[i]; i++) { + // non parent reference elements just get added + if (el.value !== '&') { + var nestedSelector = findNestedSelector(el); + + if (nestedSelector != null) { + // merge the current list of non parent selector elements + // on to the current list of selectors to add + mergeElementsOnToSelectors(currentElements, newSelectors); + var nestedPaths = []; + var replaced = void 0; + var replacedNewSelectors = []; + replaced = replaceParentSelector(nestedPaths, context, nestedSelector); + hadParentSelector = hadParentSelector || replaced; // the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors + + for (k = 0; k < nestedPaths.length; k++) { + var replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el); + addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors); } - }; - if (context.processImports !== false) { - new visitors.ImportVisitor(imports, finish) - .run(root); + newSelectors = replacedNewSelectors; + currentElements = []; + } else { + currentElements.push(el); + } } else { - return finish(); - } - }, + hadParentSelector = true; // the new list of selectors to add - // - // Here in, the parsing rules/functions - // - // The basic structure of the syntax tree generated is as follows: - // - // Ruleset -> Declaration -> Value -> Expression -> Entity - // - // Here's some Less code: - // - // .class { - // color: #fff; - // border: 1px solid #000; - // width: @w + 4px; - // > .child {...} - // } - // - // And here's what the parse tree might look like: - // - // Ruleset (Selector '.class', [ - // Declaration ("color", Value ([Expression [Color #fff]])) - // Declaration ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) - // Declaration ("width", Value ([Expression [Operation " + " [Variable "@w"][Dimension 4px]]])) - // Ruleset (Selector [Element '>', '.child'], [...]) - // ]) - // - // In general, most rules will try to parse a token with the `$re()` function, and if the return - // value is truly, will return a new node, of the relevant type. Sometimes, we need to check - // first, before parsing, that's when we use `peek()`. - // - parsers: parsers = { - // - // The `primary` rule is the *entry* and *exit* point of the parser. - // The rules here can appear at any level of the parse tree. - // - // The recursive nature of the grammar is an interplay between the `block` - // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, - // as represented by this simplified grammar: - // - // primary → (ruleset | declaration)+ - // ruleset → selector+ block - // block → '{' primary '}' - // - // Only at one point is the primary rule not called from the - // block rule: at the root level. - // - primary: function () { - var mixin = this.mixin, root = [], node; - - while (true) { - while (true) { - node = this.comment(); - if (!node) { break; } - root.push(node); - } - // always process comments before deciding if finished - if (parserInput.finished) { - break; - } - if (parserInput.peek('}')) { - break; - } + selectorsMultiplied = []; // merge the current list of non parent selector elements + // on to the current list of selectors to add - node = this.extendRule(); - if (node) { - root = root.concat(node); - continue; - } + mergeElementsOnToSelectors(currentElements, newSelectors); // loop through our current selectors - node = mixin.definition() || this.declaration() || this.ruleset() || - mixin.call(false, false) || this.variableCall() || this.entities.call() || this.atrule(); - if (node) { - root.push(node); - } else { - var foundSemiColon = false; - while (parserInput.$char(';')) { - foundSemiColon = true; - } - if (!foundSemiColon) { - break; - } - } - } + for (j = 0; j < newSelectors.length; j++) { + sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used + // whether there are parents or not + + if (context.length === 0) { + // the combinator used on el should now be applied to the next element instead so that + // it is not lost + if (sel.length > 0) { + sel[0].elements.push(new Element(el.combinator, '', el.isVariable, el._index, el._fileInfo)); + } - return root; - }, + selectorsMultiplied.push(sel); + } else { + // and the parent selectors + for (k = 0; k < context.length; k++) { + // We need to put the current selectors + // then join the last selector's elements on to the parents selectors + var newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector); // add that to our new set of selectors - // comments are collected by the main parsing mechanism and then assigned to nodes - // where the current structure allows it - comment: function () { - if (parserInput.commentStore.length) { - var comment = parserInput.commentStore.shift(); - return new(tree.Comment)(comment.text, comment.isLineComment, comment.index, fileInfo); + selectorsMultiplied.push(newSelectorPath); + } } - }, + } // our new selectors has been multiplied, so reset the state - // - // Entities are tokens which can be found inside an Expression - // - entities: { - mixinLookup: function() { - return parsers.mixin.call(true, true); - }, - // - // A string, which supports escaping " and ' - // - // "milky way" 'he\'s the one!' - // - quoted: function (forceEscaped) { - var str, index = parserInput.i, isEscaped = false; - - parserInput.save(); - if (parserInput.$char('~')) { - isEscaped = true; - } else if (forceEscaped) { - parserInput.restore(); - return; - } - str = parserInput.$quoted(); - if (!str) { - parserInput.restore(); - return; - } - parserInput.forget(); + newSelectors = selectorsMultiplied; + currentElements = []; + } + } // if we have any elements left over (e.g. .a& .b == .b) + // add them on to all the current selectors - return new(tree.Quoted)(str.charAt(0), str.substr(1, str.length - 2), isEscaped, index, fileInfo); - }, - // - // A catch-all word, such as: - // - // black border-collapse - // - keyword: function () { - var k = parserInput.$char('%') || parserInput.$re(/^\[?(?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+\]?/); - if (k) { - return tree.Color.fromKeyword(k) || new(tree.Keyword)(k); - } - }, + mergeElementsOnToSelectors(currentElements, newSelectors); - // - // A function call - // - // rgb(255, 0, 255) - // - // The arguments are parsed with the `entities.arguments` parser. - // - call: function () { - var name, args, func, index = parserInput.i; - - // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 - if (parserInput.peek(/^url\(/i)) { - return; - } + for (i = 0; i < newSelectors.length; i++) { + length = newSelectors[i].length; - parserInput.save(); + if (length > 0) { + paths.push(newSelectors[i]); + lastSelector = newSelectors[i][length - 1]; + newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList); + } + } - name = parserInput.$re(/^([\w-]+|%|progid:[\w\.]+)\(/); - if (!name) { - parserInput.forget(); - return; - } + return hadParentSelector; + } - name = name[1]; - func = this.customFuncCall(name); - if (func) { - args = func.parse(); - if (args && func.stop) { - parserInput.forget(); - return args; - } - } + function deriveSelector(visibilityInfo, deriveFrom) { + var newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition); + newSelector.copyVisibilityInfo(visibilityInfo); + return newSelector; + } // joinSelector code follows - args = this.arguments(args); - if (!parserInput.$char(')')) { - parserInput.restore('Could not parse call arguments or missing \')\''); - return; - } + var i; + var newPaths; + var hadParentSelector; + newPaths = []; + hadParentSelector = replaceParentSelector(newPaths, context, selector); - parserInput.forget(); - - return new(tree.Call)(name, args, index, fileInfo); - }, - - // - // Parsing rules for functions with non-standard args, e.g.: - // - // boolean(not(2 > 1)) - // - // This is a quick prototype, to be modified/improved when - // more custom-parsed funcs come (e.g. `selector(...)`) - // - - customFuncCall: function (name) { - /* Ideally the table is to be moved out of here for faster perf., - but it's quite tricky since it relies on all these `parsers` - and `expect` available only here */ - return { - alpha: f(parsers.ieAlpha, true), - boolean: f(condition), - 'if': f(condition) - }[name.toLowerCase()]; - - function f(parse, stop) { - return { - parse: parse, // parsing function - stop: stop // when true - stop after parse() and return its result, - // otherwise continue for plain args - }; - } - - function condition() { - return [expect(parsers.condition, 'expected condition')]; - } - }, + if (!hadParentSelector) { + if (context.length > 0) { + newPaths = []; - arguments: function (prevArgs) { - var argsComma = prevArgs || [], - argsSemiColon = [], - isSemiColonSeparated, value; - - parserInput.save(); - - while (true) { - if (prevArgs) { - prevArgs = false; - } else { - value = parsers.detachedRuleset() || this.assignment() || parsers.expression(); - if (!value) { - break; - } - - if (value.value && value.value.length == 1) { - value = value.value[0]; - } - - argsComma.push(value); - } - - if (parserInput.$char(',')) { - continue; - } - - if (parserInput.$char(';') || isSemiColonSeparated) { - isSemiColonSeparated = true; - value = (argsComma.length < 1) ? argsComma[0] - : new tree.Value(argsComma); - argsSemiColon.push(value); - argsComma = []; - } - } + for (i = 0; i < context.length; i++) { + var concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo())); + concatenated.push(selector); + newPaths.push(concatenated); + } + } else { + newPaths = [[selector]]; + } + } - parserInput.forget(); - return isSemiColonSeparated ? argsSemiColon : argsComma; - }, - literal: function () { - return this.dimension() || - this.color() || - this.quoted() || - this.unicodeDescriptor(); - }, + for (i = 0; i < newPaths.length; i++) { + paths.push(newPaths[i]); + } + } + }]); - // Assignments are argument entities for calls. - // They are present in ie filter properties as shown below. - // - // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) - // - - assignment: function () { - var key, value; - parserInput.save(); - key = parserInput.$re(/^\w+(?=\s?=)/i); - if (!key) { - parserInput.restore(); - return; - } - if (!parserInput.$char('=')) { - parserInput.restore(); - return; - } - value = parsers.entity(); - if (value) { - parserInput.forget(); - return new(tree.Assignment)(key, value); - } else { - parserInput.restore(); - } - }, + return Ruleset; + }(Node); - // - // Parse url() tokens - // - // We use a specific rule for urls, because they don't really behave like - // standard function calls. The difference is that the argument doesn't have - // to be enclosed within a string, so it can't be parsed as an Expression. - // - url: function () { - var value, index = parserInput.i; - - parserInput.autoCommentAbsorb = false; - - if (!parserInput.$str('url(')) { - parserInput.autoCommentAbsorb = true; - return; - } + Ruleset.prototype.type = 'Ruleset'; + Ruleset.prototype.isRuleset = true; - value = this.quoted() || this.variable() || this.property() || - parserInput.$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ''; + var AtRule = + /*#__PURE__*/ + function (_Node) { + _inherits(AtRule, _Node); - parserInput.autoCommentAbsorb = true; + function AtRule(name, value, rules, index, currentFileInfo, debugInfo, isRooted, visibilityInfo) { + var _this; - expectChar(')'); + _classCallCheck(this, AtRule); - return new(tree.URL)((value.value != null || - value instanceof tree.Variable || - value instanceof tree.Property) ? - value : new(tree.Anonymous)(value, index), index, fileInfo); - }, + _this = _possibleConstructorReturn(this, _getPrototypeOf(AtRule).call(this)); + var i; + _this.name = name; + _this.value = value instanceof Node ? value : value ? new Anonymous(value) : value; - // - // A Variable entity, such as `@fink`, in - // - // width: @fink + 2px - // - // We use a different parser for variable definitions, - // see `parsers.variable`. - // - variable: function () { - var ch, name, index = parserInput.i; - - parserInput.save(); - if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^@@?[\w-]+/))) { - ch = parserInput.currentChar(); - if (ch === '(' || ch === '[' && !parserInput.prevChar().match(/^\s/)) { - // this may be a VariableCall lookup - var result = parsers.variableCall(name); - if (result) { - parserInput.forget(); - return result; - } - } - parserInput.forget(); - return new(tree.Variable)(name, index, fileInfo); - } - parserInput.restore(); - }, + if (rules) { + if (Array.isArray(rules)) { + _this.rules = rules; + } else { + _this.rules = [rules]; + _this.rules[0].selectors = new Selector([], null, null, index, currentFileInfo).createEmptySelectors(); + } - // A variable entity using the protective {} e.g. @{var} - variableCurly: function () { - var curly, index = parserInput.i; + for (i = 0; i < _this.rules.length; i++) { + _this.rules[i].allowImports = true; + } - if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\{([\w-]+)\}/))) { - return new(tree.Variable)('@' + curly[1], index, fileInfo); - } - }, - // - // A Property accessor, such as `$color`, in - // - // background-color: $color - // - property: function () { - var name, index = parserInput.i; - - if (parserInput.currentChar() === '$' && (name = parserInput.$re(/^\$[\w-]+/))) { - return new(tree.Property)(name, index, fileInfo); - } - }, + _this.setParent(_this.rules, _assertThisInitialized(_this)); + } - // A property entity useing the protective {} e.g. ${prop} - propertyCurly: function () { - var curly, index = parserInput.i; + _this._index = index; + _this._fileInfo = currentFileInfo; + _this.debugInfo = debugInfo; + _this.isRooted = isRooted || false; - if (parserInput.currentChar() === '$' && (curly = parserInput.$re(/^\$\{([\w-]+)\}/))) { - return new(tree.Property)('$' + curly[1], index, fileInfo); - } - }, - // - // A Hexadecimal color - // - // #4F3C2F - // - // `rgb` and `hsl` colors are parsed through the `entities.call` parser. - // - color: function () { - var rgb; - - if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})/))) { - return new(tree.Color)(rgb[1], undefined, rgb[0]); - } - }, + _this.copyVisibilityInfo(visibilityInfo); - colorKeyword: function () { - parserInput.save(); - var autoCommentAbsorb = parserInput.autoCommentAbsorb; - parserInput.autoCommentAbsorb = false; - var k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/); - parserInput.autoCommentAbsorb = autoCommentAbsorb; - if (!k) { - parserInput.forget(); - return; - } - parserInput.restore(); - var color = tree.Color.fromKeyword(k); - if (color) { - parserInput.$str(k); - return color; - } - }, + _this.allowRoot = true; + return _this; + } - // - // A Dimension, that is, a number and a unit - // - // 0.5em 95% - // - dimension: function () { - if (parserInput.peekNotNumeric()) { - return; - } + _createClass(AtRule, [{ + key: "accept", + value: function accept(visitor) { + var value = this.value; + var rules = this.rules; - var value = parserInput.$re(/^([+-]?\d*\.?\d+)(%|[a-z_]+)?/i); - if (value) { - return new(tree.Dimension)(value[1], value[2]); - } - }, + if (rules) { + this.rules = visitor.visitArray(rules); + } - // - // A unicode descriptor, as is used in unicode-range - // - // U+0?? or U+00A1-00A9 - // - unicodeDescriptor: function () { - var ud; - - ud = parserInput.$re(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/); - if (ud) { - return new(tree.UnicodeDescriptor)(ud[0]); - } - }, + if (value) { + this.value = visitor.visit(value); + } + } + }, { + key: "isRulesetLike", + value: function isRulesetLike() { + return this.rules || !this.isCharset(); + } + }, { + key: "isCharset", + value: function isCharset() { + return '@charset' === this.name; + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + var value = this.value; + var rules = this.rules; + output.add(this.name, this.fileInfo(), this.getIndex()); - // - // JavaScript code to be evaluated - // - // `window.location.href` - // - javascript: function () { - var js, index = parserInput.i; + if (value) { + output.add(' '); + value.genCSS(context, output); + } - parserInput.save(); + if (rules) { + this.outputRuleset(context, output, rules); + } else { + output.add(';'); + } + } + }, { + key: "eval", + value: function _eval(context) { + var mediaPathBackup; + var mediaBlocksBackup; + var value = this.value; + var rules = this.rules; // media stored inside other atrule should not bubble over it + // backpup media bubbling information + + mediaPathBackup = context.mediaPath; + mediaBlocksBackup = context.mediaBlocks; // deleted media bubbling information - var escape = parserInput.$char('~'); - var jsQuote = parserInput.$char('`'); + context.mediaPath = []; + context.mediaBlocks = []; - if (!jsQuote) { - parserInput.restore(); - return; - } + if (value) { + value = value.eval(context); + } - js = parserInput.$re(/^[^`]*`/); - if (js) { - parserInput.forget(); - return new(tree.JavaScript)(js.substr(0, js.length - 1), Boolean(escape), index, fileInfo); - } - parserInput.restore('invalid javascript definition'); - } - }, + if (rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + rules = [rules[0].eval(context)]; + rules[0].root = true; + } // restore media bubbling information - // - // The variable part of a variable definition. Used in the `rule` parser - // - // @fink: - // - variable: function () { - var name; - if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) { return name[1]; } - }, + context.mediaPath = mediaPathBackup; + context.mediaBlocks = mediaBlocksBackup; + return new AtRule(this.name, value, rules, this.getIndex(), this.fileInfo(), this.debugInfo, this.isRooted, this.visibilityInfo()); + } + }, { + key: "variable", + value: function variable(name) { + if (this.rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + return Ruleset.prototype.variable.call(this.rules[0], name); + } + } + }, { + key: "find", + value: function find() { + if (this.rules) { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } - // - // Call a variable value to retrieve a detached ruleset - // or a value from a detached ruleset's rules. - // - // @fink(); - // @fink; - // color: @fink[@color]; - // - variableCall: function (parsedName) { - var lookups, important, i = parserInput.i, - inValue = !!parsedName, name = parsedName; + // assuming that there is only one rule at this point - that is how parser constructs the rule + return Ruleset.prototype.find.apply(this.rules[0], args); + } + } + }, { + key: "rulesets", + value: function rulesets() { + if (this.rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + return Ruleset.prototype.rulesets.apply(this.rules[0]); + } + } + }, { + key: "outputRuleset", + value: function outputRuleset(context, output, rules) { + var ruleCnt = rules.length; + var i; + context.tabLevel = (context.tabLevel | 0) + 1; // Compressed - parserInput.save(); + if (context.compress) { + output.add('{'); - if (name || (parserInput.currentChar() === '@' - && (name = parserInput.$re(/^(@[\w-]+)(\(\s*\))?/)))) { + for (i = 0; i < ruleCnt; i++) { + rules[i].genCSS(context, output); + } - lookups = this.mixin.ruleLookups(); + output.add('}'); + context.tabLevel--; + return; + } // Non-compressed - if (!lookups && ((inValue && parserInput.$str('()') !== '()') || (name[2] !== '()'))) { - parserInput.restore('Missing \'[...]\' lookup in variable call'); - return; - } - if (!inValue) { - name = name[1]; - } + var tabSetStr = "\n".concat(Array(context.tabLevel).join(' ')); + var tabRuleStr = "".concat(tabSetStr, " "); - if (lookups && parsers.important()) { - important = true; - } + if (!ruleCnt) { + output.add(" {".concat(tabSetStr, "}")); + } else { + output.add(" {".concat(tabRuleStr)); + rules[0].genCSS(context, output); - var call = new tree.VariableCall(name, i, fileInfo); - if (!inValue && parsers.end()) { - parserInput.forget(); - return call; - } - else { - parserInput.forget(); - return new tree.NamespaceValue(call, lookups, important, i, fileInfo); - } - } + for (i = 1; i < ruleCnt; i++) { + output.add(tabRuleStr); + rules[i].genCSS(context, output); + } - parserInput.restore(); - }, + output.add("".concat(tabSetStr, "}")); + } - // - // extend syntax - used to extend selectors - // - extend: function(isRule) { - var elements, e, index = parserInput.i, option, extendList, extend; + context.tabLevel--; + } + }]); - if (!parserInput.$str(isRule ? '&:extend(' : ':extend(')) { - return; - } + return AtRule; + }(Node); - do { - option = null; - elements = null; - while (!(option = parserInput.$re(/^(all)(?=\s*(\)|,))/))) { - e = this.element(); - if (!e) { - break; - } - if (elements) { - elements.push(e); - } else { - elements = [ e ]; - } - } + AtRule.prototype.type = 'AtRule'; - option = option && option[1]; - if (!elements) { - error('Missing target selector for :extend().'); - } - extend = new(tree.Extend)(new(tree.Selector)(elements), option, index, fileInfo); - if (extendList) { - extendList.push(extend); - } else { - extendList = [ extend ]; - } - } while (parserInput.$char(',')); + var DetachedRuleset = + /*#__PURE__*/ + function (_Node) { + _inherits(DetachedRuleset, _Node); - expect(/^\)/); + function DetachedRuleset(ruleset, frames) { + var _this; - if (isRule) { - expect(/^;/); - } + _classCallCheck(this, DetachedRuleset); - return extendList; - }, + _this = _possibleConstructorReturn(this, _getPrototypeOf(DetachedRuleset).call(this)); + _this.ruleset = ruleset; + _this.frames = frames; - // - // extendRule - used in a rule to extend all the parent selectors - // - extendRule: function() { - return this.extend(true); - }, + _this.setParent(_this.ruleset, _assertThisInitialized(_this)); - // - // Mixins - // - mixin: { - // - // A Mixin call, with an optional argument list - // - // #mixins > .square(#fff); - // #mixins.square(#fff); - // .rounded(4px, black); - // .button; - // - // We can lookup / return a value using the lookup syntax: - // - // color: #mixin.square(#fff)[@color]; - // - // The `while` loop is there because mixins can be - // namespaced, but we only support the child and descendant - // selector for now. - // - call: function (inValue, getLookup) { - var s = parserInput.currentChar(), important = false, lookups, - index = parserInput.i, elements, args, hasParens; - - if (s !== '.' && s !== '#') { return; } - - parserInput.save(); // stop us absorbing part of an invalid selector - - elements = this.elements(); - - if (elements) { - if (parserInput.$char('(')) { - args = this.args(true).args; - expectChar(')'); - hasParens = true; - } - - if (getLookup !== false) { - lookups = this.ruleLookups(); - } - if (getLookup === true && !lookups) { - parserInput.restore(); - return; - } - - if (inValue && !lookups && !hasParens) { - // This isn't a valid in-value mixin call - parserInput.restore(); - return; - } - - if (!inValue && parsers.important()) { - important = true; - } - - if (inValue || parsers.end()) { - parserInput.forget(); - var mixin = new(tree.mixin.Call)(elements, args, index, fileInfo, !lookups && important); - if (lookups) { - return new tree.NamespaceValue(mixin, lookups, important); - } - else { - return mixin; - } - } - } + return _this; + } - parserInput.restore(); - }, - /** - * Matching elements for mixins - * (Start with . or # and can have > ) - */ - elements: function() { - var elements, e, c, elem, elemIndex, - re = /^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/; - while (true) { - elemIndex = parserInput.i; - e = parserInput.$re(re); - - if (!e) { - break; - } - elem = new(tree.Element)(c, e, false, elemIndex, fileInfo); - if (elements) { - elements.push(elem); - } else { - elements = [ elem ]; - } - c = parserInput.$char('>'); - } - return elements; - }, - args: function (isCall) { - var entities = parsers.entities, - returner = { args:null, variadic: false }, - expressions = [], argsSemiColon = [], argsComma = [], - isSemiColonSeparated, expressionContainsNamed, name, nameLoop, - value, arg, expand, hasSep = true; - - parserInput.save(); - - while (true) { - if (isCall) { - arg = parsers.detachedRuleset() || parsers.expression(); - } else { - parserInput.commentStore.length = 0; - if (parserInput.$str('...')) { - returner.variadic = true; - if (parserInput.$char(';') && !isSemiColonSeparated) { - isSemiColonSeparated = true; - } - (isSemiColonSeparated ? argsSemiColon : argsComma) - .push({ variadic: true }); - break; - } - arg = entities.variable() || entities.property() || entities.literal() || entities.keyword() || this.call(true); - } - - if (!arg || !hasSep) { - break; - } - - nameLoop = null; - if (arg.throwAwayComments) { - arg.throwAwayComments(); - } - value = arg; - var val = null; - - if (isCall) { - // Variable - if (arg.value && arg.value.length == 1) { - val = arg.value[0]; - } - } else { - val = arg; - } - - if (val && (val instanceof tree.Variable || val instanceof tree.Property)) { - if (parserInput.$char(':')) { - if (expressions.length > 0) { - if (isSemiColonSeparated) { - error('Cannot mix ; and , as delimiter types'); - } - expressionContainsNamed = true; - } - - value = parsers.detachedRuleset() || parsers.expression(); - - if (!value) { - if (isCall) { - error('could not understand value for named argument'); - } else { - parserInput.restore(); - returner.args = []; - return returner; - } - } - nameLoop = (name = val.name); - } else if (parserInput.$str('...')) { - if (!isCall) { - returner.variadic = true; - if (parserInput.$char(';') && !isSemiColonSeparated) { - isSemiColonSeparated = true; - } - (isSemiColonSeparated ? argsSemiColon : argsComma) - .push({ name: arg.name, variadic: true }); - break; - } else { - expand = true; - } - } else if (!isCall) { - name = nameLoop = val.name; - value = null; - } - } - - if (value) { - expressions.push(value); - } - - argsComma.push({ name:nameLoop, value:value, expand:expand }); - - if (parserInput.$char(',')) { - hasSep = true; - continue; - } - hasSep = parserInput.$char(';') === ';'; - - if (hasSep || isSemiColonSeparated) { - - if (expressionContainsNamed) { - error('Cannot mix ; and , as delimiter types'); - } - - isSemiColonSeparated = true; - - if (expressions.length > 1) { - value = new(tree.Value)(expressions); - } - argsSemiColon.push({ name:name, value:value, expand:expand }); - - name = null; - expressions = []; - expressionContainsNamed = false; - } - } + _createClass(DetachedRuleset, [{ + key: "accept", + value: function accept(visitor) { + this.ruleset = visitor.visit(this.ruleset); + } + }, { + key: "eval", + value: function _eval(context) { + var frames = this.frames || copyArray(context.frames); + return new DetachedRuleset(this.ruleset, frames); + } + }, { + key: "callEval", + value: function callEval(context) { + return this.ruleset.eval(this.frames ? new contexts.Eval(context, this.frames.concat(context.frames)) : context); + } + }]); - parserInput.forget(); - returner.args = isSemiColonSeparated ? argsSemiColon : argsComma; - return returner; - }, - // - // A Mixin definition, with a list of parameters - // - // .rounded (@radius: 2px, @color) { - // ... - // } - // - // Until we have a finer grained state-machine, we have to - // do a look-ahead, to make sure we don't have a mixin call. - // See the `rule` function for more information. - // - // We start by matching `.rounded (`, and then proceed on to - // the argument list, which has optional default values. - // We store the parameters in `params`, with a `value` key, - // if there is a value, such as in the case of `@radius`. - // - // Once we've got our params list, and a closing `)`, we parse - // the `{...}` block. - // - definition: function () { - var name, params = [], match, ruleset, cond, variadic = false; - if ((parserInput.currentChar() !== '.' && parserInput.currentChar() !== '#') || - parserInput.peek(/^[^{]*\}/)) { - return; - } + return DetachedRuleset; + }(Node); - parserInput.save(); + DetachedRuleset.prototype.type = 'DetachedRuleset'; + DetachedRuleset.prototype.evalFirst = true; - match = parserInput.$re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/); - if (match) { - name = match[1]; + var Unit = + /*#__PURE__*/ + function (_Node) { + _inherits(Unit, _Node); - var argInfo = this.args(false); - params = argInfo.args; - variadic = argInfo.variadic; + function Unit(numerator, denominator, backupUnit) { + var _this; - // .mixincall("@{a}"); - // looks a bit like a mixin definition.. - // also - // .mixincall(@a: {rule: set;}); - // so we have to be nice and restore - if (!parserInput.$char(')')) { - parserInput.restore('Missing closing \')\''); - return; - } + _classCallCheck(this, Unit); - parserInput.commentStore.length = 0; + _this = _possibleConstructorReturn(this, _getPrototypeOf(Unit).call(this)); + _this.numerator = numerator ? copyArray(numerator).sort() : []; + _this.denominator = denominator ? copyArray(denominator).sort() : []; - if (parserInput.$str('when')) { // Guard - cond = expect(parsers.conditions, 'expected condition'); - } + if (backupUnit) { + _this.backupUnit = backupUnit; + } else if (numerator && numerator.length) { + _this.backupUnit = numerator[0]; + } - ruleset = parsers.block(); + return _this; + } - if (ruleset) { - parserInput.forget(); - return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); - } else { - parserInput.restore(); - } - } else { - parserInput.forget(); - } - }, - - ruleLookups: function() { - var rule, args, lookups = []; + _createClass(Unit, [{ + key: "clone", + value: function clone() { + return new Unit(copyArray(this.numerator), copyArray(this.denominator), this.backupUnit); + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + // Dimension checks the unit is singular and throws an error if in strict math mode. + var strictUnits = context && context.strictUnits; + + if (this.numerator.length === 1) { + output.add(this.numerator[0]); // the ideal situation + } else if (!strictUnits && this.backupUnit) { + output.add(this.backupUnit); + } else if (!strictUnits && this.denominator.length) { + output.add(this.denominator[0]); + } + } + }, { + key: "toString", + value: function toString() { + var i; + var returnStr = this.numerator.join('*'); - if (parserInput.currentChar() !== '[') { - return; - } - - while (true) { - parserInput.save(); - args = null; - rule = this.lookupValue(); - if (!rule && rule !== '') { - parserInput.restore(); - break; - } - lookups.push(rule); - parserInput.forget(); - } - if (lookups.length > 0) { - return lookups; - } - }, - - lookupValue: function() { - parserInput.save(); - - if (!parserInput.$char('[')) { - parserInput.restore(); - return; - } - - var name = parserInput.$re(/^(?:[@$]{0,2})[_a-zA-Z0-9-]*/); - - if (!parserInput.$char(']')) { - parserInput.restore(); - return; - } - - if (name || name === '') { - parserInput.forget(); - return name; - } - - parserInput.restore(); - } - }, - // - // Entities are the smallest recognized token, - // and can be found inside a rule's value. - // - entity: function () { - var entities = this.entities; + for (i = 0; i < this.denominator.length; i++) { + returnStr += "/".concat(this.denominator[i]); + } - return this.comment() || entities.literal() || entities.variable() || entities.url() || - entities.property() || entities.call() || entities.keyword() || this.mixin.call(true) || - entities.javascript(); - }, + return returnStr; + } + }, { + key: "compare", + value: function compare(other) { + return this.is(other.toString()) ? 0 : undefined; + } + }, { + key: "is", + value: function is(unitString) { + return this.toString().toUpperCase() === unitString.toUpperCase(); + } + }, { + key: "isLength", + value: function isLength() { + return RegExp('^(px|em|ex|ch|rem|in|cm|mm|pc|pt|ex|vw|vh|vmin|vmax)$', 'gi').test(this.toCSS()); + } + }, { + key: "isEmpty", + value: function isEmpty() { + return this.numerator.length === 0 && this.denominator.length === 0; + } + }, { + key: "isSingular", + value: function isSingular() { + return this.numerator.length <= 1 && this.denominator.length === 0; + } + }, { + key: "map", + value: function map(callback) { + var i; - // - // A Declaration terminator. Note that we use `peek()` to check for '}', - // because the `block` rule will be expecting it, but we still need to make sure - // it's there, if ';' was omitted. - // - end: function () { - return parserInput.$char(';') || parserInput.peek('}'); - }, + for (i = 0; i < this.numerator.length; i++) { + this.numerator[i] = callback(this.numerator[i], false); + } - // - // IE's alpha function - // - // alpha(opacity=88) - // - ieAlpha: function () { - var value; + for (i = 0; i < this.denominator.length; i++) { + this.denominator[i] = callback(this.denominator[i], true); + } + } + }, { + key: "usedUnits", + value: function usedUnits() { + var group; + var result = {}; + var mapUnit; + var groupName; + + mapUnit = function mapUnit(atomicUnit) { + /* jshint loopfunc:true */ + if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { + result[groupName] = atomicUnit; + } - // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 - if (!parserInput.$re(/^opacity=/i)) { return; } - value = parserInput.$re(/^\d+/); - if (!value) { - value = expect(parsers.entities.variable, 'Could not parse alpha'); - value = '@{' + value.name.slice(1) + '}'; - } - expectChar(')'); - return new tree.Quoted('', 'alpha(opacity=' + value + ')'); - }, + return atomicUnit; + }; - // - // A Selector Element - // - // div - // + h1 - // #socks - // input[type="text"] - // - // Elements are the building blocks for Selectors, - // they are made out of a `Combinator` (see combinator rule), - // and an element name, such as a tag a class, or `*`. - // - element: function () { - var e, c, v, index = parserInput.i; - - c = this.combinator(); - - e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) || - parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || - parserInput.$char('*') || parserInput.$char('&') || this.attribute() || - parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[\.#:](?=@)/) || - this.entities.variableCurly(); - - if (!e) { - parserInput.save(); - if (parserInput.$char('(')) { - if ((v = this.selector(false)) && parserInput.$char(')')) { - e = new(tree.Paren)(v); - parserInput.forget(); - } else { - parserInput.restore('Missing closing \')\''); - } - } else { - parserInput.forget(); - } - } + for (groupName in unitConversions) { + if (unitConversions.hasOwnProperty(groupName)) { + group = unitConversions[groupName]; + this.map(mapUnit); + } + } - if (e) { return new(tree.Element)(c, e, e instanceof tree.Variable, index, fileInfo); } - }, + return result; + } + }, { + key: "cancel", + value: function cancel() { + var counter = {}; + var atomicUnit; + var i; - // - // Combinators combine elements together, in a Selector. - // - // Because our parser isn't white-space sensitive, special care - // has to be taken, when parsing the descendant combinator, ` `, - // as it's an empty space. We have to check the previous character - // in the input, to see if it's a ` ` character. More info on how - // we deal with this in *combinator.js*. - // - combinator: function () { - var c = parserInput.currentChar(); - - if (c === '/') { - parserInput.save(); - var slashedCombinator = parserInput.$re(/^\/[a-z]+\//i); - if (slashedCombinator) { - parserInput.forget(); - return new(tree.Combinator)(slashedCombinator); - } - parserInput.restore(); - } + for (i = 0; i < this.numerator.length; i++) { + atomicUnit = this.numerator[i]; + counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; + } - if (c === '>' || c === '+' || c === '~' || c === '|' || c === '^') { - parserInput.i++; - if (c === '^' && parserInput.currentChar() === '^') { - c = '^^'; - parserInput.i++; - } - while (parserInput.isWhitespace()) { parserInput.i++; } - return new(tree.Combinator)(c); - } else if (parserInput.isWhitespace(-1)) { - return new(tree.Combinator)(' '); - } else { - return new(tree.Combinator)(null); - } - }, - // - // A CSS Selector - // with less extensions e.g. the ability to extend and guard - // - // .class > div + h1 - // li a:hover - // - // Selectors are made out of one or more Elements, see above. - // - selector: function (isLess) { - var index = parserInput.i, elements, extendList, c, e, allExtends, when, condition; - isLess = isLess !== false; - while ((isLess && (extendList = this.extend())) || (isLess && (when = parserInput.$str('when'))) || (e = this.element())) { - if (when) { - condition = expect(this.conditions, 'expected condition'); - } else if (condition) { - error('CSS guard can only be used at the end of selector'); - } else if (extendList) { - if (allExtends) { - allExtends = allExtends.concat(extendList); - } else { - allExtends = extendList; - } - } else { - if (allExtends) { error('Extend can only be used at the end of selector'); } - c = parserInput.currentChar(); - if (elements) { - elements.push(e); - } else { - elements = [ e ]; - } - e = null; - } - if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { - break; - } - } + for (i = 0; i < this.denominator.length; i++) { + atomicUnit = this.denominator[i]; + counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; + } - if (elements) { return new(tree.Selector)(elements, allExtends, condition, index, fileInfo); } - if (allExtends) { error('Extend must be used to extend a selector, it cannot be used on its own'); } - }, - selectors: function () { - var s, selectors; - while (true) { - s = this.selector(); - if (!s) { - break; - } - if (selectors) { - selectors.push(s); - } else { - selectors = [ s ]; - } - parserInput.commentStore.length = 0; - if (s.condition && selectors.length > 1) { - error("Guards are only currently allowed on a single selector."); - } - if (!parserInput.$char(',')) { break; } - if (s.condition) { - error("Guards are only currently allowed on a single selector."); - } - parserInput.commentStore.length = 0; - } - return selectors; - }, - attribute: function () { - if (!parserInput.$char('[')) { return; } + this.numerator = []; + this.denominator = []; - var entities = this.entities, - key, val, op; + for (atomicUnit in counter) { + if (counter.hasOwnProperty(atomicUnit)) { + var count = counter[atomicUnit]; - if (!(key = entities.variableCurly())) { - key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/); - } + if (count > 0) { + for (i = 0; i < count; i++) { + this.numerator.push(atomicUnit); + } + } else if (count < 0) { + for (i = 0; i < -count; i++) { + this.denominator.push(atomicUnit); + } + } + } + } - op = parserInput.$re(/^[|~*$^]?=/); - if (op) { - val = entities.quoted() || parserInput.$re(/^[0-9]+%/) || parserInput.$re(/^[\w-]+/) || entities.variableCurly(); - } + this.numerator.sort(); + this.denominator.sort(); + } + }]); - expectChar(']'); + return Unit; + }(Node); - return new(tree.Attribute)(key, op, val); - }, + Unit.prototype.type = 'Unit'; - // - // The `block` rule is used by `ruleset` and `mixin.definition`. - // It's a wrapper around the `primary` rule, with added `{}`. - // - block: function () { - var content; - if (parserInput.$char('{') && (content = this.primary()) && parserInput.$char('}')) { - return content; - } - }, + // A number with a unit + // - blockRuleset: function() { - var block = this.block(); + var Dimension = + /*#__PURE__*/ + function (_Node) { + _inherits(Dimension, _Node); - if (block) { - block = new tree.Ruleset(null, block); - } - return block; - }, - - detachedRuleset: function() { - var argInfo, params, variadic; - - parserInput.save(); - if (parserInput.$re(/^[.#]\(/)) { - /** - * DR args currently only implemented for each() function, and not - * yet settable as `@dr: #(@arg) {}` - * This should be done when DRs are merged with mixins. - * See: https://github.com/less/less-meta/issues/16 - */ - argInfo = this.mixin.args(false); - params = argInfo.args; - variadic = argInfo.variadic; - if (!parserInput.$char(')')) { - parserInput.restore(); - return; - } - } - var blockRuleset = this.blockRuleset(); - if (blockRuleset) { - parserInput.forget(); - if (params) { - return new tree.mixin.Definition(null, params, blockRuleset, null, variadic); - } - return new tree.DetachedRuleset(blockRuleset); - } - parserInput.restore(); - }, + function Dimension(value, unit) { + var _this; - // - // div, .class, body > p {...} - // - ruleset: function () { - var selectors, rules, debugInfo; + _classCallCheck(this, Dimension); - parserInput.save(); + _this = _possibleConstructorReturn(this, _getPrototypeOf(Dimension).call(this)); + _this.value = parseFloat(value); - if (context.dumpLineNumbers) { - debugInfo = getDebugInfo(parserInput.i); - } + if (isNaN(_this.value)) { + throw new Error('Dimension is not a number.'); + } - selectors = this.selectors(); + _this.unit = unit && unit instanceof Unit ? unit : new Unit(unit ? [unit] : undefined); - if (selectors && (rules = this.block())) { - parserInput.forget(); - var ruleset = new(tree.Ruleset)(selectors, rules, context.strictImports); - if (context.dumpLineNumbers) { - ruleset.debugInfo = debugInfo; - } - return ruleset; - } else { - parserInput.restore(); - } - }, - declaration: function () { - var name, value, index = parserInput.i, hasDR, - c = parserInput.currentChar(), important, merge, isVariable; + _this.setParent(_this.unit, _assertThisInitialized(_this)); - if (c === '.' || c === '#' || c === '&' || c === ':') { return; } + return _this; + } - parserInput.save(); + _createClass(Dimension, [{ + key: "accept", + value: function accept(visitor) { + this.unit = visitor.visit(this.unit); + } + }, { + key: "eval", + value: function _eval(context) { + return this; + } + }, { + key: "toColor", + value: function toColor() { + return new Color([this.value, this.value, this.value]); + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + if (context && context.strictUnits && !this.unit.isSingular()) { + throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: ".concat(this.unit.toString())); + } - name = this.variable() || this.ruleProperty(); - if (name) { - isVariable = typeof name === 'string'; + var value = this.fround(context, this.value); + var strValue = String(value); - if (isVariable) { - value = this.detachedRuleset(); - if (value) { - hasDR = true; - } - } + if (value !== 0 && value < 0.000001 && value > -0.000001) { + // would be output 1e-6 etc. + strValue = value.toFixed(20).replace(/0+$/, ''); + } - parserInput.commentStore.length = 0; - if (!value) { - // a name returned by this.ruleProperty() is always an array of the form: - // [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"] - // where each item is a tree.Keyword or tree.Variable - merge = !isVariable && name.length > 1 && name.pop().value; - - // Custom property values get permissive parsing - if (name[0].value && name[0].value.slice(0, 2) === '--') { - value = this.permissiveValue(); - } - // Try to store values as anonymous - // If we need the value later we'll re-parse it in ruleset.parseValue - else { - value = this.anonymousValue(); - } - if (value) { - parserInput.forget(); - // anonymous values absorb the end ';' which is required for them to work - return new (tree.Declaration)(name, value, false, merge, index, fileInfo); - } - - if (!value) { - value = this.value(); - } - - if (value) { - important = this.important(); - } else if (isVariable) { - // As a last resort, try permissiveValue - value = this.permissiveValue(); - } - } + if (context && context.compress) { + // Zero values doesn't need a unit + if (value === 0 && this.unit.isLength()) { + output.add(strValue); + return; + } // Float values doesn't need a leading zero - if (value && (this.end() || hasDR)) { - parserInput.forget(); - return new (tree.Declaration)(name, value, important, merge, index, fileInfo); - } - else { - parserInput.restore(); - } - } else { - parserInput.restore(); - } - }, - anonymousValue: function () { - var index = parserInput.i; - var match = parserInput.$re(/^([^.#@\$+\/'"*`(;{}-]*);/); - if (match) { - return new(tree.Anonymous)(match[1], index); - } - }, - /** - * Used for custom properties, at-rules, and variables (as fallback) - * Parses almost anything inside of {} [] () "" blocks - * until it reaches outer-most tokens. - * - * First, it will try to parse comments and entities to reach - * the end. This is mostly like the Expression parser except no - * math is allowed. - */ - permissiveValue: function (untilTokens) { - var i, e, done, value, - tok = untilTokens || ';', - index = parserInput.i, result = []; - - function testCurrentChar() { - var char = parserInput.currentChar(); - if (typeof tok === 'string') { - return char === tok; - } else { - return tok.test(char); - } - } - if (testCurrentChar()) { - return; - } - value = []; - do { - e = this.comment(); - if (e) { - value.push(e); - continue; - } - e = this.entity(); - if (e) { - value.push(e); - } - } while (e); - - done = testCurrentChar(); - - if (value.length > 0) { - value = new(tree.Expression)(value); - if (done) { - return value; - } - else { - result.push(value); - } - // Preserve space before $parseUntil as it will not - if (parserInput.prevChar() === ' ') { - result.push(new tree.Anonymous(' ', index)); - } - } - parserInput.save(); - - value = parserInput.$parseUntil(tok); - if (value) { - if (typeof value === 'string') { - error('Expected \'' + value + '\'', 'Parse'); - } - if (value.length === 1 && value[0] === ' ') { - parserInput.forget(); - return new tree.Anonymous('', index); - } - var item; - for (i = 0; i < value.length; i++) { - item = value[i]; - if (Array.isArray(item)) { - // Treat actual quotes as normal quoted values - result.push(new tree.Quoted(item[0], item[1], true, index, fileInfo)); - } - else { - if (i === value.length - 1) { - item = item.trim(); - } - // Treat like quoted values, but replace vars like unquoted expressions - var quote = new tree.Quoted('\'', item, true, index, fileInfo); - quote.variableRegex = /@([\w-]+)/g; - quote.propRegex = /\$([\w-]+)/g; - result.push(quote); - } - } - parserInput.forget(); - return new tree.Expression(result, true); - } - parserInput.restore(); - }, + if (value > 0 && value < 1) { + strValue = strValue.substr(1); + } + } - // - // An @import atrule - // - // @import "lib"; - // - // Depending on our environment, importing is done differently: - // In the browser, it's an XHR request, in Node, it would be a - // file-system operation. The function used for importing is - // stored in `import`, which we pass to the Import constructor. - // - 'import': function () { - var path, features, index = parserInput.i; + output.add(strValue); + this.unit.genCSS(context, output); + } // In an operation between two Dimensions, + // we default to the first Dimension's unit, + // so `1px + 2` will yield `3px`. - var dir = parserInput.$re(/^@import?\s+/); + }, { + key: "operate", + value: function operate(context, op, other) { + /* jshint noempty:false */ + var value = this._operate(context, op, this.value, other.value); - if (dir) { - var options = (dir ? this.importOptions() : null) || {}; + var unit = this.unit.clone(); - if ((path = this.entities.quoted() || this.entities.url())) { - features = this.mediaFeatures(); + if (op === '+' || op === '-') { + if (unit.numerator.length === 0 && unit.denominator.length === 0) { + unit = other.unit.clone(); - if (!parserInput.$char(';')) { - parserInput.i = index; - error('missing semi-colon or unrecognised media features on import'); - } - features = features && new(tree.Value)(features); - return new(tree.Import)(path, features, options, index, fileInfo); - } - else { - parserInput.i = index; - error('malformed import statement'); - } - } - }, - - importOptions: function() { - var o, options = {}, optionName, value; - - // list of options, surrounded by parens - if (!parserInput.$char('(')) { return null; } - do { - o = this.importOption(); - if (o) { - optionName = o; - value = true; - switch (optionName) { - case 'css': - optionName = 'less'; - value = false; - break; - case 'once': - optionName = 'multiple'; - value = false; - break; - } - options[optionName] = value; - if (!parserInput.$char(',')) { break; } - } - } while (o); - expectChar(')'); - return options; - }, + if (this.unit.backupUnit) { + unit.backupUnit = this.unit.backupUnit; + } + } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) ; else { + other = other.convertTo(this.unit.usedUnits()); - importOption: function() { - var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/); - if (opt) { - return opt[1]; - } - }, - - mediaFeature: function () { - var entities = this.entities, nodes = [], e, p; - parserInput.save(); - do { - e = entities.keyword() || entities.variable() || entities.mixinLookup(); - if (e) { - nodes.push(e); - } else if (parserInput.$char('(')) { - p = this.property(); - e = this.value(); - if (parserInput.$char(')')) { - if (p && e) { - nodes.push(new(tree.Paren)(new(tree.Declaration)(p, e, null, null, parserInput.i, fileInfo, true))); - } else if (e) { - nodes.push(new(tree.Paren)(e)); - } else { - error('badly formed media feature definition'); - } - } else { - error('Missing closing \')\'', 'Parse'); - } - } - } while (e); + if (context.strictUnits && other.unit.toString() !== unit.toString()) { + throw new Error("Incompatible units. Change the units or use the unit function. " + "Bad units: '".concat(unit.toString(), "' and '").concat(other.unit.toString(), "'.")); + } - parserInput.forget(); - if (nodes.length > 0) { - return new(tree.Expression)(nodes); - } - }, - - mediaFeatures: function () { - var entities = this.entities, features = [], e; - do { - e = this.mediaFeature(); - if (e) { - features.push(e); - if (!parserInput.$char(',')) { break; } - } else { - e = entities.variable() || entities.mixinLookup(); - if (e) { - features.push(e); - if (!parserInput.$char(',')) { break; } - } - } - } while (e); + value = this._operate(context, op, this.value, other.value); + } + } else if (op === '*') { + unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); + unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); + unit.cancel(); + } else if (op === '/') { + unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); + unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); + unit.cancel(); + } - return features.length > 0 ? features : null; - }, + return new Dimension(value, unit); + } + }, { + key: "compare", + value: function compare(other) { + var a; + var b; - media: function () { - var features, rules, media, debugInfo, index = parserInput.i; + if (!(other instanceof Dimension)) { + return undefined; + } - if (context.dumpLineNumbers) { - debugInfo = getDebugInfo(index); - } + if (this.unit.isEmpty() || other.unit.isEmpty()) { + a = this; + b = other; + } else { + a = this.unify(); + b = other.unify(); - parserInput.save(); + if (a.unit.compare(b.unit) !== 0) { + return undefined; + } + } - if (parserInput.$str('@media')) { - features = this.mediaFeatures(); + return Node.numericCompare(a.value, b.value); + } + }, { + key: "unify", + value: function unify() { + return this.convertTo({ + length: 'px', + duration: 's', + angle: 'rad' + }); + } + }, { + key: "convertTo", + value: function convertTo(conversions) { + var value = this.value; + var unit = this.unit.clone(); + var i; + var groupName; + var group; + var targetUnit; + var derivedConversions = {}; + var applyUnit; + + if (typeof conversions === 'string') { + for (i in unitConversions) { + if (unitConversions[i].hasOwnProperty(conversions)) { + derivedConversions = {}; + derivedConversions[i] = conversions; + } + } - rules = this.block(); + conversions = derivedConversions; + } - if (!rules) { - error('media definitions require block statements after any features'); - } + applyUnit = function applyUnit(atomicUnit, denominator) { + /* jshint loopfunc:true */ + if (group.hasOwnProperty(atomicUnit)) { + if (denominator) { + value = value / (group[atomicUnit] / group[targetUnit]); + } else { + value = value * (group[atomicUnit] / group[targetUnit]); + } - parserInput.forget(); + return targetUnit; + } - media = new(tree.Media)(rules, features, index, fileInfo); - if (context.dumpLineNumbers) { - media.debugInfo = debugInfo; - } + return atomicUnit; + }; - return media; - } + for (groupName in conversions) { + if (conversions.hasOwnProperty(groupName)) { + targetUnit = conversions[groupName]; + group = unitConversions[groupName]; + unit.map(applyUnit); + } + } - parserInput.restore(); - }, + unit.cancel(); + return new Dimension(value, unit); + } + }]); - // + return Dimension; + }(Node); - // A @plugin directive, used to import plugins dynamically. - // - // @plugin (args) "lib"; - // - plugin: function () { - var path, args, options, - index = parserInput.i, - dir = parserInput.$re(/^@plugin?\s+/); - - if (dir) { - args = this.pluginArgs(); - - if (args) { - options = { - pluginArgs: args, - isPlugin: true - }; - } - else { - options = { isPlugin: true }; - } + Dimension.prototype.type = 'Dimension'; - if ((path = this.entities.quoted() || this.entities.url())) { + var MATH$1 = Math$1; - if (!parserInput.$char(';')) { - parserInput.i = index; - error('missing semi-colon on @plugin'); - } - return new(tree.Import)(path, null, options, index, fileInfo); - } - else { - parserInput.i = index; - error('malformed @plugin statement'); - } - } - }, - - pluginArgs: function() { - // list of options, surrounded by parens - parserInput.save(); - if (!parserInput.$char('(')) { - parserInput.restore(); - return null; - } - var args = parserInput.$re(/^\s*([^\);]+)\)\s*/); - if (args[1]) { - parserInput.forget(); - return args[1].trim(); - } - else { - parserInput.restore(); - return null; - } - }, + var Operation = + /*#__PURE__*/ + function (_Node) { + _inherits(Operation, _Node); - // - // A CSS AtRule - // - // @charset "utf-8"; - // - atrule: function () { - var index = parserInput.i, name, value, rules, nonVendorSpecificName, - hasIdentifier, hasExpression, hasUnknown, hasBlock = true, isRooted = true; + function Operation(op, operands, isSpaced) { + var _this; - if (parserInput.currentChar() !== '@') { return; } + _classCallCheck(this, Operation); - value = this['import']() || this.plugin() || this.media(); - if (value) { - return value; - } + _this = _possibleConstructorReturn(this, _getPrototypeOf(Operation).call(this)); + _this.op = op.trim(); + _this.operands = operands; + _this.isSpaced = isSpaced; + return _this; + } - parserInput.save(); + _createClass(Operation, [{ + key: "accept", + value: function accept(visitor) { + this.operands = visitor.visitArray(this.operands); + } + }, { + key: "eval", + value: function _eval(context) { + var a = this.operands[0].eval(context); + var b = this.operands[1].eval(context); + var op; - name = parserInput.$re(/^@[a-z-]+/); + if (context.isMathOn(this.op)) { + op = this.op === './' ? '/' : this.op; - if (!name) { return; } + if (a instanceof Dimension && b instanceof Color) { + a = a.toColor(); + } - nonVendorSpecificName = name; - if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { - nonVendorSpecificName = '@' + name.slice(name.indexOf('-', 2) + 1); - } + if (b instanceof Dimension && a instanceof Color) { + b = b.toColor(); + } - switch (nonVendorSpecificName) { - case '@charset': - hasIdentifier = true; - hasBlock = false; - break; - case '@namespace': - hasExpression = true; - hasBlock = false; - break; - case '@keyframes': - case '@counter-style': - hasIdentifier = true; - break; - case '@document': - case '@supports': - hasUnknown = true; - isRooted = false; - break; - default: - hasUnknown = true; - break; - } + if (!a.operate) { + if (a instanceof Operation && a.op === '/' && context.math === MATH$1.PARENS_DIVISION) { + return new Operation(this.op, [a, b], this.isSpaced); + } - parserInput.commentStore.length = 0; + throw { + type: 'Operation', + message: 'Operation on an invalid type' + }; + } - if (hasIdentifier) { - value = this.entity(); - if (!value) { - error('expected ' + name + ' identifier'); - } - } else if (hasExpression) { - value = this.expression(); - if (!value) { - error('expected ' + name + ' expression'); - } - } else if (hasUnknown) { - value = this.permissiveValue(/^[{;]/); - hasBlock = (parserInput.currentChar() === '{'); - if (!value) { - if (!hasBlock && parserInput.currentChar() !== ';') { - error(name + ' rule is missing block or ending semi-colon'); - } - } - else if (!value.value) { - value = null; - } - } + return a.operate(context, op, b); + } else { + return new Operation(this.op, [a, b], this.isSpaced); + } + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + this.operands[0].genCSS(context, output); - if (hasBlock) { - rules = this.blockRuleset(); - } + if (this.isSpaced) { + output.add(' '); + } - if (rules || (!hasBlock && value && parserInput.$char(';'))) { - parserInput.forget(); - return new (tree.AtRule)(name, value, rules, index, fileInfo, - context.dumpLineNumbers ? getDebugInfo(index) : null, - isRooted - ); - } + output.add(this.op); - parserInput.restore('at-rule options not recognised'); - }, + if (this.isSpaced) { + output.add(' '); + } - // - // A Value is a comma-delimited list of Expressions - // - // font-family: Baskerville, Georgia, serif; - // - // In a Rule, a Value represents everything after the `:`, - // and before the `;`. - // - value: function () { - var e, expressions = [], index = parserInput.i; - - do { - e = this.expression(); - if (e) { - expressions.push(e); - if (!parserInput.$char(',')) { break; } - } - } while (e); + this.operands[1].genCSS(context, output); + } + }]); - if (expressions.length > 0) { - return new(tree.Value)(expressions, index); - } - }, - important: function () { - if (parserInput.currentChar() === '!') { - return parserInput.$re(/^! *important/); - } - }, - sub: function () { - var a, e; - - parserInput.save(); - if (parserInput.$char('(')) { - a = this.addition(); - if (a && parserInput.$char(')')) { - parserInput.forget(); - e = new(tree.Expression)([a]); - e.parens = true; - return e; - } - parserInput.restore('Expected \')\''); - return; - } - parserInput.restore(); - }, - multiplication: function () { - var m, a, op, operation, isSpaced; - m = this.operand(); - if (m) { - isSpaced = parserInput.isWhitespace(-1); - while (true) { - if (parserInput.peek(/^\/[*\/]/)) { - break; - } + return Operation; + }(Node); - parserInput.save(); + Operation.prototype.type = 'Operation'; - op = parserInput.$char('/') || parserInput.$char('*') || parserInput.$str('./'); + var MATH$2 = Math$1; - if (!op) { parserInput.forget(); break; } + var Expression = + /*#__PURE__*/ + function (_Node) { + _inherits(Expression, _Node); - a = this.operand(); + function Expression(value, noSpacing) { + var _this; - if (!a) { parserInput.restore(); break; } - parserInput.forget(); + _classCallCheck(this, Expression); - m.parensInOp = true; - a.parensInOp = true; - operation = new(tree.Operation)(op, [operation || m, a], isSpaced); - isSpaced = parserInput.isWhitespace(-1); - } - return operation || m; - } - }, - addition: function () { - var m, a, op, operation, isSpaced; - m = this.multiplication(); - if (m) { - isSpaced = parserInput.isWhitespace(-1); - while (true) { - op = parserInput.$re(/^[-+]\s+/) || (!isSpaced && (parserInput.$char('+') || parserInput.$char('-'))); - if (!op) { - break; - } - a = this.multiplication(); - if (!a) { - break; - } - - m.parensInOp = true; - a.parensInOp = true; - operation = new(tree.Operation)(op, [operation || m, a], isSpaced); - isSpaced = parserInput.isWhitespace(-1); - } - return operation || m; - } - }, - conditions: function () { - var a, b, index = parserInput.i, condition; - - a = this.condition(true); - if (a) { - while (true) { - if (!parserInput.peek(/^,\s*(not\s*)?\(/) || !parserInput.$char(',')) { - break; - } - b = this.condition(true); - if (!b) { - break; - } - condition = new(tree.Condition)('or', condition || a, b, index); - } - return condition || a; - } - }, - condition: function (needsParens) { - var result, logical, next; - function or() { - return parserInput.$str('or'); - } + _this = _possibleConstructorReturn(this, _getPrototypeOf(Expression).call(this)); + _this.value = value; + _this.noSpacing = noSpacing; - result = this.conditionAnd(needsParens); - if (!result) { - return ; - } - logical = or(); - if (logical) { - next = this.condition(needsParens); - if (next) { - result = new(tree.Condition)(logical, result, next); - } else { - return ; - } - } - return result; - }, - conditionAnd: function (needsParens) { - var result, logical, next, self = this; - function insideCondition() { - var cond = self.negatedCondition(needsParens) || self.parenthesisCondition(needsParens); - if (!cond && !needsParens) { - return self.atomicCondition(needsParens); - } - return cond; - } - function and() { - return parserInput.$str('and'); - } + if (!value) { + throw new Error('Expression requires an array parameter'); + } - result = insideCondition(); - if (!result) { - return ; - } - logical = and(); - if (logical) { - next = this.conditionAnd(needsParens); - if (next) { - result = new(tree.Condition)(logical, result, next); - } else { - return ; - } - } - return result; - }, - negatedCondition: function (needsParens) { - if (parserInput.$str('not')) { - var result = this.parenthesisCondition(needsParens); - if (result) { - result.negate = !result.negate; - } - return result; - } - }, - parenthesisCondition: function (needsParens) { - function tryConditionFollowedByParenthesis(me) { - var body; - parserInput.save(); - body = me.condition(needsParens); - if (!body) { - parserInput.restore(); - return ; - } - if (!parserInput.$char(')')) { - parserInput.restore(); - return ; - } - parserInput.forget(); - return body; - } + return _this; + } - var body; - parserInput.save(); - if (!parserInput.$str('(')) { - parserInput.restore(); - return ; - } - body = tryConditionFollowedByParenthesis(this); - if (body) { - parserInput.forget(); - return body; - } + _createClass(Expression, [{ + key: "accept", + value: function accept(visitor) { + this.value = visitor.visitArray(this.value); + } + }, { + key: "eval", + value: function _eval(context) { + var returnValue; + var mathOn = context.isMathOn(); + var inParenthesis = this.parens && (context.math !== MATH$2.STRICT_LEGACY || !this.parensInOp); + var doubleParen = false; - body = this.atomicCondition(needsParens); - if (!body) { - parserInput.restore(); - return ; - } - if (!parserInput.$char(')')) { - parserInput.restore('expected \')\' got \'' + parserInput.currentChar() + '\''); - return ; - } - parserInput.forget(); - return body; - }, - atomicCondition: function (needsParens) { - var entities = this.entities, index = parserInput.i, a, b, c, op; + if (inParenthesis) { + context.inParenthesis(); + } - function cond() { - return this.addition() || entities.keyword() || entities.quoted() || entities.mixinLookup(); - } - cond = cond.bind(this); - - a = cond(); - if (a) { - if (parserInput.$char('>')) { - if (parserInput.$char('=')) { - op = '>='; - } else { - op = '>'; - } - } else - if (parserInput.$char('<')) { - if (parserInput.$char('=')) { - op = '<='; - } else { - op = '<'; - } - } else - if (parserInput.$char('=')) { - if (parserInput.$char('>')) { - op = '=>'; - } else if (parserInput.$char('<')) { - op = '=<'; - } else { - op = '='; - } - } - if (op) { - b = cond(); - if (b) { - c = new(tree.Condition)(op, a, b, index, false); - } else { - error('expected expression'); - } - } else { - c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, false); - } - return c; - } - }, + if (this.value.length > 1) { + returnValue = new Expression(this.value.map(function (e) { + if (!e.eval) { + return e; + } - // - // An operand is anything that can be part of an operation, - // such as a Color, or a Variable - // - operand: function () { - var entities = this.entities, negate; + return e.eval(context); + }), this.noSpacing); + } else if (this.value.length === 1) { + if (this.value[0].parens && !this.value[0].parensInOp && !context.inCalc) { + doubleParen = true; + } - if (parserInput.peek(/^-[@\$\(]/)) { - negate = parserInput.$char('-'); - } + returnValue = this.value[0].eval(context); + } else { + returnValue = this; + } - var o = this.sub() || entities.dimension() || - entities.color() || entities.variable() || - entities.property() || entities.call() || - entities.quoted(true) || entities.colorKeyword() || - entities.mixinLookup(); + if (inParenthesis) { + context.outOfParenthesis(); + } - if (negate) { - o.parensInOp = true; - o = new(tree.Negative)(o); - } + if (this.parens && this.parensInOp && !mathOn && !doubleParen && !(returnValue instanceof Dimension)) { + returnValue = new Paren(returnValue); + } - return o; - }, + return returnValue; + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + for (var i = 0; i < this.value.length; i++) { + this.value[i].genCSS(context, output); - // - // Expressions either represent mathematical operations, - // or white-space delimited Entities. - // - // 1px solid black - // @var * 2 - // - expression: function () { - var entities = [], e, delim, index = parserInput.i; - - do { - e = this.comment(); - if (e) { - entities.push(e); - continue; - } - e = this.addition() || this.entity(); - if (e) { - entities.push(e); - // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here - if (!parserInput.peek(/^\/[\/*]/)) { - delim = parserInput.$char('/'); - if (delim) { - entities.push(new(tree.Anonymous)(delim, index)); - } - } - } - } while (e); - if (entities.length > 0) { - return new(tree.Expression)(entities); - } - }, - property: function () { - var name = parserInput.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/); - if (name) { - return name[1]; - } - }, - ruleProperty: function () { - var name = [], index = [], s, k; + if (!this.noSpacing && i + 1 < this.value.length) { + output.add(' '); + } + } + } + }, { + key: "throwAwayComments", + value: function throwAwayComments() { + this.value = this.value.filter(function (v) { + return !(v instanceof Comment); + }); + } + }]); - parserInput.save(); + return Expression; + }(Node); - var simpleProperty = parserInput.$re(/^([_a-zA-Z0-9-]+)\s*:/); - if (simpleProperty) { - name = [new(tree.Keyword)(simpleProperty[1])]; - parserInput.forget(); - return name; - } + Expression.prototype.type = 'Expression'; - function match(re) { - var i = parserInput.i, - chunk = parserInput.$re(re); - if (chunk) { - index.push(i); - return name.push(chunk[1]); - } - } + var functionCaller = + /*#__PURE__*/ + function () { + function functionCaller(name, context, index, currentFileInfo) { + _classCallCheck(this, functionCaller); - match(/^(\*?)/); - while (true) { - if (!match(/^((?:[\w-]+)|(?:[@\$]\{[\w-]+\}))/)) { - break; - } - } + this.name = name.toLowerCase(); + this.index = index; + this.context = context; + this.currentFileInfo = currentFileInfo; + this.func = context.frames[0].functionRegistry.get(this.name); + } - if ((name.length > 1) && match(/^((?:\+_|\+)?)\s*:/)) { - parserInput.forget(); + _createClass(functionCaller, [{ + key: "isValid", + value: function isValid() { + return Boolean(this.func); + } + }, { + key: "call", + value: function call(args) { + // This code is terrible and should be replaced as per this issue... + // https://github.com/less/less.js/issues/2477 + if (Array.isArray(args)) { + args = args.filter(function (item) { + if (item.type === 'Comment') { + return false; + } - // at last, we have the complete match now. move forward, - // convert name particles to tree objects and return: - if (name[0] === '') { - name.shift(); - index.shift(); - } - for (k = 0; k < name.length; k++) { - s = name[k]; - name[k] = (s.charAt(0) !== '@' && s.charAt(0) !== '$') ? - new(tree.Keyword)(s) : - (s.charAt(0) === '@' ? - new(tree.Variable)('@' + s.slice(2, -1), index[k], fileInfo) : - new(tree.Property)('$' + s.slice(2, -1), index[k], fileInfo)); - } - return name; + return true; + }).map(function (item) { + if (item.type === 'Expression') { + var subNodes = item.value.filter(function (item) { + if (item.type === 'Comment') { + return false; } - parserInput.restore(); + + return true; + }); + + if (subNodes.length === 1) { + return subNodes[0]; + } else { + return new Expression(subNodes); + } } - } - }; -}; -Parser.serializeVars = function(vars) { - var s = ''; - for (var name in vars) { - if (Object.hasOwnProperty.call(vars, name)) { - var value = vars[name]; - s += ((name[0] === '@') ? '' : '@') + name + ': ' + value + - ((String(value).slice(-1) === ';') ? '' : ';'); + return item; + }); } - } - return s; -}; + return this.func.apply(this, _toConsumableArray(args)); + } + }]); + + return functionCaller; + }(); + + // A function call node. + // + + var Call = + /*#__PURE__*/ + function (_Node) { + _inherits(Call, _Node); + + function Call(name, args, index, currentFileInfo) { + var _this; + + _classCallCheck(this, Call); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(Call).call(this)); + _this.name = name; + _this.args = args; + _this.calc = name === 'calc'; + _this._index = index; + _this._fileInfo = currentFileInfo; + return _this; + } + + _createClass(Call, [{ + key: "accept", + value: function accept(visitor) { + if (this.args) { + this.args = visitor.visitArray(this.args); + } + } // + // When evaluating a function call, + // we either find the function in the functionRegistry, + // in which case we call it, passing the evaluated arguments, + // if this returns null or we cannot find the function, we + // simply print it out as it appeared originally [2]. + // + // The reason why we evaluate the arguments, is in the case where + // we try to pass a variable to a function, like: `saturate(@color)`. + // The function should receive the value, not the variable. + // + + }, { + key: "eval", + value: function _eval(context) { + /** + * Turn off math for calc(), and switch back on for evaluating nested functions + */ + var currentMathContext = context.mathOn; + context.mathOn = !this.calc; -module.exports = Parser; + if (this.calc || context.inCalc) { + context.enterCalc(); + } -},{"../functions/function-registry":27,"../less-error":38,"../tree":67,"../utils":89,"../visitors":93,"./parser-input":43}],45:[function(require,module,exports){ -/** - * Plugin Manager - */ -var PluginManager = function(less) { - this.less = less; - this.visitors = []; - this.preProcessors = []; - this.postProcessors = []; - this.installedPlugins = []; - this.fileManagers = []; - this.iterator = -1; - this.pluginCache = {}; - this.Loader = new less.PluginLoader(less); -}; - -var pm, PluginManagerFactory = function(less, newFactory) { - if (newFactory || !pm) { - pm = new PluginManager(less); - } - return pm; - }; + var args = this.args.map(function (a) { + return a.eval(context); + }); -/** - * Adds all the plugins in the array - * @param {Array} plugins - */ -PluginManager.prototype.addPlugins = function(plugins) { - if (plugins) { - for (var i = 0; i < plugins.length; i++) { - this.addPlugin(plugins[i]); + if (this.calc || context.inCalc) { + context.exitCalc(); } - } -}; -/** - * - * @param plugin - * @param {String} filename - */ -PluginManager.prototype.addPlugin = function(plugin, filename, functionRegistry) { - this.installedPlugins.push(plugin); - if (filename) { - this.pluginCache[filename] = plugin; - } - if (plugin.install) { - plugin.install(this.less, this, functionRegistry || this.less.functions.functionRegistry); - } -}; -/** - * - * @param filename - */ -PluginManager.prototype.get = function(filename) { - return this.pluginCache[filename]; -}; -/** - * Adds a visitor. The visitor object has options on itself to determine - * when it should run. - * @param visitor - */ -PluginManager.prototype.addVisitor = function(visitor) { - this.visitors.push(visitor); -}; -/** - * Adds a pre processor object - * @param {object} preProcessor - * @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import - */ -PluginManager.prototype.addPreProcessor = function(preProcessor, priority) { - var indexToInsertAt; - for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) { - if (this.preProcessors[indexToInsertAt].priority >= priority) { - break; - } - } - this.preProcessors.splice(indexToInsertAt, 0, {preProcessor: preProcessor, priority: priority}); -}; -/** - * Adds a post processor object - * @param {object} postProcessor - * @param {number} priority - guidelines 1 = before compression, 1000 = compression, 2000 = after compression - */ -PluginManager.prototype.addPostProcessor = function(postProcessor, priority) { - var indexToInsertAt; - for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) { - if (this.postProcessors[indexToInsertAt].priority >= priority) { - break; - } - } - this.postProcessors.splice(indexToInsertAt, 0, {postProcessor: postProcessor, priority: priority}); -}; -/** - * - * @param manager - */ -PluginManager.prototype.addFileManager = function(manager) { - this.fileManagers.push(manager); -}; -/** - * - * @returns {Array} - * @private - */ -PluginManager.prototype.getPreProcessors = function() { - var preProcessors = []; - for (var i = 0; i < this.preProcessors.length; i++) { - preProcessors.push(this.preProcessors[i].preProcessor); - } - return preProcessors; -}; -/** - * - * @returns {Array} - * @private - */ -PluginManager.prototype.getPostProcessors = function() { - var postProcessors = []; - for (var i = 0; i < this.postProcessors.length; i++) { - postProcessors.push(this.postProcessors[i].postProcessor); - } - return postProcessors; -}; -/** - * - * @returns {Array} - * @private - */ -PluginManager.prototype.getVisitors = function() { - return this.visitors; -}; + context.mathOn = currentMathContext; + var result; + var funcCaller = new functionCaller(this.name, context, this.getIndex(), this.fileInfo()); -PluginManager.prototype.visitor = function() { - var self = this; - return { - first: function() { - self.iterator = -1; - return self.visitors[self.iterator]; - }, - get: function() { - self.iterator += 1; - return self.visitors[self.iterator]; + if (funcCaller.isValid()) { + try { + result = funcCaller.call(args); + } catch (e) { + throw { + type: e.type || 'Runtime', + message: "error evaluating function `".concat(this.name, "`").concat(e.message ? ": ".concat(e.message) : ''), + index: this.getIndex(), + filename: this.fileInfo().filename, + line: e.lineNumber, + column: e.columnNumber + }; + } + + if (result !== null && result !== undefined) { + // Results that that are not nodes are cast as Anonymous nodes + // Falsy values or booleans are returned as empty nodes + if (!(result instanceof Node)) { + if (!result || result === true) { + result = new Anonymous(null); + } else { + result = new Anonymous(result.toString()); + } + } + + result._index = this._index; + result._fileInfo = this._fileInfo; + return result; + } } - }; -}; -/** - * - * @returns {Array} - * @private - */ -PluginManager.prototype.getFileManagers = function() { - return this.fileManagers; -}; -// -module.exports = PluginManagerFactory; + return new Call(this.name, args, this.getIndex(), this.fileInfo()); + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + output.add("".concat(this.name, "("), this.fileInfo(), this.getIndex()); -},{}],46:[function(require,module,exports){ -var PromiseConstructor, - utils = require('./utils'); + for (var i = 0; i < this.args.length; i++) { + this.args[i].genCSS(context, output); -module.exports = function(environment, ParseTree, ImportManager) { - var render = function (input, options, callback) { - if (typeof options === 'function') { - callback = options; - options = utils.copyOptions(this.options, {}); - } - else { - options = utils.copyOptions(this.options, options || {}); + if (i + 1 < this.args.length) { + output.add(', '); + } } - if (!callback) { - if (!PromiseConstructor) { - PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise; - } - var self = this; - return new PromiseConstructor(function (resolve, reject) { - render.call(self, input, options, function(err, output) { - if (err) { - reject(err); - } else { - resolve(output); - } - }); - }); - } else { - this.parse(input, options, function(err, root, imports, options) { - if (err) { return callback(err); } + output.add(')'); + } + }]); - var result; - try { - var parseTree = new ParseTree(root, imports); - result = parseTree.toCSS(options); - } - catch (err) { return callback(err); } + return Call; + }(Node); - callback(null, result); - }); - } - }; + Call.prototype.type = 'Call'; - return render; -}; + var Variable = + /*#__PURE__*/ + function (_Node) { + _inherits(Variable, _Node); -},{"./utils":89,"promise":undefined}],47:[function(require,module,exports){ -module.exports = function (SourceMapOutput, environment) { + function Variable(name, index, currentFileInfo) { + var _this; - var SourceMapBuilder = function (options) { - this.options = options; - }; + _classCallCheck(this, Variable); - SourceMapBuilder.prototype.toCSS = function(rootNode, options, imports) { - var sourceMapOutput = new SourceMapOutput( - { - contentsIgnoredCharsMap: imports.contentsIgnoredChars, - rootNode: rootNode, - contentsMap: imports.contents, - sourceMapFilename: this.options.sourceMapFilename, - sourceMapURL: this.options.sourceMapURL, - outputFilename: this.options.sourceMapOutputFilename, - sourceMapBasepath: this.options.sourceMapBasepath, - sourceMapRootpath: this.options.sourceMapRootpath, - outputSourceFiles: this.options.outputSourceFiles, - sourceMapGenerator: this.options.sourceMapGenerator, - sourceMapFileInline: this.options.sourceMapFileInline - }); + _this = _possibleConstructorReturn(this, _getPrototypeOf(Variable).call(this)); + _this.name = name; + _this._index = index; + _this._fileInfo = currentFileInfo; + return _this; + } - var css = sourceMapOutput.toCSS(options); - this.sourceMap = sourceMapOutput.sourceMap; - this.sourceMapURL = sourceMapOutput.sourceMapURL; - if (this.options.sourceMapInputFilename) { - this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename); + _createClass(Variable, [{ + key: "eval", + value: function _eval(context) { + var variable; + var name = this.name; + + if (name.indexOf('@@') === 0) { + name = "@".concat(new Variable(name.slice(1), this.getIndex(), this.fileInfo()).eval(context).value); } - if (this.options.sourceMapBasepath !== undefined && this.sourceMapURL !== undefined) { - this.sourceMapURL = sourceMapOutput.removeBasepath(this.sourceMapURL); + + if (this.evaluating) { + throw { + type: 'Name', + message: "Recursive variable definition for ".concat(name), + filename: this.fileInfo().filename, + index: this.getIndex() + }; } - return css + this.getCSSAppendage(); - }; - SourceMapBuilder.prototype.getCSSAppendage = function() { + this.evaluating = true; + variable = this.find(context.frames, function (frame) { + var v = frame.variable(name); - var sourceMapURL = this.sourceMapURL; - if (this.options.sourceMapFileInline) { - if (this.sourceMap === undefined) { - return ''; + if (v) { + if (v.important) { + var importantScope = context.importantScope[context.importantScope.length - 1]; + importantScope.important = v.important; + } // If in calc, wrap vars in a function call to cascade evaluate args first + + + if (context.inCalc) { + return new Call('_SELF', [v.value]).eval(context); + } else { + return v.value.eval(context); } - sourceMapURL = 'data:application/json;base64,' + environment.encodeBase64(this.sourceMap); + } + }); + + if (variable) { + this.evaluating = false; + return variable; + } else { + throw { + type: 'Name', + message: "variable ".concat(name, " is undefined"), + filename: this.fileInfo().filename, + index: this.getIndex() + }; } + } + }, { + key: "find", + value: function find(obj, fun) { + for (var i = 0, r; i < obj.length; i++) { + r = fun.call(obj, obj[i]); - if (sourceMapURL) { - return '/*# sourceMappingURL=' + sourceMapURL + ' */'; + if (r) { + return r; + } } - return ''; - }; - SourceMapBuilder.prototype.getExternalSourceMap = function() { - return this.sourceMap; - }; - SourceMapBuilder.prototype.setExternalSourceMap = function(sourceMap) { - this.sourceMap = sourceMap; - }; + return null; + } + }]); - SourceMapBuilder.prototype.isInline = function() { - return this.options.sourceMapFileInline; - }; - SourceMapBuilder.prototype.getSourceMapURL = function() { - return this.sourceMapURL; - }; - SourceMapBuilder.prototype.getOutputFilename = function() { - return this.options.sourceMapOutputFilename; - }; - SourceMapBuilder.prototype.getInputFilename = function() { - return this.sourceMapInputFilename; - }; + return Variable; + }(Node); - return SourceMapBuilder; -}; + Variable.prototype.type = 'Variable'; -},{}],48:[function(require,module,exports){ -module.exports = function (environment) { + var Property = + /*#__PURE__*/ + function (_Node) { + _inherits(Property, _Node); - var SourceMapOutput = function (options) { - this._css = []; - this._rootNode = options.rootNode; - this._contentsMap = options.contentsMap; - this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap; - if (options.sourceMapFilename) { - this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/'); - } - this._outputFilename = options.outputFilename; - this.sourceMapURL = options.sourceMapURL; - if (options.sourceMapBasepath) { - this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/'); + function Property(name, index, currentFileInfo) { + var _this; + + _classCallCheck(this, Property); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(Property).call(this)); + _this.name = name; + _this._index = index; + _this._fileInfo = currentFileInfo; + return _this; + } + + _createClass(Property, [{ + key: "eval", + value: function _eval(context) { + var property; + var name = this.name; // TODO: shorten this reference + + var mergeRules = context.pluginManager.less.visitors.ToCSSVisitor.prototype._mergeRules; + + if (this.evaluating) { + throw { + type: 'Name', + message: "Recursive property reference for ".concat(name), + filename: this.fileInfo().filename, + index: this.getIndex() + }; } - if (options.sourceMapRootpath) { - this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/'); - if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') { - this._sourceMapRootpath += '/'; + + this.evaluating = true; + property = this.find(context.frames, function (frame) { + var v; + var vArr = frame.property(name); + + if (vArr) { + for (var i = 0; i < vArr.length; i++) { + v = vArr[i]; + vArr[i] = new Declaration(v.name, v.value, v.important, v.merge, v.index, v.currentFileInfo, v.inline, v.variable); } - } else { - this._sourceMapRootpath = ''; - } - this._outputSourceFiles = options.outputSourceFiles; - this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator(); - this._lineNumber = 0; - this._column = 0; - }; + mergeRules(vArr); + v = vArr[vArr.length - 1]; - SourceMapOutput.prototype.removeBasepath = function(path) { - if (this._sourceMapBasepath && path.indexOf(this._sourceMapBasepath) === 0) { - path = path.substring(this._sourceMapBasepath.length); - if (path.charAt(0) === '\\' || path.charAt(0) === '/') { - path = path.substring(1); + if (v.important) { + var importantScope = context.importantScope[context.importantScope.length - 1]; + importantScope.important = v.important; } + + v = v.value.eval(context); + return v; + } + }); + + if (property) { + this.evaluating = false; + return property; + } else { + throw { + type: 'Name', + message: "Property '".concat(name, "' is undefined"), + filename: this.currentFileInfo.filename, + index: this.index + }; } + } + }, { + key: "find", + value: function find(obj, fun) { + for (var i = 0, r; i < obj.length; i++) { + r = fun.call(obj, obj[i]); - return path; - }; + if (r) { + return r; + } + } - SourceMapOutput.prototype.normalizeFilename = function(filename) { - filename = filename.replace(/\\/g, '/'); - filename = this.removeBasepath(filename); - return (this._sourceMapRootpath || '') + filename; - }; + return null; + } + }]); - SourceMapOutput.prototype.add = function(chunk, fileInfo, index, mapLines) { + return Property; + }(Node); - // ignore adding empty strings - if (!chunk) { - return; - } + Property.prototype.type = 'Property'; - var lines, - sourceLines, - columns, - sourceColumns, - i; + var Attribute = + /*#__PURE__*/ + function (_Node) { + _inherits(Attribute, _Node); - if (fileInfo && fileInfo.filename) { - var inputSource = this._contentsMap[fileInfo.filename]; + function Attribute(key, op, value) { + var _this; - // remove vars/banner added to the top of the file - if (this._contentsIgnoredCharsMap[fileInfo.filename]) { - // adjust the index - index -= this._contentsIgnoredCharsMap[fileInfo.filename]; - if (index < 0) { index = 0; } - // adjust the source - inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]); - } - inputSource = inputSource.substring(0, index); - sourceLines = inputSource.split('\n'); - sourceColumns = sourceLines[sourceLines.length - 1]; - } + _classCallCheck(this, Attribute); - lines = chunk.split('\n'); - columns = lines[lines.length - 1]; + _this = _possibleConstructorReturn(this, _getPrototypeOf(Attribute).call(this)); + _this.key = key; + _this.op = op; + _this.value = value; + return _this; + } - if (fileInfo && fileInfo.filename) { - if (!mapLines) { - this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column}, - original: { line: sourceLines.length, column: sourceColumns.length}, - source: this.normalizeFilename(fileInfo.filename)}); - } else { - for (i = 0; i < lines.length; i++) { - this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0}, - original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0}, - source: this.normalizeFilename(fileInfo.filename)}); - } - } - } + _createClass(Attribute, [{ + key: "eval", + value: function _eval(context) { + return new Attribute(this.key.eval ? this.key.eval(context) : this.key, this.op, this.value && this.value.eval ? this.value.eval(context) : this.value); + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + output.add(this.toCSS(context)); + } + }, { + key: "toCSS", + value: function toCSS(context) { + var value = this.key.toCSS ? this.key.toCSS(context) : this.key; - if (lines.length === 1) { - this._column += columns.length; - } else { - this._lineNumber += lines.length - 1; - this._column = columns.length; + if (this.op) { + value += this.op; + value += this.value.toCSS ? this.value.toCSS(context) : this.value; } - this._css.push(chunk); - }; + return "[".concat(value, "]"); + } + }]); - SourceMapOutput.prototype.isEmpty = function() { - return this._css.length === 0; - }; + return Attribute; + }(Node); - SourceMapOutput.prototype.toCSS = function(context) { - this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null }); + Attribute.prototype.type = 'Attribute'; - if (this._outputSourceFiles) { - for (var filename in this._contentsMap) { - if (this._contentsMap.hasOwnProperty(filename)) { - var source = this._contentsMap[filename]; - if (this._contentsIgnoredCharsMap[filename]) { - source = source.slice(this._contentsIgnoredCharsMap[filename]); - } - this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source); - } - } - } + var Quoted = + /*#__PURE__*/ + function (_Node) { + _inherits(Quoted, _Node); - this._rootNode.genCSS(context, this); + function Quoted(str, content, escaped, index, currentFileInfo) { + var _this; - if (this._css.length > 0) { - var sourceMapURL, - sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON()); + _classCallCheck(this, Quoted); - if (this.sourceMapURL) { - sourceMapURL = this.sourceMapURL; - } else if (this._sourceMapFilename) { - sourceMapURL = this._sourceMapFilename; - } - this.sourceMapURL = sourceMapURL; + _this = _possibleConstructorReturn(this, _getPrototypeOf(Quoted).call(this)); + _this.escaped = escaped == null ? true : escaped; + _this.value = content || ''; + _this.quote = str.charAt(0); + _this._index = index; + _this._fileInfo = currentFileInfo; + _this.variableRegex = /@\{([\w-]+)\}/g; + _this.propRegex = /\$\{([\w-]+)\}/g; + return _this; + } - this.sourceMap = sourceMapContent; + _createClass(Quoted, [{ + key: "genCSS", + value: function genCSS(context, output) { + if (!this.escaped) { + output.add(this.quote, this.fileInfo(), this.getIndex()); } - return this._css.join(''); - }; + output.add(this.value); - return SourceMapOutput; -}; + if (!this.escaped) { + output.add(this.quote); + } + } + }, { + key: "containsVariables", + value: function containsVariables() { + return this.value.match(this.variableRegex); + } + }, { + key: "eval", + value: function _eval(context) { + var that = this; + var value = this.value; + + var variableReplacement = function variableReplacement(_, name) { + var v = new Variable("@".concat(name), that.getIndex(), that.fileInfo()).eval(context, true); + return v instanceof Quoted ? v.value : v.toCSS(); + }; -},{}],49:[function(require,module,exports){ -var contexts = require('./contexts'), - visitor = require('./visitors'), - tree = require('./tree'); + var propertyReplacement = function propertyReplacement(_, name) { + var v = new Property("$".concat(name), that.getIndex(), that.fileInfo()).eval(context, true); + return v instanceof Quoted ? v.value : v.toCSS(); + }; -module.exports = function(root, options) { - options = options || {}; - var evaldRoot, - variables = options.variables, - evalEnv = new contexts.Eval(options); + function iterativeReplace(value, regexp, replacementFnc) { + var evaluatedValue = value; - // - // Allows setting variables with a hash, so: - // - // `{ color: new tree.Color('#f01') }` will become: - // - // new tree.Declaration('@color', - // new tree.Value([ - // new tree.Expression([ - // new tree.Color('#f01') - // ]) - // ]) - // ) - // - if (typeof variables === 'object' && !Array.isArray(variables)) { - variables = Object.keys(variables).map(function (k) { - var value = variables[k]; - - if (!(value instanceof tree.Value)) { - if (!(value instanceof tree.Expression)) { - value = new tree.Expression([value]); - } - value = new tree.Value([value]); - } - return new tree.Declaration('@' + k, value, false, null, 0); - }); - evalEnv.frames = [new tree.Ruleset(null, variables)]; - } + do { + value = evaluatedValue.toString(); + evaluatedValue = value.replace(regexp, replacementFnc); + } while (value !== evaluatedValue); - var visitors = [ - new visitor.JoinSelectorVisitor(), - new visitor.MarkVisibleSelectorsVisitor(true), - new visitor.ExtendVisitor(), - new visitor.ToCSSVisitor({compress: Boolean(options.compress)}) - ], preEvalVisitors = [], v, visitorIterator; + return evaluatedValue; + } - /** - * first() / get() allows visitors to be added while visiting - * - * @todo Add scoping for visitors just like functions for @plugin; right now they're global - */ - if (options.pluginManager) { - visitorIterator = options.pluginManager.visitor(); - for (var i = 0; i < 2; i++) { - visitorIterator.first(); - while ((v = visitorIterator.get())) { - if (v.isPreEvalVisitor) { - if (i === 0 || preEvalVisitors.indexOf(v) === -1) { - preEvalVisitors.push(v); - v.run(root); - } - } - else { - if (i === 0 || visitors.indexOf(v) === -1) { - if (v.isPreVisitor) { - visitors.unshift(v); - } - else { - visitors.push(v); - } - } - } - } + value = iterativeReplace(value, this.variableRegex, variableReplacement); + value = iterativeReplace(value, this.propRegex, propertyReplacement); + return new Quoted(this.quote + value + this.quote, value, this.escaped, this.getIndex(), this.fileInfo()); + } + }, { + key: "compare", + value: function compare(other) { + // when comparing quoted strings allow the quote to differ + if (other.type === 'Quoted' && !this.escaped && !other.escaped) { + return Node.numericCompare(this.value, other.value); + } else { + return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; } - } - - evaldRoot = root.eval(evalEnv); + } + }]); - for (var i = 0; i < visitors.length; i++) { - visitors[i].run(evaldRoot); - } + return Quoted; + }(Node); - // Run any remaining visitors added after eval pass - if (options.pluginManager) { - visitorIterator.first(); - while ((v = visitorIterator.get())) { - if (visitors.indexOf(v) === -1 && preEvalVisitors.indexOf(v) === -1) { - v.run(evaldRoot); - } - } + Quoted.prototype.type = 'Quoted'; + + var URL = + /*#__PURE__*/ + function (_Node) { + _inherits(URL, _Node); + + function URL(val, index, currentFileInfo, isEvald) { + var _this; + + _classCallCheck(this, URL); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(URL).call(this)); + _this.value = val; + _this._index = index; + _this._fileInfo = currentFileInfo; + _this.isEvald = isEvald; + return _this; } - return evaldRoot; -}; - -},{"./contexts":13,"./tree":67,"./visitors":93}],50:[function(require,module,exports){ -var Node = require('./node'); - -var Anonymous = function (value, index, currentFileInfo, mapLines, rulesetLike, visibilityInfo) { - this.value = value; - this._index = index; - this._fileInfo = currentFileInfo; - this.mapLines = mapLines; - this.rulesetLike = (typeof rulesetLike === 'undefined') ? false : rulesetLike; - this.allowRoot = true; - this.copyVisibilityInfo(visibilityInfo); -}; -Anonymous.prototype = new Node(); -Anonymous.prototype.type = 'Anonymous'; -Anonymous.prototype.eval = function () { - return new Anonymous(this.value, this._index, this._fileInfo, this.mapLines, this.rulesetLike, this.visibilityInfo()); -}; -Anonymous.prototype.compare = function (other) { - return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; -}; -Anonymous.prototype.isRulesetLike = function() { - return this.rulesetLike; -}; -Anonymous.prototype.genCSS = function (context, output) { - this.nodeVisible = Boolean(this.value); - if (this.nodeVisible) { - output.add(this.value, this._fileInfo, this._index, this.mapLines); - } -}; -module.exports = Anonymous; - -},{"./node":76}],51:[function(require,module,exports){ -var Node = require('./node'); - -var Assignment = function (key, val) { - this.key = key; - this.value = val; -}; - -Assignment.prototype = new Node(); -Assignment.prototype.type = 'Assignment'; -Assignment.prototype.accept = function (visitor) { - this.value = visitor.visit(this.value); -}; -Assignment.prototype.eval = function (context) { - if (this.value.eval) { - return new Assignment(this.key, this.value.eval(context)); - } - return this; -}; -Assignment.prototype.genCSS = function (context, output) { - output.add(this.key + '='); - if (this.value.genCSS) { + _createClass(URL, [{ + key: "accept", + value: function accept(visitor) { + this.value = visitor.visit(this.value); + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + output.add('url('); this.value.genCSS(context, output); - } else { - output.add(this.value); - } -}; -module.exports = Assignment; + output.add(')'); + } + }, { + key: "eval", + value: function _eval(context) { + var val = this.value.eval(context); + var rootpath; -},{"./node":76}],52:[function(require,module,exports){ -var Node = require('./node'), - Selector = require('./selector'), - Ruleset = require('./ruleset'), - Anonymous = require('./anonymous'); + if (!this.isEvald) { + // Add the rootpath if the URL requires a rewrite + rootpath = this.fileInfo() && this.fileInfo().rootpath; -var AtRule = function (name, value, rules, index, currentFileInfo, debugInfo, isRooted, visibilityInfo) { - var i; + if (typeof rootpath === 'string' && typeof val.value === 'string' && context.pathRequiresRewrite(val.value)) { + if (!val.quote) { + rootpath = escapePath(rootpath); + } - this.name = name; - this.value = (value instanceof Node) ? value : (value ? new Anonymous(value) : value); - if (rules) { - if (Array.isArray(rules)) { - this.rules = rules; - } else { - this.rules = [rules]; - this.rules[0].selectors = (new Selector([], null, null, index, currentFileInfo)).createEmptySelectors(); - } - for (i = 0; i < this.rules.length; i++) { - this.rules[i].allowImports = true; - } - this.setParent(this.rules, this); - } - this._index = index; - this._fileInfo = currentFileInfo; - this.debugInfo = debugInfo; - this.isRooted = isRooted || false; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; -}; - -AtRule.prototype = new Node(); -AtRule.prototype.type = 'AtRule'; -AtRule.prototype.accept = function (visitor) { - var value = this.value, rules = this.rules; - if (rules) { - this.rules = visitor.visitArray(rules); - } - if (value) { - this.value = visitor.visit(value); - } -}; -AtRule.prototype.isRulesetLike = function() { - return this.rules || !this.isCharset(); -}; -AtRule.prototype.isCharset = function() { - return '@charset' === this.name; -}; -AtRule.prototype.genCSS = function (context, output) { - var value = this.value, rules = this.rules; - output.add(this.name, this.fileInfo(), this.getIndex()); - if (value) { - output.add(' '); - value.genCSS(context, output); - } - if (rules) { - this.outputRuleset(context, output, rules); - } else { - output.add(';'); - } -}; -AtRule.prototype.eval = function (context) { - var mediaPathBackup, mediaBlocksBackup, value = this.value, rules = this.rules; - - // media stored inside other atrule should not bubble over it - // backpup media bubbling information - mediaPathBackup = context.mediaPath; - mediaBlocksBackup = context.mediaBlocks; - // deleted media bubbling information - context.mediaPath = []; - context.mediaBlocks = []; - - if (value) { - value = value.eval(context); - } - if (rules) { - // assuming that there is only one rule at this point - that is how parser constructs the rule - rules = [rules[0].eval(context)]; - rules[0].root = true; - } - // restore media bubbling information - context.mediaPath = mediaPathBackup; - context.mediaBlocks = mediaBlocksBackup; - - return new AtRule(this.name, value, rules, - this.getIndex(), this.fileInfo(), this.debugInfo, this.isRooted, this.visibilityInfo()); -}; -AtRule.prototype.variable = function (name) { - if (this.rules) { - // assuming that there is only one rule at this point - that is how parser constructs the rule - return Ruleset.prototype.variable.call(this.rules[0], name); - } -}; -AtRule.prototype.find = function () { - if (this.rules) { - // assuming that there is only one rule at this point - that is how parser constructs the rule - return Ruleset.prototype.find.apply(this.rules[0], arguments); - } -}; -AtRule.prototype.rulesets = function () { - if (this.rules) { - // assuming that there is only one rule at this point - that is how parser constructs the rule - return Ruleset.prototype.rulesets.apply(this.rules[0]); - } -}; -AtRule.prototype.outputRuleset = function (context, output, rules) { - var ruleCnt = rules.length, i; - context.tabLevel = (context.tabLevel | 0) + 1; - - // Compressed - if (context.compress) { - output.add('{'); - for (i = 0; i < ruleCnt; i++) { - rules[i].genCSS(context, output); - } - output.add('}'); - context.tabLevel--; - return; - } + val.value = context.rewritePath(val.value, rootpath); + } else { + val.value = context.normalizePath(val.value); + } // Add url args if enabled - // Non-compressed - var tabSetStr = '\n' + Array(context.tabLevel).join(' '), tabRuleStr = tabSetStr + ' '; - if (!ruleCnt) { - output.add(' {' + tabSetStr + '}'); - } else { - output.add(' {' + tabRuleStr); - rules[0].genCSS(context, output); - for (i = 1; i < ruleCnt; i++) { - output.add(tabRuleStr); - rules[i].genCSS(context, output); - } - output.add(tabSetStr + '}'); - } - - context.tabLevel--; -}; -module.exports = AtRule; - -},{"./anonymous":50,"./node":76,"./ruleset":81,"./selector":82}],53:[function(require,module,exports){ -var Node = require('./node'); - -var Attribute = function (key, op, value) { - this.key = key; - this.op = op; - this.value = value; -}; -Attribute.prototype = new Node(); -Attribute.prototype.type = 'Attribute'; -Attribute.prototype.eval = function (context) { - return new Attribute(this.key.eval ? this.key.eval(context) : this.key, - this.op, (this.value && this.value.eval) ? this.value.eval(context) : this.value); -}; -Attribute.prototype.genCSS = function (context, output) { - output.add(this.toCSS(context)); -}; -Attribute.prototype.toCSS = function (context) { - var value = this.key.toCSS ? this.key.toCSS(context) : this.key; - - if (this.op) { - value += this.op; - value += (this.value.toCSS ? this.value.toCSS(context) : this.value); - } - - return '[' + value + ']'; -}; -module.exports = Attribute; - -},{"./node":76}],54:[function(require,module,exports){ -var Node = require('./node'), - Anonymous = require('./anonymous'), - FunctionCaller = require('../functions/function-caller'); -// -// A function call node. -// -var Call = function (name, args, index, currentFileInfo) { - this.name = name; - this.args = args; - this.calc = name === 'calc'; - this._index = index; - this._fileInfo = currentFileInfo; -}; -Call.prototype = new Node(); -Call.prototype.type = 'Call'; -Call.prototype.accept = function (visitor) { - if (this.args) { - this.args = visitor.visitArray(this.args); - } -}; -// -// When evaluating a function call, -// we either find the function in the functionRegistry, -// in which case we call it, passing the evaluated arguments, -// if this returns null or we cannot find the function, we -// simply print it out as it appeared originally [2]. -// -// The reason why we evaluate the arguments, is in the case where -// we try to pass a variable to a function, like: `saturate(@color)`. -// The function should receive the value, not the variable. -// -Call.prototype.eval = function (context) { - /** - * Turn off math for calc(), and switch back on for evaluating nested functions - */ - var currentMathContext = context.mathOn; - context.mathOn = !this.calc; - if (this.calc || context.inCalc) { - context.enterCalc(); - } - var args = this.args.map(function (a) { return a.eval(context); }); - if (this.calc || context.inCalc) { - context.exitCalc(); - } - context.mathOn = currentMathContext; - var result, funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo()); - - if (funcCaller.isValid()) { - try { - result = funcCaller.call(args); - } catch (e) { - throw { - type: e.type || 'Runtime', - message: 'error evaluating function `' + this.name + '`' + - (e.message ? ': ' + e.message : ''), - index: this.getIndex(), - filename: this.fileInfo().filename, - line: e.lineNumber, - column: e.columnNumber - }; - } + if (context.urlArgs) { + if (!val.value.match(/^\s*data:/)) { + var delimiter = val.value.indexOf('?') === -1 ? '?' : '&'; + var urlArgs = delimiter + context.urlArgs; - if (result !== null && result !== undefined) { - // Results that that are not nodes are cast as Anonymous nodes - // Falsy values or booleans are returned as empty nodes - if (!(result instanceof Node)) { - if (!result || result === true) { - result = new Anonymous(null); - } - else { - result = new Anonymous(result.toString()); - } - + if (val.value.indexOf('#') !== -1) { + val.value = val.value.replace('#', "".concat(urlArgs, "#")); + } else { + val.value += urlArgs; + } } - result._index = this._index; - result._fileInfo = this._fileInfo; - return result; + } } - } + return new URL(val, this.getIndex(), this.fileInfo(), true); + } + }]); - return new Call(this.name, args, this.getIndex(), this.fileInfo()); -}; -Call.prototype.genCSS = function (context, output) { - output.add(this.name + '(', this.fileInfo(), this.getIndex()); + return URL; + }(Node); - for (var i = 0; i < this.args.length; i++) { - this.args[i].genCSS(context, output); - if (i + 1 < this.args.length) { - output.add(', '); - } - } + URL.prototype.type = 'Url'; - output.add(')'); -}; -module.exports = Call; + function escapePath(path) { + return path.replace(/[\(\)'"\s]/g, function (match) { + return "\\".concat(match); + }); + } -},{"../functions/function-caller":26,"./anonymous":50,"./node":76}],55:[function(require,module,exports){ -var Node = require('./node'), - colors = require('../data/colors'); + var Media = + /*#__PURE__*/ + function (_AtRule) { + _inherits(Media, _AtRule); -// -// RGB Colors - #ff0014, #eee -// -var Color = function (rgb, a, originalForm) { - var self = this; - // - // The end goal here, is to parse the arguments - // into an integer triplet, such as `128, 255, 0` - // - // This facilitates operations and conversions. - // - if (Array.isArray(rgb)) { - this.rgb = rgb; - } else if (rgb.length >= 6) { - this.rgb = []; - rgb.match(/.{2}/g).map(function (c, i) { - if (i < 3) { - self.rgb.push(parseInt(c, 16)); - } else { - self.alpha = (parseInt(c, 16)) / 255; - } - }); - } else { - this.rgb = []; - rgb.split('').map(function (c, i) { - if (i < 3) { - self.rgb.push(parseInt(c + c, 16)); - } else { - self.alpha = (parseInt(c + c, 16)) / 255; - } - }); - } - this.alpha = this.alpha || (typeof a === 'number' ? a : 1); - if (typeof originalForm !== 'undefined') { - this.value = originalForm; - } -}; + function Media(value, features, index, currentFileInfo, visibilityInfo) { + var _this; -Color.prototype = new Node(); -Color.prototype.type = 'Color'; + _classCallCheck(this, Media); -function clamp(v, max) { - return Math.min(Math.max(v, 0), max); -} - -function toHex(v) { - return '#' + v.map(function (c) { - c = clamp(Math.round(c), 255); - return (c < 16 ? '0' : '') + c.toString(16); - }).join(''); -} - -Color.prototype.luma = function () { - var r = this.rgb[0] / 255, - g = this.rgb[1] / 255, - b = this.rgb[2] / 255; - - r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4); - g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4); - b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4); - - return 0.2126 * r + 0.7152 * g + 0.0722 * b; -}; -Color.prototype.genCSS = function (context, output) { - output.add(this.toCSS(context)); -}; -Color.prototype.toCSS = function (context, doNotCompress) { - var compress = context && context.compress && !doNotCompress, color, alpha, - colorFunction, args = []; - - // `value` is set if this color was originally - // converted from a named color string so we need - // to respect this and try to output named color too. - alpha = this.fround(context, this.alpha); - - if (this.value) { - if (this.value.indexOf('rgb') === 0) { - if (alpha < 1) { - colorFunction = 'rgba'; - } - } else if (this.value.indexOf('hsl') === 0) { - if (alpha < 1) { - colorFunction = 'hsla'; - } else { - colorFunction = 'hsl'; - } - } else { - return this.value; - } - } else { - if (alpha < 1) { - colorFunction = 'rgba'; - } - } + _this = _possibleConstructorReturn(this, _getPrototypeOf(Media).call(this)); + _this._index = index; + _this._fileInfo = currentFileInfo; + var selectors = new Selector([], null, null, _this._index, _this._fileInfo).createEmptySelectors(); + _this.features = new Value(features); + _this.rules = [new Ruleset(selectors, value)]; + _this.rules[0].allowImports = true; - switch (colorFunction) { - case 'rgba': - args = this.rgb.map(function (c) { - return clamp(Math.round(c), 255); - }).concat(clamp(alpha, 1)); - break; - case 'hsla': - args.push(clamp(alpha, 1)); - case 'hsl': - color = this.toHSL(); - args = [ - this.fround(context, color.h), - this.fround(context, color.s * 100) + '%', - this.fround(context, color.l * 100) + '%' - ].concat(args); - } + _this.copyVisibilityInfo(visibilityInfo); + + _this.allowRoot = true; - if (colorFunction) { - // Values are capped between `0` and `255`, rounded and zero-padded. - return colorFunction + '(' + args.join(',' + (compress ? '' : ' ')) + ')'; + _this.setParent(selectors, _assertThisInitialized(_this)); + + _this.setParent(_this.features, _assertThisInitialized(_this)); + + _this.setParent(_this.rules, _assertThisInitialized(_this)); + + return _this; } - color = this.toRGB(); + _createClass(Media, [{ + key: "isRulesetLike", + value: function isRulesetLike() { + return true; + } + }, { + key: "accept", + value: function accept(visitor) { + if (this.features) { + this.features = visitor.visit(this.features); + } - if (compress) { - var splitcolor = color.split(''); + if (this.rules) { + this.rules = visitor.visitArray(this.rules); + } + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + output.add('@media ', this._fileInfo, this._index); + this.features.genCSS(context, output); + this.outputRuleset(context, output, this.rules); + } + }, { + key: "eval", + value: function _eval(context) { + if (!context.mediaBlocks) { + context.mediaBlocks = []; + context.mediaPath = []; + } + + var media = new Media(null, [], this._index, this._fileInfo, this.visibilityInfo()); + + if (this.debugInfo) { + this.rules[0].debugInfo = this.debugInfo; + media.debugInfo = this.debugInfo; + } + + media.features = this.features.eval(context); + context.mediaPath.push(media); + context.mediaBlocks.push(media); + this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit(); + context.frames.unshift(this.rules[0]); + media.rules = [this.rules[0].eval(context)]; + context.frames.shift(); + context.mediaPath.pop(); + return context.mediaPath.length === 0 ? media.evalTop(context) : media.evalNested(context); + } + }, { + key: "evalTop", + value: function evalTop(context) { + var result = this; // Render all dependent Media blocks. - // Convert color to short format - if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) { - color = '#' + splitcolor[1] + splitcolor[3] + splitcolor[5]; + if (context.mediaBlocks.length > 1) { + var selectors = new Selector([], null, null, this.getIndex(), this.fileInfo()).createEmptySelectors(); + result = new Ruleset(selectors, context.mediaBlocks); + result.multiMedia = true; + result.copyVisibilityInfo(this.visibilityInfo()); + this.setParent(result, this); } - } - return color; -}; + delete context.mediaBlocks; + delete context.mediaPath; + return result; + } + }, { + key: "evalNested", + value: function evalNested(context) { + var i; + var value; + var path = context.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). + + for (i = 0; i < path.length; i++) { + value = path[i].features instanceof Value ? path[i].features.value : path[i].features; + path[i] = Array.isArray(value) ? value : [value]; + } // Trace all permutations to generate the resulting media-query. + // + // (a, b and c) with nested (d, e) -> + // a and d + // a and e + // b and c and d + // b and c and e -// -// Operations have to be done per-channel, if not, -// channels will spill onto each other. Once we have -// our result, in the form of an integer triplet, -// we create a new Color node to hold the result. -// -Color.prototype.operate = function (context, op, other) { - var rgb = new Array(3); - var alpha = this.alpha * (1 - other.alpha) + other.alpha; - for (var c = 0; c < 3; c++) { - rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]); - } - return new Color(rgb, alpha); -}; -Color.prototype.toRGB = function () { - return toHex(this.rgb); -}; -Color.prototype.toHSL = function () { - var r = this.rgb[0] / 255, - g = this.rgb[1] / 255, - b = this.rgb[2] / 255, - a = this.alpha; - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h, s, l = (max + min) / 2, d = max - min; + this.features = new Value(this.permute(path).map(function (path) { + path = path.map(function (fragment) { + return fragment.toCSS ? fragment : new Anonymous(fragment); + }); - if (max === min) { - h = s = 0; - } else { - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - - switch (max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - return { h: h * 360, s: s, l: l, a: a }; -}; -// Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript -Color.prototype.toHSV = function () { - var r = this.rgb[0] / 255, - g = this.rgb[1] / 255, - b = this.rgb[2] / 255, - a = this.alpha; - - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h, s, v = max; - - var d = max - min; - if (max === 0) { - s = 0; - } else { - s = d / max; - } + for (i = path.length - 1; i > 0; i--) { + path.splice(i, 0, new Anonymous('and')); + } - if (max === min) { - h = 0; - } else { - switch (max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - return { h: h * 360, s: s, v: v, a: a }; -}; -Color.prototype.toARGB = function () { - return toHex([this.alpha * 255].concat(this.rgb)); -}; -Color.prototype.compare = function (x) { - return (x.rgb && - x.rgb[0] === this.rgb[0] && - x.rgb[1] === this.rgb[1] && - x.rgb[2] === this.rgb[2] && - x.alpha === this.alpha) ? 0 : undefined; -}; - -Color.fromKeyword = function(keyword) { - var c, key = keyword.toLowerCase(); - if (colors.hasOwnProperty(key)) { - c = new Color(colors[key].slice(1)); - } - else if (key === 'transparent') { - c = new Color([0, 0, 0], 0); - } + return new Expression(path); + })); + this.setParent(this.features, this); // Fake a tree-node that doesn't output anything. - if (c) { - c.value = keyword; - return c; - } -}; -module.exports = Color; + return new Ruleset([], []); + } + }, { + key: "permute", + value: function permute(arr) { + if (arr.length === 0) { + return []; + } else if (arr.length === 1) { + return arr[0]; + } else { + var result = []; + var rest = this.permute(arr.slice(1)); -},{"../data/colors":14,"./node":76}],56:[function(require,module,exports){ -var Node = require('./node'); + for (var i = 0; i < rest.length; i++) { + for (var j = 0; j < arr[0].length; j++) { + result.push([arr[0][j]].concat(rest[i])); + } + } -var Combinator = function (value) { - if (value === ' ') { - this.value = ' '; - this.emptyOrWhitespace = true; - } else { - this.value = value ? value.trim() : ''; - this.emptyOrWhitespace = this.value === ''; - } -}; -Combinator.prototype = new Node(); -Combinator.prototype.type = 'Combinator'; -var _noSpaceCombinators = { - '': true, - ' ': true, - '|': true -}; -Combinator.prototype.genCSS = function (context, output) { - var spaceOrEmpty = (context.compress || _noSpaceCombinators[this.value]) ? '' : ' '; - output.add(spaceOrEmpty + this.value + spaceOrEmpty); -}; -module.exports = Combinator; - -},{"./node":76}],57:[function(require,module,exports){ -var Node = require('./node'), - getDebugInfo = require('./debug-info'); - -var Comment = function (value, isLineComment, index, currentFileInfo) { - this.value = value; - this.isLineComment = isLineComment; - this._index = index; - this._fileInfo = currentFileInfo; - this.allowRoot = true; -}; -Comment.prototype = new Node(); -Comment.prototype.type = 'Comment'; -Comment.prototype.genCSS = function (context, output) { - if (this.debugInfo) { - output.add(getDebugInfo(context, this), this.fileInfo(), this.getIndex()); - } - output.add(this.value); -}; -Comment.prototype.isSilent = function(context) { - var isCompressed = context.compress && this.value[2] !== '!'; - return this.isLineComment || isCompressed; -}; -module.exports = Comment; - -},{"./debug-info":59,"./node":76}],58:[function(require,module,exports){ -var Node = require('./node'); - -var Condition = function (op, l, r, i, negate) { - this.op = op.trim(); - this.lvalue = l; - this.rvalue = r; - this._index = i; - this.negate = negate; -}; -Condition.prototype = new Node(); -Condition.prototype.type = 'Condition'; -Condition.prototype.accept = function (visitor) { - this.lvalue = visitor.visit(this.lvalue); - this.rvalue = visitor.visit(this.rvalue); -}; -Condition.prototype.eval = function (context) { - var result = (function (op, a, b) { - switch (op) { - case 'and': return a && b; - case 'or': return a || b; - default: - switch (Node.compare(a, b)) { - case -1: - return op === '<' || op === '=<' || op === '<='; - case 0: - return op === '=' || op === '>=' || op === '=<' || op === '<='; - case 1: - return op === '>' || op === '>='; - default: - return false; - } + return result; + } + } + }, { + key: "bubbleSelectors", + value: function bubbleSelectors(selectors) { + if (!selectors) { + return; } - })(this.op, this.lvalue.eval(context), this.rvalue.eval(context)); - return this.negate ? !result : result; -}; -module.exports = Condition; + this.rules = [new Ruleset(copyArray(selectors), [this.rules[0]])]; + this.setParent(this.rules, this); + } + }]); + + return Media; + }(AtRule); + + Media.prototype.type = 'Media'; + + // CSS @import node + // + // The general strategy here is that we don't want to wait + // for the parsing to be completed, before we start importing + // the file. That's because in the context of a browser, + // most of the time will be spent waiting for the server to respond. + // + // On creation, we push the import path to our import queue, though + // `import,push`, we also pass it a callback, which it'll call once + // the file has been fetched, and parsed. + // + + var Import = + /*#__PURE__*/ + function (_Node) { + _inherits(Import, _Node); + + function Import(path, features, options, index, currentFileInfo, visibilityInfo) { + var _this; + + _classCallCheck(this, Import); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(Import).call(this)); + _this.options = options; + _this._index = index; + _this._fileInfo = currentFileInfo; + _this.path = path; + _this.features = features; + _this.allowRoot = true; + + if (_this.options.less !== undefined || _this.options.inline) { + _this.css = !_this.options.less || _this.options.inline; + } else { + var pathValue = _this.getPath(); -},{"./node":76}],59:[function(require,module,exports){ -var debugInfo = function(context, ctx, lineSeparator) { - var result = ''; - if (context.dumpLineNumbers && !context.compress) { - switch (context.dumpLineNumbers) { - case 'comments': - result = debugInfo.asComment(ctx); - break; - case 'mediaquery': - result = debugInfo.asMediaQuery(ctx); - break; - case 'all': - result = debugInfo.asComment(ctx) + (lineSeparator || '') + debugInfo.asMediaQuery(ctx); - break; + if (pathValue && /[#\.\&\?]css([\?;].*)?$/.test(pathValue)) { + _this.css = true; } - } - return result; -}; + } -debugInfo.asComment = function(ctx) { - return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; -}; + _this.copyVisibilityInfo(visibilityInfo); -debugInfo.asMediaQuery = function(ctx) { - var filenameWithProtocol = ctx.debugInfo.fileName; - if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) { - filenameWithProtocol = 'file://' + filenameWithProtocol; - } - return '@media -sass-debug-info{filename{font-family:' + - filenameWithProtocol.replace(/([.:\/\\])/g, function (a) { - if (a == '\\') { - a = '\/'; - } - return '\\' + a; - }) + - '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; -}; - -module.exports = debugInfo; - -},{}],60:[function(require,module,exports){ -var Node = require('./node'), - Value = require('./value'), - Keyword = require('./keyword'), - Anonymous = require('./anonymous'), - MATH = require('../constants').Math; - -var Declaration = function (name, value, important, merge, index, currentFileInfo, inline, variable) { - this.name = name; - this.value = (value instanceof Node) ? value : new Value([value ? new Anonymous(value) : null]); - this.important = important ? ' ' + important.trim() : ''; - this.merge = merge; - this._index = index; - this._fileInfo = currentFileInfo; - this.inline = inline || false; - this.variable = (variable !== undefined) ? variable - : (name.charAt && (name.charAt(0) === '@')); - this.allowRoot = true; - this.setParent(this.value, this); -}; - -function evalName(context, name) { - var value = '', i, n = name.length, - output = {add: function (s) {value += s;}}; - for (i = 0; i < n; i++) { - name[i].eval(context).genCSS(context, output); - } - return value; -} + _this.setParent(_this.features, _assertThisInitialized(_this)); -Declaration.prototype = new Node(); -Declaration.prototype.type = 'Declaration'; -Declaration.prototype.genCSS = function (context, output) { - output.add(this.name + (context.compress ? ':' : ': '), this.fileInfo(), this.getIndex()); - try { - this.value.genCSS(context, output); - } - catch (e) { - e.index = this._index; - e.filename = this._fileInfo.filename; - throw e; - } - output.add(this.important + ((this.inline || (context.lastRule && context.compress)) ? '' : ';'), this._fileInfo, this._index); -}; -Declaration.prototype.eval = function (context) { - var mathBypass = false, prevMath, name = this.name, evaldValue, variable = this.variable; - if (typeof name !== 'string') { - // expand 'primitive' name directly to get - // things faster (~10% for benchmark.less): - name = (name.length === 1) && (name[0] instanceof Keyword) ? - name[0].value : evalName(context, name); - variable = false; // never treat expanded interpolation as new variable name - } + _this.setParent(_this.path, _assertThisInitialized(_this)); - // @todo remove when parens-division is default - if (name === 'font' && context.math === MATH.ALWAYS) { - mathBypass = true; - prevMath = context.math; - context.math = MATH.PARENS_DIVISION; + return _this; } - try { - context.importantScope.push({}); - evaldValue = this.value.eval(context); - if (!this.variable && evaldValue.type === 'DetachedRuleset') { - throw { message: 'Rulesets cannot be evaluated on a property.', - index: this.getIndex(), filename: this.fileInfo().filename }; - } - var important = this.important, - importantResult = context.importantScope.pop(); - if (!important && importantResult.important) { - important = importantResult.important; + _createClass(Import, [{ + key: "accept", + value: function accept(visitor) { + if (this.features) { + this.features = visitor.visit(this.features); } - return new Declaration(name, - evaldValue, - important, - this.merge, - this.getIndex(), this.fileInfo(), this.inline, - variable); - } - catch (e) { - if (typeof e.index !== 'number') { - e.index = this.getIndex(); - e.filename = this.fileInfo().filename; + this.path = visitor.visit(this.path); + + if (!this.options.isPlugin && !this.options.inline && this.root) { + this.root = visitor.visit(this.root); } - throw e; - } - finally { - if (mathBypass) { - context.math = prevMath; + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + if (this.css && this.path._fileInfo.reference === undefined) { + output.add('@import ', this._fileInfo, this._index); + this.path.genCSS(context, output); + + if (this.features) { + output.add(' '); + this.features.genCSS(context, output); + } + + output.add(';'); } - } -}; -Declaration.prototype.makeImportant = function () { - return new Declaration(this.name, - this.value, - '!important', - this.merge, - this.getIndex(), this.fileInfo(), this.inline); -}; - -module.exports = Declaration; -},{"../constants":12,"./anonymous":50,"./keyword":70,"./node":76,"./value":86}],61:[function(require,module,exports){ -var Node = require('./node'), - contexts = require('../contexts'), - utils = require('../utils'); - -var DetachedRuleset = function (ruleset, frames) { - this.ruleset = ruleset; - this.frames = frames; - this.setParent(this.ruleset, this); -}; -DetachedRuleset.prototype = new Node(); -DetachedRuleset.prototype.type = 'DetachedRuleset'; -DetachedRuleset.prototype.evalFirst = true; -DetachedRuleset.prototype.accept = function (visitor) { - this.ruleset = visitor.visit(this.ruleset); -}; -DetachedRuleset.prototype.eval = function (context) { - var frames = this.frames || utils.copyArray(context.frames); - return new DetachedRuleset(this.ruleset, frames); -}; -DetachedRuleset.prototype.callEval = function (context) { - return this.ruleset.eval(this.frames ? new contexts.Eval(context, this.frames.concat(context.frames)) : context); -}; -module.exports = DetachedRuleset; - -},{"../contexts":13,"../utils":89,"./node":76}],62:[function(require,module,exports){ -var Node = require('./node'), - unitConversions = require('../data/unit-conversions'), - Unit = require('./unit'), - Color = require('./color'); - -// -// A number with a unit -// -var Dimension = function (value, unit) { - this.value = parseFloat(value); - if (isNaN(this.value)) { - throw new Error('Dimension is not a number.'); - } - this.unit = (unit && unit instanceof Unit) ? unit : - new Unit(unit ? [unit] : undefined); - this.setParent(this.unit, this); -}; - -Dimension.prototype = new Node(); -Dimension.prototype.type = 'Dimension'; -Dimension.prototype.accept = function (visitor) { - this.unit = visitor.visit(this.unit); -}; -Dimension.prototype.eval = function (context) { - return this; -}; -Dimension.prototype.toColor = function () { - return new Color([this.value, this.value, this.value]); -}; -Dimension.prototype.genCSS = function (context, output) { - if ((context && context.strictUnits) && !this.unit.isSingular()) { - throw new Error('Multiple units in dimension. Correct the units or use the unit function. Bad unit: ' + this.unit.toString()); - } - - var value = this.fround(context, this.value), - strValue = String(value); - - if (value !== 0 && value < 0.000001 && value > -0.000001) { - // would be output 1e-6 etc. - strValue = value.toFixed(20).replace(/0+$/, ''); - } - - if (context && context.compress) { - // Zero values doesn't need a unit - if (value === 0 && this.unit.isLength()) { - output.add(strValue); - return; + } + }, { + key: "getPath", + value: function getPath() { + return this.path instanceof URL ? this.path.value.value : this.path.value; + } + }, { + key: "isVariableImport", + value: function isVariableImport() { + var path = this.path; + + if (path instanceof URL) { + path = path.value; } - // Float values doesn't need a leading zero - if (value > 0 && value < 1) { - strValue = (strValue).substr(1); + if (path instanceof Quoted) { + return path.containsVariables(); } - } - output.add(strValue); - this.unit.genCSS(context, output); -}; + return true; + } + }, { + key: "evalForImport", + value: function evalForImport(context) { + var path = this.path; -// In an operation between two Dimensions, -// we default to the first Dimension's unit, -// so `1px + 2` will yield `3px`. -Dimension.prototype.operate = function (context, op, other) { - /* jshint noempty:false */ - var value = this._operate(context, op, this.value, other.value), - unit = this.unit.clone(); + if (path instanceof URL) { + path = path.value; + } - if (op === '+' || op === '-') { - if (unit.numerator.length === 0 && unit.denominator.length === 0) { - unit = other.unit.clone(); - if (this.unit.backupUnit) { - unit.backupUnit = this.unit.backupUnit; - } - } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) { - // do nothing - } else { - other = other.convertTo(this.unit.usedUnits()); + return new Import(path.eval(context), this.features, this.options, this._index, this._fileInfo, this.visibilityInfo()); + } + }, { + key: "evalPath", + value: function evalPath(context) { + var path = this.path.eval(context); + var fileInfo = this._fileInfo; - if (context.strictUnits && other.unit.toString() !== unit.toString()) { - throw new Error('Incompatible units. Change the units or use the unit function. Bad units: \'' + unit.toString() + - '\' and \'' + other.unit.toString() + '\'.'); - } + if (!(path instanceof URL)) { + // Add the rootpath if the URL requires a rewrite + var pathValue = path.value; - value = this._operate(context, op, this.value, other.value); + if (fileInfo && pathValue && context.pathRequiresRewrite(pathValue)) { + path.value = context.rewritePath(pathValue, fileInfo.rootpath); + } else { + path.value = context.normalizePath(path.value); + } } - } else if (op === '*') { - unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); - unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); - unit.cancel(); - } else if (op === '/') { - unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); - unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); - unit.cancel(); - } - return new Dimension(value, unit); -}; -Dimension.prototype.compare = function (other) { - var a, b; - if (!(other instanceof Dimension)) { - return undefined; - } + return path; + } + }, { + key: "eval", + value: function _eval(context) { + var result = this.doEval(context); - if (this.unit.isEmpty() || other.unit.isEmpty()) { - a = this; - b = other; - } else { - a = this.unify(); - b = other.unify(); - if (a.unit.compare(b.unit) !== 0) { - return undefined; + if (this.options.reference || this.blocksVisibility()) { + if (result.length || result.length === 0) { + result.forEach(function (node) { + node.addVisibilityBlock(); + }); + } else { + result.addVisibilityBlock(); + } } - } - return Node.numericCompare(a.value, b.value); -}; -Dimension.prototype.unify = function () { - return this.convertTo({ length: 'px', duration: 's', angle: 'rad' }); -}; -Dimension.prototype.convertTo = function (conversions) { - var value = this.value, unit = this.unit.clone(), - i, groupName, group, targetUnit, derivedConversions = {}, applyUnit; - - if (typeof conversions === 'string') { - for (i in unitConversions) { - if (unitConversions[i].hasOwnProperty(conversions)) { - derivedConversions = {}; - derivedConversions[i] = conversions; + return result; + } + }, { + key: "doEval", + value: function doEval(context) { + var ruleset; + var registry; + var features = this.features && this.features.eval(context); + + if (this.options.isPlugin) { + if (this.root && this.root.eval) { + try { + this.root.eval(context); + } catch (e) { + e.message = 'Plugin error during evaluation'; + throw new LessError(e, this.root.imports, this.root.filename); } + } + + registry = context.frames[0] && context.frames[0].functionRegistry; + + if (registry && this.root && this.root.functions) { + registry.addMultiple(this.root.functions); + } + + return []; } - conversions = derivedConversions; - } - applyUnit = function (atomicUnit, denominator) { - /* jshint loopfunc:true */ - if (group.hasOwnProperty(atomicUnit)) { - if (denominator) { - value = value / (group[atomicUnit] / group[targetUnit]); - } else { - value = value * (group[atomicUnit] / group[targetUnit]); - } - return targetUnit; + if (this.skip) { + if (typeof this.skip === 'function') { + this.skip = this.skip(); + } + + if (this.skip) { + return []; + } } - return atomicUnit; - }; + if (this.options.inline) { + var contents = new Anonymous(this.root, 0, { + filename: this.importedFilename, + reference: this.path._fileInfo && this.path._fileInfo.reference + }, true, true); + return this.features ? new Media([contents], this.features.value) : [contents]; + } else if (this.css) { + var newImport = new Import(this.evalPath(context), features, this.options, this._index); - for (groupName in conversions) { - if (conversions.hasOwnProperty(groupName)) { - targetUnit = conversions[groupName]; - group = unitConversions[groupName]; + if (!newImport.css && this.error) { + throw this.error; + } - unit.map(applyUnit); + return newImport; + } else { + ruleset = new Ruleset(null, copyArray(this.root.rules)); + ruleset.evalImports(context); + return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules; } - } + } + }]); - unit.cancel(); + return Import; + }(Node); - return new Dimension(value, unit); -}; -module.exports = Dimension; + Import.prototype.type = 'Import'; -},{"../data/unit-conversions":16,"./color":55,"./node":76,"./unit":84}],63:[function(require,module,exports){ -var Node = require('./node'), - Paren = require('./paren'), - Combinator = require('./combinator'); + var JsEvalNode = + /*#__PURE__*/ + function (_Node) { + _inherits(JsEvalNode, _Node); -var Element = function (combinator, value, isVariable, index, currentFileInfo, visibilityInfo) { - this.combinator = combinator instanceof Combinator ? - combinator : new Combinator(combinator); + function JsEvalNode() { + _classCallCheck(this, JsEvalNode); - if (typeof value === 'string') { - this.value = value.trim(); - } else if (value) { - this.value = value; - } else { - this.value = ''; - } - this.isVariable = isVariable; - this._index = index; - this._fileInfo = currentFileInfo; - this.copyVisibilityInfo(visibilityInfo); - this.setParent(this.combinator, this); -}; -Element.prototype = new Node(); -Element.prototype.type = 'Element'; -Element.prototype.accept = function (visitor) { - var value = this.value; - this.combinator = visitor.visit(this.combinator); - if (typeof value === 'object') { - this.value = visitor.visit(value); - } -}; -Element.prototype.eval = function (context) { - return new Element(this.combinator, - this.value.eval ? this.value.eval(context) : this.value, - this.isVariable, - this.getIndex(), - this.fileInfo(), this.visibilityInfo()); -}; -Element.prototype.clone = function () { - return new Element(this.combinator, - this.value, - this.isVariable, - this.getIndex(), - this.fileInfo(), this.visibilityInfo()); -}; -Element.prototype.genCSS = function (context, output) { - output.add(this.toCSS(context), this.fileInfo(), this.getIndex()); -}; -Element.prototype.toCSS = function (context) { - context = context || {}; - var value = this.value, firstSelector = context.firstSelector; - if (value instanceof Paren) { - // selector in parens should not be affected by outer selector - // flags (breaks only interpolated selectors - see #1973) - context.firstSelector = true; - } - value = value.toCSS ? value.toCSS(context) : value; - context.firstSelector = firstSelector; - if (value === '' && this.combinator.value.charAt(0) === '&') { - return ''; - } else { - return this.combinator.toCSS(context) + value; - } -}; -module.exports = Element; - -},{"./combinator":56,"./node":76,"./paren":78}],64:[function(require,module,exports){ -var Node = require('./node'), - Paren = require('./paren'), - Comment = require('./comment'), - Dimension = require('./dimension'), - MATH = require('../constants').Math; - -var Expression = function (value, noSpacing) { - this.value = value; - this.noSpacing = noSpacing; - if (!value) { - throw new Error('Expression requires an array parameter'); - } -}; -Expression.prototype = new Node(); -Expression.prototype.type = 'Expression'; -Expression.prototype.accept = function (visitor) { - this.value = visitor.visitArray(this.value); -}; -Expression.prototype.eval = function (context) { - var returnValue, - mathOn = context.isMathOn(), - inParenthesis = this.parens && - (context.math !== MATH.STRICT_LEGACY || !this.parensInOp), - doubleParen = false; - if (inParenthesis) { - context.inParenthesis(); - } - if (this.value.length > 1) { - returnValue = new Expression(this.value.map(function (e) { - if (!e.eval) { - return e; - } - return e.eval(context); - }), this.noSpacing); - } else if (this.value.length === 1) { - if (this.value[0].parens && !this.value[0].parensInOp && !context.inCalc) { - doubleParen = true; - } - returnValue = this.value[0].eval(context); - } else { - returnValue = this; - } - if (inParenthesis) { - context.outOfParenthesis(); - } - if (this.parens && this.parensInOp && !mathOn && !doubleParen - && (!(returnValue instanceof Dimension))) { - returnValue = new Paren(returnValue); - } - return returnValue; -}; -Expression.prototype.genCSS = function (context, output) { - for (var i = 0; i < this.value.length; i++) { - this.value[i].genCSS(context, output); - if (!this.noSpacing && i + 1 < this.value.length) { - output.add(' '); - } - } -}; -Expression.prototype.throwAwayComments = function () { - this.value = this.value.filter(function(v) { - return !(v instanceof Comment); - }); -}; -module.exports = Expression; - -},{"../constants":12,"./comment":57,"./dimension":62,"./node":76,"./paren":78}],65:[function(require,module,exports){ -var Node = require('./node'), - Selector = require('./selector'); - -var Extend = function Extend(selector, option, index, currentFileInfo, visibilityInfo) { - this.selector = selector; - this.option = option; - this.object_id = Extend.next_id++; - this.parent_ids = [this.object_id]; - this._index = index; - this._fileInfo = currentFileInfo; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; - - switch (option) { - case 'all': - this.allowBefore = true; - this.allowAfter = true; - break; - default: - this.allowBefore = false; - this.allowAfter = false; - break; + return _possibleConstructorReturn(this, _getPrototypeOf(JsEvalNode).apply(this, arguments)); } - this.setParent(this.selector, this); -}; -Extend.next_id = 0; - -Extend.prototype = new Node(); -Extend.prototype.type = 'Extend'; -Extend.prototype.accept = function (visitor) { - this.selector = visitor.visit(this.selector); -}; -Extend.prototype.eval = function (context) { - return new Extend(this.selector.eval(context), this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); -}; -Extend.prototype.clone = function (context) { - return new Extend(this.selector, this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); -}; -// it concatenates (joins) all selectors in selector array -Extend.prototype.findSelfSelectors = function (selectors) { - var selfElements = [], - i, - selectorElements; - - for (i = 0; i < selectors.length; i++) { - selectorElements = selectors[i].elements; - // duplicate the logic in genCSS function inside the selector node. - // future TODO - move both logics into the selector joiner visitor - if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === '') { - selectorElements[0].combinator.value = ' '; + + _createClass(JsEvalNode, [{ + key: "evaluateJavaScript", + value: function evaluateJavaScript(expression, context) { + var result; + var that = this; + var evalContext = {}; + + if (!context.javascriptEnabled) { + throw { + message: 'Inline JavaScript is not enabled. Is it set in your options?', + filename: this.fileInfo().filename, + index: this.getIndex() + }; } - selfElements = selfElements.concat(selectors[i].elements); - } - - this.selfSelectors = [new Selector(selfElements)]; - this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo()); -}; -module.exports = Extend; - -},{"./node":76,"./selector":82}],66:[function(require,module,exports){ -var Node = require('./node'), - Media = require('./media'), - URL = require('./url'), - Quoted = require('./quoted'), - Ruleset = require('./ruleset'), - Anonymous = require('./anonymous'), - utils = require('../utils'), - LessError = require('../less-error'); - -// -// CSS @import node -// -// The general strategy here is that we don't want to wait -// for the parsing to be completed, before we start importing -// the file. That's because in the context of a browser, -// most of the time will be spent waiting for the server to respond. -// -// On creation, we push the import path to our import queue, though -// `import,push`, we also pass it a callback, which it'll call once -// the file has been fetched, and parsed. -// -var Import = function (path, features, options, index, currentFileInfo, visibilityInfo) { - this.options = options; - this._index = index; - this._fileInfo = currentFileInfo; - this.path = path; - this.features = features; - this.allowRoot = true; - - if (this.options.less !== undefined || this.options.inline) { - this.css = !this.options.less || this.options.inline; - } else { - var pathValue = this.getPath(); - if (pathValue && /[#\.\&\?]css([\?;].*)?$/.test(pathValue)) { - this.css = true; - } - } - this.copyVisibilityInfo(visibilityInfo); - this.setParent(this.features, this); - this.setParent(this.path, this); -}; - -// -// The actual import node doesn't return anything, when converted to CSS. -// The reason is that it's used at the evaluation stage, so that the rules -// it imports can be treated like any other rules. -// -// In `eval`, we make sure all Import nodes get evaluated, recursively, so -// we end up with a flat structure, which can easily be imported in the parent -// ruleset. -// -Import.prototype = new Node(); -Import.prototype.type = 'Import'; -Import.prototype.accept = function (visitor) { - if (this.features) { - this.features = visitor.visit(this.features); - } - this.path = visitor.visit(this.path); - if (!this.options.isPlugin && !this.options.inline && this.root) { - this.root = visitor.visit(this.root); - } -}; -Import.prototype.genCSS = function (context, output) { - if (this.css && this.path._fileInfo.reference === undefined) { - output.add('@import ', this._fileInfo, this._index); - this.path.genCSS(context, output); - if (this.features) { - output.add(' '); - this.features.genCSS(context, output); + + expression = expression.replace(/@\{([\w-]+)\}/g, function (_, name) { + return that.jsify(new Variable("@".concat(name), that.getIndex(), that.fileInfo()).eval(context)); + }); + + try { + expression = new Function("return (".concat(expression, ")")); + } catch (e) { + throw { + message: "JavaScript evaluation error: ".concat(e.message, " from `").concat(expression, "`"), + filename: this.fileInfo().filename, + index: this.getIndex() + }; } - output.add(';'); - } -}; -Import.prototype.getPath = function () { - return (this.path instanceof URL) ? - this.path.value.value : this.path.value; -}; -Import.prototype.isVariableImport = function () { - var path = this.path; - if (path instanceof URL) { - path = path.value; - } - if (path instanceof Quoted) { - return path.containsVariables(); - } - return true; -}; -Import.prototype.evalForImport = function (context) { - var path = this.path; + var variables = context.frames[0].variables(); - if (path instanceof URL) { - path = path.value; - } + for (var k in variables) { + if (variables.hasOwnProperty(k)) { + /* jshint loopfunc:true */ + evalContext[k.slice(1)] = { + value: variables[k].value, + toJS: function toJS() { + return this.value.eval(context).toCSS(); + } + }; + } + } - return new Import(path.eval(context), this.features, this.options, this._index, this._fileInfo, this.visibilityInfo()); -}; -Import.prototype.evalPath = function (context) { - var path = this.path.eval(context); - var fileInfo = this._fileInfo; + try { + result = expression.call(evalContext); + } catch (e) { + throw { + message: "JavaScript evaluation error: '".concat(e.name, ": ").concat(e.message.replace(/["]/g, '\''), "'"), + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } - if (!(path instanceof URL)) { - // Add the rootpath if the URL requires a rewrite - var pathValue = path.value; - if (fileInfo && - pathValue && - context.pathRequiresRewrite(pathValue)) { - path.value = context.rewritePath(pathValue, fileInfo.rootpath); + return result; + } + }, { + key: "jsify", + value: function jsify(obj) { + if (Array.isArray(obj.value) && obj.value.length > 1) { + return "[".concat(obj.value.map(function (v) { + return v.toCSS(); + }).join(', '), "]"); } else { - path.value = context.normalizePath(path.value); + return obj.toCSS(); } + } + }]); + + return JsEvalNode; + }(Node); + + var JavaScript = + /*#__PURE__*/ + function (_JsEvalNode) { + _inherits(JavaScript, _JsEvalNode); + + function JavaScript(string, escaped, index, currentFileInfo) { + var _this; + + _classCallCheck(this, JavaScript); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(JavaScript).call(this)); + _this.escaped = escaped; + _this.expression = string; + _this._index = index; + _this._fileInfo = currentFileInfo; + return _this; } - return path; -}; -Import.prototype.eval = function (context) { - var result = this.doEval(context); - if (this.options.reference || this.blocksVisibility()) { - if (result.length || result.length === 0) { - result.forEach(function (node) { - node.addVisibilityBlock(); - } - ); + _createClass(JavaScript, [{ + key: "eval", + value: function _eval(context) { + var result = this.evaluateJavaScript(this.expression, context); + + var type = _typeof(result); + + if (type === 'number' && !isNaN(result)) { + return new Dimension(result); + } else if (type === 'string') { + return new Quoted("\"".concat(result, "\""), result, this.escaped, this._index); + } else if (Array.isArray(result)) { + return new Anonymous(result.join(', ')); } else { - result.addVisibilityBlock(); + return new Anonymous(result); } - } - return result; -}; -Import.prototype.doEval = function (context) { - var ruleset, registry, - features = this.features && this.features.eval(context); + } + }]); - if (this.options.isPlugin) { - if (this.root && this.root.eval) { - try { - this.root.eval(context); - } - catch (e) { - e.message = 'Plugin error during evaluation'; - throw new LessError(e, this.root.imports, this.root.filename); - } - } - registry = context.frames[0] && context.frames[0].functionRegistry; - if ( registry && this.root && this.root.functions ) { - registry.addMultiple( this.root.functions ); - } + return JavaScript; + }(JsEvalNode); - return []; + JavaScript.prototype.type = 'JavaScript'; + + var Assignment = + /*#__PURE__*/ + function (_Node) { + _inherits(Assignment, _Node); + + function Assignment(key, val) { + var _this; + + _classCallCheck(this, Assignment); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(Assignment).call(this)); + _this.key = key; + _this.value = val; + return _this; } - if (this.skip) { - if (typeof this.skip === 'function') { - this.skip = this.skip(); - } - if (this.skip) { - return []; + _createClass(Assignment, [{ + key: "accept", + value: function accept(visitor) { + this.value = visitor.visit(this.value); + } + }, { + key: "eval", + value: function _eval(context) { + if (this.value.eval) { + return new Assignment(this.key, this.value.eval(context)); } - } - if (this.options.inline) { - var contents = new Anonymous(this.root, 0, - { - filename: this.importedFilename, - reference: this.path._fileInfo && this.path._fileInfo.reference - }, true, true); - return this.features ? new Media([contents], this.features.value) : [contents]; - } else if (this.css) { - var newImport = new Import(this.evalPath(context), features, this.options, this._index); - if (!newImport.css && this.error) { - throw this.error; + return this; + } + }, { + key: "genCSS", + value: function genCSS(context, output) { + output.add("".concat(this.key, "=")); + + if (this.value.genCSS) { + this.value.genCSS(context, output); + } else { + output.add(this.value); } - return newImport; - } else { - ruleset = new Ruleset(null, utils.copyArray(this.root.rules)); - ruleset.evalImports(context); - - return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules; - } -}; -module.exports = Import; - -},{"../less-error":38,"../utils":89,"./anonymous":50,"./media":71,"./node":76,"./quoted":80,"./ruleset":81,"./url":85}],67:[function(require,module,exports){ -var tree = Object.create(null); - -tree.Node = require('./node'); -tree.Color = require('./color'); -tree.AtRule = require('./atrule'); -tree.DetachedRuleset = require('./detached-ruleset'); -tree.Operation = require('./operation'); -tree.Dimension = require('./dimension'); -tree.Unit = require('./unit'); -tree.Keyword = require('./keyword'); -tree.Variable = require('./variable'); -tree.Property = require('./property'); -tree.Ruleset = require('./ruleset'); -tree.Element = require('./element'); -tree.Attribute = require('./attribute'); -tree.Combinator = require('./combinator'); -tree.Selector = require('./selector'); -tree.Quoted = require('./quoted'); -tree.Expression = require('./expression'); -tree.Declaration = require('./declaration'); -tree.Call = require('./call'); -tree.URL = require('./url'); -tree.Import = require('./import'); -tree.mixin = { - Call: require('./mixin-call'), - Definition: require('./mixin-definition') -}; -tree.Comment = require('./comment'); -tree.Anonymous = require('./anonymous'); -tree.Value = require('./value'); -tree.JavaScript = require('./javascript'); -tree.Assignment = require('./assignment'); -tree.Condition = require('./condition'); -tree.Paren = require('./paren'); -tree.Media = require('./media'); -tree.UnicodeDescriptor = require('./unicode-descriptor'); -tree.Negative = require('./negative'); -tree.Extend = require('./extend'); -tree.VariableCall = require('./variable-call'); -tree.NamespaceValue = require('./namespace-value'); - -module.exports = tree; - -},{"./anonymous":50,"./assignment":51,"./atrule":52,"./attribute":53,"./call":54,"./color":55,"./combinator":56,"./comment":57,"./condition":58,"./declaration":60,"./detached-ruleset":61,"./dimension":62,"./element":63,"./expression":64,"./extend":65,"./import":66,"./javascript":68,"./keyword":70,"./media":71,"./mixin-call":72,"./mixin-definition":73,"./namespace-value":74,"./negative":75,"./node":76,"./operation":77,"./paren":78,"./property":79,"./quoted":80,"./ruleset":81,"./selector":82,"./unicode-descriptor":83,"./unit":84,"./url":85,"./value":86,"./variable":88,"./variable-call":87}],68:[function(require,module,exports){ -var JsEvalNode = require('./js-eval-node'), - Dimension = require('./dimension'), - Quoted = require('./quoted'), - Anonymous = require('./anonymous'); - -var JavaScript = function (string, escaped, index, currentFileInfo) { - this.escaped = escaped; - this.expression = string; - this._index = index; - this._fileInfo = currentFileInfo; -}; -JavaScript.prototype = new JsEvalNode(); -JavaScript.prototype.type = 'JavaScript'; -JavaScript.prototype.eval = function(context) { - var result = this.evaluateJavaScript(this.expression, context); - var type = typeof result; - - if (type === 'number' && !isNaN(result)) { - return new Dimension(result); - } else if (type === 'string') { - return new Quoted('"' + result + '"', result, this.escaped, this._index); - } else if (Array.isArray(result)) { - return new Anonymous(result.join(', ')); - } else { - return new Anonymous(result); + } + }]); + + return Assignment; + }(Node); + + Assignment.prototype.type = 'Assignment'; + + var Condition = + /*#__PURE__*/ + function (_Node) { + _inherits(Condition, _Node); + + function Condition(op, l, r, i, negate) { + var _this; + + _classCallCheck(this, Condition); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(Condition).call(this)); + _this.op = op.trim(); + _this.lvalue = l; + _this.rvalue = r; + _this._index = i; + _this.negate = negate; + return _this; } -}; -module.exports = JavaScript; + _createClass(Condition, [{ + key: "accept", + value: function accept(visitor) { + this.lvalue = visitor.visit(this.lvalue); + this.rvalue = visitor.visit(this.rvalue); + } + }, { + key: "eval", + value: function _eval(context) { + var result = function (op, a, b) { + switch (op) { + case 'and': + return a && b; + + case 'or': + return a || b; -},{"./anonymous":50,"./dimension":62,"./js-eval-node":69,"./quoted":80}],69:[function(require,module,exports){ -var Node = require('./node'), - Variable = require('./variable'); + default: + switch (Node.compare(a, b)) { + case -1: + return op === '<' || op === '=<' || op === '<='; -var JsEvalNode = function() { -}; -JsEvalNode.prototype = new Node(); + case 0: + return op === '=' || op === '>=' || op === '=<' || op === '<='; -JsEvalNode.prototype.evaluateJavaScript = function (expression, context) { - var result, - that = this, - evalContext = {}; + case 1: + return op === '>' || op === '>='; - if (!context.javascriptEnabled) { - throw { message: 'Inline JavaScript is not enabled. Is it set in your options?', - filename: this.fileInfo().filename, - index: this.getIndex() }; + default: + return false; + } + + } + }(this.op, this.lvalue.eval(context), this.rvalue.eval(context)); + + return this.negate ? !result : result; + } + }]); + + return Condition; + }(Node); + + Condition.prototype.type = 'Condition'; + + var UnicodeDescriptor = + /*#__PURE__*/ + function (_Node) { + _inherits(UnicodeDescriptor, _Node); + + function UnicodeDescriptor(value) { + var _this; + + _classCallCheck(this, UnicodeDescriptor); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(UnicodeDescriptor).call(this)); + _this.value = value; + return _this; } - expression = expression.replace(/@\{([\w-]+)\}/g, function (_, name) { - return that.jsify(new Variable('@' + name, that.getIndex(), that.fileInfo()).eval(context)); - }); + return UnicodeDescriptor; + }(Node); - try { - expression = new Function('return (' + expression + ')'); - } catch (e) { - throw { message: 'JavaScript evaluation error: ' + e.message + ' from `' + expression + '`' , - filename: this.fileInfo().filename, - index: this.getIndex() }; + UnicodeDescriptor.prototype.type = 'UnicodeDescriptor'; + + var Negative = + /*#__PURE__*/ + function (_Node) { + _inherits(Negative, _Node); + + function Negative(node) { + var _this; + + _classCallCheck(this, Negative); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(Negative).call(this)); + _this.value = node; + return _this; } - var variables = context.frames[0].variables(); - for (var k in variables) { - if (variables.hasOwnProperty(k)) { - /* jshint loopfunc:true */ - evalContext[k.slice(1)] = { - value: variables[k].value, - toJS: function () { - return this.value.eval(context).toCSS(); - } - }; + _createClass(Negative, [{ + key: "genCSS", + value: function genCSS(context, output) { + output.add('-'); + this.value.genCSS(context, output); + } + }, { + key: "eval", + value: function _eval(context) { + if (context.isMathOn()) { + return new Operation('*', [new Dimension(-1), this.value]).eval(context); } - } - try { - result = expression.call(evalContext); - } catch (e) { - throw { message: 'JavaScript evaluation error: \'' + e.name + ': ' + e.message.replace(/["]/g, '\'') + '\'' , - filename: this.fileInfo().filename, - index: this.getIndex() }; - } - return result; -}; -JsEvalNode.prototype.jsify = function (obj) { - if (Array.isArray(obj.value) && (obj.value.length > 1)) { - return '[' + obj.value.map(function (v) { return v.toCSS(); }).join(', ') + ']'; - } else { - return obj.toCSS(); - } -}; - -module.exports = JsEvalNode; - -},{"./node":76,"./variable":88}],70:[function(require,module,exports){ -var Node = require('./node'); - -var Keyword = function (value) { this.value = value; }; -Keyword.prototype = new Node(); -Keyword.prototype.type = 'Keyword'; -Keyword.prototype.genCSS = function (context, output) { - if (this.value === '%') { throw { type: 'Syntax', message: 'Invalid % without number' }; } - output.add(this.value); -}; - -Keyword.True = new Keyword('true'); -Keyword.False = new Keyword('false'); - -module.exports = Keyword; - -},{"./node":76}],71:[function(require,module,exports){ -var Ruleset = require('./ruleset'), - Value = require('./value'), - Selector = require('./selector'), - Anonymous = require('./anonymous'), - Expression = require('./expression'), - AtRule = require('./atrule'), - utils = require('../utils'); - -var Media = function (value, features, index, currentFileInfo, visibilityInfo) { - this._index = index; - this._fileInfo = currentFileInfo; - - var selectors = (new Selector([], null, null, this._index, this._fileInfo)).createEmptySelectors(); - - this.features = new Value(features); - this.rules = [new Ruleset(selectors, value)]; - this.rules[0].allowImports = true; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; - this.setParent(selectors, this); - this.setParent(this.features, this); - this.setParent(this.rules, this); -}; -Media.prototype = new AtRule(); -Media.prototype.type = 'Media'; -Media.prototype.isRulesetLike = function() { return true; }; -Media.prototype.accept = function (visitor) { - if (this.features) { - this.features = visitor.visit(this.features); - } - if (this.rules) { - this.rules = visitor.visitArray(this.rules); - } -}; -Media.prototype.genCSS = function (context, output) { - output.add('@media ', this._fileInfo, this._index); - this.features.genCSS(context, output); - this.outputRuleset(context, output, this.rules); -}; -Media.prototype.eval = function (context) { - if (!context.mediaBlocks) { - context.mediaBlocks = []; - context.mediaPath = []; - } + return new Negative(this.value.eval(context)); + } + }]); - var media = new Media(null, [], this._index, this._fileInfo, this.visibilityInfo()); - if (this.debugInfo) { - this.rules[0].debugInfo = this.debugInfo; - media.debugInfo = this.debugInfo; - } - - media.features = this.features.eval(context); + return Negative; + }(Node); - context.mediaPath.push(media); - context.mediaBlocks.push(media); + Negative.prototype.type = 'Negative'; - this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit(); - context.frames.unshift(this.rules[0]); - media.rules = [this.rules[0].eval(context)]; - context.frames.shift(); + var Extend = + /*#__PURE__*/ + function (_Node) { + _inherits(Extend, _Node); - context.mediaPath.pop(); + function Extend(selector, option, index, currentFileInfo, visibilityInfo) { + var _this; - return context.mediaPath.length === 0 ? media.evalTop(context) : - media.evalNested(context); -}; -Media.prototype.evalTop = function (context) { - var result = this; + _classCallCheck(this, Extend); - // Render all dependent Media blocks. - if (context.mediaBlocks.length > 1) { - var selectors = (new Selector([], null, null, this.getIndex(), this.fileInfo())).createEmptySelectors(); - result = new Ruleset(selectors, context.mediaBlocks); - result.multiMedia = true; - result.copyVisibilityInfo(this.visibilityInfo()); - this.setParent(result, this); - } + _this = _possibleConstructorReturn(this, _getPrototypeOf(Extend).call(this)); + _this.selector = selector; + _this.option = option; + _this.object_id = Extend.next_id++; + _this.parent_ids = [_this.object_id]; + _this._index = index; + _this._fileInfo = currentFileInfo; - delete context.mediaBlocks; - delete context.mediaPath; + _this.copyVisibilityInfo(visibilityInfo); - return result; -}; -Media.prototype.evalNested = function (context) { - var i, value, - path = context.mediaPath.concat([this]); + _this.allowRoot = true; + + switch (option) { + case 'all': + _this.allowBefore = true; + _this.allowAfter = true; + break; + + default: + _this.allowBefore = false; + _this.allowAfter = false; + break; + } + + _this.setParent(_this.selector, _assertThisInitialized(_this)); - // Extract the media-query conditions separated with `,` (OR). - for (i = 0; i < path.length; i++) { - value = path[i].features instanceof Value ? - path[i].features.value : path[i].features; - path[i] = Array.isArray(value) ? value : [value]; + return _this; } - // Trace all permutations to generate the resulting media-query. - // - // (a, b and c) with nested (d, e) -> - // a and d - // a and e - // b and c and d - // b and c and e - this.features = new Value(this.permute(path).map(function (path) { - path = path.map(function (fragment) { - return fragment.toCSS ? fragment : new Anonymous(fragment); - }); + _createClass(Extend, [{ + key: "accept", + value: function accept(visitor) { + this.selector = visitor.visit(this.selector); + } + }, { + key: "eval", + value: function _eval(context) { + return new Extend(this.selector.eval(context), this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } + }, { + key: "clone", + value: function clone(context) { + return new Extend(this.selector, this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } // it concatenates (joins) all selectors in selector array + + }, { + key: "findSelfSelectors", + value: function findSelfSelectors(selectors) { + var selfElements = []; + var i; + var selectorElements; + + for (i = 0; i < selectors.length; i++) { + selectorElements = selectors[i].elements; // duplicate the logic in genCSS function inside the selector node. + // future TODO - move both logics into the selector joiner visitor + + if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === '') { + selectorElements[0].combinator.value = ' '; + } - for (i = path.length - 1; i > 0; i--) { - path.splice(i, 0, new Anonymous('and')); + selfElements = selfElements.concat(selectors[i].elements); } - return new Expression(path); - })); - this.setParent(this.features, this); + this.selfSelectors = [new Selector(selfElements)]; + this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo()); + } + }]); - // Fake a tree-node that doesn't output anything. - return new Ruleset([], []); -}; -Media.prototype.permute = function (arr) { - if (arr.length === 0) { - return []; - } else if (arr.length === 1) { - return arr[0]; - } else { - var result = []; - var rest = this.permute(arr.slice(1)); - for (var i = 0; i < rest.length; i++) { - for (var j = 0; j < arr[0].length; j++) { - result.push([arr[0][j]].concat(rest[i])); - } - } - return result; - } -}; -Media.prototype.bubbleSelectors = function (selectors) { - if (!selectors) { - return; - } - this.rules = [new Ruleset(utils.copyArray(selectors), [this.rules[0]])]; - this.setParent(this.rules, this); -}; -module.exports = Media; - -},{"../utils":89,"./anonymous":50,"./atrule":52,"./expression":64,"./ruleset":81,"./selector":82,"./value":86}],72:[function(require,module,exports){ -var Node = require('./node'), - Selector = require('./selector'), - MixinDefinition = require('./mixin-definition'), - defaultFunc = require('../functions/default'); - -var MixinCall = function (elements, args, index, currentFileInfo, important) { - this.selector = new Selector(elements); - this.arguments = args || []; - this._index = index; - this._fileInfo = currentFileInfo; - this.important = important; - this.allowRoot = true; - this.setParent(this.selector, this); -}; -MixinCall.prototype = new Node(); -MixinCall.prototype.type = 'MixinCall'; -MixinCall.prototype.accept = function (visitor) { - if (this.selector) { - this.selector = visitor.visit(this.selector); - } - if (this.arguments.length) { - this.arguments = visitor.visitArray(this.arguments); + return Extend; + }(Node); + + Extend.next_id = 0; + Extend.prototype.type = 'Extend'; + + var VariableCall = + /*#__PURE__*/ + function (_Node) { + _inherits(VariableCall, _Node); + + function VariableCall(variable, index, currentFileInfo) { + var _this; + + _classCallCheck(this, VariableCall); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(VariableCall).call(this)); + _this.variable = variable; + _this._index = index; + _this._fileInfo = currentFileInfo; + _this.allowRoot = true; + return _this; } -}; -MixinCall.prototype.eval = function (context) { - var mixins, mixin, mixinPath, args = [], arg, argValue, - rules = [], match = false, i, m, f, isRecursive, isOneFound, - candidates = [], candidate, conditionResult = [], defaultResult, defFalseEitherCase = -1, - defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset, noArgumentsFilter; - this.selector = this.selector.eval(context); + _createClass(VariableCall, [{ + key: "eval", + value: function _eval(context) { + var rules; + var detachedRuleset = new Variable(this.variable, this.getIndex(), this.fileInfo()).eval(context); + var error = new LessError({ + message: "Could not evaluate variable call ".concat(this.variable) + }); - function calcDefGroup(mixin, mixinPath) { - var f, p, namespace; + if (!detachedRuleset.ruleset) { + if (detachedRuleset.rules) { + rules = detachedRuleset; + } else if (Array.isArray(detachedRuleset)) { + rules = new Ruleset('', detachedRuleset); + } else if (Array.isArray(detachedRuleset.value)) { + rules = new Ruleset('', detachedRuleset.value); + } else { + throw error; + } - for (f = 0; f < 2; f++) { - conditionResult[f] = true; - defaultFunc.value(f); - for (p = 0; p < mixinPath.length && conditionResult[f]; p++) { - namespace = mixinPath[p]; - if (namespace.matchCondition) { - conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, context); - } - } - if (mixin.matchCondition) { - conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, context); - } + detachedRuleset = new DetachedRuleset(rules); } - if (conditionResult[0] || conditionResult[1]) { - if (conditionResult[0] != conditionResult[1]) { - return conditionResult[1] ? - defTrue : defFalse; - } - return defNone; + if (detachedRuleset.ruleset) { + return detachedRuleset.callEval(context); } - return defFalseEitherCase; - } - for (i = 0; i < this.arguments.length; i++) { - arg = this.arguments[i]; - argValue = arg.value.eval(context); - if (arg.expand && Array.isArray(argValue.value)) { - argValue = argValue.value; - for (m = 0; m < argValue.length; m++) { - args.push({value: argValue[m]}); - } - } else { - args.push({name: arg.name, value: argValue}); - } - } + throw error; + } + }]); - noArgumentsFilter = function(rule) {return rule.matchArgs(null, context);}; + return VariableCall; + }(Node); - for (i = 0; i < context.frames.length; i++) { - if ((mixins = context.frames[i].find(this.selector, null, noArgumentsFilter)).length > 0) { - isOneFound = true; + VariableCall.prototype.type = 'VariableCall'; - // 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. + var NamespaceValue = + /*#__PURE__*/ + function (_Node) { + _inherits(NamespaceValue, _Node); - for (m = 0; m < mixins.length; m++) { - mixin = mixins[m].rule; - mixinPath = mixins[m].path; - isRecursive = false; - for (f = 0; f < context.frames.length; f++) { - if ((!(mixin instanceof MixinDefinition)) && mixin === (context.frames[f].originalRuleset || context.frames[f])) { - isRecursive = true; - break; - } - } - if (isRecursive) { - continue; - } + function NamespaceValue(ruleCall, lookups, important, index, fileInfo) { + var _this; - if (mixin.matchArgs(args, context)) { - candidate = {mixin: mixin, group: calcDefGroup(mixin, mixinPath)}; + _classCallCheck(this, NamespaceValue); - if (candidate.group !== defFalseEitherCase) { - candidates.push(candidate); - } + _this = _possibleConstructorReturn(this, _getPrototypeOf(NamespaceValue).call(this)); + _this.value = ruleCall; + _this.lookups = lookups; + _this.important = important; + _this._index = index; + _this._fileInfo = fileInfo; + return _this; + } - match = true; - } - } + _createClass(NamespaceValue, [{ + key: "eval", + value: function _eval(context) { + var i; + var name; + var rules = this.value.eval(context); - defaultFunc.reset(); + for (i = 0; i < this.lookups.length; i++) { + name = this.lookups[i]; + /** + * Eval'd DRs return rulesets. + * Eval'd mixins return rules, so let's make a ruleset if we need it. + * We need to do this because of late parsing of values + */ - count = [0, 0, 0]; - for (m = 0; m < candidates.length; m++) { - count[candidates[m].group]++; - } + if (Array.isArray(rules)) { + rules = new Ruleset([new Selector()], rules); + } - 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.getIndex(), filename: this.fileInfo().filename }; - } + if (name === '') { + rules = rules.lastDeclaration(); + } else if (name.charAt(0) === '@') { + if (name.charAt(1) === '@') { + name = "@".concat(new Variable(name.substr(1)).eval(context).value); } - for (m = 0; m < candidates.length; m++) { - candidate = candidates[m].group; - if ((candidate === defNone) || (candidate === defaultResult)) { - try { - mixin = candidates[m].mixin; - if (!(mixin instanceof MixinDefinition)) { - originalRuleset = mixin.originalRuleset || mixin; - mixin = new MixinDefinition('', [], mixin.rules, null, false, null, originalRuleset.visibilityInfo()); - mixin.originalRuleset = originalRuleset; - } - var newRules = mixin.evalCall(context, args, this.important).rules; - this._setVisibilityToReplacement(newRules); - Array.prototype.push.apply(rules, newRules); - } catch (e) { - throw { message: e.message, index: this.getIndex(), filename: this.fileInfo().filename, stack: e.stack }; - } - } + if (rules.variables) { + rules = rules.variable(name); } - if (match) { - return rules; + if (!rules) { + throw { + type: 'Name', + message: "variable ".concat(name, " not found"), + filename: this.fileInfo().filename, + index: this.getIndex() + }; } + } else { + if (name.substring(0, 2) === '$@') { + name = "$".concat(new Variable(name.substr(1)).eval(context).value); + } else { + name = name.charAt(0) === '$' ? name : "$".concat(name); + } + + if (rules.properties) { + rules = rules.property(name); + } + + if (!rules) { + throw { + type: 'Name', + message: "property \"".concat(name.substr(1), "\" not found"), + filename: this.fileInfo().filename, + index: this.getIndex() + }; + } // Properties are an array of values, since a ruleset can have multiple props. + // We pick the last one (the "cascaded" value) + + + rules = rules[rules.length - 1]; + } + + if (rules.value) { + rules = rules.eval(context).value; + } + + if (rules.ruleset) { + rules = rules.ruleset.eval(context); + } } - } - if (isOneFound) { - throw { type: 'Runtime', - message: 'No matching definition was found for `' + this.format(args) + '`', - index: this.getIndex(), filename: this.fileInfo().filename }; - } else { - throw { type: 'Name', - message: this.selector.toCSS().trim() + ' is undefined', - index: this.getIndex(), filename: this.fileInfo().filename }; - } -}; -MixinCall.prototype._setVisibilityToReplacement = function (replacement) { - var i, rule; - if (this.blocksVisibility()) { - for (i = 0; i < replacement.length; i++) { - rule = replacement[i]; - rule.addVisibilityBlock(); + return rules; + } + }]); + + return NamespaceValue; + }(Node); + + NamespaceValue.prototype.type = 'NamespaceValue'; + + var Definition = + /*#__PURE__*/ + function (_Ruleset) { + _inherits(Definition, _Ruleset); + + function Definition(name, params, rules, condition, variadic, frames, visibilityInfo) { + var _this; + + _classCallCheck(this, Definition); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(Definition).call(this)); + _this.name = name || 'anonymous mixin'; + _this.selectors = [new Selector([new Element(null, name, false, _this._index, _this._fileInfo)])]; + _this.params = params; + _this.condition = condition; + _this.variadic = variadic; + _this.arity = params.length; + _this.rules = rules; + _this._lookups = {}; + var optionalParameters = []; + _this.required = params.reduce(function (count, p) { + if (!p.name || p.name && !p.value) { + return count + 1; + } else { + optionalParameters.push(p.name); + return count; } + }, 0); + _this.optionalParameters = optionalParameters; + _this.frames = frames; + + _this.copyVisibilityInfo(visibilityInfo); + + _this.allowRoot = true; + return _this; } -}; -MixinCall.prototype.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(', ') : '') + ')'; -}; -module.exports = MixinCall; - -},{"../functions/default":25,"./mixin-definition":73,"./node":76,"./selector":82}],73:[function(require,module,exports){ -var Selector = require('./selector'), - Element = require('./element'), - Ruleset = require('./ruleset'), - Declaration = require('./declaration'), - DetachedRuleset = require('./detached-ruleset'), - Expression = require('./expression'), - contexts = require('../contexts'), - utils = require('../utils'); - -var Definition = function (name, params, rules, condition, variadic, frames, visibilityInfo) { - this.name = name || 'anonymous mixin'; - this.selectors = [new Selector([new Element(null, name, false, this._index, this._fileInfo)])]; - this.params = params; - this.condition = condition; - this.variadic = variadic; - this.arity = params.length; - this.rules = rules; - this._lookups = {}; - var optionalParameters = []; - this.required = params.reduce(function (count, p) { - if (!p.name || (p.name && !p.value)) { - return count + 1; + + _createClass(Definition, [{ + key: "accept", + value: function accept(visitor) { + if (this.params && this.params.length) { + this.params = visitor.visitArray(this.params); } - else { - optionalParameters.push(p.name); - return count; + + this.rules = visitor.visitArray(this.rules); + + if (this.condition) { + this.condition = visitor.visit(this.condition); + } + } + }, { + key: "evalParams", + value: function evalParams(context, mixinEnv, args, evaldArguments) { + /* jshint boss:true */ + var frame = new Ruleset(null, null); + var varargs; + var arg; + var params = copyArray(this.params); + var i; + var j; + var val; + var name; + var isNamedFound; + var argIndex; + var argsLength = 0; + + if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) { + frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit(); } - }, 0); - this.optionalParameters = optionalParameters; - this.frames = frames; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; -}; -Definition.prototype = new Ruleset(); -Definition.prototype.type = 'MixinDefinition'; -Definition.prototype.evalFirst = true; -Definition.prototype.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); - } -}; -Definition.prototype.evalParams = function (context, mixinEnv, args, evaldArguments) { - /* jshint boss:true */ - var frame = new Ruleset(null, null), - varargs, arg, - params = utils.copyArray(this.params), - i, j, val, name, isNamedFound, argIndex, argsLength = 0; - - if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) { - frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit(); - } - mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames)); - - if (args) { - args = utils.copyArray(args); - argsLength = args.length; - - for (i = 0; i < argsLength; i++) { + + mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames)); + + if (args) { + args = copyArray(args); + 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(context); - frame.prependRule(new Declaration(name, arg.value.eval(context))); - 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' }; + + 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(context); + frame.prependRule(new Declaration(name, arg.value.eval(context))); + isNamedFound = true; + break; } + } + + if (isNamedFound) { + args.splice(i, 1); + i--; + continue; + } else { + throw { + type: 'Runtime', + message: "Named argument for ".concat(this.name, " ").concat(args[i].name, " not found") + }; + } } + } } - } - argIndex = 0; - for (i = 0; i < params.length; i++) { - if (evaldArguments[i]) { continue; } - arg = args && args[argIndex]; + argIndex = 0; + + for (i = 0; i < params.length; i++) { + if (evaldArguments[i]) { + continue; + } - if (name = params[i].name) { + 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(context)); - } - frame.prependRule(new Declaration(name, new Expression(varargs).eval(context))); + varargs = []; + + for (j = argIndex; j < argsLength; j++) { + varargs.push(args[j].value.eval(context)); + } + + frame.prependRule(new Declaration(name, new Expression(varargs).eval(context))); } else { - val = arg && arg.value; - if (val) { - // This was a mixin call, pass in a detached ruleset of it's eval'd rules - if (Array.isArray(val)) { - val = new DetachedRuleset(new Ruleset('', val)); - } - else { - val = val.eval(context); - } - } else if (params[i].value) { - val = params[i].value.eval(mixinEnv); - frame.resetCache(); + val = arg && arg.value; + + if (val) { + // This was a mixin call, pass in a detached ruleset of it's eval'd rules + if (Array.isArray(val)) { + val = new DetachedRuleset(new Ruleset('', val)); } else { - throw { type: 'Runtime', message: 'wrong number of arguments for ' + this.name + - ' (' + argsLength + ' for ' + this.arity + ')' }; - } + val = val.eval(context); + } + } else if (params[i].value) { + val = params[i].value.eval(mixinEnv); + frame.resetCache(); + } else { + throw { + type: 'Runtime', + message: "wrong number of arguments for ".concat(this.name, " (").concat(argsLength, " for ").concat(this.arity, ")") + }; + } - frame.prependRule(new Declaration(name, val)); - evaldArguments[i] = val; + frame.prependRule(new Declaration(name, val)); + evaldArguments[i] = val; } - } + } - if (params[i].variadic && args) { + if (params[i].variadic && args) { for (j = argIndex; j < argsLength; j++) { - evaldArguments[j] = args[j].value.eval(context); + evaldArguments[j] = args[j].value.eval(context); } + } + + argIndex++; } - argIndex++; - } - return frame; -}; -Definition.prototype.makeImportant = function() { - var rules = !this.rules ? this.rules : this.rules.map(function (r) { - if (r.makeImportant) { + return frame; + } + }, { + key: "makeImportant", + value: function makeImportant() { + var rules = !this.rules ? this.rules : this.rules.map(function (r) { + if (r.makeImportant) { return r.makeImportant(true); - } else { + } else { return r; + } + }); + var result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames); + return result; + } + }, { + key: "eval", + value: function _eval(context) { + return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || copyArray(context.frames)); + } + }, { + key: "evalCall", + value: function evalCall(context, args, important) { + var _arguments = []; + var mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames; + var frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments); + var rules; + var ruleset; + frame.prependRule(new Declaration('@arguments', new Expression(_arguments).eval(context))); + rules = copyArray(this.rules); + ruleset = new Ruleset(null, rules); + ruleset.originalRuleset = this; + ruleset = ruleset.eval(new contexts.Eval(context, [this, frame].concat(mixinFrames))); + + if (important) { + ruleset = ruleset.makeImportant(); + } + + return ruleset; + } + }, { + key: "matchCondition", + value: function matchCondition(args, context) { + if (this.condition && !this.condition.eval(new contexts.Eval(context, [this.evalParams(context, + /* the parameter variables */ + new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])].concat(this.frames || []) // the parent namespace/mixin frames + .concat(context.frames)))) { + // the current environment frames + return false; } - }); - var result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames); - return result; -}; -Definition.prototype.eval = function (context) { - return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || utils.copyArray(context.frames)); -}; -Definition.prototype.evalCall = function (context, args, important) { - var _arguments = [], - mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames, - frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments), - rules, ruleset; - - frame.prependRule(new Declaration('@arguments', new Expression(_arguments).eval(context))); - - rules = utils.copyArray(this.rules); - - ruleset = new Ruleset(null, rules); - ruleset.originalRuleset = this; - ruleset = ruleset.eval(new contexts.Eval(context, [this, frame].concat(mixinFrames))); - if (important) { - ruleset = ruleset.makeImportant(); - } - return ruleset; -}; -Definition.prototype.matchCondition = function (args, context) { - if (this.condition && !this.condition.eval( - new contexts.Eval(context, - [this.evalParams(context, /* the parameter variables */ - new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])] - .concat(this.frames || []) // the parent namespace/mixin frames - .concat(context.frames)))) { // the current environment frames - return false; - } - return true; -}; -Definition.prototype.matchArgs = function (args, context) { - var allArgsCnt = (args && args.length) || 0, len, optionalParameters = this.optionalParameters; - var requiredArgsCnt = !args ? 0 : args.reduce(function (count, p) { - if (optionalParameters.indexOf(p.name) < 0) { + + return true; + } + }, { + key: "matchArgs", + value: function matchArgs(args, context) { + var allArgsCnt = args && args.length || 0; + var len; + var optionalParameters = this.optionalParameters; + var requiredArgsCnt = !args ? 0 : args.reduce(function (count, p) { + if (optionalParameters.indexOf(p.name) < 0) { return count + 1; - } else { + } else { return count; - } - }, 0); + } + }, 0); - if (!this.variadic) { - if (requiredArgsCnt < this.required) { + if (!this.variadic) { + if (requiredArgsCnt < this.required) { return false; - } - if (allArgsCnt > this.params.length) { + } + + if (allArgsCnt > this.params.length) { return false; - } - } else { - if (requiredArgsCnt < (this.required - 1)) { + } + } else { + if (requiredArgsCnt < this.required - 1) { return false; - } - } + } + } // check patterns - // check patterns - len = Math.min(requiredArgsCnt, this.arity); - for (var i = 0; i < len; i++) { - if (!this.params[i].name && !this.params[i].variadic) { + len = Math.min(requiredArgsCnt, this.arity); + + for (var i = 0; i < len; i++) { + if (!this.params[i].name && !this.params[i].variadic) { if (args[i].value.eval(context).toCSS() != this.params[i].value.eval(context).toCSS()) { - return false; + return false; } + } } - } - return true; -}; -module.exports = Definition; - -},{"../contexts":13,"../utils":89,"./declaration":60,"./detached-ruleset":61,"./element":63,"./expression":64,"./ruleset":81,"./selector":82}],74:[function(require,module,exports){ -var Node = require('./node'), - Variable = require('./variable'), - Ruleset = require('./ruleset'), - Selector = require('./selector'); - -var NamespaceValue = function (ruleCall, lookups, important, index, fileInfo) { - this.value = ruleCall; - this.lookups = lookups; - this.important = important; - this._index = index; - this._fileInfo = fileInfo; -}; -NamespaceValue.prototype = new Node(); -NamespaceValue.prototype.type = 'NamespaceValue'; -NamespaceValue.prototype.eval = function (context) { - var i, j, name, rules = this.value.eval(context); - - for (i = 0; i < this.lookups.length; i++) { - name = this.lookups[i]; - /** - * Eval'd DRs return rulesets. - * Eval'd mixins return rules, so let's make a ruleset if we need it. - * We need to do this because of late parsing of values - */ - if (Array.isArray(rules)) { - rules = new Ruleset([new Selector()], rules); - } + return true; + } + }]); - if (name === '') { - rules = rules.lastDeclaration(); - } - else if (name.charAt(0) === '@') { - if (name.charAt(1) === '@') { - name = '@' + new Variable(name.substr(1)).eval(context).value; - } - if (rules.variables) { - rules = rules.variable(name); - } - - if (!rules) { - throw { type: 'Name', - message: 'variable ' + name + ' not found', - filename: this.fileInfo().filename, - index: this.getIndex() }; - } - } - else { - if (name.substring(0, 2) === '$@') { - name = '$' + new Variable(name.substr(1)).eval(context).value; - } - else { - name = name.charAt(0) === '$' ? name : '$' + name; - } - if (rules.properties) { - rules = rules.property(name); - } - - if (!rules) { - throw { type: 'Name', - message: 'property "' + name.substr(1) + '" not found', - filename: this.fileInfo().filename, - index: this.getIndex() }; - } - // Properties are an array of values, since a ruleset can have multiple props. - // We pick the last one (the "cascaded" value) - rules = rules[rules.length - 1]; - } + return Definition; + }(Ruleset); - if (rules.value) { - rules = rules.eval(context).value; - } - if (rules.ruleset) { - rules = rules.ruleset.eval(context); - } - } - return rules; -}; -module.exports = NamespaceValue; - -},{"./node":76,"./ruleset":81,"./selector":82,"./variable":88}],75:[function(require,module,exports){ -var Node = require('./node'), - Operation = require('./operation'), - Dimension = require('./dimension'); - -var Negative = function (node) { - this.value = node; -}; -Negative.prototype = new Node(); -Negative.prototype.type = 'Negative'; -Negative.prototype.genCSS = function (context, output) { - output.add('-'); - this.value.genCSS(context, output); -}; -Negative.prototype.eval = function (context) { - if (context.isMathOn()) { - return (new Operation('*', [new Dimension(-1), this.value])).eval(context); - } - return new Negative(this.value.eval(context)); -}; -module.exports = Negative; - -},{"./dimension":62,"./node":76,"./operation":77}],76:[function(require,module,exports){ -var Node = function() { - this.parent = null; - this.visibilityBlocks = undefined; - this.nodeVisible = undefined; - this.rootNode = null; - this.parsed = null; - - var self = this; - Object.defineProperty(this, 'currentFileInfo', { - get: function() { return self.fileInfo(); } - }); - Object.defineProperty(this, 'index', { - get: function() { return self.getIndex(); } - }); + Definition.prototype.type = 'MixinDefinition'; + Definition.prototype.evalFirst = true; -}; -Node.prototype.setParent = function(nodes, parent) { - function set(node) { - if (node && node instanceof Node) { - node.parent = parent; - } - } - if (Array.isArray(nodes)) { - nodes.forEach(set); - } - else { - set(nodes); - } -}; -Node.prototype.getIndex = function() { - return this._index || (this.parent && this.parent.getIndex()) || 0; -}; -Node.prototype.fileInfo = function() { - return this._fileInfo || (this.parent && this.parent.fileInfo()) || {}; -}; -Node.prototype.isRulesetLike = function() { return false; }; -Node.prototype.toCSS = function (context) { - var strs = []; - this.genCSS(context, { - add: function(chunk, fileInfo, index) { - strs.push(chunk); - }, - isEmpty: function () { - return strs.length === 0; - } - }); - return strs.join(''); -}; -Node.prototype.genCSS = function (context, output) { - output.add(this.value); -}; -Node.prototype.accept = function (visitor) { - this.value = visitor.visit(this.value); -}; -Node.prototype.eval = function () { return this; }; -Node.prototype._operate = function (context, op, a, b) { - switch (op) { - case '+': return a + b; - case '-': return a - b; - case '*': return a * b; - case '/': return a / b; - } -}; -Node.prototype.fround = function(context, value) { - var precision = context && context.numPrecision; - // add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999...) are properly rounded: - return (precision) ? Number((value + 2e-16).toFixed(precision)) : value; -}; -Node.compare = function (a, b) { - /* returns: - -1: a < b - 0: a = b - 1: a > b - and *any* other value for a != b (e.g. undefined, NaN, -2 etc.) */ + var MixinCall = + /*#__PURE__*/ + function (_Node) { + _inherits(MixinCall, _Node); - if ((a.compare) && - // for "symmetric results" force toCSS-based comparison - // of Quoted or Anonymous if either value is one of those - !(b.type === 'Quoted' || b.type === 'Anonymous')) { - return a.compare(b); - } else if (b.compare) { - return -b.compare(a); - } else if (a.type !== b.type) { - return undefined; - } + function MixinCall(elements, args, index, currentFileInfo, important) { + var _this; - a = a.value; - b = b.value; - if (!Array.isArray(a)) { - return a === b ? 0 : undefined; - } - if (a.length !== b.length) { - return undefined; - } - for (var i = 0; i < a.length; i++) { - if (Node.compare(a[i], b[i]) !== 0) { - return undefined; - } - } - return 0; -}; - -Node.numericCompare = function (a, b) { - return a < b ? -1 - : a === b ? 0 - : a > b ? 1 : undefined; -}; -// Returns true if this node represents root of ast imported by reference -Node.prototype.blocksVisibility = function () { - if (this.visibilityBlocks == null) { - this.visibilityBlocks = 0; - } - return this.visibilityBlocks !== 0; -}; -Node.prototype.addVisibilityBlock = function () { - if (this.visibilityBlocks == null) { - this.visibilityBlocks = 0; - } - this.visibilityBlocks = this.visibilityBlocks + 1; -}; -Node.prototype.removeVisibilityBlock = function () { - if (this.visibilityBlocks == null) { - this.visibilityBlocks = 0; - } - this.visibilityBlocks = this.visibilityBlocks - 1; -}; -// Turns on node visibility - if called node will be shown in output regardless -// of whether it comes from import by reference or not -Node.prototype.ensureVisibility = function () { - this.nodeVisible = true; -}; -// Turns off node visibility - if called node will NOT be shown in output regardless -// of whether it comes from import by reference or not -Node.prototype.ensureInvisibility = function () { - this.nodeVisible = false; -}; -// return values: -// false - the node must not be visible -// true - the node must be visible -// undefined or null - the node has the same visibility as its parent -Node.prototype.isVisible = function () { - return this.nodeVisible; -}; -Node.prototype.visibilityInfo = function() { - return { - visibilityBlocks: this.visibilityBlocks, - nodeVisible: this.nodeVisible - }; -}; -Node.prototype.copyVisibilityInfo = function(info) { - if (!info) { - return; + _classCallCheck(this, MixinCall); + + _this = _possibleConstructorReturn(this, _getPrototypeOf(MixinCall).call(this)); + _this.selector = new Selector(elements); + _this.arguments = args || []; + _this._index = index; + _this._fileInfo = currentFileInfo; + _this.important = important; + _this.allowRoot = true; + + _this.setParent(_this.selector, _assertThisInitialized(_this)); + + return _this; } - this.visibilityBlocks = info.visibilityBlocks; - this.nodeVisible = info.nodeVisible; -}; -module.exports = Node; - -},{}],77:[function(require,module,exports){ -var Node = require('./node'), - Color = require('./color'), - Dimension = require('./dimension'), - MATH = require('../constants').Math; - -var Operation = function (op, operands, isSpaced) { - this.op = op.trim(); - this.operands = operands; - this.isSpaced = isSpaced; -}; -Operation.prototype = new Node(); -Operation.prototype.type = 'Operation'; -Operation.prototype.accept = function (visitor) { - this.operands = visitor.visitArray(this.operands); -}; -Operation.prototype.eval = function (context) { - var a = this.operands[0].eval(context), - b = this.operands[1].eval(context), - op; - - if (context.isMathOn(this.op)) { - op = this.op === './' ? '/' : this.op; - if (a instanceof Dimension && b instanceof Color) { - a = a.toColor(); - } - if (b instanceof Dimension && a instanceof Color) { - b = b.toColor(); - } - if (!a.operate) { - if (a instanceof Operation && a.op === '/' && context.math === MATH.PARENS_DIVISION) { - return new Operation(this.op, [a, b], this.isSpaced); - } - throw { type: 'Operation', - message: 'Operation on an invalid type' }; + + _createClass(MixinCall, [{ + key: "accept", + value: function accept(visitor) { + if (this.selector) { + this.selector = visitor.visit(this.selector); } - return a.operate(context, op, b); - } else { - return new Operation(this.op, [a, b], this.isSpaced); - } -}; -Operation.prototype.genCSS = function (context, output) { - this.operands[0].genCSS(context, output); - if (this.isSpaced) { - output.add(' '); - } - output.add(this.op); - if (this.isSpaced) { - output.add(' '); - } - this.operands[1].genCSS(context, output); -}; - -module.exports = Operation; - -},{"../constants":12,"./color":55,"./dimension":62,"./node":76}],78:[function(require,module,exports){ -var Node = require('./node'); - -var Paren = function (node) { - this.value = node; -}; -Paren.prototype = new Node(); -Paren.prototype.type = 'Paren'; -Paren.prototype.genCSS = function (context, output) { - output.add('('); - this.value.genCSS(context, output); - output.add(')'); -}; -Paren.prototype.eval = function (context) { - return new Paren(this.value.eval(context)); -}; -module.exports = Paren; - -},{"./node":76}],79:[function(require,module,exports){ -var Node = require('./node'), - Declaration = require('./declaration'); - -var Property = function (name, index, currentFileInfo) { - this.name = name; - this._index = index; - this._fileInfo = currentFileInfo; -}; -Property.prototype = new Node(); -Property.prototype.type = 'Property'; -Property.prototype.eval = function (context) { - var property, name = this.name; - // TODO: shorten this reference - var mergeRules = context.pluginManager.less.visitors.ToCSSVisitor.prototype._mergeRules; - - if (this.evaluating) { - throw { type: 'Name', - message: 'Recursive property reference for ' + name, - filename: this.fileInfo().filename, - index: this.getIndex() }; - } + if (this.arguments.length) { + this.arguments = visitor.visitArray(this.arguments); + } + } + }, { + key: "eval", + value: function _eval(context) { + var mixins; + var mixin; + var mixinPath; + var args = []; + var arg; + var argValue; + var rules = []; + var match = false; + var i; + var m; + var f; + var isRecursive; + var isOneFound; + var candidates = []; + var candidate; + var conditionResult = []; + var defaultResult; + var defFalseEitherCase = -1; + var defNone = 0; + var defTrue = 1; + var defFalse = 2; + var count; + var originalRuleset; + var noArgumentsFilter; + this.selector = this.selector.eval(context); + + function calcDefGroup(mixin, mixinPath) { + var f; + var p; + var namespace; + + for (f = 0; f < 2; f++) { + conditionResult[f] = true; + defaultFunc.value(f); - this.evaluating = true; + for (p = 0; p < mixinPath.length && conditionResult[f]; p++) { + namespace = mixinPath[p]; - property = this.find(context.frames, function (frame) { + if (namespace.matchCondition) { + conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, context); + } + } - var v, vArr = frame.property(name); - if (vArr) { - for (var i = 0; i < vArr.length; i++) { - v = vArr[i]; - - vArr[i] = new Declaration(v.name, - v.value, - v.important, - v.merge, - v.index, - v.currentFileInfo, - v.inline, - v.variable - ); + if (mixin.matchCondition) { + conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, context); } - mergeRules(vArr); + } - v = vArr[vArr.length - 1]; - if (v.important) { - var importantScope = context.importantScope[context.importantScope.length - 1]; - importantScope.important = v.important; + if (conditionResult[0] || conditionResult[1]) { + if (conditionResult[0] != conditionResult[1]) { + return conditionResult[1] ? defTrue : defFalse; } - v = v.value.eval(context); - return v; - } - }); - if (property) { - this.evaluating = false; - return property; - } else { - throw { type: 'Name', - message: 'Property \'' + name + '\' is undefined', - filename: this.currentFileInfo.filename, - index: this.index }; - } -}; -Property.prototype.find = function (obj, fun) { - for (var i = 0, r; i < obj.length; i++) { - r = fun.call(obj, obj[i]); - if (r) { return r; } - } - return null; -}; -module.exports = Property; - -},{"./declaration":60,"./node":76}],80:[function(require,module,exports){ -var Node = require('./node'), - Variable = require('./variable'), - Property = require('./property'); - -var Quoted = function (str, content, escaped, index, currentFileInfo) { - this.escaped = (escaped == null) ? true : escaped; - this.value = content || ''; - this.quote = str.charAt(0); - this._index = index; - this._fileInfo = currentFileInfo; - this.variableRegex = /@\{([\w-]+)\}/g; - this.propRegex = /\$\{([\w-]+)\}/g; -}; -Quoted.prototype = new Node(); -Quoted.prototype.type = 'Quoted'; -Quoted.prototype.genCSS = function (context, output) { - if (!this.escaped) { - output.add(this.quote, this.fileInfo(), this.getIndex()); - } - output.add(this.value); - if (!this.escaped) { - output.add(this.quote); - } -}; -Quoted.prototype.containsVariables = function() { - return this.value.match(this.variableRegex); -}; -Quoted.prototype.eval = function (context) { - var that = this, value = this.value; - var variableReplacement = function (_, name) { - var v = new Variable('@' + name, that.getIndex(), that.fileInfo()).eval(context, true); - return (v instanceof Quoted) ? v.value : v.toCSS(); - }; - var propertyReplacement = function (_, name) { - var v = new Property('$' + name, that.getIndex(), that.fileInfo()).eval(context, true); - return (v instanceof Quoted) ? v.value : v.toCSS(); - }; - function iterativeReplace(value, regexp, replacementFnc) { - var evaluatedValue = value; - do { - value = evaluatedValue; - evaluatedValue = value.replace(regexp, replacementFnc); - } while (value !== evaluatedValue); - return evaluatedValue; - } - value = iterativeReplace(value, this.variableRegex, variableReplacement); - value = iterativeReplace(value, this.propRegex, propertyReplacement); - return new Quoted(this.quote + value + this.quote, value, this.escaped, this.getIndex(), this.fileInfo()); -}; -Quoted.prototype.compare = function (other) { - // when comparing quoted strings allow the quote to differ - if (other.type === 'Quoted' && !this.escaped && !other.escaped) { - return Node.numericCompare(this.value, other.value); - } else { - return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; - } -}; -module.exports = Quoted; - -},{"./node":76,"./property":79,"./variable":88}],81:[function(require,module,exports){ -var Node = require('./node'), - Declaration = require('./declaration'), - Keyword = require('./keyword'), - Comment = require('./comment'), - Paren = require('./paren'), - Selector = require('./selector'), - Element = require('./element'), - Anonymous = require('./anonymous'), - contexts = require('../contexts'), - globalFunctionRegistry = require('../functions/function-registry'), - defaultFunc = require('../functions/default'), - getDebugInfo = require('./debug-info'), - utils = require('../utils'); - -var Ruleset = function (selectors, rules, strictImports, visibilityInfo) { - this.selectors = selectors; - this.rules = rules; - this._lookups = {}; - this._variables = null; - this._properties = null; - this.strictImports = strictImports; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; - - this.setParent(this.selectors, this); - this.setParent(this.rules, this); - -}; -Ruleset.prototype = new Node(); -Ruleset.prototype.type = 'Ruleset'; -Ruleset.prototype.isRuleset = true; -Ruleset.prototype.isRulesetLike = function() { return true; }; -Ruleset.prototype.accept = function (visitor) { - if (this.paths) { - this.paths = visitor.visitArray(this.paths, true); - } else if (this.selectors) { - this.selectors = visitor.visitArray(this.selectors); - } - if (this.rules && this.rules.length) { - this.rules = visitor.visitArray(this.rules); - } -}; -Ruleset.prototype.eval = function (context) { - var that = this, selectors, selCnt, selector, i, hasVariable, hasOnePassingSelector = false; - if (this.selectors && (selCnt = this.selectors.length)) { - selectors = new Array(selCnt); - defaultFunc.error({ - type: 'Syntax', - message: 'it is currently only allowed in parametric mixin guards,' - }); + return defNone; + } - for (i = 0; i < selCnt; i++) { - selector = this.selectors[i].eval(context); - for (var j = 0; j < selector.elements.length; j++) { - if (selector.elements[j].isVariable) { - hasVariable = true; - break; - } - } - selectors[i] = selector; - if (selector.evaldCondition) { - hasOnePassingSelector = true; - } + return defFalseEitherCase; } - if (hasVariable) { - var toParseSelectors = new Array(selCnt); - for (i = 0; i < selCnt; i++) { - selector = selectors[i]; - toParseSelectors[i] = selector.toCSS(context); - } - this.parse.parseNode( - toParseSelectors.join(','), - ["selectors"], - selectors[0].getIndex(), - selectors[0].fileInfo(), - function(err, result) { - if (result) { - selectors = utils.flattenArray(result); - } - }); - } + for (i = 0; i < this.arguments.length; i++) { + arg = this.arguments[i]; + argValue = arg.value.eval(context); - defaultFunc.reset(); - } else { - hasOnePassingSelector = true; - } + if (arg.expand && Array.isArray(argValue.value)) { + argValue = argValue.value; - var rules = this.rules ? utils.copyArray(this.rules) : null, - ruleset = new Ruleset(selectors, rules, this.strictImports, this.visibilityInfo()), - rule, subRule; + for (m = 0; m < argValue.length; m++) { + args.push({ + value: argValue[m] + }); + } + } else { + args.push({ + name: arg.name, + value: argValue + }); + } + } - ruleset.originalRuleset = this; - ruleset.root = this.root; - ruleset.firstRoot = this.firstRoot; - ruleset.allowImports = this.allowImports; + noArgumentsFilter = function noArgumentsFilter(rule) { + return rule.matchArgs(null, context); + }; - if (this.debugInfo) { - ruleset.debugInfo = this.debugInfo; - } + for (i = 0; i < context.frames.length; i++) { + if ((mixins = context.frames[i].find(this.selector, null, noArgumentsFilter)).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. - if (!hasOnePassingSelector) { - rules.length = 0; - } + for (m = 0; m < mixins.length; m++) { + mixin = mixins[m].rule; + mixinPath = mixins[m].path; + isRecursive = false; - // inherit a function registry from the frames stack when possible; - // otherwise from the global registry - ruleset.functionRegistry = (function (frames) { - var i = 0, - n = frames.length, - found; - for ( ; i !== n ; ++i ) { - found = frames[ i ].functionRegistry; - if ( found ) { return found; } - } - return globalFunctionRegistry; - }(context.frames)).inherit(); + for (f = 0; f < context.frames.length; f++) { + if (!(mixin instanceof Definition) && mixin === (context.frames[f].originalRuleset || context.frames[f])) { + isRecursive = true; + break; + } + } - // push the current ruleset to the frames stack - var ctxFrames = context.frames; - ctxFrames.unshift(ruleset); + if (isRecursive) { + continue; + } - // currrent selectors - var ctxSelectors = context.selectors; - if (!ctxSelectors) { - context.selectors = ctxSelectors = []; - } - ctxSelectors.unshift(this.selectors); + if (mixin.matchArgs(args, context)) { + candidate = { + mixin: mixin, + group: calcDefGroup(mixin, mixinPath) + }; - // Evaluate imports - if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { - ruleset.evalImports(context); - } + if (candidate.group !== defFalseEitherCase) { + candidates.push(candidate); + } - // Store the frames around mixin definitions, - // so they can be evaluated like closures when the time comes. - var rsRules = ruleset.rules; - for (i = 0; (rule = rsRules[i]); i++) { - if (rule.evalFirst) { - rsRules[i] = rule.eval(context); - } - } + match = true; + } + } - var mediaBlockCount = (context.mediaBlocks && context.mediaBlocks.length) || 0; + defaultFunc.reset(); + count = [0, 0, 0]; - // Evaluate mixin calls. - for (i = 0; (rule = rsRules[i]); i++) { - if (rule.type === 'MixinCall') { - /* jshint loopfunc:true */ - rules = rule.eval(context).filter(function(r) { - if ((r instanceof Declaration) && r.variable) { - // do not pollute the scope if the variable is - // already there. consider returning false here - // but we need a way to "return" variable from mixins - return !(ruleset.variable(r.name)); - } - return true; - }); - rsRules.splice.apply(rsRules, [i, 1].concat(rules)); - i += rules.length - 1; - ruleset.resetCache(); - } else if (rule.type === 'VariableCall') { - /* jshint loopfunc:true */ - rules = rule.eval(context).rules.filter(function(r) { - if ((r instanceof Declaration) && r.variable) { - // do not pollute the scope at all - return false; - } - return true; - }); - rsRules.splice.apply(rsRules, [i, 1].concat(rules)); - i += rules.length - 1; - ruleset.resetCache(); - } - } - - // Evaluate everything else - for (i = 0; (rule = rsRules[i]); i++) { - if (!rule.evalFirst) { - rsRules[i] = rule = rule.eval ? rule.eval(context) : rule; - } - } + for (m = 0; m < candidates.length; m++) { + count[candidates[m].group]++; + } - // Evaluate everything else - for (i = 0; (rule = rsRules[i]); i++) { - // for rulesets, check if it is a css guard and can be removed - if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) { - // check if it can be folded in (e.g. & where) - if (rule.selectors[0] && rule.selectors[0].isJustParentSelector()) { - rsRules.splice(i--, 1); - - for (var j = 0; (subRule = rule.rules[j]); j++) { - if (subRule instanceof Node) { - subRule.copyVisibilityInfo(rule.visibilityInfo()); - if (!(subRule instanceof Declaration) || !subRule.variable) { - rsRules.splice(++i, 0, subRule); - } - } - } + 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 `".concat(this.format(args), "`"), + index: this.getIndex(), + filename: this.fileInfo().filename + }; + } } - } - } - // Pop the stack - ctxFrames.shift(); - ctxSelectors.shift(); + for (m = 0; m < candidates.length; m++) { + candidate = candidates[m].group; - if (context.mediaBlocks) { - for (i = mediaBlockCount; i < context.mediaBlocks.length; i++) { - context.mediaBlocks[i].bubbleSelectors(selectors); - } - } + if (candidate === defNone || candidate === defaultResult) { + try { + mixin = candidates[m].mixin; - return ruleset; -}; -Ruleset.prototype.evalImports = function(context) { - var rules = this.rules, i, importRules; - if (!rules) { return; } + if (!(mixin instanceof Definition)) { + originalRuleset = mixin.originalRuleset || mixin; + mixin = new Definition('', [], mixin.rules, null, false, null, originalRuleset.visibilityInfo()); + mixin.originalRuleset = originalRuleset; + } - for (i = 0; i < rules.length; i++) { - if (rules[i].type === 'Import') { - importRules = rules[i].eval(context); - if (importRules && (importRules.length || importRules.length === 0)) { - rules.splice.apply(rules, [i, 1].concat(importRules)); - i += importRules.length - 1; - } else { - rules.splice(i, 1, importRules); - } - this.resetCache(); - } - } -}; -Ruleset.prototype.makeImportant = function() { - var result = new Ruleset(this.selectors, this.rules.map(function (r) { - if (r.makeImportant) { - return r.makeImportant(); - } else { - return r; - } - }), this.strictImports, this.visibilityInfo()); + var newRules = mixin.evalCall(context, args, this.important).rules; - return result; -}; -Ruleset.prototype.matchArgs = function (args) { - return !args || args.length === 0; -}; -// lets you call a css selector with a guard -Ruleset.prototype.matchCondition = function (args, context) { - var lastSelector = this.selectors[this.selectors.length - 1]; - if (!lastSelector.evaldCondition) { - return false; - } - if (lastSelector.condition && - !lastSelector.condition.eval( - new contexts.Eval(context, - context.frames))) { - return false; - } - return true; -}; -Ruleset.prototype.resetCache = function () { - this._rulesets = null; - this._variables = null; - this._properties = null; - this._lookups = {}; -}; -Ruleset.prototype.variables = function () { - if (!this._variables) { - this._variables = !this.rules ? {} : this.rules.reduce(function (hash, r) { - if (r instanceof Declaration && r.variable === true) { - hash[r.name] = r; - } - // when evaluating variables in an import statement, imports have not been eval'd - // so we need to go inside import statements. - // guard against root being a string (in the case of inlined less) - if (r.type === 'Import' && r.root && r.root.variables) { - var vars = r.root.variables(); - for (var name in vars) { - if (vars.hasOwnProperty(name)) { - hash[name] = r.root.variable(name); - } + this._setVisibilityToReplacement(newRules); + + Array.prototype.push.apply(rules, newRules); + } catch (e) { + throw { + message: e.message, + index: this.getIndex(), + filename: this.fileInfo().filename, + stack: e.stack + }; } + } } - return hash; - }, {}); - } - return this._variables; -}; -Ruleset.prototype.properties = function () { - if (!this._properties) { - this._properties = !this.rules ? {} : this.rules.reduce(function (hash, r) { - if (r instanceof Declaration && r.variable !== true) { - var name = (r.name.length === 1) && (r.name[0] instanceof Keyword) ? - r.name[0].value : r.name; - // Properties don't overwrite as they can merge - if (!hash['$' + name]) { - hash['$' + name] = [ r ]; - } - else { - hash['$' + name].push(r); - } + + if (match) { + return rules; } - return hash; - }, {}); - } - return this._properties; -}; -Ruleset.prototype.variable = function (name) { - var decl = this.variables()[name]; - if (decl) { - return this.parseValue(decl); - } -}; -Ruleset.prototype.property = function (name) { - var decl = this.properties()[name]; - if (decl) { - return this.parseValue(decl); - } -}; -Ruleset.prototype.lastDeclaration = function () { - for (var i = this.rules.length; i > 0; i--) { - var decl = this.rules[i - 1]; - if (decl instanceof Declaration) { - return this.parseValue(decl); + } } - } -}; -Ruleset.prototype.parseValue = function(toParse) { - var self = this; - function transformDeclaration(decl) { - if (decl.value instanceof Anonymous && !decl.parsed) { - if (typeof decl.value.value === 'string') { - this.parse.parseNode( - decl.value.value, - ['value', 'important'], - decl.value.getIndex(), - decl.fileInfo(), - function(err, result) { - if (err) { - decl.parsed = true; - } - if (result) { - decl.value = result[0]; - decl.important = result[1] || ''; - decl.parsed = true; - } - }); - } else { - decl.parsed = true; - } - return decl; - } - else { - return decl; + if (isOneFound) { + throw { + type: 'Runtime', + message: "No matching definition was found for `".concat(this.format(args), "`"), + index: this.getIndex(), + filename: this.fileInfo().filename + }; + } else { + throw { + type: 'Name', + message: "".concat(this.selector.toCSS().trim(), " is undefined"), + index: this.getIndex(), + filename: this.fileInfo().filename + }; } - } - if (!Array.isArray(toParse)) { - return transformDeclaration.call(self, toParse); - } - else { - var nodes = []; - toParse.forEach(function(n) { - nodes.push(transformDeclaration.call(self, n)); - }); - return nodes; - } -}; -Ruleset.prototype.rulesets = function () { - if (!this.rules) { return []; } - - var filtRules = [], rules = this.rules, - i, rule; + } + }, { + key: "_setVisibilityToReplacement", + value: function _setVisibilityToReplacement(replacement) { + var i; + var rule; - for (i = 0; (rule = rules[i]); i++) { - if (rule.isRuleset) { - filtRules.push(rule); + if (this.blocksVisibility()) { + for (i = 0; i < replacement.length; i++) { + rule = replacement[i]; + rule.addVisibilityBlock(); + } } - } + } + }, { + key: "format", + value: function format(args) { + return "".concat(this.selector.toCSS().trim(), "(").concat(args ? args.map(function (a) { + var argValue = ''; + + if (a.name) { + argValue += "".concat(a.name, ":"); + } - return filtRules; -}; -Ruleset.prototype.prependRule = function (rule) { - var rules = this.rules; - if (rules) { - rules.unshift(rule); - } else { - this.rules = [ rule ]; - } - this.setParent(rule, this); -}; -Ruleset.prototype.find = function (selector, self, filter) { - self = self || this; - var rules = [], match, foundMixins, - key = selector.toCSS(); + if (a.value.toCSS) { + argValue += a.value.toCSS(); + } else { + argValue += '???'; + } - if (key in this._lookups) { return this._lookups[key]; } + return argValue; + }).join(', ') : '', ")"); + } + }]); + + return MixinCall; + }(Node); + + MixinCall.prototype.type = 'MixinCall'; + + var tree = { + Node: Node, + Color: Color, + AtRule: AtRule, + DetachedRuleset: DetachedRuleset, + Operation: Operation, + Dimension: Dimension, + Unit: Unit, + Keyword: Keyword, + Variable: Variable, + Property: Property, + Ruleset: Ruleset, + Element: Element, + Attribute: Attribute, + Combinator: Combinator, + Selector: Selector, + Quoted: Quoted, + Expression: Expression, + Declaration: Declaration, + Call: Call, + URL: URL, + Import: Import, + Comment: Comment, + Anonymous: Anonymous, + Value: Value, + JavaScript: JavaScript, + Assignment: Assignment, + Condition: Condition, + Paren: Paren, + Media: Media, + UnicodeDescriptor: UnicodeDescriptor, + Negative: Negative, + Extend: Extend, + VariableCall: VariableCall, + NamespaceValue: NamespaceValue, + mixin: { + Call: MixinCall, + Definition: Definition + } + }; + + var logger = { + error: function error(msg) { + this._fireEvent('error', msg); + }, + warn: function warn(msg) { + this._fireEvent('warn', msg); + }, + info: function info(msg) { + this._fireEvent('info', msg); + }, + debug: function debug(msg) { + this._fireEvent('debug', msg); + }, + addListener: function addListener(listener) { + this._listeners.push(listener); + }, + removeListener: function removeListener(listener) { + for (var i = 0; i < this._listeners.length; i++) { + if (this._listeners[i] === listener) { + this._listeners.splice(i, 1); - this.rulesets().forEach(function (rule) { - if (rule !== self) { - for (var j = 0; j < rule.selectors.length; j++) { - match = selector.match(rule.selectors[j]); - if (match) { - if (selector.elements.length > match) { - if (!filter || filter(rule)) { - foundMixins = rule.find(new Selector(selector.elements.slice(match)), self, filter); - for (var i = 0; i < foundMixins.length; ++i) { - foundMixins[i].path.push(rule); - } - Array.prototype.push.apply(rules, foundMixins); - } - } else { - rules.push({ rule: rule, path: []}); - } - break; - } - } - } - }); - this._lookups[key] = rules; - return rules; -}; -Ruleset.prototype.genCSS = function (context, output) { - var i, j, - charsetRuleNodes = [], - ruleNodes = [], - debugInfo, // Line number debugging - rule, - path; - - context.tabLevel = (context.tabLevel || 0); - - if (!this.root) { - context.tabLevel++; - } - - var tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join(' '), - tabSetStr = context.compress ? '' : Array(context.tabLevel).join(' '), - sep; - - var charsetNodeIndex = 0; - var importNodeIndex = 0; - for (i = 0; (rule = this.rules[i]); i++) { - if (rule instanceof Comment) { - if (importNodeIndex === i) { - importNodeIndex++; - } - ruleNodes.push(rule); - } else if (rule.isCharset && rule.isCharset()) { - ruleNodes.splice(charsetNodeIndex, 0, rule); - charsetNodeIndex++; - importNodeIndex++; - } else if (rule.type === 'Import') { - ruleNodes.splice(importNodeIndex, 0, rule); - importNodeIndex++; - } else { - ruleNodes.push(rule); + return; } - } - ruleNodes = charsetRuleNodes.concat(ruleNodes); - - // If this is the root node, we don't render - // a selector, or {}. - if (!this.root) { - debugInfo = getDebugInfo(context, this, tabSetStr); + } + }, + _fireEvent: function _fireEvent(type, msg) { + for (var i = 0; i < this._listeners.length; i++) { + var logFunction = this._listeners[i][type]; - if (debugInfo) { - output.add(debugInfo); - output.add(tabSetStr); + if (logFunction) { + logFunction(msg); } + } + }, + _listeners: [] + }; - var paths = this.paths, pathCnt = paths.length, - pathSubCnt; - - sep = context.compress ? ',' : (',\n' + tabSetStr); + var environment = + /*#__PURE__*/ + function () { + function environment(externalEnvironment, fileManagers) { + _classCallCheck(this, environment); - for (i = 0; i < pathCnt; i++) { - path = paths[i]; - if (!(pathSubCnt = path.length)) { continue; } - if (i > 0) { output.add(sep); } + this.fileManagers = fileManagers || []; + externalEnvironment = externalEnvironment || {}; + var optionalFunctions = ['encodeBase64', 'mimeLookup', 'charsetLookup', 'getSourceMapGenerator']; + var requiredFunctions = []; + var functions = requiredFunctions.concat(optionalFunctions); - context.firstSelector = true; - path[0].genCSS(context, output); + for (var i = 0; i < functions.length; i++) { + var propName = functions[i]; + var environmentFunc = externalEnvironment[propName]; - context.firstSelector = false; - for (j = 1; j < pathSubCnt; j++) { - path[j].genCSS(context, output); - } + if (environmentFunc) { + this[propName] = environmentFunc.bind(externalEnvironment); + } else if (i < requiredFunctions.length) { + this.warn("missing required function in environment - ".concat(propName)); } - - output.add((context.compress ? '{' : ' {\n') + tabRuleStr); + } } - // Compile rules and rulesets - for (i = 0; (rule = ruleNodes[i]); i++) { - - if (i + 1 === ruleNodes.length) { - context.lastRule = true; + _createClass(environment, [{ + key: "getFileManager", + value: function getFileManager(filename, currentDirectory, options, environment, isSync) { + if (!filename) { + logger.warn('getFileManager called with no filename.. Please report this issue. continuing.'); } - var currentLastRule = context.lastRule; - if (rule.isRulesetLike(rule)) { - context.lastRule = false; + if (currentDirectory == null) { + logger.warn('getFileManager called with null directory.. Please report this issue. continuing.'); } - if (rule.genCSS) { - rule.genCSS(context, output); - } else if (rule.value) { - output.add(rule.value.toString()); + var fileManagers = this.fileManagers; + + if (options.pluginManager) { + fileManagers = [].concat(fileManagers).concat(options.pluginManager.getFileManagers()); } - context.lastRule = currentLastRule; + for (var i = fileManagers.length - 1; i >= 0; i--) { + var fileManager = fileManagers[i]; - if (!context.lastRule && rule.isVisible()) { - output.add(context.compress ? '' : ('\n' + tabRuleStr)); - } else { - context.lastRule = false; + if (fileManager[isSync ? 'supportsSync' : 'supports'](filename, currentDirectory, options, environment)) { + return fileManager; + } } - } - if (!this.root) { - output.add((context.compress ? '}' : '\n' + tabSetStr + '}')); - context.tabLevel--; - } + return null; + } + }, { + key: "addFileManager", + value: function addFileManager(fileManager) { + this.fileManagers.push(fileManager); + } + }, { + key: "clearFileManagers", + value: function clearFileManagers() { + this.fileManagers = []; + } + }]); - if (!output.isEmpty() && !context.compress && this.firstRoot) { - output.add('\n'); - } -}; + return environment; + }(); -Ruleset.prototype.joinSelectors = function (paths, context, selectors) { - for (var s = 0; s < selectors.length; s++) { - this.joinSelector(paths, context, selectors[s]); + var AbstractFileManager = + /*#__PURE__*/ + function () { + function AbstractFileManager() { + _classCallCheck(this, AbstractFileManager); } -}; -Ruleset.prototype.joinSelector = function (paths, context, selector) { + _createClass(AbstractFileManager, [{ + key: "getPath", + value: function getPath(filename) { + var j = filename.lastIndexOf('?'); - function createParenthesis(elementsToPak, originalElement) { - var replacementParen, j; - if (elementsToPak.length === 0) { - replacementParen = new Paren(elementsToPak[0]); - } else { - var insideParent = new Array(elementsToPak.length); - for (j = 0; j < elementsToPak.length; j++) { - insideParent[j] = new Element( - null, - elementsToPak[j], - originalElement.isVariable, - originalElement._index, - originalElement._fileInfo - ); - } - replacementParen = new Paren(new Selector(insideParent)); + if (j > 0) { + filename = filename.slice(0, j); } - return replacementParen; - } - function createSelector(containedElement, originalElement) { - var element, selector; - element = new Element(null, containedElement, originalElement.isVariable, originalElement._index, originalElement._fileInfo); - selector = new Selector([element]); - return selector; - } - - // joins selector path from `beginningPath` with selector path in `addPath` - // `replacedElement` contains element that is being replaced by `addPath` - // returns concatenated path - function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) { - var newSelectorPath, lastSelector, newJoinedSelector; - // our new selector path - newSelectorPath = []; + j = filename.lastIndexOf('/'); - // construct the joined selector - if & is the first thing this will be empty, - // if not newJoinedSelector will be the last set of elements in the selector - if (beginningPath.length > 0) { - newSelectorPath = utils.copyArray(beginningPath); - lastSelector = newSelectorPath.pop(); - newJoinedSelector = originalSelector.createDerived(utils.copyArray(lastSelector.elements)); + if (j < 0) { + j = filename.lastIndexOf('\\'); } - else { - newJoinedSelector = originalSelector.createDerived([]); + + if (j < 0) { + return ''; } - if (addPath.length > 0) { - // /deep/ is a CSS4 selector - (removed, so should deprecate) - // that is valid without anything in front of it - // so if the & does not have a combinator that is "" or " " then - // and there is a combinator on the parent, then grab that. - // this also allows + a { & .b { .a & { ... though not sure why you would want to do that - var combinator = replacedElement.combinator, parentEl = addPath[0].elements[0]; - if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) { - combinator = parentEl.combinator; - } - // join the elements so far with the first part of the parent - newJoinedSelector.elements.push(new Element( - combinator, - parentEl.value, - replacedElement.isVariable, - replacedElement._index, - replacedElement._fileInfo - )); - newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1)); + return filename.slice(0, j + 1); + } + }, { + key: "tryAppendExtension", + value: function tryAppendExtension(path, ext) { + return /(\.[a-z]*$)|([\?;].*)$/.test(path) ? path : path + ext; + } + }, { + key: "tryAppendLessExtension", + value: function tryAppendLessExtension(path) { + return this.tryAppendExtension(path, '.less'); + } + }, { + key: "supportsSync", + value: function supportsSync() { + return false; + } + }, { + key: "alwaysMakePathsAbsolute", + value: function alwaysMakePathsAbsolute() { + return false; + } + }, { + key: "isPathAbsolute", + value: function isPathAbsolute(filename) { + return /^(?:[a-z-]+:|\/|\\|#)/i.test(filename); + } // TODO: pull out / replace? + + }, { + key: "join", + value: function join(basePath, laterPath) { + if (!basePath) { + return laterPath; } - // now add the joined selector - but only if it is not empty - if (newJoinedSelector.elements.length !== 0) { - newSelectorPath.push(newJoinedSelector); + return basePath + laterPath; + } + }, { + key: "pathDiff", + value: function pathDiff(url, baseUrl) { + // diff between two paths to create a relative path + var urlParts = this.extractUrlParts(url); + var baseUrlParts = this.extractUrlParts(baseUrl); + var i; + var max; + var urlDirectories; + var baseUrlDirectories; + var 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; + } } - // put together the parent selectors after the join (e.g. the rest of the parent) - if (addPath.length > 1) { - var restOfPath = addPath.slice(1); - restOfPath = restOfPath.map(function (selector) { - return selector.createDerived(selector.elements, []); - }); - newSelectorPath = newSelectorPath.concat(restOfPath); + baseUrlDirectories = baseUrlParts.directories.slice(i); + urlDirectories = urlParts.directories.slice(i); + + for (i = 0; i < baseUrlDirectories.length - 1; i++) { + diff += '../'; } - return newSelectorPath; - } - // joins selector path from `beginningPath` with every selector path in `addPaths` array - // `replacedElement` contains element that is being replaced by `addPath` - // returns array with all concatenated paths - function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) { - var j; - for (j = 0; j < beginningPath.length; j++) { - var newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector); - result.push(newSelectorPath); + for (i = 0; i < urlDirectories.length - 1; i++) { + diff += "".concat(urlDirectories[i], "/"); } - return result; - } - function mergeElementsOnToSelectors(elements, selectors) { - var i, sel; + return diff; + } + }, { + key: "extractUrlParts", + // helper function, not part of API + value: function extractUrlParts(url, baseUrl) { + // urlParts[1] = protocol://hostname/ OR / + // urlParts[2] = / if path relative to host base + // urlParts[3] = directories + // urlParts[4] = filename + // urlParts[5] = parameters + var urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i; + var urlParts = url.match(urlPartsRegex); + var returner = {}; + var rawDirectories = []; + var directories = []; + var i; + var baseUrlParts; + + if (!urlParts) { + throw new Error("Could not parse sheet href - '".concat(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 - '".concat(baseUrl, "'")); + } - if (elements.length === 0) { - return ; - } - if (selectors.length === 0) { - selectors.push([ new Selector(elements) ]); - return; - } + urlParts[1] = urlParts[1] || baseUrlParts[1] || ''; - for (i = 0; (sel = selectors[i]); i++) { - // if the previous thing in sel is a parent this needs to join on to it - if (sel.length > 0) { - sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements)); - } - else { - sel.push(new Selector(elements)); - } + if (!urlParts[2]) { + urlParts[3] = baseUrlParts[3] + urlParts[3]; + } } - } - // replace all parent selectors inside `inSelector` by content of `context` array - // resulting selectors are returned inside `paths` array - // returns true if `inSelector` contained at least one parent selector - function replaceParentSelector(paths, context, inSelector) { - // The paths are [[Selector]] - // The first list is a list of comma separated selectors - // The inner list is a list of inheritance separated selectors - // e.g. - // .a, .b { - // .c { - // } - // } - // == [[.a] [.c]] [[.b] [.c]] - // - var i, j, k, currentElements, newSelectors, selectorsMultiplied, sel, el, hadParentSelector = false, length, lastSelector; - function findNestedSelector(element) { - var maybeSelector; - if (!(element.value instanceof Paren)) { - return null; - } + if (urlParts[3]) { + rawDirectories = urlParts[3].replace(/\\/g, '/').split('/'); // collapse '..' and skip '.' - maybeSelector = element.value.value; - if (!(maybeSelector instanceof Selector)) { - return null; + for (i = 0; i < rawDirectories.length; i++) { + if (rawDirectories[i] === '..') { + directories.pop(); + } else if (rawDirectories[i] !== '.') { + directories.push(rawDirectories[i]); } - - return maybeSelector; + } } - // the elements from the current selector so far - currentElements = []; - // the current list of new selectors to add to the path. - // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors - // by the parents - newSelectors = [ - [] - ]; + returner.hostPart = urlParts[1]; + returner.directories = directories; + returner.rawPath = (urlParts[1] || '') + rawDirectories.join('/'); + returner.path = (urlParts[1] || '') + directories.join('/'); + returner.filename = urlParts[4]; + returner.fileUrl = returner.path + (urlParts[4] || ''); + returner.url = returner.fileUrl + (urlParts[5] || ''); + return returner; + } + }]); - for (i = 0; (el = inSelector.elements[i]); i++) { - // non parent reference elements just get added - if (el.value !== '&') { - var nestedSelector = findNestedSelector(el); - if (nestedSelector != null) { - // merge the current list of non parent selector elements - // on to the current list of selectors to add - mergeElementsOnToSelectors(currentElements, newSelectors); - - var nestedPaths = [], replaced, replacedNewSelectors = []; - replaced = replaceParentSelector(nestedPaths, context, nestedSelector); - hadParentSelector = hadParentSelector || replaced; - // the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors - for (k = 0; k < nestedPaths.length; k++) { - var replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el); - addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors); - } - newSelectors = replacedNewSelectors; - currentElements = []; + return AbstractFileManager; + }(); - } else { - currentElements.push(el); - } + var AbstractPluginLoader = + /*#__PURE__*/ + function () { + function AbstractPluginLoader() { + _classCallCheck(this, AbstractPluginLoader); - } else { - hadParentSelector = true; - // the new list of selectors to add - selectorsMultiplied = []; + // Implemented by Node.js plugin loader + this.require = function () { + return null; + }; + } + + _createClass(AbstractPluginLoader, [{ + key: "evalPlugin", + value: function evalPlugin(contents, context, imports, pluginOptions, fileInfo) { + var loader; + var registry; + var pluginObj; + var localModule; + var pluginManager; + var filename; + var result; + pluginManager = context.pluginManager; + + if (fileInfo) { + if (typeof fileInfo === 'string') { + filename = fileInfo; + } else { + filename = fileInfo.filename; + } + } - // merge the current list of non parent selector elements - // on to the current list of selectors to add - mergeElementsOnToSelectors(currentElements, newSelectors); + var shortname = new this.less.FileManager().extractUrlParts(filename).filename; - // loop through our current selectors - for (j = 0; j < newSelectors.length; j++) { - sel = newSelectors[j]; - // if we don't have any parent paths, the & might be in a mixin so that it can be used - // whether there are parents or not - if (context.length === 0) { - // the combinator used on el should now be applied to the next element instead so that - // it is not lost - if (sel.length > 0) { - sel[0].elements.push(new Element(el.combinator, '', el.isVariable, el._index, el._fileInfo)); - } - selectorsMultiplied.push(sel); - } - else { - // and the parent selectors - for (k = 0; k < context.length; k++) { - // We need to put the current selectors - // then join the last selector's elements on to the parents selectors - var newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector); - // add that to our new set of selectors - selectorsMultiplied.push(newSelectorPath); - } - } - } + if (filename) { + pluginObj = pluginManager.get(filename); - // our new selectors has been multiplied, so reset the state - newSelectors = selectorsMultiplied; - currentElements = []; - } - } + if (pluginObj) { + result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); - // if we have any elements left over (e.g. .a& .b == .b) - // add them on to all the current selectors - mergeElementsOnToSelectors(currentElements, newSelectors); + if (result) { + return result; + } - for (i = 0; i < newSelectors.length; i++) { - length = newSelectors[i].length; - if (length > 0) { - paths.push(newSelectors[i]); - lastSelector = newSelectors[i][length - 1]; - newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList); + try { + if (pluginObj.use) { + pluginObj.use.call(this.context, pluginObj); + } + } catch (e) { + e.message = e.message || 'Error during @plugin call'; + return new LessError(e, imports, filename); } + + return pluginObj; + } } - return hadParentSelector; - } + localModule = { + exports: {}, + pluginManager: pluginManager, + fileInfo: fileInfo + }; + registry = functionRegistry.create(); - function deriveSelector(visibilityInfo, deriveFrom) { - var newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition); - newSelector.copyVisibilityInfo(visibilityInfo); - return newSelector; - } + var registerPlugin = function registerPlugin(obj) { + pluginObj = obj; + }; - // joinSelector code follows - var i, newPaths, hadParentSelector; + try { + loader = new Function('module', 'require', 'registerPlugin', 'functions', 'tree', 'less', 'fileInfo', contents); + loader(localModule, this.require(filename), registerPlugin, registry, this.less.tree, this.less, fileInfo); + } catch (e) { + return new LessError(e, imports, filename); + } - newPaths = []; - hadParentSelector = replaceParentSelector(newPaths, context, selector); + if (!pluginObj) { + pluginObj = localModule.exports; + } - if (!hadParentSelector) { - if (context.length > 0) { - newPaths = []; - for (i = 0; i < context.length; i++) { + pluginObj = this.validatePlugin(pluginObj, filename, shortname); + + if (pluginObj instanceof LessError) { + return pluginObj; + } + + if (pluginObj) { + pluginObj.imports = imports; + pluginObj.filename = filename; // For < 3.x (or unspecified minVersion) - setOptions() before install() + + if (!pluginObj.minVersion || this.compareVersion('3.0.0', pluginObj.minVersion) < 0) { + result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); + + if (result) { + return result; + } + } // Run on first load + + + pluginManager.addPlugin(pluginObj, fileInfo.filename, registry); + pluginObj.functions = registry.getLocalFunctions(); // Need to call setOptions again because the pluginObj might have functions - var concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo())); + result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); - concatenated.push(selector); - newPaths.push(concatenated); + if (result) { + return result; + } // Run every @plugin call + + + try { + if (pluginObj.use) { + pluginObj.use.call(this.context, pluginObj); } + } catch (e) { + e.message = e.message || 'Error during @plugin call'; + return new LessError(e, imports, filename); + } + } else { + return new LessError({ + message: 'Not a valid plugin' + }, imports, filename); } - else { - newPaths = [[selector]]; + + return pluginObj; + } + }, { + key: "trySetOptions", + value: function trySetOptions(plugin, filename, name, options) { + if (options && !plugin.setOptions) { + return new LessError({ + message: "Options have been provided but the plugin ".concat(name, " does not support any options.") + }); } - } - for (i = 0; i < newPaths.length; i++) { - paths.push(newPaths[i]); - } - -}; -module.exports = Ruleset; - -},{"../contexts":13,"../functions/default":25,"../functions/function-registry":27,"../utils":89,"./anonymous":50,"./comment":57,"./debug-info":59,"./declaration":60,"./element":63,"./keyword":70,"./node":76,"./paren":78,"./selector":82}],82:[function(require,module,exports){ -var Node = require('./node'), - Element = require('./element'), - LessError = require('../less-error'); - -var Selector = function (elements, extendList, condition, index, currentFileInfo, visibilityInfo) { - this.extendList = extendList; - this.condition = condition; - this.evaldCondition = !condition; - this._index = index; - this._fileInfo = currentFileInfo; - this.elements = this.getElements(elements); - this.mixinElements_ = undefined; - this.copyVisibilityInfo(visibilityInfo); - this.setParent(this.elements, this); -}; -Selector.prototype = new Node(); -Selector.prototype.type = 'Selector'; -Selector.prototype.accept = function (visitor) { - if (this.elements) { - this.elements = visitor.visitArray(this.elements); - } - if (this.extendList) { - this.extendList = visitor.visitArray(this.extendList); - } - if (this.condition) { - this.condition = visitor.visit(this.condition); - } -}; -Selector.prototype.createDerived = function(elements, extendList, evaldCondition) { - elements = this.getElements(elements); - var newSelector = new Selector(elements, extendList || this.extendList, - null, this.getIndex(), this.fileInfo(), this.visibilityInfo()); - newSelector.evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition; - newSelector.mediaEmpty = this.mediaEmpty; - return newSelector; -}; -Selector.prototype.getElements = function(els) { - if (!els) { - return [new Element('', '&', false, this._index, this._fileInfo)]; - } - if (typeof els === 'string') { - this.parse.parseNode( - els, - ['selector'], - this._index, - this._fileInfo, - function(err, result) { - if (err) { - throw new LessError({ - index: err.index, - message: err.message - }, this.parse.imports, this._fileInfo.filename); - } - els = result[0].elements; - }); - } - return els; -}; -Selector.prototype.createEmptySelectors = function() { - var el = new Element('', '&', false, this._index, this._fileInfo), - sels = [new Selector([el], null, null, this._index, this._fileInfo)]; - sels[0].mediaEmpty = true; - return sels; -}; -Selector.prototype.match = function (other) { - var elements = this.elements, - len = elements.length, - olen, i; - - other = other.mixinElements(); - olen = other.length; - if (olen === 0 || len < olen) { - return 0; - } else { - for (i = 0; i < olen; i++) { - if (elements[i].value !== other[i]) { - return 0; - } + try { + plugin.setOptions && plugin.setOptions(options); + } catch (e) { + return new LessError(e); } - } + } + }, { + key: "validatePlugin", + value: function validatePlugin(plugin, filename, name) { + if (plugin) { + // support plugins being a function + // so that the plugin can be more usable programmatically + if (typeof plugin === 'function') { + plugin = new plugin(); + } - return olen; // return number of matched elements -}; -Selector.prototype.mixinElements = function() { - if (this.mixinElements_) { - return this.mixinElements_; - } + if (plugin.minVersion) { + if (this.compareVersion(plugin.minVersion, this.less.version) < 0) { + return new LessError({ + message: "Plugin ".concat(name, " requires version ").concat(this.versionToString(plugin.minVersion)) + }); + } + } - var elements = this.elements.map( function(v) { - return v.combinator.value + (v.value.value || v.value); - }).join('').match(/[,&#\*\.\w-]([\w-]|(\\.))*/g); + return plugin; + } - if (elements) { - if (elements[0] === '&') { - elements.shift(); + return null; + } + }, { + key: "compareVersion", + value: function compareVersion(aVersion, bVersion) { + if (typeof aVersion === 'string') { + aVersion = aVersion.match(/^(\d+)\.?(\d+)?\.?(\d+)?/); + aVersion.shift(); } - } else { - elements = []; - } - - return (this.mixinElements_ = elements); -}; -Selector.prototype.isJustParentSelector = function() { - return !this.mediaEmpty && - this.elements.length === 1 && - this.elements[0].value === '&' && - (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === ''); -}; -Selector.prototype.eval = function (context) { - var evaldCondition = this.condition && this.condition.eval(context), - elements = this.elements, extendList = this.extendList; - - elements = elements && elements.map(function (e) { return e.eval(context); }); - extendList = extendList && extendList.map(function(extend) { return extend.eval(context); }); - - return this.createDerived(elements, extendList, evaldCondition); -}; -Selector.prototype.genCSS = function (context, output) { - var i, element; - if ((!context || !context.firstSelector) && this.elements[0].combinator.value === '') { - output.add(' ', this.fileInfo(), this.getIndex()); - } - for (i = 0; i < this.elements.length; i++) { - element = this.elements[i]; - element.genCSS(context, output); - } -}; -Selector.prototype.getIsOutput = function() { - return this.evaldCondition; -}; -module.exports = Selector; - -},{"../less-error":38,"./element":63,"./node":76}],83:[function(require,module,exports){ -var Node = require('./node'); - -var UnicodeDescriptor = function (value) { - this.value = value; -}; -UnicodeDescriptor.prototype = new Node(); -UnicodeDescriptor.prototype.type = 'UnicodeDescriptor'; - -module.exports = UnicodeDescriptor; - -},{"./node":76}],84:[function(require,module,exports){ -var Node = require('./node'), - unitConversions = require('../data/unit-conversions'), - utils = require('../utils'); - -var Unit = function (numerator, denominator, backupUnit) { - this.numerator = numerator ? utils.copyArray(numerator).sort() : []; - this.denominator = denominator ? utils.copyArray(denominator).sort() : []; - if (backupUnit) { - this.backupUnit = backupUnit; - } else if (numerator && numerator.length) { - this.backupUnit = numerator[0]; - } -}; - -Unit.prototype = new Node(); -Unit.prototype.type = 'Unit'; -Unit.prototype.clone = function () { - return new Unit(utils.copyArray(this.numerator), utils.copyArray(this.denominator), this.backupUnit); -}; -Unit.prototype.genCSS = function (context, output) { - // Dimension checks the unit is singular and throws an error if in strict math mode. - var strictUnits = context && context.strictUnits; - if (this.numerator.length === 1) { - output.add(this.numerator[0]); // the ideal situation - } else if (!strictUnits && this.backupUnit) { - output.add(this.backupUnit); - } else if (!strictUnits && this.denominator.length) { - output.add(this.denominator[0]); - } -}; -Unit.prototype.toString = function () { - var i, returnStr = this.numerator.join('*'); - for (i = 0; i < this.denominator.length; i++) { - returnStr += '/' + this.denominator[i]; - } - return returnStr; -}; -Unit.prototype.compare = function (other) { - return this.is(other.toString()) ? 0 : undefined; -}; -Unit.prototype.is = function (unitString) { - return this.toString().toUpperCase() === unitString.toUpperCase(); -}; -Unit.prototype.isLength = function () { - return RegExp('^(px|em|ex|ch|rem|in|cm|mm|pc|pt|ex|vw|vh|vmin|vmax)$', 'gi').test(this.toCSS()); -}; -Unit.prototype.isEmpty = function () { - return this.numerator.length === 0 && this.denominator.length === 0; -}; -Unit.prototype.isSingular = function() { - return this.numerator.length <= 1 && this.denominator.length === 0; -}; -Unit.prototype.map = function(callback) { - var i; - for (i = 0; i < this.numerator.length; i++) { - this.numerator[i] = callback(this.numerator[i], false); - } + for (var i = 0; i < aVersion.length; i++) { + if (aVersion[i] !== bVersion[i]) { + return parseInt(aVersion[i]) > parseInt(bVersion[i]) ? -1 : 1; + } + } - for (i = 0; i < this.denominator.length; i++) { - this.denominator[i] = callback(this.denominator[i], true); - } -}; -Unit.prototype.usedUnits = function() { - var group, result = {}, mapUnit, groupName; + return 0; + } + }, { + key: "versionToString", + value: function versionToString(version) { + var versionString = ''; - mapUnit = function (atomicUnit) { - /* jshint loopfunc:true */ - if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { - result[groupName] = atomicUnit; + for (var i = 0; i < version.length; i++) { + versionString += (versionString ? '.' : '') + version[i]; } - return atomicUnit; - }; - - for (groupName in unitConversions) { - if (unitConversions.hasOwnProperty(groupName)) { - group = unitConversions[groupName]; + return versionString; + } + }, { + key: "printUsage", + value: function printUsage(plugins) { + for (var i = 0; i < plugins.length; i++) { + var plugin = plugins[i]; - this.map(mapUnit); + if (plugin.printUsage) { + plugin.printUsage(); + } } - } + } + }]); - return result; -}; -Unit.prototype.cancel = function () { - var counter = {}, atomicUnit, i; + return AbstractPluginLoader; + }(); - for (i = 0; i < this.numerator.length; i++) { - atomicUnit = this.numerator[i]; - counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; - } + var _visitArgs = { + visitDeeper: true + }; + var _hasIndexed = false; - for (i = 0; i < this.denominator.length; i++) { - atomicUnit = this.denominator[i]; - counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; - } + function _noop(node) { + return node; + } - this.numerator = []; - this.denominator = []; + function indexNodeTypes(parent, ticker) { + // add .typeIndex to tree node types for lookup table + var key; + var child; - for (atomicUnit in counter) { - if (counter.hasOwnProperty(atomicUnit)) { - var count = counter[atomicUnit]; + for (key in parent) { + /* eslint guard-for-in: 0 */ + child = parent[key]; - if (count > 0) { - for (i = 0; i < count; i++) { - this.numerator.push(atomicUnit); - } - } else if (count < 0) { - for (i = 0; i < -count; i++) { - this.denominator.push(atomicUnit); - } - } - } + switch (_typeof(child)) { + case 'function': + // ignore bound functions directly on tree which do not have a prototype + // or aren't nodes + if (child.prototype && child.prototype.type) { + child.prototype.typeIndex = ticker++; + } + + break; + + case 'object': + ticker = indexNodeTypes(child, ticker); + break; + } } - this.numerator.sort(); - this.denominator.sort(); -}; -module.exports = Unit; - -},{"../data/unit-conversions":16,"../utils":89,"./node":76}],85:[function(require,module,exports){ -var Node = require('./node'); - -var URL = function (val, index, currentFileInfo, isEvald) { - this.value = val; - this._index = index; - this._fileInfo = currentFileInfo; - this.isEvald = isEvald; -}; -URL.prototype = new Node(); -URL.prototype.type = 'Url'; -URL.prototype.accept = function (visitor) { - this.value = visitor.visit(this.value); -}; -URL.prototype.genCSS = function (context, output) { - output.add('url('); - this.value.genCSS(context, output); - output.add(')'); -}; -URL.prototype.eval = function (context) { - var val = this.value.eval(context), - rootpath; - - if (!this.isEvald) { - // Add the rootpath if the URL requires a rewrite - rootpath = this.fileInfo() && this.fileInfo().rootpath; - if (typeof rootpath === 'string' && - typeof val.value === 'string' && - context.pathRequiresRewrite(val.value)) { - if (!val.quote) { - rootpath = escapePath(rootpath); - } - val.value = context.rewritePath(val.value, rootpath); - } else { - val.value = context.normalizePath(val.value); - } + return ticker; + } - // Add url args if enabled - if (context.urlArgs) { - if (!val.value.match(/^\s*data:/)) { - var delimiter = val.value.indexOf('?') === -1 ? '?' : '&'; - var urlArgs = delimiter + context.urlArgs; - if (val.value.indexOf('#') !== -1) { - val.value = val.value.replace('#', urlArgs + '#'); - } else { - val.value += urlArgs; - } - } - } + var Visitor = + /*#__PURE__*/ + function () { + function Visitor(implementation) { + _classCallCheck(this, Visitor); + + this._implementation = implementation; + this._visitInCache = {}; + this._visitOutCache = {}; + + if (!_hasIndexed) { + indexNodeTypes(tree, 1); + _hasIndexed = true; + } } - return new URL(val, this.getIndex(), this.fileInfo(), true); -}; + _createClass(Visitor, [{ + key: "visit", + value: function visit(node) { + if (!node) { + return node; + } -function escapePath(path) { - return path.replace(/[\(\)'"\s]/g, function(match) { return '\\' + match; }); -} + var nodeTypeIndex = node.typeIndex; -module.exports = URL; + if (!nodeTypeIndex) { + // MixinCall args aren't a node type? + if (node.value && node.value.typeIndex) { + this.visit(node.value); + } -},{"./node":76}],86:[function(require,module,exports){ -var Node = require('./node'); + return node; + } -var Value = function (value) { - if (!value) { - throw new Error('Value requires an array argument'); - } - if (!Array.isArray(value)) { - this.value = [ value ]; - } - else { - this.value = value; - } -}; -Value.prototype = new Node(); -Value.prototype.type = 'Value'; -Value.prototype.accept = function (visitor) { - if (this.value) { - this.value = visitor.visitArray(this.value); - } -}; -Value.prototype.eval = function (context) { - if (this.value.length === 1) { - return this.value[0].eval(context); - } else { - return new Value(this.value.map(function (v) { - return v.eval(context); - })); - } -}; -Value.prototype.genCSS = function (context, output) { - var i; - for (i = 0; i < this.value.length; i++) { - this.value[i].genCSS(context, output); - if (i + 1 < this.value.length) { - output.add((context && context.compress) ? ',' : ', '); - } - } -}; -module.exports = Value; - -},{"./node":76}],87:[function(require,module,exports){ -var Node = require('./node'), - Variable = require('./variable'), - Ruleset = require('./ruleset'), - DetachedRuleset = require('./detached-ruleset'), - LessError = require('../less-error'); - -var VariableCall = function (variable, index, currentFileInfo) { - this.variable = variable; - this._index = index; - this._fileInfo = currentFileInfo; - this.allowRoot = true; -}; -VariableCall.prototype = new Node(); -VariableCall.prototype.type = 'VariableCall'; -VariableCall.prototype.eval = function (context) { - var rules, detachedRuleset = new Variable(this.variable, this.getIndex(), this.fileInfo()).eval(context), - error = new LessError({message: 'Could not evaluate variable call ' + this.variable}); - - if (!detachedRuleset.ruleset) { - if (detachedRuleset.rules) { - rules = detachedRuleset; + var impl = this._implementation; + var func = this._visitInCache[nodeTypeIndex]; + var funcOut = this._visitOutCache[nodeTypeIndex]; + var visitArgs = _visitArgs; + var fnName; + visitArgs.visitDeeper = true; + + if (!func) { + fnName = "visit".concat(node.type); + func = impl[fnName] || _noop; + funcOut = impl["".concat(fnName, "Out")] || _noop; + this._visitInCache[nodeTypeIndex] = func; + this._visitOutCache[nodeTypeIndex] = funcOut; } - else if (Array.isArray(detachedRuleset)) { - rules = new Ruleset('', detachedRuleset); + + if (func !== _noop) { + var newNode = func.call(impl, node, visitArgs); + + if (node && impl.isReplacing) { + node = newNode; + } } - else if (Array.isArray(detachedRuleset.value)) { - rules = new Ruleset('', detachedRuleset.value); + + if (visitArgs.visitDeeper && node && node.accept) { + node.accept(this); } - else { - throw error; + + if (funcOut != _noop) { + funcOut.call(impl, node); } - detachedRuleset = new DetachedRuleset(rules); - } - if (detachedRuleset.ruleset) { - return detachedRuleset.callEval(context); - } - throw error; -}; -module.exports = VariableCall; -},{"../less-error":38,"./detached-ruleset":61,"./node":76,"./ruleset":81,"./variable":88}],88:[function(require,module,exports){ -var Node = require('./node'), - Call = require('./call'); + return node; + } + }, { + key: "visitArray", + value: function visitArray(nodes, nonReplacing) { + if (!nodes) { + return nodes; + } -var Variable = function (name, index, currentFileInfo) { - this.name = name; - this._index = index; - this._fileInfo = currentFileInfo; -}; -Variable.prototype = new Node(); -Variable.prototype.type = 'Variable'; -Variable.prototype.eval = function (context) { - var variable, name = this.name; + var cnt = nodes.length; + var i; // Non-replacing - if (name.indexOf('@@') === 0) { - name = '@' + new Variable(name.slice(1), this.getIndex(), this.fileInfo()).eval(context).value; - } + if (nonReplacing || !this._implementation.isReplacing) { + for (i = 0; i < cnt; i++) { + this.visit(nodes[i]); + } - if (this.evaluating) { - throw { type: 'Name', - message: 'Recursive variable definition for ' + name, - filename: this.fileInfo().filename, - index: this.getIndex() }; - } + return nodes; + } // Replacing - this.evaluating = true; - variable = this.find(context.frames, function (frame) { - var v = frame.variable(name); - if (v) { - if (v.important) { - var importantScope = context.importantScope[context.importantScope.length - 1]; - importantScope.important = v.important; - } - // If in calc, wrap vars in a function call to cascade evaluate args first - if (context.inCalc) { - return (new Call('_SELF', [v.value])).eval(context); - } - else { - return v.value.eval(context); - } - } - }); - if (variable) { - this.evaluating = false; - return variable; - } else { - throw { type: 'Name', - message: 'variable ' + name + ' is undefined', - filename: this.fileInfo().filename, - index: this.getIndex() }; - } -}; -Variable.prototype.find = function (obj, fun) { - for (var i = 0, r; i < obj.length; i++) { - r = fun.call(obj, obj[i]); - if (r) { return r; } - } - return null; -}; -module.exports = Variable; + var out = []; -},{"./call":54,"./node":76}],89:[function(require,module,exports){ -/* jshint proto: true */ -var Constants = require('./constants'); -var clone = require('clone'); + for (i = 0; i < cnt; i++) { + var evald = this.visit(nodes[i]); -var utils = { - getLocation: function(index, inputStream) { - var n = index + 1, - line = null, - column = -1; + if (evald === undefined) { + continue; + } - while (--n >= 0 && inputStream.charAt(n) !== '\n') { - column++; + if (!evald.splice) { + out.push(evald); + } else if (evald.length) { + this.flatten(evald, out); + } } - if (typeof index === 'number') { - line = (inputStream.slice(0, index).match(/\n/g) || '').length; + return out; + } + }, { + key: "flatten", + value: function flatten(arr, out) { + if (!out) { + out = []; } - return { - line: line, - column: column - }; - }, - copyArray: function(arr) { - var i, length = arr.length, - copy = new Array(length); - - for (i = 0; i < length; i++) { - copy[i] = arr[i]; - } - return copy; - }, - clone: function (obj) { - var cloned = {}; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - cloned[prop] = obj[prop]; - } - } - return cloned; - }, - copyOptions: function(obj1, obj2) { - if (obj2 && obj2._defaults) { - return obj2; - } - var opts = utils.defaults(obj1, obj2); - if (opts.strictMath) { - opts.math = Constants.Math.STRICT_LEGACY; - } - // Back compat with changed relativeUrls option - if (opts.relativeUrls) { - opts.rewriteUrls = Constants.RewriteUrls.ALL; - } - if (typeof opts.math === 'string') { - switch (opts.math.toLowerCase()) { - case 'always': - opts.math = Constants.Math.ALWAYS; - break; - case 'parens-division': - opts.math = Constants.Math.PARENS_DIVISION; - break; - case 'strict': - case 'parens': - opts.math = Constants.Math.PARENS; - break; - case 'strict-legacy': - opts.math = Constants.Math.STRICT_LEGACY; - } - } - if (typeof opts.rewriteUrls === 'string') { - switch (opts.rewriteUrls.toLowerCase()) { - case 'off': - opts.rewriteUrls = Constants.RewriteUrls.OFF; - break; - case 'local': - opts.rewriteUrls = Constants.RewriteUrls.LOCAL; - break; - case 'all': - opts.rewriteUrls = Constants.RewriteUrls.ALL; - break; - } - } - return opts; - }, - defaults: function(obj1, obj2) { - var newObj = obj2 || {}; - if (!obj2._defaults) { - newObj = {}; - var defaults = clone(obj1); - newObj._defaults = defaults; - var cloned = obj2 ? clone(obj2) : {}; - Object.assign(newObj, defaults, cloned); - } - return newObj; - }, - merge: function(obj1, obj2) { - for (var prop in obj2) { - if (obj2.hasOwnProperty(prop)) { - obj1[prop] = obj2[prop]; - } - } - return obj1; - }, - flattenArray: function(arr, result) { - result = result || []; - for (var i = 0, length = arr.length; i < length; i++) { - var value = arr[i]; - if (Array.isArray(value)) { - utils.flattenArray(value, result); - } else { - if (value !== undefined) { - result.push(value); - } - } - } - return result; - } -}; + var cnt; + var i; + var item; + var nestedCnt; + var j; + var nestedItem; -module.exports = utils; -},{"./constants":12,"clone":100}],90:[function(require,module,exports){ -var tree = require('../tree'), - Visitor = require('./visitor'), - logger = require('../logger'), - utils = require('../utils'); + for (i = 0, cnt = arr.length; i < cnt; i++) { + item = arr[i]; -/* jshint loopfunc:true */ + if (item === undefined) { + continue; + } -var ExtendFinderVisitor = function() { - this._visitor = new Visitor(this); - this.contexts = []; - this.allExtendsStack = [[]]; -}; + if (!item.splice) { + out.push(item); + continue; + } -ExtendFinderVisitor.prototype = { - run: function (root) { - root = this._visitor.visit(root); - root.allExtends = this.allExtendsStack[0]; - return root; - }, - visitDeclaration: function (declNode, visitArgs) { - visitArgs.visitDeeper = false; - }, - visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { - visitArgs.visitDeeper = false; - }, - visitRuleset: function (rulesetNode, visitArgs) { - if (rulesetNode.root) { - return; - } + for (j = 0, nestedCnt = item.length; j < nestedCnt; j++) { + nestedItem = item[j]; - var i, j, extend, allSelectorsExtendList = [], extendList; + if (nestedItem === undefined) { + continue; + } - // get &:extend(.a); rules which apply to all selectors in this ruleset - var rules = rulesetNode.rules, ruleCnt = rules ? rules.length : 0; - for (i = 0; i < ruleCnt; i++) { - if (rulesetNode.rules[i] instanceof tree.Extend) { - allSelectorsExtendList.push(rules[i]); - rulesetNode.extendOnEveryPath = true; + if (!nestedItem.splice) { + out.push(nestedItem); + } else if (nestedItem.length) { + this.flatten(nestedItem, out); } + } } - // now find every selector and apply the extends that apply to all extends - // and the ones which apply to an individual extend - var paths = rulesetNode.paths; - for (i = 0; i < paths.length; i++) { - var selectorPath = paths[i], - selector = selectorPath[selectorPath.length - 1], - selExtendList = selector.extendList; + return out; + } + }]); + + return Visitor; + }(); + + var ImportSequencer = + /*#__PURE__*/ + function () { + function ImportSequencer(onSequencerEmpty) { + _classCallCheck(this, ImportSequencer); + + this.imports = []; + this.variableImports = []; + this._onSequencerEmpty = onSequencerEmpty; + this._currentDepth = 0; + } + + _createClass(ImportSequencer, [{ + key: "addImport", + value: function addImport(callback) { + var importSequencer = this; + var importItem = { + callback: callback, + args: null, + isReady: false + }; + this.imports.push(importItem); + return function () { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } - extendList = selExtendList ? utils.copyArray(selExtendList).concat(allSelectorsExtendList) - : allSelectorsExtendList; + importItem.args = Array.prototype.slice.call(args, 0); + importItem.isReady = true; + importSequencer.tryRun(); + }; + } + }, { + key: "addVariableImport", + value: function addVariableImport(callback) { + this.variableImports.push(callback); + } + }, { + key: "tryRun", + value: function tryRun() { + this._currentDepth++; - if (extendList) { - extendList = extendList.map(function(allSelectorsExtend) { - return allSelectorsExtend.clone(); - }); + try { + while (true) { + while (this.imports.length > 0) { + var importItem = this.imports[0]; + + if (!importItem.isReady) { + return; + } + + this.imports = this.imports.slice(1); + importItem.callback.apply(null, importItem.args); } - for (j = 0; j < extendList.length; j++) { - this.foundExtends = true; - extend = extendList[j]; - extend.findSelfSelectors(selectorPath); - extend.ruleset = rulesetNode; - if (j === 0) { extend.firstExtendOnThisSelectorPath = true; } - this.allExtendsStack[this.allExtendsStack.length - 1].push(extend); + if (this.variableImports.length === 0) { + break; } + + var variableImport = this.variableImports[0]; + this.variableImports = this.variableImports.slice(1); + variableImport(); + } + } finally { + this._currentDepth--; } - this.contexts.push(rulesetNode.selectors); - }, - visitRulesetOut: function (rulesetNode) { - if (!rulesetNode.root) { - this.contexts.length = this.contexts.length - 1; + if (this._currentDepth === 0 && this._onSequencerEmpty) { + this._onSequencerEmpty(); } + } + }]); + + return ImportSequencer; + }(); + + var ImportVisitor = function ImportVisitor(importer, finish) { + this._visitor = new Visitor(this); + this._importer = importer; + this._finish = finish; + this.context = new contexts.Eval(); + this.importCount = 0; + this.onceFileDetectionMap = {}; + this.recursionDetector = {}; + this._sequencer = new ImportSequencer(this._onSequencerEmpty.bind(this)); + }; + + ImportVisitor.prototype = { + isReplacing: false, + run: function run(root) { + try { + // process the contents + this._visitor.visit(root); + } catch (e) { + this.error = e; + } + + this.isFinished = true; + + this._sequencer.tryRun(); + }, + _onSequencerEmpty: function _onSequencerEmpty() { + if (!this.isFinished) { + return; + } + + this._finish(this.error); + }, + visitImport: function visitImport(importNode, visitArgs) { + var inlineCSS = importNode.options.inline; + + if (!importNode.css || inlineCSS) { + var context = new contexts.Eval(this.context, copyArray(this.context.frames)); + var importParent = context.frames[0]; + this.importCount++; + + if (importNode.isVariableImport()) { + this._sequencer.addVariableImport(this.processImportNode.bind(this, importNode, context, importParent)); + } else { + this.processImportNode(importNode, context, importParent); + } + } + + visitArgs.visitDeeper = false; + }, + processImportNode: function processImportNode(importNode, context, importParent) { + var evaldImportNode; + var inlineCSS = importNode.options.inline; + + try { + evaldImportNode = importNode.evalForImport(context); + } catch (e) { + if (!e.filename) { + e.index = importNode.getIndex(); + e.filename = importNode.fileInfo().filename; + } // attempt to eval properly and treat as css + + + importNode.css = true; // if that fails, this error will be thrown + + importNode.error = e; + } + + if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) { + if (evaldImportNode.options.multiple) { + context.importMultiple = true; + } // try appending if we haven't determined if it is css or not + + + var tryAppendLessExtension = evaldImportNode.css === undefined; + + for (var i = 0; i < importParent.rules.length; i++) { + if (importParent.rules[i] === importNode) { + importParent.rules[i] = evaldImportNode; + break; + } + } + + var onImported = this.onImported.bind(this, evaldImportNode, context); + + var sequencedOnImported = this._sequencer.addImport(onImported); + + this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.fileInfo(), evaldImportNode.options, sequencedOnImported); + } else { + this.importCount--; + + if (this.isFinished) { + this._sequencer.tryRun(); + } + } + }, + onImported: function onImported(importNode, context, e, root, importedAtRoot, fullPath) { + if (e) { + if (!e.filename) { + e.index = importNode.getIndex(); + e.filename = importNode.fileInfo().filename; + } + + this.error = e; + } + + var importVisitor = this; + var inlineCSS = importNode.options.inline; + var isPlugin = importNode.options.isPlugin; + var isOptional = importNode.options.optional; + var duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector; + + if (!context.importMultiple) { + if (duplicateImport) { + importNode.skip = true; + } else { + importNode.skip = function () { + if (fullPath in importVisitor.onceFileDetectionMap) { + return true; + } + + importVisitor.onceFileDetectionMap[fullPath] = true; + return false; + }; + } + } + + if (!fullPath && isOptional) { + importNode.skip = true; + } + + if (root) { + importNode.root = root; + importNode.importedFilename = fullPath; + + if (!inlineCSS && !isPlugin && (context.importMultiple || !duplicateImport)) { + importVisitor.recursionDetector[fullPath] = true; + var oldContext = this.context; + this.context = context; + + try { + this._visitor.visit(root); + } catch (e) { + this.error = e; + } + + this.context = oldContext; + } + } + + importVisitor.importCount--; + + if (importVisitor.isFinished) { + importVisitor._sequencer.tryRun(); + } + }, + visitDeclaration: function visitDeclaration(declNode, visitArgs) { + if (declNode.value.type === 'DetachedRuleset') { + this.context.frames.unshift(declNode); + } else { + visitArgs.visitDeeper = false; + } + }, + visitDeclarationOut: function visitDeclarationOut(declNode) { + if (declNode.value.type === 'DetachedRuleset') { + this.context.frames.shift(); + } + }, + visitAtRule: function visitAtRule(atRuleNode, visitArgs) { + this.context.frames.unshift(atRuleNode); + }, + visitAtRuleOut: function visitAtRuleOut(atRuleNode) { + this.context.frames.shift(); + }, + visitMixinDefinition: function visitMixinDefinition(mixinDefinitionNode, visitArgs) { + this.context.frames.unshift(mixinDefinitionNode); + }, + visitMixinDefinitionOut: function visitMixinDefinitionOut(mixinDefinitionNode) { + this.context.frames.shift(); + }, + visitRuleset: function visitRuleset(rulesetNode, visitArgs) { + this.context.frames.unshift(rulesetNode); + }, + visitRulesetOut: function visitRulesetOut(rulesetNode) { + this.context.frames.shift(); + }, + visitMedia: function visitMedia(mediaNode, visitArgs) { + this.context.frames.unshift(mediaNode.rules[0]); }, - visitMedia: function (mediaNode, visitArgs) { - mediaNode.allExtends = []; - this.allExtendsStack.push(mediaNode.allExtends); - }, - visitMediaOut: function (mediaNode) { - this.allExtendsStack.length = this.allExtendsStack.length - 1; - }, - visitAtRule: function (atRuleNode, visitArgs) { + visitMediaOut: function visitMediaOut(mediaNode) { + this.context.frames.shift(); + } + }; + + var SetTreeVisibilityVisitor = + /*#__PURE__*/ + function () { + function SetTreeVisibilityVisitor(visible) { + _classCallCheck(this, SetTreeVisibilityVisitor); + + this.visible = visible; + } + + _createClass(SetTreeVisibilityVisitor, [{ + key: "run", + value: function run(root) { + this.visit(root); + } + }, { + key: "visitArray", + value: function visitArray(nodes) { + if (!nodes) { + return nodes; + } + + var cnt = nodes.length; + var i; + + for (i = 0; i < cnt; i++) { + this.visit(nodes[i]); + } + + return nodes; + } + }, { + key: "visit", + value: function visit(node) { + if (!node) { + return node; + } + + if (node.constructor === Array) { + return this.visitArray(node); + } + + if (!node.blocksVisibility || node.blocksVisibility()) { + return node; + } + + if (this.visible) { + node.ensureVisibility(); + } else { + node.ensureInvisibility(); + } + + node.accept(this); + return node; + } + }]); + + return SetTreeVisibilityVisitor; + }(); + + /* jshint loopfunc:true */ + + var ExtendFinderVisitor = + /*#__PURE__*/ + function () { + function ExtendFinderVisitor() { + _classCallCheck(this, ExtendFinderVisitor); + + this._visitor = new Visitor(this); + this.contexts = []; + this.allExtendsStack = [[]]; + } + + _createClass(ExtendFinderVisitor, [{ + key: "run", + value: function run(root) { + root = this._visitor.visit(root); + root.allExtends = this.allExtendsStack[0]; + return root; + } + }, { + key: "visitDeclaration", + value: function visitDeclaration(declNode, visitArgs) { + visitArgs.visitDeeper = false; + } + }, { + key: "visitMixinDefinition", + value: function visitMixinDefinition(mixinDefinitionNode, visitArgs) { + visitArgs.visitDeeper = false; + } + }, { + key: "visitRuleset", + value: function visitRuleset(rulesetNode, visitArgs) { + if (rulesetNode.root) { + return; + } + + var i; + var j; + var extend; + var allSelectorsExtendList = []; + var extendList; // get &:extend(.a); rules which apply to all selectors in this ruleset + + var rules = rulesetNode.rules; + var ruleCnt = rules ? rules.length : 0; + + for (i = 0; i < ruleCnt; i++) { + if (rulesetNode.rules[i] instanceof tree.Extend) { + allSelectorsExtendList.push(rules[i]); + rulesetNode.extendOnEveryPath = true; + } + } // now find every selector and apply the extends that apply to all extends + // and the ones which apply to an individual extend + + + var paths = rulesetNode.paths; + + for (i = 0; i < paths.length; i++) { + var selectorPath = paths[i]; + var selector = selectorPath[selectorPath.length - 1]; + var selExtendList = selector.extendList; + extendList = selExtendList ? copyArray(selExtendList).concat(allSelectorsExtendList) : allSelectorsExtendList; + + if (extendList) { + extendList = extendList.map(function (allSelectorsExtend) { + return allSelectorsExtend.clone(); + }); + } + + for (j = 0; j < extendList.length; j++) { + this.foundExtends = true; + extend = extendList[j]; + extend.findSelfSelectors(selectorPath); + extend.ruleset = rulesetNode; + + if (j === 0) { + extend.firstExtendOnThisSelectorPath = true; + } + + this.allExtendsStack[this.allExtendsStack.length - 1].push(extend); + } + } + + this.contexts.push(rulesetNode.selectors); + } + }, { + key: "visitRulesetOut", + value: function visitRulesetOut(rulesetNode) { + if (!rulesetNode.root) { + this.contexts.length = this.contexts.length - 1; + } + } + }, { + key: "visitMedia", + value: function visitMedia(mediaNode, visitArgs) { + mediaNode.allExtends = []; + this.allExtendsStack.push(mediaNode.allExtends); + } + }, { + key: "visitMediaOut", + value: function visitMediaOut(mediaNode) { + this.allExtendsStack.length = this.allExtendsStack.length - 1; + } + }, { + key: "visitAtRule", + value: function visitAtRule(atRuleNode, visitArgs) { atRuleNode.allExtends = []; this.allExtendsStack.push(atRuleNode.allExtends); - }, - visitAtRuleOut: function (atRuleNode) { + } + }, { + key: "visitAtRuleOut", + value: function visitAtRuleOut(atRuleNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; - } -}; + } + }]); -var ProcessExtendsVisitor = function() { - this._visitor = new Visitor(this); -}; + return ExtendFinderVisitor; + }(); -ProcessExtendsVisitor.prototype = { - run: function(root) { + var ProcessExtendsVisitor = + /*#__PURE__*/ + function () { + function ProcessExtendsVisitor() { + _classCallCheck(this, ProcessExtendsVisitor); + + this._visitor = new Visitor(this); + } + + _createClass(ProcessExtendsVisitor, [{ + key: "run", + value: function run(root) { var extendFinder = new ExtendFinderVisitor(); this.extendIndices = {}; extendFinder.run(root); - if (!extendFinder.foundExtends) { return root; } + + if (!extendFinder.foundExtends) { + return root; + } + root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends)); this.allExtendsStack = [root.allExtends]; + var newRoot = this._visitor.visit(root); + this.checkExtendsForNonMatched(root.allExtends); return newRoot; - }, - checkExtendsForNonMatched: function(extendList) { + } + }, { + key: "checkExtendsForNonMatched", + value: function checkExtendsForNonMatched(extendList) { var indices = this.extendIndices; - extendList.filter(function(extend) { - return !extend.hasFoundMatches && extend.parent_ids.length == 1; - }).forEach(function(extend) { - var selector = '_unknown_'; - try { - selector = extend.selector.toCSS({}); - } - catch (_) {} - - if (!indices[extend.index + ' ' + selector]) { - indices[extend.index + ' ' + selector] = true; - logger.warn('extend \'' + selector + '\' has no matches'); - } + extendList.filter(function (extend) { + return !extend.hasFoundMatches && extend.parent_ids.length == 1; + }).forEach(function (extend) { + var selector = '_unknown_'; + + try { + selector = extend.selector.toCSS({}); + } catch (_) {} + + if (!indices["".concat(extend.index, " ").concat(selector)]) { + indices["".concat(extend.index, " ").concat(selector)] = true; + logger.warn("extend '".concat(selector, "' has no matches")); + } }); - }, - doExtendChaining: function (extendsList, extendsListTarget, iterationCount) { + } + }, { + key: "doExtendChaining", + value: function doExtendChaining(extendsList, extendsListTarget, iterationCount) { // // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering // and pasting the selector we would do normally, but we are also adding an extend with the same target selector @@ -10849,2108 +7426,6902 @@ ProcessExtendsVisitor.prototype = { // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already // processed if we look at each selector at a time, as is done in visitRuleset - - var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, - extend, targetExtend, newExtend; - - iterationCount = iterationCount || 0; - - // loop through comparing every extend with every target extend. + var extendIndex; + var targetExtendIndex; + var matches; + var extendsToAdd = []; + var newSelector; + var extendVisitor = this; + var selectorPath; + var extend; + var targetExtend; + var newExtend; + iterationCount = iterationCount || 0; // loop through comparing every extend with every target extend. // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one // and the second is the target. // the separation into two lists allows us to process a subset of chains with a bigger set, as is the // case when processing media queries + for (extendIndex = 0; extendIndex < extendsList.length; extendIndex++) { - for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) { + for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) { + extend = extendsList[extendIndex]; + targetExtend = extendsListTarget[targetExtendIndex]; // look for circular references - extend = extendsList[extendIndex]; - targetExtend = extendsListTarget[targetExtendIndex]; + if (extend.parent_ids.indexOf(targetExtend.object_id) >= 0) { + continue; + } // find a match in the target extends self selector (the bit before :extend) - // look for circular references - if ( extend.parent_ids.indexOf( targetExtend.object_id ) >= 0 ) { continue; } - // find a match in the target extends self selector (the bit before :extend) - selectorPath = [targetExtend.selfSelectors[0]]; - matches = extendVisitor.findMatch(extend, selectorPath); + selectorPath = [targetExtend.selfSelectors[0]]; + matches = extendVisitor.findMatch(extend, selectorPath); - if (matches.length) { - extend.hasFoundMatches = true; + if (matches.length) { + extend.hasFoundMatches = true; // we found a match, so for each self selector.. - // we found a match, so for each self selector.. - extend.selfSelectors.forEach(function(selfSelector) { - var info = targetExtend.visibilityInfo(); + extend.selfSelectors.forEach(function (selfSelector) { + var info = targetExtend.visibilityInfo(); // process the extend as usual - // process the extend as usual - newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector, extend.isVisible()); + newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector, extend.isVisible()); // but now we create a new extend from it - // but now we create a new extend from it - newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0, targetExtend.fileInfo(), info); - newExtend.selfSelectors = newSelector; + newExtend = new tree.Extend(targetExtend.selector, targetExtend.option, 0, targetExtend.fileInfo(), info); + newExtend.selfSelectors = newSelector; // add the extend onto the list of extends for that selector - // add the extend onto the list of extends for that selector - newSelector[newSelector.length - 1].extendList = [newExtend]; + newSelector[newSelector.length - 1].extendList = [newExtend]; // record that we need to add it. - // record that we need to add it. - extendsToAdd.push(newExtend); - newExtend.ruleset = targetExtend.ruleset; + extendsToAdd.push(newExtend); + newExtend.ruleset = targetExtend.ruleset; // remember its parents for circular references - // remember its parents for circular references - newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids); + newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids); // only process the selector once.. if we have :extend(.a,.b) then multiple + // extends will look at the same selector path, so when extending + // we know that any others will be duplicates in terms of what is added to the css - // only process the selector once.. if we have :extend(.a,.b) then multiple - // extends will look at the same selector path, so when extending - // we know that any others will be duplicates in terms of what is added to the css - if (targetExtend.firstExtendOnThisSelectorPath) { - newExtend.firstExtendOnThisSelectorPath = true; - targetExtend.ruleset.paths.push(newSelector); - } - }); + if (targetExtend.firstExtendOnThisSelectorPath) { + newExtend.firstExtendOnThisSelectorPath = true; + targetExtend.ruleset.paths.push(newSelector); } + }); } + } } if (extendsToAdd.length) { - // try to detect circular references to stop a stack overflow. - // may no longer be needed. - this.extendChainCount++; - if (iterationCount > 100) { - var selectorOne = '{unable to calculate}'; - var selectorTwo = '{unable to calculate}'; - try { - selectorOne = extendsToAdd[0].selfSelectors[0].toCSS(); - selectorTwo = extendsToAdd[0].selector.toCSS(); - } - catch (e) {} - throw { message: 'extend circular reference detected. One of the circular extends is currently:' + - selectorOne + ':extend(' + selectorTwo + ')'}; - } + // try to detect circular references to stop a stack overflow. + // may no longer be needed. + this.extendChainCount++; + + if (iterationCount > 100) { + var selectorOne = '{unable to calculate}'; + var selectorTwo = '{unable to calculate}'; + + try { + selectorOne = extendsToAdd[0].selfSelectors[0].toCSS(); + selectorTwo = extendsToAdd[0].selector.toCSS(); + } catch (e) {} + + throw { + message: "extend circular reference detected. One of the circular extends is currently:".concat(selectorOne, ":extend(").concat(selectorTwo, ")") + }; + } // now process the new extends on the existing rules so that we can handle a extending b extending c extending + // d extending e... + - // now process the new extends on the existing rules so that we can handle a extending b extending c extending - // d extending e... - return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1)); + return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1)); } else { - return extendsToAdd; + return extendsToAdd; } - }, - visitDeclaration: function (ruleNode, visitArgs) { + } + }, { + key: "visitDeclaration", + value: function visitDeclaration(ruleNode, visitArgs) { visitArgs.visitDeeper = false; - }, - visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { + } + }, { + key: "visitMixinDefinition", + value: function visitMixinDefinition(mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; - }, - visitSelector: function (selectorNode, visitArgs) { + } + }, { + key: "visitSelector", + value: function visitSelector(selectorNode, visitArgs) { visitArgs.visitDeeper = false; - }, - visitRuleset: function (rulesetNode, visitArgs) { + } + }, { + key: "visitRuleset", + value: function visitRuleset(rulesetNode, visitArgs) { if (rulesetNode.root) { - return; + return; } - var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length - 1], - selectorsToAdd = [], extendVisitor = this, selectorPath; - // look at each selector path in the ruleset, find any extend matches and then copy, find and replace + var matches; + var pathIndex; + var extendIndex; + var allExtends = this.allExtendsStack[this.allExtendsStack.length - 1]; + var selectorsToAdd = []; + var extendVisitor = this; + var selectorPath; // look at each selector path in the ruleset, find any extend matches and then copy, find and replace for (extendIndex = 0; extendIndex < allExtends.length; extendIndex++) { - for (pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) { - selectorPath = rulesetNode.paths[pathIndex]; + for (pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) { + selectorPath = rulesetNode.paths[pathIndex]; // extending extends happens initially, before the main pass + + if (rulesetNode.extendOnEveryPath) { + continue; + } - // extending extends happens initially, before the main pass - if (rulesetNode.extendOnEveryPath) { continue; } - var extendList = selectorPath[selectorPath.length - 1].extendList; - if (extendList && extendList.length) { continue; } + var extendList = selectorPath[selectorPath.length - 1].extendList; - matches = this.findMatch(allExtends[extendIndex], selectorPath); + if (extendList && extendList.length) { + continue; + } - if (matches.length) { - allExtends[extendIndex].hasFoundMatches = true; + matches = this.findMatch(allExtends[extendIndex], selectorPath); - allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) { - var extendedSelectors; - extendedSelectors = extendVisitor.extendSelector(matches, selectorPath, selfSelector, allExtends[extendIndex].isVisible()); - selectorsToAdd.push(extendedSelectors); - }); - } + if (matches.length) { + allExtends[extendIndex].hasFoundMatches = true; + allExtends[extendIndex].selfSelectors.forEach(function (selfSelector) { + var extendedSelectors; + extendedSelectors = extendVisitor.extendSelector(matches, selectorPath, selfSelector, allExtends[extendIndex].isVisible()); + selectorsToAdd.push(extendedSelectors); + }); } + } } + rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd); - }, - findMatch: function (extend, haystackSelectorPath) { + } + }, { + key: "findMatch", + value: function findMatch(extend, haystackSelectorPath) { // // look through the haystack selector path to try and find the needle - extend.selector // returns an array of selector matches that can then be replaced // - var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement, - targetCombinator, i, - extendVisitor = this, - needleElements = extend.selector.elements, - potentialMatches = [], potentialMatch, matches = []; + var haystackSelectorIndex; + var hackstackSelector; + var hackstackElementIndex; + var haystackElement; + var targetCombinator; + var i; + var extendVisitor = this; + var needleElements = extend.selector.elements; + var potentialMatches = []; + var potentialMatch; + var matches = []; // loop through the haystack elements - // loop through the haystack elements for (haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) { - hackstackSelector = haystackSelectorPath[haystackSelectorIndex]; + hackstackSelector = haystackSelectorPath[haystackSelectorIndex]; + + for (hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) { + haystackElement = hackstackSelector.elements[hackstackElementIndex]; // if we allow elements before our match we can add a potential match every time. otherwise only at the first element. + + if (extend.allowBefore || haystackSelectorIndex === 0 && hackstackElementIndex === 0) { + potentialMatches.push({ + pathIndex: haystackSelectorIndex, + index: hackstackElementIndex, + matched: 0, + initialCombinator: haystackElement.combinator + }); + } + + for (i = 0; i < potentialMatches.length; i++) { + potentialMatch = potentialMatches[i]; // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't + // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to + // work out what the resulting combinator will be + + targetCombinator = haystackElement.combinator.value; - for (hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) { + if (targetCombinator === '' && hackstackElementIndex === 0) { + targetCombinator = ' '; + } // if we don't match, null our match to indicate failure - haystackElement = hackstackSelector.elements[hackstackElementIndex]; - // if we allow elements before our match we can add a potential match every time. otherwise only at the first element. - if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) { - potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, - initialCombinator: haystackElement.combinator}); + if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) || potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator) { + potentialMatch = null; + } else { + potentialMatch.matched++; + } // if we are still valid and have finished, test whether we have elements after and whether these are allowed + + + if (potentialMatch) { + potentialMatch.finished = potentialMatch.matched === needleElements.length; + + if (potentialMatch.finished && !extend.allowAfter && (hackstackElementIndex + 1 < hackstackSelector.elements.length || haystackSelectorIndex + 1 < haystackSelectorPath.length)) { + potentialMatch = null; } + } // if null we remove, if not, we are still valid, so either push as a valid match or continue - for (i = 0; i < potentialMatches.length; i++) { - potentialMatch = potentialMatches[i]; - // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't - // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to - // work out what the resulting combinator will be - targetCombinator = haystackElement.combinator.value; - if (targetCombinator === '' && hackstackElementIndex === 0) { - targetCombinator = ' '; - } + if (potentialMatch) { + if (potentialMatch.finished) { + potentialMatch.length = needleElements.length; + potentialMatch.endPathIndex = haystackSelectorIndex; + potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match - // if we don't match, null our match to indicate failure - if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) || - (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) { - potentialMatch = null; - } else { - potentialMatch.matched++; - } + potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again - // if we are still valid and have finished, test whether we have elements after and whether these are allowed - if (potentialMatch) { - potentialMatch.finished = potentialMatch.matched === needleElements.length; - if (potentialMatch.finished && - (!extend.allowAfter && - (hackstackElementIndex + 1 < hackstackSelector.elements.length || haystackSelectorIndex + 1 < haystackSelectorPath.length))) { - potentialMatch = null; - } - } - // if null we remove, if not, we are still valid, so either push as a valid match or continue - if (potentialMatch) { - if (potentialMatch.finished) { - potentialMatch.length = needleElements.length; - potentialMatch.endPathIndex = haystackSelectorIndex; - potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match - potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again - matches.push(potentialMatch); - } - } else { - potentialMatches.splice(i, 1); - i--; - } + matches.push(potentialMatch); } + } else { + potentialMatches.splice(i, 1); + i--; + } } + } } + return matches; - }, - isElementValuesEqual: function(elementValue1, elementValue2) { + } + }, { + key: "isElementValuesEqual", + value: function isElementValuesEqual(elementValue1, elementValue2) { if (typeof elementValue1 === 'string' || typeof elementValue2 === 'string') { - return elementValue1 === elementValue2; + return elementValue1 === elementValue2; } + if (elementValue1 instanceof tree.Attribute) { - if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) { - return false; - } - if (!elementValue1.value || !elementValue2.value) { - if (elementValue1.value || elementValue2.value) { - return false; - } - return true; + if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) { + return false; + } + + if (!elementValue1.value || !elementValue2.value) { + if (elementValue1.value || elementValue2.value) { + return false; } - elementValue1 = elementValue1.value.value || elementValue1.value; - elementValue2 = elementValue2.value.value || elementValue2.value; - return elementValue1 === elementValue2; + + return true; + } + + elementValue1 = elementValue1.value.value || elementValue1.value; + elementValue2 = elementValue2.value.value || elementValue2.value; + return elementValue1 === elementValue2; } + elementValue1 = elementValue1.value; elementValue2 = elementValue2.value; + if (elementValue1 instanceof tree.Selector) { - if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) { + if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) { + return false; + } + + for (var i = 0; i < elementValue1.elements.length; i++) { + if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) { + if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) { return false; + } } - for (var i = 0; i < elementValue1.elements.length; i++) { - if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) { - if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) { - return false; - } - } - if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) { - return false; - } + + if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) { + return false; } - return true; + } + + return true; } - return false; - }, - extendSelector:function (matches, selectorPath, replacementSelector, isVisible) { + return false; + } + }, { + key: "extendSelector", + value: function extendSelector(matches, selectorPath, replacementSelector, isVisible) { // for a set of matches, replace each match with the replacement selector - - var currentSelectorPathIndex = 0, - currentSelectorPathElementIndex = 0, - path = [], - matchIndex, - selector, - firstElement, - match, - newElements; + var currentSelectorPathIndex = 0; + var currentSelectorPathElementIndex = 0; + var path = []; + var matchIndex; + var selector; + var firstElement; + var match; + var newElements; for (matchIndex = 0; matchIndex < matches.length; matchIndex++) { - match = matches[matchIndex]; - selector = selectorPath[match.pathIndex]; - firstElement = new tree.Element( - match.initialCombinator, - replacementSelector.elements[0].value, - replacementSelector.elements[0].isVariable, - replacementSelector.elements[0].getIndex(), - replacementSelector.elements[0].fileInfo() - ); - - if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) { - path[path.length - 1].elements = path[path.length - 1] - .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); - currentSelectorPathElementIndex = 0; - currentSelectorPathIndex++; - } - - newElements = selector.elements - .slice(currentSelectorPathElementIndex, match.index) - .concat([firstElement]) - .concat(replacementSelector.elements.slice(1)); - - if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) { - path[path.length - 1].elements = - path[path.length - 1].elements.concat(newElements); - } else { - path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex)); + match = matches[matchIndex]; + selector = selectorPath[match.pathIndex]; + firstElement = new tree.Element(match.initialCombinator, replacementSelector.elements[0].value, replacementSelector.elements[0].isVariable, replacementSelector.elements[0].getIndex(), replacementSelector.elements[0].fileInfo()); - path.push(new tree.Selector( - newElements - )); - } - currentSelectorPathIndex = match.endPathIndex; - currentSelectorPathElementIndex = match.endPathElementIndex; - if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) { - currentSelectorPathElementIndex = 0; - currentSelectorPathIndex++; - } + if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) { + path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); + currentSelectorPathElementIndex = 0; + currentSelectorPathIndex++; + } + + newElements = selector.elements.slice(currentSelectorPathElementIndex, match.index).concat([firstElement]).concat(replacementSelector.elements.slice(1)); + + if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) { + path[path.length - 1].elements = path[path.length - 1].elements.concat(newElements); + } else { + path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex)); + path.push(new tree.Selector(newElements)); + } + + currentSelectorPathIndex = match.endPathIndex; + currentSelectorPathElementIndex = match.endPathElementIndex; + + if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) { + currentSelectorPathElementIndex = 0; + currentSelectorPathIndex++; + } } if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) { - path[path.length - 1].elements = path[path.length - 1] - .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); - currentSelectorPathIndex++; + path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); + currentSelectorPathIndex++; } path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length)); path = path.map(function (currentValue) { - // we can re-use elements here, because the visibility property matters only for selectors - var derived = currentValue.createDerived(currentValue.elements); - if (isVisible) { - derived.ensureVisibility(); - } else { - derived.ensureInvisibility(); - } - return derived; + // we can re-use elements here, because the visibility property matters only for selectors + var derived = currentValue.createDerived(currentValue.elements); + + if (isVisible) { + derived.ensureVisibility(); + } else { + derived.ensureInvisibility(); + } + + return derived; }); return path; - }, - visitMedia: function (mediaNode, visitArgs) { + } + }, { + key: "visitMedia", + value: function visitMedia(mediaNode, visitArgs) { var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends)); this.allExtendsStack.push(newAllExtends); - }, - visitMediaOut: function (mediaNode) { + } + }, { + key: "visitMediaOut", + value: function visitMediaOut(mediaNode) { var lastIndex = this.allExtendsStack.length - 1; this.allExtendsStack.length = lastIndex; - }, - visitAtRule: function (atRuleNode, visitArgs) { + } + }, { + key: "visitAtRule", + value: function visitAtRule(atRuleNode, visitArgs) { var newAllExtends = atRuleNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, atRuleNode.allExtends)); this.allExtendsStack.push(newAllExtends); - }, - visitAtRuleOut: function (atRuleNode) { + } + }, { + key: "visitAtRuleOut", + value: function visitAtRuleOut(atRuleNode) { var lastIndex = this.allExtendsStack.length - 1; this.allExtendsStack.length = lastIndex; - } -}; + } + }]); -module.exports = ProcessExtendsVisitor; + return ProcessExtendsVisitor; + }(); -},{"../logger":39,"../tree":67,"../utils":89,"./visitor":97}],91:[function(require,module,exports){ -function ImportSequencer(onSequencerEmpty) { - this.imports = []; - this.variableImports = []; - this._onSequencerEmpty = onSequencerEmpty; - this._currentDepth = 0; -} + var JoinSelectorVisitor = + /*#__PURE__*/ + function () { + function JoinSelectorVisitor() { + _classCallCheck(this, JoinSelectorVisitor); -ImportSequencer.prototype.addImport = function(callback) { - var importSequencer = this, - importItem = { - callback: callback, - args: null, - isReady: false - }; - this.imports.push(importItem); - return function() { - importItem.args = Array.prototype.slice.call(arguments, 0); - importItem.isReady = true; - importSequencer.tryRun(); - }; -}; + this.contexts = [[]]; + this._visitor = new Visitor(this); + } + + _createClass(JoinSelectorVisitor, [{ + key: "run", + value: function run(root) { + return this._visitor.visit(root); + } + }, { + key: "visitDeclaration", + value: function visitDeclaration(declNode, visitArgs) { + visitArgs.visitDeeper = false; + } + }, { + key: "visitMixinDefinition", + value: function visitMixinDefinition(mixinDefinitionNode, visitArgs) { + visitArgs.visitDeeper = false; + } + }, { + key: "visitRuleset", + value: function visitRuleset(rulesetNode, visitArgs) { + var context = this.contexts[this.contexts.length - 1]; + var paths = []; + var selectors; + this.contexts.push(paths); -ImportSequencer.prototype.addVariableImport = function(callback) { - this.variableImports.push(callback); -}; + if (!rulesetNode.root) { + selectors = rulesetNode.selectors; -ImportSequencer.prototype.tryRun = function() { - this._currentDepth++; - try { - while (true) { - while (this.imports.length > 0) { - var importItem = this.imports[0]; - if (!importItem.isReady) { - return; - } - this.imports = this.imports.slice(1); - importItem.callback.apply(null, importItem.args); - } - if (this.variableImports.length === 0) { - break; + if (selectors) { + selectors = selectors.filter(function (selector) { + return selector.getIsOutput(); + }); + rulesetNode.selectors = selectors.length ? selectors : selectors = null; + + if (selectors) { + rulesetNode.joinSelectors(paths, context, selectors); } - var variableImport = this.variableImports[0]; - this.variableImports = this.variableImports.slice(1); - variableImport(); + } + + if (!selectors) { + rulesetNode.rules = null; + } + + rulesetNode.paths = paths; } - } finally { - this._currentDepth--; - } - if (this._currentDepth === 0 && this._onSequencerEmpty) { - this._onSequencerEmpty(); - } -}; + } + }, { + key: "visitRulesetOut", + value: function visitRulesetOut(rulesetNode) { + this.contexts.length = this.contexts.length - 1; + } + }, { + key: "visitMedia", + value: function visitMedia(mediaNode, visitArgs) { + var context = this.contexts[this.contexts.length - 1]; + mediaNode.rules[0].root = context.length === 0 || context[0].multiMedia; + } + }, { + key: "visitAtRule", + value: function visitAtRule(atRuleNode, visitArgs) { + var context = this.contexts[this.contexts.length - 1]; -module.exports = ImportSequencer; + if (atRuleNode.rules && atRuleNode.rules.length) { + atRuleNode.rules[0].root = atRuleNode.isRooted || context.length === 0 || null; + } + } + }]); -},{}],92:[function(require,module,exports){ -var contexts = require('../contexts'), - Visitor = require('./visitor'), - ImportSequencer = require('./import-sequencer'), - utils = require('../utils'); + return JoinSelectorVisitor; + }(); -var ImportVisitor = function(importer, finish) { + var CSSVisitorUtils = + /*#__PURE__*/ + function () { + function CSSVisitorUtils(context) { + _classCallCheck(this, CSSVisitorUtils); - this._visitor = new Visitor(this); - this._importer = importer; - this._finish = finish; - this.context = new contexts.Eval(); - this.importCount = 0; - this.onceFileDetectionMap = {}; - this.recursionDetector = {}; - this._sequencer = new ImportSequencer(this._onSequencerEmpty.bind(this)); -}; + this._visitor = new Visitor(this); + this._context = context; + } -ImportVisitor.prototype = { - isReplacing: false, - run: function (root) { - try { - // process the contents - this._visitor.visit(root); + _createClass(CSSVisitorUtils, [{ + key: "containsSilentNonBlockedChild", + value: function containsSilentNonBlockedChild(bodyRules) { + var rule; + + if (!bodyRules) { + return false; } - catch (e) { - this.error = e; + + for (var r = 0; r < bodyRules.length; r++) { + rule = bodyRules[r]; + + if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) { + // the atrule contains something that was referenced (likely by extend) + // therefore it needs to be shown in output too + return true; + } } - this.isFinished = true; - this._sequencer.tryRun(); - }, - _onSequencerEmpty: function() { - if (!this.isFinished) { + return false; + } + }, { + key: "keepOnlyVisibleChilds", + value: function keepOnlyVisibleChilds(owner) { + if (owner && owner.rules) { + owner.rules = owner.rules.filter(function (thing) { + return thing.isVisible(); + }); + } + } + }, { + key: "isEmpty", + value: function isEmpty(owner) { + return owner && owner.rules ? owner.rules.length === 0 : true; + } + }, { + key: "hasVisibleSelector", + value: function hasVisibleSelector(rulesetNode) { + return rulesetNode && rulesetNode.paths ? rulesetNode.paths.length > 0 : false; + } + }, { + key: "resolveVisibility", + value: function resolveVisibility(node, originalRules) { + if (!node.blocksVisibility()) { + if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) { return; + } + + return node; } - this._finish(this.error); - }, - visitImport: function (importNode, visitArgs) { - var inlineCSS = importNode.options.inline; - if (!importNode.css || inlineCSS) { + var compiledRulesBody = node.rules[0]; + this.keepOnlyVisibleChilds(compiledRulesBody); - var context = new contexts.Eval(this.context, utils.copyArray(this.context.frames)); - var importParent = context.frames[0]; + if (this.isEmpty(compiledRulesBody)) { + return; + } - this.importCount++; - if (importNode.isVariableImport()) { - this._sequencer.addVariableImport(this.processImportNode.bind(this, importNode, context, importParent)); - } else { - this.processImportNode(importNode, context, importParent); - } + node.ensureVisibility(); + node.removeVisibilityBlock(); + return node; + } + }, { + key: "isVisibleRuleset", + value: function isVisibleRuleset(rulesetNode) { + if (rulesetNode.firstRoot) { + return true; } - visitArgs.visitDeeper = false; - }, - processImportNode: function(importNode, context, importParent) { - var evaldImportNode, - inlineCSS = importNode.options.inline; - try { - evaldImportNode = importNode.evalForImport(context); - } catch (e) { - if (!e.filename) { e.index = importNode.getIndex(); e.filename = importNode.fileInfo().filename; } - // attempt to eval properly and treat as css - importNode.css = true; - // if that fails, this error will be thrown - importNode.error = e; + if (this.isEmpty(rulesetNode)) { + return false; } - if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) { + if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) { + return false; + } - if (evaldImportNode.options.multiple) { - context.importMultiple = true; - } + return true; + } + }]); - // try appending if we haven't determined if it is css or not - var tryAppendLessExtension = evaldImportNode.css === undefined; + return CSSVisitorUtils; + }(); - for (var i = 0; i < importParent.rules.length; i++) { - if (importParent.rules[i] === importNode) { - importParent.rules[i] = evaldImportNode; - break; - } - } + var ToCSSVisitor = function ToCSSVisitor(context) { + this._visitor = new Visitor(this); + this._context = context; + this.utils = new CSSVisitorUtils(context); + }; - var onImported = this.onImported.bind(this, evaldImportNode, context), - sequencedOnImported = this._sequencer.addImport(onImported); + ToCSSVisitor.prototype = { + isReplacing: true, + run: function run(root) { + return this._visitor.visit(root); + }, + visitDeclaration: function visitDeclaration(declNode, visitArgs) { + if (declNode.blocksVisibility() || declNode.variable) { + return; + } - this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.fileInfo(), - evaldImportNode.options, sequencedOnImported); - } else { - this.importCount--; - if (this.isFinished) { - this._sequencer.tryRun(); - } - } + return declNode; }, - onImported: function (importNode, context, e, root, importedAtRoot, fullPath) { - if (e) { - if (!e.filename) { - e.index = importNode.getIndex(); e.filename = importNode.fileInfo().filename; - } - this.error = e; - } + visitMixinDefinition: function visitMixinDefinition(mixinNode, visitArgs) { + // mixin definitions do not get eval'd - this means they keep state + // so we have to clear that state here so it isn't used if toCSS is called twice + mixinNode.frames = []; + }, + visitExtend: function visitExtend(extendNode, visitArgs) {}, + visitComment: function visitComment(commentNode, visitArgs) { + if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) { + return; + } - var importVisitor = this, - inlineCSS = importNode.options.inline, - isPlugin = importNode.options.isPlugin, - isOptional = importNode.options.optional, - duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector; + return commentNode; + }, + visitMedia: function visitMedia(mediaNode, visitArgs) { + var originalRules = mediaNode.rules[0].rules; + mediaNode.accept(this._visitor); + visitArgs.visitDeeper = false; + return this.utils.resolveVisibility(mediaNode, originalRules); + }, + visitImport: function visitImport(importNode, visitArgs) { + if (importNode.blocksVisibility()) { + return; + } - if (!context.importMultiple) { - if (duplicateImport) { - importNode.skip = true; - } else { - importNode.skip = function() { - if (fullPath in importVisitor.onceFileDetectionMap) { - return true; - } - importVisitor.onceFileDetectionMap[fullPath] = true; - return false; - }; - } + return importNode; + }, + visitAtRule: function visitAtRule(atRuleNode, visitArgs) { + if (atRuleNode.rules && atRuleNode.rules.length) { + return this.visitAtRuleWithBody(atRuleNode, visitArgs); + } else { + return this.visitAtRuleWithoutBody(atRuleNode, visitArgs); + } + }, + visitAnonymous: function visitAnonymous(anonymousNode, visitArgs) { + if (!anonymousNode.blocksVisibility()) { + anonymousNode.accept(this._visitor); + return anonymousNode; + } + }, + visitAtRuleWithBody: function visitAtRuleWithBody(atRuleNode, visitArgs) { + // if there is only one nested ruleset and that one has no path, then it is + // just fake ruleset + function hasFakeRuleset(atRuleNode) { + var bodyRules = atRuleNode.rules; + return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0); + } + + function getBodyRules(atRuleNode) { + var nodeRules = atRuleNode.rules; + + if (hasFakeRuleset(atRuleNode)) { + return nodeRules[0].rules; } - if (!fullPath && isOptional) { - importNode.skip = true; + return nodeRules; + } // it is still true that it is only one ruleset in array + // this is last such moment + // process childs + + + var originalRules = getBodyRules(atRuleNode); + atRuleNode.accept(this._visitor); + visitArgs.visitDeeper = false; + + if (!this.utils.isEmpty(atRuleNode)) { + this._mergeRules(atRuleNode.rules[0].rules); + } + + return this.utils.resolveVisibility(atRuleNode, originalRules); + }, + visitAtRuleWithoutBody: function visitAtRuleWithoutBody(atRuleNode, visitArgs) { + if (atRuleNode.blocksVisibility()) { + return; + } + + if (atRuleNode.name === '@charset') { + // Only output the debug info together with subsequent @charset definitions + // a comment (or @media statement) before the actual @charset atrule would + // be considered illegal css as it has to be on the first line + if (this.charset) { + if (atRuleNode.debugInfo) { + var comment = new tree.Comment("/* ".concat(atRuleNode.toCSS(this._context).replace(/\n/g, ''), " */\n")); + comment.debugInfo = atRuleNode.debugInfo; + return this._visitor.visit(comment); + } + + return; } - if (root) { - importNode.root = root; - importNode.importedFilename = fullPath; + this.charset = true; + } + + return atRuleNode; + }, + checkValidNodes: function checkValidNodes(rules, isRoot) { + if (!rules) { + return; + } - if (!inlineCSS && !isPlugin && (context.importMultiple || !duplicateImport)) { - importVisitor.recursionDetector[fullPath] = true; + for (var i = 0; i < rules.length; i++) { + var ruleNode = rules[i]; - var oldContext = this.context; - this.context = context; - try { - this._visitor.visit(root); - } catch (e) { - this.error = e; - } - this.context = oldContext; - } + if (isRoot && ruleNode instanceof tree.Declaration && !ruleNode.variable) { + throw { + message: 'Properties must be inside selector blocks. They cannot be in the root', + index: ruleNode.getIndex(), + filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename + }; } - importVisitor.importCount--; + if (ruleNode instanceof tree.Call) { + throw { + message: "Function '".concat(ruleNode.name, "' is undefined"), + index: ruleNode.getIndex(), + filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename + }; + } - if (importVisitor.isFinished) { - importVisitor._sequencer.tryRun(); + if (ruleNode.type && !ruleNode.allowRoot) { + throw { + message: "".concat(ruleNode.type, " node returned by a function is not valid here"), + index: ruleNode.getIndex(), + filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename + }; } + } }, - visitDeclaration: function (declNode, visitArgs) { - if (declNode.value.type === 'DetachedRuleset') { - this.context.frames.unshift(declNode); + visitRuleset: function visitRuleset(rulesetNode, visitArgs) { + // at this point rulesets are nested into each other + var rule; + var rulesets = []; + this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot); + + if (!rulesetNode.root) { + // remove invisible paths + this._compileRulesetPaths(rulesetNode); // remove rulesets from this ruleset body and compile them separately + + + var nodeRules = rulesetNode.rules; + var nodeRuleCnt = nodeRules ? nodeRules.length : 0; + + for (var i = 0; i < nodeRuleCnt;) { + rule = nodeRules[i]; + + if (rule && rule.rules) { + // visit because we are moving them out from being a child + rulesets.push(this._visitor.visit(rule)); + nodeRules.splice(i, 1); + nodeRuleCnt--; + continue; + } + + i++; + } // accept the visitor to remove rules and refactor itself + // then we can decide nogw whether we want it or not + // compile body + + + if (nodeRuleCnt > 0) { + rulesetNode.accept(this._visitor); } else { - visitArgs.visitDeeper = false; - } - }, - visitDeclarationOut: function(declNode) { - if (declNode.value.type === 'DetachedRuleset') { - this.context.frames.shift(); + rulesetNode.rules = null; } + + visitArgs.visitDeeper = false; + } else { + // if (! rulesetNode.root) { + rulesetNode.accept(this._visitor); + visitArgs.visitDeeper = false; + } + + if (rulesetNode.rules) { + this._mergeRules(rulesetNode.rules); + + this._removeDuplicateRules(rulesetNode.rules); + } // now decide whether we keep the ruleset + + + if (this.utils.isVisibleRuleset(rulesetNode)) { + rulesetNode.ensureVisibility(); + rulesets.splice(0, 0, rulesetNode); + } + + if (rulesets.length === 1) { + return rulesets[0]; + } + + return rulesets; }, - visitAtRule: function (atRuleNode, visitArgs) { - this.context.frames.unshift(atRuleNode); - }, - visitAtRuleOut: function (atRuleNode) { - this.context.frames.shift(); - }, - visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { - this.context.frames.unshift(mixinDefinitionNode); - }, - visitMixinDefinitionOut: function (mixinDefinitionNode) { - this.context.frames.shift(); - }, - visitRuleset: function (rulesetNode, visitArgs) { - this.context.frames.unshift(rulesetNode); - }, - visitRulesetOut: function (rulesetNode) { - this.context.frames.shift(); + _compileRulesetPaths: function _compileRulesetPaths(rulesetNode) { + if (rulesetNode.paths) { + rulesetNode.paths = rulesetNode.paths.filter(function (p) { + var i; + + if (p[0].elements[0].combinator.value === ' ') { + p[0].elements[0].combinator = new tree.Combinator(''); + } + + for (i = 0; i < p.length; i++) { + if (p[i].isVisible() && p[i].getIsOutput()) { + return true; + } + } + + return false; + }); + } }, - visitMedia: function (mediaNode, visitArgs) { - this.context.frames.unshift(mediaNode.rules[0]); + _removeDuplicateRules: function _removeDuplicateRules(rules) { + if (!rules) { + return; + } // remove duplicates + + + var ruleCache = {}; + var ruleList; + var rule; + var i; + + for (i = rules.length - 1; i >= 0; i--) { + rule = rules[i]; + + if (rule instanceof tree.Declaration) { + if (!ruleCache[rule.name]) { + ruleCache[rule.name] = rule; + } else { + ruleList = ruleCache[rule.name]; + + if (ruleList instanceof tree.Declaration) { + ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._context)]; + } + + var ruleCSS = rule.toCSS(this._context); + + if (ruleList.indexOf(ruleCSS) !== -1) { + rules.splice(i, 1); + } else { + ruleList.push(ruleCSS); + } + } + } + } }, - visitMediaOut: function (mediaNode) { - this.context.frames.shift(); - } -}; -module.exports = ImportVisitor; + _mergeRules: function _mergeRules(rules) { + if (!rules) { + return; + } -},{"../contexts":13,"../utils":89,"./import-sequencer":91,"./visitor":97}],93:[function(require,module,exports){ -var visitors = { - Visitor: require('./visitor'), - ImportVisitor: require('./import-visitor'), - MarkVisibleSelectorsVisitor: require('./set-tree-visibility-visitor'), - ExtendVisitor: require('./extend-visitor'), - JoinSelectorVisitor: require('./join-selector-visitor'), - ToCSSVisitor: require('./to-css-visitor') -}; + var groups = {}; + var groupsArr = []; + + for (var i = 0; i < rules.length; i++) { + var rule = rules[i]; + + if (rule.merge) { + var key = rule.name; + groups[key] ? rules.splice(i--, 1) : groupsArr.push(groups[key] = []); + groups[key].push(rule); + } + } -module.exports = visitors; + groupsArr.forEach(function (group) { + if (group.length > 0) { + var result = group[0]; + var space = []; + var comma = [new tree.Expression(space)]; + group.forEach(function (rule) { + if (rule.merge === '+' && space.length > 0) { + comma.push(new tree.Expression(space = [])); + } + + space.push(rule.value); + result.important = result.important || rule.important; + }); + result.value = new tree.Value(comma); + } + }); + } + }; + + var visitors = { + Visitor: Visitor, + ImportVisitor: ImportVisitor, + MarkVisibleSelectorsVisitor: SetTreeVisibilityVisitor, + ExtendVisitor: ProcessExtendsVisitor, + JoinSelectorVisitor: JoinSelectorVisitor, + ToCSSVisitor: ToCSSVisitor + }; + + // Split the input into chunks. + var chunker = (function (input, fail) { + var len = input.length; + var level = 0; + var parenLevel = 0; + var lastOpening; + var lastOpeningParen; + var lastMultiComment; + var lastMultiCommentEndBrace; + var chunks = []; + var emitFrom = 0; + var chunkerCurrentIndex; + var currentChunkStartIndex; + var cc; + var cc2; + var matched; + + function emitChunk(force) { + var len = chunkerCurrentIndex - emitFrom; + + if (len < 512 && !force || !len) { + return; + } + + chunks.push(input.slice(emitFrom, chunkerCurrentIndex + 1)); + emitFrom = chunkerCurrentIndex + 1; + } + + for (chunkerCurrentIndex = 0; chunkerCurrentIndex < len; chunkerCurrentIndex++) { + cc = input.charCodeAt(chunkerCurrentIndex); + + if (cc >= 97 && cc <= 122 || cc < 34) { + // a-z or whitespace + continue; + } + + switch (cc) { + case 40: + // ( + parenLevel++; + lastOpeningParen = chunkerCurrentIndex; + continue; + + case 41: + // ) + if (--parenLevel < 0) { + return fail('missing opening `(`', chunkerCurrentIndex); + } + + continue; + + case 59: + // ; + if (!parenLevel) { + emitChunk(); + } + + continue; + + case 123: + // { + level++; + lastOpening = chunkerCurrentIndex; + continue; + + case 125: + // } + if (--level < 0) { + return fail('missing opening `{`', chunkerCurrentIndex); + } + + if (!level && !parenLevel) { + emitChunk(); + } + + continue; + + case 92: + // \ + if (chunkerCurrentIndex < len - 1) { + chunkerCurrentIndex++; + continue; + } + + return fail('unescaped `\\`', chunkerCurrentIndex); + + case 34: + case 39: + case 96: + // ", ' and ` + matched = 0; + currentChunkStartIndex = chunkerCurrentIndex; + + for (chunkerCurrentIndex = chunkerCurrentIndex + 1; chunkerCurrentIndex < len; chunkerCurrentIndex++) { + cc2 = input.charCodeAt(chunkerCurrentIndex); + + if (cc2 > 96) { + continue; + } + + if (cc2 == cc) { + matched = 1; + break; + } + + if (cc2 == 92) { + // \ + if (chunkerCurrentIndex == len - 1) { + return fail('unescaped `\\`', chunkerCurrentIndex); + } + + chunkerCurrentIndex++; + } + } + + if (matched) { + continue; + } + + return fail("unmatched `".concat(String.fromCharCode(cc), "`"), currentChunkStartIndex); + + case 47: + // /, check for comment + if (parenLevel || chunkerCurrentIndex == len - 1) { + continue; + } + + cc2 = input.charCodeAt(chunkerCurrentIndex + 1); + + if (cc2 == 47) { + // //, find lnfeed + for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len; chunkerCurrentIndex++) { + cc2 = input.charCodeAt(chunkerCurrentIndex); + + if (cc2 <= 13 && (cc2 == 10 || cc2 == 13)) { + break; + } + } + } else if (cc2 == 42) { + // /*, find */ + lastMultiComment = currentChunkStartIndex = chunkerCurrentIndex; + + for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len - 1; chunkerCurrentIndex++) { + cc2 = input.charCodeAt(chunkerCurrentIndex); + + if (cc2 == 125) { + lastMultiCommentEndBrace = chunkerCurrentIndex; + } + + if (cc2 != 42) { + continue; + } + + if (input.charCodeAt(chunkerCurrentIndex + 1) == 47) { + break; + } + } + + if (chunkerCurrentIndex == len - 1) { + return fail('missing closing `*/`', currentChunkStartIndex); + } + + chunkerCurrentIndex++; + } + + continue; + + case 42: + // *, check for unmatched */ + if (chunkerCurrentIndex < len - 1 && input.charCodeAt(chunkerCurrentIndex + 1) == 47) { + return fail('unmatched `/*`', chunkerCurrentIndex); + } + + continue; + } + } + + if (level !== 0) { + if (lastMultiComment > lastOpening && lastMultiCommentEndBrace > lastMultiComment) { + return fail('missing closing `}` or `*/`', lastOpening); + } else { + return fail('missing closing `}`', lastOpening); + } + } else if (parenLevel !== 0) { + return fail('missing closing `)`', lastOpeningParen); + } + + emitChunk(true); + return chunks; + }); + + var getParserInput = (function () { + var // Less input string + input; + var // current chunk + j; + var // holds state for backtracking + saveStack = []; + var // furthest index the parser has gone to + furthest; + var // if this is furthest we got to, this is the probably cause + furthestPossibleErrorMessage; + var // chunkified input + chunks; + var // current chunk + current; + var // index of current chunk, in `input` + currentPos; + var parserInput = {}; + var CHARCODE_SPACE = 32; + var CHARCODE_TAB = 9; + var CHARCODE_LF = 10; + var CHARCODE_CR = 13; + var CHARCODE_PLUS = 43; + var CHARCODE_COMMA = 44; + var CHARCODE_FORWARD_SLASH = 47; + var CHARCODE_9 = 57; + + function skipWhitespace(length) { + var oldi = parserInput.i; + var oldj = j; + var curr = parserInput.i - currentPos; + var endIndex = parserInput.i + current.length - curr; + var mem = parserInput.i += length; + var inp = input; + var c; + var nextChar; + var comment; + + for (; parserInput.i < endIndex; parserInput.i++) { + c = inp.charCodeAt(parserInput.i); + + if (parserInput.autoCommentAbsorb && c === CHARCODE_FORWARD_SLASH) { + nextChar = inp.charAt(parserInput.i + 1); + + if (nextChar === '/') { + comment = { + index: parserInput.i, + isLineComment: true + }; + var nextNewLine = inp.indexOf('\n', parserInput.i + 2); + + if (nextNewLine < 0) { + nextNewLine = endIndex; + } + + parserInput.i = nextNewLine; + comment.text = inp.substr(comment.index, parserInput.i - comment.index); + parserInput.commentStore.push(comment); + continue; + } else if (nextChar === '*') { + var nextStarSlash = inp.indexOf('*/', parserInput.i + 2); + + if (nextStarSlash >= 0) { + comment = { + index: parserInput.i, + text: inp.substr(parserInput.i, nextStarSlash + 2 - parserInput.i), + isLineComment: false + }; + parserInput.i += comment.text.length - 1; + parserInput.commentStore.push(comment); + continue; + } + } + + break; + } + + if (c !== CHARCODE_SPACE && c !== CHARCODE_LF && c !== CHARCODE_TAB && c !== CHARCODE_CR) { + break; + } + } + + current = current.slice(length + parserInput.i - mem + curr); + currentPos = parserInput.i; + + if (!current.length) { + if (j < chunks.length - 1) { + current = chunks[++j]; + skipWhitespace(0); // skip space at the beginning of a chunk + + return true; // things changed + } + + parserInput.finished = true; + } + + return oldi !== parserInput.i || oldj !== j; + } + + parserInput.save = function () { + currentPos = parserInput.i; + saveStack.push({ + current: current, + i: parserInput.i, + j: j + }); + }; + + parserInput.restore = function (possibleErrorMessage) { + if (parserInput.i > furthest || parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage) { + furthest = parserInput.i; + furthestPossibleErrorMessage = possibleErrorMessage; + } + + var state = saveStack.pop(); + current = state.current; + currentPos = parserInput.i = state.i; + j = state.j; + }; + + parserInput.forget = function () { + saveStack.pop(); + }; + + parserInput.isWhitespace = function (offset) { + var pos = parserInput.i + (offset || 0); + var code = input.charCodeAt(pos); + return code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF; + }; // Specialization of $(tok) + + + parserInput.$re = function (tok) { + if (parserInput.i > currentPos) { + current = current.slice(parserInput.i - currentPos); + currentPos = parserInput.i; + } + + var m = tok.exec(current); + + if (!m) { + return null; + } + + skipWhitespace(m[0].length); + + if (typeof m === 'string') { + return m; + } + + return m.length === 1 ? m[0] : m; + }; + + parserInput.$char = function (tok) { + if (input.charAt(parserInput.i) !== tok) { + return null; + } + + skipWhitespace(1); + return tok; + }; + + parserInput.$str = function (tok) { + var tokLength = tok.length; // https://jsperf.com/string-startswith/21 + + for (var i = 0; i < tokLength; i++) { + if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { + return null; + } + } + + skipWhitespace(tokLength); + return tok; + }; + + parserInput.$quoted = function (loc) { + var pos = loc || parserInput.i; + var startChar = input.charAt(pos); + + if (startChar !== '\'' && startChar !== '"') { + return; + } + + var length = input.length; + var currentPosition = pos; + + for (var i = 1; i + currentPosition < length; i++) { + var nextChar = input.charAt(i + currentPosition); + + switch (nextChar) { + case '\\': + i++; + continue; + + case '\r': + case '\n': + break; + + case startChar: + var str = input.substr(currentPosition, i + 1); + + if (!loc && loc !== 0) { + skipWhitespace(i + 1); + return str; + } + + return [startChar, str]; + + default: + } + } + + return null; + }; + /** + * Permissive parsing. Ignores everything except matching {} [] () and quotes + * until matching token (outside of blocks) + */ + + + parserInput.$parseUntil = function (tok) { + var quote = ''; + var returnVal = null; + var inComment = false; + var blockDepth = 0; + var blockStack = []; + var parseGroups = []; + var length = input.length; + var startPos = parserInput.i; + var lastPos = parserInput.i; + var i = parserInput.i; + var loop = true; + var testChar; + + if (typeof tok === 'string') { + testChar = function testChar(char) { + return char === tok; + }; + } else { + testChar = function testChar(char) { + return tok.test(char); + }; + } + + do { + var nextChar = input.charAt(i); + + if (blockDepth === 0 && testChar(nextChar)) { + returnVal = input.substr(lastPos, i - lastPos); + + if (returnVal) { + parseGroups.push(returnVal); + } else { + parseGroups.push(' '); + } + + returnVal = parseGroups; + skipWhitespace(i - startPos); + loop = false; + } else { + if (inComment) { + if (nextChar === '*' && input.charAt(i + 1) === '/') { + i++; + blockDepth--; + inComment = false; + } + + i++; + continue; + } + + switch (nextChar) { + case '\\': + i++; + nextChar = input.charAt(i); + parseGroups.push(input.substr(lastPos, i - lastPos + 1)); + lastPos = i + 1; + break; + + case '/': + if (input.charAt(i + 1) === '*') { + i++; + inComment = true; + blockDepth++; + } + + break; + + case '\'': + case '"': + quote = parserInput.$quoted(i); + + if (quote) { + parseGroups.push(input.substr(lastPos, i - lastPos), quote); + i += quote[1].length - 1; + lastPos = i + 1; + } else { + skipWhitespace(i - startPos); + returnVal = nextChar; + loop = false; + } + + break; + + case '{': + blockStack.push('}'); + blockDepth++; + break; + + case '(': + blockStack.push(')'); + blockDepth++; + break; + + case '[': + blockStack.push(']'); + blockDepth++; + break; + + case '}': + case ')': + case ']': + var expected = blockStack.pop(); + + if (nextChar === expected) { + blockDepth--; + } else { + // move the parser to the error and return expected + skipWhitespace(i - startPos); + returnVal = expected; + loop = false; + } + + } + + i++; + + if (i > length) { + loop = false; + } + } + } while (loop); + + return returnVal ? returnVal : null; + }; + + parserInput.autoCommentAbsorb = true; + parserInput.commentStore = []; + parserInput.finished = false; // Same as $(), but don't change the state of the parser, + // just return the match. + + parserInput.peek = function (tok) { + if (typeof tok === 'string') { + // https://jsperf.com/string-startswith/21 + for (var i = 0; i < tok.length; i++) { + if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { + return false; + } + } + + return true; + } else { + return tok.test(current); + } + }; // Specialization of peek() + // TODO remove or change some currentChar calls to peekChar + + + parserInput.peekChar = function (tok) { + return input.charAt(parserInput.i) === tok; + }; + + parserInput.currentChar = function () { + return input.charAt(parserInput.i); + }; + + parserInput.prevChar = function () { + return input.charAt(parserInput.i - 1); + }; + + parserInput.getInput = function () { + return input; + }; + + parserInput.peekNotNumeric = function () { + var c = input.charCodeAt(parserInput.i); // Is the first char of the dimension 0-9, '.', '+' or '-' + + return c > CHARCODE_9 || c < CHARCODE_PLUS || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA; + }; + + parserInput.start = function (str, chunkInput, failFunction) { + input = str; + parserInput.i = j = currentPos = furthest = 0; // chunking apparently makes things quicker (but my tests indicate + // it might actually make things slower in node at least) + // and it is a non-perfect parse - it can't recognise + // unquoted urls, meaning it can't distinguish comments + // meaning comments with quotes or {}() in them get 'counted' + // and then lead to parse errors. + // In addition if the chunking chunks in the wrong place we might + // not be able to parse a parser statement in one go + // this is officially deprecated but can be switched on via an option + // in the case it causes too much performance issues. + + if (chunkInput) { + chunks = chunker(str, failFunction); + } else { + chunks = [str]; + } + + current = chunks[0]; + skipWhitespace(0); + }; + + parserInput.end = function () { + var message; + var isFinished = parserInput.i >= input.length; + + if (parserInput.i < furthest) { + message = furthestPossibleErrorMessage; + parserInput.i = furthest; + } + + return { + isFinished: isFinished, + furthest: parserInput.i, + furthestPossibleErrorMessage: message, + furthestReachedEnd: parserInput.i >= input.length - 1, + furthestChar: input[parserInput.i] + }; + }; + + return parserInput; + }); + + // less.js - parser + // + // A relatively straight-forward predictive parser. + // There is no tokenization/lexing stage, the input is parsed + // in one sweep. + // + // To make the parser fast enough to run in the browser, several + // optimization had to be made: + // + // - Matching and slicing on a huge input is often cause of slowdowns. + // The solution is to chunkify the input into smaller strings. + // The chunks are stored in the `chunks` var, + // `j` holds the current chunk index, and `currentPos` holds + // the index of the current chunk in relation to `input`. + // This gives us an almost 4x speed-up. + // + // - In many cases, we don't need to match individual tokens; + // for example, if a value doesn't hold any variables, operations + // or dynamic references, the parser can effectively 'skip' it, + // treating it as a literal. + // An example would be '1px solid #000' - which evaluates to itself, + // we don't need to know what the individual components are. + // The drawback, of course is that you don't get the benefits of + // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, + // and a smaller speed-up in the code-gen. + // + // + // Token matching is done with the `$` function, which either takes + // a terminal string or regexp, or a non-terminal function to call. + // It also takes care of moving all the indices forwards. + // + + var Parser = function Parser(context, imports, fileInfo) { + var parsers; + var parserInput = getParserInput(); + + function error(msg, type) { + throw new LessError({ + index: parserInput.i, + filename: fileInfo.filename, + type: type || 'Syntax', + message: msg + }, imports); + } + + function expect(arg, msg) { + // some older browsers return typeof 'function' for RegExp + var result = arg instanceof Function ? arg.call(parsers) : parserInput.$re(arg); + + if (result) { + return result; + } + + error(msg || (typeof arg === 'string' ? "expected '".concat(arg, "' got '").concat(parserInput.currentChar(), "'") : 'unexpected token')); + } // Specialization of expect() + + + function expectChar(arg, msg) { + if (parserInput.$char(arg)) { + return arg; + } + + error(msg || "expected '".concat(arg, "' got '").concat(parserInput.currentChar(), "'")); + } + + function getDebugInfo(index) { + var filename = fileInfo.filename; + return { + lineNumber: getLocation(index, parserInput.getInput()).line + 1, + fileName: filename + }; + } + /** + * Used after initial parsing to create nodes on the fly + * + * @param {String} str - string to parse + * @param {Array} parseList - array of parsers to run input through e.g. ["value", "important"] + * @param {Number} currentIndex - start number to begin indexing + * @param {Object} fileInfo - fileInfo to attach to created nodes + */ + + + function parseNode(str, parseList, currentIndex, fileInfo, callback) { + var result; + var returnNodes = []; + var parser = parserInput; + + try { + parser.start(str, false, function fail(msg, index) { + callback({ + message: msg, + index: index + currentIndex + }); + }); + + for (var x = 0, p, i; p = parseList[x]; x++) { + i = parser.i; + result = parsers[p](); + + if (result) { + result._index = i + currentIndex; + result._fileInfo = fileInfo; + returnNodes.push(result); + } else { + returnNodes.push(null); + } + } + + var endInfo = parser.end(); + + if (endInfo.isFinished) { + callback(null, returnNodes); + } else { + callback(true, null); + } + } catch (e) { + throw new LessError({ + index: e.index + currentIndex, + message: e.message + }, imports, fileInfo.filename); + } + } // + // The Parser + // + + + return { + parserInput: parserInput, + imports: imports, + fileInfo: fileInfo, + parseNode: parseNode, + // + // Parse an input string into an abstract syntax tree, + // @param str A string containing 'less' markup + // @param callback call `callback` when done. + // @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply + // + parse: function parse(str, callback, additionalData) { + var root; + var error = null; + var globalVars; + var modifyVars; + var ignored; + var preText = ''; + globalVars = additionalData && additionalData.globalVars ? "".concat(Parser.serializeVars(additionalData.globalVars), "\n") : ''; + modifyVars = additionalData && additionalData.modifyVars ? "\n".concat(Parser.serializeVars(additionalData.modifyVars)) : ''; + + if (context.pluginManager) { + var preProcessors = context.pluginManager.getPreProcessors(); + + for (var i = 0; i < preProcessors.length; i++) { + str = preProcessors[i].process(str, { + context: context, + imports: imports, + fileInfo: fileInfo + }); + } + } + + if (globalVars || additionalData && additionalData.banner) { + preText = (additionalData && additionalData.banner ? additionalData.banner : '') + globalVars; + ignored = imports.contentsIgnoredChars; + ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0; + ignored[fileInfo.filename] += preText.length; + } + + str = str.replace(/\r\n?/g, '\n'); // Remove potential UTF Byte Order Mark + + str = preText + str.replace(/^\uFEFF/, '') + modifyVars; + imports.contents[fileInfo.filename] = str; // Start with the primary rule. + // The whole syntax tree is held under a Ruleset node, + // with the `root` property set to true, so no `{}` are + // output. The callback is called when the input is parsed. + + try { + parserInput.start(str, context.chunkInput, function fail(msg, index) { + throw new LessError({ + index: index, + type: 'Parse', + message: msg, + filename: fileInfo.filename + }, imports); + }); + tree.Node.prototype.parse = this; + root = new tree.Ruleset(null, this.parsers.primary()); + tree.Node.prototype.rootNode = root; + root.root = true; + root.firstRoot = true; + root.functionRegistry = functionRegistry.inherit(); + } catch (e) { + return callback(new LessError(e, imports, fileInfo.filename)); + } // If `i` is smaller than the `input.length - 1`, + // it means the parser wasn't able to parse the whole + // string, so we've got a parsing error. + // + // We try to extract a \n delimited string, + // showing the line where the parse error occurred. + // We split it up into two parts (the part which parsed, + // and the part which didn't), so we can color them differently. + + + var endInfo = parserInput.end(); + + if (!endInfo.isFinished) { + var message = endInfo.furthestPossibleErrorMessage; + + if (!message) { + message = 'Unrecognised input'; + + if (endInfo.furthestChar === '}') { + message += '. Possibly missing opening \'{\''; + } else if (endInfo.furthestChar === ')') { + message += '. Possibly missing opening \'(\''; + } else if (endInfo.furthestReachedEnd) { + message += '. Possibly missing something'; + } + } + + error = new LessError({ + type: 'Parse', + message: message, + index: endInfo.furthest, + filename: fileInfo.filename + }, imports); + } + + var finish = function finish(e) { + e = error || e || imports.error; + + if (e) { + if (!(e instanceof LessError)) { + e = new LessError(e, imports, fileInfo.filename); + } + + return callback(e); + } else { + return callback(null, root); + } + }; + + if (context.processImports !== false) { + new visitors.ImportVisitor(imports, finish).run(root); + } else { + return finish(); + } + }, + // + // Here in, the parsing rules/functions + // + // The basic structure of the syntax tree generated is as follows: + // + // Ruleset -> Declaration -> Value -> Expression -> Entity + // + // Here's some Less code: + // + // .class { + // color: #fff; + // border: 1px solid #000; + // width: @w + 4px; + // > .child {...} + // } + // + // And here's what the parse tree might look like: + // + // Ruleset (Selector '.class', [ + // Declaration ("color", Value ([Expression [Color #fff]])) + // Declaration ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) + // Declaration ("width", Value ([Expression [Operation " + " [Variable "@w"][Dimension 4px]]])) + // Ruleset (Selector [Element '>', '.child'], [...]) + // ]) + // + // In general, most rules will try to parse a token with the `$re()` function, and if the return + // value is truly, will return a new node, of the relevant type. Sometimes, we need to check + // first, before parsing, that's when we use `peek()`. + // + parsers: parsers = { + // + // The `primary` rule is the *entry* and *exit* point of the parser. + // The rules here can appear at any level of the parse tree. + // + // The recursive nature of the grammar is an interplay between the `block` + // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, + // as represented by this simplified grammar: + // + // primary → (ruleset | declaration)+ + // ruleset → selector+ block + // block → '{' primary '}' + // + // Only at one point is the primary rule not called from the + // block rule: at the root level. + // + primary: function primary() { + var mixin = this.mixin; + var root = []; + var node; + + while (true) { + while (true) { + node = this.comment(); + + if (!node) { + break; + } + + root.push(node); + } // always process comments before deciding if finished + + + if (parserInput.finished) { + break; + } + + if (parserInput.peek('}')) { + break; + } + + node = this.extendRule(); + + if (node) { + root = root.concat(node); + continue; + } + + node = mixin.definition() || this.declaration() || this.ruleset() || mixin.call(false, false) || this.variableCall() || this.entities.call() || this.atrule(); + + if (node) { + root.push(node); + } else { + var foundSemiColon = false; + + while (parserInput.$char(';')) { + foundSemiColon = true; + } + + if (!foundSemiColon) { + break; + } + } + } + + return root; + }, + // comments are collected by the main parsing mechanism and then assigned to nodes + // where the current structure allows it + comment: function comment() { + if (parserInput.commentStore.length) { + var comment = parserInput.commentStore.shift(); + return new tree.Comment(comment.text, comment.isLineComment, comment.index, fileInfo); + } + }, + // + // Entities are tokens which can be found inside an Expression + // + entities: { + mixinLookup: function mixinLookup() { + return parsers.mixin.call(true, true); + }, + // + // A string, which supports escaping " and ' + // + // "milky way" 'he\'s the one!' + // + quoted: function quoted(forceEscaped) { + var str; + var index = parserInput.i; + var isEscaped = false; + parserInput.save(); + + if (parserInput.$char('~')) { + isEscaped = true; + } else if (forceEscaped) { + parserInput.restore(); + return; + } + + str = parserInput.$quoted(); + + if (!str) { + parserInput.restore(); + return; + } + + parserInput.forget(); + return new tree.Quoted(str.charAt(0), str.substr(1, str.length - 2), isEscaped, index, fileInfo); + }, + // + // A catch-all word, such as: + // + // black border-collapse + // + keyword: function keyword() { + var k = parserInput.$char('%') || parserInput.$re(/^\[?(?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+\]?/); + + if (k) { + return tree.Color.fromKeyword(k) || new tree.Keyword(k); + } + }, + // + // A function call + // + // rgb(255, 0, 255) + // + // The arguments are parsed with the `entities.arguments` parser. + // + call: function call() { + var name; + var args; + var func; + var index = parserInput.i; // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 + + if (parserInput.peek(/^url\(/i)) { + return; + } + + parserInput.save(); + name = parserInput.$re(/^([\w-]+|%|progid:[\w\.]+)\(/); + + if (!name) { + parserInput.forget(); + return; + } + + name = name[1]; + func = this.customFuncCall(name); + + if (func) { + args = func.parse(); + + if (args && func.stop) { + parserInput.forget(); + return args; + } + } + + args = this.arguments(args); + + if (!parserInput.$char(')')) { + parserInput.restore('Could not parse call arguments or missing \')\''); + return; + } + + parserInput.forget(); + return new tree.Call(name, args, index, fileInfo); + }, + // + // Parsing rules for functions with non-standard args, e.g.: + // + // boolean(not(2 > 1)) + // + // This is a quick prototype, to be modified/improved when + // more custom-parsed funcs come (e.g. `selector(...)`) + // + customFuncCall: function customFuncCall(name) { + /* Ideally the table is to be moved out of here for faster perf., + but it's quite tricky since it relies on all these `parsers` + and `expect` available only here */ + return { + alpha: f(parsers.ieAlpha, true), + boolean: f(condition), + 'if': f(condition) + }[name.toLowerCase()]; + + function f(parse, stop) { + return { + parse: parse, + // parsing function + stop: stop // when true - stop after parse() and return its result, + // otherwise continue for plain args + + }; + } + + function condition() { + return [expect(parsers.condition, 'expected condition')]; + } + }, + arguments: function _arguments(prevArgs) { + var argsComma = prevArgs || []; + var argsSemiColon = []; + var isSemiColonSeparated; + var value; + parserInput.save(); + + while (true) { + if (prevArgs) { + prevArgs = false; + } else { + value = parsers.detachedRuleset() || this.assignment() || parsers.expression(); + + if (!value) { + break; + } + + if (value.value && value.value.length == 1) { + value = value.value[0]; + } + + argsComma.push(value); + } + + if (parserInput.$char(',')) { + continue; + } + + if (parserInput.$char(';') || isSemiColonSeparated) { + isSemiColonSeparated = true; + value = argsComma.length < 1 ? argsComma[0] : new tree.Value(argsComma); + argsSemiColon.push(value); + argsComma = []; + } + } + + parserInput.forget(); + return isSemiColonSeparated ? argsSemiColon : argsComma; + }, + literal: function literal() { + return this.dimension() || this.color() || this.quoted() || this.unicodeDescriptor(); + }, + // Assignments are argument entities for calls. + // They are present in ie filter properties as shown below. + // + // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) + // + assignment: function assignment() { + var key; + var value; + parserInput.save(); + key = parserInput.$re(/^\w+(?=\s?=)/i); + + if (!key) { + parserInput.restore(); + return; + } + + if (!parserInput.$char('=')) { + parserInput.restore(); + return; + } + + value = parsers.entity(); + + if (value) { + parserInput.forget(); + return new tree.Assignment(key, value); + } else { + parserInput.restore(); + } + }, + // + // Parse url() tokens + // + // We use a specific rule for urls, because they don't really behave like + // standard function calls. The difference is that the argument doesn't have + // to be enclosed within a string, so it can't be parsed as an Expression. + // + url: function url() { + var value; + var index = parserInput.i; + parserInput.autoCommentAbsorb = false; + + if (!parserInput.$str('url(')) { + parserInput.autoCommentAbsorb = true; + return; + } + + value = this.quoted() || this.variable() || this.property() || parserInput.$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ''; + parserInput.autoCommentAbsorb = true; + expectChar(')'); + return new tree.URL(value.value != null || value instanceof tree.Variable || value instanceof tree.Property ? value : new tree.Anonymous(value, index), index, fileInfo); + }, + // + // A Variable entity, such as `@fink`, in + // + // width: @fink + 2px + // + // We use a different parser for variable definitions, + // see `parsers.variable`. + // + variable: function variable() { + var ch; + var name; + var index = parserInput.i; + parserInput.save(); + + if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^@@?[\w-]+/))) { + ch = parserInput.currentChar(); + + if (ch === '(' || ch === '[' && !parserInput.prevChar().match(/^\s/)) { + // this may be a VariableCall lookup + var result = parsers.variableCall(name); + + if (result) { + parserInput.forget(); + return result; + } + } + + parserInput.forget(); + return new tree.Variable(name, index, fileInfo); + } + + parserInput.restore(); + }, + // A variable entity using the protective {} e.g. @{var} + variableCurly: function variableCurly() { + var curly; + var index = parserInput.i; + + if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\{([\w-]+)\}/))) { + return new tree.Variable("@".concat(curly[1]), index, fileInfo); + } + }, + // + // A Property accessor, such as `$color`, in + // + // background-color: $color + // + property: function property() { + var name; + var index = parserInput.i; + + if (parserInput.currentChar() === '$' && (name = parserInput.$re(/^\$[\w-]+/))) { + return new tree.Property(name, index, fileInfo); + } + }, + // A property entity useing the protective {} e.g. ${prop} + propertyCurly: function propertyCurly() { + var curly; + var index = parserInput.i; + + if (parserInput.currentChar() === '$' && (curly = parserInput.$re(/^\$\{([\w-]+)\}/))) { + return new tree.Property("$".concat(curly[1]), index, fileInfo); + } + }, + // + // A Hexadecimal color + // + // #4F3C2F + // + // `rgb` and `hsl` colors are parsed through the `entities.call` parser. + // + color: function color() { + var rgb; + parserInput.save(); + + if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})([\w.#\[])?/))) { + if (!rgb[2]) { + parserInput.forget(); + return new tree.Color(rgb[1], undefined, rgb[0]); + } + } + + parserInput.restore(); + }, + colorKeyword: function colorKeyword() { + parserInput.save(); + var autoCommentAbsorb = parserInput.autoCommentAbsorb; + parserInput.autoCommentAbsorb = false; + var k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/); + parserInput.autoCommentAbsorb = autoCommentAbsorb; + + if (!k) { + parserInput.forget(); + return; + } + + parserInput.restore(); + var color = tree.Color.fromKeyword(k); + + if (color) { + parserInput.$str(k); + return color; + } + }, + // + // A Dimension, that is, a number and a unit + // + // 0.5em 95% + // + dimension: function dimension() { + if (parserInput.peekNotNumeric()) { + return; + } + + var value = parserInput.$re(/^([+-]?\d*\.?\d+)(%|[a-z_]+)?/i); + + if (value) { + return new tree.Dimension(value[1], value[2]); + } + }, + // + // A unicode descriptor, as is used in unicode-range + // + // U+0?? or U+00A1-00A9 + // + unicodeDescriptor: function unicodeDescriptor() { + var ud; + ud = parserInput.$re(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/); + + if (ud) { + return new tree.UnicodeDescriptor(ud[0]); + } + }, + // + // JavaScript code to be evaluated + // + // `window.location.href` + // + javascript: function javascript() { + var js; + var index = parserInput.i; + parserInput.save(); + var escape = parserInput.$char('~'); + var jsQuote = parserInput.$char('`'); + + if (!jsQuote) { + parserInput.restore(); + return; + } + + js = parserInput.$re(/^[^`]*`/); + + if (js) { + parserInput.forget(); + return new tree.JavaScript(js.substr(0, js.length - 1), Boolean(escape), index, fileInfo); + } + + parserInput.restore('invalid javascript definition'); + } + }, + // + // The variable part of a variable definition. Used in the `rule` parser + // + // @fink: + // + variable: function variable() { + var name; + + if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) { + return name[1]; + } + }, + // + // Call a variable value to retrieve a detached ruleset + // or a value from a detached ruleset's rules. + // + // @fink(); + // @fink; + // color: @fink[@color]; + // + variableCall: function variableCall(parsedName) { + var lookups; + var important; + var i = parserInput.i; + var inValue = !!parsedName; + var name = parsedName; + parserInput.save(); + + if (name || parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)(\(\s*\))?/))) { + lookups = this.mixin.ruleLookups(); + + if (!lookups && (inValue && parserInput.$str('()') !== '()' || name[2] !== '()')) { + parserInput.restore('Missing \'[...]\' lookup in variable call'); + return; + } + + if (!inValue) { + name = name[1]; + } + + if (lookups && parsers.important()) { + important = true; + } + + var call = new tree.VariableCall(name, i, fileInfo); + + if (!inValue && parsers.end()) { + parserInput.forget(); + return call; + } else { + parserInput.forget(); + return new tree.NamespaceValue(call, lookups, important, i, fileInfo); + } + } + + parserInput.restore(); + }, + // + // extend syntax - used to extend selectors + // + extend: function extend(isRule) { + var elements; + var e; + var index = parserInput.i; + var option; + var extendList; + var extend; + + if (!parserInput.$str(isRule ? '&:extend(' : ':extend(')) { + return; + } + + do { + option = null; + elements = null; + + while (!(option = parserInput.$re(/^(all)(?=\s*(\)|,))/))) { + e = this.element(); + + if (!e) { + break; + } + + if (elements) { + elements.push(e); + } else { + elements = [e]; + } + } + + option = option && option[1]; + + if (!elements) { + error('Missing target selector for :extend().'); + } + + extend = new tree.Extend(new tree.Selector(elements), option, index, fileInfo); + + if (extendList) { + extendList.push(extend); + } else { + extendList = [extend]; + } + } while (parserInput.$char(',')); + + expect(/^\)/); + + if (isRule) { + expect(/^;/); + } + + return extendList; + }, + // + // extendRule - used in a rule to extend all the parent selectors + // + extendRule: function extendRule() { + return this.extend(true); + }, + // + // Mixins + // + mixin: { + // + // A Mixin call, with an optional argument list + // + // #mixins > .square(#fff); + // #mixins.square(#fff); + // .rounded(4px, black); + // .button; + // + // We can lookup / return a value using the lookup syntax: + // + // color: #mixin.square(#fff)[@color]; + // + // The `while` loop is there because mixins can be + // namespaced, but we only support the child and descendant + // selector for now. + // + call: function call(inValue, getLookup) { + var s = parserInput.currentChar(); + var important = false; + var lookups; + var index = parserInput.i; + var elements; + var args; + var hasParens; + + if (s !== '.' && s !== '#') { + return; + } + + parserInput.save(); // stop us absorbing part of an invalid selector + + elements = this.elements(); + + if (elements) { + if (parserInput.$char('(')) { + args = this.args(true).args; + expectChar(')'); + hasParens = true; + } + + if (getLookup !== false) { + lookups = this.ruleLookups(); + } + + if (getLookup === true && !lookups) { + parserInput.restore(); + return; + } + + if (inValue && !lookups && !hasParens) { + // This isn't a valid in-value mixin call + parserInput.restore(); + return; + } + + if (!inValue && parsers.important()) { + important = true; + } + + if (inValue || parsers.end()) { + parserInput.forget(); + var mixin = new tree.mixin.Call(elements, args, index, fileInfo, !lookups && important); + + if (lookups) { + return new tree.NamespaceValue(mixin, lookups, important); + } else { + return mixin; + } + } + } + + parserInput.restore(); + }, + + /** + * Matching elements for mixins + * (Start with . or # and can have > ) + */ + elements: function elements() { + var elements; + var e; + var c; + var elem; + var elemIndex; + var re = /^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/; + + while (true) { + elemIndex = parserInput.i; + e = parserInput.$re(re); + + if (!e) { + break; + } + + elem = new tree.Element(c, e, false, elemIndex, fileInfo); + + if (elements) { + elements.push(elem); + } else { + elements = [elem]; + } + + c = parserInput.$char('>'); + } + + return elements; + }, + args: function args(isCall) { + var entities = parsers.entities; + var returner = { + args: null, + variadic: false + }; + var expressions = []; + var argsSemiColon = []; + var argsComma = []; + var isSemiColonSeparated; + var expressionContainsNamed; + var name; + var nameLoop; + var value; + var arg; + var expand; + var hasSep = true; + parserInput.save(); + + while (true) { + if (isCall) { + arg = parsers.detachedRuleset() || parsers.expression(); + } else { + parserInput.commentStore.length = 0; + + if (parserInput.$str('...')) { + returner.variadic = true; + + if (parserInput.$char(';') && !isSemiColonSeparated) { + isSemiColonSeparated = true; + } + + (isSemiColonSeparated ? argsSemiColon : argsComma).push({ + variadic: true + }); + break; + } + + arg = entities.variable() || entities.property() || entities.literal() || entities.keyword() || this.call(true); + } + + if (!arg || !hasSep) { + break; + } + + nameLoop = null; + + if (arg.throwAwayComments) { + arg.throwAwayComments(); + } + + value = arg; + var val = null; + + if (isCall) { + // Variable + if (arg.value && arg.value.length == 1) { + val = arg.value[0]; + } + } else { + val = arg; + } + + if (val && (val instanceof tree.Variable || val instanceof tree.Property)) { + if (parserInput.$char(':')) { + if (expressions.length > 0) { + if (isSemiColonSeparated) { + error('Cannot mix ; and , as delimiter types'); + } + + expressionContainsNamed = true; + } + + value = parsers.detachedRuleset() || parsers.expression(); + + if (!value) { + if (isCall) { + error('could not understand value for named argument'); + } else { + parserInput.restore(); + returner.args = []; + return returner; + } + } + + nameLoop = name = val.name; + } else if (parserInput.$str('...')) { + if (!isCall) { + returner.variadic = true; + + if (parserInput.$char(';') && !isSemiColonSeparated) { + isSemiColonSeparated = true; + } + + (isSemiColonSeparated ? argsSemiColon : argsComma).push({ + name: arg.name, + variadic: true + }); + break; + } else { + expand = true; + } + } else if (!isCall) { + name = nameLoop = val.name; + value = null; + } + } + + if (value) { + expressions.push(value); + } + + argsComma.push({ + name: nameLoop, + value: value, + expand: expand + }); + + if (parserInput.$char(',')) { + hasSep = true; + continue; + } + + hasSep = parserInput.$char(';') === ';'; + + if (hasSep || isSemiColonSeparated) { + if (expressionContainsNamed) { + error('Cannot mix ; and , as delimiter types'); + } + + isSemiColonSeparated = true; + + if (expressions.length > 1) { + value = new tree.Value(expressions); + } + + argsSemiColon.push({ + name: name, + value: value, + expand: expand + }); + name = null; + expressions = []; + expressionContainsNamed = false; + } + } + + parserInput.forget(); + returner.args = isSemiColonSeparated ? argsSemiColon : argsComma; + return returner; + }, + // + // A Mixin definition, with a list of parameters + // + // .rounded (@radius: 2px, @color) { + // ... + // } + // + // Until we have a finer grained state-machine, we have to + // do a look-ahead, to make sure we don't have a mixin call. + // See the `rule` function for more information. + // + // We start by matching `.rounded (`, and then proceed on to + // the argument list, which has optional default values. + // We store the parameters in `params`, with a `value` key, + // if there is a value, such as in the case of `@radius`. + // + // Once we've got our params list, and a closing `)`, we parse + // the `{...}` block. + // + definition: function definition() { + var name; + var params = []; + var match; + var ruleset; + var cond; + var variadic = false; + + if (parserInput.currentChar() !== '.' && parserInput.currentChar() !== '#' || parserInput.peek(/^[^{]*\}/)) { + return; + } + + parserInput.save(); + match = parserInput.$re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/); + + if (match) { + name = match[1]; + var argInfo = this.args(false); + params = argInfo.args; + variadic = argInfo.variadic; // .mixincall("@{a}"); + // looks a bit like a mixin definition.. + // also + // .mixincall(@a: {rule: set;}); + // so we have to be nice and restore + + if (!parserInput.$char(')')) { + parserInput.restore('Missing closing \')\''); + return; + } + + parserInput.commentStore.length = 0; + + if (parserInput.$str('when')) { + // Guard + cond = expect(parsers.conditions, 'expected condition'); + } + + ruleset = parsers.block(); + + if (ruleset) { + parserInput.forget(); + return new tree.mixin.Definition(name, params, ruleset, cond, variadic); + } else { + parserInput.restore(); + } + } else { + parserInput.forget(); + } + }, + ruleLookups: function ruleLookups() { + var rule; + var lookups = []; + + if (parserInput.currentChar() !== '[') { + return; + } + + while (true) { + parserInput.save(); + rule = this.lookupValue(); + + if (!rule && rule !== '') { + parserInput.restore(); + break; + } + + lookups.push(rule); + parserInput.forget(); + } + + if (lookups.length > 0) { + return lookups; + } + }, + lookupValue: function lookupValue() { + parserInput.save(); + + if (!parserInput.$char('[')) { + parserInput.restore(); + return; + } + + var name = parserInput.$re(/^(?:[@$]{0,2})[_a-zA-Z0-9-]*/); + + if (!parserInput.$char(']')) { + parserInput.restore(); + return; + } + + if (name || name === '') { + parserInput.forget(); + return name; + } + + parserInput.restore(); + } + }, + // + // Entities are the smallest recognized token, + // and can be found inside a rule's value. + // + entity: function entity() { + var entities = this.entities; + return this.comment() || entities.literal() || entities.variable() || entities.url() || entities.property() || entities.call() || entities.keyword() || this.mixin.call(true) || entities.javascript(); + }, + // + // A Declaration terminator. Note that we use `peek()` to check for '}', + // because the `block` rule will be expecting it, but we still need to make sure + // it's there, if ';' was omitted. + // + end: function end() { + return parserInput.$char(';') || parserInput.peek('}'); + }, + // + // IE's alpha function + // + // alpha(opacity=88) + // + ieAlpha: function ieAlpha() { + var value; // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 + + if (!parserInput.$re(/^opacity=/i)) { + return; + } + + value = parserInput.$re(/^\d+/); + + if (!value) { + value = expect(parsers.entities.variable, 'Could not parse alpha'); + value = "@{".concat(value.name.slice(1), "}"); + } + + expectChar(')'); + return new tree.Quoted('', "alpha(opacity=".concat(value, ")")); + }, + // + // A Selector Element + // + // div + // + h1 + // #socks + // input[type="text"] + // + // Elements are the building blocks for Selectors, + // they are made out of a `Combinator` (see combinator rule), + // and an element name, such as a tag a class, or `*`. + // + element: function element() { + var e; + var c; + var v; + var index = parserInput.i; + c = this.combinator(); + e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) || parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || parserInput.$char('*') || parserInput.$char('&') || this.attribute() || parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[\.#:](?=@)/) || this.entities.variableCurly(); + + if (!e) { + parserInput.save(); + + if (parserInput.$char('(')) { + if ((v = this.selector(false)) && parserInput.$char(')')) { + e = new tree.Paren(v); + parserInput.forget(); + } else { + parserInput.restore('Missing closing \')\''); + } + } else { + parserInput.forget(); + } + } + + if (e) { + return new tree.Element(c, e, e instanceof tree.Variable, index, fileInfo); + } + }, + // + // Combinators combine elements together, in a Selector. + // + // Because our parser isn't white-space sensitive, special care + // has to be taken, when parsing the descendant combinator, ` `, + // as it's an empty space. We have to check the previous character + // in the input, to see if it's a ` ` character. More info on how + // we deal with this in *combinator.js*. + // + combinator: function combinator() { + var c = parserInput.currentChar(); + + if (c === '/') { + parserInput.save(); + var slashedCombinator = parserInput.$re(/^\/[a-z]+\//i); + + if (slashedCombinator) { + parserInput.forget(); + return new tree.Combinator(slashedCombinator); + } + + parserInput.restore(); + } + + if (c === '>' || c === '+' || c === '~' || c === '|' || c === '^') { + parserInput.i++; + + if (c === '^' && parserInput.currentChar() === '^') { + c = '^^'; + parserInput.i++; + } + + while (parserInput.isWhitespace()) { + parserInput.i++; + } + + return new tree.Combinator(c); + } else if (parserInput.isWhitespace(-1)) { + return new tree.Combinator(' '); + } else { + return new tree.Combinator(null); + } + }, + // + // A CSS Selector + // with less extensions e.g. the ability to extend and guard + // + // .class > div + h1 + // li a:hover + // + // Selectors are made out of one or more Elements, see above. + // + selector: function selector(isLess) { + var index = parserInput.i; + var elements; + var extendList; + var c; + var e; + var allExtends; + var when; + var condition; + isLess = isLess !== false; + + while (isLess && (extendList = this.extend()) || isLess && (when = parserInput.$str('when')) || (e = this.element())) { + if (when) { + condition = expect(this.conditions, 'expected condition'); + } else if (condition) { + error('CSS guard can only be used at the end of selector'); + } else if (extendList) { + if (allExtends) { + allExtends = allExtends.concat(extendList); + } else { + allExtends = extendList; + } + } else { + if (allExtends) { + error('Extend can only be used at the end of selector'); + } + + c = parserInput.currentChar(); + + if (elements) { + elements.push(e); + } else { + elements = [e]; + } + + e = null; + } + + if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { + break; + } + } + + if (elements) { + return new tree.Selector(elements, allExtends, condition, index, fileInfo); + } + + if (allExtends) { + error('Extend must be used to extend a selector, it cannot be used on its own'); + } + }, + selectors: function selectors() { + var s; + var selectors; + + while (true) { + s = this.selector(); + + if (!s) { + break; + } + + if (selectors) { + selectors.push(s); + } else { + selectors = [s]; + } + + parserInput.commentStore.length = 0; + + if (s.condition && selectors.length > 1) { + error("Guards are only currently allowed on a single selector."); + } + + if (!parserInput.$char(',')) { + break; + } + + if (s.condition) { + error("Guards are only currently allowed on a single selector."); + } + + parserInput.commentStore.length = 0; + } + + return selectors; + }, + attribute: function attribute() { + if (!parserInput.$char('[')) { + return; + } + + var entities = this.entities; + var key; + var val; + var op; + + if (!(key = entities.variableCurly())) { + key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/); + } + + op = parserInput.$re(/^[|~*$^]?=/); + + if (op) { + val = entities.quoted() || parserInput.$re(/^[0-9]+%/) || parserInput.$re(/^[\w-]+/) || entities.variableCurly(); + } + + expectChar(']'); + return new tree.Attribute(key, op, val); + }, + // + // The `block` rule is used by `ruleset` and `mixin.definition`. + // It's a wrapper around the `primary` rule, with added `{}`. + // + block: function block() { + var content; + + if (parserInput.$char('{') && (content = this.primary()) && parserInput.$char('}')) { + return content; + } + }, + blockRuleset: function blockRuleset() { + var block = this.block(); + + if (block) { + block = new tree.Ruleset(null, block); + } + + return block; + }, + detachedRuleset: function detachedRuleset() { + var argInfo; + var params; + var variadic; + parserInput.save(); + + if (parserInput.$re(/^[.#]\(/)) { + /** + * DR args currently only implemented for each() function, and not + * yet settable as `@dr: #(@arg) {}` + * This should be done when DRs are merged with mixins. + * See: https://github.com/less/less-meta/issues/16 + */ + argInfo = this.mixin.args(false); + params = argInfo.args; + variadic = argInfo.variadic; + + if (!parserInput.$char(')')) { + parserInput.restore(); + return; + } + } + + var blockRuleset = this.blockRuleset(); + + if (blockRuleset) { + parserInput.forget(); + + if (params) { + return new tree.mixin.Definition(null, params, blockRuleset, null, variadic); + } + + return new tree.DetachedRuleset(blockRuleset); + } + + parserInput.restore(); + }, + // + // div, .class, body > p {...} + // + ruleset: function ruleset() { + var selectors; + var rules; + var debugInfo; + parserInput.save(); + + if (context.dumpLineNumbers) { + debugInfo = getDebugInfo(parserInput.i); + } + + selectors = this.selectors(); + + if (selectors && (rules = this.block())) { + parserInput.forget(); + var ruleset = new tree.Ruleset(selectors, rules, context.strictImports); + + if (context.dumpLineNumbers) { + ruleset.debugInfo = debugInfo; + } + + return ruleset; + } else { + parserInput.restore(); + } + }, + declaration: function declaration() { + var name; + var value; + var index = parserInput.i; + var hasDR; + var c = parserInput.currentChar(); + var important; + var merge; + var isVariable; + + if (c === '.' || c === '#' || c === '&' || c === ':') { + return; + } + + parserInput.save(); + name = this.variable() || this.ruleProperty(); + + if (name) { + isVariable = typeof name === 'string'; + + if (isVariable) { + value = this.detachedRuleset(); + + if (value) { + hasDR = true; + } + } + + parserInput.commentStore.length = 0; + + if (!value) { + // a name returned by this.ruleProperty() is always an array of the form: + // [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"] + // where each item is a tree.Keyword or tree.Variable + merge = !isVariable && name.length > 1 && name.pop().value; // Custom property values get permissive parsing + + if (name[0].value && name[0].value.slice(0, 2) === '--') { + value = this.permissiveValue(); + } // Try to store values as anonymous + // If we need the value later we'll re-parse it in ruleset.parseValue + else { + value = this.anonymousValue(); + } + + if (value) { + parserInput.forget(); // anonymous values absorb the end ';' which is required for them to work + + return new tree.Declaration(name, value, false, merge, index, fileInfo); + } + + if (!value) { + value = this.value(); + } + + if (value) { + important = this.important(); + } else if (isVariable) { + // As a last resort, try permissiveValue + value = this.permissiveValue(); + } + } + + if (value && (this.end() || hasDR)) { + parserInput.forget(); + return new tree.Declaration(name, value, important, merge, index, fileInfo); + } else { + parserInput.restore(); + } + } else { + parserInput.restore(); + } + }, + anonymousValue: function anonymousValue() { + var index = parserInput.i; + var match = parserInput.$re(/^([^.#@\$+\/'"*`(;{}-]*);/); + + if (match) { + return new tree.Anonymous(match[1], index); + } + }, + + /** + * Used for custom properties, at-rules, and variables (as fallback) + * Parses almost anything inside of {} [] () "" blocks + * until it reaches outer-most tokens. + * + * First, it will try to parse comments and entities to reach + * the end. This is mostly like the Expression parser except no + * math is allowed. + */ + permissiveValue: function permissiveValue(untilTokens) { + var i; + var e; + var done; + var value; + var tok = untilTokens || ';'; + var index = parserInput.i; + var result = []; + + function testCurrentChar() { + var char = parserInput.currentChar(); + + if (typeof tok === 'string') { + return char === tok; + } else { + return tok.test(char); + } + } + + if (testCurrentChar()) { + return; + } + + value = []; + + do { + e = this.comment(); + + if (e) { + value.push(e); + continue; + } + + e = this.entity(); + + if (e) { + value.push(e); + } + } while (e); + + done = testCurrentChar(); + + if (value.length > 0) { + value = new tree.Expression(value); + + if (done) { + return value; + } else { + result.push(value); + } // Preserve space before $parseUntil as it will not + + + if (parserInput.prevChar() === ' ') { + result.push(new tree.Anonymous(' ', index)); + } + } + + parserInput.save(); + value = parserInput.$parseUntil(tok); + + if (value) { + if (typeof value === 'string') { + error("Expected '".concat(value, "'"), 'Parse'); + } + + if (value.length === 1 && value[0] === ' ') { + parserInput.forget(); + return new tree.Anonymous('', index); + } + + var item; + + for (i = 0; i < value.length; i++) { + item = value[i]; + + if (Array.isArray(item)) { + // Treat actual quotes as normal quoted values + result.push(new tree.Quoted(item[0], item[1], true, index, fileInfo)); + } else { + if (i === value.length - 1) { + item = item.trim(); + } // Treat like quoted values, but replace vars like unquoted expressions + + + var quote = new tree.Quoted('\'', item, true, index, fileInfo); + quote.variableRegex = /@([\w-]+)/g; + quote.propRegex = /\$([\w-]+)/g; + result.push(quote); + } + } + + parserInput.forget(); + return new tree.Expression(result, true); + } + + parserInput.restore(); + }, + // + // An @import atrule + // + // @import "lib"; + // + // Depending on our environment, importing is done differently: + // In the browser, it's an XHR request, in Node, it would be a + // file-system operation. The function used for importing is + // stored in `import`, which we pass to the Import constructor. + // + 'import': function _import() { + var path; + var features; + var index = parserInput.i; + var dir = parserInput.$re(/^@import?\s+/); + + if (dir) { + var options = (dir ? this.importOptions() : null) || {}; + + if (path = this.entities.quoted() || this.entities.url()) { + features = this.mediaFeatures(); + + if (!parserInput.$char(';')) { + parserInput.i = index; + error('missing semi-colon or unrecognised media features on import'); + } + + features = features && new tree.Value(features); + return new tree.Import(path, features, options, index, fileInfo); + } else { + parserInput.i = index; + error('malformed import statement'); + } + } + }, + importOptions: function importOptions() { + var o; + var options = {}; + var optionName; + var value; // list of options, surrounded by parens + + if (!parserInput.$char('(')) { + return null; + } + + do { + o = this.importOption(); + + if (o) { + optionName = o; + value = true; + + switch (optionName) { + case 'css': + optionName = 'less'; + value = false; + break; + + case 'once': + optionName = 'multiple'; + value = false; + break; + } + + options[optionName] = value; + + if (!parserInput.$char(',')) { + break; + } + } + } while (o); + + expectChar(')'); + return options; + }, + importOption: function importOption() { + var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/); + + if (opt) { + return opt[1]; + } + }, + mediaFeature: function mediaFeature() { + var entities = this.entities; + var nodes = []; + var e; + var p; + parserInput.save(); + + do { + e = entities.keyword() || entities.variable() || entities.mixinLookup(); + + if (e) { + nodes.push(e); + } else if (parserInput.$char('(')) { + p = this.property(); + e = this.value(); + + if (parserInput.$char(')')) { + if (p && e) { + nodes.push(new tree.Paren(new tree.Declaration(p, e, null, null, parserInput.i, fileInfo, true))); + } else if (e) { + nodes.push(new tree.Paren(e)); + } else { + error('badly formed media feature definition'); + } + } else { + error('Missing closing \')\'', 'Parse'); + } + } + } while (e); + + parserInput.forget(); + + if (nodes.length > 0) { + return new tree.Expression(nodes); + } + }, + mediaFeatures: function mediaFeatures() { + var entities = this.entities; + var features = []; + var e; + + do { + e = this.mediaFeature(); + + if (e) { + features.push(e); + + if (!parserInput.$char(',')) { + break; + } + } else { + e = entities.variable() || entities.mixinLookup(); + + if (e) { + features.push(e); + + if (!parserInput.$char(',')) { + break; + } + } + } + } while (e); + + return features.length > 0 ? features : null; + }, + media: function media() { + var features; + var rules; + var media; + var debugInfo; + var index = parserInput.i; + + if (context.dumpLineNumbers) { + debugInfo = getDebugInfo(index); + } + + parserInput.save(); + + if (parserInput.$str('@media')) { + features = this.mediaFeatures(); + rules = this.block(); + + if (!rules) { + error('media definitions require block statements after any features'); + } + + parserInput.forget(); + media = new tree.Media(rules, features, index, fileInfo); + + if (context.dumpLineNumbers) { + media.debugInfo = debugInfo; + } + + return media; + } + + parserInput.restore(); + }, + // + // A @plugin directive, used to import plugins dynamically. + // + // @plugin (args) "lib"; + // + plugin: function plugin() { + var path; + var args; + var options; + var index = parserInput.i; + var dir = parserInput.$re(/^@plugin?\s+/); + + if (dir) { + args = this.pluginArgs(); + + if (args) { + options = { + pluginArgs: args, + isPlugin: true + }; + } else { + options = { + isPlugin: true + }; + } + + if (path = this.entities.quoted() || this.entities.url()) { + if (!parserInput.$char(';')) { + parserInput.i = index; + error('missing semi-colon on @plugin'); + } + + return new tree.Import(path, null, options, index, fileInfo); + } else { + parserInput.i = index; + error('malformed @plugin statement'); + } + } + }, + pluginArgs: function pluginArgs() { + // list of options, surrounded by parens + parserInput.save(); + + if (!parserInput.$char('(')) { + parserInput.restore(); + return null; + } + + var args = parserInput.$re(/^\s*([^\);]+)\)\s*/); + + if (args[1]) { + parserInput.forget(); + return args[1].trim(); + } else { + parserInput.restore(); + return null; + } + }, + // + // A CSS AtRule + // + // @charset "utf-8"; + // + atrule: function atrule() { + var index = parserInput.i; + var name; + var value; + var rules; + var nonVendorSpecificName; + var hasIdentifier; + var hasExpression; + var hasUnknown; + var hasBlock = true; + var isRooted = true; + + if (parserInput.currentChar() !== '@') { + return; + } + + value = this['import']() || this.plugin() || this.media(); + + if (value) { + return value; + } + + parserInput.save(); + name = parserInput.$re(/^@[a-z-]+/); + + if (!name) { + return; + } + + nonVendorSpecificName = name; + + if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { + nonVendorSpecificName = "@".concat(name.slice(name.indexOf('-', 2) + 1)); + } + + switch (nonVendorSpecificName) { + case '@charset': + hasIdentifier = true; + hasBlock = false; + break; + + case '@namespace': + hasExpression = true; + hasBlock = false; + break; + + case '@keyframes': + case '@counter-style': + hasIdentifier = true; + break; + + case '@document': + case '@supports': + hasUnknown = true; + isRooted = false; + break; + + default: + hasUnknown = true; + break; + } + + parserInput.commentStore.length = 0; + + if (hasIdentifier) { + value = this.entity(); + + if (!value) { + error("expected ".concat(name, " identifier")); + } + } else if (hasExpression) { + value = this.expression(); + + if (!value) { + error("expected ".concat(name, " expression")); + } + } else if (hasUnknown) { + value = this.permissiveValue(/^[{;]/); + hasBlock = parserInput.currentChar() === '{'; + + if (!value) { + if (!hasBlock && parserInput.currentChar() !== ';') { + error("".concat(name, " rule is missing block or ending semi-colon")); + } + } else if (!value.value) { + value = null; + } + } + + if (hasBlock) { + rules = this.blockRuleset(); + } + + if (rules || !hasBlock && value && parserInput.$char(';')) { + parserInput.forget(); + return new tree.AtRule(name, value, rules, index, fileInfo, context.dumpLineNumbers ? getDebugInfo(index) : null, isRooted); + } + + parserInput.restore('at-rule options not recognised'); + }, + // + // A Value is a comma-delimited list of Expressions + // + // font-family: Baskerville, Georgia, serif; + // + // In a Rule, a Value represents everything after the `:`, + // and before the `;`. + // + value: function value() { + var e; + var expressions = []; + var index = parserInput.i; + + do { + e = this.expression(); + + if (e) { + expressions.push(e); + + if (!parserInput.$char(',')) { + break; + } + } + } while (e); + + if (expressions.length > 0) { + return new tree.Value(expressions, index); + } + }, + important: function important() { + if (parserInput.currentChar() === '!') { + return parserInput.$re(/^! *important/); + } + }, + sub: function sub() { + var a; + var e; + parserInput.save(); + + if (parserInput.$char('(')) { + a = this.addition(); + + if (a && parserInput.$char(')')) { + parserInput.forget(); + e = new tree.Expression([a]); + e.parens = true; + return e; + } + + parserInput.restore('Expected \')\''); + return; + } + + parserInput.restore(); + }, + multiplication: function multiplication() { + var m; + var a; + var op; + var operation; + var isSpaced; + m = this.operand(); + + if (m) { + isSpaced = parserInput.isWhitespace(-1); + + while (true) { + if (parserInput.peek(/^\/[*\/]/)) { + break; + } + + parserInput.save(); + op = parserInput.$char('/') || parserInput.$char('*') || parserInput.$str('./'); + + if (!op) { + parserInput.forget(); + break; + } + + a = this.operand(); + + if (!a) { + parserInput.restore(); + break; + } + + parserInput.forget(); + m.parensInOp = true; + a.parensInOp = true; + operation = new tree.Operation(op, [operation || m, a], isSpaced); + isSpaced = parserInput.isWhitespace(-1); + } + + return operation || m; + } + }, + addition: function addition() { + var m; + var a; + var op; + var operation; + var isSpaced; + m = this.multiplication(); + + if (m) { + isSpaced = parserInput.isWhitespace(-1); + + while (true) { + op = parserInput.$re(/^[-+]\s+/) || !isSpaced && (parserInput.$char('+') || parserInput.$char('-')); + + if (!op) { + break; + } + + a = this.multiplication(); + + if (!a) { + break; + } + + m.parensInOp = true; + a.parensInOp = true; + operation = new tree.Operation(op, [operation || m, a], isSpaced); + isSpaced = parserInput.isWhitespace(-1); + } + + return operation || m; + } + }, + conditions: function conditions() { + var a; + var b; + var index = parserInput.i; + var condition; + a = this.condition(true); + + if (a) { + while (true) { + if (!parserInput.peek(/^,\s*(not\s*)?\(/) || !parserInput.$char(',')) { + break; + } + + b = this.condition(true); + + if (!b) { + break; + } + + condition = new tree.Condition('or', condition || a, b, index); + } + + return condition || a; + } + }, + condition: function condition(needsParens) { + var result; + var logical; + var next; + + function or() { + return parserInput.$str('or'); + } + + result = this.conditionAnd(needsParens); + + if (!result) { + return; + } + + logical = or(); + + if (logical) { + next = this.condition(needsParens); + + if (next) { + result = new tree.Condition(logical, result, next); + } else { + return; + } + } + + return result; + }, + conditionAnd: function conditionAnd(needsParens) { + var result; + var logical; + var next; + var self = this; + + function insideCondition() { + var cond = self.negatedCondition(needsParens) || self.parenthesisCondition(needsParens); + + if (!cond && !needsParens) { + return self.atomicCondition(needsParens); + } + + return cond; + } + + function and() { + return parserInput.$str('and'); + } + + result = insideCondition(); + + if (!result) { + return; + } + + logical = and(); + + if (logical) { + next = this.conditionAnd(needsParens); + + if (next) { + result = new tree.Condition(logical, result, next); + } else { + return; + } + } + + return result; + }, + negatedCondition: function negatedCondition(needsParens) { + if (parserInput.$str('not')) { + var result = this.parenthesisCondition(needsParens); + + if (result) { + result.negate = !result.negate; + } + + return result; + } + }, + parenthesisCondition: function parenthesisCondition(needsParens) { + function tryConditionFollowedByParenthesis(me) { + var body; + parserInput.save(); + body = me.condition(needsParens); + + if (!body) { + parserInput.restore(); + return; + } + + if (!parserInput.$char(')')) { + parserInput.restore(); + return; + } + + parserInput.forget(); + return body; + } + + var body; + parserInput.save(); + + if (!parserInput.$str('(')) { + parserInput.restore(); + return; + } + + body = tryConditionFollowedByParenthesis(this); + + if (body) { + parserInput.forget(); + return body; + } + + body = this.atomicCondition(needsParens); + + if (!body) { + parserInput.restore(); + return; + } + + if (!parserInput.$char(')')) { + parserInput.restore("expected ')' got '".concat(parserInput.currentChar(), "'")); + return; + } + + parserInput.forget(); + return body; + }, + atomicCondition: function atomicCondition(needsParens) { + var entities = this.entities; + var index = parserInput.i; + var a; + var b; + var c; + var op; + + function cond() { + return this.addition() || entities.keyword() || entities.quoted() || entities.mixinLookup(); + } + + cond = cond.bind(this); + a = cond(); + + if (a) { + if (parserInput.$char('>')) { + if (parserInput.$char('=')) { + op = '>='; + } else { + op = '>'; + } + } else if (parserInput.$char('<')) { + if (parserInput.$char('=')) { + op = '<='; + } else { + op = '<'; + } + } else if (parserInput.$char('=')) { + if (parserInput.$char('>')) { + op = '=>'; + } else if (parserInput.$char('<')) { + op = '=<'; + } else { + op = '='; + } + } + + if (op) { + b = cond(); + + if (b) { + c = new tree.Condition(op, a, b, index, false); + } else { + error('expected expression'); + } + } else { + c = new tree.Condition('=', a, new tree.Keyword('true'), index, false); + } + + return c; + } + }, + // + // An operand is anything that can be part of an operation, + // such as a Color, or a Variable + // + operand: function operand() { + var entities = this.entities; + var negate; + + if (parserInput.peek(/^-[@\$\(]/)) { + negate = parserInput.$char('-'); + } + + var o = this.sub() || entities.dimension() || entities.color() || entities.variable() || entities.property() || entities.call() || entities.quoted(true) || entities.colorKeyword() || entities.mixinLookup(); + + if (negate) { + o.parensInOp = true; + o = new tree.Negative(o); + } + + return o; + }, + // + // Expressions either represent mathematical operations, + // or white-space delimited Entities. + // + // 1px solid black + // @var * 2 + // + expression: function expression() { + var entities = []; + var e; + var delim; + var index = parserInput.i; + + do { + e = this.comment(); + + if (e) { + entities.push(e); + continue; + } + + e = this.addition() || this.entity(); + + if (e) { + entities.push(e); // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here + + if (!parserInput.peek(/^\/[\/*]/)) { + delim = parserInput.$char('/'); + + if (delim) { + entities.push(new tree.Anonymous(delim, index)); + } + } + } + } while (e); + + if (entities.length > 0) { + return new tree.Expression(entities); + } + }, + property: function property() { + var name = parserInput.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/); + + if (name) { + return name[1]; + } + }, + ruleProperty: function ruleProperty() { + var name = []; + var index = []; + var s; + var k; + parserInput.save(); + var simpleProperty = parserInput.$re(/^([_a-zA-Z0-9-]+)\s*:/); + + if (simpleProperty) { + name = [new tree.Keyword(simpleProperty[1])]; + parserInput.forget(); + return name; + } + + function match(re) { + var i = parserInput.i; + var chunk = parserInput.$re(re); + + if (chunk) { + index.push(i); + return name.push(chunk[1]); + } + } + + match(/^(\*?)/); + + while (true) { + if (!match(/^((?:[\w-]+)|(?:[@\$]\{[\w-]+\}))/)) { + break; + } + } + + if (name.length > 1 && match(/^((?:\+_|\+)?)\s*:/)) { + parserInput.forget(); // at last, we have the complete match now. move forward, + // convert name particles to tree objects and return: + + if (name[0] === '') { + name.shift(); + index.shift(); + } + + for (k = 0; k < name.length; k++) { + s = name[k]; + name[k] = s.charAt(0) !== '@' && s.charAt(0) !== '$' ? new tree.Keyword(s) : s.charAt(0) === '@' ? new tree.Variable("@".concat(s.slice(2, -1)), index[k], fileInfo) : new tree.Property("$".concat(s.slice(2, -1)), index[k], fileInfo); + } + + return name; + } + + parserInput.restore(); + } + } + }; + }; + + Parser.serializeVars = function (vars) { + var s = ''; + + for (var name in vars) { + if (Object.hasOwnProperty.call(vars, name)) { + var value = vars[name]; + s += "".concat((name[0] === '@' ? '' : '@') + name, ": ").concat(value).concat(String(value).slice(-1) === ';' ? '' : ';'); + } + } + + return s; + }; + + function boolean(condition) { + return condition ? Keyword.True : Keyword.False; + } + + function If(condition, trueValue, falseValue) { + return condition ? trueValue : falseValue || new Anonymous(); + } + + var boolean$1 = { + boolean: boolean, + 'if': If + }; + + var colorFunctions; + + function clamp$1(val) { + return Math.min(1, Math.max(0, val)); + } + + function hsla(origColor, hsl) { + var color = colorFunctions.hsla(hsl.h, hsl.s, hsl.l, hsl.a); + + if (color) { + if (origColor.value && /^(rgb|hsl)/.test(origColor.value)) { + color.value = origColor.value; + } else { + color.value = 'rgb'; + } + + return color; + } + } + + function toHSL(color) { + if (color.toHSL) { + return color.toHSL(); + } else { + throw new Error('Argument cannot be evaluated to a color'); + } + } + + function toHSV(color) { + if (color.toHSV) { + return color.toHSV(); + } else { + throw new Error('Argument cannot be evaluated to a color'); + } + } + + function number(n) { + if (n instanceof Dimension) { + return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); + } else if (typeof n === 'number') { + return n; + } else { + throw { + type: 'Argument', + message: 'color functions take numbers as parameters' + }; + } + } + + function scaled(n, size) { + if (n instanceof Dimension && n.unit.is('%')) { + return parseFloat(n.value * size / 100); + } else { + return number(n); + } + } + + colorFunctions = { + rgb: function rgb(r, g, b) { + var color = colorFunctions.rgba(r, g, b, 1.0); + + if (color) { + color.value = 'rgb'; + return color; + } + }, + rgba: function rgba(r, g, b, a) { + try { + if (r instanceof Color) { + if (g) { + a = number(g); + } else { + a = r.alpha; + } + + return new Color(r.rgb, a, 'rgba'); + } + + var rgb = [r, g, b].map(function (c) { + return scaled(c, 255); + }); + a = number(a); + return new Color(rgb, a, 'rgba'); + } catch (e) {} + }, + hsl: function hsl(h, s, l) { + var color = colorFunctions.hsla(h, s, l, 1.0); + + if (color) { + color.value = 'hsl'; + return color; + } + }, + hsla: function hsla(h, s, l, a) { + try { + var hue = function hue(h) { + h = h < 0 ? h + 1 : h > 1 ? h - 1 : h; + + if (h * 6 < 1) { + return m1 + (m2 - m1) * h * 6; + } else if (h * 2 < 1) { + return m2; + } else if (h * 3 < 2) { + return m1 + (m2 - m1) * (2 / 3 - h) * 6; + } else { + return m1; + } + }; + + if (h instanceof Color) { + if (s) { + a = number(s); + } else { + a = h.alpha; + } + + return new Color(h.rgb, a, 'hsla'); + } + + var m1; + var m2; + h = number(h) % 360 / 360; + s = clamp$1(number(s)); + l = clamp$1(number(l)); + a = clamp$1(number(a)); + m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; + m1 = l * 2 - m2; + var rgb = [hue(h + 1 / 3) * 255, hue(h) * 255, hue(h - 1 / 3) * 255]; + a = number(a); + return new Color(rgb, a, 'hsla'); + } catch (e) {} + }, + hsv: function hsv(h, s, v) { + return colorFunctions.hsva(h, s, v, 1.0); + }, + hsva: function hsva(h, s, v, a) { + h = number(h) % 360 / 360 * 360; + s = number(s); + v = number(v); + a = number(a); + var i; + var f; + i = Math.floor(h / 60 % 6); + f = h / 60 - i; + var vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; + var perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; + return colorFunctions.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); + }, + hue: function hue(color) { + return new Dimension(toHSL(color).h); + }, + saturation: function saturation(color) { + return new Dimension(toHSL(color).s * 100, '%'); + }, + lightness: function lightness(color) { + return new Dimension(toHSL(color).l * 100, '%'); + }, + hsvhue: function hsvhue(color) { + return new Dimension(toHSV(color).h); + }, + hsvsaturation: function hsvsaturation(color) { + return new Dimension(toHSV(color).s * 100, '%'); + }, + hsvvalue: function hsvvalue(color) { + return new Dimension(toHSV(color).v * 100, '%'); + }, + red: function red(color) { + return new Dimension(color.rgb[0]); + }, + green: function green(color) { + return new Dimension(color.rgb[1]); + }, + blue: function blue(color) { + return new Dimension(color.rgb[2]); + }, + alpha: function alpha(color) { + return new Dimension(toHSL(color).a); + }, + luma: function luma(color) { + return new Dimension(color.luma() * color.alpha * 100, '%'); + }, + luminance: function luminance(color) { + var luminance = 0.2126 * color.rgb[0] / 255 + 0.7152 * color.rgb[1] / 255 + 0.0722 * color.rgb[2] / 255; + return new Dimension(luminance * color.alpha * 100, '%'); + }, + saturate: function saturate(color, amount, method) { + // filter: saturate(3.2); + // should be kept as is, so check for color + if (!color.rgb) { + return null; + } + + var hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.s += hsl.s * amount.value / 100; + } else { + hsl.s += amount.value / 100; + } + + hsl.s = clamp$1(hsl.s); + return hsla(color, hsl); + }, + desaturate: function desaturate(color, amount, method) { + var hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.s -= hsl.s * amount.value / 100; + } else { + hsl.s -= amount.value / 100; + } + + hsl.s = clamp$1(hsl.s); + return hsla(color, hsl); + }, + lighten: function lighten(color, amount, method) { + var hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.l += hsl.l * amount.value / 100; + } else { + hsl.l += amount.value / 100; + } + + hsl.l = clamp$1(hsl.l); + return hsla(color, hsl); + }, + darken: function darken(color, amount, method) { + var hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.l -= hsl.l * amount.value / 100; + } else { + hsl.l -= amount.value / 100; + } + + hsl.l = clamp$1(hsl.l); + return hsla(color, hsl); + }, + fadein: function fadein(color, amount, method) { + var hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.a += hsl.a * amount.value / 100; + } else { + hsl.a += amount.value / 100; + } + + hsl.a = clamp$1(hsl.a); + return hsla(color, hsl); + }, + fadeout: function fadeout(color, amount, method) { + var hsl = toHSL(color); + + if (typeof method !== 'undefined' && method.value === 'relative') { + hsl.a -= hsl.a * amount.value / 100; + } else { + hsl.a -= amount.value / 100; + } + + hsl.a = clamp$1(hsl.a); + return hsla(color, hsl); + }, + fade: function fade(color, amount) { + var hsl = toHSL(color); + hsl.a = amount.value / 100; + hsl.a = clamp$1(hsl.a); + return hsla(color, hsl); + }, + spin: function spin(color, amount) { + var hsl = toHSL(color); + var hue = (hsl.h + amount.value) % 360; + hsl.h = hue < 0 ? 360 + hue : hue; + return hsla(color, hsl); + }, + // + // Copyright (c) 2006-2009 Hampton Catlin, Natalie Weizenbaum, and Chris Eppstein + // http://sass-lang.com + // + mix: function mix(color1, color2, weight) { + if (!weight) { + weight = new Dimension(50); + } + + var p = weight.value / 100.0; + var w = p * 2 - 1; + var a = toHSL(color1).a - toHSL(color2).a; + var w1 = ((w * a == -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0; + var w2 = 1 - w1; + var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; + var alpha = color1.alpha * p + color2.alpha * (1 - p); + return new Color(rgb, alpha); + }, + greyscale: function greyscale(color) { + return colorFunctions.desaturate(color, new Dimension(100)); + }, + contrast: function contrast(color, dark, light, threshold) { + // filter: contrast(3.2); + // should be kept as is, so check for color + if (!color.rgb) { + return null; + } + + if (typeof light === 'undefined') { + light = colorFunctions.rgba(255, 255, 255, 1.0); + } + + if (typeof dark === 'undefined') { + dark = colorFunctions.rgba(0, 0, 0, 1.0); + } // Figure out which is actually light and dark: + + + if (dark.luma() > light.luma()) { + var t = light; + light = dark; + dark = t; + } + + if (typeof threshold === 'undefined') { + threshold = 0.43; + } else { + threshold = number(threshold); + } + + if (color.luma() < threshold) { + return light; + } else { + return dark; + } + }, + // Changes made in 2.7.0 - Reverted in 3.0.0 + // contrast: function (color, color1, color2, threshold) { + // // Return which of `color1` and `color2` has the greatest contrast with `color` + // // according to the standard WCAG contrast ratio calculation. + // // http://www.w3.org/TR/WCAG20/#contrast-ratiodef + // // The threshold param is no longer used, in line with SASS. + // // filter: contrast(3.2); + // // should be kept as is, so check for color + // if (!color.rgb) { + // return null; + // } + // if (typeof color1 === 'undefined') { + // color1 = colorFunctions.rgba(0, 0, 0, 1.0); + // } + // if (typeof color2 === 'undefined') { + // color2 = colorFunctions.rgba(255, 255, 255, 1.0); + // } + // var contrast1, contrast2; + // var luma = color.luma(); + // var luma1 = color1.luma(); + // var luma2 = color2.luma(); + // // Calculate contrast ratios for each color + // if (luma > luma1) { + // contrast1 = (luma + 0.05) / (luma1 + 0.05); + // } else { + // contrast1 = (luma1 + 0.05) / (luma + 0.05); + // } + // if (luma > luma2) { + // contrast2 = (luma + 0.05) / (luma2 + 0.05); + // } else { + // contrast2 = (luma2 + 0.05) / (luma + 0.05); + // } + // if (contrast1 > contrast2) { + // return color1; + // } else { + // return color2; + // } + // }, + argb: function argb(color) { + return new Anonymous(color.toARGB()); + }, + color: function color(c) { + if (c instanceof Quoted && /^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})$/i.test(c.value)) { + var val = c.value.slice(1); + return new Color(val, undefined, "#".concat(val)); + } + + if (c instanceof Color || (c = Color.fromKeyword(c.value))) { + c.value = undefined; + return c; + } + + throw { + type: 'Argument', + message: 'argument must be a color keyword or 3|4|6|8 digit hex e.g. #FFF' + }; + }, + tint: function tint(color, amount) { + return colorFunctions.mix(colorFunctions.rgb(255, 255, 255), color, amount); + }, + shade: function shade(color, amount) { + return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount); + } + }; + var color = colorFunctions; + + // ref: http://www.w3.org/TR/compositing-1 + + function colorBlend(mode, color1, color2) { + var ab = color1.alpha; // result + + var // backdrop + cb; + var as = color2.alpha; + var // source + cs; + var ar; + var cr; + var r = []; + ar = as + ab * (1 - as); + + for (var i = 0; i < 3; i++) { + cb = color1.rgb[i] / 255; + cs = color2.rgb[i] / 255; + cr = mode(cb, cs); + + if (ar) { + cr = (as * cs + ab * (cb - as * (cb + cs - cr))) / ar; + } + + r[i] = cr * 255; + } + + return new Color(r, ar); + } + + var colorBlendModeFunctions = { + multiply: function multiply(cb, cs) { + return cb * cs; + }, + screen: function screen(cb, cs) { + return cb + cs - cb * cs; + }, + overlay: function overlay(cb, cs) { + cb *= 2; + return cb <= 1 ? colorBlendModeFunctions.multiply(cb, cs) : colorBlendModeFunctions.screen(cb - 1, cs); + }, + softlight: function softlight(cb, cs) { + var d = 1; + var e = cb; + + if (cs > 0.5) { + e = 1; + d = cb > 0.25 ? Math.sqrt(cb) : ((16 * cb - 12) * cb + 4) * cb; + } + + return cb - (1 - 2 * cs) * e * (d - cb); + }, + hardlight: function hardlight(cb, cs) { + return colorBlendModeFunctions.overlay(cs, cb); + }, + difference: function difference(cb, cs) { + return Math.abs(cb - cs); + }, + exclusion: function exclusion(cb, cs) { + return cb + cs - 2 * cb * cs; + }, + // non-w3c functions: + average: function average(cb, cs) { + return (cb + cs) / 2; + }, + negation: function negation(cb, cs) { + return 1 - Math.abs(cb + cs - 1); + } + }; + + for (var f in colorBlendModeFunctions) { + if (colorBlendModeFunctions.hasOwnProperty(f)) { + colorBlend[f] = colorBlend.bind(null, colorBlendModeFunctions[f]); + } + } + + var dataUri = (function (environment) { + var fallback = function fallback(functionThis, node) { + return new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context); + }; + + return { + 'data-uri': function dataUri(mimetypeNode, filePathNode) { + if (!filePathNode) { + filePathNode = mimetypeNode; + mimetypeNode = null; + } + + var mimetype = mimetypeNode && mimetypeNode.value; + var filePath = filePathNode.value; + var currentFileInfo = this.currentFileInfo; + var currentDirectory = currentFileInfo.rewriteUrls ? currentFileInfo.currentDirectory : currentFileInfo.entryPath; + var fragmentStart = filePath.indexOf('#'); + var fragment = ''; + + if (fragmentStart !== -1) { + fragment = filePath.slice(fragmentStart); + filePath = filePath.slice(0, fragmentStart); + } + + var context = clone(this.context); + context.rawBuffer = true; + var fileManager = environment.getFileManager(filePath, currentDirectory, context, environment, true); + + if (!fileManager) { + return fallback(this, filePathNode); + } + + var useBase64 = false; // detect the mimetype if not given + + if (!mimetypeNode) { + mimetype = environment.mimeLookup(filePath); + + if (mimetype === 'image/svg+xml') { + useBase64 = false; + } else { + // use base 64 unless it's an ASCII or UTF-8 format + var charset = environment.charsetLookup(mimetype); + useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; + } + + if (useBase64) { + mimetype += ';base64'; + } + } else { + useBase64 = /;base64$/.test(mimetype); + } + + var fileSync = fileManager.loadFileSync(filePath, currentDirectory, context, environment); + + if (!fileSync.contents) { + logger.warn("Skipped data-uri embedding of ".concat(filePath, " because file not found")); + return fallback(this, filePathNode || mimetypeNode); + } + + var buf = fileSync.contents; + + if (useBase64 && !environment.encodeBase64) { + return fallback(this, filePathNode); + } + + buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf); + var uri = "data:".concat(mimetype, ",").concat(buf).concat(fragment); + return new URL(new Quoted("\"".concat(uri, "\""), uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); + } + }; + }); + + var getItemsFromNode = function getItemsFromNode(node) { + // handle non-array values as an array of length 1 + // return 'undefined' if index is invalid + var items = Array.isArray(node.value) ? node.value : Array(node); + return items; + }; + + var list = { + _SELF: function _SELF(n) { + return n; + }, + extract: function extract(values, index) { + index = index.value - 1; // (1-based index) + + return getItemsFromNode(values)[index]; + }, + length: function length(values) { + return new Dimension(getItemsFromNode(values).length); + }, + + /** + * Creates a Less list of incremental values. + * Modeled after Lodash's range function, also exists natively in PHP + * + * @param {Dimension} [start=1] + * @param {Dimension} end - e.g. 10 or 10px - unit is added to output + * @param {Dimension} [step=1] + */ + range: function range(start, end, step) { + var from; + var to; + var stepValue = 1; + var list = []; + + if (end) { + to = end; + from = start.value; + + if (step) { + stepValue = step.value; + } + } else { + from = 1; + to = start; + } + + for (var i = from; i <= to.value; i += stepValue) { + list.push(new Dimension(i, to.unit)); + } + + return new Expression(list); + }, + each: function each(list, rs) { + var rules = []; + var newRules; + var iterator; + + if (list.value && !(list instanceof Quoted)) { + if (Array.isArray(list.value)) { + iterator = list.value; + } else { + iterator = [list.value]; + } + } else if (list.ruleset) { + iterator = list.ruleset.rules; + } else if (list.rules) { + iterator = list.rules; + } else if (Array.isArray(list)) { + iterator = list; + } else { + iterator = [list]; + } + + var valueName = '@value'; + var keyName = '@key'; + var indexName = '@index'; + + if (rs.params) { + valueName = rs.params[0] && rs.params[0].name; + keyName = rs.params[1] && rs.params[1].name; + indexName = rs.params[2] && rs.params[2].name; + rs = rs.rules; + } else { + rs = rs.ruleset; + } + + for (var i = 0; i < iterator.length; i++) { + var key = void 0; + var value = void 0; + var item = iterator[i]; + + if (item instanceof Declaration) { + key = typeof item.name === 'string' ? item.name : item.name[0].value; + value = item.value; + } else { + key = new Dimension(i + 1); + value = item; + } + + if (item instanceof Comment) { + continue; + } + + newRules = rs.rules.slice(0); + + if (valueName) { + newRules.push(new Declaration(valueName, value, false, false, this.index, this.currentFileInfo)); + } + + if (indexName) { + newRules.push(new Declaration(indexName, new Dimension(i + 1), false, false, this.index, this.currentFileInfo)); + } + + if (keyName) { + newRules.push(new Declaration(keyName, key, false, false, this.index, this.currentFileInfo)); + } + + rules.push(new Ruleset([new Selector([new Element("", '&')])], newRules, rs.strictImports, rs.visibilityInfo())); + } + + return new Ruleset([new Selector([new Element("", '&')])], rules, rs.strictImports, rs.visibilityInfo()).eval(this.context); + } + }; + + var MathHelper = function MathHelper(fn, unit, n) { + if (!(n instanceof Dimension)) { + throw { + type: 'Argument', + message: 'argument must be a number' + }; + } + + if (unit == null) { + unit = n.unit; + } else { + n = n.unify(); + } + + return new Dimension(fn(parseFloat(n.value)), unit); + }; + + var mathFunctions = { + // name, unit + ceil: null, + floor: null, + sqrt: null, + abs: null, + tan: '', + sin: '', + cos: '', + atan: 'rad', + asin: 'rad', + acos: 'rad' + }; + + for (var f$1 in mathFunctions) { + if (mathFunctions.hasOwnProperty(f$1)) { + mathFunctions[f$1] = MathHelper.bind(null, Math[f$1], mathFunctions[f$1]); + } + } + + mathFunctions.round = function (n, f) { + var fraction = typeof f === 'undefined' ? 0 : f.value; + return MathHelper(function (num) { + return num.toFixed(fraction); + }, null, n); + }; + + var minMax = function minMax(isMin, args) { + args = Array.prototype.slice.call(args); + + switch (args.length) { + case 0: + throw { + type: 'Argument', + message: 'one or more arguments required' + }; + } + + var i; // key is the unit.toString() for unified Dimension values, + + var j; + var current; + var currentUnified; + var referenceUnified; + var unit; + var unitStatic; + var unitClone; + var // elems only contains original argument values. + order = []; + var values = {}; // value is the index into the order array. + + for (i = 0; i < args.length; i++) { + current = args[i]; + + if (!(current instanceof Dimension)) { + if (Array.isArray(args[i].value)) { + Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value)); + } + + continue; + } + + currentUnified = current.unit.toString() === '' && unitClone !== undefined ? new Dimension(current.value, unitClone).unify() : current.unify(); + unit = currentUnified.unit.toString() === '' && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString(); + unitStatic = unit !== '' && unitStatic === undefined || unit !== '' && order[0].unify().unit.toString() === '' ? unit : unitStatic; + unitClone = unit !== '' && unitClone === undefined ? current.unit.toString() : unitClone; + j = values[''] !== undefined && unit !== '' && unit === unitStatic ? values[''] : values[unit]; + + if (j === undefined) { + if (unitStatic !== undefined && unit !== unitStatic) { + throw { + type: 'Argument', + message: 'incompatible types' + }; + } + + values[unit] = order.length; + order.push(current); + continue; + } + + referenceUnified = order[j].unit.toString() === '' && unitClone !== undefined ? new Dimension(order[j].value, unitClone).unify() : order[j].unify(); + + if (isMin && currentUnified.value < referenceUnified.value || !isMin && currentUnified.value > referenceUnified.value) { + order[j] = current; + } + } + + if (order.length == 1) { + return order[0]; + } + + args = order.map(function (a) { + return a.toCSS(this.context); + }).join(this.context.compress ? ',' : ', '); + return new Anonymous("".concat(isMin ? 'min' : 'max', "(").concat(args, ")")); + }; + + var number$1 = { + min: function min() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return minMax(true, args); + }, + max: function max() { + for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + return minMax(false, args); + }, + convert: function convert(val, unit) { + return val.convertTo(unit.value); + }, + pi: function pi() { + return new Dimension(Math.PI); + }, + mod: function mod(a, b) { + return new Dimension(a.value % b.value, a.unit); + }, + pow: function pow(x, y) { + if (typeof x === 'number' && typeof y === 'number') { + x = new Dimension(x); + y = new Dimension(y); + } else if (!(x instanceof Dimension) || !(y instanceof Dimension)) { + throw { + type: 'Argument', + message: 'arguments must be numbers' + }; + } + + return new Dimension(Math.pow(x.value, y.value), x.unit); + }, + percentage: function percentage(n) { + var result = MathHelper(function (num) { + return num * 100; + }, '%', n); + return result; + } + }; + + var string = { + e: function e(str) { + return new Quoted('"', str instanceof JavaScript ? str.evaluated : str.value, true); + }, + escape: function escape(str) { + return new Anonymous(encodeURI(str.value).replace(/=/g, '%3D').replace(/:/g, '%3A').replace(/#/g, '%23').replace(/;/g, '%3B').replace(/\(/g, '%28').replace(/\)/g, '%29')); + }, + replace: function replace(string, pattern, replacement, flags) { + var result = string.value; + replacement = replacement.type === 'Quoted' ? replacement.value : replacement.toCSS(); + result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement); + return new Quoted(string.quote || '', result, string.escaped); + }, + '%': function _(string + /* arg, arg, ... */ + ) { + var args = Array.prototype.slice.call(arguments, 1); + var result = string.value; + + var _loop = function _loop(i) { + /* jshint loopfunc:true */ + result = result.replace(/%[sda]/i, function (token) { + var value = args[i].type === 'Quoted' && token.match(/s/i) ? args[i].value : args[i].toCSS(); + return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; + }); + }; + + for (var i = 0; i < args.length; i++) { + _loop(i); + } + + result = result.replace(/%%/g, '%'); + return new Quoted(string.quote || '', result, string.escaped); + } + }; + + var svg = (function (environment) { + return { + 'svg-gradient': function svgGradient(direction) { + var stops; + var gradientDirectionSvg; + var gradientType = 'linear'; + var rectangleDimension = 'x="0" y="0" width="1" height="1"'; + var renderEnv = { + compress: false + }; + var returner; + var directionValue = direction.toCSS(renderEnv); + var i; + var color; + var position; + var positionValue; + var alpha; + + function throwArgumentDescriptor() { + throw { + type: 'Argument', + message: 'svg-gradient expects direction, start_color [start_position], [color position,]...,' + ' end_color [end_position] or direction, color list' + }; + } + + if (arguments.length == 2) { + if (arguments[1].value.length < 2) { + throwArgumentDescriptor(); + } + + stops = arguments[1].value; + } else if (arguments.length < 3) { + throwArgumentDescriptor(); + } else { + stops = Array.prototype.slice.call(arguments, 1); + } + + switch (directionValue) { + case 'to bottom': + gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"'; + break; + + case 'to right': + gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"'; + break; + + case 'to bottom right': + gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"'; + break; + + case 'to top right': + gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"'; + break; + + case 'ellipse': + case 'ellipse at center': + gradientType = 'radial'; + gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"'; + rectangleDimension = 'x="-50" y="-50" width="101" height="101"'; + break; + + default: + throw { + type: 'Argument', + message: 'svg-gradient direction must be \'to bottom\', \'to right\',' + ' \'to bottom right\', \'to top right\' or \'ellipse at center\'' + }; + } + + returner = "<".concat(gradientType, "Gradient id=\"g\" ").concat(gradientDirectionSvg, ">"); + + for (i = 0; i < stops.length; i += 1) { + if (stops[i] instanceof Expression) { + color = stops[i].value[0]; + position = stops[i].value[1]; + } else { + color = stops[i]; + position = undefined; + } + + if (!(color instanceof Color) || !((i === 0 || i + 1 === stops.length) && position === undefined) && !(position instanceof Dimension)) { + throwArgumentDescriptor(); + } + + positionValue = position ? position.toCSS(renderEnv) : i === 0 ? '0%' : '100%'; + alpha = color.alpha; + returner += ""); + } + + returner += ""); + returner = encodeURIComponent(returner); + returner = "data:image/svg+xml,".concat(returner); + return new URL(new Quoted("'".concat(returner, "'"), returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); + } + }; + }); + + var isa = function isa(n, Type) { + return n instanceof Type ? Keyword.True : Keyword.False; + }; + + var isunit = function isunit(n, unit) { + if (unit === undefined) { + throw { + type: 'Argument', + message: 'missing the required second argument to isunit.' + }; + } + + unit = typeof unit.value === 'string' ? unit.value : unit; + + if (typeof unit !== 'string') { + throw { + type: 'Argument', + message: 'Second argument to isunit should be a unit or a string.' + }; + } + + return n instanceof Dimension && n.unit.is(unit) ? Keyword.True : Keyword.False; + }; + + var types = { + isruleset: function isruleset(n) { + return isa(n, DetachedRuleset); + }, + iscolor: function iscolor(n) { + return isa(n, Color); + }, + isnumber: function isnumber(n) { + return isa(n, Dimension); + }, + isstring: function isstring(n) { + return isa(n, Quoted); + }, + iskeyword: function iskeyword(n) { + return isa(n, Keyword); + }, + isurl: function isurl(n) { + return isa(n, URL); + }, + ispixel: function ispixel(n) { + return isunit(n, 'px'); + }, + ispercentage: function ispercentage(n) { + return isunit(n, '%'); + }, + isem: function isem(n) { + return isunit(n, 'em'); + }, + isunit: isunit, + unit: function unit(val, _unit) { + if (!(val instanceof Dimension)) { + throw { + type: 'Argument', + message: "the first argument to unit must be a number".concat(val instanceof Operation ? '. Have you forgotten parenthesis?' : '') + }; + } + + if (_unit) { + if (_unit instanceof Keyword) { + _unit = _unit.value; + } else { + _unit = _unit.toCSS(); + } + } else { + _unit = ''; + } + + return new Dimension(val.value, _unit); + }, + 'get-unit': function getUnit(n) { + return new Anonymous(n.unit); + } + }; + + var Functions = (function (environment) { + var functions = { + functionRegistry: functionRegistry, + functionCaller: functionCaller + }; // register functions + + functionRegistry.addMultiple(boolean$1); + functionRegistry.add('default', defaultFunc.eval.bind(defaultFunc)); + functionRegistry.addMultiple(color); + functionRegistry.addMultiple(colorBlend); + functionRegistry.addMultiple(dataUri(environment)); + functionRegistry.addMultiple(list); + functionRegistry.addMultiple(mathFunctions); + functionRegistry.addMultiple(number$1); + functionRegistry.addMultiple(string); + functionRegistry.addMultiple(svg()); + functionRegistry.addMultiple(types); + return functions; + }); + + var sourceMapOutput = (function (environment) { + var SourceMapOutput = + /*#__PURE__*/ + function () { + function SourceMapOutput(options) { + _classCallCheck(this, SourceMapOutput); + + this._css = []; + this._rootNode = options.rootNode; + this._contentsMap = options.contentsMap; + this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap; + + if (options.sourceMapFilename) { + this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/'); + } + + this._outputFilename = options.outputFilename; + this.sourceMapURL = options.sourceMapURL; + + if (options.sourceMapBasepath) { + this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/'); + } + + if (options.sourceMapRootpath) { + this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/'); + + if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') { + this._sourceMapRootpath += '/'; + } + } else { + this._sourceMapRootpath = ''; + } + + this._outputSourceFiles = options.outputSourceFiles; + this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator(); + this._lineNumber = 0; + this._column = 0; + } + + _createClass(SourceMapOutput, [{ + key: "removeBasepath", + value: function removeBasepath(path) { + if (this._sourceMapBasepath && path.indexOf(this._sourceMapBasepath) === 0) { + path = path.substring(this._sourceMapBasepath.length); + + if (path.charAt(0) === '\\' || path.charAt(0) === '/') { + path = path.substring(1); + } + } + + return path; + } + }, { + key: "normalizeFilename", + value: function normalizeFilename(filename) { + filename = filename.replace(/\\/g, '/'); + filename = this.removeBasepath(filename); + return (this._sourceMapRootpath || '') + filename; + } + }, { + key: "add", + value: function add(chunk, fileInfo, index, mapLines) { + // ignore adding empty strings + if (!chunk) { + return; + } + + var lines; + var sourceLines; + var columns; + var sourceColumns; + var i; + + if (fileInfo && fileInfo.filename) { + var inputSource = this._contentsMap[fileInfo.filename]; // remove vars/banner added to the top of the file + + if (this._contentsIgnoredCharsMap[fileInfo.filename]) { + // adjust the index + index -= this._contentsIgnoredCharsMap[fileInfo.filename]; + + if (index < 0) { + index = 0; + } // adjust the source + + + inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]); + } // ignore empty content + + + if (inputSource === undefined) { + return; + } + + inputSource = inputSource.substring(0, index); + sourceLines = inputSource.split('\n'); + sourceColumns = sourceLines[sourceLines.length - 1]; + } + + lines = chunk.split('\n'); + columns = lines[lines.length - 1]; + + if (fileInfo && fileInfo.filename) { + if (!mapLines) { + this._sourceMapGenerator.addMapping({ + generated: { + line: this._lineNumber + 1, + column: this._column + }, + original: { + line: sourceLines.length, + column: sourceColumns.length + }, + source: this.normalizeFilename(fileInfo.filename) + }); + } else { + for (i = 0; i < lines.length; i++) { + this._sourceMapGenerator.addMapping({ + generated: { + line: this._lineNumber + i + 1, + column: i === 0 ? this._column : 0 + }, + original: { + line: sourceLines.length + i, + column: i === 0 ? sourceColumns.length : 0 + }, + source: this.normalizeFilename(fileInfo.filename) + }); + } + } + } + + if (lines.length === 1) { + this._column += columns.length; + } else { + this._lineNumber += lines.length - 1; + this._column = columns.length; + } + + this._css.push(chunk); + } + }, { + key: "isEmpty", + value: function isEmpty() { + return this._css.length === 0; + } + }, { + key: "toCSS", + value: function toCSS(context) { + this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ + file: this._outputFilename, + sourceRoot: null + }); + + if (this._outputSourceFiles) { + for (var filename in this._contentsMap) { + if (this._contentsMap.hasOwnProperty(filename)) { + var source = this._contentsMap[filename]; + + if (this._contentsIgnoredCharsMap[filename]) { + source = source.slice(this._contentsIgnoredCharsMap[filename]); + } + + this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source); + } + } + } + + this._rootNode.genCSS(context, this); + + if (this._css.length > 0) { + var sourceMapURL; + var sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON()); + + if (this.sourceMapURL) { + sourceMapURL = this.sourceMapURL; + } else if (this._sourceMapFilename) { + sourceMapURL = this._sourceMapFilename; + } + + this.sourceMapURL = sourceMapURL; + this.sourceMap = sourceMapContent; + } + + return this._css.join(''); + } + }]); + + return SourceMapOutput; + }(); + + return SourceMapOutput; + }); + + var sourceMapBuilder = (function (SourceMapOutput, environment) { + var SourceMapBuilder = + /*#__PURE__*/ + function () { + function SourceMapBuilder(options) { + _classCallCheck(this, SourceMapBuilder); + + this.options = options; + } + + _createClass(SourceMapBuilder, [{ + key: "toCSS", + value: function toCSS(rootNode, options, imports) { + var sourceMapOutput = new SourceMapOutput({ + contentsIgnoredCharsMap: imports.contentsIgnoredChars, + rootNode: rootNode, + contentsMap: imports.contents, + sourceMapFilename: this.options.sourceMapFilename, + sourceMapURL: this.options.sourceMapURL, + outputFilename: this.options.sourceMapOutputFilename, + sourceMapBasepath: this.options.sourceMapBasepath, + sourceMapRootpath: this.options.sourceMapRootpath, + outputSourceFiles: this.options.outputSourceFiles, + sourceMapGenerator: this.options.sourceMapGenerator, + sourceMapFileInline: this.options.sourceMapFileInline + }); + var css = sourceMapOutput.toCSS(options); + this.sourceMap = sourceMapOutput.sourceMap; + this.sourceMapURL = sourceMapOutput.sourceMapURL; + + if (this.options.sourceMapInputFilename) { + this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename); + } + + if (this.options.sourceMapBasepath !== undefined && this.sourceMapURL !== undefined) { + this.sourceMapURL = sourceMapOutput.removeBasepath(this.sourceMapURL); + } + + return css + this.getCSSAppendage(); + } + }, { + key: "getCSSAppendage", + value: function getCSSAppendage() { + var sourceMapURL = this.sourceMapURL; + + if (this.options.sourceMapFileInline) { + if (this.sourceMap === undefined) { + return ''; + } + + sourceMapURL = "data:application/json;base64,".concat(environment.encodeBase64(this.sourceMap)); + } + + if (sourceMapURL) { + return "/*# sourceMappingURL=".concat(sourceMapURL, " */"); + } + + return ''; + } + }, { + key: "getExternalSourceMap", + value: function getExternalSourceMap() { + return this.sourceMap; + } + }, { + key: "setExternalSourceMap", + value: function setExternalSourceMap(sourceMap) { + this.sourceMap = sourceMap; + } + }, { + key: "isInline", + value: function isInline() { + return this.options.sourceMapFileInline; + } + }, { + key: "getSourceMapURL", + value: function getSourceMapURL() { + return this.sourceMapURL; + } + }, { + key: "getOutputFilename", + value: function getOutputFilename() { + return this.options.sourceMapOutputFilename; + } + }, { + key: "getInputFilename", + value: function getInputFilename() { + return this.sourceMapInputFilename; + } + }]); + + return SourceMapBuilder; + }(); + + return SourceMapBuilder; + }); + + var transformTree = (function (root) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var evaldRoot; + var variables = options.variables; + var evalEnv = new contexts.Eval(options); // + // Allows setting variables with a hash, so: + // + // `{ color: new tree.Color('#f01') }` will become: + // + // new tree.Declaration('@color', + // new tree.Value([ + // new tree.Expression([ + // new tree.Color('#f01') + // ]) + // ]) + // ) + // + + if (_typeof(variables) === 'object' && !Array.isArray(variables)) { + variables = Object.keys(variables).map(function (k) { + var value = variables[k]; + + if (!(value instanceof tree.Value)) { + if (!(value instanceof tree.Expression)) { + value = new tree.Expression([value]); + } + + value = new tree.Value([value]); + } + + return new tree.Declaration("@".concat(k), value, false, null, 0); + }); + evalEnv.frames = [new tree.Ruleset(null, variables)]; + } + + var visitors$1 = [new visitors.JoinSelectorVisitor(), new visitors.MarkVisibleSelectorsVisitor(true), new visitors.ExtendVisitor(), new visitors.ToCSSVisitor({ + compress: Boolean(options.compress) + })]; + var preEvalVisitors = []; + var v; + var visitorIterator; + /** + * first() / get() allows visitors to be added while visiting + * + * @todo Add scoping for visitors just like functions for @plugin; right now they're global + */ + + if (options.pluginManager) { + visitorIterator = options.pluginManager.visitor(); + + for (var i = 0; i < 2; i++) { + visitorIterator.first(); + + while (v = visitorIterator.get()) { + if (v.isPreEvalVisitor) { + if (i === 0 || preEvalVisitors.indexOf(v) === -1) { + preEvalVisitors.push(v); + v.run(root); + } + } else { + if (i === 0 || visitors$1.indexOf(v) === -1) { + if (v.isPreVisitor) { + visitors$1.unshift(v); + } else { + visitors$1.push(v); + } + } + } + } + } + } + + evaldRoot = root.eval(evalEnv); + + for (var i = 0; i < visitors$1.length; i++) { + visitors$1[i].run(evaldRoot); + } // Run any remaining visitors added after eval pass + + + if (options.pluginManager) { + visitorIterator.first(); + + while (v = visitorIterator.get()) { + if (visitors$1.indexOf(v) === -1 && preEvalVisitors.indexOf(v) === -1) { + v.run(evaldRoot); + } + } + } + + return evaldRoot; + }); + + var parseTree = (function (SourceMapBuilder) { + var ParseTree = + /*#__PURE__*/ + function () { + function ParseTree(root, imports) { + _classCallCheck(this, ParseTree); + + this.root = root; + this.imports = imports; + } + + _createClass(ParseTree, [{ + key: "toCSS", + value: function toCSS(options) { + var evaldRoot; + var result = {}; + var sourceMapBuilder; + + try { + evaldRoot = transformTree(this.root, options); + } catch (e) { + throw new LessError(e, this.imports); + } + + try { + var compress = Boolean(options.compress); + + if (compress) { + logger.warn('The compress option has been deprecated. ' + 'We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.'); + } + + var toCSSOptions = { + compress: compress, + dumpLineNumbers: options.dumpLineNumbers, + strictUnits: Boolean(options.strictUnits), + numPrecision: 8 + }; + + if (options.sourceMap) { + sourceMapBuilder = new SourceMapBuilder(options.sourceMap); + result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports); + } else { + result.css = evaldRoot.toCSS(toCSSOptions); + } + } catch (e) { + throw new LessError(e, this.imports); + } + + if (options.pluginManager) { + var postProcessors = options.pluginManager.getPostProcessors(); + + for (var i = 0; i < postProcessors.length; i++) { + result.css = postProcessors[i].process(result.css, { + sourceMap: sourceMapBuilder, + options: options, + imports: this.imports + }); + } + } + + if (options.sourceMap) { + result.map = sourceMapBuilder.getExternalSourceMap(); + } + + result.imports = []; + + for (var file in this.imports.files) { + if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) { + result.imports.push(file); + } + } + + return result; + } + }]); + + return ParseTree; + }(); + + return ParseTree; + }); + + var importManager = (function (environment) { + // FileInfo = { + // 'rewriteUrls' - option - whether to adjust URL's to be relative + // 'filename' - full resolved filename of current file + // 'rootpath' - path to append to normal URLs for this node + // 'currentDirectory' - path to the current file, absolute + // 'rootFilename' - filename of the base file + // 'entryPath' - absolute path to the entry file + // 'reference' - whether the file should not be output and only output parts that are referenced + var ImportManager = + /*#__PURE__*/ + function () { + function ImportManager(less, context, rootFileInfo) { + _classCallCheck(this, ImportManager); + + this.less = less; + this.rootFilename = rootFileInfo.filename; + this.paths = context.paths || []; // Search paths, when importing + + this.contents = {}; // map - filename to contents of all the files + + this.contentsIgnoredChars = {}; // map - filename to lines at the beginning of each file to ignore + + this.mime = context.mime; + this.error = null; + this.context = context; // Deprecated? Unused outside of here, could be useful. + + this.queue = []; // Files which haven't been imported yet + + this.files = {}; // Holds the imported parse trees. + } + /** + * Add an import to be imported + * @param path - the raw path + * @param tryAppendExtension - whether to try appending a file extension (.less or .js if the path has no extension) + * @param currentFileInfo - the current file info (used for instance to work out relative paths) + * @param importOptions - import options + * @param callback - callback for when it is imported + */ + + + _createClass(ImportManager, [{ + key: "push", + value: function push(path, tryAppendExtension, currentFileInfo, importOptions, callback) { + var importManager = this; + var pluginLoader = this.context.pluginManager.Loader; + this.queue.push(path); + + var fileParsedFunc = function fileParsedFunc(e, root, fullPath) { + importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue + + var importedEqualsRoot = fullPath === importManager.rootFilename; + + if (importOptions.optional && e) { + callback(null, { + rules: [] + }, false, null); + logger.info("The file ".concat(fullPath, " was skipped because it was not found and the import was marked optional.")); + } else { + // Inline imports aren't cached here. + // If we start to cache them, please make sure they won't conflict with non-inline imports of the + // same name as they used to do before this comment and the condition below have been added. + if (!importManager.files[fullPath] && !importOptions.inline) { + importManager.files[fullPath] = { + root: root, + options: importOptions + }; + } + + if (e && !importManager.error) { + importManager.error = e; + } + + callback(e, root, importedEqualsRoot, fullPath); + } + }; + + var newFileInfo = { + rewriteUrls: this.context.rewriteUrls, + entryPath: currentFileInfo.entryPath, + rootpath: currentFileInfo.rootpath, + rootFilename: currentFileInfo.rootFilename + }; + var fileManager = environment.getFileManager(path, currentFileInfo.currentDirectory, this.context, environment); + + if (!fileManager) { + fileParsedFunc({ + message: "Could not find a file-manager for ".concat(path) + }); + return; + } + + var loadFileCallback = function loadFileCallback(loadedFile) { + var plugin; + var resolvedFilename = loadedFile.filename; + var contents = loadedFile.contents.replace(/^\uFEFF/, ''); // Pass on an updated rootpath if path of imported file is relative and file + // is in a (sub|sup) directory + // + // Examples: + // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/', + // then rootpath should become 'less/module/nav/' + // - If path of imported file is '../mixins.less' and rootpath is 'less/', + // then rootpath should become 'less/../' + + newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename); + + if (newFileInfo.rewriteUrls) { + newFileInfo.rootpath = fileManager.join(importManager.context.rootpath || '', fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath)); + + if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) { + newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath); + } + } + + newFileInfo.filename = resolvedFilename; + var newEnv = new contexts.Parse(importManager.context); + newEnv.processImports = false; + importManager.contents[resolvedFilename] = contents; + + if (currentFileInfo.reference || importOptions.reference) { + newFileInfo.reference = true; + } + + if (importOptions.isPlugin) { + plugin = pluginLoader.evalPlugin(contents, newEnv, importManager, importOptions.pluginArgs, newFileInfo); + + if (plugin instanceof LessError) { + fileParsedFunc(plugin, null, resolvedFilename); + } else { + fileParsedFunc(null, plugin, resolvedFilename); + } + } else if (importOptions.inline) { + fileParsedFunc(null, contents, resolvedFilename); + } else { + // import (multiple) parse trees apparently get altered and can't be cached. + // TODO: investigate why this is + if (importManager.files[resolvedFilename] && !importManager.files[resolvedFilename].options.multiple && !importOptions.multiple) { + fileParsedFunc(null, importManager.files[resolvedFilename].root, resolvedFilename); + } else { + new Parser(newEnv, importManager, newFileInfo).parse(contents, function (e, root) { + fileParsedFunc(e, root, resolvedFilename); + }); + } + } + }; + + var promise; + var context = clone(this.context); + + if (tryAppendExtension) { + context.ext = importOptions.isPlugin ? '.js' : '.less'; + } + + if (importOptions.isPlugin) { + context.mime = 'application/javascript'; + promise = pluginLoader.loadPlugin(path, currentFileInfo.currentDirectory, context, environment, fileManager); + } else { + promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, context, environment, function (err, loadedFile) { + if (err) { + fileParsedFunc(err); + } else { + loadFileCallback(loadedFile); + } + }); + } + + if (promise) { + promise.then(loadFileCallback, fileParsedFunc); + } + } + }]); + + return ImportManager; + }(); + + return ImportManager; + }); + + var Render = (function (environment, ParseTree, ImportManager) { + var render = function render(input, options, callback) { + if (typeof options === 'function') { + callback = options; + options = copyOptions(this.options, {}); + } else { + options = copyOptions(this.options, options || {}); + } + + if (!callback) { + var self = this; + return new Promise(function (resolve, reject) { + render.call(self, input, options, function (err, output) { + if (err) { + reject(err); + } else { + resolve(output); + } + }); + }); + } else { + this.parse(input, options, function (err, root, imports, options) { + if (err) { + return callback(err); + } + + var result; + + try { + var parseTree = new ParseTree(root, imports); + result = parseTree.toCSS(options); + } catch (err) { + return callback(err); + } + + callback(null, result); + }); + } + }; + + return render; + }); + + /** + * Plugin Manager + */ + var PluginManager = + /*#__PURE__*/ + function () { + function PluginManager(less) { + _classCallCheck(this, PluginManager); + + this.less = less; + this.visitors = []; + this.preProcessors = []; + this.postProcessors = []; + this.installedPlugins = []; + this.fileManagers = []; + this.iterator = -1; + this.pluginCache = {}; + this.Loader = new less.PluginLoader(less); + } + /** + * Adds all the plugins in the array + * @param {Array} plugins + */ + + + _createClass(PluginManager, [{ + key: "addPlugins", + value: function addPlugins(plugins) { + if (plugins) { + for (var i = 0; i < plugins.length; i++) { + this.addPlugin(plugins[i]); + } + } + } + /** + * + * @param plugin + * @param {String} filename + */ + + }, { + key: "addPlugin", + value: function addPlugin(plugin, filename, functionRegistry) { + this.installedPlugins.push(plugin); + + if (filename) { + this.pluginCache[filename] = plugin; + } + + if (plugin.install) { + plugin.install(this.less, this, functionRegistry || this.less.functions.functionRegistry); + } + } + /** + * + * @param filename + */ + + }, { + key: "get", + value: function get(filename) { + return this.pluginCache[filename]; + } + /** + * Adds a visitor. The visitor object has options on itself to determine + * when it should run. + * @param visitor + */ + + }, { + key: "addVisitor", + value: function addVisitor(visitor) { + this.visitors.push(visitor); + } + /** + * Adds a pre processor object + * @param {object} preProcessor + * @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import + */ + + }, { + key: "addPreProcessor", + value: function addPreProcessor(preProcessor, priority) { + var indexToInsertAt; + + for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) { + if (this.preProcessors[indexToInsertAt].priority >= priority) { + break; + } + } + + this.preProcessors.splice(indexToInsertAt, 0, { + preProcessor: preProcessor, + priority: priority + }); + } + /** + * Adds a post processor object + * @param {object} postProcessor + * @param {number} priority - guidelines 1 = before compression, 1000 = compression, 2000 = after compression + */ + + }, { + key: "addPostProcessor", + value: function addPostProcessor(postProcessor, priority) { + var indexToInsertAt; + + for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) { + if (this.postProcessors[indexToInsertAt].priority >= priority) { + break; + } + } -},{"./extend-visitor":90,"./import-visitor":92,"./join-selector-visitor":94,"./set-tree-visibility-visitor":95,"./to-css-visitor":96,"./visitor":97}],94:[function(require,module,exports){ -var Visitor = require('./visitor'); + this.postProcessors.splice(indexToInsertAt, 0, { + postProcessor: postProcessor, + priority: priority + }); + } + /** + * + * @param manager + */ + + }, { + key: "addFileManager", + value: function addFileManager(manager) { + this.fileManagers.push(manager); + } + /** + * + * @returns {Array} + * @private + */ -var JoinSelectorVisitor = function() { - this.contexts = [[]]; - this._visitor = new Visitor(this); -}; + }, { + key: "getPreProcessors", + value: function getPreProcessors() { + var preProcessors = []; -JoinSelectorVisitor.prototype = { - run: function (root) { - return this._visitor.visit(root); - }, - visitDeclaration: function (declNode, visitArgs) { - visitArgs.visitDeeper = false; - }, - visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { - visitArgs.visitDeeper = false; - }, + for (var i = 0; i < this.preProcessors.length; i++) { + preProcessors.push(this.preProcessors[i].preProcessor); + } - visitRuleset: function (rulesetNode, visitArgs) { - var context = this.contexts[this.contexts.length - 1], - paths = [], selectors; + return preProcessors; + } + /** + * + * @returns {Array} + * @private + */ - this.contexts.push(paths); + }, { + key: "getPostProcessors", + value: function getPostProcessors() { + var postProcessors = []; - if (!rulesetNode.root) { - selectors = rulesetNode.selectors; - if (selectors) { - selectors = selectors.filter(function(selector) { return selector.getIsOutput(); }); - rulesetNode.selectors = selectors.length ? selectors : (selectors = null); - if (selectors) { rulesetNode.joinSelectors(paths, context, selectors); } - } - if (!selectors) { rulesetNode.rules = null; } - rulesetNode.paths = paths; - } - }, - visitRulesetOut: function (rulesetNode) { - this.contexts.length = this.contexts.length - 1; - }, - visitMedia: function (mediaNode, visitArgs) { - var context = this.contexts[this.contexts.length - 1]; - mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia); - }, - visitAtRule: function (atRuleNode, visitArgs) { - var context = this.contexts[this.contexts.length - 1]; - if (atRuleNode.rules && atRuleNode.rules.length) { - atRuleNode.rules[0].root = (atRuleNode.isRooted || context.length === 0 || null); + for (var i = 0; i < this.postProcessors.length; i++) { + postProcessors.push(this.postProcessors[i].postProcessor); } - } -}; -module.exports = JoinSelectorVisitor; + return postProcessors; + } + /** + * + * @returns {Array} + * @private + */ + + }, { + key: "getVisitors", + value: function getVisitors() { + return this.visitors; + } + }, { + key: "visitor", + value: function visitor() { + var self = this; + return { + first: function first() { + self.iterator = -1; + return self.visitors[self.iterator]; + }, + get: function get() { + self.iterator += 1; + return self.visitors[self.iterator]; + } + }; + } + /** + * + * @returns {Array} + * @private + */ + + }, { + key: "getFileManagers", + value: function getFileManagers() { + return this.fileManagers; + } + }]); -},{"./visitor":97}],95:[function(require,module,exports){ -var SetTreeVisibilityVisitor = function(visible) { - this.visible = visible; -}; -SetTreeVisibilityVisitor.prototype.run = function(root) { - this.visit(root); -}; -SetTreeVisibilityVisitor.prototype.visitArray = function(nodes) { - if (!nodes) { - return nodes; - } + return PluginManager; + }(); - var cnt = nodes.length, i; - for (i = 0; i < cnt; i++) { - this.visit(nodes[i]); - } - return nodes; -}; -SetTreeVisibilityVisitor.prototype.visit = function(node) { - if (!node) { - return node; - } - if (node.constructor === Array) { - return this.visitArray(node); - } + var pm; - if (!node.blocksVisibility || node.blocksVisibility()) { - return node; - } - if (this.visible) { - node.ensureVisibility(); - } else { - node.ensureInvisibility(); + function PluginManagerFactory(less, newFactory) { + if (newFactory || !pm) { + pm = new PluginManager(less); } - node.accept(this); - return node; -}; -module.exports = SetTreeVisibilityVisitor; -},{}],96:[function(require,module,exports){ -var tree = require('../tree'), - Visitor = require('./visitor'); + return pm; + } -var CSSVisitorUtils = function(context) { - this._visitor = new Visitor(this); - this._context = context; -}; + var Parse = (function (environment, ParseTree, ImportManager) { + var parse = function parse(input, options, callback) { + if (typeof options === 'function') { + callback = options; + options = copyOptions(this.options, {}); + } else { + options = copyOptions(this.options, options || {}); + } -CSSVisitorUtils.prototype = { - containsSilentNonBlockedChild: function(bodyRules) { - var rule; - if (!bodyRules) { - return false; - } - for (var r = 0; r < bodyRules.length; r++) { - rule = bodyRules[r]; - if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) { - // the atrule contains something that was referenced (likely by extend) - // therefore it needs to be shown in output too - return true; + if (!callback) { + var self = this; + return new Promise(function (resolve, reject) { + parse.call(self, input, options, function (err, output) { + if (err) { + reject(err); + } else { + resolve(output); } + }); + }); + } else { + var context; + var rootFileInfo; + var pluginManager = new PluginManagerFactory(this, !options.reUsePluginManager); + options.pluginManager = pluginManager; + context = new contexts.Parse(options); + + if (options.rootFileInfo) { + rootFileInfo = options.rootFileInfo; + } else { + var filename = options.filename || 'input'; + var entryPath = filename.replace(/[^\/\\]*$/, ''); + rootFileInfo = { + filename: filename, + rewriteUrls: context.rewriteUrls, + rootpath: context.rootpath || '', + currentDirectory: entryPath, + entryPath: entryPath, + rootFilename: filename + }; // add in a missing trailing slash + + if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== '/') { + rootFileInfo.rootpath += '/'; + } } - return false; - }, - keepOnlyVisibleChilds: function(owner) { - if (owner && owner.rules) { - owner.rules = owner.rules.filter(function(thing) { - return thing.isVisible(); - }); - } - }, + var imports = new ImportManager(this, context, rootFileInfo); + this.importManager = imports; // TODO: allow the plugins to be just a list of paths or names + // Do an async plugin queue like lessc - isEmpty: function(owner) { - return (owner && owner.rules) - ? (owner.rules.length === 0) : true; - }, + if (options.plugins) { + options.plugins.forEach(function (plugin) { + var evalResult; + var contents; - hasVisibleSelector: function(rulesetNode) { - return (rulesetNode && rulesetNode.paths) - ? (rulesetNode.paths.length > 0) : false; - }, + if (plugin.fileContent) { + contents = plugin.fileContent.replace(/^\uFEFF/, ''); + evalResult = pluginManager.Loader.evalPlugin(contents, context, imports, plugin.options, plugin.filename); - resolveVisibility: function (node, originalRules) { - if (!node.blocksVisibility()) { - if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) { - return ; + if (evalResult instanceof LessError) { + return callback(evalResult); + } + } else { + pluginManager.addPlugin(plugin); } - - return node; + }); } - var compiledRulesBody = node.rules[0]; - this.keepOnlyVisibleChilds(compiledRulesBody); + new Parser(context, imports, rootFileInfo).parse(input, function (e, root) { + if (e) { + return callback(e); + } - if (this.isEmpty(compiledRulesBody)) { - return ; - } + callback(null, root, imports, options); + }, options); + } + }; - node.ensureVisibility(); - node.removeVisibilityBlock(); + return parse; + }); - return node; - }, + var lessRoot = (function (environment$1, fileManagers) { + /** + * @todo + * This original code could be improved quite a bit. + * Many classes / modules currently add side-effects / mutations to passed in objects, + * which makes it hard to refactor and reason about. + */ + environment$1 = new environment(environment$1, fileManagers); + var SourceMapOutput = sourceMapOutput(environment$1); + var SourceMapBuilder = sourceMapBuilder(SourceMapOutput, environment$1); + var ParseTree = parseTree(SourceMapBuilder); + var ImportManager = importManager(environment$1); + var render = Render(environment$1, ParseTree); + var parse = Parse(environment$1, ParseTree, ImportManager); + var functions = Functions(environment$1); + /** + * @todo + * This root properties / methods need to be organized. + * It's not clear what should / must be public and why. + */ - isVisibleRuleset: function(rulesetNode) { - if (rulesetNode.firstRoot) { - return true; - } + var initial = { + version: [3, 10, 0], + data: data, + tree: tree, + Environment: environment, + AbstractFileManager: AbstractFileManager, + AbstractPluginLoader: AbstractPluginLoader, + environment: environment$1, + visitors: visitors, + Parser: Parser, + functions: functions, + contexts: contexts, + SourceMapOutput: SourceMapOutput, + SourceMapBuilder: SourceMapBuilder, + ParseTree: ParseTree, + ImportManager: ImportManager, + render: render, + parse: parse, + LessError: LessError, + transformTree: transformTree, + utils: utils, + PluginManager: PluginManagerFactory, + logger: logger + }; // Create a public API + + var ctor = function ctor(t) { + return function () { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return _construct(t, args); + }; + }; - if (this.isEmpty(rulesetNode)) { - return false; - } + var t; + var api = Object.create(initial); - if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) { - return false; - } + for (var n in initial.tree) { + /* eslint guard-for-in: 0 */ + t = initial.tree[n]; - return true; - } + if (typeof t === 'function') { + api[n.toLowerCase()] = ctor(t); + } else { + api[n] = Object.create(null); -}; + for (var o in t) { + /* eslint guard-for-in: 0 */ + api[n][o.toLowerCase()] = ctor(t[o]); + } + } + } -var ToCSSVisitor = function(context) { - this._visitor = new Visitor(this); - this._context = context; - this.utils = new CSSVisitorUtils(context); -}; + return api; + }); -ToCSSVisitor.prototype = { - isReplacing: true, - run: function (root) { - return this._visitor.visit(root); - }, + var options; + var logger$1; + var fileCache = {}; // TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load - visitDeclaration: function (declNode, visitArgs) { - if (declNode.blocksVisibility() || declNode.variable) { - return; - } - return declNode; - }, + var FileManager = + /*#__PURE__*/ + function (_AbstractFileManager) { + _inherits(FileManager, _AbstractFileManager); - visitMixinDefinition: function (mixinNode, visitArgs) { - // mixin definitions do not get eval'd - this means they keep state - // so we have to clear that state here so it isn't used if toCSS is called twice - mixinNode.frames = []; - }, + function FileManager() { + _classCallCheck(this, FileManager); - visitExtend: function (extendNode, visitArgs) { - }, + return _possibleConstructorReturn(this, _getPrototypeOf(FileManager).apply(this, arguments)); + } - visitComment: function (commentNode, visitArgs) { - if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) { - return; + _createClass(FileManager, [{ + key: "alwaysMakePathsAbsolute", + value: function alwaysMakePathsAbsolute() { + return true; + } + }, { + key: "join", + value: function join(basePath, laterPath) { + if (!basePath) { + return laterPath; } - return commentNode; - }, - - visitMedia: function(mediaNode, visitArgs) { - var originalRules = mediaNode.rules[0].rules; - mediaNode.accept(this._visitor); - visitArgs.visitDeeper = false; - return this.utils.resolveVisibility(mediaNode, originalRules); - }, + return this.extractUrlParts(laterPath, basePath).path; + } + }, { + key: "doXHR", + value: function doXHR(url, type, callback, errback) { + var xhr = new XMLHttpRequest(); + var async = options.isFileProtocol ? options.fileAsync : true; - visitImport: function (importNode, visitArgs) { - if (importNode.blocksVisibility()) { - return ; + if (typeof xhr.overrideMimeType === 'function') { + xhr.overrideMimeType('text/css'); } - return importNode; - }, - visitAtRule: function(atRuleNode, visitArgs) { - if (atRuleNode.rules && atRuleNode.rules.length) { - return this.visitAtRuleWithBody(atRuleNode, visitArgs); - } else { - return this.visitAtRuleWithoutBody(atRuleNode, visitArgs); - } - }, + logger$1.debug("XHR: Getting '".concat(url, "'")); + xhr.open('GET', url, async); + xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); + xhr.send(null); - visitAnonymous: function(anonymousNode, visitArgs) { - if (!anonymousNode.blocksVisibility()) { - anonymousNode.accept(this._visitor); - return anonymousNode; + 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); + } } - }, - visitAtRuleWithBody: function(atRuleNode, visitArgs) { - // if there is only one nested ruleset and that one has no path, then it is - // just fake ruleset - function hasFakeRuleset(atRuleNode) { - var bodyRules = atRuleNode.rules; - return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0); - } - function getBodyRules(atRuleNode) { - var nodeRules = atRuleNode.rules; - if (hasFakeRuleset(atRuleNode)) { - return nodeRules[0].rules; + if (options.isFileProtocol && !options.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); } - - return nodeRules; + }; + } else { + handleResponse(xhr, callback, errback); } - // it is still true that it is only one ruleset in array - // this is last such moment - // process childs - var originalRules = getBodyRules(atRuleNode); - atRuleNode.accept(this._visitor); - visitArgs.visitDeeper = false; - - if (!this.utils.isEmpty(atRuleNode)) { - this._mergeRules(atRuleNode.rules[0].rules); + } + }, { + key: "supports", + value: function supports() { + return true; + } + }, { + key: "clearFileCache", + value: function clearFileCache() { + fileCache = {}; + } + }, { + key: "loadFile", + value: function loadFile(filename, currentDirectory, options, environment) { + // TODO: Add prefix support like less-node? + // What about multiple paths? + if (currentDirectory && !this.isPathAbsolute(filename)) { + filename = currentDirectory + filename; } - return this.utils.resolveVisibility(atRuleNode, originalRules); - }, - - visitAtRuleWithoutBody: function(atRuleNode, visitArgs) { - if (atRuleNode.blocksVisibility()) { - return; - } + filename = options.ext ? this.tryAppendExtension(filename, options.ext) : filename; + options = options || {}; // sheet may be set to the stylesheet for the initial load or a collection of properties including + // some context variables for imports - if (atRuleNode.name === '@charset') { - // Only output the debug info together with subsequent @charset definitions - // a comment (or @media statement) before the actual @charset atrule would - // be considered illegal css as it has to be on the first line - if (this.charset) { - if (atRuleNode.debugInfo) { - var comment = new tree.Comment('/* ' + atRuleNode.toCSS(this._context).replace(/\n/g, '') + ' */\n'); - comment.debugInfo = atRuleNode.debugInfo; - return this._visitor.visit(comment); - } - return; + var hrefParts = this.extractUrlParts(filename, window.location.href); + var href = hrefParts.url; + var self = this; + return new Promise(function (resolve, reject) { + if (options.useFileCache && fileCache[href]) { + try { + var lessText = fileCache[href]; + return resolve({ + contents: lessText, + filename: href, + webInfo: { + lastModified: new Date() + } + }); + } catch (e) { + return reject({ + filename: href, + message: "Error loading file ".concat(href, " error was ").concat(e.message) + }); } - this.charset = true; - } + } - return atRuleNode; - }, + self.doXHR(href, options.mime, function doXHRCallback(data, lastModified) { + // per file cache + fileCache[href] = data; // Use remote copy (re-parse) - checkValidNodes: function(rules, isRoot) { - if (!rules) { - return; - } + resolve({ + contents: data, + filename: href, + webInfo: { + lastModified: lastModified + } + }); + }, function doXHRError(status, url) { + reject({ + type: 'File', + message: "'".concat(url, "' wasn't found (").concat(status, ")"), + href: href + }); + }); + }); + } + }]); - for (var i = 0; i < rules.length; i++) { - var ruleNode = rules[i]; - if (isRoot && ruleNode instanceof tree.Declaration && !ruleNode.variable) { - throw { message: 'Properties must be inside selector blocks. They cannot be in the root', - index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename}; - } - if (ruleNode instanceof tree.Call) { - throw { message: 'Function \'' + ruleNode.name + '\' is undefined', - index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename}; - } - if (ruleNode.type && !ruleNode.allowRoot) { - throw { message: ruleNode.type + ' node returned by a function is not valid here', - index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename}; - } - } - }, + return FileManager; + }(AbstractFileManager); - visitRuleset: function (rulesetNode, visitArgs) { - // at this point rulesets are nested into each other - var rule, rulesets = []; + var FM = (function (opts, log) { + options = opts; + logger$1 = log; + return FileManager; + }); - this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot); + /** + * Browser Plugin Loader + */ - if (!rulesetNode.root) { - // remove invisible paths - this._compileRulesetPaths(rulesetNode); - - // remove rulesets from this ruleset body and compile them separately - var nodeRules = rulesetNode.rules, nodeRuleCnt = nodeRules ? nodeRules.length : 0; - for (var i = 0; i < nodeRuleCnt; ) { - rule = nodeRules[i]; - if (rule && rule.rules) { - // visit because we are moving them out from being a child - rulesets.push(this._visitor.visit(rule)); - nodeRules.splice(i, 1); - nodeRuleCnt--; - continue; - } - i++; - } - // accept the visitor to remove rules and refactor itself - // then we can decide nogw whether we want it or not - // compile body - if (nodeRuleCnt > 0) { - rulesetNode.accept(this._visitor); - } else { - rulesetNode.rules = null; - } - visitArgs.visitDeeper = false; + var PluginLoader = + /*#__PURE__*/ + function (_AbstractPluginLoader) { + _inherits(PluginLoader, _AbstractPluginLoader); - } else { // if (! rulesetNode.root) { - rulesetNode.accept(this._visitor); - visitArgs.visitDeeper = false; - } + function PluginLoader(less) { + var _this; - if (rulesetNode.rules) { - this._mergeRules(rulesetNode.rules); - this._removeDuplicateRules(rulesetNode.rules); - } + _classCallCheck(this, PluginLoader); - // now decide whether we keep the ruleset - if (this.utils.isVisibleRuleset(rulesetNode)) { - rulesetNode.ensureVisibility(); - rulesets.splice(0, 0, rulesetNode); - } + _this = _possibleConstructorReturn(this, _getPrototypeOf(PluginLoader).call(this)); + _this.less = less; // Should we shim this.require for browser? Probably not? - if (rulesets.length === 1) { - return rulesets[0]; - } - return rulesets; - }, + return _this; + } - _compileRulesetPaths: function(rulesetNode) { - if (rulesetNode.paths) { - rulesetNode.paths = rulesetNode.paths - .filter(function(p) { - var i; - if (p[0].elements[0].combinator.value === ' ') { - p[0].elements[0].combinator = new(tree.Combinator)(''); - } - for (i = 0; i < p.length; i++) { - if (p[i].isVisible() && p[i].getIsOutput()) { - return true; - } - } - return false; - }); - } - }, + _createClass(PluginLoader, [{ + key: "loadPlugin", + value: function loadPlugin(filename, basePath, context, environment, fileManager) { + return new Promise(function (fulfill, reject) { + fileManager.loadFile(filename, basePath, context, environment).then(fulfill).catch(reject); + }); + } + }]); - _removeDuplicateRules: function(rules) { - if (!rules) { return; } + return PluginLoader; + }(AbstractPluginLoader); - // remove duplicates - var ruleCache = {}, - ruleList, rule, i; + var LogListener = (function (less, options) { + var logLevel_debug = 4; + var logLevel_info = 3; + var logLevel_warn = 2; + var logLevel_error = 1; // The amount of logging in the javascript console. + // 3 - Debug, information and errors + // 2 - Information and errors + // 1 - Errors + // 0 - None + // Defaults to 2 - for (i = rules.length - 1; i >= 0 ; i--) { - rule = rules[i]; - if (rule instanceof tree.Declaration) { - if (!ruleCache[rule.name]) { - ruleCache[rule.name] = rule; - } else { - ruleList = ruleCache[rule.name]; - if (ruleList instanceof tree.Declaration) { - ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._context)]; - } - var ruleCSS = rule.toCSS(this._context); - if (ruleList.indexOf(ruleCSS) !== -1) { - rules.splice(i, 1); - } else { - ruleList.push(ruleCSS); - } - } - } + options.logLevel = typeof options.logLevel !== 'undefined' ? options.logLevel : options.env === 'development' ? logLevel_info : logLevel_error; + + if (!options.loggers) { + options.loggers = [{ + debug: function debug(msg) { + if (options.logLevel >= logLevel_debug) { + console.log(msg); + } + }, + info: function info(msg) { + if (options.logLevel >= logLevel_info) { + console.log(msg); + } + }, + warn: function warn(msg) { + if (options.logLevel >= logLevel_warn) { + console.warn(msg); + } + }, + error: function error(msg) { + if (options.logLevel >= logLevel_error) { + console.error(msg); + } } - }, + }]; + } - _mergeRules: function(rules) { - if (!rules) { - return; - } - - var groups = {}, - groupsArr = []; - - for (var i = 0; i < rules.length; i++) { - var rule = rules[i]; - if (rule.merge) { - var key = rule.name; - groups[key] ? rules.splice(i--, 1) : - groupsArr.push(groups[key] = []); - groups[key].push(rule); - } - } - - groupsArr.forEach(function(group) { - if (group.length > 0) { - var result = group[0], - space = [], - comma = [new tree.Expression(space)]; - group.forEach(function(rule) { - if ((rule.merge === '+') && (space.length > 0)) { - comma.push(new tree.Expression(space = [])); - } - space.push(rule.value); - result.important = result.important || rule.important; - }); - result.value = new tree.Value(comma); - } - }); + for (var i = 0; i < options.loggers.length; i++) { + less.logger.addListener(options.loggers[i]); } -}; + }); + + var ErrorReporting = (function (window, less, options) { + function errorHTML(e, rootHref) { + var id = "less-error-message:".concat(extractId(rootHref || '')); + var template = '
  • {content}
  • '; + var elem = window.document.createElement('div'); + var timer; + var content; + var errors = []; + var filename = e.filename || rootHref; + var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; + elem.id = id; + elem.className = 'less-error-message'; + content = "

    ".concat(e.type || 'Syntax', "Error: ").concat(e.message || 'There is an error in your .less file') + "

    in ").concat(filenameNoPath, " "); + + var errorline = function errorline(e, i, classname) { + if (e.extract[i] !== undefined) { + errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1)).replace(/\{class\}/, classname).replace(/\{content\}/, e.extract[i])); + } + }; + + if (e.line) { + errorline(e, 0, ''); + errorline(e, 1, 'line'); + errorline(e, 2, ''); + content += "on line ".concat(e.line, ", column ").concat(e.column + 1, ":

      ").concat(errors.join(''), "
    "); + } + + if (e.stack && (e.extract || options.logLevel >= 4)) { + content += "
    Stack Trace
    ".concat(e.stack.split('\n').slice(1).join('
    ')); + } -module.exports = ToCSSVisitor; + elem.innerHTML = content; // CSS for error messages -},{"../tree":67,"./visitor":97}],97:[function(require,module,exports){ -var tree = require('../tree'); + browser.createCSS(window.document, ['.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #dd6666;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.line {', 'color: #ff0000;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}'].join('\n'), { + title: 'error-message' + }); + elem.style.cssText = ['font-family: Arial, sans-serif', 'border: 1px solid #e00', 'background-color: #eee', 'border-radius: 5px', '-webkit-border-radius: 5px', '-moz-border-radius: 5px', 'color: #e00', 'padding: 15px', 'margin-bottom: 15px'].join(';'); -var _visitArgs = { visitDeeper: true }, - _hasIndexed = false; + if (options.env === 'development') { + timer = setInterval(function () { + var document = window.document; + var body = document.body; -function _noop(node) { - return node; -} + if (body) { + if (document.getElementById(id)) { + body.replaceChild(elem, document.getElementById(id)); + } else { + body.insertBefore(elem, body.firstChild); + } -function indexNodeTypes(parent, ticker) { - // add .typeIndex to tree node types for lookup table - var key, child; - for (key in parent) { - /* eslint guard-for-in: 0 */ - child = parent[key]; - switch (typeof child) { - case 'function': - // ignore bound functions directly on tree which do not have a prototype - // or aren't nodes - if (child.prototype && child.prototype.type) { - child.prototype.typeIndex = ticker++; - } - break; - case 'object': - ticker = indexNodeTypes(child, ticker); - break; - - } + clearInterval(timer); + } + }, 10); + } } - return ticker; -} -var Visitor = function(implementation) { - this._implementation = implementation; - this._visitInCache = {}; - this._visitOutCache = {}; + function removeErrorHTML(path) { + var node = window.document.getElementById("less-error-message:".concat(extractId(path))); - if (!_hasIndexed) { - indexNodeTypes(tree, 1); - _hasIndexed = true; + if (node) { + node.parentNode.removeChild(node); + } } -}; -Visitor.prototype = { - visit: function(node) { - if (!node) { - return node; - } + function removeError(path) { + if (!options.errorReporting || options.errorReporting === 'html') { + removeErrorHTML(path); + } else if (options.errorReporting === 'console') ; else if (typeof options.errorReporting === 'function') { + options.errorReporting('remove', path); + } + } - var nodeTypeIndex = node.typeIndex; - if (!nodeTypeIndex) { - // MixinCall args aren't a node type? - if (node.value && node.value.typeIndex) { - this.visit(node.value); - } - return node; - } + function errorConsole(e, rootHref) { + var template = '{line} {content}'; + var filename = e.filename || rootHref; + var errors = []; + var content = "".concat(e.type || 'Syntax', "Error: ").concat(e.message || 'There is an error in your .less file', " in ").concat(filename); + + var errorline = function errorline(e, i, classname) { + if (e.extract[i] !== undefined) { + errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1)).replace(/\{class\}/, classname).replace(/\{content\}/, e.extract[i])); + } + }; + + if (e.line) { + errorline(e, 0, ''); + errorline(e, 1, 'line'); + errorline(e, 2, ''); + content += " on line ".concat(e.line, ", column ").concat(e.column + 1, ":\n").concat(errors.join('\n')); + } - var impl = this._implementation, - func = this._visitInCache[nodeTypeIndex], - funcOut = this._visitOutCache[nodeTypeIndex], - visitArgs = _visitArgs, - fnName; + if (e.stack && (e.extract || options.logLevel >= 4)) { + content += "\nStack Trace\n".concat(e.stack); + } - visitArgs.visitDeeper = true; + less.logger.error(content); + } - if (!func) { - fnName = 'visit' + node.type; - func = impl[fnName] || _noop; - funcOut = impl[fnName + 'Out'] || _noop; - this._visitInCache[nodeTypeIndex] = func; - this._visitOutCache[nodeTypeIndex] = funcOut; - } + function error(e, rootHref) { + if (!options.errorReporting || options.errorReporting === 'html') { + errorHTML(e, rootHref); + } else if (options.errorReporting === 'console') { + errorConsole(e, rootHref); + } else if (typeof options.errorReporting === 'function') { + options.errorReporting('add', e, rootHref); + } + } - if (func !== _noop) { - var newNode = func.call(impl, node, visitArgs); - if (node && impl.isReplacing) { - node = newNode; - } - } + return { + add: error, + remove: removeError + }; + }); - if (visitArgs.visitDeeper && node && node.accept) { - node.accept(this); - } + // Cache system is a bit outdated and could do with work + var Cache = (function (window, options, logger) { + var cache = null; - if (funcOut != _noop) { - funcOut.call(impl, node); - } + if (options.env !== 'development') { + try { + cache = typeof window.localStorage === 'undefined' ? null : window.localStorage; + } catch (_) {} + } - return node; - }, - visitArray: function(nodes, nonReplacing) { - if (!nodes) { - return nodes; - } + return { + setCSS: function setCSS(path, lastModified, modifyVars, styles) { + if (cache) { + logger.info("saving ".concat(path, " to cache.")); - var cnt = nodes.length, i; + try { + cache.setItem(path, styles); + cache.setItem("".concat(path, ":timestamp"), lastModified); - // Non-replacing - if (nonReplacing || !this._implementation.isReplacing) { - for (i = 0; i < cnt; i++) { - this.visit(nodes[i]); + if (modifyVars) { + cache.setItem("".concat(path, ":vars"), JSON.stringify(modifyVars)); } - return nodes; + } catch (e) { + // TODO - could do with adding more robust error handling + logger.error("failed to save \"".concat(path, "\" to local storage for caching.")); + } } + }, + getCSS: function getCSS(path, webInfo, modifyVars) { + var css = cache && cache.getItem(path); + var timestamp = cache && cache.getItem("".concat(path, ":timestamp")); + var vars = cache && cache.getItem("".concat(path, ":vars")); + modifyVars = modifyVars || {}; + vars = vars || "{}"; // if not set, treat as the JSON representation of an empty object - // Replacing - var out = []; - for (i = 0; i < cnt; i++) { - var evald = this.visit(nodes[i]); - if (evald === undefined) { continue; } - if (!evald.splice) { - out.push(evald); - } else if (evald.length) { - this.flatten(evald, out); - } - } - return out; - }, - flatten: function(arr, out) { - if (!out) { - out = []; + if (timestamp && webInfo.lastModified && new Date(webInfo.lastModified).valueOf() === new Date(timestamp).valueOf() && JSON.stringify(modifyVars) === vars) { + // Use local copy + return css; } + } + }; + }); - var cnt, i, item, - nestedCnt, j, nestedItem; + var ImageSize = (function () { + function _imageSize() { + throw { + type: 'Runtime', + message: 'Image size functions are not supported in browser version of less' + }; + } - for (i = 0, cnt = arr.length; i < cnt; i++) { - item = arr[i]; - if (item === undefined) { - continue; - } - if (!item.splice) { - out.push(item); - continue; - } + var imageFunctions = { + 'image-size': function imageSize(filePathNode) { + _imageSize(); - for (j = 0, nestedCnt = item.length; j < nestedCnt; j++) { - nestedItem = item[j]; - if (nestedItem === undefined) { - continue; - } - if (!nestedItem.splice) { - out.push(nestedItem); - } else if (nestedItem.length) { - this.flatten(nestedItem, out); - } - } - } + return -1; + }, + 'image-width': function imageWidth(filePathNode) { + _imageSize(); - return out; - } -}; -module.exports = Visitor; + return -1; + }, + 'image-height': function imageHeight(filePathNode) { + _imageSize(); -},{"../tree":67}],98:[function(require,module,exports){ -"use strict"; + return -1; + } + }; + functionRegistry.addMultiple(imageFunctions); + }); -// rawAsap provides everything we need except exception management. -var rawAsap = require("./raw"); -// RawTasks are recycled to reduce GC churn. -var freeTasks = []; -// We queue errors to ensure they are thrown in right order (FIFO). -// Array-as-queue is good enough here, since we are just dealing with exceptions. -var pendingErrors = []; -var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError); + // + var root = (function (window, options) { + var document = window.document; + var less = lessRoot(); + less.options = options; + var environment = less.environment; + var FileManager = FM(options, less.logger); + var fileManager = new FileManager(); + environment.addFileManager(fileManager); + less.FileManager = FileManager; + less.PluginLoader = PluginLoader; + LogListener(less, options); + var errors = ErrorReporting(window, less, options); + var cache = less.cache = options.cache || Cache(window, options, less.logger); + ImageSize(less.environment); // Setup user functions - Deprecate? -function throwFirstError() { - if (pendingErrors.length) { - throw pendingErrors.shift(); + if (options.functions) { + less.functions.functionRegistry.addMultiple(options.functions); } -} -/** - * Calls a task as soon as possible after returning, in its own event, with priority - * over other events like animation, reflow, and repaint. An error thrown from an - * event will not interrupt, nor even substantially slow down the processing of - * other events, but will be rather postponed to a lower priority event. - * @param {{call}} task A callable object, typically a function that takes no - * arguments. - */ -module.exports = asap; -function asap(task) { - var rawTask; - if (freeTasks.length) { - rawTask = freeTasks.pop(); - } else { - rawTask = new RawTask(); - } - rawTask.task = task; - rawAsap(rawTask); -} + var typePattern = /^text\/(x-)?less$/; -// We wrap tasks with recyclable task objects. A task object implements -// `call`, just like a function. -function RawTask() { - this.task = null; -} + function clone(obj) { + var cloned = {}; -// The sole purpose of wrapping the task is to catch the exception and recycle -// the task object after its single use. -RawTask.prototype.call = function () { - try { - this.task.call(); - } catch (error) { - if (asap.onerror) { - // This hook exists purely for testing purposes. - // Its name will be periodically randomized to break any code that - // depends on its existence. - asap.onerror(error); - } else { - // In a web browser, exceptions are not fatal. However, to avoid - // slowing down the queue of pending tasks, we rethrow the error in a - // lower priority turn. - pendingErrors.push(error); - requestErrorThrow(); - } - } finally { - this.task = null; - freeTasks[freeTasks.length] = this; - } -}; - -},{"./raw":99}],99:[function(require,module,exports){ -(function (global){ -"use strict"; - -// Use the fastest means possible to execute a task in its own turn, with -// priority over other events including IO, animation, reflow, and redraw -// events in browsers. -// -// An exception thrown by a task will permanently interrupt the processing of -// subsequent tasks. The higher level `asap` function ensures that if an -// exception is thrown by a task, that the task queue will continue flushing as -// soon as possible, but if you use `rawAsap` directly, you are responsible to -// either ensure that no exceptions are thrown from your task, or to manually -// call `rawAsap.requestFlush` if an exception is thrown. -module.exports = rawAsap; -function rawAsap(task) { - if (!queue.length) { - requestFlush(); - flushing = true; - } - // Equivalent to push, but avoids a function call. - queue[queue.length] = task; -} - -var queue = []; -// Once a flush has been requested, no further calls to `requestFlush` are -// necessary until the next `flush` completes. -var flushing = false; -// `requestFlush` is an implementation-specific method that attempts to kick -// off a `flush` event as quickly as possible. `flush` will attempt to exhaust -// the event queue before yielding to the browser's own event loop. -var requestFlush; -// The position of the next task to execute in the task queue. This is -// preserved between calls to `flush` so that it can be resumed if -// a task throws an exception. -var index = 0; -// If a task schedules additional tasks recursively, the task queue can grow -// unbounded. To prevent memory exhaustion, the task queue will periodically -// truncate already-completed tasks. -var capacity = 1024; - -// The flush function processes all tasks that have been scheduled with -// `rawAsap` unless and until one of those tasks throws an exception. -// If a task throws an exception, `flush` ensures that its state will remain -// consistent and will resume where it left off when called again. -// However, `flush` does not make any arrangements to be called again if an -// exception is thrown. -function flush() { - while (index < queue.length) { - var currentIndex = index; - // Advance the index before calling the task. This ensures that we will - // begin flushing on the next task the task throws an error. - index = index + 1; - queue[currentIndex].call(); - // Prevent leaking memory for long chains of recursive calls to `asap`. - // If we call `asap` within tasks scheduled by `asap`, the queue will - // grow, but to avoid an O(n) walk for every task we execute, we don't - // shift tasks off the queue after they have been executed. - // Instead, we periodically shift 1024 tasks off the queue. - if (index > capacity) { - // Manually shift all values starting at the index back to the - // beginning of the queue. - for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) { - queue[scan] = queue[scan + index]; - } - queue.length -= index; - index = 0; - } - } - queue.length = 0; - index = 0; - flushing = false; -} - -// `requestFlush` is implemented using a strategy based on data collected from -// every available SauceLabs Selenium web driver worker at time of writing. -// https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593 - -// Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that -// have WebKitMutationObserver but not un-prefixed MutationObserver. -// Must use `global` or `self` instead of `window` to work in both frames and web -// workers. `global` is a provision of Browserify, Mr, Mrs, or Mop. - -/* globals self */ -var scope = typeof global !== "undefined" ? global : self; -var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver; - -// MutationObservers are desirable because they have high priority and work -// reliably everywhere they are implemented. -// They are implemented in all modern browsers. -// -// - Android 4-4.3 -// - Chrome 26-34 -// - Firefox 14-29 -// - Internet Explorer 11 -// - iPad Safari 6-7.1 -// - iPhone Safari 7-7.1 -// - Safari 6-7 -if (typeof BrowserMutationObserver === "function") { - requestFlush = makeRequestCallFromMutationObserver(flush); - -// MessageChannels are desirable because they give direct access to the HTML -// task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera -// 11-12, and in web workers in many engines. -// Although message channels yield to any queued rendering and IO tasks, they -// would be better than imposing the 4ms delay of timers. -// However, they do not work reliably in Internet Explorer or Safari. - -// Internet Explorer 10 is the only browser that has setImmediate but does -// not have MutationObservers. -// Although setImmediate yields to the browser's renderer, it would be -// preferrable to falling back to setTimeout since it does not have -// the minimum 4ms penalty. -// Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and -// Desktop to a lesser extent) that renders both setImmediate and -// MessageChannel useless for the purposes of ASAP. -// https://github.com/kriskowal/q/issues/396 - -// Timers are implemented universally. -// We fall back to timers in workers in most engines, and in foreground -// contexts in the following browsers. -// However, note that even this simple case requires nuances to operate in a -// broad spectrum of browsers. -// -// - Firefox 3-13 -// - Internet Explorer 6-9 -// - iPad Safari 4.3 -// - Lynx 2.8.7 -} else { - requestFlush = makeRequestCallFromTimer(flush); -} - -// `requestFlush` requests that the high priority event queue be flushed as -// soon as possible. -// This is useful to prevent an error thrown in a task from stalling the event -// queue if the exception handled by Node.js’s -// `process.on("uncaughtException")` or by a domain. -rawAsap.requestFlush = requestFlush; - -// To request a high priority event, we induce a mutation observer by toggling -// the text of a text node between "1" and "-1". -function makeRequestCallFromMutationObserver(callback) { - var toggle = 1; - var observer = new BrowserMutationObserver(callback); - var node = document.createTextNode(""); - observer.observe(node, {characterData: true}); - return function requestCall() { - toggle = -toggle; - node.data = toggle; - }; -} - -// The message channel technique was discovered by Malte Ubl and was the -// original foundation for this library. -// http://www.nonblocking.io/2011/06/windownexttick.html - -// Safari 6.0.5 (at least) intermittently fails to create message ports on a -// page's first load. Thankfully, this version of Safari supports -// MutationObservers, so we don't need to fall back in that case. - -// function makeRequestCallFromMessageChannel(callback) { -// var channel = new MessageChannel(); -// channel.port1.onmessage = callback; -// return function requestCall() { -// channel.port2.postMessage(0); -// }; -// } - -// For reasons explained above, we are also unable to use `setImmediate` -// under any circumstances. -// Even if we were, there is another bug in Internet Explorer 10. -// It is not sufficient to assign `setImmediate` to `requestFlush` because -// `setImmediate` must be called *by name* and therefore must be wrapped in a -// closure. -// Never forget. - -// function makeRequestCallFromSetImmediate(callback) { -// return function requestCall() { -// setImmediate(callback); -// }; -// } - -// Safari 6.0 has a problem where timers will get lost while the user is -// scrolling. This problem does not impact ASAP because Safari 6.0 supports -// mutation observers, so that implementation is used instead. -// However, if we ever elect to use timers in Safari, the prevalent work-around -// is to add a scroll event listener that calls for a flush. - -// `setTimeout` does not call the passed callback if the delay is less than -// approximately 7 in web workers in Firefox 8 through 18, and sometimes not -// even then. - -function makeRequestCallFromTimer(callback) { - return function requestCall() { - // We dispatch a timeout with a specified delay of 0 for engines that - // can reliably accommodate that request. This will usually be snapped - // to a 4 milisecond delay, but once we're flushing, there's no delay - // between events. - var timeoutHandle = setTimeout(handleTimer, 0); - // However, since this timer gets frequently dropped in Firefox - // workers, we enlist an interval handle that will try to fire - // an event 20 times per second until it succeeds. - var intervalHandle = setInterval(handleTimer, 50); - - function handleTimer() { - // Whichever timer succeeds will cancel both timers and - // execute the callback. - clearTimeout(timeoutHandle); - clearInterval(intervalHandle); - callback(); + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + cloned[prop] = obj[prop]; } - }; -} - -// This is for `asap.js` only. -// Its name will be periodically randomized to break any code that depends on -// its existence. -rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer; - -// ASAP was originally a nextTick shim included in Q. This was factored out -// into this ASAP package. It was later adapted to RSVP which made further -// amendments. These decisions, particularly to marginalize MessageChannel and -// to capture the MutationObserver implementation in a closure, were integrated -// back into ASAP proper. -// https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],100:[function(require,module,exports){ -var clone = (function() { -'use strict'; - -function _instanceof(obj, type) { - return type != null && obj instanceof type; -} - -var nativeMap; -try { - nativeMap = Map; -} catch(_) { - // maybe a reference error because no `Map`. Give it a dummy value that no - // value will ever be an instanceof. - nativeMap = function() {}; -} - -var nativeSet; -try { - nativeSet = Set; -} catch(_) { - nativeSet = function() {}; -} - -var nativePromise; -try { - nativePromise = Promise; -} catch(_) { - nativePromise = function() {}; -} - -/** - * Clones (copies) an Object using deep copying. - * - * This function supports circular references by default, but if you are certain - * there are no circular references in your object, you can save some CPU time - * by calling clone(obj, false). - * - * Caution: if `circular` is false and `parent` contains circular references, - * your program may enter an infinite loop and crash. - * - * @param `parent` - the object to be cloned - * @param `circular` - set to true if the object to be cloned may contain - * circular references. (optional - true by default) - * @param `depth` - set to a number if the object is only to be cloned to - * a particular depth. (optional - defaults to Infinity) - * @param `prototype` - sets the prototype to be used when cloning an object. - * (optional - defaults to parent prototype). - * @param `includeNonEnumerable` - set to true if the non-enumerable properties - * should be cloned as well. Non-enumerable properties on the prototype - * chain will be ignored. (optional - false by default) -*/ -function clone(parent, circular, depth, prototype, includeNonEnumerable) { - if (typeof circular === 'object') { - depth = circular.depth; - prototype = circular.prototype; - includeNonEnumerable = circular.includeNonEnumerable; - circular = circular.circular; - } - // maintain two arrays for circular references, where corresponding parents - // and children have the same index - var allParents = []; - var allChildren = []; - - var useBuffer = typeof Buffer != 'undefined'; + } - if (typeof circular == 'undefined') - circular = true; + return cloned; + } // only really needed for phantom - if (typeof depth == 'undefined') - depth = Infinity; - // recurse this function so we don't reset allParents and allChildren - function _clone(parent, depth) { - // cloning null always returns null - if (parent === null) - return null; + function bind(func, thisArg) { + var curryArgs = Array.prototype.slice.call(arguments, 2); + return function () { + var args = curryArgs.concat(Array.prototype.slice.call(arguments, 0)); + return func.apply(thisArg, args); + }; + } - if (depth === 0) - return parent; + function loadStyles(modifyVars) { + var styles = document.getElementsByTagName('style'); + var style; + + for (var i = 0; i < styles.length; i++) { + style = styles[i]; + + if (style.type.match(typePattern)) { + var instanceOptions = clone(options); + instanceOptions.modifyVars = modifyVars; + var lessText = style.innerHTML || ''; + instanceOptions.filename = document.location.href.replace(/#.*$/, ''); + /* jshint loopfunc:true */ + // use closure to store current style + + less.render(lessText, instanceOptions, bind(function (style, e, result) { + if (e) { + errors.add(e, 'inline'); + } else { + style.type = 'text/css'; - var child; - var proto; - if (typeof parent != 'object') { - return parent; - } - - if (_instanceof(parent, nativeMap)) { - child = new nativeMap(); - } else if (_instanceof(parent, nativeSet)) { - child = new nativeSet(); - } else if (_instanceof(parent, nativePromise)) { - child = new nativePromise(function (resolve, reject) { - parent.then(function(value) { - resolve(_clone(value, depth - 1)); - }, function(err) { - reject(_clone(err, depth - 1)); - }); - }); - } else if (clone.__isArray(parent)) { - child = []; - } else if (clone.__isRegExp(parent)) { - child = new RegExp(parent.source, __getRegExpFlags(parent)); - if (parent.lastIndex) child.lastIndex = parent.lastIndex; - } else if (clone.__isDate(parent)) { - child = new Date(parent.getTime()); - } else if (useBuffer && Buffer.isBuffer(parent)) { - if (Buffer.allocUnsafe) { - // Node.js >= 4.5.0 - child = Buffer.allocUnsafe(parent.length); - } else { - // Older Node.js versions - child = new Buffer(parent.length); - } - parent.copy(child); - return child; - } else if (_instanceof(parent, Error)) { - child = Object.create(parent); - } else { - if (typeof prototype == 'undefined') { - proto = Object.getPrototypeOf(parent); - child = Object.create(proto); - } - else { - child = Object.create(prototype); - proto = prototype; + if (style.styleSheet) { + style.styleSheet.cssText = result.css; + } else { + style.innerHTML = result.css; + } + } + }, null, style)); + } } } - if (circular) { - var index = allParents.indexOf(parent); + function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) { + var instanceOptions = clone(options); + addDataAttr(instanceOptions, sheet); + instanceOptions.mime = sheet.type; - if (index != -1) { - return allChildren[index]; + if (modifyVars) { + instanceOptions.modifyVars = modifyVars; } - allParents.push(parent); - allChildren.push(child); - } - if (_instanceof(parent, nativeMap)) { - parent.forEach(function(value, key) { - var keyChild = _clone(key, depth - 1); - var valueChild = _clone(value, depth - 1); - child.set(keyChild, valueChild); - }); - } - if (_instanceof(parent, nativeSet)) { - parent.forEach(function(value) { - var entryChild = _clone(value, depth - 1); - child.add(entryChild); - }); - } + function loadInitialFileCallback(loadedFile) { + var data = loadedFile.contents; + var path = loadedFile.filename; + var webInfo = loadedFile.webInfo; + var newFileInfo = { + currentDirectory: fileManager.getPath(path), + filename: path, + rootFilename: path, + rewriteUrls: instanceOptions.rewriteUrls + }; + newFileInfo.entryPath = newFileInfo.currentDirectory; + newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory; - for (var i in parent) { - var attrs; - if (proto) { - attrs = Object.getOwnPropertyDescriptor(proto, i); - } + if (webInfo) { + webInfo.remaining = remaining; + var css = cache.getCSS(path, webInfo, instanceOptions.modifyVars); - if (attrs && attrs.set == null) { - continue; + if (!reload && css) { + webInfo.local = true; + callback(null, css, data, sheet, webInfo, path); + return; + } + } // TODO add tests around how this behaves when reloading + + + errors.remove(path); + instanceOptions.rootFileInfo = newFileInfo; + less.render(data, instanceOptions, function (e, result) { + if (e) { + e.href = path; + callback(e); + } else { + cache.setCSS(sheet.href, webInfo.lastModified, instanceOptions.modifyVars, result.css); + callback(null, result.css, data, sheet, webInfo, path); + } + }); } - child[i] = _clone(parent[i], depth - 1); + + fileManager.loadFile(sheet.href, null, instanceOptions, environment).then(function (loadedFile) { + loadInitialFileCallback(loadedFile); + }).catch(function (err) { + console.log(err); + callback(err); + }); } - if (Object.getOwnPropertySymbols) { - var symbols = Object.getOwnPropertySymbols(parent); - for (var i = 0; i < symbols.length; i++) { - // Don't need to worry about cloning a symbol because it is a primitive, - // like a number or string. - var symbol = symbols[i]; - var descriptor = Object.getOwnPropertyDescriptor(parent, symbol); - if (descriptor && !descriptor.enumerable && !includeNonEnumerable) { - continue; - } - child[symbol] = _clone(parent[symbol], depth - 1); - if (!descriptor.enumerable) { - Object.defineProperty(child, symbol, { - enumerable: false - }); - } + function loadStyleSheets(callback, reload, modifyVars) { + for (var i = 0; i < less.sheets.length; i++) { + loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars); } } - if (includeNonEnumerable) { - var allPropertyNames = Object.getOwnPropertyNames(parent); - for (var i = 0; i < allPropertyNames.length; i++) { - var propertyName = allPropertyNames[i]; - var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName); - if (descriptor && descriptor.enumerable) { - continue; - } - child[propertyName] = _clone(parent[propertyName], depth - 1); - Object.defineProperty(child, propertyName, { - enumerable: false - }); + function initRunningMode() { + if (less.env === 'development') { + less.watchTimer = setInterval(function () { + if (less.watchMode) { + fileManager.clearFileCache(); + loadStyleSheets(function (e, css, _, sheet, webInfo) { + if (e) { + errors.add(e, e.href || sheet.href); + } else if (css) { + browser.createCSS(window.document, css, sheet); + } + }); + } + }, options.poll); } - } + } // + // Watch mode + // - return child; - } - return _clone(parent, depth); -} + less.watch = function () { + if (!less.watchMode) { + less.env = 'development'; + initRunningMode(); + } -/** - * Simple flat clone using prototype, accepts only objects, usefull for property - * override on FLAT configuration object (no nested props). - * - * USE WITH CAUTION! This may not behave as you wish if you do not know how this - * works. - */ -clone.clonePrototype = function clonePrototype(parent) { - if (parent === null) - return null; - - var c = function () {}; - c.prototype = parent; - return new c(); -}; - -// private utility functions - -function __objToStr(o) { - return Object.prototype.toString.call(o); -} -clone.__objToStr = __objToStr; - -function __isDate(o) { - return typeof o === 'object' && __objToStr(o) === '[object Date]'; -} -clone.__isDate = __isDate; - -function __isArray(o) { - return typeof o === 'object' && __objToStr(o) === '[object Array]'; -} -clone.__isArray = __isArray; - -function __isRegExp(o) { - return typeof o === 'object' && __objToStr(o) === '[object RegExp]'; -} -clone.__isRegExp = __isRegExp; - -function __getRegExpFlags(re) { - var flags = ''; - if (re.global) flags += 'g'; - if (re.ignoreCase) flags += 'i'; - if (re.multiline) flags += 'm'; - return flags; -} -clone.__getRegExpFlags = __getRegExpFlags; - -return clone; -})(); - -if (typeof module === 'object' && module.exports) { - module.exports = clone; -} - -},{}],101:[function(require,module,exports){ -'use strict'; - -var asap = require('asap/raw'); - -function noop() {} - -// States: -// -// 0 - pending -// 1 - fulfilled with _value -// 2 - rejected with _value -// 3 - adopted the state of another promise, _value -// -// once the state is no longer pending (0) it is immutable - -// All `_` prefixed properties will be reduced to `_{random number}` -// at build time to obfuscate them and discourage their use. -// We don't use symbols or Object.defineProperty to fully hide them -// because the performance isn't good enough. - - -// to avoid using try/catch inside critical functions, we -// extract them to here. -var LAST_ERROR = null; -var IS_ERROR = {}; -function getThen(obj) { - try { - return obj.then; - } catch (ex) { - LAST_ERROR = ex; - return IS_ERROR; - } -} + this.watchMode = true; + return true; + }; -function tryCallOne(fn, a) { - try { - return fn(a); - } catch (ex) { - LAST_ERROR = ex; - return IS_ERROR; - } -} -function tryCallTwo(fn, a, b) { - try { - fn(a, b); - } catch (ex) { - LAST_ERROR = ex; - return IS_ERROR; - } -} + less.unwatch = function () { + clearInterval(less.watchTimer); + this.watchMode = false; + return false; + }; // + // Synchronously get all tags with the 'rel' attribute set to + // "stylesheet/less". + // -module.exports = Promise; -function Promise(fn) { - if (typeof this !== 'object') { - throw new TypeError('Promises must be constructed via new'); - } - if (typeof fn !== 'function') { - throw new TypeError('Promise constructor\'s argument is not a function'); - } - this._40 = 0; - this._65 = 0; - this._55 = null; - this._72 = null; - if (fn === noop) return; - doResolve(fn, this); -} -Promise._37 = null; -Promise._87 = null; -Promise._61 = noop; - -Promise.prototype.then = function(onFulfilled, onRejected) { - if (this.constructor !== Promise) { - return safeThen(this, onFulfilled, onRejected); - } - var res = new Promise(noop); - handle(this, new Handler(onFulfilled, onRejected, res)); - return res; -}; - -function safeThen(self, onFulfilled, onRejected) { - return new self.constructor(function (resolve, reject) { - var res = new Promise(noop); - res.then(resolve, reject); - handle(self, new Handler(onFulfilled, onRejected, res)); - }); -} -function handle(self, deferred) { - while (self._65 === 3) { - self = self._55; - } - if (Promise._37) { - Promise._37(self); - } - if (self._65 === 0) { - if (self._40 === 0) { - self._40 = 1; - self._72 = deferred; - return; - } - if (self._40 === 1) { - self._40 = 2; - self._72 = [self._72, deferred]; - return; - } - self._72.push(deferred); - return; - } - handleResolved(self, deferred); -} - -function handleResolved(self, deferred) { - asap(function() { - var cb = self._65 === 1 ? deferred.onFulfilled : deferred.onRejected; - if (cb === null) { - if (self._65 === 1) { - resolve(deferred.promise, self._55); - } else { - reject(deferred.promise, self._55); + less.registerStylesheetsImmediately = function () { + var links = document.getElementsByTagName('link'); + less.sheets = []; + + for (var i = 0; i < links.length; i++) { + if (links[i].rel === 'stylesheet/less' || links[i].rel.match(/stylesheet/) && links[i].type.match(typePattern)) { + less.sheets.push(links[i]); + } } - return; - } - var ret = tryCallOne(cb, self._55); - if (ret === IS_ERROR) { - reject(deferred.promise, LAST_ERROR); - } else { - resolve(deferred.promise, ret); - } - }); -} -function resolve(self, newValue) { - // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure - if (newValue === self) { - return reject( - self, - new TypeError('A promise cannot be resolved with itself.') - ); - } - if ( - newValue && - (typeof newValue === 'object' || typeof newValue === 'function') - ) { - var then = getThen(newValue); - if (then === IS_ERROR) { - return reject(self, LAST_ERROR); - } - if ( - then === self.then && - newValue instanceof Promise - ) { - self._65 = 3; - self._55 = newValue; - finale(self); - return; - } else if (typeof then === 'function') { - doResolve(then.bind(newValue), self); - return; - } - } - self._65 = 1; - self._55 = newValue; - finale(self); -} - -function reject(self, newValue) { - self._65 = 2; - self._55 = newValue; - if (Promise._87) { - Promise._87(self, newValue); - } - finale(self); -} -function finale(self) { - if (self._40 === 1) { - handle(self, self._72); - self._72 = null; - } - if (self._40 === 2) { - for (var i = 0; i < self._72.length; i++) { - handle(self, self._72[i]); - } - self._72 = null; - } -} + }; // + // Asynchronously get all tags with the 'rel' attribute set to + // "stylesheet/less", returning a Promise. + // -function Handler(onFulfilled, onRejected, promise){ - this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; - this.onRejected = typeof onRejected === 'function' ? onRejected : null; - this.promise = promise; -} -/** - * Take a potentially misbehaving resolver function and make sure - * onFulfilled and onRejected are only called once. - * - * Makes no guarantees about asynchrony. - */ -function doResolve(fn, promise) { - var done = false; - var res = tryCallTwo(fn, function (value) { - if (done) return; - done = true; - resolve(promise, value); - }, function (reason) { - if (done) return; - done = true; - reject(promise, reason); - }); - if (!done && res === IS_ERROR) { - done = true; - reject(promise, LAST_ERROR); - } -} + less.registerStylesheets = function () { + return new Promise(function (resolve, reject) { + less.registerStylesheetsImmediately(); + resolve(); + }); + }; // + // With this function, it's possible to alter variables and re-render + // CSS without reloading less-files + // -},{"asap/raw":99}],102:[function(require,module,exports){ -'use strict'; -//This file contains the ES6 extensions to the core Promises/A+ API + less.modifyVars = function (record) { + return less.refresh(true, record, false); + }; + + less.refresh = function (reload, modifyVars, clearFileCache) { + if ((reload || clearFileCache) && clearFileCache !== false) { + fileManager.clearFileCache(); + } -var Promise = require('./core.js'); + return new Promise(function (resolve, reject) { + var startTime; + var endTime; + var totalMilliseconds; + var remainingSheets; + startTime = endTime = new Date(); // Set counter for remaining unprocessed sheets + + remainingSheets = less.sheets.length; + + if (remainingSheets === 0) { + endTime = new Date(); + totalMilliseconds = endTime - startTime; + less.logger.info('Less has finished and no sheets were loaded.'); + resolve({ + startTime: startTime, + endTime: endTime, + totalMilliseconds: totalMilliseconds, + sheets: less.sheets.length + }); + } else { + // Relies on less.sheets array, callback seems to be guaranteed to be called for every element of the array + loadStyleSheets(function (e, css, _, sheet, webInfo) { + if (e) { + errors.add(e, e.href || sheet.href); + reject(e); + return; + } -module.exports = Promise; + if (webInfo.local) { + less.logger.info("Loading ".concat(sheet.href, " from cache.")); + } else { + less.logger.info("Rendered ".concat(sheet.href, " successfully.")); + } -/* Static Functions */ + browser.createCSS(window.document, css, sheet); + less.logger.info("CSS for ".concat(sheet.href, " generated in ").concat(new Date() - endTime, "ms")); // Count completed sheet -var TRUE = valuePromise(true); -var FALSE = valuePromise(false); -var NULL = valuePromise(null); -var UNDEFINED = valuePromise(undefined); -var ZERO = valuePromise(0); -var EMPTYSTRING = valuePromise(''); + remainingSheets--; // Check if the last remaining sheet was processed and then call the promise -function valuePromise(value) { - var p = new Promise(Promise._61); - p._65 = 1; - p._55 = value; - return p; -} -Promise.resolve = function (value) { - if (value instanceof Promise) return value; + if (remainingSheets === 0) { + totalMilliseconds = new Date() - startTime; + less.logger.info("Less has finished. CSS generated in ".concat(totalMilliseconds, "ms")); + resolve({ + startTime: startTime, + endTime: endTime, + totalMilliseconds: totalMilliseconds, + sheets: less.sheets.length + }); + } - if (value === null) return NULL; - if (value === undefined) return UNDEFINED; - if (value === true) return TRUE; - if (value === false) return FALSE; - if (value === 0) return ZERO; - if (value === '') return EMPTYSTRING; + endTime = new Date(); + }, reload, modifyVars); + } - if (typeof value === 'object' || typeof value === 'function') { - try { - var then = value.then; - if (typeof then === 'function') { - return new Promise(then.bind(value)); - } - } catch (ex) { - return new Promise(function (resolve, reject) { - reject(ex); + loadStyles(modifyVars); }); + }; + + less.refreshStyles = loadStyles; + return less; + }); + + /** + * Kicks off less and compiles any stylesheets + * used in the browser distributed version of less + * to kick-start less using the browser api + */ + var options$1 = defaultOptions(); + + if (window.less) { + for (var key in window.less) { + if (window.less.hasOwnProperty(key)) { + options$1[key] = window.less[key]; + } } } - return valuePromise(value); -}; - -Promise.all = function (arr) { - var args = Array.prototype.slice.call(arr); - - return new Promise(function (resolve, reject) { - if (args.length === 0) return resolve([]); - var remaining = args.length; - function res(i, val) { - if (val && (typeof val === 'object' || typeof val === 'function')) { - if (val instanceof Promise && val.then === Promise.prototype.then) { - while (val._65 === 3) { - val = val._55; - } - if (val._65 === 1) return res(i, val._55); - if (val._65 === 2) reject(val._55); - val.then(function (val) { - res(i, val); - }, reject); - return; - } else { - var then = val.then; - if (typeof then === 'function') { - var p = new Promise(then.bind(val)); - p.then(function (val) { - res(i, val); - }, reject); - return; - } - } - } - args[i] = val; - if (--remaining === 0) { - resolve(args); - } + + addDefaultOptions(window, options$1); + options$1.plugins = options$1.plugins || []; + + if (window.LESS_PLUGINS) { + options$1.plugins = options$1.plugins.concat(window.LESS_PLUGINS); + } + + var less = root(window, options$1); + window.less = less; + var css; + var head; + var style; // Always restore page visibility + + function resolveOrReject(data) { + if (data.filename) { + console.warn(data); } - for (var i = 0; i < args.length; i++) { - res(i, args[i]); + + if (!options$1.async) { + head.removeChild(style); } - }); -}; + } -Promise.reject = function (value) { - return new Promise(function (resolve, reject) { - reject(value); - }); -}; + if (options$1.onReady) { + if (/!watch/.test(window.location.hash)) { + less.watch(); + } // Simulate synchronous stylesheet loading by hiding page rendering -Promise.race = function (values) { - return new Promise(function (resolve, reject) { - values.forEach(function(value){ - Promise.resolve(value).then(resolve, reject); - }); - }); -}; -/* Prototype Methods */ + if (!options$1.async) { + css = 'body { display: none !important }'; + head = document.head || document.getElementsByTagName('head')[0]; + style = document.createElement('style'); + style.type = 'text/css'; -Promise.prototype['catch'] = function (onRejected) { - return this.then(null, onRejected); -}; + if (style.styleSheet) { + style.styleSheet.cssText = css; + } else { + style.appendChild(document.createTextNode(css)); + } -},{"./core.js":101}],103:[function(require,module,exports){ -// should work in any browser without browserify + head.appendChild(style); + } -if (typeof Promise.prototype.done !== 'function') { - Promise.prototype.done = function (onFulfilled, onRejected) { - var self = arguments.length ? this.then.apply(this, arguments) : this - self.then(null, function (err) { - setTimeout(function () { - throw err - }, 0) - }) + less.registerStylesheetsImmediately(); + less.pageLoadFinished = less.refresh(less.env === 'development').then(resolveOrReject, resolveOrReject); } -} -},{}],104:[function(require,module,exports){ -// not "use strict" so we can declare global "Promise" - -var asap = require('asap'); - -if (typeof Promise === 'undefined') { - Promise = require('./lib/core.js') - require('./lib/es6-extensions.js') -} -require('./polyfill-done.js'); + return less; -},{"./lib/core.js":101,"./lib/es6-extensions.js":102,"./polyfill-done.js":103,"asap":98}]},{},[2])(2) -}); \ No newline at end of file +})); diff --git a/dist/less.min.js b/dist/less.min.js index 59944494c..632460c09 100644 --- a/dist/less.min.js +++ b/dist/less.min.js @@ -1,18 +1,11 @@ -/*! - * Less - Leaner CSS v3.9.0 +/** + * Less - Leaner CSS v3.10.0 * http://lesscss.org - * - * Copyright (c) 2009-2018, Alexis Sellier + * + * Copyright (c) 2009-2019, Alexis Sellier * Licensed under the Apache-2.0 License. * + * @license Apache-2.0 */ - - /** * @license Apache-2.0 - */ - -!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.less=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g0||b.isFileProtocol?"development":"production");var c=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(a.location.hash);c&&(b.dumpLineNumbers=c[1]),void 0===b.useFileCache&&(b.useFileCache=!0),void 0===b.onReady&&(b.onReady=!0),b.relativeUrls&&(b.rewriteUrls="all")}},{"./browser":3,"./utils":11}],2:[function(a,b,c){function d(a){a.filename&&console.warn(a),e.async||h.removeChild(i)}a("promise/polyfill");var e=a("../less/default-options")();if(window.less)for(key in window.less)window.less.hasOwnProperty(key)&&(e[key]=window.less[key]);a("./add-default-options")(window,e),e.plugins=e.plugins||[],window.LESS_PLUGINS&&(e.plugins=e.plugins.concat(window.LESS_PLUGINS));var f=b.exports=a("./index")(window,e);window.less=f;var g,h,i;e.onReady&&(/!watch/.test(window.location.hash)&&f.watch(),e.async||(g="body { display: none !important }",h=document.head||document.getElementsByTagName("head")[0],i=document.createElement("style"),i.type="text/css",i.styleSheet?i.styleSheet.cssText=g:i.appendChild(document.createTextNode(g)),h.appendChild(i)),f.registerStylesheetsImmediately(),f.pageLoadFinished=f.refresh("development"===f.env).then(d,d))},{"../less/default-options":17,"./add-default-options":1,"./index":8,"promise/polyfill":104}],3:[function(a,b,c){var d=a("./utils");b.exports={createCSS:function(a,b,c){var e=c.href||"",f="less:"+(c.title||d.extractId(e)),g=a.getElementById(f),h=!1,i=a.createElement("style");i.setAttribute("type","text/css"),c.media&&i.setAttribute("media",c.media),i.id=f,i.styleSheet||(i.appendChild(a.createTextNode(b)),h=null!==g&&g.childNodes.length>0&&i.childNodes.length>0&&g.firstChild.nodeValue===i.firstChild.nodeValue);var j=a.getElementsByTagName("head")[0];if(null===g||h===!1){var k=c&&c.nextSibling||null;k?k.parentNode.insertBefore(i,k):j.appendChild(i)}if(g&&h===!1&&g.parentNode.removeChild(g),i.styleSheet)try{i.styleSheet.cssText=b}catch(l){throw new Error("Couldn't reassign styleSheet.cssText.")}},currentScript:function(a){var b=a.document;return b.currentScript||function(){var a=b.getElementsByTagName("script");return a[a.length-1]}()}}},{"./utils":11}],4:[function(a,b,c){b.exports=function(a,b,c){var d=null;if("development"!==b.env)try{d="undefined"==typeof a.localStorage?null:a.localStorage}catch(e){}return{setCSS:function(a,b,e,f){if(d){c.info("saving "+a+" to cache.");try{d.setItem(a,f),d.setItem(a+":timestamp",b),e&&d.setItem(a+":vars",JSON.stringify(e))}catch(g){c.error('failed to save "'+a+'" to local storage for caching.')}}},getCSS:function(a,b,c){var e=d&&d.getItem(a),f=d&&d.getItem(a+":timestamp"),g=d&&d.getItem(a+":vars");if(c=c||{},g=g||"{}",f&&b.lastModified&&new Date(b.lastModified).valueOf()===new Date(f).valueOf()&&JSON.stringify(c)===g)return e}}}},{}],5:[function(a,b,c){var d=a("./utils"),e=a("./browser");b.exports=function(a,b,c){function f(b,f){var g,h,i="less-error-message:"+d.extractId(f||""),j='
  • {content}
  • ',k=a.document.createElement("div"),l=[],m=b.filename||f,n=m.match(/([^\/]+(\?.*)?)$/)[1];k.id=i,k.className="less-error-message",h="

    "+(b.type||"Syntax")+"Error: "+(b.message||"There is an error in your .less file")+'

    in '+n+" ";var o=function(a,b,c){void 0!==a.extract[b]&&l.push(j.replace(/\{line\}/,(parseInt(a.line,10)||0)+(b-1)).replace(/\{class\}/,c).replace(/\{content\}/,a.extract[b]))};b.line&&(o(b,0,""),o(b,1,"line"),o(b,2,""),h+="on line "+b.line+", column "+(b.column+1)+":

      "+l.join("")+"
    "),b.stack&&(b.extract||c.logLevel>=4)&&(h+="
    Stack Trace
    "+b.stack.split("\n").slice(1).join("
    ")),k.innerHTML=h,e.createCSS(a.document,[".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),k.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),"development"===c.env&&(g=setInterval(function(){var b=a.document,c=b.body;c&&(b.getElementById(i)?c.replaceChild(k,b.getElementById(i)):c.insertBefore(k,c.firstChild),clearInterval(g))},10))}function g(b){var c=a.document.getElementById("less-error-message:"+d.extractId(b));c&&c.parentNode.removeChild(c)}function h(a){}function i(a){c.errorReporting&&"html"!==c.errorReporting?"console"===c.errorReporting?h(a):"function"==typeof c.errorReporting&&c.errorReporting("remove",a):g(a)}function j(a,d){var e="{line} {content}",f=a.filename||d,g=[],h=(a.type||"Syntax")+"Error: "+(a.message||"There is an error in your .less file")+" in "+f,i=function(a,b,c){void 0!==a.extract[b]&&g.push(e.replace(/\{line\}/,(parseInt(a.line,10)||0)+(b-1)).replace(/\{class\}/,c).replace(/\{content\}/,a.extract[b]))};a.line&&(i(a,0,""),i(a,1,"line"),i(a,2,""),h+=" on line "+a.line+", column "+(a.column+1)+":\n"+g.join("\n")),a.stack&&(a.extract||c.logLevel>=4)&&(h+="\nStack Trace\n"+a.stack),b.logger.error(h)}function k(a,b){c.errorReporting&&"html"!==c.errorReporting?"console"===c.errorReporting?j(a,b):"function"==typeof c.errorReporting&&c.errorReporting("add",a,b):f(a,b)}return{add:k,remove:i}}},{"./browser":3,"./utils":11}],6:[function(a,b,c){b.exports=function(b,c){var d=a("../less/environment/abstract-file-manager.js"),e={},f=function(){};return f.prototype=new d,f.prototype.alwaysMakePathsAbsolute=function(){return!0},f.prototype.join=function(a,b){return a?this.extractUrlParts(b,a).path:b},f.prototype.doXHR=function(a,d,e,f){function g(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):"function"==typeof d&&d(b.status,a)}var h=new XMLHttpRequest,i=!b.isFileProtocol||b.fileAsync;"function"==typeof h.overrideMimeType&&h.overrideMimeType("text/css"),c.debug("XHR: Getting '"+a+"'"),h.open("GET",a,i),h.setRequestHeader("Accept",d||"text/x-less, text/css; q=0.9, */*; q=0.5"),h.send(null),b.isFileProtocol&&!b.fileAsync?0===h.status||h.status>=200&&h.status<300?e(h.responseText):f(h.status,a):i?h.onreadystatechange=function(){4==h.readyState&&g(h,e,f)}:g(h,e,f)},f.prototype.supports=function(a,b,c,d){return!0},f.prototype.clearFileCache=function(){e={}},f.prototype.loadFile=function(a,b,c,d){b&&!this.isPathAbsolute(a)&&(a=b+a),a=c.ext?this.tryAppendExtension(a,c.ext):a,c=c||{};var f=this.extractUrlParts(a,window.location.href),g=f.url,h=this;return new Promise(function(a,b){if(c.useFileCache&&e[g])try{var d=e[g];return a({contents:d,filename:g,webInfo:{lastModified:new Date}})}catch(f){return b({filename:g,message:"Error loading file "+g+" error was "+f.message})}h.doXHR(g,c.mime,function(b,c){e[g]=b,a({contents:b,filename:g,webInfo:{lastModified:c}})},function(a,c){b({type:"File",message:"'"+c+"' wasn't found ("+a+")",href:g})})})},f}},{"../less/environment/abstract-file-manager.js":18}],7:[function(a,b,c){b.exports=function(){function b(){throw{type:"Runtime",message:"Image size functions are not supported in browser version of less"}}var c=a("./../less/functions/function-registry"),d={"image-size":function(a){return b(this,a),-1},"image-width":function(a){return b(this,a),-1},"image-height":function(a){return b(this,a),-1}};c.addMultiple(d)}},{"./../less/functions/function-registry":27}],8:[function(a,b,c){var d=a("./utils").addDataAttr,e=a("./browser");b.exports=function(b,c){function f(a){var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b}function g(a,b){var c=Array.prototype.slice.call(arguments,2);return function(){var d=c.concat(Array.prototype.slice.call(arguments,0));return a.apply(b,d)}}function h(a){for(var b,d=l.getElementsByTagName("style"),e=0;e=c&&console.log(a)},info:function(a){b.logLevel>=d&&console.log(a)},warn:function(a){b.logLevel>=e&&console.warn(a)},error:function(a){b.logLevel>=f&&console.error(a)}}]);for(var g=0;gg.Math.PARENS_DIVISION)||this.parensStack&&this.parensStack.length))},f.Eval.prototype.pathRequiresRewrite=function(a){var b=this.rewriteUrls===g.RewriteUrls.LOCAL?e:d;return b(a)},f.Eval.prototype.rewritePath=function(a,b){var c;return b=b||"",c=this.normalizePath(b+a),e(a)&&d(b)&&e(c)===!1&&(c="./"+c),c},f.Eval.prototype.normalizePath=function(a){var b,c=a.split("/").reverse();for(a=[];0!==c.length;)switch(b=c.pop()){case".":break;case"..":0===a.length||".."===a[a.length-1]?a.push(b):a.pop();break;default:a.push(b)}return a.join("/")}},{"./constants":12}],14:[function(a,b,c){b.exports={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgrey:"#a9a9a9",darkgreen:"#006400",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",grey:"#808080",green:"#008000",greenyellow:"#adff2f",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgrey:"#d3d3d3",lightgreen:"#90ee90",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370d8",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#d87093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"}},{}],15:[function(a,b,c){b.exports={colors:a("./colors"),unitConversions:a("./unit-conversions")}},{"./colors":14,"./unit-conversions":16}],16:[function(a,b,c){b.exports={length:{m:1,cm:.01,mm:.001,"in":.0254,px:.0254/96,pt:.0254/72,pc:.0254/72*12},duration:{s:1,ms:.001},angle:{rad:1/(2*Math.PI),deg:1/360,grad:.0025,turn:1}}},{}],17:[function(a,b,c){b.exports=function(){return{javascriptEnabled:!1,depends:!1,compress:!1,lint:!1,paths:[],color:!0,strictImports:!1,insecure:!1,rootpath:"",rewriteUrls:!1,ieCompat:!1,math:0,strictUnits:!1,globalVars:null,modifyVars:null,urlArgs:""}}},{}],18:[function(a,b,c){var d=function(){};d.prototype.getPath=function(a){var b=a.lastIndexOf("?");return b>0&&(a=a.slice(0,b)),b=a.lastIndexOf("/"),b<0&&(b=a.lastIndexOf("\\")),b<0?"":a.slice(0,b+1)},d.prototype.tryAppendExtension=function(a,b){return/(\.[a-z]*$)|([\?;].*)$/.test(a)?a:a+b},d.prototype.tryAppendLessExtension=function(a){return this.tryAppendExtension(a,".less")},d.prototype.supportsSync=function(){return!1},d.prototype.alwaysMakePathsAbsolute=function(){return!1},d.prototype.isPathAbsolute=function(a){return/^(?:[a-z-]+:|\/|\\|#)/i.test(a)},d.prototype.join=function(a,b){return a?a+b:b},d.prototype.pathDiff=function(a,b){var c,d,e,f,g=this.extractUrlParts(a),h=this.extractUrlParts(b),i="";if(g.hostPart!==h.hostPart)return"";for(d=Math.max(h.directories.length,g.directories.length),c=0;cparseInt(b[c])?-1:1;return 0},f.prototype.versionToString=function(a){for(var b="",c=0;c=0;h--){var i=g[h];if(i[f?"supportsSync":"supports"](a,b,c,e))return i}return null},e.prototype.addFileManager=function(a){this.fileManagers.push(a)},e.prototype.clearFileManagers=function(){this.fileManagers=[]},b.exports=e},{"../logger":39}],21:[function(a,b,c){var d=a("./function-registry"),e=a("../tree/anonymous"),f=a("../tree/keyword");d.addMultiple({"boolean":function(a){return a?f.True:f.False},"if":function(a,b,c){return a?b:c||new e}})},{"../tree/anonymous":50,"../tree/keyword":70,"./function-registry":27}],22:[function(a,b,c){function d(a,b,c){var d,f,g,h,i=b.alpha,j=c.alpha,k=[];g=j+i*(1-j);for(var l=0;l<3;l++)d=b.rgb[l]/255,f=c.rgb[l]/255,h=a(d,f),g&&(h=(j*f+i*(d-j*(d+f-h)))/g),k[l]=255*h;return new e(k,g)}var e=a("../tree/color"),f=a("./function-registry"),g={multiply:function(a,b){return a*b},screen:function(a,b){return a+b-a*b},overlay:function(a,b){return a*=2,a<=1?g.multiply(a,b):g.screen(a-1,b)},softlight:function(a,b){var c=1,d=a;return b>.5&&(d=1,c=a>.25?Math.sqrt(a):((16*a-12)*a+4)*a),a-(1-2*b)*d*(c-a)},hardlight:function(a,b){return g.overlay(b,a)},difference:function(a,b){return Math.abs(a-b)},exclusion:function(a,b){return a+b-2*a*b},average:function(a,b){return(a+b)/2},negation:function(a,b){return 1-Math.abs(a+b-1)}};for(var h in g)g.hasOwnProperty(h)&&(d[h]=d.bind(null,g[h]));f.addMultiple(d)},{"../tree/color":55,"./function-registry":27}],23:[function(a,b,c){function d(a){return Math.min(1,Math.max(0,a))}function e(a,b){var c=h.hsla(b.h,b.s,b.l,b.a);if(c)return c.value=a.value&&/^(rgb|hsl)/.test(a.value)?a.value:"rgb",c}function f(a){if(a instanceof i)return parseFloat(a.unit.is("%")?a.value/100:a.value);if("number"==typeof a)return a;throw{type:"Argument",message:"color functions take numbers as parameters"}}function g(a,b){return a instanceof i&&a.unit.is("%")?parseFloat(a.value*b/100):f(a)}var h,i=a("../tree/dimension"),j=a("../tree/color"),k=a("../tree/quoted"),l=a("../tree/anonymous"),m=a("./function-registry");h={rgb:function(a,b,c){var d=h.rgba(a,b,c,1);if(d)return d.value="rgb",d},rgba:function(a,b,c,d){try{if(a instanceof j)return d=b?f(b):a.alpha,new j(a.rgb,d,"rgba");var e=[a,b,c].map(function(a){return g(a,255)});return d=f(d),new j(e,d,"rgba")}catch(h){}},hsl:function(a,b,c){var d=h.hsla(a,b,c,1);if(d)return d.value="hsl",d},hsla:function(a,b,c,e){function g(a){return a=a<0?a+1:a>1?a-1:a,6*a<1?h+(i-h)*a*6:2*a<1?i:3*a<2?h+(i-h)*(2/3-a)*6:h}try{if(a instanceof j)return e=b?f(b):a.alpha,new j(a.rgb,e,"hsla");var h,i;a=f(a)%360/360,b=d(f(b)),c=d(f(c)),e=d(f(e)),i=c<=.5?c*(b+1):c+b-c*b,h=2*c-i;var k=[255*g(a+1/3),255*g(a),255*g(a-1/3)];return e=f(e),new j(k,e,"hsla")}catch(l){}},hsv:function(a,b,c){return h.hsva(a,b,c,1)},hsva:function(a,b,c,d){a=f(a)%360/360*360,b=f(b),c=f(c),d=f(d);var e,g;e=Math.floor(a/60%6),g=a/60-e;var i=[c,c*(1-b),c*(1-g*b),c*(1-(1-g)*b)],j=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return h.rgba(255*i[j[e][0]],255*i[j[e][1]],255*i[j[e][2]],d)},hue:function(a){return new i(a.toHSL().h)},saturation:function(a){return new i(100*a.toHSL().s,"%")},lightness:function(a){return new i(100*a.toHSL().l,"%")},hsvhue:function(a){return new i(a.toHSV().h)},hsvsaturation:function(a){return new i(100*a.toHSV().s,"%")},hsvvalue:function(a){return new i(100*a.toHSV().v,"%")},red:function(a){return new i(a.rgb[0])},green:function(a){return new i(a.rgb[1])},blue:function(a){return new i(a.rgb[2])},alpha:function(a){return new i(a.toHSL().a)},luma:function(a){return new i(a.luma()*a.alpha*100,"%")},luminance:function(a){var b=.2126*a.rgb[0]/255+.7152*a.rgb[1]/255+.0722*a.rgb[2]/255;return new i(b*a.alpha*100,"%")},saturate:function(a,b,c){if(!a.rgb)return null;var f=a.toHSL();return f.s+="undefined"!=typeof c&&"relative"===c.value?f.s*b.value/100:b.value/100,f.s=d(f.s),e(a,f)},desaturate:function(a,b,c){var f=a.toHSL();return f.s-="undefined"!=typeof c&&"relative"===c.value?f.s*b.value/100:b.value/100,f.s=d(f.s),e(a,f)},lighten:function(a,b,c){var f=a.toHSL();return f.l+="undefined"!=typeof c&&"relative"===c.value?f.l*b.value/100:b.value/100,f.l=d(f.l),e(a,f)},darken:function(a,b,c){var f=a.toHSL();return f.l-="undefined"!=typeof c&&"relative"===c.value?f.l*b.value/100:b.value/100,f.l=d(f.l),e(a,f)},fadein:function(a,b,c){var f=a.toHSL();return f.a+="undefined"!=typeof c&&"relative"===c.value?f.a*b.value/100:b.value/100,f.a=d(f.a),e(a,f)},fadeout:function(a,b,c){var f=a.toHSL();return f.a-="undefined"!=typeof c&&"relative"===c.value?f.a*b.value/100:b.value/100,f.a=d(f.a),e(a,f)},fade:function(a,b){var c=a.toHSL();return c.a=b.value/100,c.a=d(c.a),e(a,c)},spin:function(a,b){var c=a.toHSL(),d=(c.h+b.value)%360;return c.h=d<0?360+d:d,e(a,c)},mix:function(a,b,c){a.toHSL&&b.toHSL||(console.log(b.type),console.dir(b)),c||(c=new i(50));var d=c.value/100,e=2*d-1,f=a.toHSL().a-b.toHSL().a,g=((e*f==-1?e:(e+f)/(1+e*f))+1)/2,h=1-g,k=[a.rgb[0]*g+b.rgb[0]*h,a.rgb[1]*g+b.rgb[1]*h,a.rgb[2]*g+b.rgb[2]*h],l=a.alpha*d+b.alpha*(1-d);return new j(k,l)},greyscale:function(a){return h.desaturate(a,new i(100))},contrast:function(a,b,c,d){if(!a.rgb)return null;if("undefined"==typeof c&&(c=h.rgba(255,255,255,1)),"undefined"==typeof b&&(b=h.rgba(0,0,0,1)),b.luma()>c.luma()){var e=c;c=b,b=e}return d="undefined"==typeof d?.43:f(d),a.luma()=v&&this.context.ieCompat!==!1?(h.warn("Skipped data-uri embedding of "+j+" because its size ("+u.length+" characters) exceeds IE8-safe "+v+" characters!"),g(this,f||a)):new d(new c('"'+u+'"',u,(!1),this.index,this.currentFileInfo),this.index,this.currentFileInfo)})}},{"../logger":39,"../tree/quoted":80,"../tree/url":85,"../utils":89,"./function-registry":27}],25:[function(a,b,c){var d=a("../tree/keyword"),e=a("./function-registry"),f={eval:function(){var a=this.value_,b=this.error_;if(b)throw b;if(null!=a)return a?d.True:d.False},value:function(a){this.value_=a},error:function(a){this.error_=a},reset:function(){this.value_=this.error_=null}};e.add("default",f.eval.bind(f)),b.exports=f},{"../tree/keyword":70,"./function-registry":27}],26:[function(a,b,c){var d=a("../tree/expression"),e=function(a,b,c,d){this.name=a.toLowerCase(),this.index=c,this.context=b,this.currentFileInfo=d,this.func=b.frames[0].functionRegistry.get(this.name)};e.prototype.isValid=function(){return Boolean(this.func)},e.prototype.call=function(a){return Array.isArray(a)&&(a=a.filter(function(a){return"Comment"!==a.type}).map(function(a){if("Expression"===a.type){ -var b=a.value.filter(function(a){return"Comment"!==a.type});return 1===b.length?b[0]:new d(b)}return a})),this.func.apply(this,a)},b.exports=e},{"../tree/expression":64}],27:[function(a,b,c){function d(a){return{_data:{},add:function(a,b){a=a.toLowerCase(),this._data.hasOwnProperty(a),this._data[a]=b},addMultiple:function(a){Object.keys(a).forEach(function(b){this.add(b,a[b])}.bind(this))},get:function(b){return this._data[b]||a&&a.get(b)},getLocalFunctions:function(){return this._data},inherit:function(){return d(this)},create:function(a){return d(a)}}}b.exports=d(null)},{}],28:[function(a,b,c){b.exports=function(b){var c={functionRegistry:a("./function-registry"),functionCaller:a("./function-caller")};return a("./boolean"),a("./default"),a("./color"),a("./color-blending"),a("./data-uri")(b),a("./list"),a("./math"),a("./number"),a("./string"),a("./svg")(b),a("./types"),c}},{"./boolean":21,"./color":23,"./color-blending":22,"./data-uri":24,"./default":25,"./function-caller":26,"./function-registry":27,"./list":29,"./math":31,"./number":32,"./string":33,"./svg":34,"./types":35}],29:[function(a,b,c){var d=a("../tree/comment"),e=a("../tree/dimension"),f=a("../tree/declaration"),g=a("../tree/expression"),h=a("../tree/ruleset"),i=a("../tree/selector"),j=a("../tree/element"),k=a("./function-registry"),l=function(a){var b=Array.isArray(a.value)?a.value:Array(a);return b};k.addMultiple({_SELF:function(a){return a},extract:function(a,b){return b=b.value-1,l(a)[b]},length:function(a){return new e(l(a).length)},range:function(a,b,c){var d,f,h=1,i=[];b?(f=b,d=a.value,c&&(h=c.value)):(d=1,f=a);for(var j=d;j<=f.value;j+=h)i.push(new e(j,f.unit));return new g(i)},each:function(a,b){var c,g,k=[];g=a.value?Array.isArray(a.value)?a.value:[a.value]:a.ruleset?a.ruleset.rules:a.rules?a.rules:Array.isArray(a)?a:[a];var l="@value",m="@key",n="@index";b.params?(l=b.params[0]&&b.params[0].name,m=b.params[1]&&b.params[1].name,n=b.params[2]&&b.params[2].name,b=b.rules):b=b.ruleset;for(var o=0;oi.value)&&(m[f]=g);else{if(void 0!==k&&j!==k)throw{type:"Argument",message:"incompatible types"};n[j]=m.length,m.push(g)}else Array.isArray(b[c].value)&&Array.prototype.push.apply(b,Array.prototype.slice.call(b[c].value));return 1==m.length?m[0]:(b=m.map(function(a){return a.toCSS(this.context)}).join(this.context.compress?",":", "),new e((a?"min":"max")+"("+b+")"))};f.addMultiple({min:function(){return h(!0,arguments)},max:function(){return h(!1,arguments)},convert:function(a,b){return a.convertTo(b.value)},pi:function(){return new d(Math.PI)},mod:function(a,b){return new d(a.value%b.value,a.unit)},pow:function(a,b){if("number"==typeof a&&"number"==typeof b)a=new d(a),b=new d(b);else if(!(a instanceof d&&b instanceof d))throw{type:"Argument",message:"arguments must be numbers"};return new d(Math.pow(a.value,b.value),a.unit)},percentage:function(a){var b=g._math(function(a){return 100*a},"%",a);return b}})},{"../tree/anonymous":50,"../tree/dimension":62,"./function-registry":27,"./math-helper.js":30}],33:[function(a,b,c){var d=a("../tree/quoted"),e=a("../tree/anonymous"),f=a("../tree/javascript"),g=a("./function-registry");g.addMultiple({e:function(a){return new e(a instanceof f?a.evaluated:a.value)},escape:function(a){return new e(encodeURI(a.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},replace:function(a,b,c,e){var f=a.value;return c="Quoted"===c.type?c.value:c.toCSS(),f=f.replace(new RegExp(b.value,e?e.value:""),c),new d(a.quote||"",f,a.escaped)},"%":function(a){for(var b=Array.prototype.slice.call(arguments,1),c=a.value,e=0;e",k=0;k";return j+="',j=encodeURIComponent(j),j="data:image/svg+xml,"+j,new g(new f("'"+j+"'",j,(!1),this.index,this.currentFileInfo),this.index,this.currentFileInfo)})}},{"../tree/color":55,"../tree/dimension":62,"../tree/expression":64,"../tree/quoted":80,"../tree/url":85,"./function-registry":27}],35:[function(a,b,c){var d=a("../tree/keyword"),e=a("../tree/detached-ruleset"),f=a("../tree/dimension"),g=a("../tree/color"),h=a("../tree/quoted"),i=a("../tree/anonymous"),j=a("../tree/url"),k=a("../tree/operation"),l=a("./function-registry"),m=function(a,b){return a instanceof b?d.True:d.False},n=function(a,b){if(void 0===b)throw{type:"Argument",message:"missing the required second argument to isunit."};if(b="string"==typeof b.value?b.value:b,"string"!=typeof b)throw{type:"Argument",message:"Second argument to isunit should be a unit or a string."};return a instanceof f&&a.unit.is(b)?d.True:d.False};l.addMultiple({isruleset:function(a){return m(a,e)},iscolor:function(a){return m(a,g)},isnumber:function(a){return m(a,f)},isstring:function(a){return m(a,h)},iskeyword:function(a){return m(a,d)},isurl:function(a){return m(a,j)},ispixel:function(a){return n(a,"px")},ispercentage:function(a){return n(a,"%")},isem:function(a){return n(a,"em")},isunit:n,unit:function(a,b){if(!(a instanceof f))throw{type:"Argument",message:"the first argument to unit must be a number"+(a instanceof k?". Have you forgotten parenthesis?":"")};return b=b?b instanceof d?b.value:b.toCSS():"",new f(a.value,b)},"get-unit":function(a){return new i(a.unit)}})},{"../tree/anonymous":50,"../tree/color":55,"../tree/detached-ruleset":61,"../tree/dimension":62,"../tree/keyword":70,"../tree/operation":77,"../tree/quoted":80,"../tree/url":85,"./function-registry":27}],36:[function(a,b,c){var d=a("./contexts"),e=a("./parser/parser"),f=a("./less-error"),g=a("./utils"),h=("undefined"==typeof Promise?a("promise"):Promise,a("./logger"));b.exports=function(a){var b=function(a,b,c){this.less=a,this.rootFilename=c.filename,this.paths=b.paths||[],this.contents={},this.contentsIgnoredChars={},this.mime=b.mime,this.error=null,this.context=b,this.queue=[],this.files={}};return b.prototype.push=function(b,c,i,j,k){var l=this,m=this.context.pluginManager.Loader;this.queue.push(b);var n=function(a,c,d){l.queue.splice(l.queue.indexOf(b),1);var e=d===l.rootFilename;j.optional&&a?(k(null,{rules:[]},!1,null),h.info("The file "+d+" was skipped because it was not found and the import was marked optional.")):(l.files[d]||j.inline||(l.files[d]={root:c,options:j}),a&&!l.error&&(l.error=a),k(a,c,e,d))},o={rewriteUrls:this.context.rewriteUrls,entryPath:i.entryPath,rootpath:i.rootpath,rootFilename:i.rootFilename},p=a.getFileManager(b,i.currentDirectory,this.context,a);if(!p)return void n({message:"Could not find a file-manager for "+b});var q,r=function(a){var b,c=a.filename,g=a.contents.replace(/^\uFEFF/,"");o.currentDirectory=p.getPath(c),o.rewriteUrls&&(o.rootpath=p.join(l.context.rootpath||"",p.pathDiff(o.currentDirectory,o.entryPath)),!p.isPathAbsolute(o.rootpath)&&p.alwaysMakePathsAbsolute()&&(o.rootpath=p.join(o.entryPath,o.rootpath))),o.filename=c;var h=new d.Parse(l.context);h.processImports=!1,l.contents[c]=g,(i.reference||j.reference)&&(o.reference=!0),j.isPlugin?(b=m.evalPlugin(g,h,l,j.pluginArgs,o),b instanceof f?n(b,null,c):n(null,b,c)):j.inline?n(null,g,c):!l.files[c]||l.files[c].options.multiple||j.multiple?new e(h,l,o).parse(g,function(a,b){n(a,b,c)}):n(null,l.files[c].root,c)},s=g.clone(this.context);c&&(s.ext=j.isPlugin?".js":".less"),q=j.isPlugin?m.loadPlugin(b,i.currentDirectory,s,a,p):p.loadFile(b,i.currentDirectory,s,a,function(a,b){a?n(a):r(b)}),q&&q.then(r,n)},b}},{"./contexts":13,"./less-error":38,"./logger":39,"./parser/parser":44,"./utils":89,promise:void 0}],37:[function(a,b,c){b.exports=function(b,c){var d,e,f,g,h,i,j={version:[3,9,0],data:a("./data"),tree:a("./tree"),Environment:h=a("./environment/environment"),AbstractFileManager:a("./environment/abstract-file-manager"),AbstractPluginLoader:a("./environment/abstract-plugin-loader"),environment:b=new h(b,c),visitors:a("./visitors"),Parser:a("./parser/parser"),functions:a("./functions")(b),contexts:a("./contexts"),SourceMapOutput:d=a("./source-map-output")(b),SourceMapBuilder:e=a("./source-map-builder")(d,b),ParseTree:f=a("./parse-tree")(e),ImportManager:g=a("./import-manager")(b),render:a("./render")(b,f,g),parse:a("./parse")(b,f,g),LessError:a("./less-error"),transformTree:a("./transform-tree"),utils:a("./utils"),PluginManager:a("./plugin-manager"),logger:a("./logger")},k=function(a){return function(){var b=Object.create(a.prototype);return a.apply(b,Array.prototype.slice.call(arguments,0)),b}},l=Object.create(j);for(var m in j.tree)if(i=j.tree[m],"function"==typeof i)l[m.toLowerCase()]=k(i);else{l[m]=Object.create(null);for(var n in i)l[m][n.toLowerCase()]=k(i[n])}return l}},{"./contexts":13,"./data":15,"./environment/abstract-file-manager":18,"./environment/abstract-plugin-loader":19,"./environment/environment":20,"./functions":28,"./import-manager":36,"./less-error":38,"./logger":39,"./parse":41,"./parse-tree":40,"./parser/parser":44,"./plugin-manager":45,"./render":46,"./source-map-builder":47,"./source-map-output":48,"./transform-tree":49,"./tree":67,"./utils":89,"./visitors":93}],38:[function(a,b,c){var d=a("./utils"),e=b.exports=function(a,b,c){Error.call(this);var e=a.filename||c;if(this.message=a.message,this.stack=a.stack,b&&e){var f=b.contents[e],g=d.getLocation(a.index,f),h=g.line,i=g.column,j=a.call&&d.getLocation(a.call,f).line,k=f?f.split("\n"):"";if(this.type=a.type||"Syntax",this.filename=e,this.index=a.index,this.line="number"==typeof h?h+1:null,this.column=i,!this.line&&this.stack){var l=this.stack.match(/(|Function):(\d+):(\d+)/);l&&(l[2]&&(this.line=parseInt(l[2])-2),l[3]&&(this.column=parseInt(l[3])))}this.callLine=j+1,this.callExtract=k[j],this.extract=[k[this.line-2],k[this.line-1],k[this.line]]}};if("undefined"==typeof Object.create){var f=function(){};f.prototype=Error.prototype,e.prototype=new f}else e.prototype=Object.create(Error.prototype);e.prototype.constructor=e,e.prototype.toString=function(a){a=a||{};var b="",c=this.extract||[],d=[],e=function(a){return a};if(a.stylize){var f=typeof a.stylize;if("function"!==f)throw Error("options.stylize should be a function, got a "+f+"!");e=a.stylize}if(null!==this.line){if("string"==typeof c[0]&&d.push(e(this.line-1+" "+c[0],"grey")),"string"==typeof c[1]){var g=this.line+" ";c[1]&&(g+=c[1].slice(0,this.column)+e(e(e(c[1].substr(this.column,1),"bold")+c[1].slice(this.column+1),"red"),"inverse")),d.push(g)}"string"==typeof c[2]&&d.push(e(this.line+1+" "+c[2],"grey")),d=d.join("\n")+e("","reset")+"\n"}return b+=e(this.type+"Error: "+this.message,"red"),this.filename&&(b+=e(" in ","red")+this.filename),this.line&&(b+=e(" on line "+this.line+", column "+(this.column+1)+":","grey")),b+="\n"+d,this.callLine&&(b+=e("from ","red")+(this.filename||"")+"/n",b+=e(this.callLine,"grey")+" "+this.callExtract+"/n"),b}},{"./utils":89}],39:[function(a,b,c){b.exports={error:function(a){this._fireEvent("error",a)},warn:function(a){this._fireEvent("warn",a)},info:function(a){this._fireEvent("info",a)},debug:function(a){this._fireEvent("debug",a)},addListener:function(a){this._listeners.push(a)},removeListener:function(a){for(var b=0;b=97&&j<=122||j<34))switch(j){case 40:o++,e=h;continue;case 41:if(--o<0)return b("missing opening `(`",h);continue;case 59:o||c();continue;case 123:n++,d=h;continue;case 125:if(--n<0)return b("missing opening `{`",h);n||o||c();continue;case 92:if(h96)){if(k==j){l=1;break}if(92==k){if(h==m-1)return b("unescaped `\\`",h);h++}}if(l)continue;return b("unmatched `"+String.fromCharCode(j)+"`",i);case 47:if(o||h==m-1)continue;if(k=a.charCodeAt(h+1),47==k)for(h+=2;hd&&g>f?b("missing closing `}` or `*/`",d):b("missing closing `}`",d):0!==o?b("missing closing `)`",e):(c(!0),p)}},{}],43:[function(a,b,c){var d=a("./chunker");b.exports=function(){function a(d){for(var e,f,j,p=k.i,q=c,s=k.i-i,t=k.i+h.length-s,u=k.i+=d,v=b;k.i=0){j={index:k.i,text:v.substr(k.i,x+2-k.i),isLineComment:!1},k.i+=j.text.length-1,k.commentStore.push(j);continue}}break}if(e!==l&&e!==n&&e!==m&&e!==o)break}if(h=h.slice(d+k.i-u+s),i=k.i,!h.length){if(ce||k.i===e&&a&&!f)&&(e=k.i,f=a);var b=j.pop();h=b.current,i=k.i=b.i,c=b.j},k.forget=function(){j.pop()},k.isWhitespace=function(a){var c=k.i+(a||0),d=b.charCodeAt(c);return d===l||d===o||d===m||d===n},k.$re=function(b){k.i>i&&(h=h.slice(k.i-i),i=k.i);var c=b.exec(h);return c?(a(c[0].length),"string"==typeof c?c:1===c.length?c[0]:c):null},k.$char=function(c){return b.charAt(k.i)!==c?null:(a(1),c)},k.$str=function(c){for(var d=c.length,e=0;el&&(p=!1)}q=r}while(p);return f?f:null},k.autoCommentAbsorb=!0,k.commentStore=[],k.finished=!1,k.peek=function(a){if("string"==typeof a){for(var c=0;cs||a=b.length;return k.i=b.length-1,furthestChar:b[k.i]}},k}},{"./chunker":42}],44:[function(a,b,c){var d=a("../less-error"),e=a("../tree"),f=a("../visitors"),g=a("./parser-input"),h=a("../utils"),i=a("../functions/function-registry"),j=function k(a,b,c){function j(a,e){throw new d({index:q.i,filename:c.filename,type:e||"Syntax",message:a},b)}function l(a,b){var c=a instanceof Function?a.call(p):q.$re(a);return c?c:void j(b||("string"==typeof a?"expected '"+a+"' got '"+q.currentChar()+"'":"unexpected token"))}function m(a,b){return q.$char(a)?a:void j(b||"expected '"+a+"' got '"+q.currentChar()+"'")}function n(a){var b=c.filename;return{lineNumber:h.getLocation(a,q.getInput()).line+1,fileName:b}}function o(a,c,e,f,g){var h,i=[],j=q;try{j.start(a,!1,function(a,b){g({message:a,index:b+e})});for(var k,l,m=0;k=c[m];m++)l=j.i,h=p[k](),h?(h._index=l+e,h._fileInfo=f,i.push(h)):i.push(null);var n=j.end();n.isFinished?g(null,i):g(!0,null)}catch(o){throw new d({index:o.index+e,message:o.message},b,f.filename)}}var p,q=g();return{parserInput:q,imports:b,fileInfo:c,parseNode:o,parse:function(g,h,j){var l,m,n,o,p=null,r="";if(m=j&&j.globalVars?k.serializeVars(j.globalVars)+"\n":"",n=j&&j.modifyVars?"\n"+k.serializeVars(j.modifyVars):"",a.pluginManager)for(var s=a.pluginManager.getPreProcessors(),t=0;t")}return a},args:function(a){var b,c,d,f,g,h,i,k=p.entities,l={args:null,variadic:!1},m=[],n=[],o=[],r=!0;for(q.save();;){if(a)h=p.detachedRuleset()||p.expression();else{if(q.commentStore.length=0,q.$str("...")){l.variadic=!0,q.$char(";")&&!b&&(b=!0),(b?n:o).push({variadic:!0});break}h=k.variable()||k.property()||k.literal()||k.keyword()||this.call(!0)}if(!h||!r)break;f=null,h.throwAwayComments&&h.throwAwayComments(),g=h;var s=null;if(a?h.value&&1==h.value.length&&(s=h.value[0]):s=h,s&&(s instanceof e.Variable||s instanceof e.Property))if(q.$char(":")){if(m.length>0&&(b&&j("Cannot mix ; and , as delimiter types"),c=!0),g=p.detachedRuleset()||p.expression(),!g){if(!a)return q.restore(),l.args=[],l;j("could not understand value for named argument")}f=d=s.name}else if(q.$str("...")){if(!a){l.variadic=!0,q.$char(";")&&!b&&(b=!0),(b?n:o).push({name:h.name,variadic:!0});break}i=!0}else a||(d=f=s.name,g=null);g&&m.push(g),o.push({name:f,value:g,expand:i}),q.$char(",")?r=!0:(r=";"===q.$char(";"),(r||b)&&(c&&j("Cannot mix ; and , as delimiter types"),b=!0,m.length>1&&(g=new e.Value(m)),n.push({name:d,value:g,expand:i}),d=null,m=[],c=!1))}return q.forget(),l.args=b?n:o,l},definition:function(){var a,b,c,d,f=[],g=!1;if(!("."!==q.currentChar()&&"#"!==q.currentChar()||q.peek(/^[^{]*\}/)))if(q.save(),b=q.$re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){a=b[1];var h=this.args(!1);if(f=h.args,g=h.variadic,!q.$char(")"))return void q.restore("Missing closing ')'");if(q.commentStore.length=0,q.$str("when")&&(d=l(p.conditions,"expected condition")),c=p.block())return q.forget(),new e.mixin.Definition(a,f,c,d,g);q.restore()}else q.forget()},ruleLookups:function(){var a,b,c=[];if("["===q.currentChar()){for(;;){if(q.save(),b=null,a=this.lookupValue(),!a&&""!==a){q.restore();break}c.push(a),q.forget()}return c.length>0?c:void 0}},lookupValue:function(){if(q.save(),!q.$char("["))return void q.restore();var a=q.$re(/^(?:[@$]{0,2})[_a-zA-Z0-9-]*/);return q.$char("]")&&(a||""===a)?(q.forget(),a):void q.restore()}},entity:function(){var a=this.entities;return this.comment()||a.literal()||a.variable()||a.url()||a.property()||a.call()||a.keyword()||this.mixin.call(!0)||a.javascript()},end:function(){return q.$char(";")||q.peek("}")},ieAlpha:function(){var a;if(q.$re(/^opacity=/i))return a=q.$re(/^\d+/),a||(a=l(p.entities.variable,"Could not parse alpha"), -a="@{"+a.name.slice(1)+"}"),m(")"),new e.Quoted("","alpha(opacity="+a+")")},element:function(){var a,b,d,f=q.i;if(b=this.combinator(),a=q.$re(/^(?:\d+\.\d+|\d+)%/)||q.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||q.$char("*")||q.$char("&")||this.attribute()||q.$re(/^\([^&()@]+\)/)||q.$re(/^[\.#:](?=@)/)||this.entities.variableCurly(),a||(q.save(),q.$char("(")?(d=this.selector(!1))&&q.$char(")")?(a=new e.Paren(d),q.forget()):q.restore("Missing closing ')'"):q.forget()),a)return new e.Element(b,a,a instanceof e.Variable,f,c)},combinator:function(){var a=q.currentChar();if("/"===a){q.save();var b=q.$re(/^\/[a-z]+\//i);if(b)return q.forget(),new e.Combinator(b);q.restore()}if(">"===a||"+"===a||"~"===a||"|"===a||"^"===a){for(q.i++,"^"===a&&"^"===q.currentChar()&&(a="^^",q.i++);q.isWhitespace();)q.i++;return new e.Combinator(a)}return new e.Combinator(q.isWhitespace(-1)?" ":null)},selector:function(a){var b,d,f,g,h,i,k,m=q.i;for(a=a!==!1;(a&&(d=this.extend())||a&&(i=q.$str("when"))||(g=this.element()))&&(i?k=l(this.conditions,"expected condition"):k?j("CSS guard can only be used at the end of selector"):d?h=h?h.concat(d):d:(h&&j("Extend can only be used at the end of selector"),f=q.currentChar(),b?b.push(g):b=[g],g=null),"{"!==f&&"}"!==f&&";"!==f&&","!==f&&")"!==f););return b?new e.Selector(b,h,k,m,c):void(h&&j("Extend must be used to extend a selector, it cannot be used on its own"))},selectors:function(){for(var a,b;;){if(a=this.selector(),!a)break;if(b?b.push(a):b=[a],q.commentStore.length=0,a.condition&&b.length>1&&j("Guards are only currently allowed on a single selector."),!q.$char(","))break;a.condition&&j("Guards are only currently allowed on a single selector."),q.commentStore.length=0}return b},attribute:function(){if(q.$char("[")){var a,b,c,d=this.entities;return(a=d.variableCurly())||(a=l(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/)),c=q.$re(/^[|~*$^]?=/),c&&(b=d.quoted()||q.$re(/^[0-9]+%/)||q.$re(/^[\w-]+/)||d.variableCurly()),m("]"),new e.Attribute(a,c,b)}},block:function(){var a;if(q.$char("{")&&(a=this.primary())&&q.$char("}"))return a},blockRuleset:function(){var a=this.block();return a&&(a=new e.Ruleset(null,a)),a},detachedRuleset:function(){var a,b,c;if(q.save(),q.$re(/^[.#]\(/)&&(a=this.mixin.args(!1),b=a.args,c=a.variadic,!q.$char(")")))return void q.restore();var d=this.blockRuleset();return d?(q.forget(),b?new e.mixin.Definition(null,b,d,null,c):new e.DetachedRuleset(d)):void q.restore()},ruleset:function(){var b,c,d;if(q.save(),a.dumpLineNumbers&&(d=n(q.i)),b=this.selectors(),b&&(c=this.block())){q.forget();var f=new e.Ruleset(b,c,a.strictImports);return a.dumpLineNumbers&&(f.debugInfo=d),f}q.restore()},declaration:function(){var a,b,d,f,g,h,i=q.i,j=q.currentChar();if("."!==j&&"#"!==j&&"&"!==j&&":"!==j)if(q.save(),a=this.variable()||this.ruleProperty()){if(h="string"==typeof a,h&&(b=this.detachedRuleset(),b&&(d=!0)),q.commentStore.length=0,!b){if(g=!h&&a.length>1&&a.pop().value,b=a[0].value&&"--"===a[0].value.slice(0,2)?this.permissiveValue():this.anonymousValue())return q.forget(),new e.Declaration(a,b,(!1),g,i,c);b||(b=this.value()),b?f=this.important():h&&(b=this.permissiveValue())}if(b&&(this.end()||d))return q.forget(),new e.Declaration(a,b,f,g,i,c);q.restore()}else q.restore()},anonymousValue:function(){var a=q.i,b=q.$re(/^([^.#@\$+\/'"*`(;{}-]*);/);if(b)return new e.Anonymous(b[1],a)},permissiveValue:function(a){function b(){var a=q.currentChar();return"string"==typeof i?a===i:i.test(a)}var d,f,g,h,i=a||";",k=q.i,l=[];if(!b()){h=[];do f=this.comment(),f?h.push(f):(f=this.entity(),f&&h.push(f));while(f);if(g=b(),h.length>0){if(h=new e.Expression(h),g)return h;l.push(h)," "===q.prevChar()&&l.push(new e.Anonymous(" ",k))}if(q.save(),h=q.$parseUntil(i)){if("string"==typeof h&&j("Expected '"+h+"'","Parse"),1===h.length&&" "===h[0])return q.forget(),new e.Anonymous("",k);var m;for(d=0;d0)return new e.Expression(f)},mediaFeatures:function(){var a,b=this.entities,c=[];do if(a=this.mediaFeature()){if(c.push(a),!q.$char(","))break}else if(a=b.variable()||b.mixinLookup(),a&&(c.push(a),!q.$char(",")))break;while(a);return c.length>0?c:null},media:function(){var b,d,f,g,h=q.i;return a.dumpLineNumbers&&(g=n(h)),q.save(),q.$str("@media")?(b=this.mediaFeatures(),d=this.block(),d||j("media definitions require block statements after any features"),q.forget(),f=new e.Media(d,b,h,c),a.dumpLineNumbers&&(f.debugInfo=g),f):void q.restore()},plugin:function(){var a,b,d,f=q.i,g=q.$re(/^@plugin?\s+/);if(g){if(b=this.pluginArgs(),d=b?{pluginArgs:b,isPlugin:!0}:{isPlugin:!0},a=this.entities.quoted()||this.entities.url())return q.$char(";")||(q.i=f,j("missing semi-colon on @plugin")),new e.Import(a,null,d,f,c);q.i=f,j("malformed @plugin statement")}},pluginArgs:function(){if(q.save(),!q.$char("("))return q.restore(),null;var a=q.$re(/^\s*([^\);]+)\)\s*/);return a[1]?(q.forget(),a[1].trim()):(q.restore(),null)},atrule:function(){var b,d,f,g,h,i,k,l=q.i,m=!0,o=!0;if("@"===q.currentChar()){if(d=this["import"]()||this.plugin()||this.media())return d;if(q.save(),b=q.$re(/^@[a-z-]+/)){switch(g=b,"-"==b.charAt(1)&&b.indexOf("-",2)>0&&(g="@"+b.slice(b.indexOf("-",2)+1)),g){case"@charset":h=!0,m=!1;break;case"@namespace":i=!0,m=!1;break;case"@keyframes":case"@counter-style":h=!0;break;case"@document":case"@supports":k=!0,o=!1;break;default:k=!0}return q.commentStore.length=0,h?(d=this.entity(),d||j("expected "+b+" identifier")):i?(d=this.expression(),d||j("expected "+b+" expression")):k&&(d=this.permissiveValue(/^[{;]/),m="{"===q.currentChar(),d?d.value||(d=null):m||";"===q.currentChar()||j(b+" rule is missing block or ending semi-colon")),m&&(f=this.blockRuleset()),f||!m&&d&&q.$char(";")?(q.forget(),new e.AtRule(b,d,f,l,c,a.dumpLineNumbers?n(l):null,o)):void q.restore("at-rule options not recognised")}}},value:function(){var a,b=[],c=q.i;do if(a=this.expression(),a&&(b.push(a),!q.$char(",")))break;while(a);if(b.length>0)return new e.Value(b,c)},important:function(){if("!"===q.currentChar())return q.$re(/^! *important/)},sub:function(){var a,b;return q.save(),q.$char("(")?(a=this.addition(),a&&q.$char(")")?(q.forget(),b=new e.Expression([a]),b.parens=!0,b):void q.restore("Expected ')'")):void q.restore()},multiplication:function(){var a,b,c,d,f;if(a=this.operand()){for(f=q.isWhitespace(-1);;){if(q.peek(/^\/[*\/]/))break;if(q.save(),c=q.$char("/")||q.$char("*")||q.$str("./"),!c){q.forget();break}if(b=this.operand(),!b){q.restore();break}q.forget(),a.parensInOp=!0,b.parensInOp=!0,d=new e.Operation(c,[d||a,b],f),f=q.isWhitespace(-1)}return d||a}},addition:function(){var a,b,c,d,f;if(a=this.multiplication()){for(f=q.isWhitespace(-1);;){if(c=q.$re(/^[-+]\s+/)||!f&&(q.$char("+")||q.$char("-")),!c)break;if(b=this.multiplication(),!b)break;a.parensInOp=!0,b.parensInOp=!0,d=new e.Operation(c,[d||a,b],f),f=q.isWhitespace(-1)}return d||a}},conditions:function(){var a,b,c,d=q.i;if(a=this.condition(!0)){for(;;){if(!q.peek(/^,\s*(not\s*)?\(/)||!q.$char(","))break;if(b=this.condition(!0),!b)break;c=new e.Condition("or",c||a,b,d)}return c||a}},condition:function(a){function b(){return q.$str("or")}var c,d,f;if(c=this.conditionAnd(a)){if(d=b()){if(f=this.condition(a),!f)return;c=new e.Condition(d,c,f)}return c}},conditionAnd:function(a){function b(){var b=h.negatedCondition(a)||h.parenthesisCondition(a);return b||a?b:h.atomicCondition(a)}function c(){return q.$str("and")}var d,f,g,h=this;if(d=b()){if(f=c()){if(g=this.conditionAnd(a),!g)return;d=new e.Condition(f,d,g)}return d}},negatedCondition:function(a){if(q.$str("not")){var b=this.parenthesisCondition(a);return b&&(b.negate=!b.negate),b}},parenthesisCondition:function(a){function b(b){var c;return q.save(),(c=b.condition(a))&&q.$char(")")?(q.forget(),c):void q.restore()}var c;return q.save(),q.$str("(")?(c=b(this))?(q.forget(),c):(c=this.atomicCondition(a))?q.$char(")")?(q.forget(),c):void q.restore("expected ')' got '"+q.currentChar()+"'"):void q.restore():void q.restore()},atomicCondition:function(a){function b(){return this.addition()||h.keyword()||h.quoted()||h.mixinLookup()}var c,d,f,g,h=this.entities,i=q.i;if(b=b.bind(this),c=b())return q.$char(">")?g=q.$char("=")?">=":">":q.$char("<")?g=q.$char("=")?"<=":"<":q.$char("=")&&(g=q.$char(">")?"=>":q.$char("<")?"=<":"="),g?(d=b(),d?f=new e.Condition(g,c,d,i,(!1)):j("expected expression")):f=new e.Condition("=",c,new e.Keyword("true"),i,(!1)),f},operand:function(){var a,b=this.entities;q.peek(/^-[@\$\(]/)&&(a=q.$char("-"));var c=this.sub()||b.dimension()||b.color()||b.variable()||b.property()||b.call()||b.quoted(!0)||b.colorKeyword()||b.mixinLookup();return a&&(c.parensInOp=!0,c=new e.Negative(c)),c},expression:function(){var a,b,c=[],d=q.i;do a=this.comment(),a?c.push(a):(a=this.addition()||this.entity(),a&&(c.push(a),q.peek(/^\/[\/*]/)||(b=q.$char("/"),b&&c.push(new e.Anonymous(b,d)))));while(a);if(c.length>0)return new e.Expression(c)},property:function(){var a=q.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/);if(a)return a[1]},ruleProperty:function(){function a(a){var b=q.i,c=q.$re(a);if(c)return g.push(b),f.push(c[1])}var b,d,f=[],g=[];q.save();var h=q.$re(/^([_a-zA-Z0-9-]+)\s*:/);if(h)return f=[new e.Keyword(h[1])],q.forget(),f;for(a(/^(\*?)/);;)if(!a(/^((?:[\w-]+)|(?:[@\$]\{[\w-]+\}))/))break;if(f.length>1&&a(/^((?:\+_|\+)?)\s*:/)){for(q.forget(),""===f[0]&&(f.shift(),g.shift()),d=0;d=b);c++);this.preProcessors.splice(c,0,{preProcessor:a,priority:b})},e.prototype.addPostProcessor=function(a,b){var c;for(c=0;c=b);c++);this.postProcessors.splice(c,0,{postProcessor:a,priority:b})},e.prototype.addFileManager=function(a){this.fileManagers.push(a)},e.prototype.getPreProcessors=function(){for(var a=[],b=0;b0){var d,e=JSON.stringify(this._sourceMapGenerator.toJSON());this.sourceMapURL?d=this.sourceMapURL:this._sourceMapFilename&&(d=this._sourceMapFilename),this.sourceMapURL=d,this.sourceMap=e}return this._css.join("")},b}},{}],49:[function(a,b,c){var d=a("./contexts"),e=a("./visitors"),f=a("./tree");b.exports=function(a,b){b=b||{};var c,g=b.variables,h=new d.Eval(b);"object"!=typeof g||Array.isArray(g)||(g=Object.keys(g).map(function(a){var b=g[a];return b instanceof f.Value||(b instanceof f.Expression||(b=new f.Expression([b])),b=new f.Value([b])),new f.Declaration("@"+a,b,(!1),null,0)}),h.frames=[new f.Ruleset(null,g)]);var i,j,k=[new e.JoinSelectorVisitor,new e.MarkVisibleSelectorsVisitor((!0)),new e.ExtendVisitor,new e.ToCSSVisitor({compress:Boolean(b.compress)})],l=[];if(b.pluginManager){j=b.pluginManager.visitor();for(var m=0;m<2;m++)for(j.first();i=j.get();)i.isPreEvalVisitor?0!==m&&l.indexOf(i)!==-1||(l.push(i),i.run(a)):0!==m&&k.indexOf(i)!==-1||(i.isPreVisitor?k.unshift(i):k.push(i))}c=a.eval(h);for(var m=0;m=6?(this.rgb=[],a.match(/.{2}/g).map(function(a,b){b<3?d.rgb.push(parseInt(a,16)):d.alpha=parseInt(a,16)/255})):(this.rgb=[],a.split("").map(function(a,b){b<3?d.rgb.push(parseInt(a+a,16)):d.alpha=parseInt(a+a,16)/255})),this.alpha=this.alpha||("number"==typeof b?b:1),"undefined"!=typeof c&&(this.value=c)};h.prototype=new f,h.prototype.type="Color",h.prototype.luma=function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255;return a=a<=.03928?a/12.92:Math.pow((a+.055)/1.055,2.4),b=b<=.03928?b/12.92:Math.pow((b+.055)/1.055,2.4),c=c<=.03928?c/12.92:Math.pow((c+.055)/1.055,2.4),.2126*a+.7152*b+.0722*c},h.prototype.genCSS=function(a,b){b.add(this.toCSS(a))},h.prototype.toCSS=function(a,b){var c,e,f,g=a&&a.compress&&!b,h=[];if(e=this.fround(a,this.alpha),this.value)if(0===this.value.indexOf("rgb"))e<1&&(f="rgba");else{if(0!==this.value.indexOf("hsl"))return this.value;f=e<1?"hsla":"hsl"}else e<1&&(f="rgba");switch(f){case"rgba":h=this.rgb.map(function(a){return d(Math.round(a),255)}).concat(d(e,1));break;case"hsla":h.push(d(e,1));case"hsl":c=this.toHSL(),h=[this.fround(a,c.h),this.fround(a,100*c.s)+"%",this.fround(a,100*c.l)+"%"].concat(h)}if(f)return f+"("+h.join(","+(g?"":" "))+")";if(c=this.toRGB(),g){var i=c.split("");i[1]===i[2]&&i[3]===i[4]&&i[5]===i[6]&&(c="#"+i[1]+i[3]+i[5])}return c},h.prototype.operate=function(a,b,c){for(var d=new Array(3),e=this.alpha*(1-c.alpha)+c.alpha,f=0;f<3;f++)d[f]=this._operate(a,b,this.rgb[f],c.rgb[f]);return new h(d,e)},h.prototype.toRGB=function(){return e(this.rgb)},h.prototype.toHSL=function(){var a,b,c=this.rgb[0]/255,d=this.rgb[1]/255,e=this.rgb[2]/255,f=this.alpha,g=Math.max(c,d,e),h=Math.min(c,d,e),i=(g+h)/2,j=g-h;if(g===h)a=b=0;else{switch(b=i>.5?j/(2-g-h):j/(g+h),g){case c:a=(d-e)/j+(d="===a||"=<"===a||"<="===a;case 1:return">"===a||">="===a;default:return!1}}}(this.op,this.lvalue.eval(a),this.rvalue.eval(a));return this.negate?!b:b},b.exports=e},{"./node":76}],59:[function(a,b,c){var d=function(a,b,c){var e="";if(a.dumpLineNumbers&&!a.compress)switch(a.dumpLineNumbers){case"comments":e=d.asComment(b);break;case"mediaquery":e=d.asMediaQuery(b);break;case"all":e=d.asComment(b)+(c||"")+d.asMediaQuery(b)}return e};d.asComment=function(a){return"/* line "+a.debugInfo.lineNumber+", "+a.debugInfo.fileName+" */\n"},d.asMediaQuery=function(a){var b=a.debugInfo.fileName;return/^[a-z]+:\/\//i.test(b)||(b="file://"+b),"@media -sass-debug-info{filename{font-family:"+b.replace(/([.:\/\\])/g,function(a){return"\\"==a&&(a="/"),"\\"+a})+"}line{font-family:\\00003"+a.debugInfo.lineNumber+"}}\n"},b.exports=d},{}],60:[function(a,b,c){function d(a,b){var c,d="",e=b.length,f={add:function(a){d+=a}};for(c=0;c-1e-6&&(d=c.toFixed(20).replace(/0+$/,"")),a&&a.compress){if(0===c&&this.unit.isLength())return void b.add(d);c>0&&c<1&&(d=d.substr(1))}b.add(d),this.unit.genCSS(a,b)},h.prototype.operate=function(a,b,c){var d=this._operate(a,b,this.value,c.value),e=this.unit.clone();if("+"===b||"-"===b)if(0===e.numerator.length&&0===e.denominator.length)e=c.unit.clone(),this.unit.backupUnit&&(e.backupUnit=this.unit.backupUnit);else if(0===c.unit.numerator.length&&0===e.denominator.length);else{if(c=c.convertTo(this.unit.usedUnits()),a.strictUnits&&c.unit.toString()!==e.toString())throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '"+e.toString()+"' and '"+c.unit.toString()+"'.");d=this._operate(a,b,this.value,c.value)}else"*"===b?(e.numerator=e.numerator.concat(c.unit.numerator).sort(),e.denominator=e.denominator.concat(c.unit.denominator).sort(),e.cancel()):"/"===b&&(e.numerator=e.numerator.concat(c.unit.denominator).sort(),e.denominator=e.denominator.concat(c.unit.numerator).sort(),e.cancel());return new h(d,e)},h.prototype.compare=function(a){var b,c;if(a instanceof h){if(this.unit.isEmpty()||a.unit.isEmpty())b=this,c=a;else if(b=this.unify(),c=a.unify(),0!==b.unit.compare(c.unit))return;return d.numericCompare(b.value,c.value)}},h.prototype.unify=function(){return this.convertTo({length:"px",duration:"s",angle:"rad"})},h.prototype.convertTo=function(a){var b,c,d,f,g,i=this.value,j=this.unit.clone(),k={};if("string"==typeof a){for(b in e)e[b].hasOwnProperty(a)&&(k={},k[b]=a);a=k}g=function(a,b){return d.hasOwnProperty(a)?(b?i/=d[a]/d[f]:i*=d[a]/d[f],f):a};for(c in a)a.hasOwnProperty(c)&&(f=a[c],d=e[c],j.map(g));return j.cancel(),new h(i,j)},b.exports=h},{"../data/unit-conversions":16,"./color":55,"./node":76,"./unit":84}],63:[function(a,b,c){var d=a("./node"),e=a("./paren"),f=a("./combinator"),g=function(a,b,c,d,e,g){this.combinator=a instanceof f?a:new f(a),this.value="string"==typeof b?b.trim():b?b:"",this.isVariable=c,this._index=d,this._fileInfo=e,this.copyVisibilityInfo(g),this.setParent(this.combinator,this)};g.prototype=new d,g.prototype.type="Element",g.prototype.accept=function(a){var b=this.value;this.combinator=a.visit(this.combinator),"object"==typeof b&&(this.value=a.visit(b))},g.prototype.eval=function(a){return new g(this.combinator,this.value.eval?this.value.eval(a):this.value,this.isVariable,this.getIndex(),this.fileInfo(),this.visibilityInfo())},g.prototype.clone=function(){return new g(this.combinator,this.value,this.isVariable,this.getIndex(),this.fileInfo(),this.visibilityInfo())},g.prototype.genCSS=function(a,b){b.add(this.toCSS(a),this.fileInfo(),this.getIndex())},g.prototype.toCSS=function(a){a=a||{};var b=this.value,c=a.firstSelector;return b instanceof e&&(a.firstSelector=!0),b=b.toCSS?b.toCSS(a):b,a.firstSelector=c,""===b&&"&"===this.combinator.value.charAt(0)?"":this.combinator.toCSS(a)+b},b.exports=g},{"./combinator":56,"./node":76,"./paren":78}],64:[function(a,b,c){var d=a("./node"),e=a("./paren"),f=a("./comment"),g=a("./dimension"),h=a("../constants").Math,i=function(a,b){if(this.value=a,this.noSpacing=b,!a)throw new Error("Expression requires an array parameter")};i.prototype=new d,i.prototype.type="Expression",i.prototype.accept=function(a){this.value=a.visitArray(this.value)},i.prototype.eval=function(a){var b,c=a.isMathOn(),d=this.parens&&(a.math!==h.STRICT_LEGACY||!this.parensInOp),f=!1;return d&&a.inParenthesis(),this.value.length>1?b=new i(this.value.map(function(b){return b.eval?b.eval(a):b}),this.noSpacing):1===this.value.length?(!this.value[0].parens||this.value[0].parensInOp||a.inCalc||(f=!0),b=this.value[0].eval(a)):b=this,d&&a.outOfParenthesis(),!this.parens||!this.parensInOp||c||f||b instanceof g||(b=new e(b)),b},i.prototype.genCSS=function(a,b){for(var c=0;c0&&c.length&&""===c[0].combinator.value&&(c[0].combinator.value=" "),d=d.concat(a[b].elements);this.selfSelectors=[new e(d)],this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo())},b.exports=f},{"./node":76,"./selector":82}],66:[function(a,b,c){var d=a("./node"),e=a("./media"),f=a("./url"),g=a("./quoted"),h=a("./ruleset"),i=a("./anonymous"),j=a("../utils"),k=a("../less-error"),l=function(a,b,c,d,e,f){if(this.options=c,this._index=d,this._fileInfo=e,this.path=a,this.features=b,this.allowRoot=!0,void 0!==this.options.less||this.options.inline)this.css=!this.options.less||this.options.inline;else{var g=this.getPath();g&&/[#\.\&\?]css([\?;].*)?$/.test(g)&&(this.css=!0)}this.copyVisibilityInfo(f),this.setParent(this.features,this),this.setParent(this.path,this)};l.prototype=new d,l.prototype.type="Import",l.prototype.accept=function(a){this.features&&(this.features=a.visit(this.features)),this.path=a.visit(this.path),this.options.isPlugin||this.options.inline||!this.root||(this.root=a.visit(this.root))},l.prototype.genCSS=function(a,b){this.css&&void 0===this.path._fileInfo.reference&&(b.add("@import ",this._fileInfo,this._index),this.path.genCSS(a,b),this.features&&(b.add(" "),this.features.genCSS(a,b)),b.add(";"))},l.prototype.getPath=function(){return this.path instanceof f?this.path.value.value:this.path.value},l.prototype.isVariableImport=function(){var a=this.path;return a instanceof f&&(a=a.value),!(a instanceof g)||a.containsVariables()},l.prototype.evalForImport=function(a){var b=this.path;return b instanceof f&&(b=b.value),new l(b.eval(a),this.features,this.options,this._index,this._fileInfo,this.visibilityInfo())},l.prototype.evalPath=function(a){var b=this.path.eval(a),c=this._fileInfo;if(!(b instanceof f)){var d=b.value;b.value=c&&d&&a.pathRequiresRewrite(d)?a.rewritePath(d,c.rootpath):a.normalizePath(b.value)}return b},l.prototype.eval=function(a){var b=this.doEval(a);return(this.options.reference||this.blocksVisibility())&&(b.length||0===b.length?b.forEach(function(a){a.addVisibilityBlock()}):b.addVisibilityBlock()),b},l.prototype.doEval=function(a){var b,c,d=this.features&&this.features.eval(a);if(this.options.isPlugin){if(this.root&&this.root.eval)try{this.root.eval(a)}catch(f){throw f.message="Plugin error during evaluation",new k(f,this.root.imports,this.root.filename)}return c=a.frames[0]&&a.frames[0].functionRegistry,c&&this.root&&this.root.functions&&c.addMultiple(this.root.functions),[]}if(this.skip&&("function"==typeof this.skip&&(this.skip=this.skip()),this.skip))return[];if(this.options.inline){var g=new i(this.root,0,{filename:this.importedFilename,reference:this.path._fileInfo&&this.path._fileInfo.reference},(!0),(!0));return this.features?new e([g],this.features.value):[g]}if(this.css){var m=new l(this.evalPath(a),d,this.options,this._index);if(!m.css&&this.error)throw this.error;return m}return b=new h(null,j.copyArray(this.root.rules)),b.evalImports(a),this.features?new e(b.rules,this.features.value):b.rules},b.exports=l},{"../less-error":38,"../utils":89,"./anonymous":50,"./media":71,"./node":76,"./quoted":80,"./ruleset":81,"./url":85}],67:[function(a,b,c){var d=Object.create(null);d.Node=a("./node"),d.Color=a("./color"),d.AtRule=a("./atrule"),d.DetachedRuleset=a("./detached-ruleset"),d.Operation=a("./operation"),d.Dimension=a("./dimension"),d.Unit=a("./unit"),d.Keyword=a("./keyword"),d.Variable=a("./variable"),d.Property=a("./property"),d.Ruleset=a("./ruleset"),d.Element=a("./element"),d.Attribute=a("./attribute"),d.Combinator=a("./combinator"),d.Selector=a("./selector"),d.Quoted=a("./quoted"),d.Expression=a("./expression"),d.Declaration=a("./declaration"),d.Call=a("./call"),d.URL=a("./url"),d.Import=a("./import"),d.mixin={Call:a("./mixin-call"),Definition:a("./mixin-definition")},d.Comment=a("./comment"),d.Anonymous=a("./anonymous"),d.Value=a("./value"),d.JavaScript=a("./javascript"),d.Assignment=a("./assignment"),d.Condition=a("./condition"),d.Paren=a("./paren"),d.Media=a("./media"),d.UnicodeDescriptor=a("./unicode-descriptor"),d.Negative=a("./negative"),d.Extend=a("./extend"),d.VariableCall=a("./variable-call"),d.NamespaceValue=a("./namespace-value"),b.exports=d},{"./anonymous":50,"./assignment":51,"./atrule":52,"./attribute":53,"./call":54,"./color":55,"./combinator":56,"./comment":57,"./condition":58,"./declaration":60,"./detached-ruleset":61,"./dimension":62,"./element":63,"./expression":64,"./extend":65,"./import":66,"./javascript":68,"./keyword":70,"./media":71,"./mixin-call":72,"./mixin-definition":73,"./namespace-value":74,"./negative":75,"./node":76,"./operation":77,"./paren":78,"./property":79,"./quoted":80,"./ruleset":81,"./selector":82,"./unicode-descriptor":83,"./unit":84,"./url":85,"./value":86,"./variable":88,"./variable-call":87}],68:[function(a,b,c){var d=a("./js-eval-node"),e=a("./dimension"),f=a("./quoted"),g=a("./anonymous"),h=function(a,b,c,d){this.escaped=b,this.expression=a,this._index=c,this._fileInfo=d};h.prototype=new d,h.prototype.type="JavaScript",h.prototype.eval=function(a){var b=this.evaluateJavaScript(this.expression,a),c=typeof b;return"number"!==c||isNaN(b)?"string"===c?new f('"'+b+'"',b,this.escaped,this._index):new g(Array.isArray(b)?b.join(", "):b):new e(b)},b.exports=h},{"./anonymous":50,"./dimension":62,"./js-eval-node":69,"./quoted":80}],69:[function(a,b,c){var d=a("./node"),e=a("./variable"),f=function(){};f.prototype=new d,f.prototype.evaluateJavaScript=function(a,b){var c,d=this,f={};if(!b.javascriptEnabled)throw{message:"Inline JavaScript is not enabled. Is it set in your options?",filename:this.fileInfo().filename,index:this.getIndex()};a=a.replace(/@\{([\w-]+)\}/g,function(a,c){return d.jsify(new e("@"+c,d.getIndex(),d.fileInfo()).eval(b))});try{a=new Function("return ("+a+")")}catch(g){throw{message:"JavaScript evaluation error: "+g.message+" from `"+a+"`",filename:this.fileInfo().filename,index:this.getIndex()}}var h=b.frames[0].variables();for(var i in h)h.hasOwnProperty(i)&&(f[i.slice(1)]={value:h[i].value,toJS:function(){return this.value.eval(b).toCSS()}});try{c=a.call(f)}catch(g){throw{message:"JavaScript evaluation error: '"+g.name+": "+g.message.replace(/["]/g,"'")+"'",filename:this.fileInfo().filename,index:this.getIndex()}}return c},f.prototype.jsify=function(a){return Array.isArray(a.value)&&a.value.length>1?"["+a.value.map(function(a){return a.toCSS()}).join(", ")+"]":a.toCSS()},b.exports=f},{"./node":76,"./variable":88}],70:[function(a,b,c){var d=a("./node"),e=function(a){this.value=a};e.prototype=new d,e.prototype.type="Keyword",e.prototype.genCSS=function(a,b){if("%"===this.value)throw{type:"Syntax",message:"Invalid % without number"};b.add(this.value)},e.True=new e("true"),e.False=new e("false"),b.exports=e},{"./node":76}],71:[function(a,b,c){var d=a("./ruleset"),e=a("./value"),f=a("./selector"),g=a("./anonymous"),h=a("./expression"),i=a("./atrule"),j=a("../utils"),k=function(a,b,c,g,h){this._index=c,this._fileInfo=g;var i=new f([],null,null,this._index,this._fileInfo).createEmptySelectors();this.features=new e(b),this.rules=[new d(i,a)],this.rules[0].allowImports=!0,this.copyVisibilityInfo(h),this.allowRoot=!0,this.setParent(i,this),this.setParent(this.features,this),this.setParent(this.rules,this)};k.prototype=new i,k.prototype.type="Media",k.prototype.isRulesetLike=function(){return!0},k.prototype.accept=function(a){this.features&&(this.features=a.visit(this.features)),this.rules&&(this.rules=a.visitArray(this.rules))},k.prototype.genCSS=function(a,b){b.add("@media ",this._fileInfo,this._index),this.features.genCSS(a,b),this.outputRuleset(a,b,this.rules)},k.prototype.eval=function(a){a.mediaBlocks||(a.mediaBlocks=[],a.mediaPath=[]);var b=new k(null,[],this._index,this._fileInfo,this.visibilityInfo());return this.debugInfo&&(this.rules[0].debugInfo=this.debugInfo,b.debugInfo=this.debugInfo),b.features=this.features.eval(a),a.mediaPath.push(b),a.mediaBlocks.push(b),this.rules[0].functionRegistry=a.frames[0].functionRegistry.inherit(),a.frames.unshift(this.rules[0]),b.rules=[this.rules[0].eval(a)],a.frames.shift(),a.mediaPath.pop(),0===a.mediaPath.length?b.evalTop(a):b.evalNested(a)},k.prototype.evalTop=function(a){var b=this;if(a.mediaBlocks.length>1){var c=new f([],null,null,this.getIndex(),this.fileInfo()).createEmptySelectors();b=new d(c,a.mediaBlocks),b.multiMedia=!0,b.copyVisibilityInfo(this.visibilityInfo()),this.setParent(b,this)}return delete a.mediaBlocks,delete a.mediaPath,b},k.prototype.evalNested=function(a){var b,c,f=a.mediaPath.concat([this]);for(b=0;b0;b--)a.splice(b,0,new g("and"));return new h(a)})),this.setParent(this.features,this),new d([],[])},k.prototype.permute=function(a){if(0===a.length)return[];if(1===a.length)return a[0];for(var b=[],c=this.permute(a.slice(1)),d=0;d0){for(n=!0,k=0;k0)p=B;else if(p=A,q[A]+q[B]>1)throw{type:"Runtime",message:"Ambiguous use of `default()` found when matching for `"+this.format(t)+"`",index:this.getIndex(),filename:this.fileInfo().filename};for(k=0;kthis.params.length)return!1}c=Math.min(f,this.arity);for(var g=0;gb?1:void 0},d.prototype.blocksVisibility=function(){return null==this.visibilityBlocks&&(this.visibilityBlocks=0),0!==this.visibilityBlocks},d.prototype.addVisibilityBlock=function(){null==this.visibilityBlocks&&(this.visibilityBlocks=0),this.visibilityBlocks=this.visibilityBlocks+1},d.prototype.removeVisibilityBlock=function(){null==this.visibilityBlocks&&(this.visibilityBlocks=0),this.visibilityBlocks=this.visibilityBlocks-1},d.prototype.ensureVisibility=function(){this.nodeVisible=!0},d.prototype.ensureInvisibility=function(){this.nodeVisible=!1},d.prototype.isVisible=function(){return this.nodeVisible},d.prototype.visibilityInfo=function(){return{visibilityBlocks:this.visibilityBlocks,nodeVisible:this.nodeVisible}},d.prototype.copyVisibilityInfo=function(a){a&&(this.visibilityBlocks=a.visibilityBlocks,this.nodeVisible=a.nodeVisible)},b.exports=d},{}],77:[function(a,b,c){var d=a("./node"),e=a("./color"),f=a("./dimension"),g=a("../constants").Math,h=function(a,b,c){this.op=a.trim(),this.operands=b,this.isSpaced=c};h.prototype=new d,h.prototype.type="Operation",h.prototype.accept=function(a){this.operands=a.visit(this.operands)},h.prototype.eval=function(a){var b,c=this.operands[0].eval(a),d=this.operands[1].eval(a);if(a.isMathOn(this.op)){if(b="./"===this.op?"/":this.op,c instanceof f&&d instanceof e&&(c=c.toColor()),d instanceof f&&c instanceof e&&(d=d.toColor()),!c.operate){if(c instanceof h&&"/"===c.op&&a.math===g.PARENS_DIVISION)return new h(this.op,[c,d],this.isSpaced);throw{type:"Operation",message:"Operation on an invalid type"}}return c.operate(a,b,d)}return new h(this.op,[c,d],this.isSpaced)},h.prototype.genCSS=function(a,b){this.operands[0].genCSS(a,b),this.isSpaced&&b.add(" "),b.add(this.op),this.isSpaced&&b.add(" "),this.operands[1].genCSS(a,b)},b.exports=h},{"../constants":12,"./color":55,"./dimension":62,"./node":76}],78:[function(a,b,c){var d=a("./node"),e=function(a){this.value=a};e.prototype=new d,e.prototype.type="Paren",e.prototype.genCSS=function(a,b){b.add("("),this.value.genCSS(a,b),b.add(")")},e.prototype.eval=function(a){return new e(this.value.eval(a))},b.exports=e},{"./node":76}],79:[function(a,b,c){var d=a("./node"),e=a("./declaration"),f=function(a,b,c){this.name=a,this._index=b,this._fileInfo=c};f.prototype=new d,f.prototype.type="Property",f.prototype.eval=function(a){var b,c=this.name,d=a.pluginManager.less.visitors.ToCSSVisitor.prototype._mergeRules;if(this.evaluating)throw{type:"Name",message:"Recursive property reference for "+c,filename:this.fileInfo().filename,index:this.getIndex()};if(this.evaluating=!0,b=this.find(a.frames,function(b){var f,g=b.property(c);if(g){for(var h=0;h0;a--){var b=this.rules[a-1];if(b instanceof e)return this.parseValue(b)}},q.prototype.parseValue=function(a){function b(a){return a.value instanceof k&&!a.parsed?("string"==typeof a.value.value?this.parse.parseNode(a.value.value,["value","important"],a.value.getIndex(),a.fileInfo(),function(b,c){b&&(a.parsed=!0),c&&(a.value=c[0],a.important=c[1]||"",a.parsed=!0)}):a.parsed=!0,a):a}var c=this;if(Array.isArray(a)){var d=[];return a.forEach(function(a){d.push(b.call(c,a))}),d}return b.call(c,a)},q.prototype.rulesets=function(){if(!this.rules)return[];var a,b,c=[],d=this.rules;for(a=0;b=d[a];a++)b.isRuleset&&c.push(b);return c},q.prototype.prependRule=function(a){var b=this.rules;b?b.unshift(a):this.rules=[a],this.setParent(a,this)},q.prototype.find=function(a,b,c){b=b||this;var d,e,f=[],g=a.toCSS();return g in this._lookups?this._lookups[g]:(this.rulesets().forEach(function(g){if(g!==b)for(var h=0;hd){if(!c||c(g)){e=g.find(new i(a.elements.slice(d)),b,c);for(var j=0;j0&&b.add(k),a.firstSelector=!0,h[0].genCSS(a,b),a.firstSelector=!1,d=1;d0?(e=p.copyArray(a),f=e.pop(),g=d.createDerived(p.copyArray(f.elements))):g=d.createDerived([]),b.length>0){var h=c.combinator,i=b[0].elements[0];h.emptyOrWhitespace&&!i.combinator.emptyOrWhitespace&&(h=i.combinator),g.elements.push(new j(h,i.value,c.isVariable,c._index,c._fileInfo)),g.elements=g.elements.concat(b[0].elements.slice(1))}if(0!==g.elements.length&&e.push(g),b.length>1){var k=b.slice(1);k=k.map(function(a){return a.createDerived(a.elements,[])}),e=e.concat(k)}return e}function g(a,b,c,d,e){var g;for(g=0;g0?d[d.length-1]=d[d.length-1].createDerived(d[d.length-1].elements.concat(a)):d.push(new i(a))}}function l(a,b,c){function m(a){var b;return a.value instanceof h?(b=a.value.value,b instanceof i?b:null):null}var n,o,p,q,r,s,t,u,v,w,x=!1;for(q=[],r=[[]],n=0;u=c.elements[n];n++)if("&"!==u.value){var y=m(u);if(null!=y){k(q,r);var z,A=[],B=[];for(z=l(A,b,y),x=x||z,p=0;p0&&t[0].elements.push(new j(u.combinator,"",u.isVariable,u._index,u._fileInfo)),s.push(t);else for(p=0;p0&&(a.push(r[n]),w=r[n][v-1],r[n][v-1]=w.createDerived(w.elements,c.extendList));return x}function m(a,b){var c=b.createDerived(b.elements,b.extendList,b.evaldCondition);return c.copyVisibilityInfo(a),c}var n,o,q;if(o=[],q=l(o,b,c),!q)if(b.length>0)for(o=[],n=0;n0)for(b=0;b=0&&"\n"!==b.charAt(c);)e++;return"number"==typeof a&&(d=(b.slice(0,a).match(/\n/g)||"").length),{line:d,column:e}},copyArray:function(a){var b,c=a.length,d=new Array(c);for(b=0;b=0||(i=[k.selfSelectors[0]],g=n.findMatch(j,i),g.length&&(j.hasFoundMatches=!0,j.selfSelectors.forEach(function(a){var b=k.visibilityInfo();h=n.extendSelector(g,i,a,j.isVisible()),l=new d.Extend(k.selector,k.option,0,k.fileInfo(),b),l.selfSelectors=h,h[h.length-1].extendList=[l],m.push(l),l.ruleset=k.ruleset,l.parent_ids=l.parent_ids.concat(k.parent_ids,j.parent_ids),k.firstExtendOnThisSelectorPath&&(l.firstExtendOnThisSelectorPath=!0,k.ruleset.paths.push(h))})));if(m.length){if(this.extendChainCount++,c>100){var o="{unable to calculate}",p="{unable to calculate}";try{o=m[0].selfSelectors[0].toCSS(),p=m[0].selector.toCSS()}catch(q){}throw{message:"extend circular reference detected. One of the circular extends is currently:"+o+":extend("+p+")"}}return m.concat(n.doExtendChaining(m,b,c+1))}return m},visitDeclaration:function(a,b){b.visitDeeper=!1},visitMixinDefinition:function(a,b){b.visitDeeper=!1},visitSelector:function(a,b){b.visitDeeper=!1},visitRuleset:function(a,b){if(!a.root){var c,d,e,f,g=this.allExtendsStack[this.allExtendsStack.length-1],h=[],i=this;for(e=0;e0&&k[i.matched].combinator.value!==g?i=null:i.matched++,i&&(i.finished=i.matched===k.length,i.finished&&!a.allowAfter&&(e+1k&&l>0&&(m[m.length-1].elements=m[m.length-1].elements.concat(b[k].elements.slice(l)),l=0,k++),j=g.elements.slice(l,i.index).concat([h]).concat(c.elements.slice(1)),k===i.pathIndex&&f>0?m[m.length-1].elements=m[m.length-1].elements.concat(j):(m=m.concat(b.slice(k,i.pathIndex)),m.push(new d.Selector(j))),k=i.endPathIndex,l=i.endPathElementIndex,l>=b[k].elements.length&&(l=0,k++);return k0&&(m[m.length-1].elements=m[m.length-1].elements.concat(b[k].elements.slice(l)),k++),m=m.concat(b.slice(k,b.length)),m=m.map(function(a){var b=a.createDerived(a.elements);return e?b.ensureVisibility():b.ensureInvisibility(),b})},visitMedia:function(a,b){var c=a.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);c=c.concat(this.doExtendChaining(c,a.allExtends)),this.allExtendsStack.push(c)},visitMediaOut:function(a){var b=this.allExtendsStack.length-1;this.allExtendsStack.length=b},visitAtRule:function(a,b){var c=a.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);c=c.concat(this.doExtendChaining(c,a.allExtends)),this.allExtendsStack.push(c)},visitAtRuleOut:function(a){var b=this.allExtendsStack.length-1;this.allExtendsStack.length=b}},b.exports=i},{"../logger":39,"../tree":67,"../utils":89,"./visitor":97}],91:[function(a,b,c){function d(a){this.imports=[],this.variableImports=[],this._onSequencerEmpty=a,this._currentDepth=0}d.prototype.addImport=function(a){var b=this,c={callback:a,args:null,isReady:!1};return this.imports.push(c),function(){c.args=Array.prototype.slice.call(arguments,0),c.isReady=!0,b.tryRun()}},d.prototype.addVariableImport=function(a){this.variableImports.push(a)},d.prototype.tryRun=function(){this._currentDepth++;try{for(;;){for(;this.imports.length>0;){var a=this.imports[0];if(!a.isReady)return;this.imports=this.imports.slice(1),a.callback.apply(null,a.args)}if(0===this.variableImports.length)break;var b=this.variableImports[0];this.variableImports=this.variableImports.slice(1),b()}}finally{this._currentDepth--}0===this._currentDepth&&this._onSequencerEmpty&&this._onSequencerEmpty()},b.exports=d},{}],92:[function(a,b,c){var d=a("../contexts"),e=a("./visitor"),f=a("./import-sequencer"),g=a("../utils"),h=function(a,b){this._visitor=new e(this),this._importer=a,this._finish=b,this.context=new d.Eval,this.importCount=0,this.onceFileDetectionMap={},this.recursionDetector={},this._sequencer=new f(this._onSequencerEmpty.bind(this))};h.prototype={isReplacing:!1,run:function(a){try{this._visitor.visit(a)}catch(b){this.error=b}this.isFinished=!0,this._sequencer.tryRun()},_onSequencerEmpty:function(){this.isFinished&&this._finish(this.error)},visitImport:function(a,b){var c=a.options.inline;if(!a.css||c){var e=new d.Eval(this.context,g.copyArray(this.context.frames)),f=e.frames[0];this.importCount++,a.isVariableImport()?this._sequencer.addVariableImport(this.processImportNode.bind(this,a,e,f)):this.processImportNode(a,e,f)}b.visitDeeper=!1},processImportNode:function(a,b,c){var d,e=a.options.inline;try{d=a.evalForImport(b)}catch(f){f.filename||(f.index=a.getIndex(),f.filename=a.fileInfo().filename),a.css=!0,a.error=f}if(!d||d.css&&!e)this.importCount--,this.isFinished&&this._sequencer.tryRun();else{d.options.multiple&&(b.importMultiple=!0);for(var g=void 0===d.css,h=0;h0},resolveVisibility:function(a,b){if(!a.blocksVisibility()){if(this.isEmpty(a)&&!this.containsSilentNonBlockedChild(b))return;return a}var c=a.rules[0];if(this.keepOnlyVisibleChilds(c),!this.isEmpty(c))return a.ensureVisibility(),a.removeVisibilityBlock(),a},isVisibleRuleset:function(a){return!!a.firstRoot||!this.isEmpty(a)&&!(!a.root&&!this.hasVisibleSelector(a))}};var g=function(a){this._visitor=new e(this),this._context=a,this.utils=new f(a)};g.prototype={isReplacing:!0,run:function(a){return this._visitor.visit(a)},visitDeclaration:function(a,b){if(!a.blocksVisibility()&&!a.variable)return a},visitMixinDefinition:function(a,b){a.frames=[]},visitExtend:function(a,b){},visitComment:function(a,b){if(!a.blocksVisibility()&&!a.isSilent(this._context))return a},visitMedia:function(a,b){var c=a.rules[0].rules;return a.accept(this._visitor),b.visitDeeper=!1,this.utils.resolveVisibility(a,c)},visitImport:function(a,b){if(!a.blocksVisibility())return a},visitAtRule:function(a,b){return a.rules&&a.rules.length?this.visitAtRuleWithBody(a,b):this.visitAtRuleWithoutBody(a,b)},visitAnonymous:function(a,b){if(!a.blocksVisibility())return a.accept(this._visitor),a},visitAtRuleWithBody:function(a,b){function c(a){var b=a.rules;return 1===b.length&&(!b[0].paths||0===b[0].paths.length)}function d(a){var b=a.rules;return c(a)?b[0].rules:b}var e=d(a);return a.accept(this._visitor),b.visitDeeper=!1,this.utils.isEmpty(a)||this._mergeRules(a.rules[0].rules),this.utils.resolveVisibility(a,e)},visitAtRuleWithoutBody:function(a,b){if(!a.blocksVisibility()){if("@charset"===a.name){if(this.charset){if(a.debugInfo){var c=new d.Comment("/* "+a.toCSS(this._context).replace(/\n/g,"")+" */\n");return c.debugInfo=a.debugInfo,this._visitor.visit(c)}return}this.charset=!0}return a}},checkValidNodes:function(a,b){if(a)for(var c=0;c0?a.accept(this._visitor):a.rules=null,b.visitDeeper=!1}return a.rules&&(this._mergeRules(a.rules),this._removeDuplicateRules(a.rules)),this.utils.isVisibleRuleset(a)&&(a.ensureVisibility(),d.splice(0,0,a)),1===d.length?d[0]:d},_compileRulesetPaths:function(a){a.paths&&(a.paths=a.paths.filter(function(a){var b;for(" "===a[0].elements[0].combinator.value&&(a[0].elements[0].combinator=new d.Combinator("")),b=0;b=0;e--)if(c=a[e],c instanceof d.Declaration)if(f[c.name]){b=f[c.name],b instanceof d.Declaration&&(b=f[c.name]=[f[c.name].toCSS(this._context)]);var g=c.toCSS(this._context);b.indexOf(g)!==-1?a.splice(e,1):b.push(g)}else f[c.name]=c}},_mergeRules:function(a){if(a){for(var b={},c=[],e=0;e0){var b=a[0],c=[],e=[new d.Expression(c)];a.forEach(function(a){"+"===a.merge&&c.length>0&&e.push(new d.Expression(c=[])),c.push(a.value),b.important=b.important||a.important}),b.value=new d.Value(e)}})}}},b.exports=g},{"../tree":67,"./visitor":97}],97:[function(a,b,c){function d(a){return a}function e(a,b){var c,d;for(c in a)switch(d=a[c],typeof d){case"function":d.prototype&&d.prototype.type&&(d.prototype.typeIndex=b++);break;case"object":b=e(d,b)}return b}var f=a("../tree"),g={visitDeeper:!0},h=!1,i=function(a){this._implementation=a,this._visitInCache={},this._visitOutCache={},h||(e(f,1),h=!0)};i.prototype={visit:function(a){if(!a)return a;var b=a.typeIndex;if(!b)return a.value&&a.value.typeIndex&&this.visit(a.value),a;var c,e=this._implementation,f=this._visitInCache[b],h=this._visitOutCache[b],i=g;if(i.visitDeeper=!0,f||(c="visit"+a.type,f=e[c]||d,h=e[c+"Out"]||d,this._visitInCache[b]=f,this._visitOutCache[b]=h),f!==d){var j=f.call(e,a,i);a&&e.isReplacing&&(a=j)}return i.visitDeeper&&a&&a.accept&&a.accept(this),h!=d&&h.call(e,a),a},visitArray:function(a,b){if(!a)return a;var c,d=a.length;if(b||!this._implementation.isReplacing){for(c=0;ck){for(var b=0,c=h.length-j;b0&&l.childNodes.length>0&&s.firstChild.nodeValue===l.firstChild.nodeValue);var u=t.getElementsByTagName("head")[0];if(null===s||!1===o){var c=i&&i.nextSibling||null;c?c.parentNode.insertBefore(l,c):u.appendChild(l)}if(s&&!1===o&&s.parentNode.removeChild(s),l.styleSheet)try{l.styleSheet.cssText=n}catch(e){throw new Error("Couldn't reassign styleSheet.cssText.")}},currentScript:function(e){var t,n=e.document;return n.currentScript||(t=n.getElementsByTagName("script"))[t.length-1]}};function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){for(var n=0;nt?1:void 0};var y=function(e){function t(e,n,i){var a;r(this,t);var s=h(a=f(this,l(t).call(this)));return Array.isArray(e)?a.rgb=e:e.length>=6?(a.rgb=[],e.match(/.{2}/g).map(function(e,t){t<3?s.rgb.push(parseInt(e,16)):s.alpha=parseInt(e,16)/255})):(a.rgb=[],e.split("").map(function(e,t){t<3?s.rgb.push(parseInt(e+e,16)):s.alpha=parseInt(e+e,16)/255})),a.alpha=a.alpha||("number"==typeof n?n:1),void 0!==i&&(a.value=i),a}return o(t,g),s(t,[{key:"luma",value:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255;return.2126*(e=e<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4))+.7152*(t=t<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4))+.0722*(n=n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4))}},{key:"genCSS",value:function(e,t){t.add(this.toCSS(e))}},{key:"toCSS",value:function(e,t){var n,i,r,a=e&&e.compress&&!t,s=[];if(i=this.fround(e,this.alpha),this.value)if(0===this.value.indexOf("rgb"))i<1&&(r="rgba");else{if(0!==this.value.indexOf("hsl"))return this.value;r=i<1?"hsla":"hsl"}else i<1&&(r="rgba");switch(r){case"rgba":s=this.rgb.map(function(e){return b(Math.round(e),255)}).concat(b(i,1));break;case"hsla":s.push(b(i,1));case"hsl":n=this.toHSL(),s=[this.fround(e,n.h),"".concat(this.fround(e,100*n.s),"%"),"".concat(this.fround(e,100*n.l),"%")].concat(s)}if(r)return"".concat(r,"(").concat(s.join(",".concat(a?"":" ")),")");if(n=this.toRGB(),a){var o=n.split("");o[1]===o[2]&&o[3]===o[4]&&o[5]===o[6]&&(n="#".concat(o[1]).concat(o[3]).concat(o[5]))}return n}},{key:"operate",value:function(e,n,i){for(var r=new Array(3),a=this.alpha*(1-i.alpha)+i.alpha,s=0;s<3;s++)r[s]=this._operate(e,n,this.rgb[s],i.rgb[s]);return new t(r,a)}},{key:"toRGB",value:function(){return w(this.rgb)}},{key:"toHSL",value:function(){var e,t,n=this.rgb[0]/255,i=this.rgb[1]/255,r=this.rgb[2]/255,a=this.alpha,s=Math.max(n,i,r),o=Math.min(n,i,r),l=(s+o)/2,u=s-o;if(s===o)e=t=0;else{switch(t=l>.5?u/(2-s-o):u/(s+o),s){case n:e=(i-r)/u+(i0&&void 0!==arguments[0]?arguments[0]:{},t=this.value,n=e.firstSelector;return t instanceof k&&(e.firstSelector=!0),t=t.toCSS?t.toCSS(e):t,e.firstSelector=n,""===t&&"&"===this.combinator.value.charAt(0)?"":this.combinator.toCSS(e)+t}}]),t}();I.prototype.type="Element";var C={ALWAYS:0,PARENS_DIVISION:1,PARENS:2,STRICT_LEGACY:3},_={OFF:0,LOCAL:1,ALL:2};var A=function(e,t){return e(t={exports:{}},t.exports),t.exports}(function(e){var t=function(){function e(e,t){return null!=t&&e instanceof t}var t,n,i;try{t=Map}catch(e){t=function(){}}try{n=Set}catch(e){n=function(){}}try{i=Promise}catch(e){i=function(){}}function r(a,o,l,u,c){"object"==typeof o&&(l=o.depth,u=o.prototype,c=o.includeNonEnumerable,o=o.circular);var h=[],f=[],p="undefined"!=typeof Buffer;return void 0===o&&(o=!0),void 0===l&&(l=1/0),function a(l,v){if(null===l)return null;if(0===v)return l;var d,m;if("object"!=typeof l)return l;if(e(l,t))d=new t;else if(e(l,n))d=new n;else if(e(l,i))d=new i(function(e,t){l.then(function(t){e(a(t,v-1))},function(e){t(a(e,v-1))})});else if(r.__isArray(l))d=[];else if(r.__isRegExp(l))d=new RegExp(l.source,s(l)),l.lastIndex&&(d.lastIndex=l.lastIndex);else if(r.__isDate(l))d=new Date(l.getTime());else{if(p&&Buffer.isBuffer(l))return d=Buffer.allocUnsafe?Buffer.allocUnsafe(l.length):new Buffer(l.length),l.copy(d),d;e(l,Error)?d=Object.create(l):void 0===u?(m=Object.getPrototypeOf(l),d=Object.create(m)):(d=Object.create(u),m=u)}if(o){var g=h.indexOf(l);if(-1!=g)return f[g];h.push(l),f.push(d)}for(var y in e(l,t)&&l.forEach(function(e,t){var n=a(t,v-1),i=a(e,v-1);d.set(n,i)}),e(l,n)&&l.forEach(function(e){var t=a(e,v-1);d.add(t)}),l){var b;m&&(b=Object.getOwnPropertyDescriptor(m,y)),b&&null==b.set||(d[y]=a(l[y],v-1))}if(Object.getOwnPropertySymbols){var w=Object.getOwnPropertySymbols(l);for(y=0;y=0&&"\n"!==t.charAt(n);)r++;return"number"==typeof e&&(i=(t.slice(0,e).match(/\n/g)||"").length),{line:i,column:r}}function P(e){var t,n=e.length,i=new Array(n);for(t=0;t1&&void 0!==arguments[1]?arguments[1]:[],n=0,i=e.length;n|Function):(\d+):(\d+)/);c&&(c[2]&&(this.line=parseInt(c[2])-2),c[3]&&(this.column=parseInt(c[3])))}this.callLine=l+1,this.callExtract=u[l],this.extract=[u[this.line-2],u[this.line-1],u[this.line]]}};if(void 0===Object.create){var L=function(){};L.prototype=Error.prototype,$.prototype=new L}else $.prototype=Object.create(Error.prototype);$.prototype.constructor=$,$.prototype.toString=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t="",n=this.extract||[],r=[],a=function(e){return e};if(e.stylize){var s=i(e.stylize);if("function"!==s)throw Error("options.stylize should be a function, got a ".concat(s,"!"));a=e.stylize}if(null!==this.line){if("string"==typeof n[0]&&r.push(a("".concat(this.line-1," ").concat(n[0]),"grey")),"string"==typeof n[1]){var o="".concat(this.line," ");n[1]&&(o+=n[1].slice(0,this.column)+a(a(a(n[1].substr(this.column,1),"bold")+n[1].slice(this.column+1),"red"),"inverse")),r.push(o)}"string"==typeof n[2]&&r.push(a("".concat(this.line+1," ").concat(n[2]),"grey")),r="".concat(r.join("\n")+a("","reset"),"\n")}return t+=a("".concat(this.type,"Error: ").concat(this.message),"red"),this.filename&&(t+=a(" in ","red")+this.filename),this.line&&(t+=a(" on line ".concat(this.line,", column ").concat(this.column+1,":"),"grey")),t+="\n".concat(r),this.callLine&&(t+="".concat(a("from ","red")+(this.filename||""),"/n"),t+="".concat(a(this.callLine,"grey")," ").concat(this.callExtract,"/n")),t};var D=function(e){function t(e,n,i,a,s,o){var u;return r(this,t),(u=f(this,l(t).call(this))).extendList=n,u.condition=i,u.evaldCondition=!i,u._index=a,u._fileInfo=s,u.elements=u.getElements(e),u.mixinElements_=void 0,u.copyVisibilityInfo(o),u.setParent(u.elements,h(u)),u}return o(t,g),s(t,[{key:"accept",value:function(e){this.elements&&(this.elements=e.visitArray(this.elements)),this.extendList&&(this.extendList=e.visitArray(this.extendList)),this.condition&&(this.condition=e.visit(this.condition))}},{key:"createDerived",value:function(e,n,i){var r=new t(e=this.getElements(e),n||this.extendList,null,this.getIndex(),this.fileInfo(),this.visibilityInfo());return r.evaldCondition=null!=i?i:this.evaldCondition,r.mediaEmpty=this.mediaEmpty,r}},{key:"getElements",value:function(e){return e?("string"==typeof e&&this.parse.parseNode(e,["selector"],this._index,this._fileInfo,function(t,n){if(t)throw new $({index:t.index,message:t.message},this.parse.imports,this._fileInfo.filename);e=n[0].elements}),e):[new I("","&",!1,this._index,this._fileInfo)]}},{key:"createEmptySelectors",value:function(){var e=[new t([new I("","&",!1,this._index,this._fileInfo)],null,null,this._index,this._fileInfo)];return e[0].mediaEmpty=!0,e}},{key:"match",value:function(e){var t,n,i=this.elements,r=i.length;if(0===(t=(e=e.mixinElements()).length)||rC.PARENS_DIVISION)||this.parensStack&&this.parensStack.length))}},{key:"pathRequiresRewrite",value:function(e){return(this.rewriteUrls===_.LOCAL?K:Q)(e)}},{key:"rewritePath",value:function(e,t){var n;return t=t||"",n=this.normalizePath(t+e),K(e)&&Q(t)&&!1===K(n)&&(n="./".concat(n)),n}},{key:"normalizePath",value:function(e){var t,n=e.split("/").reverse();for(e=[];0!==n.length;)switch(t=n.pop()){case".":break;case"..":0===e.length||".."===e[e.length-1]?e.push(t):e.pop();break;default:e.push(t)}return e.join("/")}}]),e}();var Z=function e(t){return{_data:{},add:function(e,t){e=e.toLowerCase(),this._data.hasOwnProperty(e),this._data[e]=t},addMultiple:function(e){var t=this;Object.keys(e).forEach(function(n){t.add(n,e[n])})},get:function(e){return this._data[e]||t&&t.get(e)},getLocalFunctions:function(){return this._data},inherit:function(){return e(this)},create:function(t){return e(t)}}}(null),Y={eval:function(){var e=this.value_,t=this.error_;if(t)throw t;if(null!=e)return e?j.True:j.False},value:function(e){this.value_=e},error:function(e){this.error_=e},reset:function(){this.value_=this.error_=null}},X=function(e){function t(e,n,i,a){var s;return r(this,t),(s=f(this,l(t).call(this))).selectors=e,s.rules=n,s._lookups={},s._variables=null,s._properties=null,s.strictImports=i,s.copyVisibilityInfo(a),s.allowRoot=!0,s.setParent(s.selectors,h(s)),s.setParent(s.rules,h(s)),s}return o(t,g),s(t,[{key:"isRulesetLike",value:function(){return!0}},{key:"accept",value:function(e){this.paths?this.paths=e.visitArray(this.paths,!0):this.selectors&&(this.selectors=e.visitArray(this.selectors)),this.rules&&this.rules.length&&(this.rules=e.visitArray(this.rules))}},{key:"eval",value:function(e){var n,i,r,a,s,o=!1;if(this.selectors&&(i=this.selectors.length)){for(n=new Array(i),Y.error({type:"Syntax",message:"it is currently only allowed in parametric mixin guards,"}),a=0;a0;e--){var t=this.rules[e-1];if(t instanceof q)return this.parseValue(t)}}},{key:"parseValue",value:function(e){var t=this;function n(e){return e.value instanceof B&&!e.parsed?("string"==typeof e.value.value?this.parse.parseNode(e.value.value,["value","important"],e.value.getIndex(),e.fileInfo(),function(t,n){t&&(e.parsed=!0),n&&(e.value=n[0],e.important=n[1]||"",e.parsed=!0)}):e.parsed=!0,e):e}if(Array.isArray(e)){var i=[];return e.forEach(function(e){i.push(n.call(t,e))}),i}return n.call(t,e)}},{key:"rulesets",value:function(){if(!this.rules)return[];var e,t,n=[],i=this.rules;for(e=0;t=i[e];e++)t.isRuleset&&n.push(t);return n}},{key:"prependRule",value:function(e){var t=this.rules;t?t.unshift(e):this.rules=[e],this.setParent(e,this)}},{key:"find",value:function(e){var t,n,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this,r=arguments.length>2?arguments[2]:void 0,a=[],s=e.toCSS();return s in this._lookups?this._lookups[s]:(this.rulesets().forEach(function(s){if(s!==i)for(var o=0;ot){if(!r||r(s)){n=s.find(new D(e.elements.slice(t)),i,r);for(var l=0;l0&&t.add(l),e.firstSelector=!0,s[0].genCSS(e,t),e.firstSelector=!1,i=1;i0?(a=(r=P(e)).pop(),s=i.createDerived(P(a.elements))):s=i.createDerived([]),t.length>0){var o=n.combinator,l=t[0].elements[0];o.emptyOrWhitespace&&!l.combinator.emptyOrWhitespace&&(o=l.combinator),s.elements.push(new I(o,l.value,n.isVariable,n._index,n._fileInfo)),s.elements=s.elements.concat(t[0].elements.slice(1))}if(0!==s.elements.length&&r.push(s),t.length>1){var u=t.slice(1);u=u.map(function(e){return e.createDerived(e.elements,[])}),r=r.concat(u)}return r}function s(e,t,n,i,r){var s;for(s=0;s0?i[i.length-1]=i[i.length-1].createDerived(i[i.length-1].elements.concat(e)):i.push(new D(e));else t.push([new D(e)])}function l(e,t){var n=t.createDerived(t.elements,t.extendList,t.evaldCondition);return n.copyVisibilityInfo(e),n}var u,c;if(!function e(t,n,l){var u,c,h,f,p,v,d,m,g,y,b,w,x=!1;for(f=[],p=[[]],u=0;m=l.elements[u];u++)if("&"!==m.value){var S=(w=void 0,(b=m).value instanceof k&&(w=b.value.value)instanceof D?w:null);if(null!=S){o(f,p);var C,_=[],A=[];for(C=e(_,n,S),x=x||C,h=0;h<_.length;h++)s(p,[r(i(_[h],m),m)],m,l,A);p=A,f=[]}else f.push(m)}else{for(x=!0,v=[],o(f,p),c=0;c0&&d[0].elements.push(new I(m.combinator,"",m.isVariable,m._index,m._fileInfo)),v.push(d);else for(h=0;h0&&(t.push(p[u]),y=p[u][g-1],p[u][g-1]=y.createDerived(y.elements,l.extendList));return x}(c=[],t,n))if(t.length>0)for(c=[],u=0;u0)for(t=0;t-1e-6&&(i=n.toFixed(20).replace(/0+$/,"")),e&&e.compress){if(0===n&&this.unit.isLength())return void t.add(i);n>0&&n<1&&(i=i.substr(1))}t.add(i),this.unit.genCSS(e,t)}},{key:"operate",value:function(e,n,i){var r=this._operate(e,n,this.value,i.value),a=this.unit.clone();if("+"===n||"-"===n)if(0===a.numerator.length&&0===a.denominator.length)a=i.unit.clone(),this.unit.backupUnit&&(a.backupUnit=this.unit.backupUnit);else if(0===i.unit.numerator.length&&0===a.denominator.length);else{if(i=i.convertTo(this.unit.usedUnits()),e.strictUnits&&i.unit.toString()!==a.toString())throw new Error("Incompatible units. Change the units or use the unit function. "+"Bad units: '".concat(a.toString(),"' and '").concat(i.unit.toString(),"'."));r=this._operate(e,n,this.value,i.value)}else"*"===n?(a.numerator=a.numerator.concat(i.unit.numerator).sort(),a.denominator=a.denominator.concat(i.unit.denominator).sort(),a.cancel()):"/"===n&&(a.numerator=a.numerator.concat(i.unit.denominator).sort(),a.denominator=a.denominator.concat(i.unit.numerator).sort(),a.cancel());return new t(r,a)}},{key:"compare",value:function(e){var n,i;if(e instanceof t){if(this.unit.isEmpty()||e.unit.isEmpty())n=this,i=e;else if(n=this.unify(),i=e.unify(),0!==n.unit.compare(i.unit))return;return g.numericCompare(n.value,i.value)}}},{key:"unify",value:function(){return this.convertTo({length:"px",duration:"s",angle:"rad"})}},{key:"convertTo",value:function(e){var n,i,r,a,s,o=this.value,l=this.unit.clone(),u={};if("string"==typeof e){for(n in d)d[n].hasOwnProperty(e)&&((u={})[n]=e);e=u}for(i in s=function(e,t){return r.hasOwnProperty(e)?(t?o/=r[e]/r[a]:o*=r[e]/r[a],a):e},e)e.hasOwnProperty(i)&&(a=e[i],r=d[i],l.map(s));return l.cancel(),new t(o,l)}}]),t}();ie.prototype.type="Dimension";var re=C,ae=function(e){function t(e,n,i){var a;return r(this,t),(a=f(this,l(t).call(this))).op=e.trim(),a.operands=n,a.isSpaced=i,a}return o(t,g),s(t,[{key:"accept",value:function(e){this.operands=e.visitArray(this.operands)}},{key:"eval",value:function(e){var n,i=this.operands[0].eval(e),r=this.operands[1].eval(e);if(e.isMathOn(this.op)){if(n="./"===this.op?"/":this.op,i instanceof ie&&r instanceof y&&(i=i.toColor()),r instanceof ie&&i instanceof y&&(r=r.toColor()),!i.operate){if(i instanceof t&&"/"===i.op&&e.math===re.PARENS_DIVISION)return new t(this.op,[i,r],this.isSpaced);throw{type:"Operation",message:"Operation on an invalid type"}}return i.operate(e,n,r)}return new t(this.op,[i,r],this.isSpaced)}},{key:"genCSS",value:function(e,t){this.operands[0].genCSS(e,t),this.isSpaced&&t.add(" "),t.add(this.op),this.isSpaced&&t.add(" "),this.operands[1].genCSS(e,t)}}]),t}();ae.prototype.type="Operation";var se=C,oe=function(e){function t(e,n){var i;if(r(this,t),(i=f(this,l(t).call(this))).value=e,i.noSpacing=n,!e)throw new Error("Expression requires an array parameter");return i}return o(t,g),s(t,[{key:"accept",value:function(e){this.value=e.visitArray(this.value)}},{key:"eval",value:function(e){var n,i=e.isMathOn(),r=this.parens&&(e.math!==se.STRICT_LEGACY||!this.parensInOp),a=!1;return r&&e.inParenthesis(),this.value.length>1?n=new t(this.value.map(function(t){return t.eval?t.eval(e):t}),this.noSpacing):1===this.value.length?(!this.value[0].parens||this.value[0].parensInOp||e.inCalc||(a=!0),n=this.value[0].eval(e)):n=this,r&&e.outOfParenthesis(),!this.parens||!this.parensInOp||i||a||n instanceof ie||(n=new k(n)),n}},{key:"genCSS",value:function(e,t){for(var n=0;n1){var n=new D([],null,null,this.getIndex(),this.fileInfo()).createEmptySelectors();(t=new X(n,e.mediaBlocks)).multiMedia=!0,t.copyVisibilityInfo(this.visibilityInfo()),this.setParent(t,this)}return delete e.mediaBlocks,delete e.mediaPath,t}},{key:"evalNested",value:function(e){var t,n,i=e.mediaPath.concat([this]);for(t=0;t0;t--)e.splice(t,0,new B("and"));return new oe(e)})),this.setParent(this.features,this),new X([],[])}},{key:"permute",value:function(e){if(0===e.length)return[];if(1===e.length)return e[0];for(var t=[],n=this.permute(e.slice(1)),i=0;i1?"[".concat(e.value.map(function(e){return e.toCSS()}).join(", "),"]"):e.toCSS()}}]),t}(),ye=function(e){function t(e,n,i,a){var s;return r(this,t),(s=f(this,l(t).call(this))).escaped=n,s.expression=e,s._index=i,s._fileInfo=a,s}return o(t,ge),s(t,[{key:"eval",value:function(e){var t=this.evaluateJavaScript(this.expression,e),n=i(t);return"number"!==n||isNaN(t)?"string"===n?new pe('"'.concat(t,'"'),t,this.escaped,this._index):Array.isArray(t)?new B(t.join(", ")):new B(t):new ie(t)}}]),t}();ye.prototype.type="JavaScript";var be=function(e){function t(e,n){var i;return r(this,t),(i=f(this,l(t).call(this))).key=e,i.value=n,i}return o(t,g),s(t,[{key:"accept",value:function(e){this.value=e.visit(this.value)}},{key:"eval",value:function(e){return this.value.eval?new t(this.key,this.value.eval(e)):this}},{key:"genCSS",value:function(e,t){t.add("".concat(this.key,"=")),this.value.genCSS?this.value.genCSS(e,t):t.add(this.value)}}]),t}();be.prototype.type="Assignment";var we=function(e){function t(e,n,i,a,s){var o;return r(this,t),(o=f(this,l(t).call(this))).op=e.trim(),o.lvalue=n,o.rvalue=i,o._index=a,o.negate=s,o}return o(t,g),s(t,[{key:"accept",value:function(e){this.lvalue=e.visit(this.lvalue),this.rvalue=e.visit(this.rvalue)}},{key:"eval",value:function(e){var t=function(e,t,n){switch(e){case"and":return t&&n;case"or":return t||n;default:switch(g.compare(t,n)){case-1:return"<"===e||"=<"===e||"<="===e;case 0:return"="===e||">="===e||"=<"===e||"<="===e;case 1:return">"===e||">="===e;default:return!1}}}(this.op,this.lvalue.eval(e),this.rvalue.eval(e));return this.negate?!t:t}}]),t}();we.prototype.type="Condition";var ke=function(e){function t(e){var n;return r(this,t),(n=f(this,l(t).call(this))).value=e,n}return o(t,g),t}();ke.prototype.type="UnicodeDescriptor";var xe=function(e){function t(e){var n;return r(this,t),(n=f(this,l(t).call(this))).value=e,n}return o(t,g),s(t,[{key:"genCSS",value:function(e,t){t.add("-"),this.value.genCSS(e,t)}},{key:"eval",value:function(e){return e.isMathOn()?new ae("*",[new ie(-1),this.value]).eval(e):new t(this.value.eval(e))}}]),t}();xe.prototype.type="Negative";var Se=function(e){function t(e,n,i,a,s){var o;switch(r(this,t),(o=f(this,l(t).call(this))).selector=e,o.option=n,o.object_id=t.next_id++,o.parent_ids=[o.object_id],o._index=i,o._fileInfo=a,o.copyVisibilityInfo(s),o.allowRoot=!0,n){case"all":o.allowBefore=!0,o.allowAfter=!0;break;default:o.allowBefore=!1,o.allowAfter=!1}return o.setParent(o.selector,h(o)),o}return o(t,g),s(t,[{key:"accept",value:function(e){this.selector=e.visit(this.selector)}},{key:"eval",value:function(e){return new t(this.selector.eval(e),this.option,this.getIndex(),this.fileInfo(),this.visibilityInfo())}},{key:"clone",value:function(e){return new t(this.selector,this.option,this.getIndex(),this.fileInfo(),this.visibilityInfo())}},{key:"findSelfSelectors",value:function(e){var t,n,i=[];for(t=0;t0&&n.length&&""===n[0].combinator.value&&(n[0].combinator.value=" "),i=i.concat(e[t].elements);this.selfSelectors=[new D(i)],this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo())}}]),t}();Se.next_id=0,Se.prototype.type="Extend";var Ie=function(e){function t(e,n,i){var a;return r(this,t),(a=f(this,l(t).call(this))).variable=e,a._index=n,a._fileInfo=i,a.allowRoot=!0,a}return o(t,g),s(t,[{key:"eval",value:function(e){var t,n=new ce(this.variable,this.getIndex(),this.fileInfo()).eval(e),i=new $({message:"Could not evaluate variable call ".concat(this.variable)});if(!n.ruleset){if(n.rules)t=n;else if(Array.isArray(n))t=new X("",n);else{if(!Array.isArray(n.value))throw i;t=new X("",n.value)}n=new te(t)}if(n.ruleset)return n.callEval(e);throw i}}]),t}();Ie.prototype.type="VariableCall";var Ce=function(e){function t(e,n,i,a,s){var o;return r(this,t),(o=f(this,l(t).call(this))).value=e,o.lookups=n,o.important=i,o._index=a,o._fileInfo=s,o}return o(t,g),s(t,[{key:"eval",value:function(e){var t,n,i=this.value.eval(e);for(t=0;tthis.params.length)return!1}n=Math.min(a,this.arity);for(var s=0;s0){for(c=!0,o=0;o0)f=I;else if(f=S,p[S]+p[I]>1)throw{type:"Runtime",message:"Ambiguous use of `default()` found when matching for `".concat(this.format(m),"`"),index:this.getIndex(),filename:this.fileInfo().filename};for(o=0;o=0;s--){var o=a[s];if(o[r?"supportsSync":"supports"](e,t,n,i))return o}return null}},{key:"addFileManager",value:function(e){this.fileManagers.push(e)}},{key:"clearFileManagers",value:function(){this.fileManagers=[]}}]),e}(),Re=function(){function e(){r(this,e)}return s(e,[{key:"getPath",value:function(e){var t=e.lastIndexOf("?");return t>0&&(e=e.slice(0,t)),(t=e.lastIndexOf("/"))<0&&(t=e.lastIndexOf("\\")),t<0?"":e.slice(0,t+1)}},{key:"tryAppendExtension",value:function(e,t){return/(\.[a-z]*$)|([\?;].*)$/.test(e)?e:e+t}},{key:"tryAppendLessExtension",value:function(e){return this.tryAppendExtension(e,".less")}},{key:"supportsSync",value:function(){return!1}},{key:"alwaysMakePathsAbsolute",value:function(){return!1}},{key:"isPathAbsolute",value:function(e){return/^(?:[a-z-]+:|\/|\\|#)/i.test(e)}},{key:"join",value:function(e,t){return e?e+t:t}},{key:"pathDiff",value:function(e,t){var n,i,r,a,s=this.extractUrlParts(e),o=this.extractUrlParts(t),l="";if(s.hostPart!==o.hostPart)return"";for(i=Math.max(o.directories.length,s.directories.length),n=0;nparseInt(t[n])?-1:1;return 0}},{key:"versionToString",value:function(e){for(var t="",n=0;n0;){var e=this.imports[0];if(!e.isReady)return;this.imports=this.imports.slice(1),e.callback.apply(null,e.args)}if(0===this.variableImports.length)break;var t=this.variableImports[0];this.variableImports=this.variableImports.slice(1),t()}}finally{this._currentDepth--}0===this._currentDepth&&this._onSequencerEmpty&&this._onSequencerEmpty()}}]),e}(),Ne=function(e,t){this._visitor=new Le(this),this._importer=e,this._finish=t,this.context=new G.Eval,this.importCount=0,this.onceFileDetectionMap={},this.recursionDetector={},this._sequencer=new De(this._onSequencerEmpty.bind(this))};Ne.prototype={isReplacing:!1,run:function(e){try{this._visitor.visit(e)}catch(e){this.error=e}this.isFinished=!0,this._sequencer.tryRun()},_onSequencerEmpty:function(){this.isFinished&&this._finish(this.error)},visitImport:function(e,t){var n=e.options.inline;if(!e.css||n){var i=new G.Eval(this.context,P(this.context.frames)),r=i.frames[0];this.importCount++,e.isVariableImport()?this._sequencer.addVariableImport(this.processImportNode.bind(this,e,i,r)):this.processImportNode(e,i,r)}t.visitDeeper=!1},processImportNode:function(e,t,n){var i,r=e.options.inline;try{i=e.evalForImport(t)}catch(t){t.filename||(t.index=e.getIndex(),t.filename=e.fileInfo().filename),e.css=!0,e.error=t}if(!i||i.css&&!r)this.importCount--,this.isFinished&&this._sequencer.tryRun();else{i.options.multiple&&(t.importMultiple=!0);for(var a=void 0===i.css,s=0;s=0||(o=[u.selfSelectors[0]],(a=f.findMatch(l,o)).length&&(l.hasFoundMatches=!0,l.selfSelectors.forEach(function(e){var t=u.visibilityInfo();s=f.extendSelector(a,o,e,l.isVisible()),(c=new Me.Extend(u.selector,u.option,0,u.fileInfo(),t)).selfSelectors=s,s[s.length-1].extendList=[c],h.push(c),c.ruleset=u.ruleset,c.parent_ids=c.parent_ids.concat(u.parent_ids,l.parent_ids),u.firstExtendOnThisSelectorPath&&(c.firstExtendOnThisSelectorPath=!0,u.ruleset.paths.push(s))})));if(h.length){if(this.extendChainCount++,n>100){var p="{unable to calculate}",v="{unable to calculate}";try{p=h[0].selfSelectors[0].toCSS(),v=h[0].selector.toCSS()}catch(e){}throw{message:"extend circular reference detected. One of the circular extends is currently:".concat(p,":extend(").concat(v,")")}}return h.concat(f.doExtendChaining(h,t,n+1))}return h}},{key:"visitDeclaration",value:function(e,t){t.visitDeeper=!1}},{key:"visitMixinDefinition",value:function(e,t){t.visitDeeper=!1}},{key:"visitSelector",value:function(e,t){t.visitDeeper=!1}},{key:"visitRuleset",value:function(e,t){if(!e.root){var n,i,r,a,s=this.allExtendsStack[this.allExtendsStack.length-1],o=[],l=this;for(r=0;r0&&u[l.matched].combinator.value!==s?l=null:l.matched++,l&&(l.finished=l.matched===u.length,l.finished&&!e.allowAfter&&(r+1u&&c>0&&(h[h.length-1].elements=h[h.length-1].elements.concat(t[u].elements.slice(c)),c=0,u++),l=a.elements.slice(c,o.index).concat([s]).concat(n.elements.slice(1)),u===o.pathIndex&&r>0?h[h.length-1].elements=h[h.length-1].elements.concat(l):(h=h.concat(t.slice(u,o.pathIndex))).push(new Me.Selector(l)),u=o.endPathIndex,(c=o.endPathElementIndex)>=t[u].elements.length&&(c=0,u++);return u0&&(h[h.length-1].elements=h[h.length-1].elements.concat(t[u].elements.slice(c)),u++),h=(h=h.concat(t.slice(u,t.length))).map(function(e){var t=e.createDerived(e.elements);return i?t.ensureVisibility():t.ensureInvisibility(),t})}},{key:"visitMedia",value:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)}},{key:"visitMediaOut",value:function(e){var t=this.allExtendsStack.length-1;this.allExtendsStack.length=t}},{key:"visitAtRule",value:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)}},{key:"visitAtRuleOut",value:function(e){var t=this.allExtendsStack.length-1;this.allExtendsStack.length=t}}]),e}(),qe=function(){function e(){r(this,e),this.contexts=[[]],this._visitor=new Le(this)}return s(e,[{key:"run",value:function(e){return this._visitor.visit(e)}},{key:"visitDeclaration",value:function(e,t){t.visitDeeper=!1}},{key:"visitMixinDefinition",value:function(e,t){t.visitDeeper=!1}},{key:"visitRuleset",value:function(e,t){var n,i=this.contexts[this.contexts.length-1],r=[];this.contexts.push(r),e.root||((n=e.selectors)&&(n=n.filter(function(e){return e.getIsOutput()}),e.selectors=n.length?n:n=null,n&&e.joinSelectors(r,i,n)),n||(e.rules=null),e.paths=r)}},{key:"visitRulesetOut",value:function(e){this.contexts.length=this.contexts.length-1}},{key:"visitMedia",value:function(e,t){var n=this.contexts[this.contexts.length-1];e.rules[0].root=0===n.length||n[0].multiMedia}},{key:"visitAtRule",value:function(e,t){var n=this.contexts[this.contexts.length-1];e.rules&&e.rules.length&&(e.rules[0].root=e.isRooted||0===n.length||null)}}]),e}(),Te=function(){function e(t){r(this,e),this._visitor=new Le(this),this._context=t}return s(e,[{key:"containsSilentNonBlockedChild",value:function(e){var t;if(!e)return!1;for(var n=0;n0}},{key:"resolveVisibility",value:function(e,t){if(!e.blocksVisibility()){if(this.isEmpty(e)&&!this.containsSilentNonBlockedChild(t))return;return e}var n=e.rules[0];if(this.keepOnlyVisibleChilds(n),!this.isEmpty(n))return e.ensureVisibility(),e.removeVisibilityBlock(),e}},{key:"isVisibleRuleset",value:function(e){return!!e.firstRoot||!this.isEmpty(e)&&!(!e.root&&!this.hasVisibleSelector(e))}}]),e}(),ze=function(e){this._visitor=new Le(this),this._context=e,this.utils=new Te(e)};ze.prototype={isReplacing:!0,run:function(e){return this._visitor.visit(e)},visitDeclaration:function(e,t){if(!e.blocksVisibility()&&!e.variable)return e},visitMixinDefinition:function(e,t){e.frames=[]},visitExtend:function(e,t){},visitComment:function(e,t){if(!e.blocksVisibility()&&!e.isSilent(this._context))return e},visitMedia:function(e,t){var n=e.rules[0].rules;return e.accept(this._visitor),t.visitDeeper=!1,this.utils.resolveVisibility(e,n)},visitImport:function(e,t){if(!e.blocksVisibility())return e},visitAtRule:function(e,t){return e.rules&&e.rules.length?this.visitAtRuleWithBody(e,t):this.visitAtRuleWithoutBody(e,t)},visitAnonymous:function(e,t){if(!e.blocksVisibility())return e.accept(this._visitor),e},visitAtRuleWithBody:function(e,t){var n=function(e){var t=e.rules;return function(e){var t=e.rules;return 1===t.length&&(!t[0].paths||0===t[0].paths.length)}(e)?t[0].rules:t}(e);return e.accept(this._visitor),t.visitDeeper=!1,this.utils.isEmpty(e)||this._mergeRules(e.rules[0].rules),this.utils.resolveVisibility(e,n)},visitAtRuleWithoutBody:function(e,t){if(!e.blocksVisibility()){if("@charset"===e.name){if(this.charset){if(e.debugInfo){var n=new Me.Comment("/* ".concat(e.toCSS(this._context).replace(/\n/g,"")," */\n"));return n.debugInfo=e.debugInfo,this._visitor.visit(n)}return}this.charset=!0}return e}},checkValidNodes:function(e,t){if(e)for(var n=0;n0?e.accept(this._visitor):e.rules=null,t.visitDeeper=!1}return e.rules&&(this._mergeRules(e.rules),this._removeDuplicateRules(e.rules)),this.utils.isVisibleRuleset(e)&&(e.ensureVisibility(),i.splice(0,0,e)),1===i.length?i[0]:i},_compileRulesetPaths:function(e){e.paths&&(e.paths=e.paths.filter(function(e){var t;for(" "===e[0].elements[0].combinator.value&&(e[0].elements[0].combinator=new Me.Combinator("")),t=0;t=0;i--)if((n=e[i])instanceof Me.Declaration)if(r[n.name]){(t=r[n.name])instanceof Me.Declaration&&(t=r[n.name]=[r[n.name].toCSS(this._context)]);var a=n.toCSS(this._context);-1!==t.indexOf(a)?e.splice(i,1):t.push(a)}else r[n.name]=n}},_mergeRules:function(e){if(e){for(var t={},n=[],i=0;i0){var t=e[0],n=[],i=[new Me.Expression(n)];e.forEach(function(e){"+"===e.merge&&n.length>0&&i.push(new Me.Expression(n=[])),n.push(e.value),t.important=t.important||e.important}),t.value=new Me.Value(i)}})}}};var Ge={Visitor:Le,ImportVisitor:Ne,MarkVisibleSelectorsVisitor:je,ExtendVisitor:Ue,JoinSelectorVisitor:qe,ToCSSVisitor:ze},We=function(){var e,t,n,i,r,a,s,o=[],l={},u=32,c=9,h=10,f=13,p=47;function v(n){for(var i,o,d,m=l.i,g=t,y=l.i-s,b=l.i+a.length-y,w=l.i+=n,k=e;l.i=0){d={index:l.i,text:k.substr(l.i,S+2-l.i),isLineComment:!1},l.i+=d.text.length-1,l.commentStore.push(d);continue}}break}if(i!==u&&i!==h&&i!==c&&i!==f)break}if(a=a.slice(n+l.i-w+y),s=l.i,!a.length){if(tn||l.i===n&&e&&!i)&&(n=l.i,i=e);var r=o.pop();a=r.current,s=l.i=r.i,t=r.j},l.forget=function(){o.pop()},l.isWhitespace=function(t){var n=l.i+(t||0),i=e.charCodeAt(n);return i===u||i===f||i===c||i===h},l.$re=function(e){l.i>s&&(a=a.slice(l.i-s),s=l.i);var t=e.exec(a);return t?(v(t[0].length),"string"==typeof t?t:1===t.length?t[0]:t):null},l.$char=function(t){return e.charAt(l.i)!==t?null:(v(1),t)},l.$str=function(t){for(var n=t.length,i=0;ic&&(d=!1)}}while(d);return r||null},l.autoCommentAbsorb=!0,l.commentStore=[],l.finished=!1,l.peek=function(t){if("string"==typeof t){for(var n=0;n57||t<43||t===p||44===t},l.start=function(i,o,u){e=i,l.i=t=s=n=0,r=o?function(e,t){var n,i,r,a,s,o,l,u,c,h=e.length,f=0,p=0,v=[],d=0;function m(t){var n=s-d;n<512&&!t||!n||(v.push(e.slice(d,s+1)),d=s+1)}for(s=0;s=97&&l<=122||l<34))switch(l){case 40:p++,i=s;continue;case 41:if(--p<0)return t("missing opening `(`",s);continue;case 59:p||m();continue;case 123:f++,n=s;continue;case 125:if(--f<0)return t("missing opening `{`",s);f||p||m();continue;case 92:if(s96)){if(u==l){c=1;break}if(92==u){if(s==h-1)return t("unescaped `\\`",s);s++}}if(c)continue;return t("unmatched `".concat(String.fromCharCode(l),"`"),o);case 47:if(p||s==h-1)continue;if(47==(u=e.charCodeAt(s+1)))for(s+=2;sn&&a>r?"missing closing `}` or `*/`":"missing closing `}`",n):0!==p?t("missing closing `)`",i):(m(!0),v)}(i,u):[i],a=r[0],v(0)},l.end=function(){var t,r=l.i>=e.length;return l.i=e.length-1,furthestChar:e[l.i]}},l},Je=function e(t,n,i){var r,a=We();function s(e,t){throw new $({index:a.i,filename:i.filename,type:t||"Syntax",message:e},n)}function o(e,t){var n=e instanceof Function?e.call(r):a.$re(e);if(n)return n;s(t||("string"==typeof e?"expected '".concat(e,"' got '").concat(a.currentChar(),"'"):"unexpected token"))}function l(e,t){if(a.$char(e))return e;s(t||"expected '".concat(e,"' got '").concat(a.currentChar(),"'"))}function u(e){var t=i.filename;return{lineNumber:M(e,a.getInput()).line+1,fileName:t}}return{parserInput:a,imports:n,fileInfo:i,parseNode:function(e,t,i,s,o){var l,u=[],c=a;try{c.start(e,!1,function(e,t){o({message:e,index:t+i})});for(var h,f,p=0;h=t[p];p++)f=c.i,(l=r[h]())?(l._index=f+i,l._fileInfo=s,u.push(l)):u.push(null);c.end().isFinished?o(null,u):o(!0,null)}catch(e){throw new $({index:e.index+i,message:e.message},n,s.filename)}},parse:function(r,s,o){var l,u,c,h,f=null,p="";if(u=o&&o.globalVars?"".concat(e.serializeVars(o.globalVars),"\n"):"",c=o&&o.modifyVars?"\n".concat(e.serializeVars(o.modifyVars)):"",t.pluginManager)for(var v=t.pluginManager.getPreProcessors(),d=0;d");return e},args:function(e){var t,n,i,o,l,u,c,h=r.entities,f={args:null,variadic:!1},p=[],v=[],d=[],m=!0;for(a.save();;){if(e)u=r.detachedRuleset()||r.expression();else{if(a.commentStore.length=0,a.$str("...")){f.variadic=!0,a.$char(";")&&!t&&(t=!0),(t?v:d).push({variadic:!0});break}u=h.variable()||h.property()||h.literal()||h.keyword()||this.call(!0)}if(!u||!m)break;o=null,u.throwAwayComments&&u.throwAwayComments(),l=u;var g=null;if(e?u.value&&1==u.value.length&&(g=u.value[0]):g=u,g&&(g instanceof Me.Variable||g instanceof Me.Property))if(a.$char(":")){if(p.length>0&&(t&&s("Cannot mix ; and , as delimiter types"),n=!0),!(l=r.detachedRuleset()||r.expression())){if(!e)return a.restore(),f.args=[],f;s("could not understand value for named argument")}o=i=g.name}else if(a.$str("...")){if(!e){f.variadic=!0,a.$char(";")&&!t&&(t=!0),(t?v:d).push({name:u.name,variadic:!0});break}c=!0}else e||(i=o=g.name,l=null);l&&p.push(l),d.push({name:o,value:l,expand:c}),a.$char(",")?m=!0:((m=";"===a.$char(";"))||t)&&(n&&s("Cannot mix ; and , as delimiter types"),t=!0,p.length>1&&(l=new Me.Value(p)),v.push({name:i,value:l,expand:c}),i=null,p=[],n=!1)}return a.forget(),f.args=t?v:d,f},definition:function(){var e,t,n,i,s=[],l=!1;if(!("."!==a.currentChar()&&"#"!==a.currentChar()||a.peek(/^[^{]*\}/)))if(a.save(),t=a.$re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=t[1];var u=this.args(!1);if(s=u.args,l=u.variadic,!a.$char(")"))return void a.restore("Missing closing ')'");if(a.commentStore.length=0,a.$str("when")&&(i=o(r.conditions,"expected condition")),n=r.block())return a.forget(),new Me.mixin.Definition(e,s,n,i,l);a.restore()}else a.forget()},ruleLookups:function(){var e,t=[];if("["===a.currentChar()){for(;;){if(a.save(),!(e=this.lookupValue())&&""!==e){a.restore();break}t.push(e),a.forget()}return t.length>0?t:void 0}},lookupValue:function(){if(a.save(),a.$char("[")){var e=a.$re(/^(?:[@$]{0,2})[_a-zA-Z0-9-]*/);if(a.$char("]"))return e||""===e?(a.forget(),e):void a.restore();a.restore()}else a.restore()}},entity:function(){var e=this.entities;return this.comment()||e.literal()||e.variable()||e.url()||e.property()||e.call()||e.keyword()||this.mixin.call(!0)||e.javascript()},end:function(){return a.$char(";")||a.peek("}")},ieAlpha:function(){var e;if(a.$re(/^opacity=/i))return(e=a.$re(/^\d+/))||(e=o(r.entities.variable,"Could not parse alpha"),e="@{".concat(e.name.slice(1),"}")),l(")"),new Me.Quoted("","alpha(opacity=".concat(e,")"))},element:function(){var e,t,n,r=a.i;if(t=this.combinator(),(e=a.$re(/^(?:\d+\.\d+|\d+)%/)||a.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||a.$char("*")||a.$char("&")||this.attribute()||a.$re(/^\([^&()@]+\)/)||a.$re(/^[\.#:](?=@)/)||this.entities.variableCurly())||(a.save(),a.$char("(")?(n=this.selector(!1))&&a.$char(")")?(e=new Me.Paren(n),a.forget()):a.restore("Missing closing ')'"):a.forget()),e)return new Me.Element(t,e,e instanceof Me.Variable,r,i)},combinator:function(){var e=a.currentChar();if("/"===e){a.save();var t=a.$re(/^\/[a-z]+\//i);if(t)return a.forget(),new Me.Combinator(t);a.restore()}if(">"===e||"+"===e||"~"===e||"|"===e||"^"===e){for(a.i++,"^"===e&&"^"===a.currentChar()&&(e="^^",a.i++);a.isWhitespace();)a.i++;return new Me.Combinator(e)}return a.isWhitespace(-1)?new Me.Combinator(" "):new Me.Combinator(null)},selector:function(e){var t,n,r,l,u,c,h,f=a.i;for(e=!1!==e;(e&&(n=this.extend())||e&&(c=a.$str("when"))||(l=this.element()))&&(c?h=o(this.conditions,"expected condition"):h?s("CSS guard can only be used at the end of selector"):n?u=u?u.concat(n):n:(u&&s("Extend can only be used at the end of selector"),r=a.currentChar(),t?t.push(l):t=[l],l=null),"{"!==r&&"}"!==r&&";"!==r&&","!==r&&")"!==r););if(t)return new Me.Selector(t,u,h,f,i);u&&s("Extend must be used to extend a selector, it cannot be used on its own")},selectors:function(){for(var e,t;(e=this.selector())&&(t?t.push(e):t=[e],a.commentStore.length=0,e.condition&&t.length>1&&s("Guards are only currently allowed on a single selector."),a.$char(","));)e.condition&&s("Guards are only currently allowed on a single selector."),a.commentStore.length=0;return t},attribute:function(){if(a.$char("[")){var e,t,n,i=this.entities;return(e=i.variableCurly())||(e=o(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/)),(n=a.$re(/^[|~*$^]?=/))&&(t=i.quoted()||a.$re(/^[0-9]+%/)||a.$re(/^[\w-]+/)||i.variableCurly()),l("]"),new Me.Attribute(e,n,t)}},block:function(){var e;if(a.$char("{")&&(e=this.primary())&&a.$char("}"))return e},blockRuleset:function(){var e=this.block();return e&&(e=new Me.Ruleset(null,e)),e},detachedRuleset:function(){var e,t,n;if(a.save(),!a.$re(/^[.#]\(/)||(t=(e=this.mixin.args(!1)).args,n=e.variadic,a.$char(")"))){var i=this.blockRuleset();if(i)return a.forget(),t?new Me.mixin.Definition(null,t,i,null,n):new Me.DetachedRuleset(i);a.restore()}else a.restore()},ruleset:function(){var e,n,i;if(a.save(),t.dumpLineNumbers&&(i=u(a.i)),(e=this.selectors())&&(n=this.block())){a.forget();var r=new Me.Ruleset(e,n,t.strictImports);return t.dumpLineNumbers&&(r.debugInfo=i),r}a.restore()},declaration:function(){var e,t,n,r,s,o,l=a.i,u=a.currentChar();if("."!==u&&"#"!==u&&"&"!==u&&":"!==u)if(a.save(),e=this.variable()||this.ruleProperty()){if((o="string"==typeof e)&&(t=this.detachedRuleset())&&(n=!0),a.commentStore.length=0,!t){if(s=!o&&e.length>1&&e.pop().value,t=e[0].value&&"--"===e[0].value.slice(0,2)?this.permissiveValue():this.anonymousValue())return a.forget(),new Me.Declaration(e,t,!1,s,l,i);t||(t=this.value()),t?r=this.important():o&&(t=this.permissiveValue())}if(t&&(this.end()||n))return a.forget(),new Me.Declaration(e,t,r,s,l,i);a.restore()}else a.restore()},anonymousValue:function(){var e=a.i,t=a.$re(/^([^.#@\$+\/'"*`(;{}-]*);/);if(t)return new Me.Anonymous(t[1],e)},permissiveValue:function(e){var t,n,r,o,l=e||";",u=a.i,c=[];function h(){var e=a.currentChar();return"string"==typeof l?e===l:l.test(e)}if(!h()){o=[];do{(n=this.comment())?o.push(n):(n=this.entity())&&o.push(n)}while(n);if(r=h(),o.length>0){if(o=new Me.Expression(o),r)return o;c.push(o)," "===a.prevChar()&&c.push(new Me.Anonymous(" ",u))}if(a.save(),o=a.$parseUntil(l)){if("string"==typeof o&&s("Expected '".concat(o,"'"),"Parse"),1===o.length&&" "===o[0])return a.forget(),new Me.Anonymous("",u);var f;for(t=0;t0)return new Me.Expression(r)},mediaFeatures:function(){var e,t=this.entities,n=[];do{if(e=this.mediaFeature()){if(n.push(e),!a.$char(","))break}else if((e=t.variable()||t.mixinLookup())&&(n.push(e),!a.$char(",")))break}while(e);return n.length>0?n:null},media:function(){var e,n,r,o,l=a.i;if(t.dumpLineNumbers&&(o=u(l)),a.save(),a.$str("@media"))return e=this.mediaFeatures(),(n=this.block())||s("media definitions require block statements after any features"),a.forget(),r=new Me.Media(n,e,l,i),t.dumpLineNumbers&&(r.debugInfo=o),r;a.restore()},plugin:function(){var e,t,n,r=a.i;if(a.$re(/^@plugin?\s+/)){if(n=(t=this.pluginArgs())?{pluginArgs:t,isPlugin:!0}:{isPlugin:!0},e=this.entities.quoted()||this.entities.url())return a.$char(";")||(a.i=r,s("missing semi-colon on @plugin")),new Me.Import(e,null,n,r,i);a.i=r,s("malformed @plugin statement")}},pluginArgs:function(){if(a.save(),!a.$char("("))return a.restore(),null;var e=a.$re(/^\s*([^\);]+)\)\s*/);return e[1]?(a.forget(),e[1].trim()):(a.restore(),null)},atrule:function(){var e,n,r,o,l,c,h,f=a.i,p=!0,v=!0;if("@"===a.currentChar()){if(n=this.import()||this.plugin()||this.media())return n;if(a.save(),e=a.$re(/^@[a-z-]+/)){switch(o=e,"-"==e.charAt(1)&&e.indexOf("-",2)>0&&(o="@".concat(e.slice(e.indexOf("-",2)+1))),o){case"@charset":l=!0,p=!1;break;case"@namespace":c=!0,p=!1;break;case"@keyframes":case"@counter-style":l=!0;break;case"@document":case"@supports":h=!0,v=!1;break;default:h=!0}if(a.commentStore.length=0,l?(n=this.entity())||s("expected ".concat(e," identifier")):c?(n=this.expression())||s("expected ".concat(e," expression")):h&&(n=this.permissiveValue(/^[{;]/),p="{"===a.currentChar(),n?n.value||(n=null):p||";"===a.currentChar()||s("".concat(e," rule is missing block or ending semi-colon"))),p&&(r=this.blockRuleset()),r||!p&&n&&a.$char(";"))return a.forget(),new Me.AtRule(e,n,r,f,i,t.dumpLineNumbers?u(f):null,v);a.restore("at-rule options not recognised")}}},value:function(){var e,t=[],n=a.i;do{if((e=this.expression())&&(t.push(e),!a.$char(",")))break}while(e);if(t.length>0)return new Me.Value(t,n)},important:function(){if("!"===a.currentChar())return a.$re(/^! *important/)},sub:function(){var e,t;if(a.save(),a.$char("("))return(e=this.addition())&&a.$char(")")?(a.forget(),(t=new Me.Expression([e])).parens=!0,t):void a.restore("Expected ')'");a.restore()},multiplication:function(){var e,t,n,i,r;if(e=this.operand()){for(r=a.isWhitespace(-1);!a.peek(/^\/[*\/]/);){if(a.save(),!(n=a.$char("/")||a.$char("*")||a.$str("./"))){a.forget();break}if(!(t=this.operand())){a.restore();break}a.forget(),e.parensInOp=!0,t.parensInOp=!0,i=new Me.Operation(n,[i||e,t],r),r=a.isWhitespace(-1)}return i||e}},addition:function(){var e,t,n,i,r;if(e=this.multiplication()){for(r=a.isWhitespace(-1);(n=a.$re(/^[-+]\s+/)||!r&&(a.$char("+")||a.$char("-")))&&(t=this.multiplication());)e.parensInOp=!0,t.parensInOp=!0,i=new Me.Operation(n,[i||e,t],r),r=a.isWhitespace(-1);return i||e}},conditions:function(){var e,t,n,i=a.i;if(e=this.condition(!0)){for(;a.peek(/^,\s*(not\s*)?\(/)&&a.$char(",")&&(t=this.condition(!0));)n=new Me.Condition("or",n||e,t,i);return n||e}},condition:function(e){var t,n,i;if(t=this.conditionAnd(e)){if(n=a.$str("or")){if(!(i=this.condition(e)))return;t=new Me.Condition(n,t,i)}return t}},conditionAnd:function(e){var t,n,i,r,s=this;if(t=(r=s.negatedCondition(e)||s.parenthesisCondition(e))||e?r:s.atomicCondition(e)){if(n=a.$str("and")){if(!(i=this.conditionAnd(e)))return;t=new Me.Condition(n,t,i)}return t}},negatedCondition:function(e){if(a.$str("not")){var t=this.parenthesisCondition(e);return t&&(t.negate=!t.negate),t}},parenthesisCondition:function(e){var t;if(a.save(),a.$str("(")){if(t=function(t){var n;if(a.save(),n=t.condition(e)){if(a.$char(")"))return a.forget(),n;a.restore()}else a.restore()}(this))return a.forget(),t;if(t=this.atomicCondition(e)){if(a.$char(")"))return a.forget(),t;a.restore("expected ')' got '".concat(a.currentChar(),"'"))}else a.restore()}else a.restore()},atomicCondition:function(e){var t,n,i,r,o=this.entities,l=a.i;function u(){return this.addition()||o.keyword()||o.quoted()||o.mixinLookup()}if(t=(u=u.bind(this))())return a.$char(">")?r=a.$char("=")?">=":">":a.$char("<")?r=a.$char("=")?"<=":"<":a.$char("=")&&(r=a.$char(">")?"=>":a.$char("<")?"=<":"="),r?(n=u())?i=new Me.Condition(r,t,n,l,!1):s("expected expression"):i=new Me.Condition("=",t,new Me.Keyword("true"),l,!1),i},operand:function(){var e,t=this.entities;a.peek(/^-[@\$\(]/)&&(e=a.$char("-"));var n=this.sub()||t.dimension()||t.color()||t.variable()||t.property()||t.call()||t.quoted(!0)||t.colorKeyword()||t.mixinLookup();return e&&(n.parensInOp=!0,n=new Me.Negative(n)),n},expression:function(){var e,t,n=[],i=a.i;do{(e=this.comment())?n.push(e):(e=this.addition()||this.entity())&&(n.push(e),a.peek(/^\/[\/*]/)||(t=a.$char("/"))&&n.push(new Me.Anonymous(t,i)))}while(e);if(n.length>0)return new Me.Expression(n)},property:function(){var e=a.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/);if(e)return e[1]},ruleProperty:function(){var e,t,n=[],r=[];a.save();var s=a.$re(/^([_a-zA-Z0-9-]+)\s*:/);if(s)return n=[new Me.Keyword(s[1])],a.forget(),n;function o(e){var t=a.i,i=a.$re(e);if(i)return r.push(t),n.push(i[1])}for(o(/^(\*?)/);o(/^((?:[\w-]+)|(?:[@\$]\{[\w-]+\}))/););if(n.length>1&&o(/^((?:\+_|\+)?)\s*:/)){for(a.forget(),""===n[0]&&(n.shift(),r.shift()),t=0;t1?e-1:e)<1?r+(a-r)*e*6:2*e<1?a:3*e<2?r+(a-r)*(2/3-e)*6:r};if(e instanceof y)return i=t?et(t):e.alpha,new y(e.rgb,i,"hsla");e=et(e)%360/360,t=Ke(et(t)),n=Ke(et(n)),i=Ke(et(i)),r=2*n-(a=n<=.5?n*(t+1):n+t-n*t);var o=[255*s(e+1/3),255*s(e),255*s(e-1/3)];return i=et(i),new y(o,i,"hsla")}catch(e){}},hsv:function(e,t,n){return He.hsva(e,t,n,1)},hsva:function(e,t,n,i){var r,a;e=et(e)%360/360*360,t=et(t),n=et(n),i=et(i);var s=[n,n*(1-t),n*(1-(a=e/60-(r=Math.floor(e/60%6)))*t),n*(1-(1-a)*t)],o=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return He.rgba(255*s[o[r][0]],255*s[o[r][1]],255*s[o[r][2]],i)},hue:function(e){return new ie(Ye(e).h)},saturation:function(e){return new ie(100*Ye(e).s,"%")},lightness:function(e){return new ie(100*Ye(e).l,"%")},hsvhue:function(e){return new ie(Xe(e).h)},hsvsaturation:function(e){return new ie(100*Xe(e).s,"%")},hsvvalue:function(e){return new ie(100*Xe(e).v,"%")},red:function(e){return new ie(e.rgb[0])},green:function(e){return new ie(e.rgb[1])},blue:function(e){return new ie(e.rgb[2])},alpha:function(e){return new ie(Ye(e).a)},luma:function(e){return new ie(e.luma()*e.alpha*100,"%")},luminance:function(e){var t=.2126*e.rgb[0]/255+.7152*e.rgb[1]/255+.0722*e.rgb[2]/255;return new ie(t*e.alpha*100,"%")},saturate:function(e,t,n){if(!e.rgb)return null;var i=Ye(e);return void 0!==n&&"relative"===n.value?i.s+=i.s*t.value/100:i.s+=t.value/100,i.s=Ke(i.s),Ze(e,i)},desaturate:function(e,t,n){var i=Ye(e);return void 0!==n&&"relative"===n.value?i.s-=i.s*t.value/100:i.s-=t.value/100,i.s=Ke(i.s),Ze(e,i)},lighten:function(e,t,n){var i=Ye(e);return void 0!==n&&"relative"===n.value?i.l+=i.l*t.value/100:i.l+=t.value/100,i.l=Ke(i.l),Ze(e,i)},darken:function(e,t,n){var i=Ye(e);return void 0!==n&&"relative"===n.value?i.l-=i.l*t.value/100:i.l-=t.value/100,i.l=Ke(i.l),Ze(e,i)},fadein:function(e,t,n){var i=Ye(e);return void 0!==n&&"relative"===n.value?i.a+=i.a*t.value/100:i.a+=t.value/100,i.a=Ke(i.a),Ze(e,i)},fadeout:function(e,t,n){var i=Ye(e);return void 0!==n&&"relative"===n.value?i.a-=i.a*t.value/100:i.a-=t.value/100,i.a=Ke(i.a),Ze(e,i)},fade:function(e,t){var n=Ye(e);return n.a=t.value/100,n.a=Ke(n.a),Ze(e,n)},spin:function(e,t){var n=Ye(e),i=(n.h+t.value)%360;return n.h=i<0?360+i:i,Ze(e,n)},mix:function(e,t,n){n||(n=new ie(50));var i=n.value/100,r=2*i-1,a=Ye(e).a-Ye(t).a,s=((r*a==-1?r:(r+a)/(1+r*a))+1)/2,o=1-s,l=[e.rgb[0]*s+t.rgb[0]*o,e.rgb[1]*s+t.rgb[1]*o,e.rgb[2]*s+t.rgb[2]*o],u=e.alpha*i+t.alpha*(1-i);return new y(l,u)},greyscale:function(e){return He.desaturate(e,new ie(100))},contrast:function(e,t,n,i){if(!e.rgb)return null;if(void 0===n&&(n=He.rgba(255,255,255,1)),void 0===t&&(t=He.rgba(0,0,0,1)),t.luma()>n.luma()){var r=n;n=t,t=r}return i=void 0===i?.43:et(i),e.luma().5&&(i=1,n=e>.25?Math.sqrt(e):((16*e-12)*e+4)*e),e-(1-2*t)*i*(n-e)},hardlight:function(e,t){return it.overlay(t,e)},difference:function(e,t){return Math.abs(e-t)},exclusion:function(e,t){return e+t-2*e*t},average:function(e,t){return(e+t)/2},negation:function(e,t){return 1-Math.abs(e+t-1)}};for(var rt in it)it.hasOwnProperty(rt)&&(nt[rt]=nt.bind(null,it[rt]));var at=function(e){return Array.isArray(e.value)?e.value:Array(e)},st={_SELF:function(e){return e},extract:function(e,t){return t=t.value-1,at(e)[t]},length:function(e){return new ie(at(e).length)},range:function(e,t,n){var i,r,a=1,s=[];t?(r=t,i=e.value,n&&(a=n.value)):(i=1,r=e);for(var o=i;o<=r.value;o+=a)s.push(new ie(o,r.unit));return new oe(s)},each:function(e,t){var n,i,r=[];i=!e.value||e instanceof pe?e.ruleset?e.ruleset.rules:e.rules?e.rules:Array.isArray(e)?e:[e]:Array.isArray(e.value)?e.value:[e.value];var a="@value",s="@key",o="@index";t.params?(a=t.params[0]&&t.params[0].name,s=t.params[1]&&t.params[1].name,o=t.params[2]&&t.params[2].name,t=t.rules):t=t.ruleset;for(var l=0;ls.value)&&(c[i]=r);else{if(void 0!==l&&o!==l)throw{type:"Argument",message:"incompatible types"};h[o]=c.length,c.push(r)}else Array.isArray(t[n].value)&&Array.prototype.push.apply(t,Array.prototype.slice.call(t[n].value));return 1==c.length?c[0]:(t=c.map(function(e){return e.toCSS(this.context)}).join(this.context.compress?",":", "),new B("".concat(e?"min":"max","(").concat(t,")")))},ft={min:function(){for(var e=arguments.length,t=new Array(e),n=0;n"),r=0;r");return i+="'),i=encodeURIComponent(i),i="data:image/svg+xml,".concat(i),new ve(new pe("'".concat(i,"'"),i,!1,this.index,this.currentFileInfo),this.index,this.currentFileInfo)}}),Z.addMultiple(mt),t},yt=function(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=n.variables,a=new G.Eval(n);"object"!==i(r)||Array.isArray(r)||(r=Object.keys(r).map(function(e){var t=r[e];return t instanceof Me.Value||(t instanceof Me.Expression||(t=new Me.Expression([t])),t=new Me.Value([t])),new Me.Declaration("@".concat(e),t,!1,null,0)}),a.frames=[new Me.Ruleset(null,r)]);var s,o,l=[new Ge.JoinSelectorVisitor,new Ge.MarkVisibleSelectorsVisitor(!0),new Ge.ExtendVisitor,new Ge.ToCSSVisitor({compress:Boolean(n.compress)})],u=[];if(n.pluginManager){o=n.pluginManager.visitor();for(var c=0;c<2;c++)for(o.first();s=o.get();)s.isPreEvalVisitor?0!==c&&-1!==u.indexOf(s)||(u.push(s),s.run(e)):0!==c&&-1!==l.indexOf(s)||(s.isPreVisitor?l.unshift(s):l.push(s))}t=e.eval(a);for(c=0;c=t);n++);this.preProcessors.splice(n,0,{preProcessor:e,priority:t})}},{key:"addPostProcessor",value:function(e,t){var n;for(n=0;n=t);n++);this.postProcessors.splice(n,0,{postProcessor:e,priority:t})}},{key:"addFileManager",value:function(e){this.fileManagers.push(e)}},{key:"getPreProcessors",value:function(){for(var e=[],t=0;t0){var i,r=JSON.stringify(this._sourceMapGenerator.toJSON());this.sourceMapURL?i=this.sourceMapURL:this._sourceMapFilename&&(i=this._sourceMapFilename),this.sourceMapURL=i,this.sourceMap=r}return this._css.join("")}}]),t}()}(e=new Ee(e,t)),a=function(e,t){return function(){function n(e){r(this,n),this.options=e}return s(n,[{key:"toCSS",value:function(t,n,i){var r=new e({contentsIgnoredCharsMap:i.contentsIgnoredChars,rootNode:t,contentsMap:i.contents,sourceMapFilename:this.options.sourceMapFilename,sourceMapURL:this.options.sourceMapURL,outputFilename:this.options.sourceMapOutputFilename,sourceMapBasepath:this.options.sourceMapBasepath,sourceMapRootpath:this.options.sourceMapRootpath,outputSourceFiles:this.options.outputSourceFiles,sourceMapGenerator:this.options.sourceMapGenerator,sourceMapFileInline:this.options.sourceMapFileInline}),a=r.toCSS(n);return this.sourceMap=r.sourceMap,this.sourceMapURL=r.sourceMapURL,this.options.sourceMapInputFilename&&(this.sourceMapInputFilename=r.normalizeFilename(this.options.sourceMapInputFilename)),void 0!==this.options.sourceMapBasepath&&void 0!==this.sourceMapURL&&(this.sourceMapURL=r.removeBasepath(this.sourceMapURL)),a+this.getCSSAppendage()}},{key:"getCSSAppendage",value:function(){var e=this.sourceMapURL;if(this.options.sourceMapFileInline){if(void 0===this.sourceMap)return"";e="data:application/json;base64,".concat(t.encodeBase64(this.sourceMap))}return e?"/*# sourceMappingURL=".concat(e," */"):""}},{key:"getExternalSourceMap",value:function(){return this.sourceMap}},{key:"setExternalSourceMap",value:function(e){this.sourceMap=e}},{key:"isInline",value:function(){return this.options.sourceMapFileInline}},{key:"getSourceMapURL",value:function(){return this.sourceMapURL}},{key:"getOutputFilename",value:function(){return this.options.sourceMapOutputFilename}},{key:"getInputFilename",value:function(){return this.sourceMapInputFilename}}]),n}()}(i,e),o=function(e){return function(){function t(e,n){r(this,t),this.root=e,this.imports=n}return s(t,[{key:"toCSS",value:function(t){var n,i,r={};try{n=yt(this.root,t)}catch(e){throw new $(e,this.imports)}try{var a=Boolean(t.compress);a&&Pe.warn("The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.");var s={compress:a,dumpLineNumbers:t.dumpLineNumbers,strictUnits:Boolean(t.strictUnits),numPrecision:8};t.sourceMap?(i=new e(t.sourceMap),r.css=i.toCSS(n,s,this.imports)):r.css=n.toCSS(s)}catch(e){throw new $(e,this.imports)}if(t.pluginManager)for(var o=t.pluginManager.getPostProcessors(),l=0;l=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):"function"==typeof i&&i(t.status,e)}"function"==typeof r.overrideMimeType&&r.overrideMimeType("text/css"),xt.debug("XHR: Getting '".concat(e,"'")),r.open("GET",e,a),r.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),r.send(null),kt.isFileProtocol&&!kt.fileAsync?0===r.status||r.status>=200&&r.status<300?n(r.responseText):i(r.status,e):a?r.onreadystatechange=function(){4==r.readyState&&s(r,n,i)}:s(r,n,i)}},{key:"supports",value:function(){return!0}},{key:"clearFileCache",value:function(){It={}}},{key:"loadFile",value:function(e,t,n,i){t&&!this.isPathAbsolute(e)&&(e=t+e),e=n.ext?this.tryAppendExtension(e,n.ext):e,n=n||{};var r=this.extractUrlParts(e,window.location.href).url,a=this;return new Promise(function(e,t){if(n.useFileCache&&It[r])try{var i=It[r];return e({contents:i,filename:r,webInfo:{lastModified:new Date}})}catch(e){return t({filename:r,message:"Error loading file ".concat(r," error was ").concat(e.message)})}a.doXHR(r,n.mime,function(t,n){It[r]=t,e({contents:t,filename:r,webInfo:{lastModified:n}})},function(e,n){t({type:"File",message:"'".concat(n,"' wasn't found (").concat(e,")"),href:r})})})}}]),t}(),_t=function(e,t){return kt=e,xt=t,Ct},At=function(e){function t(e){var n;return r(this,t),(n=f(this,l(t).call(this))).less=e,n}return o(t,Oe),s(t,[{key:"loadPlugin",value:function(e,t,n,i,r){return new Promise(function(a,s){r.loadFile(e,t,n,i).then(a).catch(s)})}}]),t}(),Mt=function(t,i,r){return{add:function(a,s){r.errorReporting&&"html"!==r.errorReporting?"console"===r.errorReporting?function(e,t){var n=e.filename||t,a=[],s="".concat(e.type||"Syntax","Error: ").concat(e.message||"There is an error in your .less file"," in ").concat(n),o=function(e,t,n){void 0!==e.extract[t]&&a.push("{line} {content}".replace(/\{line\}/,(parseInt(e.line,10)||0)+(t-1)).replace(/\{class\}/,n).replace(/\{content\}/,e.extract[t]))};e.line&&(o(e,0,""),o(e,1,"line"),o(e,2,""),s+=" on line ".concat(e.line,", column ").concat(e.column+1,":\n").concat(a.join("\n"))),e.stack&&(e.extract||r.logLevel>=4)&&(s+="\nStack Trace\n".concat(e.stack)),i.logger.error(s)}(a,s):"function"==typeof r.errorReporting&&r.errorReporting("add",a,s):function(i,a){var s,o,l="less-error-message:".concat(e(a||"")),u=t.document.createElement("div"),c=[],h=i.filename||a,f=h.match(/([^\/]+(\?.*)?)$/)[1];u.id=l,u.className="less-error-message",o="

    ".concat(i.type||"Syntax","Error: ").concat(i.message||"There is an error in your .less file")+'

    in ').concat(f," ");var p=function(e,t,n){void 0!==e.extract[t]&&c.push('

  • {content}
  • '.replace(/\{line\}/,(parseInt(e.line,10)||0)+(t-1)).replace(/\{class\}/,n).replace(/\{content\}/,e.extract[t]))};i.line&&(p(i,0,""),p(i,1,"line"),p(i,2,""),o+="on line ".concat(i.line,", column ").concat(i.column+1,":

      ").concat(c.join(""),"
    ")),i.stack&&(i.extract||r.logLevel>=4)&&(o+="
    Stack Trace
    ".concat(i.stack.split("\n").slice(1).join("
    "))),u.innerHTML=o,n.createCSS(t.document,[".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),u.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),"development"===r.env&&(s=setInterval(function(){var e=t.document,n=e.body;n&&(e.getElementById(l)?n.replaceChild(u,e.getElementById(l)):n.insertBefore(u,n.firstChild),clearInterval(s))},10))}(a,s)},remove:function(n){r.errorReporting&&"html"!==r.errorReporting?"console"===r.errorReporting||"function"==typeof r.errorReporting&&r.errorReporting("remove",n):function(n){var i=t.document.getElementById("less-error-message:".concat(e(n)));i&&i.parentNode.removeChild(i)}(n)}}},Pt={javascriptEnabled:!1,depends:!1,compress:!1,lint:!1,paths:[],color:!0,strictImports:!1,insecure:!1,rootpath:"",rewriteUrls:!1,math:0,strictUnits:!1,globalVars:null,modifyVars:null,urlArgs:""};if(window.less)for(var Et in window.less)window.less.hasOwnProperty(Et)&&(Pt[Et]=window.less[Et]);!function(e,i){t(i,n.currentScript(e)),void 0===i.isFileProtocol&&(i.isFileProtocol=/^(file|(chrome|safari)(-extension)?|resource|qrc|app):/.test(e.location.protocol)),i.async=i.async||!1,i.fileAsync=i.fileAsync||!1,i.poll=i.poll||(i.isFileProtocol?1e3:1500),i.env=i.env||("127.0.0.1"==e.location.hostname||"0.0.0.0"==e.location.hostname||"localhost"==e.location.hostname||e.location.port&&e.location.port.length>0||i.isFileProtocol?"development":"production");var r=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(e.location.hash);r&&(i.dumpLineNumbers=r[1]),void 0===i.useFileCache&&(i.useFileCache=!0),void 0===i.onReady&&(i.onReady=!0),i.relativeUrls&&(i.rewriteUrls="all")}(window,Pt),Pt.plugins=Pt.plugins||[],window.LESS_PLUGINS&&(Pt.plugins=Pt.plugins.concat(window.LESS_PLUGINS));var Rt,Ot,Ft,Vt=function(e,i){var r=e.document,a=St();a.options=i;var s=a.environment,o=_t(i,a.logger),l=new o;s.addFileManager(l),a.FileManager=o,a.PluginLoader=At,function(e,t){t.logLevel=void 0!==t.logLevel?t.logLevel:"development"===t.env?3:1,t.loggers||(t.loggers=[{debug:function(e){t.logLevel>=4&&console.log(e)},info:function(e){t.logLevel>=3&&console.log(e)},warn:function(e){t.logLevel>=2&&console.warn(e)},error:function(e){t.logLevel>=1&&console.error(e)}}]);for(var n=0;n 0 && styleNode.childNodes.length > 0 &&\n oldStyleNode.firstChild.nodeValue === styleNode.firstChild.nodeValue);\n }\n\n const head = document.getElementsByTagName('head')[0];\n\n // If there is no oldStyleNode, just append; otherwise, only append if we need\n // to replace oldStyleNode with an updated stylesheet\n if (oldStyleNode === null || keepOldStyleNode === false) {\n const nextEl = sheet && sheet.nextSibling || null;\n if (nextEl) {\n nextEl.parentNode.insertBefore(styleNode, nextEl);\n } else {\n head.appendChild(styleNode);\n }\n }\n if (oldStyleNode && keepOldStyleNode === false) {\n oldStyleNode.parentNode.removeChild(oldStyleNode);\n }\n\n // For IE.\n // This needs to happen *after* the style element is added to the DOM, otherwise IE 7 and 8 may crash.\n // See http://social.msdn.microsoft.com/Forums/en-US/7e081b65-878a-4c22-8e68-c10d39c2ed32/internet-explorer-crashes-appending-style-element-to-head\n if (styleNode.styleSheet) {\n try {\n styleNode.styleSheet.cssText = styles;\n } catch (e) {\n throw new Error('Couldn\\'t reassign styleSheet.cssText.');\n }\n }\n },\n currentScript: function(window) {\n const document = window.document;\n return document.currentScript || (() => {\n const scripts = document.getElementsByTagName('script');\n return scripts[scripts.length - 1];\n })();\n }\n};\n","export default {\n 'aliceblue':'#f0f8ff',\n 'antiquewhite':'#faebd7',\n 'aqua':'#00ffff',\n 'aquamarine':'#7fffd4',\n 'azure':'#f0ffff',\n 'beige':'#f5f5dc',\n 'bisque':'#ffe4c4',\n 'black':'#000000',\n 'blanchedalmond':'#ffebcd',\n 'blue':'#0000ff',\n 'blueviolet':'#8a2be2',\n 'brown':'#a52a2a',\n 'burlywood':'#deb887',\n 'cadetblue':'#5f9ea0',\n 'chartreuse':'#7fff00',\n 'chocolate':'#d2691e',\n 'coral':'#ff7f50',\n 'cornflowerblue':'#6495ed',\n 'cornsilk':'#fff8dc',\n 'crimson':'#dc143c',\n 'cyan':'#00ffff',\n 'darkblue':'#00008b',\n 'darkcyan':'#008b8b',\n 'darkgoldenrod':'#b8860b',\n 'darkgray':'#a9a9a9',\n 'darkgrey':'#a9a9a9',\n 'darkgreen':'#006400',\n 'darkkhaki':'#bdb76b',\n 'darkmagenta':'#8b008b',\n 'darkolivegreen':'#556b2f',\n 'darkorange':'#ff8c00',\n 'darkorchid':'#9932cc',\n 'darkred':'#8b0000',\n 'darksalmon':'#e9967a',\n 'darkseagreen':'#8fbc8f',\n 'darkslateblue':'#483d8b',\n 'darkslategray':'#2f4f4f',\n 'darkslategrey':'#2f4f4f',\n 'darkturquoise':'#00ced1',\n 'darkviolet':'#9400d3',\n 'deeppink':'#ff1493',\n 'deepskyblue':'#00bfff',\n 'dimgray':'#696969',\n 'dimgrey':'#696969',\n 'dodgerblue':'#1e90ff',\n 'firebrick':'#b22222',\n 'floralwhite':'#fffaf0',\n 'forestgreen':'#228b22',\n 'fuchsia':'#ff00ff',\n 'gainsboro':'#dcdcdc',\n 'ghostwhite':'#f8f8ff',\n 'gold':'#ffd700',\n 'goldenrod':'#daa520',\n 'gray':'#808080',\n 'grey':'#808080',\n 'green':'#008000',\n 'greenyellow':'#adff2f',\n 'honeydew':'#f0fff0',\n 'hotpink':'#ff69b4',\n 'indianred':'#cd5c5c',\n 'indigo':'#4b0082',\n 'ivory':'#fffff0',\n 'khaki':'#f0e68c',\n 'lavender':'#e6e6fa',\n 'lavenderblush':'#fff0f5',\n 'lawngreen':'#7cfc00',\n 'lemonchiffon':'#fffacd',\n 'lightblue':'#add8e6',\n 'lightcoral':'#f08080',\n 'lightcyan':'#e0ffff',\n 'lightgoldenrodyellow':'#fafad2',\n 'lightgray':'#d3d3d3',\n 'lightgrey':'#d3d3d3',\n 'lightgreen':'#90ee90',\n 'lightpink':'#ffb6c1',\n 'lightsalmon':'#ffa07a',\n 'lightseagreen':'#20b2aa',\n 'lightskyblue':'#87cefa',\n 'lightslategray':'#778899',\n 'lightslategrey':'#778899',\n 'lightsteelblue':'#b0c4de',\n 'lightyellow':'#ffffe0',\n 'lime':'#00ff00',\n 'limegreen':'#32cd32',\n 'linen':'#faf0e6',\n 'magenta':'#ff00ff',\n 'maroon':'#800000',\n 'mediumaquamarine':'#66cdaa',\n 'mediumblue':'#0000cd',\n 'mediumorchid':'#ba55d3',\n 'mediumpurple':'#9370d8',\n 'mediumseagreen':'#3cb371',\n 'mediumslateblue':'#7b68ee',\n 'mediumspringgreen':'#00fa9a',\n 'mediumturquoise':'#48d1cc',\n 'mediumvioletred':'#c71585',\n 'midnightblue':'#191970',\n 'mintcream':'#f5fffa',\n 'mistyrose':'#ffe4e1',\n 'moccasin':'#ffe4b5',\n 'navajowhite':'#ffdead',\n 'navy':'#000080',\n 'oldlace':'#fdf5e6',\n 'olive':'#808000',\n 'olivedrab':'#6b8e23',\n 'orange':'#ffa500',\n 'orangered':'#ff4500',\n 'orchid':'#da70d6',\n 'palegoldenrod':'#eee8aa',\n 'palegreen':'#98fb98',\n 'paleturquoise':'#afeeee',\n 'palevioletred':'#d87093',\n 'papayawhip':'#ffefd5',\n 'peachpuff':'#ffdab9',\n 'peru':'#cd853f',\n 'pink':'#ffc0cb',\n 'plum':'#dda0dd',\n 'powderblue':'#b0e0e6',\n 'purple':'#800080',\n 'rebeccapurple':'#663399',\n 'red':'#ff0000',\n 'rosybrown':'#bc8f8f',\n 'royalblue':'#4169e1',\n 'saddlebrown':'#8b4513',\n 'salmon':'#fa8072',\n 'sandybrown':'#f4a460',\n 'seagreen':'#2e8b57',\n 'seashell':'#fff5ee',\n 'sienna':'#a0522d',\n 'silver':'#c0c0c0',\n 'skyblue':'#87ceeb',\n 'slateblue':'#6a5acd',\n 'slategray':'#708090',\n 'slategrey':'#708090',\n 'snow':'#fffafa',\n 'springgreen':'#00ff7f',\n 'steelblue':'#4682b4',\n 'tan':'#d2b48c',\n 'teal':'#008080',\n 'thistle':'#d8bfd8',\n 'tomato':'#ff6347',\n 'turquoise':'#40e0d0',\n 'violet':'#ee82ee',\n 'wheat':'#f5deb3',\n 'white':'#ffffff',\n 'whitesmoke':'#f5f5f5',\n 'yellow':'#ffff00',\n 'yellowgreen':'#9acd32'\n};","export default {\n length: {\n 'm': 1,\n 'cm': 0.01,\n 'mm': 0.001,\n 'in': 0.0254,\n 'px': 0.0254 / 96,\n 'pt': 0.0254 / 72,\n 'pc': 0.0254 / 72 * 12\n },\n duration: {\n 's': 1,\n 'ms': 0.001\n },\n angle: {\n 'rad': 1 / (2 * Math.PI),\n 'deg': 1 / 360,\n 'grad': 1 / 400,\n 'turn': 1\n }\n};","import colors from './colors';\nimport unitConversions from './unit-conversions';\n\nexport default { colors, unitConversions };\n","class Node {\n constructor() {\n this.parent = null;\n this.visibilityBlocks = undefined;\n this.nodeVisible = undefined;\n this.rootNode = null;\n this.parsed = null;\n\n const self = this;\n Object.defineProperty(this, 'currentFileInfo', {\n get: function() { return self.fileInfo(); }\n });\n Object.defineProperty(this, 'index', {\n get: function() { return self.getIndex(); }\n });\n\n }\n\n setParent(nodes, parent) {\n function set(node) {\n if (node && node instanceof Node) {\n node.parent = parent;\n }\n }\n if (Array.isArray(nodes)) {\n nodes.forEach(set);\n }\n else {\n set(nodes);\n }\n }\n\n getIndex() {\n return this._index || (this.parent && this.parent.getIndex()) || 0;\n }\n\n fileInfo() {\n return this._fileInfo || (this.parent && this.parent.fileInfo()) || {};\n }\n\n isRulesetLike() {\n return false;\n }\n\n toCSS(context) {\n const strs = [];\n this.genCSS(context, {\n add: function(chunk, fileInfo, index) {\n strs.push(chunk);\n },\n isEmpty: function () {\n return strs.length === 0;\n }\n });\n return strs.join('');\n }\n\n genCSS(context, output) {\n output.add(this.value);\n }\n\n accept(visitor) {\n this.value = visitor.visit(this.value);\n }\n\n eval() { return this; }\n\n _operate(context, op, a, b) {\n switch (op) {\n case '+': return a + b;\n case '-': return a - b;\n case '*': return a * b;\n case '/': return a / b;\n }\n }\n\n fround(context, value) {\n const precision = context && context.numPrecision;\n // add \"epsilon\" to ensure numbers like 1.000000005 (represented as 1.000000004999...) are properly rounded:\n return (precision) ? Number((value + 2e-16).toFixed(precision)) : value;\n }\n\n // Returns true if this node represents root of ast imported by reference\n blocksVisibility() {\n if (this.visibilityBlocks == null) {\n this.visibilityBlocks = 0;\n }\n return this.visibilityBlocks !== 0;\n }\n\n addVisibilityBlock() {\n if (this.visibilityBlocks == null) {\n this.visibilityBlocks = 0;\n }\n this.visibilityBlocks = this.visibilityBlocks + 1;\n }\n\n removeVisibilityBlock() {\n if (this.visibilityBlocks == null) {\n this.visibilityBlocks = 0;\n }\n this.visibilityBlocks = this.visibilityBlocks - 1;\n }\n\n // Turns on node visibility - if called node will be shown in output regardless\n // of whether it comes from import by reference or not\n ensureVisibility() {\n this.nodeVisible = true;\n }\n\n // Turns off node visibility - if called node will NOT be shown in output regardless\n // of whether it comes from import by reference or not\n ensureInvisibility() {\n this.nodeVisible = false;\n }\n\n // return values:\n // false - the node must not be visible\n // true - the node must be visible\n // undefined or null - the node has the same visibility as its parent\n isVisible() {\n return this.nodeVisible;\n }\n\n visibilityInfo() {\n return {\n visibilityBlocks: this.visibilityBlocks,\n nodeVisible: this.nodeVisible\n };\n }\n\n copyVisibilityInfo(info) {\n if (!info) {\n return;\n }\n this.visibilityBlocks = info.visibilityBlocks;\n this.nodeVisible = info.nodeVisible;\n }\n}\n\nNode.compare = (a, b) => {\n /* returns:\n -1: a < b\n 0: a = b\n 1: a > b\n and *any* other value for a != b (e.g. undefined, NaN, -2 etc.) */\n\n if ((a.compare) &&\n // for \"symmetric results\" force toCSS-based comparison\n // of Quoted or Anonymous if either value is one of those\n !(b.type === 'Quoted' || b.type === 'Anonymous')) {\n return a.compare(b);\n } else if (b.compare) {\n return -b.compare(a);\n } else if (a.type !== b.type) {\n return undefined;\n }\n\n a = a.value;\n b = b.value;\n if (!Array.isArray(a)) {\n return a === b ? 0 : undefined;\n }\n if (a.length !== b.length) {\n return undefined;\n }\n for (let i = 0; i < a.length; i++) {\n if (Node.compare(a[i], b[i]) !== 0) {\n return undefined;\n }\n }\n return 0;\n};\n\nNode.numericCompare = (a, b) => a < b ? -1\n : a === b ? 0\n : a > b ? 1 : undefined;\nexport default Node;\n","import Node from './node';\nimport colors from '../data/colors';\n\n//\n// RGB Colors - #ff0014, #eee\n//\nclass Color extends Node {\n constructor(rgb, a, originalForm) {\n super();\n\n const self = this;\n //\n // The end goal here, is to parse the arguments\n // into an integer triplet, such as `128, 255, 0`\n //\n // This facilitates operations and conversions.\n //\n if (Array.isArray(rgb)) {\n this.rgb = rgb;\n } else if (rgb.length >= 6) {\n this.rgb = [];\n rgb.match(/.{2}/g).map((c, i) => {\n if (i < 3) {\n self.rgb.push(parseInt(c, 16));\n } else {\n self.alpha = (parseInt(c, 16)) / 255;\n }\n });\n } else {\n this.rgb = [];\n rgb.split('').map((c, i) => {\n if (i < 3) {\n self.rgb.push(parseInt(c + c, 16));\n } else {\n self.alpha = (parseInt(c + c, 16)) / 255;\n }\n });\n }\n this.alpha = this.alpha || (typeof a === 'number' ? a : 1);\n if (typeof originalForm !== 'undefined') {\n this.value = originalForm;\n }\n }\n\n luma() {\n let r = this.rgb[0] / 255;\n let g = this.rgb[1] / 255;\n let b = this.rgb[2] / 255;\n\n r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4);\n g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4);\n b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4);\n\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n }\n\n genCSS(context, output) {\n output.add(this.toCSS(context));\n }\n\n toCSS(context, doNotCompress) {\n const compress = context && context.compress && !doNotCompress;\n let color;\n let alpha;\n let colorFunction;\n let args = [];\n\n // `value` is set if this color was originally\n // converted from a named color string so we need\n // to respect this and try to output named color too.\n alpha = this.fround(context, this.alpha);\n\n if (this.value) {\n if (this.value.indexOf('rgb') === 0) {\n if (alpha < 1) {\n colorFunction = 'rgba';\n }\n } else if (this.value.indexOf('hsl') === 0) {\n if (alpha < 1) {\n colorFunction = 'hsla';\n } else {\n colorFunction = 'hsl';\n }\n } else {\n return this.value;\n }\n } else {\n if (alpha < 1) {\n colorFunction = 'rgba';\n }\n }\n\n switch (colorFunction) {\n case 'rgba':\n args = this.rgb.map(c => clamp(Math.round(c), 255)).concat(clamp(alpha, 1));\n break;\n case 'hsla':\n args.push(clamp(alpha, 1));\n case 'hsl':\n color = this.toHSL();\n args = [\n this.fround(context, color.h),\n `${this.fround(context, color.s * 100)}%`,\n `${this.fround(context, color.l * 100)}%`\n ].concat(args);\n }\n\n if (colorFunction) {\n // Values are capped between `0` and `255`, rounded and zero-padded.\n return `${colorFunction}(${args.join(`,${compress ? '' : ' '}`)})`;\n }\n\n color = this.toRGB();\n\n if (compress) {\n const splitcolor = color.split('');\n\n // Convert color to short format\n if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) {\n color = `#${splitcolor[1]}${splitcolor[3]}${splitcolor[5]}`;\n }\n }\n\n return color;\n }\n\n //\n // Operations have to be done per-channel, if not,\n // channels will spill onto each other. Once we have\n // our result, in the form of an integer triplet,\n // we create a new Color node to hold the result.\n //\n operate(context, op, other) {\n const rgb = new Array(3);\n const alpha = this.alpha * (1 - other.alpha) + other.alpha;\n for (let c = 0; c < 3; c++) {\n rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]);\n }\n return new Color(rgb, alpha);\n }\n\n toRGB() {\n return toHex(this.rgb);\n }\n\n toHSL() {\n const r = this.rgb[0] / 255;\n const g = this.rgb[1] / 255;\n const b = this.rgb[2] / 255;\n const a = this.alpha;\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n let h;\n let s;\n const l = (max + min) / 2;\n const d = max - min;\n\n if (max === min) {\n h = s = 0;\n } else {\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n\n switch (max) {\n case r: h = (g - b) / d + (g < b ? 6 : 0); break;\n case g: h = (b - r) / d + 2; break;\n case b: h = (r - g) / d + 4; break;\n }\n h /= 6;\n }\n return { h: h * 360, s, l, a };\n }\n\n // Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript\n toHSV() {\n const r = this.rgb[0] / 255;\n const g = this.rgb[1] / 255;\n const b = this.rgb[2] / 255;\n const a = this.alpha;\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n let h;\n let s;\n const v = max;\n\n const d = max - min;\n if (max === 0) {\n s = 0;\n } else {\n s = d / max;\n }\n\n if (max === min) {\n h = 0;\n } else {\n switch (max) {\n case r: h = (g - b) / d + (g < b ? 6 : 0); break;\n case g: h = (b - r) / d + 2; break;\n case b: h = (r - g) / d + 4; break;\n }\n h /= 6;\n }\n return { h: h * 360, s, v, a };\n }\n\n toARGB() {\n return toHex([this.alpha * 255].concat(this.rgb));\n }\n\n compare(x) {\n return (x.rgb &&\n x.rgb[0] === this.rgb[0] &&\n x.rgb[1] === this.rgb[1] &&\n x.rgb[2] === this.rgb[2] &&\n x.alpha === this.alpha) ? 0 : undefined;\n }\n}\n\nColor.prototype.type = 'Color';\n\nfunction clamp(v, max) {\n return Math.min(Math.max(v, 0), max);\n}\n\nfunction toHex(v) {\n return `#${v.map(c => {\n c = clamp(Math.round(c), 255);\n return (c < 16 ? '0' : '') + c.toString(16);\n }).join('')}`;\n}\n\nColor.fromKeyword = keyword => {\n let c;\n const key = keyword.toLowerCase();\n if (colors.hasOwnProperty(key)) {\n c = new Color(colors[key].slice(1));\n }\n else if (key === 'transparent') {\n c = new Color([0, 0, 0], 0);\n }\n\n if (c) {\n c.value = keyword;\n return c;\n }\n};\nexport default Color;\n","import Node from './node';\n\nclass Paren extends Node {\n constructor(node) {\n super();\n\n this.value = node;\n }\n\n genCSS(context, output) {\n output.add('(');\n this.value.genCSS(context, output);\n output.add(')');\n }\n\n eval(context) {\n return new Paren(this.value.eval(context));\n }\n}\n\nParen.prototype.type = 'Paren';\nexport default Paren;\n","import Node from './node';\nconst _noSpaceCombinators = {\n '': true,\n ' ': true,\n '|': true\n};\n\nclass Combinator extends Node {\n constructor(value) {\n super();\n\n if (value === ' ') {\n this.value = ' ';\n this.emptyOrWhitespace = true;\n } else {\n this.value = value ? value.trim() : '';\n this.emptyOrWhitespace = this.value === '';\n }\n }\n\n genCSS(context, output) {\n const spaceOrEmpty = (context.compress || _noSpaceCombinators[this.value]) ? '' : ' ';\n output.add(spaceOrEmpty + this.value + spaceOrEmpty);\n }\n}\n\nCombinator.prototype.type = 'Combinator';\n\nexport default Combinator;\n","import Node from './node';\nimport Paren from './paren';\nimport Combinator from './combinator';\n\nclass Element extends Node {\n constructor(combinator, value, isVariable, index, currentFileInfo, visibilityInfo) {\n super();\n\n this.combinator = combinator instanceof Combinator ?\n combinator : new Combinator(combinator);\n\n if (typeof value === 'string') {\n this.value = value.trim();\n } else if (value) {\n this.value = value;\n } else {\n this.value = '';\n }\n this.isVariable = isVariable;\n this._index = index;\n this._fileInfo = currentFileInfo;\n this.copyVisibilityInfo(visibilityInfo);\n this.setParent(this.combinator, this);\n }\n\n accept(visitor) {\n const value = this.value;\n this.combinator = visitor.visit(this.combinator);\n if (typeof value === 'object') {\n this.value = visitor.visit(value);\n }\n }\n\n eval(context) {\n return new Element(this.combinator,\n this.value.eval ? this.value.eval(context) : this.value,\n this.isVariable,\n this.getIndex(),\n this.fileInfo(), this.visibilityInfo());\n }\n\n clone() {\n return new Element(this.combinator,\n this.value,\n this.isVariable,\n this.getIndex(),\n this.fileInfo(), this.visibilityInfo());\n }\n\n genCSS(context, output) {\n output.add(this.toCSS(context), this.fileInfo(), this.getIndex());\n }\n\n toCSS(context = {}) {\n let value = this.value;\n const firstSelector = context.firstSelector;\n if (value instanceof Paren) {\n // selector in parens should not be affected by outer selector\n // flags (breaks only interpolated selectors - see #1973)\n context.firstSelector = true;\n }\n value = value.toCSS ? value.toCSS(context) : value;\n context.firstSelector = firstSelector;\n if (value === '' && this.combinator.value.charAt(0) === '&') {\n return '';\n } else {\n return this.combinator.toCSS(context) + value;\n }\n }\n}\n\nElement.prototype.type = 'Element';\nexport default Element;\n","\nexport const Math = {\n ALWAYS: 0,\n PARENS_DIVISION: 1,\n PARENS: 2,\n STRICT_LEGACY: 3\n};\n\nexport const RewriteUrls = {\n OFF: 0,\n LOCAL: 1,\n ALL: 2\n};","var clone = (function() {\n'use strict';\n\nfunction _instanceof(obj, type) {\n return type != null && obj instanceof type;\n}\n\nvar nativeMap;\ntry {\n nativeMap = Map;\n} catch(_) {\n // maybe a reference error because no `Map`. Give it a dummy value that no\n // value will ever be an instanceof.\n nativeMap = function() {};\n}\n\nvar nativeSet;\ntry {\n nativeSet = Set;\n} catch(_) {\n nativeSet = function() {};\n}\n\nvar nativePromise;\ntry {\n nativePromise = Promise;\n} catch(_) {\n nativePromise = function() {};\n}\n\n/**\n * Clones (copies) an Object using deep copying.\n *\n * This function supports circular references by default, but if you are certain\n * there are no circular references in your object, you can save some CPU time\n * by calling clone(obj, false).\n *\n * Caution: if `circular` is false and `parent` contains circular references,\n * your program may enter an infinite loop and crash.\n *\n * @param `parent` - the object to be cloned\n * @param `circular` - set to true if the object to be cloned may contain\n * circular references. (optional - true by default)\n * @param `depth` - set to a number if the object is only to be cloned to\n * a particular depth. (optional - defaults to Infinity)\n * @param `prototype` - sets the prototype to be used when cloning an object.\n * (optional - defaults to parent prototype).\n * @param `includeNonEnumerable` - set to true if the non-enumerable properties\n * should be cloned as well. Non-enumerable properties on the prototype\n * chain will be ignored. (optional - false by default)\n*/\nfunction clone(parent, circular, depth, prototype, includeNonEnumerable) {\n if (typeof circular === 'object') {\n depth = circular.depth;\n prototype = circular.prototype;\n includeNonEnumerable = circular.includeNonEnumerable;\n circular = circular.circular;\n }\n // maintain two arrays for circular references, where corresponding parents\n // and children have the same index\n var allParents = [];\n var allChildren = [];\n\n var useBuffer = typeof Buffer != 'undefined';\n\n if (typeof circular == 'undefined')\n circular = true;\n\n if (typeof depth == 'undefined')\n depth = Infinity;\n\n // recurse this function so we don't reset allParents and allChildren\n function _clone(parent, depth) {\n // cloning null always returns null\n if (parent === null)\n return null;\n\n if (depth === 0)\n return parent;\n\n var child;\n var proto;\n if (typeof parent != 'object') {\n return parent;\n }\n\n if (_instanceof(parent, nativeMap)) {\n child = new nativeMap();\n } else if (_instanceof(parent, nativeSet)) {\n child = new nativeSet();\n } else if (_instanceof(parent, nativePromise)) {\n child = new nativePromise(function (resolve, reject) {\n parent.then(function(value) {\n resolve(_clone(value, depth - 1));\n }, function(err) {\n reject(_clone(err, depth - 1));\n });\n });\n } else if (clone.__isArray(parent)) {\n child = [];\n } else if (clone.__isRegExp(parent)) {\n child = new RegExp(parent.source, __getRegExpFlags(parent));\n if (parent.lastIndex) child.lastIndex = parent.lastIndex;\n } else if (clone.__isDate(parent)) {\n child = new Date(parent.getTime());\n } else if (useBuffer && Buffer.isBuffer(parent)) {\n if (Buffer.allocUnsafe) {\n // Node.js >= 4.5.0\n child = Buffer.allocUnsafe(parent.length);\n } else {\n // Older Node.js versions\n child = new Buffer(parent.length);\n }\n parent.copy(child);\n return child;\n } else if (_instanceof(parent, Error)) {\n child = Object.create(parent);\n } else {\n if (typeof prototype == 'undefined') {\n proto = Object.getPrototypeOf(parent);\n child = Object.create(proto);\n }\n else {\n child = Object.create(prototype);\n proto = prototype;\n }\n }\n\n if (circular) {\n var index = allParents.indexOf(parent);\n\n if (index != -1) {\n return allChildren[index];\n }\n allParents.push(parent);\n allChildren.push(child);\n }\n\n if (_instanceof(parent, nativeMap)) {\n parent.forEach(function(value, key) {\n var keyChild = _clone(key, depth - 1);\n var valueChild = _clone(value, depth - 1);\n child.set(keyChild, valueChild);\n });\n }\n if (_instanceof(parent, nativeSet)) {\n parent.forEach(function(value) {\n var entryChild = _clone(value, depth - 1);\n child.add(entryChild);\n });\n }\n\n for (var i in parent) {\n var attrs;\n if (proto) {\n attrs = Object.getOwnPropertyDescriptor(proto, i);\n }\n\n if (attrs && attrs.set == null) {\n continue;\n }\n child[i] = _clone(parent[i], depth - 1);\n }\n\n if (Object.getOwnPropertySymbols) {\n var symbols = Object.getOwnPropertySymbols(parent);\n for (var i = 0; i < symbols.length; i++) {\n // Don't need to worry about cloning a symbol because it is a primitive,\n // like a number or string.\n var symbol = symbols[i];\n var descriptor = Object.getOwnPropertyDescriptor(parent, symbol);\n if (descriptor && !descriptor.enumerable && !includeNonEnumerable) {\n continue;\n }\n child[symbol] = _clone(parent[symbol], depth - 1);\n if (!descriptor.enumerable) {\n Object.defineProperty(child, symbol, {\n enumerable: false\n });\n }\n }\n }\n\n if (includeNonEnumerable) {\n var allPropertyNames = Object.getOwnPropertyNames(parent);\n for (var i = 0; i < allPropertyNames.length; i++) {\n var propertyName = allPropertyNames[i];\n var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName);\n if (descriptor && descriptor.enumerable) {\n continue;\n }\n child[propertyName] = _clone(parent[propertyName], depth - 1);\n Object.defineProperty(child, propertyName, {\n enumerable: false\n });\n }\n }\n\n return child;\n }\n\n return _clone(parent, depth);\n}\n\n/**\n * Simple flat clone using prototype, accepts only objects, usefull for property\n * override on FLAT configuration object (no nested props).\n *\n * USE WITH CAUTION! This may not behave as you wish if you do not know how this\n * works.\n */\nclone.clonePrototype = function clonePrototype(parent) {\n if (parent === null)\n return null;\n\n var c = function () {};\n c.prototype = parent;\n return new c();\n};\n\n// private utility functions\n\nfunction __objToStr(o) {\n return Object.prototype.toString.call(o);\n}\nclone.__objToStr = __objToStr;\n\nfunction __isDate(o) {\n return typeof o === 'object' && __objToStr(o) === '[object Date]';\n}\nclone.__isDate = __isDate;\n\nfunction __isArray(o) {\n return typeof o === 'object' && __objToStr(o) === '[object Array]';\n}\nclone.__isArray = __isArray;\n\nfunction __isRegExp(o) {\n return typeof o === 'object' && __objToStr(o) === '[object RegExp]';\n}\nclone.__isRegExp = __isRegExp;\n\nfunction __getRegExpFlags(re) {\n var flags = '';\n if (re.global) flags += 'g';\n if (re.ignoreCase) flags += 'i';\n if (re.multiline) flags += 'm';\n return flags;\n}\nclone.__getRegExpFlags = __getRegExpFlags;\n\nreturn clone;\n})();\n\nif (typeof module === 'object' && module.exports) {\n module.exports = clone;\n}\n","/* jshint proto: true */\nimport * as Constants from './constants';\nimport CloneHelper from 'clone';\n\nexport function getLocation(index, inputStream) {\n let n = index + 1;\n let line = null;\n let column = -1;\n\n while (--n >= 0 && inputStream.charAt(n) !== '\\n') {\n column++;\n }\n\n if (typeof index === 'number') {\n line = (inputStream.slice(0, index).match(/\\n/g) || '').length;\n }\n\n return {\n line,\n column\n };\n}\n\nexport function copyArray(arr) {\n let i;\n const length = arr.length;\n const copy = new Array(length);\n\n for (i = 0; i < length; i++) {\n copy[i] = arr[i];\n }\n return copy;\n}\n\nexport function clone(obj) {\n const cloned = {};\n for (const prop in obj) {\n if (obj.hasOwnProperty(prop)) {\n cloned[prop] = obj[prop];\n }\n }\n return cloned;\n}\n\nexport function defaults(obj1, obj2) {\n let newObj = obj2 || {};\n if (!obj2._defaults) {\n newObj = {};\n const defaults = CloneHelper(obj1);\n newObj._defaults = defaults;\n const cloned = obj2 ? CloneHelper(obj2) : {};\n Object.assign(newObj, defaults, cloned);\n }\n return newObj;\n}\n\nexport function copyOptions(obj1, obj2) {\n if (obj2 && obj2._defaults) {\n return obj2;\n }\n const opts = defaults(obj1, obj2);\n if (opts.strictMath) {\n opts.math = Constants.Math.STRICT_LEGACY;\n }\n // Back compat with changed relativeUrls option\n if (opts.relativeUrls) {\n opts.rewriteUrls = Constants.RewriteUrls.ALL;\n }\n if (typeof opts.math === 'string') {\n switch (opts.math.toLowerCase()) {\n case 'always':\n opts.math = Constants.Math.ALWAYS;\n break;\n case 'parens-division':\n opts.math = Constants.Math.PARENS_DIVISION;\n break;\n case 'strict':\n case 'parens':\n opts.math = Constants.Math.PARENS;\n break;\n case 'strict-legacy':\n opts.math = Constants.Math.STRICT_LEGACY;\n }\n }\n if (typeof opts.rewriteUrls === 'string') {\n switch (opts.rewriteUrls.toLowerCase()) {\n case 'off':\n opts.rewriteUrls = Constants.RewriteUrls.OFF;\n break;\n case 'local':\n opts.rewriteUrls = Constants.RewriteUrls.LOCAL;\n break;\n case 'all':\n opts.rewriteUrls = Constants.RewriteUrls.ALL;\n break;\n }\n }\n return opts;\n}\n\nexport function merge(obj1, obj2) {\n for (const prop in obj2) {\n if (obj2.hasOwnProperty(prop)) {\n obj1[prop] = obj2[prop];\n }\n }\n return obj1;\n}\n\nexport function flattenArray(arr, result = []) {\n for (let i = 0, length = arr.length; i < length; i++) {\n const value = arr[i];\n if (Array.isArray(value)) {\n flattenArray(value, result);\n } else {\n if (value !== undefined) {\n result.push(value);\n }\n }\n }\n return result;\n}","import * as utils from './utils';\n/**\n * This is a centralized class of any error that could be thrown internally (mostly by the parser).\n * Besides standard .message it keeps some additional data like a path to the file where the error\n * occurred along with line and column numbers.\n *\n * @class\n * @extends Error\n * @type {module.LessError}\n *\n * @prop {string} type\n * @prop {string} filename\n * @prop {number} index\n * @prop {number} line\n * @prop {number} column\n * @prop {number} callLine\n * @prop {number} callExtract\n * @prop {string[]} extract\n *\n * @param {Object} e - An error object to wrap around or just a descriptive object\n * @param {Object} fileContentMap - An object with file contents in 'contents' property (like importManager) @todo - move to fileManager?\n * @param {string} [currentFilename]\n */\nconst LessError = function LessError(e, fileContentMap, currentFilename) {\n Error.call(this);\n\n const filename = e.filename || currentFilename;\n\n this.message = e.message;\n this.stack = e.stack;\n\n if (fileContentMap && filename) {\n const input = fileContentMap.contents[filename];\n const loc = utils.getLocation(e.index, input);\n const line = loc.line;\n const col = loc.column;\n const callLine = e.call && utils.getLocation(e.call, input).line;\n const lines = input ? input.split('\\n') : '';\n\n this.type = e.type || 'Syntax';\n this.filename = filename;\n this.index = e.index;\n this.line = typeof line === 'number' ? line + 1 : null;\n this.column = col;\n\n if (!this.line && this.stack) {\n const found = this.stack.match(/(|Function):(\\d+):(\\d+)/);\n\n if (found) {\n if (found[2]) {\n this.line = parseInt(found[2]) - 2;\n }\n if (found[3]) {\n this.column = parseInt(found[3]);\n }\n }\n }\n\n this.callLine = callLine + 1;\n this.callExtract = lines[callLine];\n\n this.extract = [\n lines[this.line - 2],\n lines[this.line - 1],\n lines[this.line]\n ];\n }\n\n};\n\nif (typeof Object.create === 'undefined') {\n const F = () => {};\n F.prototype = Error.prototype;\n LessError.prototype = new F();\n} else {\n LessError.prototype = Object.create(Error.prototype);\n}\n\nLessError.prototype.constructor = LessError;\n\n/**\n * An overridden version of the default Object.prototype.toString\n * which uses additional information to create a helpful message.\n *\n * @param {Object} options\n * @returns {string}\n */\nLessError.prototype.toString = function(options = {}) {\n let message = '';\n const extract = this.extract || [];\n let error = [];\n let stylize = str => str;\n if (options.stylize) {\n const type = typeof options.stylize;\n if (type !== 'function') {\n throw Error(`options.stylize should be a function, got a ${type}!`);\n }\n stylize = options.stylize;\n }\n\n if (this.line !== null) {\n if (typeof extract[0] === 'string') {\n error.push(stylize(`${this.line - 1} ${extract[0]}`, 'grey'));\n }\n\n if (typeof extract[1] === 'string') {\n let errorTxt = `${this.line} `;\n if (extract[1]) {\n errorTxt += extract[1].slice(0, this.column) +\n stylize(stylize(stylize(extract[1].substr(this.column, 1), 'bold') +\n extract[1].slice(this.column + 1), 'red'), 'inverse');\n }\n error.push(errorTxt);\n }\n\n if (typeof extract[2] === 'string') {\n error.push(stylize(`${this.line + 1} ${extract[2]}`, 'grey'));\n }\n error = `${error.join('\\n') + stylize('', 'reset')}\\n`;\n }\n\n message += stylize(`${this.type}Error: ${this.message}`, 'red');\n if (this.filename) {\n message += stylize(' in ', 'red') + this.filename;\n }\n if (this.line) {\n message += stylize(` on line ${this.line}, column ${this.column + 1}:`, 'grey');\n }\n\n message += `\\n${error}`;\n\n if (this.callLine) {\n message += `${stylize('from ', 'red') + (this.filename || '')}/n`;\n message += `${stylize(this.callLine, 'grey')} ${this.callExtract}/n`;\n }\n\n return message;\n};\n\nexport default LessError;","import Node from './node';\nimport Element from './element';\nimport LessError from '../less-error';\n\nclass Selector extends Node {\n constructor(elements, extendList, condition, index, currentFileInfo, visibilityInfo) {\n super();\n\n this.extendList = extendList;\n this.condition = condition;\n this.evaldCondition = !condition;\n this._index = index;\n this._fileInfo = currentFileInfo;\n this.elements = this.getElements(elements);\n this.mixinElements_ = undefined;\n this.copyVisibilityInfo(visibilityInfo);\n this.setParent(this.elements, this);\n }\n\n accept(visitor) {\n if (this.elements) {\n this.elements = visitor.visitArray(this.elements);\n }\n if (this.extendList) {\n this.extendList = visitor.visitArray(this.extendList);\n }\n if (this.condition) {\n this.condition = visitor.visit(this.condition);\n }\n }\n\n createDerived(elements, extendList, evaldCondition) {\n elements = this.getElements(elements);\n const newSelector = new Selector(elements, extendList || this.extendList,\n null, this.getIndex(), this.fileInfo(), this.visibilityInfo());\n newSelector.evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition;\n newSelector.mediaEmpty = this.mediaEmpty;\n return newSelector;\n }\n\n getElements(els) {\n if (!els) {\n return [new Element('', '&', false, this._index, this._fileInfo)];\n }\n if (typeof els === 'string') {\n this.parse.parseNode(\n els, \n ['selector'],\n this._index, \n this._fileInfo, \n function(err, result) {\n if (err) {\n throw new LessError({\n index: err.index,\n message: err.message\n }, this.parse.imports, this._fileInfo.filename);\n }\n els = result[0].elements;\n });\n }\n return els;\n }\n\n createEmptySelectors() {\n const el = new Element('', '&', false, this._index, this._fileInfo);\n const sels = [new Selector([el], null, null, this._index, this._fileInfo)];\n sels[0].mediaEmpty = true;\n return sels;\n }\n\n match(other) {\n const elements = this.elements;\n const len = elements.length;\n let olen;\n let i;\n\n other = other.mixinElements();\n olen = other.length;\n if (olen === 0 || len < olen) {\n return 0;\n } else {\n for (i = 0; i < olen; i++) {\n if (elements[i].value !== other[i]) {\n return 0;\n }\n }\n }\n\n return olen; // return number of matched elements\n }\n\n mixinElements() {\n if (this.mixinElements_) {\n return this.mixinElements_;\n }\n\n let elements = this.elements.map( v => v.combinator.value + (v.value.value || v.value)).join('').match(/[,&#\\*\\.\\w-]([\\w-]|(\\\\.))*/g);\n\n if (elements) {\n if (elements[0] === '&') {\n elements.shift();\n }\n } else {\n elements = [];\n }\n\n return (this.mixinElements_ = elements);\n }\n\n isJustParentSelector() {\n return !this.mediaEmpty &&\n this.elements.length === 1 &&\n this.elements[0].value === '&' &&\n (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === '');\n }\n\n eval(context) {\n const evaldCondition = this.condition && this.condition.eval(context);\n let elements = this.elements;\n let extendList = this.extendList;\n\n elements = elements && elements.map(e => e.eval(context));\n extendList = extendList && extendList.map(extend => extend.eval(context));\n\n return this.createDerived(elements, extendList, evaldCondition);\n }\n\n genCSS(context, output) {\n let i;\n let element;\n if ((!context || !context.firstSelector) && this.elements[0].combinator.value === '') {\n output.add(' ', this.fileInfo(), this.getIndex());\n }\n for (i = 0; i < this.elements.length; i++) {\n element = this.elements[i];\n element.genCSS(context, output);\n }\n }\n\n getIsOutput() {\n return this.evaldCondition;\n }\n}\n\nSelector.prototype.type = 'Selector';\nexport default Selector;\n","import Node from './node';\n\nclass Value extends Node {\n constructor(value) {\n super();\n\n if (!value) {\n throw new Error('Value requires an array argument');\n }\n if (!Array.isArray(value)) {\n this.value = [ value ];\n }\n else {\n this.value = value;\n }\n }\n\n accept(visitor) {\n if (this.value) {\n this.value = visitor.visitArray(this.value);\n }\n }\n\n eval(context) {\n if (this.value.length === 1) {\n return this.value[0].eval(context);\n } else {\n return new Value(this.value.map(v => v.eval(context)));\n }\n }\n\n genCSS(context, output) {\n let i;\n for (i = 0; i < this.value.length; i++) {\n this.value[i].genCSS(context, output);\n if (i + 1 < this.value.length) {\n output.add((context && context.compress) ? ',' : ', ');\n }\n }\n }\n}\n\nValue.prototype.type = 'Value';\nexport default Value;\n","import Node from './node';\n\nclass Keyword extends Node {\n constructor(value) {\n super();\n\n this.value = value;\n }\n\n genCSS(context, output) {\n if (this.value === '%') { throw { type: 'Syntax', message: 'Invalid % without number' }; }\n output.add(this.value);\n }\n}\n\nKeyword.prototype.type = 'Keyword';\n\nKeyword.True = new Keyword('true');\nKeyword.False = new Keyword('false');\n\nexport default Keyword;\n","import Node from './node';\n\nclass Anonymous extends Node {\n constructor(value, index, currentFileInfo, mapLines, rulesetLike, visibilityInfo) {\n super();\n\n this.value = value;\n this._index = index;\n this._fileInfo = currentFileInfo;\n this.mapLines = mapLines;\n this.rulesetLike = (typeof rulesetLike === 'undefined') ? false : rulesetLike;\n this.allowRoot = true;\n this.copyVisibilityInfo(visibilityInfo);\n }\n\n eval() {\n return new Anonymous(this.value, this._index, this._fileInfo, this.mapLines, this.rulesetLike, this.visibilityInfo());\n }\n\n compare(other) {\n return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined;\n }\n\n isRulesetLike() {\n return this.rulesetLike;\n }\n\n genCSS(context, output) {\n this.nodeVisible = Boolean(this.value);\n if (this.nodeVisible) {\n output.add(this.value, this._fileInfo, this._index, this.mapLines);\n }\n }\n}\n\nAnonymous.prototype.type = 'Anonymous';\nexport default Anonymous;\n","import Node from './node';\nimport Value from './value';\nimport Keyword from './keyword';\nimport Anonymous from './anonymous';\nimport * as Constants from '../constants';\nconst MATH = Constants.Math;\n\n\nclass Declaration extends Node {\n constructor(name, value, important, merge, index, currentFileInfo, inline, variable) {\n super();\n\n this.name = name;\n this.value = (value instanceof Node) ? value : new Value([value ? new Anonymous(value) : null]);\n this.important = important ? ` ${important.trim()}` : '';\n this.merge = merge;\n this._index = index;\n this._fileInfo = currentFileInfo;\n this.inline = inline || false;\n this.variable = (variable !== undefined) ? variable\n : (name.charAt && (name.charAt(0) === '@'));\n this.allowRoot = true;\n this.setParent(this.value, this);\n }\n\n genCSS(context, output) {\n output.add(this.name + (context.compress ? ':' : ': '), this.fileInfo(), this.getIndex());\n try {\n this.value.genCSS(context, output);\n }\n catch (e) {\n e.index = this._index;\n e.filename = this._fileInfo.filename;\n throw e;\n }\n output.add(this.important + ((this.inline || (context.lastRule && context.compress)) ? '' : ';'), this._fileInfo, this._index);\n }\n\n eval(context) {\n let mathBypass = false;\n let prevMath;\n let name = this.name;\n let evaldValue;\n let variable = this.variable;\n if (typeof name !== 'string') {\n // expand 'primitive' name directly to get\n // things faster (~10% for benchmark.less):\n name = (name.length === 1) && (name[0] instanceof Keyword) ?\n name[0].value : evalName(context, name);\n variable = false; // never treat expanded interpolation as new variable name\n }\n\n // @todo remove when parens-division is default\n if (name === 'font' && context.math === MATH.ALWAYS) {\n mathBypass = true;\n prevMath = context.math;\n context.math = MATH.PARENS_DIVISION;\n }\n try {\n context.importantScope.push({});\n evaldValue = this.value.eval(context);\n\n if (!this.variable && evaldValue.type === 'DetachedRuleset') {\n throw { message: 'Rulesets cannot be evaluated on a property.',\n index: this.getIndex(), filename: this.fileInfo().filename };\n }\n let important = this.important;\n const importantResult = context.importantScope.pop();\n if (!important && importantResult.important) {\n important = importantResult.important;\n }\n\n return new Declaration(name,\n evaldValue,\n important,\n this.merge,\n this.getIndex(), this.fileInfo(), this.inline,\n variable);\n }\n catch (e) {\n if (typeof e.index !== 'number') {\n e.index = this.getIndex();\n e.filename = this.fileInfo().filename;\n }\n throw e;\n }\n finally {\n if (mathBypass) {\n context.math = prevMath;\n }\n }\n }\n\n makeImportant() {\n return new Declaration(this.name,\n this.value,\n '!important',\n this.merge,\n this.getIndex(), this.fileInfo(), this.inline);\n }\n}\n\nfunction evalName(context, name) {\n let value = '';\n let i;\n const n = name.length;\n const output = {add: function (s) {value += s;}};\n for (i = 0; i < n; i++) {\n name[i].eval(context).genCSS(context, output);\n }\n return value;\n}\n\nDeclaration.prototype.type = 'Declaration';\nexport default Declaration;","const debugInfo = (context, ctx, lineSeparator) => {\n let result = '';\n if (context.dumpLineNumbers && !context.compress) {\n switch (context.dumpLineNumbers) {\n case 'comments':\n result = debugInfo.asComment(ctx);\n break;\n case 'mediaquery':\n result = debugInfo.asMediaQuery(ctx);\n break;\n case 'all':\n result = debugInfo.asComment(ctx) + (lineSeparator || '') + debugInfo.asMediaQuery(ctx);\n break;\n }\n }\n return result;\n};\n\ndebugInfo.asComment = ctx => `/* line ${ctx.debugInfo.lineNumber}, ${ctx.debugInfo.fileName} */\\n`;\n\ndebugInfo.asMediaQuery = ctx => {\n let filenameWithProtocol = ctx.debugInfo.fileName;\n if (!/^[a-z]+:\\/\\//i.test(filenameWithProtocol)) {\n filenameWithProtocol = `file://${filenameWithProtocol}`;\n }\n return `@media -sass-debug-info{filename{font-family:${filenameWithProtocol.replace(/([.:\\/\\\\])/g, a => {\n if (a == '\\\\') {\n a = '\\/';\n }\n return `\\\\${a}`;\n })}}line{font-family:\\\\00003${ctx.debugInfo.lineNumber}}}\\n`;\n};\n\nexport default debugInfo;\n","import Node from './node';\nimport getDebugInfo from './debug-info';\n\nclass Comment extends Node {\n constructor(value, isLineComment, index, currentFileInfo) {\n super();\n\n this.value = value;\n this.isLineComment = isLineComment;\n this._index = index;\n this._fileInfo = currentFileInfo;\n this.allowRoot = true;\n }\n\n genCSS(context, output) {\n if (this.debugInfo) {\n output.add(getDebugInfo(context, this), this.fileInfo(), this.getIndex());\n }\n output.add(this.value);\n }\n\n isSilent(context) {\n const isCompressed = context.compress && this.value[2] !== '!';\n return this.isLineComment || isCompressed;\n }\n}\n\nComment.prototype.type = 'Comment';\nexport default Comment;\n","const contexts = {};\nexport default contexts;\nimport * as Constants from './constants';\n\nconst copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) {\n if (!original) { return; }\n\n for (let i = 0; i < propertiesToCopy.length; i++) {\n if (original.hasOwnProperty(propertiesToCopy[i])) {\n destination[propertiesToCopy[i]] = original[propertiesToCopy[i]];\n }\n }\n};\n\n/*\n parse is used whilst parsing\n */\nconst parseCopyProperties = [\n // options\n 'paths', // option - unmodified - paths to search for imports on\n 'rewriteUrls', // option - whether to adjust URL's to be relative\n 'rootpath', // option - rootpath to append to URL's\n 'strictImports', // option -\n 'insecure', // option - whether to allow imports from insecure ssl hosts\n 'dumpLineNumbers', // option - whether to dump line numbers\n 'compress', // option - whether to compress\n 'syncImport', // option - whether to import synchronously\n 'chunkInput', // option - whether to chunk input. more performant but causes parse issues.\n 'mime', // browser only - mime type for sheet import\n 'useFileCache', // browser only - whether to use the per file session cache\n // context\n 'processImports', // option & context - whether to process imports. if false then imports will not be imported.\n // Used by the import manager to stop multiple import visitors being created.\n 'pluginManager' // Used as the plugin manager for the session\n];\n\ncontexts.Parse = function(options) {\n copyFromOriginal(options, this, parseCopyProperties);\n\n if (typeof this.paths === 'string') { this.paths = [this.paths]; }\n};\n\nconst evalCopyProperties = [\n 'paths', // additional include paths\n 'compress', // whether to compress\n 'math', // whether math has to be within parenthesis\n 'strictUnits', // whether units need to evaluate correctly\n 'sourceMap', // whether to output a source map\n 'importMultiple', // whether we are currently importing multiple copies\n 'urlArgs', // whether to add args into url tokens\n 'javascriptEnabled', // option - whether Inline JavaScript is enabled. if undefined, defaults to false\n 'pluginManager', // Used as the plugin manager for the session\n 'importantScope', // used to bubble up !important statements\n 'rewriteUrls' // option - whether to adjust URL's to be relative\n];\n\nfunction isPathRelative(path) {\n return !/^(?:[a-z-]+:|\\/|#)/i.test(path);\n}\n\nfunction isPathLocalRelative(path) {\n return path.charAt(0) === '.';\n}\n\ncontexts.Eval = class {\n constructor(options, frames) {\n copyFromOriginal(options, this, evalCopyProperties);\n\n if (typeof this.paths === 'string') { this.paths = [this.paths]; }\n\n this.frames = frames || [];\n this.importantScope = this.importantScope || [];\n this.inCalc = false;\n this.mathOn = true;\n }\n\n enterCalc() {\n if (!this.calcStack) {\n this.calcStack = [];\n }\n this.calcStack.push(true);\n this.inCalc = true;\n }\n\n exitCalc() {\n this.calcStack.pop();\n if (!this.calcStack) {\n this.inCalc = false;\n }\n }\n\n inParenthesis() {\n if (!this.parensStack) {\n this.parensStack = [];\n }\n this.parensStack.push(true);\n };\n\n outOfParenthesis() {\n this.parensStack.pop();\n };\n\n isMathOn(op) {\n if (!this.mathOn) {\n return false;\n }\n if (op === '/' && this.math !== Constants.Math.ALWAYS && (!this.parensStack || !this.parensStack.length)) {\n return false;\n }\n if (this.math > Constants.Math.PARENS_DIVISION) {\n return this.parensStack && this.parensStack.length;\n }\n return true;\n }\n\n pathRequiresRewrite(path) {\n const isRelative = this.rewriteUrls === Constants.RewriteUrls.LOCAL ? isPathLocalRelative : isPathRelative;\n\n return isRelative(path);\n }\n\n rewritePath(path, rootpath) {\n let newPath;\n\n rootpath = rootpath || '';\n newPath = this.normalizePath(rootpath + path);\n\n // If a path was explicit relative and the rootpath was not an absolute path\n // we must ensure that the new path is also explicit relative.\n if (isPathLocalRelative(path) &&\n isPathRelative(rootpath) &&\n isPathLocalRelative(newPath) === false) {\n newPath = `./${newPath}`;\n }\n\n return newPath;\n }\n\n normalizePath(path) {\n const segments = path.split('/').reverse();\n let segment;\n\n path = [];\n while (segments.length !== 0) {\n segment = segments.pop();\n switch ( segment ) {\n case '.':\n break;\n case '..':\n if ((path.length === 0) || (path[path.length - 1] === '..')) {\n path.push( segment );\n } else {\n path.pop();\n }\n break;\n default:\n path.push(segment);\n break;\n }\n }\n\n return path.join('/');\n }\n}\n","function makeRegistry( base ) {\n return {\n _data: {},\n add: function(name, func) {\n // precautionary case conversion, as later querying of\n // the registry by function-caller uses lower case as well.\n name = name.toLowerCase();\n\n if (this._data.hasOwnProperty(name)) {\n // TODO warn\n }\n this._data[name] = func;\n },\n addMultiple: function(functions) {\n Object.keys(functions).forEach(\n name => {\n this.add(name, functions[name]);\n });\n },\n get: function(name) {\n return this._data[name] || ( base && base.get( name ));\n },\n getLocalFunctions: function() {\n return this._data;\n },\n inherit: function() {\n return makeRegistry( this );\n },\n create: function(base) {\n return makeRegistry(base);\n }\n };\n}\n\nexport default makeRegistry( null );","import Keyword from '../tree/keyword';\n\nconst defaultFunc = {\n eval: function () {\n const v = this.value_;\n const e = this.error_;\n if (e) {\n throw e;\n }\n if (v != null) {\n return v ? Keyword.True : Keyword.False;\n }\n },\n value: function (v) {\n this.value_ = v;\n },\n error: function (e) {\n this.error_ = e;\n },\n reset: function () {\n this.value_ = this.error_ = null;\n }\n};\n\nexport default defaultFunc;\n","import Node from './node';\nimport Declaration from './declaration';\nimport Keyword from './keyword';\nimport Comment from './comment';\nimport Paren from './paren';\nimport Selector from './selector';\nimport Element from './element';\nimport Anonymous from './anonymous';\nimport contexts from '../contexts';\nimport globalFunctionRegistry from '../functions/function-registry';\nimport defaultFunc from '../functions/default';\nimport getDebugInfo from './debug-info';\nimport * as utils from '../utils';\n\nclass Ruleset extends Node {\n constructor(selectors, rules, strictImports, visibilityInfo) {\n super();\n\n this.selectors = selectors;\n this.rules = rules;\n this._lookups = {};\n this._variables = null;\n this._properties = null;\n this.strictImports = strictImports;\n this.copyVisibilityInfo(visibilityInfo);\n this.allowRoot = true;\n\n this.setParent(this.selectors, this);\n this.setParent(this.rules, this);\n\n }\n\n isRulesetLike() {\n return true;\n }\n\n accept(visitor) {\n if (this.paths) {\n this.paths = visitor.visitArray(this.paths, true);\n } else if (this.selectors) {\n this.selectors = visitor.visitArray(this.selectors);\n }\n if (this.rules && this.rules.length) {\n this.rules = visitor.visitArray(this.rules);\n }\n }\n\n eval(context) {\n const that = this;\n let selectors;\n let selCnt;\n let selector;\n let i;\n let hasVariable;\n let hasOnePassingSelector = false;\n\n if (this.selectors && (selCnt = this.selectors.length)) {\n selectors = new Array(selCnt);\n defaultFunc.error({\n type: 'Syntax',\n message: 'it is currently only allowed in parametric mixin guards,'\n });\n\n for (i = 0; i < selCnt; i++) {\n selector = this.selectors[i].eval(context);\n for (var j = 0; j < selector.elements.length; j++) {\n if (selector.elements[j].isVariable) {\n hasVariable = true;\n break;\n }\n }\n selectors[i] = selector;\n if (selector.evaldCondition) {\n hasOnePassingSelector = true;\n }\n }\n\n if (hasVariable) {\n const toParseSelectors = new Array(selCnt);\n for (i = 0; i < selCnt; i++) {\n selector = selectors[i];\n toParseSelectors[i] = selector.toCSS(context);\n }\n this.parse.parseNode(\n toParseSelectors.join(','),\n [\"selectors\"], \n selectors[0].getIndex(), \n selectors[0].fileInfo(), \n (err, result) => {\n if (result) {\n selectors = utils.flattenArray(result);\n }\n });\n }\n\n defaultFunc.reset();\n } else {\n hasOnePassingSelector = true;\n }\n\n let rules = this.rules ? utils.copyArray(this.rules) : null;\n const ruleset = new Ruleset(selectors, rules, this.strictImports, this.visibilityInfo());\n let rule;\n let subRule;\n\n ruleset.originalRuleset = this;\n ruleset.root = this.root;\n ruleset.firstRoot = this.firstRoot;\n ruleset.allowImports = this.allowImports;\n\n if (this.debugInfo) {\n ruleset.debugInfo = this.debugInfo;\n }\n\n if (!hasOnePassingSelector) {\n rules.length = 0;\n }\n\n // inherit a function registry from the frames stack when possible;\n // otherwise from the global registry\n ruleset.functionRegistry = (frames => {\n let i = 0;\n const n = frames.length;\n let found;\n for ( ; i !== n ; ++i ) {\n found = frames[ i ].functionRegistry;\n if ( found ) { return found; }\n }\n return globalFunctionRegistry;\n })(context.frames).inherit();\n\n // push the current ruleset to the frames stack\n const ctxFrames = context.frames;\n ctxFrames.unshift(ruleset);\n\n // currrent selectors\n let ctxSelectors = context.selectors;\n if (!ctxSelectors) {\n context.selectors = ctxSelectors = [];\n }\n ctxSelectors.unshift(this.selectors);\n\n // Evaluate imports\n if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {\n ruleset.evalImports(context);\n }\n\n // Store the frames around mixin definitions,\n // so they can be evaluated like closures when the time comes.\n const rsRules = ruleset.rules;\n for (i = 0; (rule = rsRules[i]); i++) {\n if (rule.evalFirst) {\n rsRules[i] = rule.eval(context);\n }\n }\n\n const mediaBlockCount = (context.mediaBlocks && context.mediaBlocks.length) || 0;\n\n // Evaluate mixin calls.\n for (i = 0; (rule = rsRules[i]); i++) {\n if (rule.type === 'MixinCall') {\n /* jshint loopfunc:true */\n rules = rule.eval(context).filter(r => {\n if ((r instanceof Declaration) && r.variable) {\n // do not pollute the scope if the variable is\n // already there. consider returning false here\n // but we need a way to \"return\" variable from mixins\n return !(ruleset.variable(r.name));\n }\n return true;\n });\n rsRules.splice(...[i, 1].concat(rules));\n i += rules.length - 1;\n ruleset.resetCache();\n } else if (rule.type === 'VariableCall') {\n /* jshint loopfunc:true */\n rules = rule.eval(context).rules.filter(r => {\n if ((r instanceof Declaration) && r.variable) {\n // do not pollute the scope at all\n return false;\n }\n return true;\n });\n rsRules.splice(...[i, 1].concat(rules));\n i += rules.length - 1;\n ruleset.resetCache();\n }\n }\n\n // Evaluate everything else\n for (i = 0; (rule = rsRules[i]); i++) {\n if (!rule.evalFirst) {\n rsRules[i] = rule = rule.eval ? rule.eval(context) : rule;\n }\n }\n\n // Evaluate everything else\n for (i = 0; (rule = rsRules[i]); i++) {\n // for rulesets, check if it is a css guard and can be removed\n if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) {\n // check if it can be folded in (e.g. & where)\n if (rule.selectors[0] && rule.selectors[0].isJustParentSelector()) {\n rsRules.splice(i--, 1);\n\n for (var j = 0; (subRule = rule.rules[j]); j++) {\n if (subRule instanceof Node) {\n subRule.copyVisibilityInfo(rule.visibilityInfo());\n if (!(subRule instanceof Declaration) || !subRule.variable) {\n rsRules.splice(++i, 0, subRule);\n }\n }\n }\n }\n }\n }\n\n // Pop the stack\n ctxFrames.shift();\n ctxSelectors.shift();\n\n if (context.mediaBlocks) {\n for (i = mediaBlockCount; i < context.mediaBlocks.length; i++) {\n context.mediaBlocks[i].bubbleSelectors(selectors);\n }\n }\n\n return ruleset;\n }\n\n evalImports(context) {\n const rules = this.rules;\n let i;\n let importRules;\n if (!rules) { return; }\n\n for (i = 0; i < rules.length; i++) {\n if (rules[i].type === 'Import') {\n importRules = rules[i].eval(context);\n if (importRules && (importRules.length || importRules.length === 0)) {\n rules.splice(...[i, 1].concat(importRules));\n i += importRules.length - 1;\n } else {\n rules.splice(i, 1, importRules);\n }\n this.resetCache();\n }\n }\n }\n\n makeImportant() {\n const result = new Ruleset(this.selectors, this.rules.map(r => {\n if (r.makeImportant) {\n return r.makeImportant();\n } else {\n return r;\n }\n }), this.strictImports, this.visibilityInfo());\n\n return result;\n }\n\n matchArgs(args) {\n return !args || args.length === 0;\n }\n\n // lets you call a css selector with a guard\n matchCondition(args, context) {\n const lastSelector = this.selectors[this.selectors.length - 1];\n if (!lastSelector.evaldCondition) {\n return false;\n }\n if (lastSelector.condition &&\n !lastSelector.condition.eval(\n new contexts.Eval(context,\n context.frames))) {\n return false;\n }\n return true;\n }\n\n resetCache() {\n this._rulesets = null;\n this._variables = null;\n this._properties = null;\n this._lookups = {};\n }\n\n variables() {\n if (!this._variables) {\n this._variables = !this.rules ? {} : this.rules.reduce((hash, r) => {\n if (r instanceof Declaration && r.variable === true) {\n hash[r.name] = r;\n }\n // when evaluating variables in an import statement, imports have not been eval'd\n // so we need to go inside import statements.\n // guard against root being a string (in the case of inlined less)\n if (r.type === 'Import' && r.root && r.root.variables) {\n const vars = r.root.variables();\n for (const name in vars) {\n if (vars.hasOwnProperty(name)) {\n hash[name] = r.root.variable(name);\n }\n }\n }\n return hash;\n }, {});\n }\n return this._variables;\n }\n\n properties() {\n if (!this._properties) {\n this._properties = !this.rules ? {} : this.rules.reduce((hash, r) => {\n if (r instanceof Declaration && r.variable !== true) {\n const name = (r.name.length === 1) && (r.name[0] instanceof Keyword) ?\n r.name[0].value : r.name;\n // Properties don't overwrite as they can merge\n if (!hash[`$${name}`]) {\n hash[`$${name}`] = [ r ];\n }\n else {\n hash[`$${name}`].push(r);\n }\n }\n return hash;\n }, {});\n }\n return this._properties;\n }\n\n variable(name) {\n const decl = this.variables()[name];\n if (decl) {\n return this.parseValue(decl);\n }\n }\n\n property(name) {\n const decl = this.properties()[name];\n if (decl) {\n return this.parseValue(decl);\n }\n }\n\n lastDeclaration() {\n for (let i = this.rules.length; i > 0; i--) {\n const decl = this.rules[i - 1];\n if (decl instanceof Declaration) {\n return this.parseValue(decl);\n }\n }\n }\n\n parseValue(toParse) {\n const self = this;\n function transformDeclaration(decl) {\n if (decl.value instanceof Anonymous && !decl.parsed) {\n if (typeof decl.value.value === 'string') {\n this.parse.parseNode(\n decl.value.value,\n ['value', 'important'], \n decl.value.getIndex(), \n decl.fileInfo(), \n (err, result) => {\n if (err) {\n decl.parsed = true;\n }\n if (result) {\n decl.value = result[0];\n decl.important = result[1] || '';\n decl.parsed = true;\n }\n });\n } else {\n decl.parsed = true;\n }\n\n return decl;\n }\n else {\n return decl;\n }\n }\n if (!Array.isArray(toParse)) {\n return transformDeclaration.call(self, toParse);\n }\n else {\n const nodes = [];\n toParse.forEach(n => {\n nodes.push(transformDeclaration.call(self, n));\n });\n return nodes;\n }\n }\n\n rulesets() {\n if (!this.rules) { return []; }\n\n const filtRules = [];\n const rules = this.rules;\n let i;\n let rule;\n\n for (i = 0; (rule = rules[i]); i++) {\n if (rule.isRuleset) {\n filtRules.push(rule);\n }\n }\n\n return filtRules;\n }\n\n prependRule(rule) {\n const rules = this.rules;\n if (rules) {\n rules.unshift(rule);\n } else {\n this.rules = [ rule ];\n }\n this.setParent(rule, this);\n }\n\n find(selector, self = this, filter) {\n const rules = [];\n let match;\n let foundMixins;\n const key = selector.toCSS();\n\n if (key in this._lookups) { return this._lookups[key]; }\n\n this.rulesets().forEach(rule => {\n if (rule !== self) {\n for (let j = 0; j < rule.selectors.length; j++) {\n match = selector.match(rule.selectors[j]);\n if (match) {\n if (selector.elements.length > match) {\n if (!filter || filter(rule)) {\n foundMixins = rule.find(new Selector(selector.elements.slice(match)), self, filter);\n for (let i = 0; i < foundMixins.length; ++i) {\n foundMixins[i].path.push(rule);\n }\n Array.prototype.push.apply(rules, foundMixins);\n }\n } else {\n rules.push({ rule, path: []});\n }\n break;\n }\n }\n }\n });\n this._lookups[key] = rules;\n return rules;\n }\n\n genCSS(context, output) {\n let i;\n let j;\n const charsetRuleNodes = [];\n let ruleNodes = [];\n\n let // Line number debugging\n debugInfo;\n\n let rule;\n let path;\n\n context.tabLevel = (context.tabLevel || 0);\n\n if (!this.root) {\n context.tabLevel++;\n }\n\n const tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join(' ');\n const tabSetStr = context.compress ? '' : Array(context.tabLevel).join(' ');\n let sep;\n\n let charsetNodeIndex = 0;\n let importNodeIndex = 0;\n for (i = 0; (rule = this.rules[i]); i++) {\n if (rule instanceof Comment) {\n if (importNodeIndex === i) {\n importNodeIndex++;\n }\n ruleNodes.push(rule);\n } else if (rule.isCharset && rule.isCharset()) {\n ruleNodes.splice(charsetNodeIndex, 0, rule);\n charsetNodeIndex++;\n importNodeIndex++;\n } else if (rule.type === 'Import') {\n ruleNodes.splice(importNodeIndex, 0, rule);\n importNodeIndex++;\n } else {\n ruleNodes.push(rule);\n }\n }\n ruleNodes = charsetRuleNodes.concat(ruleNodes);\n\n // If this is the root node, we don't render\n // a selector, or {}.\n if (!this.root) {\n debugInfo = getDebugInfo(context, this, tabSetStr);\n\n if (debugInfo) {\n output.add(debugInfo);\n output.add(tabSetStr);\n }\n\n const paths = this.paths;\n const pathCnt = paths.length;\n let pathSubCnt;\n\n sep = context.compress ? ',' : (`,\\n${tabSetStr}`);\n\n for (i = 0; i < pathCnt; i++) {\n path = paths[i];\n if (!(pathSubCnt = path.length)) { continue; }\n if (i > 0) { output.add(sep); }\n\n context.firstSelector = true;\n path[0].genCSS(context, output);\n\n context.firstSelector = false;\n for (j = 1; j < pathSubCnt; j++) {\n path[j].genCSS(context, output);\n }\n }\n\n output.add((context.compress ? '{' : ' {\\n') + tabRuleStr);\n }\n\n // Compile rules and rulesets\n for (i = 0; (rule = ruleNodes[i]); i++) {\n\n if (i + 1 === ruleNodes.length) {\n context.lastRule = true;\n }\n\n const currentLastRule = context.lastRule;\n if (rule.isRulesetLike(rule)) {\n context.lastRule = false;\n }\n\n if (rule.genCSS) {\n rule.genCSS(context, output);\n } else if (rule.value) {\n output.add(rule.value.toString());\n }\n\n context.lastRule = currentLastRule;\n\n if (!context.lastRule && rule.isVisible()) {\n output.add(context.compress ? '' : (`\\n${tabRuleStr}`));\n } else {\n context.lastRule = false;\n }\n }\n\n if (!this.root) {\n output.add((context.compress ? '}' : `\\n${tabSetStr}}`));\n context.tabLevel--;\n }\n\n if (!output.isEmpty() && !context.compress && this.firstRoot) {\n output.add('\\n');\n }\n }\n\n joinSelectors(paths, context, selectors) {\n for (let s = 0; s < selectors.length; s++) {\n this.joinSelector(paths, context, selectors[s]);\n }\n }\n\n joinSelector(paths, context, selector) {\n function createParenthesis(elementsToPak, originalElement) {\n let replacementParen;\n let j;\n if (elementsToPak.length === 0) {\n replacementParen = new Paren(elementsToPak[0]);\n } else {\n const insideParent = new Array(elementsToPak.length);\n for (j = 0; j < elementsToPak.length; j++) {\n insideParent[j] = new Element(\n null,\n elementsToPak[j],\n originalElement.isVariable,\n originalElement._index,\n originalElement._fileInfo\n );\n }\n replacementParen = new Paren(new Selector(insideParent));\n }\n return replacementParen;\n }\n\n function createSelector(containedElement, originalElement) {\n let element;\n let selector;\n element = new Element(null, containedElement, originalElement.isVariable, originalElement._index, originalElement._fileInfo);\n selector = new Selector([element]);\n return selector;\n }\n\n // joins selector path from `beginningPath` with selector path in `addPath`\n // `replacedElement` contains element that is being replaced by `addPath`\n // returns concatenated path\n function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) {\n let newSelectorPath;\n let lastSelector;\n let newJoinedSelector;\n // our new selector path\n newSelectorPath = [];\n\n // construct the joined selector - if & is the first thing this will be empty,\n // if not newJoinedSelector will be the last set of elements in the selector\n if (beginningPath.length > 0) {\n newSelectorPath = utils.copyArray(beginningPath);\n lastSelector = newSelectorPath.pop();\n newJoinedSelector = originalSelector.createDerived(utils.copyArray(lastSelector.elements));\n }\n else {\n newJoinedSelector = originalSelector.createDerived([]);\n }\n\n if (addPath.length > 0) {\n // /deep/ is a CSS4 selector - (removed, so should deprecate)\n // that is valid without anything in front of it\n // so if the & does not have a combinator that is \"\" or \" \" then\n // and there is a combinator on the parent, then grab that.\n // this also allows + a { & .b { .a & { ... though not sure why you would want to do that\n let combinator = replacedElement.combinator;\n\n const parentEl = addPath[0].elements[0];\n if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) {\n combinator = parentEl.combinator;\n }\n // join the elements so far with the first part of the parent\n newJoinedSelector.elements.push(new Element(\n combinator,\n parentEl.value,\n replacedElement.isVariable,\n replacedElement._index,\n replacedElement._fileInfo\n ));\n newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1));\n }\n\n // now add the joined selector - but only if it is not empty\n if (newJoinedSelector.elements.length !== 0) {\n newSelectorPath.push(newJoinedSelector);\n }\n\n // put together the parent selectors after the join (e.g. the rest of the parent)\n if (addPath.length > 1) {\n let restOfPath = addPath.slice(1);\n restOfPath = restOfPath.map(selector => selector.createDerived(selector.elements, []));\n newSelectorPath = newSelectorPath.concat(restOfPath);\n }\n return newSelectorPath;\n }\n\n // joins selector path from `beginningPath` with every selector path in `addPaths` array\n // `replacedElement` contains element that is being replaced by `addPath`\n // returns array with all concatenated paths\n function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) {\n let j;\n for (j = 0; j < beginningPath.length; j++) {\n const newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector);\n result.push(newSelectorPath);\n }\n return result;\n }\n\n function mergeElementsOnToSelectors(elements, selectors) {\n let i;\n let sel;\n\n if (elements.length === 0) {\n return ;\n }\n if (selectors.length === 0) {\n selectors.push([ new Selector(elements) ]);\n return;\n }\n\n for (i = 0; (sel = selectors[i]); i++) {\n // if the previous thing in sel is a parent this needs to join on to it\n if (sel.length > 0) {\n sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));\n }\n else {\n sel.push(new Selector(elements));\n }\n }\n }\n\n // replace all parent selectors inside `inSelector` by content of `context` array\n // resulting selectors are returned inside `paths` array\n // returns true if `inSelector` contained at least one parent selector\n function replaceParentSelector(paths, context, inSelector) {\n // The paths are [[Selector]]\n // The first list is a list of comma separated selectors\n // The inner list is a list of inheritance separated selectors\n // e.g.\n // .a, .b {\n // .c {\n // }\n // }\n // == [[.a] [.c]] [[.b] [.c]]\n //\n let i;\n\n let j;\n let k;\n let currentElements;\n let newSelectors;\n let selectorsMultiplied;\n let sel;\n let el;\n let hadParentSelector = false;\n let length;\n let lastSelector;\n function findNestedSelector(element) {\n let maybeSelector;\n if (!(element.value instanceof Paren)) {\n return null;\n }\n\n maybeSelector = element.value.value;\n if (!(maybeSelector instanceof Selector)) {\n return null;\n }\n\n return maybeSelector;\n }\n\n // the elements from the current selector so far\n currentElements = [];\n // the current list of new selectors to add to the path.\n // We will build it up. We initiate it with one empty selector as we \"multiply\" the new selectors\n // by the parents\n newSelectors = [\n []\n ];\n\n for (i = 0; (el = inSelector.elements[i]); i++) {\n // non parent reference elements just get added\n if (el.value !== '&') {\n const nestedSelector = findNestedSelector(el);\n if (nestedSelector != null) {\n // merge the current list of non parent selector elements\n // on to the current list of selectors to add\n mergeElementsOnToSelectors(currentElements, newSelectors);\n\n const nestedPaths = [];\n let replaced;\n const replacedNewSelectors = [];\n replaced = replaceParentSelector(nestedPaths, context, nestedSelector);\n hadParentSelector = hadParentSelector || replaced;\n // the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors\n for (k = 0; k < nestedPaths.length; k++) {\n const replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el);\n addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors);\n }\n newSelectors = replacedNewSelectors;\n currentElements = [];\n } else {\n currentElements.push(el);\n }\n\n } else {\n hadParentSelector = true;\n // the new list of selectors to add\n selectorsMultiplied = [];\n\n // merge the current list of non parent selector elements\n // on to the current list of selectors to add\n mergeElementsOnToSelectors(currentElements, newSelectors);\n\n // loop through our current selectors\n for (j = 0; j < newSelectors.length; j++) {\n sel = newSelectors[j];\n // if we don't have any parent paths, the & might be in a mixin so that it can be used\n // whether there are parents or not\n if (context.length === 0) {\n // the combinator used on el should now be applied to the next element instead so that\n // it is not lost\n if (sel.length > 0) {\n sel[0].elements.push(new Element(el.combinator, '', el.isVariable, el._index, el._fileInfo));\n }\n selectorsMultiplied.push(sel);\n }\n else {\n // and the parent selectors\n for (k = 0; k < context.length; k++) {\n // We need to put the current selectors\n // then join the last selector's elements on to the parents selectors\n const newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector);\n // add that to our new set of selectors\n selectorsMultiplied.push(newSelectorPath);\n }\n }\n }\n\n // our new selectors has been multiplied, so reset the state\n newSelectors = selectorsMultiplied;\n currentElements = [];\n }\n }\n\n // if we have any elements left over (e.g. .a& .b == .b)\n // add them on to all the current selectors\n mergeElementsOnToSelectors(currentElements, newSelectors);\n\n for (i = 0; i < newSelectors.length; i++) {\n length = newSelectors[i].length;\n if (length > 0) {\n paths.push(newSelectors[i]);\n lastSelector = newSelectors[i][length - 1];\n newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList);\n }\n }\n\n return hadParentSelector;\n }\n\n function deriveSelector(visibilityInfo, deriveFrom) {\n const newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition);\n newSelector.copyVisibilityInfo(visibilityInfo);\n return newSelector;\n }\n\n // joinSelector code follows\n let i;\n\n let newPaths;\n let hadParentSelector;\n\n newPaths = [];\n hadParentSelector = replaceParentSelector(newPaths, context, selector);\n\n if (!hadParentSelector) {\n if (context.length > 0) {\n newPaths = [];\n for (i = 0; i < context.length; i++) {\n\n const concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo()));\n\n concatenated.push(selector);\n newPaths.push(concatenated);\n }\n }\n else {\n newPaths = [[selector]];\n }\n }\n\n for (i = 0; i < newPaths.length; i++) {\n paths.push(newPaths[i]);\n }\n }\n}\n\nRuleset.prototype.type = 'Ruleset';\nRuleset.prototype.isRuleset = true;\nexport default Ruleset;\n","import Node from './node';\nimport Selector from './selector';\nimport Ruleset from './ruleset';\nimport Anonymous from './anonymous';\n\nclass AtRule extends Node {\n constructor(\n name,\n value,\n rules,\n index,\n currentFileInfo,\n debugInfo,\n isRooted,\n visibilityInfo\n ) {\n super();\n\n let i;\n\n this.name = name;\n this.value = (value instanceof Node) ? value : (value ? new Anonymous(value) : value);\n if (rules) {\n if (Array.isArray(rules)) {\n this.rules = rules;\n } else {\n this.rules = [rules];\n this.rules[0].selectors = (new Selector([], null, null, index, currentFileInfo)).createEmptySelectors();\n }\n for (i = 0; i < this.rules.length; i++) {\n this.rules[i].allowImports = true;\n }\n this.setParent(this.rules, this);\n }\n this._index = index;\n this._fileInfo = currentFileInfo;\n this.debugInfo = debugInfo;\n this.isRooted = isRooted || false;\n this.copyVisibilityInfo(visibilityInfo);\n this.allowRoot = true;\n }\n\n accept(visitor) {\n const value = this.value;\n const rules = this.rules;\n if (rules) {\n this.rules = visitor.visitArray(rules);\n }\n if (value) {\n this.value = visitor.visit(value);\n }\n }\n\n isRulesetLike() {\n return this.rules || !this.isCharset();\n }\n\n isCharset() {\n return '@charset' === this.name;\n }\n\n genCSS(context, output) {\n const value = this.value;\n const rules = this.rules;\n output.add(this.name, this.fileInfo(), this.getIndex());\n if (value) {\n output.add(' ');\n value.genCSS(context, output);\n }\n if (rules) {\n this.outputRuleset(context, output, rules);\n } else {\n output.add(';');\n }\n }\n\n eval(context) {\n let mediaPathBackup;\n let mediaBlocksBackup;\n let value = this.value;\n let rules = this.rules;\n\n // media stored inside other atrule should not bubble over it\n // backpup media bubbling information\n mediaPathBackup = context.mediaPath;\n mediaBlocksBackup = context.mediaBlocks;\n // deleted media bubbling information\n context.mediaPath = [];\n context.mediaBlocks = [];\n\n if (value) {\n value = value.eval(context);\n }\n if (rules) {\n // assuming that there is only one rule at this point - that is how parser constructs the rule\n rules = [rules[0].eval(context)];\n rules[0].root = true;\n }\n // restore media bubbling information\n context.mediaPath = mediaPathBackup;\n context.mediaBlocks = mediaBlocksBackup;\n\n return new AtRule(this.name, value, rules,\n this.getIndex(), this.fileInfo(), this.debugInfo, this.isRooted, this.visibilityInfo());\n }\n\n variable(name) {\n if (this.rules) {\n // assuming that there is only one rule at this point - that is how parser constructs the rule\n return Ruleset.prototype.variable.call(this.rules[0], name);\n }\n }\n\n find(...args) {\n if (this.rules) {\n // assuming that there is only one rule at this point - that is how parser constructs the rule\n return Ruleset.prototype.find.apply(this.rules[0], args);\n }\n }\n\n rulesets() {\n if (this.rules) {\n // assuming that there is only one rule at this point - that is how parser constructs the rule\n return Ruleset.prototype.rulesets.apply(this.rules[0]);\n }\n }\n\n outputRuleset(context, output, rules) {\n const ruleCnt = rules.length;\n let i;\n context.tabLevel = (context.tabLevel | 0) + 1;\n\n // Compressed\n if (context.compress) {\n output.add('{');\n for (i = 0; i < ruleCnt; i++) {\n rules[i].genCSS(context, output);\n }\n output.add('}');\n context.tabLevel--;\n return;\n }\n\n // Non-compressed\n const tabSetStr = `\\n${Array(context.tabLevel).join(' ')}`;\n\n const tabRuleStr = `${tabSetStr} `;\n if (!ruleCnt) {\n output.add(` {${tabSetStr}}`);\n } else {\n output.add(` {${tabRuleStr}`);\n rules[0].genCSS(context, output);\n for (i = 1; i < ruleCnt; i++) {\n output.add(tabRuleStr);\n rules[i].genCSS(context, output);\n }\n output.add(`${tabSetStr}}`);\n }\n\n context.tabLevel--;\n }\n}\n\nAtRule.prototype.type = 'AtRule';\nexport default AtRule;\n","import Node from './node';\nimport contexts from '../contexts';\nimport * as utils from '../utils';\n\nclass DetachedRuleset extends Node {\n constructor(ruleset, frames) {\n super();\n\n this.ruleset = ruleset;\n this.frames = frames;\n this.setParent(this.ruleset, this);\n }\n\n accept(visitor) {\n this.ruleset = visitor.visit(this.ruleset);\n }\n\n eval(context) {\n const frames = this.frames || utils.copyArray(context.frames);\n return new DetachedRuleset(this.ruleset, frames);\n }\n\n callEval(context) {\n return this.ruleset.eval(this.frames ? new contexts.Eval(context, this.frames.concat(context.frames)) : context);\n }\n}\n\nDetachedRuleset.prototype.type = 'DetachedRuleset';\nDetachedRuleset.prototype.evalFirst = true;\nexport default DetachedRuleset;\n","import Node from './node';\nimport unitConversions from '../data/unit-conversions';\nimport * as utils from '../utils';\n\nclass Unit extends Node {\n constructor(numerator, denominator, backupUnit) {\n super();\n\n this.numerator = numerator ? utils.copyArray(numerator).sort() : [];\n this.denominator = denominator ? utils.copyArray(denominator).sort() : [];\n if (backupUnit) {\n this.backupUnit = backupUnit;\n } else if (numerator && numerator.length) {\n this.backupUnit = numerator[0];\n }\n }\n\n clone() {\n return new Unit(utils.copyArray(this.numerator), utils.copyArray(this.denominator), this.backupUnit);\n }\n\n genCSS(context, output) {\n // Dimension checks the unit is singular and throws an error if in strict math mode.\n const strictUnits = context && context.strictUnits;\n if (this.numerator.length === 1) {\n output.add(this.numerator[0]); // the ideal situation\n } else if (!strictUnits && this.backupUnit) {\n output.add(this.backupUnit);\n } else if (!strictUnits && this.denominator.length) {\n output.add(this.denominator[0]);\n }\n }\n\n toString() {\n let i;\n let returnStr = this.numerator.join('*');\n for (i = 0; i < this.denominator.length; i++) {\n returnStr += `/${this.denominator[i]}`;\n }\n return returnStr;\n }\n\n compare(other) {\n return this.is(other.toString()) ? 0 : undefined;\n }\n\n is(unitString) {\n return this.toString().toUpperCase() === unitString.toUpperCase();\n }\n\n isLength() {\n return RegExp('^(px|em|ex|ch|rem|in|cm|mm|pc|pt|ex|vw|vh|vmin|vmax)$', 'gi').test(this.toCSS());\n }\n\n isEmpty() {\n return this.numerator.length === 0 && this.denominator.length === 0;\n }\n\n isSingular() {\n return this.numerator.length <= 1 && this.denominator.length === 0;\n }\n\n map(callback) {\n let i;\n\n for (i = 0; i < this.numerator.length; i++) {\n this.numerator[i] = callback(this.numerator[i], false);\n }\n\n for (i = 0; i < this.denominator.length; i++) {\n this.denominator[i] = callback(this.denominator[i], true);\n }\n }\n\n usedUnits() {\n let group;\n const result = {};\n let mapUnit;\n let groupName;\n\n mapUnit = atomicUnit => {\n /* jshint loopfunc:true */\n if (group.hasOwnProperty(atomicUnit) && !result[groupName]) {\n result[groupName] = atomicUnit;\n }\n\n return atomicUnit;\n };\n\n for (groupName in unitConversions) {\n if (unitConversions.hasOwnProperty(groupName)) {\n group = unitConversions[groupName];\n\n this.map(mapUnit);\n }\n }\n\n return result;\n }\n\n cancel() {\n const counter = {};\n let atomicUnit;\n let i;\n\n for (i = 0; i < this.numerator.length; i++) {\n atomicUnit = this.numerator[i];\n counter[atomicUnit] = (counter[atomicUnit] || 0) + 1;\n }\n\n for (i = 0; i < this.denominator.length; i++) {\n atomicUnit = this.denominator[i];\n counter[atomicUnit] = (counter[atomicUnit] || 0) - 1;\n }\n\n this.numerator = [];\n this.denominator = [];\n\n for (atomicUnit in counter) {\n if (counter.hasOwnProperty(atomicUnit)) {\n const count = counter[atomicUnit];\n\n if (count > 0) {\n for (i = 0; i < count; i++) {\n this.numerator.push(atomicUnit);\n }\n } else if (count < 0) {\n for (i = 0; i < -count; i++) {\n this.denominator.push(atomicUnit);\n }\n }\n }\n }\n\n this.numerator.sort();\n this.denominator.sort();\n }\n}\n\nUnit.prototype.type = 'Unit';\nexport default Unit;\n","import Node from './node';\nimport unitConversions from '../data/unit-conversions';\nimport Unit from './unit';\nimport Color from './color';\n\n//\n// A number with a unit\n//\nclass Dimension extends Node {\n constructor(value, unit) {\n super();\n\n this.value = parseFloat(value);\n if (isNaN(this.value)) {\n throw new Error('Dimension is not a number.');\n }\n this.unit = (unit && unit instanceof Unit) ? unit :\n new Unit(unit ? [unit] : undefined);\n this.setParent(this.unit, this);\n }\n\n accept(visitor) {\n this.unit = visitor.visit(this.unit);\n }\n\n eval(context) {\n return this;\n }\n\n toColor() {\n return new Color([this.value, this.value, this.value]);\n }\n\n genCSS(context, output) {\n if ((context && context.strictUnits) && !this.unit.isSingular()) {\n throw new Error(`Multiple units in dimension. Correct the units or use the unit function. Bad unit: ${this.unit.toString()}`);\n }\n\n const value = this.fround(context, this.value);\n let strValue = String(value);\n\n if (value !== 0 && value < 0.000001 && value > -0.000001) {\n // would be output 1e-6 etc.\n strValue = value.toFixed(20).replace(/0+$/, '');\n }\n\n if (context && context.compress) {\n // Zero values doesn't need a unit\n if (value === 0 && this.unit.isLength()) {\n output.add(strValue);\n return;\n }\n\n // Float values doesn't need a leading zero\n if (value > 0 && value < 1) {\n strValue = (strValue).substr(1);\n }\n }\n\n output.add(strValue);\n this.unit.genCSS(context, output);\n }\n\n // In an operation between two Dimensions,\n // we default to the first Dimension's unit,\n // so `1px + 2` will yield `3px`.\n operate(context, op, other) {\n /* jshint noempty:false */\n let value = this._operate(context, op, this.value, other.value);\n\n let unit = this.unit.clone();\n\n if (op === '+' || op === '-') {\n if (unit.numerator.length === 0 && unit.denominator.length === 0) {\n unit = other.unit.clone();\n if (this.unit.backupUnit) {\n unit.backupUnit = this.unit.backupUnit;\n }\n } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) {\n // do nothing\n } else {\n other = other.convertTo(this.unit.usedUnits());\n\n if (context.strictUnits && other.unit.toString() !== unit.toString()) {\n throw new Error(`Incompatible units. Change the units or use the unit function. ` + \n `Bad units: '${unit.toString()}' and '${other.unit.toString()}'.`);\n }\n\n value = this._operate(context, op, this.value, other.value);\n }\n } else if (op === '*') {\n unit.numerator = unit.numerator.concat(other.unit.numerator).sort();\n unit.denominator = unit.denominator.concat(other.unit.denominator).sort();\n unit.cancel();\n } else if (op === '/') {\n unit.numerator = unit.numerator.concat(other.unit.denominator).sort();\n unit.denominator = unit.denominator.concat(other.unit.numerator).sort();\n unit.cancel();\n }\n return new Dimension(value, unit);\n }\n\n compare(other) {\n let a;\n let b;\n\n if (!(other instanceof Dimension)) {\n return undefined;\n }\n\n if (this.unit.isEmpty() || other.unit.isEmpty()) {\n a = this;\n b = other;\n } else {\n a = this.unify();\n b = other.unify();\n if (a.unit.compare(b.unit) !== 0) {\n return undefined;\n }\n }\n\n return Node.numericCompare(a.value, b.value);\n }\n\n unify() {\n return this.convertTo({ length: 'px', duration: 's', angle: 'rad' });\n }\n\n convertTo(conversions) {\n let value = this.value;\n const unit = this.unit.clone();\n let i;\n let groupName;\n let group;\n let targetUnit;\n let derivedConversions = {};\n let applyUnit;\n\n if (typeof conversions === 'string') {\n for (i in unitConversions) {\n if (unitConversions[i].hasOwnProperty(conversions)) {\n derivedConversions = {};\n derivedConversions[i] = conversions;\n }\n }\n conversions = derivedConversions;\n }\n applyUnit = (atomicUnit, denominator) => {\n /* jshint loopfunc:true */\n if (group.hasOwnProperty(atomicUnit)) {\n if (denominator) {\n value = value / (group[atomicUnit] / group[targetUnit]);\n } else {\n value = value * (group[atomicUnit] / group[targetUnit]);\n }\n\n return targetUnit;\n }\n\n return atomicUnit;\n };\n\n for (groupName in conversions) {\n if (conversions.hasOwnProperty(groupName)) {\n targetUnit = conversions[groupName];\n group = unitConversions[groupName];\n\n unit.map(applyUnit);\n }\n }\n\n unit.cancel();\n\n return new Dimension(value, unit);\n }\n}\n\nDimension.prototype.type = 'Dimension';\nexport default Dimension;\n","import Node from './node';\nimport Color from './color';\nimport Dimension from './dimension';\nimport * as Constants from '../constants';\nconst MATH = Constants.Math;\n\n\nclass Operation extends Node {\n constructor(op, operands, isSpaced) {\n super();\n\n this.op = op.trim();\n this.operands = operands;\n this.isSpaced = isSpaced;\n }\n\n accept(visitor) {\n this.operands = visitor.visitArray(this.operands);\n }\n\n eval(context) {\n let a = this.operands[0].eval(context);\n let b = this.operands[1].eval(context);\n let op;\n\n if (context.isMathOn(this.op)) {\n op = this.op === './' ? '/' : this.op;\n if (a instanceof Dimension && b instanceof Color) {\n a = a.toColor();\n }\n if (b instanceof Dimension && a instanceof Color) {\n b = b.toColor();\n }\n if (!a.operate) {\n if (a instanceof Operation && a.op === '/' && context.math === MATH.PARENS_DIVISION) {\n return new Operation(this.op, [a, b], this.isSpaced);\n }\n throw { type: 'Operation',\n message: 'Operation on an invalid type' };\n }\n\n return a.operate(context, op, b);\n } else {\n return new Operation(this.op, [a, b], this.isSpaced);\n }\n }\n\n genCSS(context, output) {\n this.operands[0].genCSS(context, output);\n if (this.isSpaced) {\n output.add(' ');\n }\n output.add(this.op);\n if (this.isSpaced) {\n output.add(' ');\n }\n this.operands[1].genCSS(context, output);\n }\n}\n\nOperation.prototype.type = 'Operation';\nexport default Operation;\n","import Node from './node';\nimport Paren from './paren';\nimport Comment from './comment';\nimport Dimension from './dimension';\nimport * as Constants from '../constants';\nconst MATH = Constants.Math;\n\nclass Expression extends Node {\n constructor(value, noSpacing) {\n super();\n\n this.value = value;\n this.noSpacing = noSpacing;\n if (!value) {\n throw new Error('Expression requires an array parameter');\n }\n }\n\n accept(visitor) {\n this.value = visitor.visitArray(this.value);\n }\n\n eval(context) {\n let returnValue;\n const mathOn = context.isMathOn();\n\n const inParenthesis = this.parens && \n (context.math !== MATH.STRICT_LEGACY || !this.parensInOp);\n\n let doubleParen = false;\n if (inParenthesis) {\n context.inParenthesis();\n }\n if (this.value.length > 1) {\n returnValue = new Expression(this.value.map(e => {\n if (!e.eval) {\n return e;\n }\n return e.eval(context);\n }), this.noSpacing);\n } else if (this.value.length === 1) {\n if (this.value[0].parens && !this.value[0].parensInOp && !context.inCalc) {\n doubleParen = true;\n }\n returnValue = this.value[0].eval(context);\n } else {\n returnValue = this;\n }\n if (inParenthesis) {\n context.outOfParenthesis();\n }\n if (this.parens && this.parensInOp && !mathOn && !doubleParen \n && (!(returnValue instanceof Dimension))) {\n returnValue = new Paren(returnValue);\n }\n return returnValue;\n }\n\n genCSS(context, output) {\n for (let i = 0; i < this.value.length; i++) {\n this.value[i].genCSS(context, output);\n if (!this.noSpacing && i + 1 < this.value.length) {\n output.add(' ');\n }\n }\n }\n\n throwAwayComments() {\n this.value = this.value.filter(v => !(v instanceof Comment));\n }\n}\n\nExpression.prototype.type = 'Expression';\nexport default Expression;\n","import Expression from '../tree/expression';\n\nclass functionCaller {\n constructor(name, context, index, currentFileInfo) {\n this.name = name.toLowerCase();\n this.index = index;\n this.context = context;\n this.currentFileInfo = currentFileInfo;\n\n this.func = context.frames[0].functionRegistry.get(this.name);\n }\n\n isValid() {\n return Boolean(this.func);\n }\n\n call(args) {\n // This code is terrible and should be replaced as per this issue...\n // https://github.com/less/less.js/issues/2477\n if (Array.isArray(args)) {\n args = args.filter(item => {\n if (item.type === 'Comment') {\n return false;\n }\n return true;\n })\n .map(item => {\n if (item.type === 'Expression') {\n const subNodes = item.value.filter(item => {\n if (item.type === 'Comment') {\n return false;\n }\n return true;\n });\n if (subNodes.length === 1) {\n return subNodes[0];\n } else {\n return new Expression(subNodes);\n }\n }\n return item;\n });\n }\n\n return this.func(...args);\n }\n}\n\nexport default functionCaller;\n","import Node from './node';\nimport Anonymous from './anonymous';\nimport FunctionCaller from '../functions/function-caller';\n\n//\n// A function call node.\n//\nclass Call extends Node {\n constructor(name, args, index, currentFileInfo) {\n super();\n\n this.name = name;\n this.args = args;\n this.calc = name === 'calc';\n this._index = index;\n this._fileInfo = currentFileInfo;\n }\n\n accept(visitor) {\n if (this.args) {\n this.args = visitor.visitArray(this.args);\n }\n }\n\n //\n // When evaluating a function call,\n // we either find the function in the functionRegistry,\n // in which case we call it, passing the evaluated arguments,\n // if this returns null or we cannot find the function, we\n // simply print it out as it appeared originally [2].\n //\n // The reason why we evaluate the arguments, is in the case where\n // we try to pass a variable to a function, like: `saturate(@color)`.\n // The function should receive the value, not the variable.\n //\n eval(context) {\n /**\n * Turn off math for calc(), and switch back on for evaluating nested functions\n */\n const currentMathContext = context.mathOn;\n context.mathOn = !this.calc;\n if (this.calc || context.inCalc) {\n context.enterCalc();\n }\n const args = this.args.map(a => a.eval(context));\n if (this.calc || context.inCalc) {\n context.exitCalc();\n }\n context.mathOn = currentMathContext;\n\n let result;\n const funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo());\n\n if (funcCaller.isValid()) {\n try {\n result = funcCaller.call(args);\n } catch (e) {\n throw { \n type: e.type || 'Runtime',\n message: `error evaluating function \\`${this.name}\\`${e.message ? `: ${e.message}` : ''}`,\n index: this.getIndex(), \n filename: this.fileInfo().filename,\n line: e.lineNumber,\n column: e.columnNumber\n };\n }\n\n if (result !== null && result !== undefined) {\n // Results that that are not nodes are cast as Anonymous nodes\n // Falsy values or booleans are returned as empty nodes\n if (!(result instanceof Node)) {\n if (!result || result === true) {\n result = new Anonymous(null); \n }\n else {\n result = new Anonymous(result.toString()); \n }\n \n }\n result._index = this._index;\n result._fileInfo = this._fileInfo;\n return result;\n }\n\n }\n\n return new Call(this.name, args, this.getIndex(), this.fileInfo());\n }\n\n genCSS(context, output) {\n output.add(`${this.name}(`, this.fileInfo(), this.getIndex());\n\n for (let i = 0; i < this.args.length; i++) {\n this.args[i].genCSS(context, output);\n if (i + 1 < this.args.length) {\n output.add(', ');\n }\n }\n\n output.add(')');\n }\n}\n\nCall.prototype.type = 'Call';\nexport default Call;\n","import Node from './node';\nimport Call from './call';\n\nclass Variable extends Node {\n constructor(name, index, currentFileInfo) {\n super();\n\n this.name = name;\n this._index = index;\n this._fileInfo = currentFileInfo;\n }\n\n eval(context) {\n let variable;\n let name = this.name;\n\n if (name.indexOf('@@') === 0) {\n name = `@${new Variable(name.slice(1), this.getIndex(), this.fileInfo()).eval(context).value}`;\n }\n\n if (this.evaluating) {\n throw { type: 'Name',\n message: `Recursive variable definition for ${name}`,\n filename: this.fileInfo().filename,\n index: this.getIndex() };\n }\n\n this.evaluating = true;\n\n variable = this.find(context.frames, frame => {\n const v = frame.variable(name);\n if (v) {\n if (v.important) {\n const importantScope = context.importantScope[context.importantScope.length - 1];\n importantScope.important = v.important;\n }\n // If in calc, wrap vars in a function call to cascade evaluate args first\n if (context.inCalc) {\n return (new Call('_SELF', [v.value])).eval(context);\n }\n else {\n return v.value.eval(context);\n }\n }\n });\n if (variable) {\n this.evaluating = false;\n return variable;\n } else {\n throw { type: 'Name',\n message: `variable ${name} is undefined`,\n filename: this.fileInfo().filename,\n index: this.getIndex() };\n }\n }\n\n find(obj, fun) {\n for (let i = 0, r; i < obj.length; i++) {\n r = fun.call(obj, obj[i]);\n if (r) { return r; }\n }\n return null;\n }\n}\n\nVariable.prototype.type = 'Variable';\nexport default Variable;\n","import Node from './node';\nimport Declaration from './declaration';\n\nclass Property extends Node {\n constructor(name, index, currentFileInfo) {\n super();\n\n this.name = name;\n this._index = index;\n this._fileInfo = currentFileInfo;\n }\n\n eval(context) {\n let property;\n const name = this.name;\n // TODO: shorten this reference\n const mergeRules = context.pluginManager.less.visitors.ToCSSVisitor.prototype._mergeRules;\n\n if (this.evaluating) {\n throw { type: 'Name',\n message: `Recursive property reference for ${name}`,\n filename: this.fileInfo().filename,\n index: this.getIndex() };\n }\n\n this.evaluating = true;\n\n property = this.find(context.frames, frame => {\n let v;\n const vArr = frame.property(name);\n if (vArr) {\n for (let i = 0; i < vArr.length; i++) {\n v = vArr[i];\n\n vArr[i] = new Declaration(v.name,\n v.value,\n v.important,\n v.merge,\n v.index,\n v.currentFileInfo,\n v.inline,\n v.variable\n );\n }\n mergeRules(vArr);\n\n v = vArr[vArr.length - 1];\n if (v.important) {\n const importantScope = context.importantScope[context.importantScope.length - 1];\n importantScope.important = v.important;\n }\n v = v.value.eval(context);\n return v;\n }\n });\n if (property) {\n this.evaluating = false;\n return property;\n } else {\n throw { type: 'Name',\n message: `Property '${name}' is undefined`,\n filename: this.currentFileInfo.filename,\n index: this.index };\n }\n }\n\n find(obj, fun) {\n for (let i = 0, r; i < obj.length; i++) {\n r = fun.call(obj, obj[i]);\n if (r) { return r; }\n }\n return null;\n }\n}\n\nProperty.prototype.type = 'Property';\nexport default Property;\n","import Node from './node';\n\nclass Attribute extends Node {\n constructor(key, op, value) {\n super();\n\n this.key = key;\n this.op = op;\n this.value = value;\n }\n\n eval(context) {\n return new Attribute(this.key.eval ? this.key.eval(context) : this.key,\n this.op, (this.value && this.value.eval) ? this.value.eval(context) : this.value);\n }\n\n genCSS(context, output) {\n output.add(this.toCSS(context));\n }\n\n toCSS(context) {\n let value = this.key.toCSS ? this.key.toCSS(context) : this.key;\n\n if (this.op) {\n value += this.op;\n value += (this.value.toCSS ? this.value.toCSS(context) : this.value);\n }\n\n return `[${value}]`;\n }\n}\n\nAttribute.prototype.type = 'Attribute';\nexport default Attribute;\n","import Node from './node';\nimport Variable from './variable';\nimport Property from './property';\n\nclass Quoted extends Node {\n constructor(str, content, escaped, index, currentFileInfo) {\n super();\n\n this.escaped = (escaped == null) ? true : escaped;\n this.value = content || '';\n this.quote = str.charAt(0);\n this._index = index;\n this._fileInfo = currentFileInfo;\n this.variableRegex = /@\\{([\\w-]+)\\}/g;\n this.propRegex = /\\$\\{([\\w-]+)\\}/g;\n }\n\n genCSS(context, output) {\n if (!this.escaped) {\n output.add(this.quote, this.fileInfo(), this.getIndex());\n }\n output.add(this.value);\n if (!this.escaped) {\n output.add(this.quote);\n }\n }\n\n containsVariables() {\n return this.value.match(this.variableRegex);\n }\n\n eval(context) {\n const that = this;\n let value = this.value;\n const variableReplacement = (_, name) => {\n const v = new Variable(`@${name}`, that.getIndex(), that.fileInfo()).eval(context, true);\n return (v instanceof Quoted) ? v.value : v.toCSS();\n };\n const propertyReplacement = (_, name) => {\n const v = new Property(`$${name}`, that.getIndex(), that.fileInfo()).eval(context, true);\n return (v instanceof Quoted) ? v.value : v.toCSS();\n };\n function iterativeReplace(value, regexp, replacementFnc) {\n let evaluatedValue = value;\n do {\n value = evaluatedValue.toString();\n evaluatedValue = value.replace(regexp, replacementFnc);\n } while (value !== evaluatedValue);\n return evaluatedValue;\n }\n value = iterativeReplace(value, this.variableRegex, variableReplacement);\n value = iterativeReplace(value, this.propRegex, propertyReplacement);\n return new Quoted(this.quote + value + this.quote, value, this.escaped, this.getIndex(), this.fileInfo());\n }\n\n compare(other) {\n // when comparing quoted strings allow the quote to differ\n if (other.type === 'Quoted' && !this.escaped && !other.escaped) {\n return Node.numericCompare(this.value, other.value);\n } else {\n return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined;\n }\n }\n}\n\nQuoted.prototype.type = 'Quoted';\nexport default Quoted;\n","import Node from './node';\n\nclass URL extends Node {\n constructor(val, index, currentFileInfo, isEvald) {\n super();\n\n this.value = val;\n this._index = index;\n this._fileInfo = currentFileInfo;\n this.isEvald = isEvald;\n }\n\n accept(visitor) {\n this.value = visitor.visit(this.value);\n }\n\n genCSS(context, output) {\n output.add('url(');\n this.value.genCSS(context, output);\n output.add(')');\n }\n\n eval(context) {\n const val = this.value.eval(context);\n let rootpath;\n\n if (!this.isEvald) {\n // Add the rootpath if the URL requires a rewrite\n rootpath = this.fileInfo() && this.fileInfo().rootpath;\n if (typeof rootpath === 'string' &&\n typeof val.value === 'string' &&\n context.pathRequiresRewrite(val.value)) {\n if (!val.quote) {\n rootpath = escapePath(rootpath);\n }\n val.value = context.rewritePath(val.value, rootpath);\n } else {\n val.value = context.normalizePath(val.value);\n }\n\n // Add url args if enabled\n if (context.urlArgs) {\n if (!val.value.match(/^\\s*data:/)) {\n const delimiter = val.value.indexOf('?') === -1 ? '?' : '&';\n const urlArgs = delimiter + context.urlArgs;\n if (val.value.indexOf('#') !== -1) {\n val.value = val.value.replace('#', `${urlArgs}#`);\n } else {\n val.value += urlArgs;\n }\n }\n }\n }\n\n return new URL(val, this.getIndex(), this.fileInfo(), true);\n }\n}\n\nURL.prototype.type = 'Url';\n\nfunction escapePath(path) {\n return path.replace(/[\\(\\)'\"\\s]/g, match => `\\\\${match}`);\n}\n\nexport default URL;\n","import Ruleset from './ruleset';\nimport Value from './value';\nimport Selector from './selector';\nimport Anonymous from './anonymous';\nimport Expression from './expression';\nimport AtRule from './atrule';\nimport * as utils from '../utils';\n\nclass Media extends AtRule {\n constructor(value, features, index, currentFileInfo, visibilityInfo) {\n super();\n\n this._index = index;\n this._fileInfo = currentFileInfo;\n\n const selectors = (new Selector([], null, null, this._index, this._fileInfo)).createEmptySelectors();\n\n this.features = new Value(features);\n this.rules = [new Ruleset(selectors, value)];\n this.rules[0].allowImports = true;\n this.copyVisibilityInfo(visibilityInfo);\n this.allowRoot = true;\n this.setParent(selectors, this);\n this.setParent(this.features, this);\n this.setParent(this.rules, this);\n }\n\n isRulesetLike() {\n return true;\n }\n\n accept(visitor) {\n if (this.features) {\n this.features = visitor.visit(this.features);\n }\n if (this.rules) {\n this.rules = visitor.visitArray(this.rules);\n }\n }\n\n genCSS(context, output) {\n output.add('@media ', this._fileInfo, this._index);\n this.features.genCSS(context, output);\n this.outputRuleset(context, output, this.rules);\n }\n\n eval(context) {\n if (!context.mediaBlocks) {\n context.mediaBlocks = [];\n context.mediaPath = [];\n }\n\n const media = new Media(null, [], this._index, this._fileInfo, this.visibilityInfo());\n if (this.debugInfo) {\n this.rules[0].debugInfo = this.debugInfo;\n media.debugInfo = this.debugInfo;\n }\n \n media.features = this.features.eval(context);\n\n context.mediaPath.push(media);\n context.mediaBlocks.push(media);\n\n this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit();\n context.frames.unshift(this.rules[0]);\n media.rules = [this.rules[0].eval(context)];\n context.frames.shift();\n\n context.mediaPath.pop();\n\n return context.mediaPath.length === 0 ? media.evalTop(context) :\n media.evalNested(context);\n }\n\n evalTop(context) {\n let result = this;\n\n // Render all dependent Media blocks.\n if (context.mediaBlocks.length > 1) {\n const selectors = (new Selector([], null, null, this.getIndex(), this.fileInfo())).createEmptySelectors();\n result = new Ruleset(selectors, context.mediaBlocks);\n result.multiMedia = true;\n result.copyVisibilityInfo(this.visibilityInfo());\n this.setParent(result, this);\n }\n\n delete context.mediaBlocks;\n delete context.mediaPath;\n\n return result;\n }\n\n evalNested(context) {\n let i;\n let value;\n const path = context.mediaPath.concat([this]);\n\n // Extract the media-query conditions separated with `,` (OR).\n for (i = 0; i < path.length; i++) {\n value = path[i].features instanceof Value ?\n path[i].features.value : path[i].features;\n path[i] = Array.isArray(value) ? value : [value];\n }\n\n // Trace all permutations to generate the resulting media-query.\n //\n // (a, b and c) with nested (d, e) ->\n // a and d\n // a and e\n // b and c and d\n // b and c and e\n this.features = new Value(this.permute(path).map(path => {\n path = path.map(fragment => fragment.toCSS ? fragment : new Anonymous(fragment));\n\n for (i = path.length - 1; i > 0; i--) {\n path.splice(i, 0, new Anonymous('and'));\n }\n\n return new Expression(path);\n }));\n this.setParent(this.features, this);\n\n // Fake a tree-node that doesn't output anything.\n return new Ruleset([], []);\n }\n\n permute(arr) {\n if (arr.length === 0) {\n return [];\n } else if (arr.length === 1) {\n return arr[0];\n } else {\n const result = [];\n const rest = this.permute(arr.slice(1));\n for (let i = 0; i < rest.length; i++) {\n for (let j = 0; j < arr[0].length; j++) {\n result.push([arr[0][j]].concat(rest[i]));\n }\n }\n return result;\n }\n }\n\n bubbleSelectors(selectors) {\n if (!selectors) {\n return;\n }\n this.rules = [new Ruleset(utils.copyArray(selectors), [this.rules[0]])];\n this.setParent(this.rules, this);\n }\n}\n\nMedia.prototype.type = 'Media';\nexport default Media;\n","import Node from './node';\nimport Media from './media';\nimport URL from './url';\nimport Quoted from './quoted';\nimport Ruleset from './ruleset';\nimport Anonymous from './anonymous';\nimport * as utils from '../utils';\nimport LessError from '../less-error';\n\n//\n// CSS @import node\n//\n// The general strategy here is that we don't want to wait\n// for the parsing to be completed, before we start importing\n// the file. That's because in the context of a browser,\n// most of the time will be spent waiting for the server to respond.\n//\n// On creation, we push the import path to our import queue, though\n// `import,push`, we also pass it a callback, which it'll call once\n// the file has been fetched, and parsed.\n//\nclass Import extends Node {\n constructor(path, features, options, index, currentFileInfo, visibilityInfo) {\n super();\n\n this.options = options;\n this._index = index;\n this._fileInfo = currentFileInfo;\n this.path = path;\n this.features = features;\n this.allowRoot = true;\n\n if (this.options.less !== undefined || this.options.inline) {\n this.css = !this.options.less || this.options.inline;\n } else {\n const pathValue = this.getPath();\n if (pathValue && /[#\\.\\&\\?]css([\\?;].*)?$/.test(pathValue)) {\n this.css = true;\n }\n }\n this.copyVisibilityInfo(visibilityInfo);\n this.setParent(this.features, this);\n this.setParent(this.path, this);\n }\n\n accept(visitor) {\n if (this.features) {\n this.features = visitor.visit(this.features);\n }\n this.path = visitor.visit(this.path);\n if (!this.options.isPlugin && !this.options.inline && this.root) {\n this.root = visitor.visit(this.root);\n }\n }\n\n genCSS(context, output) {\n if (this.css && this.path._fileInfo.reference === undefined) {\n output.add('@import ', this._fileInfo, this._index);\n this.path.genCSS(context, output);\n if (this.features) {\n output.add(' ');\n this.features.genCSS(context, output);\n }\n output.add(';');\n }\n }\n\n getPath() {\n return (this.path instanceof URL) ?\n this.path.value.value : this.path.value;\n }\n\n isVariableImport() {\n let path = this.path;\n if (path instanceof URL) {\n path = path.value;\n }\n if (path instanceof Quoted) {\n return path.containsVariables();\n }\n\n return true;\n }\n\n evalForImport(context) {\n let path = this.path;\n\n if (path instanceof URL) {\n path = path.value;\n }\n\n return new Import(path.eval(context), this.features, this.options, this._index, this._fileInfo, this.visibilityInfo());\n }\n\n evalPath(context) {\n const path = this.path.eval(context);\n const fileInfo = this._fileInfo;\n\n if (!(path instanceof URL)) {\n // Add the rootpath if the URL requires a rewrite\n const pathValue = path.value;\n if (fileInfo &&\n pathValue &&\n context.pathRequiresRewrite(pathValue)) {\n path.value = context.rewritePath(pathValue, fileInfo.rootpath);\n } else {\n path.value = context.normalizePath(path.value);\n }\n }\n\n return path;\n }\n\n eval(context) {\n const result = this.doEval(context);\n if (this.options.reference || this.blocksVisibility()) {\n if (result.length || result.length === 0) {\n result.forEach(node => {\n node.addVisibilityBlock();\n }\n );\n } else {\n result.addVisibilityBlock();\n }\n }\n return result;\n }\n\n doEval(context) {\n let ruleset;\n let registry;\n const features = this.features && this.features.eval(context);\n\n if (this.options.isPlugin) {\n if (this.root && this.root.eval) {\n try {\n this.root.eval(context);\n }\n catch (e) {\n e.message = 'Plugin error during evaluation';\n throw new LessError(e, this.root.imports, this.root.filename);\n }\n }\n registry = context.frames[0] && context.frames[0].functionRegistry;\n if ( registry && this.root && this.root.functions ) {\n registry.addMultiple( this.root.functions );\n }\n\n return [];\n }\n\n if (this.skip) {\n if (typeof this.skip === 'function') {\n this.skip = this.skip();\n }\n if (this.skip) {\n return [];\n }\n }\n if (this.options.inline) {\n const contents = new Anonymous(this.root, 0,\n {\n filename: this.importedFilename,\n reference: this.path._fileInfo && this.path._fileInfo.reference\n }, true, true);\n\n return this.features ? new Media([contents], this.features.value) : [contents];\n } else if (this.css) {\n const newImport = new Import(this.evalPath(context), features, this.options, this._index);\n if (!newImport.css && this.error) {\n throw this.error;\n }\n return newImport;\n } else {\n ruleset = new Ruleset(null, utils.copyArray(this.root.rules));\n ruleset.evalImports(context);\n\n return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules;\n }\n }\n}\n\nImport.prototype.type = 'Import';\nexport default Import;\n","import Node from './node';\nimport Variable from './variable';\n\nclass JsEvalNode extends Node {\n evaluateJavaScript(expression, context) {\n let result;\n const that = this;\n const evalContext = {};\n\n if (!context.javascriptEnabled) {\n throw { message: 'Inline JavaScript is not enabled. Is it set in your options?',\n filename: this.fileInfo().filename,\n index: this.getIndex() };\n }\n\n expression = expression.replace(/@\\{([\\w-]+)\\}/g, (_, name) => that.jsify(new Variable(`@${name}`, that.getIndex(), that.fileInfo()).eval(context)));\n\n try {\n expression = new Function(`return (${expression})`);\n } catch (e) {\n throw { message: `JavaScript evaluation error: ${e.message} from \\`${expression}\\`` ,\n filename: this.fileInfo().filename,\n index: this.getIndex() };\n }\n\n const variables = context.frames[0].variables();\n for (const k in variables) {\n if (variables.hasOwnProperty(k)) {\n /* jshint loopfunc:true */\n evalContext[k.slice(1)] = {\n value: variables[k].value,\n toJS: function () {\n return this.value.eval(context).toCSS();\n }\n };\n }\n }\n\n try {\n result = expression.call(evalContext);\n } catch (e) {\n throw { message: `JavaScript evaluation error: '${e.name}: ${e.message.replace(/[\"]/g, '\\'')}'` ,\n filename: this.fileInfo().filename,\n index: this.getIndex() };\n }\n return result;\n }\n\n jsify(obj) {\n if (Array.isArray(obj.value) && (obj.value.length > 1)) {\n return `[${obj.value.map(v => v.toCSS()).join(', ')}]`;\n } else {\n return obj.toCSS();\n }\n }\n}\n\nexport default JsEvalNode;\n","import JsEvalNode from './js-eval-node';\nimport Dimension from './dimension';\nimport Quoted from './quoted';\nimport Anonymous from './anonymous';\n\nclass JavaScript extends JsEvalNode {\n constructor(string, escaped, index, currentFileInfo) {\n super();\n\n this.escaped = escaped;\n this.expression = string;\n this._index = index;\n this._fileInfo = currentFileInfo;\n }\n\n eval(context) {\n const result = this.evaluateJavaScript(this.expression, context);\n const type = typeof result;\n\n if (type === 'number' && !isNaN(result)) {\n return new Dimension(result);\n } else if (type === 'string') {\n return new Quoted(`\"${result}\"`, result, this.escaped, this._index);\n } else if (Array.isArray(result)) {\n return new Anonymous(result.join(', '));\n } else {\n return new Anonymous(result);\n }\n }\n}\n\nJavaScript.prototype.type = 'JavaScript';\nexport default JavaScript;\n","import Node from './node';\n\nclass Assignment extends Node {\n constructor(key, val) {\n super();\n\n this.key = key;\n this.value = val;\n }\n\n accept(visitor) {\n this.value = visitor.visit(this.value);\n }\n\n eval(context) {\n if (this.value.eval) {\n return new Assignment(this.key, this.value.eval(context));\n }\n return this;\n }\n\n genCSS(context, output) {\n output.add(`${this.key}=`);\n if (this.value.genCSS) {\n this.value.genCSS(context, output);\n } else {\n output.add(this.value);\n }\n }\n}\n\nAssignment.prototype.type = 'Assignment';\nexport default Assignment;\n","import Node from './node';\n\nclass Condition extends Node {\n constructor(op, l, r, i, negate) {\n super();\n\n this.op = op.trim();\n this.lvalue = l;\n this.rvalue = r;\n this._index = i;\n this.negate = negate;\n }\n\n accept(visitor) {\n this.lvalue = visitor.visit(this.lvalue);\n this.rvalue = visitor.visit(this.rvalue);\n }\n\n eval(context) {\n const result = ((op, a, b) => {\n switch (op) {\n case 'and': return a && b;\n case 'or': return a || b;\n default:\n switch (Node.compare(a, b)) {\n case -1:\n return op === '<' || op === '=<' || op === '<=';\n case 0:\n return op === '=' || op === '>=' || op === '=<' || op === '<=';\n case 1:\n return op === '>' || op === '>=';\n default:\n return false;\n }\n }\n })(this.op, this.lvalue.eval(context), this.rvalue.eval(context));\n\n return this.negate ? !result : result;\n }\n}\n\nCondition.prototype.type = 'Condition';\nexport default Condition;\n","import Node from './node';\n\nclass UnicodeDescriptor extends Node {\n constructor(value) {\n super();\n\n this.value = value;\n }\n}\n\nUnicodeDescriptor.prototype.type = 'UnicodeDescriptor';\n\nexport default UnicodeDescriptor;\n","import Node from './node';\nimport Operation from './operation';\nimport Dimension from './dimension';\n\nclass Negative extends Node {\n constructor(node) {\n super();\n\n this.value = node;\n }\n\n genCSS(context, output) {\n output.add('-');\n this.value.genCSS(context, output);\n }\n\n eval(context) {\n if (context.isMathOn()) {\n return (new Operation('*', [new Dimension(-1), this.value])).eval(context);\n }\n return new Negative(this.value.eval(context));\n }\n}\n\nNegative.prototype.type = 'Negative';\nexport default Negative;\n","import Node from './node';\nimport Selector from './selector';\n\nclass Extend extends Node {\n constructor(selector, option, index, currentFileInfo, visibilityInfo) {\n super();\n\n this.selector = selector;\n this.option = option;\n this.object_id = Extend.next_id++;\n this.parent_ids = [this.object_id];\n this._index = index;\n this._fileInfo = currentFileInfo;\n this.copyVisibilityInfo(visibilityInfo);\n this.allowRoot = true;\n\n switch (option) {\n case 'all':\n this.allowBefore = true;\n this.allowAfter = true;\n break;\n default:\n this.allowBefore = false;\n this.allowAfter = false;\n break;\n }\n this.setParent(this.selector, this);\n }\n\n accept(visitor) {\n this.selector = visitor.visit(this.selector);\n }\n\n eval(context) {\n return new Extend(this.selector.eval(context), this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo());\n }\n\n clone(context) {\n return new Extend(this.selector, this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo());\n }\n\n // it concatenates (joins) all selectors in selector array\n findSelfSelectors(selectors) {\n let selfElements = [];\n let i;\n let selectorElements;\n\n for (i = 0; i < selectors.length; i++) {\n selectorElements = selectors[i].elements;\n // duplicate the logic in genCSS function inside the selector node.\n // future TODO - move both logics into the selector joiner visitor\n if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === '') {\n selectorElements[0].combinator.value = ' ';\n }\n selfElements = selfElements.concat(selectors[i].elements);\n }\n\n this.selfSelectors = [new Selector(selfElements)];\n this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo());\n }\n}\n\nExtend.next_id = 0;\n\nExtend.prototype.type = 'Extend';\nexport default Extend;\n","import Node from './node';\nimport Variable from './variable';\nimport Ruleset from './ruleset';\nimport DetachedRuleset from './detached-ruleset';\nimport LessError from '../less-error';\n\nclass VariableCall extends Node {\n constructor(variable, index, currentFileInfo) {\n super();\n\n this.variable = variable;\n this._index = index;\n this._fileInfo = currentFileInfo;\n this.allowRoot = true;\n }\n\n eval(context) {\n let rules;\n let detachedRuleset = new Variable(this.variable, this.getIndex(), this.fileInfo()).eval(context);\n const error = new LessError({message: `Could not evaluate variable call ${this.variable}`});\n\n if (!detachedRuleset.ruleset) {\n if (detachedRuleset.rules) {\n rules = detachedRuleset;\n }\n else if (Array.isArray(detachedRuleset)) {\n rules = new Ruleset('', detachedRuleset);\n }\n else if (Array.isArray(detachedRuleset.value)) {\n rules = new Ruleset('', detachedRuleset.value);\n }\n else {\n throw error;\n }\n detachedRuleset = new DetachedRuleset(rules);\n }\n\n if (detachedRuleset.ruleset) {\n return detachedRuleset.callEval(context);\n }\n throw error;\n }\n}\n\nVariableCall.prototype.type = 'VariableCall';\nexport default VariableCall;\n","import Node from './node';\nimport Variable from './variable';\nimport Ruleset from './ruleset';\nimport Selector from './selector';\n\nclass NamespaceValue extends Node {\n constructor(ruleCall, lookups, important, index, fileInfo) {\n super();\n\n this.value = ruleCall;\n this.lookups = lookups;\n this.important = important;\n this._index = index;\n this._fileInfo = fileInfo;\n }\n\n eval(context) {\n let i;\n let j;\n let name;\n let rules = this.value.eval(context);\n\n for (i = 0; i < this.lookups.length; i++) {\n name = this.lookups[i];\n\n /**\n * Eval'd DRs return rulesets.\n * Eval'd mixins return rules, so let's make a ruleset if we need it.\n * We need to do this because of late parsing of values\n */\n if (Array.isArray(rules)) {\n rules = new Ruleset([new Selector()], rules);\n }\n\n if (name === '') {\n rules = rules.lastDeclaration();\n }\n else if (name.charAt(0) === '@') {\n if (name.charAt(1) === '@') {\n name = `@${new Variable(name.substr(1)).eval(context).value}`;\n }\n if (rules.variables) {\n rules = rules.variable(name);\n }\n \n if (!rules) {\n throw { type: 'Name',\n message: `variable ${name} not found`,\n filename: this.fileInfo().filename,\n index: this.getIndex() };\n }\n }\n else {\n if (name.substring(0, 2) === '$@') {\n name = `$${new Variable(name.substr(1)).eval(context).value}`;\n }\n else {\n name = name.charAt(0) === '$' ? name : `$${name}`;\n }\n if (rules.properties) {\n rules = rules.property(name);\n }\n \n if (!rules) {\n throw { type: 'Name',\n message: `property \"${name.substr(1)}\" not found`,\n filename: this.fileInfo().filename,\n index: this.getIndex() };\n }\n // Properties are an array of values, since a ruleset can have multiple props.\n // We pick the last one (the \"cascaded\" value)\n rules = rules[rules.length - 1];\n }\n\n if (rules.value) {\n rules = rules.eval(context).value;\n }\n if (rules.ruleset) {\n rules = rules.ruleset.eval(context);\n }\n }\n return rules;\n }\n}\n\nNamespaceValue.prototype.type = 'NamespaceValue';\nexport default NamespaceValue;\n","import Selector from './selector';\nimport Element from './element';\nimport Ruleset from './ruleset';\nimport Declaration from './declaration';\nimport DetachedRuleset from './detached-ruleset';\nimport Expression from './expression';\nimport contexts from '../contexts';\nimport * as utils from '../utils';\n\nclass Definition extends Ruleset {\n constructor(name, params, rules, condition, variadic, frames, visibilityInfo) {\n super();\n\n this.name = name || 'anonymous mixin';\n this.selectors = [new Selector([new Element(null, name, false, this._index, this._fileInfo)])];\n this.params = params;\n this.condition = condition;\n this.variadic = variadic;\n this.arity = params.length;\n this.rules = rules;\n this._lookups = {};\n const optionalParameters = [];\n this.required = params.reduce((count, p) => {\n if (!p.name || (p.name && !p.value)) {\n return count + 1;\n }\n else {\n optionalParameters.push(p.name);\n return count;\n }\n }, 0);\n this.optionalParameters = optionalParameters;\n this.frames = frames;\n this.copyVisibilityInfo(visibilityInfo);\n this.allowRoot = true;\n }\n\n accept(visitor) {\n if (this.params && this.params.length) {\n this.params = visitor.visitArray(this.params);\n }\n this.rules = visitor.visitArray(this.rules);\n if (this.condition) {\n this.condition = visitor.visit(this.condition);\n }\n }\n\n evalParams(context, mixinEnv, args, evaldArguments) {\n /* jshint boss:true */\n const frame = new Ruleset(null, null);\n\n let varargs;\n let arg;\n const params = utils.copyArray(this.params);\n let i;\n let j;\n let val;\n let name;\n let isNamedFound;\n let argIndex;\n let argsLength = 0;\n\n if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) {\n frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit();\n }\n mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames));\n\n if (args) {\n args = utils.copyArray(args);\n argsLength = args.length;\n\n for (i = 0; i < argsLength; i++) {\n arg = args[i];\n if (name = (arg && arg.name)) {\n isNamedFound = false;\n for (j = 0; j < params.length; j++) {\n if (!evaldArguments[j] && name === params[j].name) {\n evaldArguments[j] = arg.value.eval(context);\n frame.prependRule(new Declaration(name, arg.value.eval(context)));\n isNamedFound = true;\n break;\n }\n }\n if (isNamedFound) {\n args.splice(i, 1);\n i--;\n continue;\n } else {\n throw { type: 'Runtime', message: `Named argument for ${this.name} ${args[i].name} not found` };\n }\n }\n }\n }\n argIndex = 0;\n for (i = 0; i < params.length; i++) {\n if (evaldArguments[i]) { continue; }\n\n arg = args && args[argIndex];\n\n if (name = params[i].name) {\n if (params[i].variadic) {\n varargs = [];\n for (j = argIndex; j < argsLength; j++) {\n varargs.push(args[j].value.eval(context));\n }\n frame.prependRule(new Declaration(name, new Expression(varargs).eval(context)));\n } else {\n val = arg && arg.value;\n if (val) {\n // This was a mixin call, pass in a detached ruleset of it's eval'd rules\n if (Array.isArray(val)) {\n val = new DetachedRuleset(new Ruleset('', val));\n }\n else {\n val = val.eval(context);\n }\n } else if (params[i].value) {\n val = params[i].value.eval(mixinEnv);\n frame.resetCache();\n } else {\n throw { type: 'Runtime', message: `wrong number of arguments for ${this.name} (${argsLength} for ${this.arity})` };\n }\n\n frame.prependRule(new Declaration(name, val));\n evaldArguments[i] = val;\n }\n }\n\n if (params[i].variadic && args) {\n for (j = argIndex; j < argsLength; j++) {\n evaldArguments[j] = args[j].value.eval(context);\n }\n }\n argIndex++;\n }\n\n return frame;\n }\n\n makeImportant() {\n const rules = !this.rules ? this.rules : this.rules.map(r => {\n if (r.makeImportant) {\n return r.makeImportant(true);\n } else {\n return r;\n }\n });\n const result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames);\n return result;\n }\n\n eval(context) {\n return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || utils.copyArray(context.frames));\n }\n\n evalCall(context, args, important) {\n const _arguments = [];\n const mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames;\n const frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments);\n let rules;\n let ruleset;\n\n frame.prependRule(new Declaration('@arguments', new Expression(_arguments).eval(context)));\n\n rules = utils.copyArray(this.rules);\n\n ruleset = new Ruleset(null, rules);\n ruleset.originalRuleset = this;\n ruleset = ruleset.eval(new contexts.Eval(context, [this, frame].concat(mixinFrames)));\n if (important) {\n ruleset = ruleset.makeImportant();\n }\n return ruleset;\n }\n\n matchCondition(args, context) {\n if (this.condition && !this.condition.eval(\n new contexts.Eval(context,\n [this.evalParams(context, /* the parameter variables */\n new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])]\n .concat(this.frames || []) // the parent namespace/mixin frames\n .concat(context.frames)))) { // the current environment frames\n return false;\n }\n return true;\n }\n\n matchArgs(args, context) {\n const allArgsCnt = (args && args.length) || 0;\n let len;\n const optionalParameters = this.optionalParameters;\n const requiredArgsCnt = !args ? 0 : args.reduce((count, p) => {\n if (optionalParameters.indexOf(p.name) < 0) {\n return count + 1;\n } else {\n return count;\n }\n }, 0);\n\n if (!this.variadic) {\n if (requiredArgsCnt < this.required) {\n return false;\n }\n if (allArgsCnt > this.params.length) {\n return false;\n }\n } else {\n if (requiredArgsCnt < (this.required - 1)) {\n return false;\n }\n }\n\n // check patterns\n len = Math.min(requiredArgsCnt, this.arity);\n\n for (let i = 0; i < len; i++) {\n if (!this.params[i].name && !this.params[i].variadic) {\n if (args[i].value.eval(context).toCSS() != this.params[i].value.eval(context).toCSS()) {\n return false;\n }\n }\n }\n return true;\n }\n}\n\nDefinition.prototype.type = 'MixinDefinition';\nDefinition.prototype.evalFirst = true;\nexport default Definition;\n","import Node from './node';\nimport Selector from './selector';\nimport MixinDefinition from './mixin-definition';\nimport defaultFunc from '../functions/default';\n\nclass MixinCall extends Node {\n constructor(elements, args, index, currentFileInfo, important) {\n super();\n\n this.selector = new Selector(elements);\n this.arguments = args || [];\n this._index = index;\n this._fileInfo = currentFileInfo;\n this.important = important;\n this.allowRoot = true;\n this.setParent(this.selector, this);\n }\n\n accept(visitor) {\n if (this.selector) {\n this.selector = visitor.visit(this.selector);\n }\n if (this.arguments.length) {\n this.arguments = visitor.visitArray(this.arguments);\n }\n }\n\n eval(context) {\n let mixins;\n let mixin;\n let mixinPath;\n const args = [];\n let arg;\n let argValue;\n const rules = [];\n let match = false;\n let i;\n let m;\n let f;\n let isRecursive;\n let isOneFound;\n const candidates = [];\n let candidate;\n const conditionResult = [];\n let defaultResult;\n const defFalseEitherCase = -1;\n const defNone = 0;\n const defTrue = 1;\n const defFalse = 2;\n let count;\n let originalRuleset;\n let noArgumentsFilter;\n\n this.selector = this.selector.eval(context);\n\n function calcDefGroup(mixin, mixinPath) {\n let f;\n let p;\n let namespace;\n\n for (f = 0; f < 2; f++) {\n conditionResult[f] = true;\n defaultFunc.value(f);\n for (p = 0; p < mixinPath.length && conditionResult[f]; p++) {\n namespace = mixinPath[p];\n if (namespace.matchCondition) {\n conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, context);\n }\n }\n if (mixin.matchCondition) {\n conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, context);\n }\n }\n if (conditionResult[0] || conditionResult[1]) {\n if (conditionResult[0] != conditionResult[1]) {\n return conditionResult[1] ?\n defTrue : defFalse;\n }\n\n return defNone;\n }\n return defFalseEitherCase;\n }\n\n for (i = 0; i < this.arguments.length; i++) {\n arg = this.arguments[i];\n argValue = arg.value.eval(context);\n if (arg.expand && Array.isArray(argValue.value)) {\n argValue = argValue.value;\n for (m = 0; m < argValue.length; m++) {\n args.push({value: argValue[m]});\n }\n } else {\n args.push({name: arg.name, value: argValue});\n }\n }\n\n noArgumentsFilter = rule => rule.matchArgs(null, context);\n\n for (i = 0; i < context.frames.length; i++) {\n if ((mixins = context.frames[i].find(this.selector, null, noArgumentsFilter)).length > 0) {\n isOneFound = true;\n\n // To make `default()` function independent of definition order we have two \"subpasses\" here.\n // At first we evaluate each guard *twice* (with `default() == true` and `default() == false`),\n // and build candidate list with corresponding flags. Then, when we know all possible matches,\n // we make a final decision.\n\n for (m = 0; m < mixins.length; m++) {\n mixin = mixins[m].rule;\n mixinPath = mixins[m].path;\n isRecursive = false;\n for (f = 0; f < context.frames.length; f++) {\n if ((!(mixin instanceof MixinDefinition)) && mixin === (context.frames[f].originalRuleset || context.frames[f])) {\n isRecursive = true;\n break;\n }\n }\n if (isRecursive) {\n continue;\n }\n\n if (mixin.matchArgs(args, context)) {\n candidate = {mixin, group: calcDefGroup(mixin, mixinPath)};\n\n if (candidate.group !== defFalseEitherCase) {\n candidates.push(candidate);\n }\n\n match = true;\n }\n }\n\n defaultFunc.reset();\n\n count = [0, 0, 0];\n for (m = 0; m < candidates.length; m++) {\n count[candidates[m].group]++;\n }\n\n if (count[defNone] > 0) {\n defaultResult = defFalse;\n } else {\n defaultResult = defTrue;\n if ((count[defTrue] + count[defFalse]) > 1) {\n throw { type: 'Runtime',\n message: `Ambiguous use of \\`default()\\` found when matching for \\`${this.format(args)}\\``,\n index: this.getIndex(), filename: this.fileInfo().filename };\n }\n }\n\n for (m = 0; m < candidates.length; m++) {\n candidate = candidates[m].group;\n if ((candidate === defNone) || (candidate === defaultResult)) {\n try {\n mixin = candidates[m].mixin;\n if (!(mixin instanceof MixinDefinition)) {\n originalRuleset = mixin.originalRuleset || mixin;\n mixin = new MixinDefinition('', [], mixin.rules, null, false, null, originalRuleset.visibilityInfo());\n mixin.originalRuleset = originalRuleset;\n }\n const newRules = mixin.evalCall(context, args, this.important).rules;\n this._setVisibilityToReplacement(newRules);\n Array.prototype.push.apply(rules, newRules);\n } catch (e) {\n throw { message: e.message, index: this.getIndex(), filename: this.fileInfo().filename, stack: e.stack };\n }\n }\n }\n\n if (match) {\n return rules;\n }\n }\n }\n if (isOneFound) {\n throw { type: 'Runtime',\n message: `No matching definition was found for \\`${this.format(args)}\\``,\n index: this.getIndex(), filename: this.fileInfo().filename };\n } else {\n throw { type: 'Name',\n message: `${this.selector.toCSS().trim()} is undefined`,\n index: this.getIndex(), filename: this.fileInfo().filename };\n }\n }\n\n _setVisibilityToReplacement(replacement) {\n let i;\n let rule;\n if (this.blocksVisibility()) {\n for (i = 0; i < replacement.length; i++) {\n rule = replacement[i];\n rule.addVisibilityBlock();\n }\n }\n }\n\n format(args) {\n return `${this.selector.toCSS().trim()}(${args ? args.map(a => {\n let argValue = '';\n if (a.name) {\n argValue += `${a.name}:`;\n }\n if (a.value.toCSS) {\n argValue += a.value.toCSS();\n } else {\n argValue += '???';\n }\n return argValue;\n }).join(', ') : ''})`;\n }\n}\n\nMixinCall.prototype.type = 'MixinCall';\nexport default MixinCall;\n","const tree = Object.create(null);\n\nimport Node from './node';\nimport Color from './color';\nimport AtRule from './atrule';\nimport DetachedRuleset from './detached-ruleset';\nimport Operation from './operation';\nimport Dimension from './dimension';\nimport Unit from './unit';\nimport Keyword from './keyword';\nimport Variable from './variable';\nimport Property from './property';\nimport Ruleset from './ruleset';\nimport Element from './element';\nimport Attribute from './attribute';\nimport Combinator from './combinator';\nimport Selector from './selector';\nimport Quoted from './quoted';\nimport Expression from './expression';\nimport Declaration from './declaration';\nimport Call from './call';\nimport URL from './url';\nimport Import from './import';\nimport Comment from './comment';\nimport Anonymous from './anonymous';\nimport Value from './value';\nimport JavaScript from './javascript';\nimport Assignment from './assignment';\nimport Condition from './condition';\nimport Paren from './paren';\nimport Media from './media';\nimport UnicodeDescriptor from './unicode-descriptor';\nimport Negative from './negative';\nimport Extend from './extend';\nimport VariableCall from './variable-call';\nimport NamespaceValue from './namespace-value';\n\n// mixins\nimport MixinCall from './mixin-call';\nimport MixinDefinition from './mixin-definition';\n\nexport default {\n Node, Color, AtRule, DetachedRuleset, Operation,\n Dimension, Unit, Keyword, Variable, Property,\n Ruleset, Element, Attribute, Combinator, Selector,\n Quoted, Expression, Declaration, Call, URL, Import,\n Comment, Anonymous, Value, JavaScript, Assignment,\n Condition, Paren, Media, UnicodeDescriptor, Negative,\n Extend, VariableCall, NamespaceValue,\n mixin: {\n Call: MixinCall,\n Definition: MixinDefinition\n }\n};","export default {\n error: function(msg) {\n this._fireEvent('error', msg);\n },\n warn: function(msg) {\n this._fireEvent('warn', msg);\n },\n info: function(msg) {\n this._fireEvent('info', msg);\n },\n debug: function(msg) {\n this._fireEvent('debug', msg);\n },\n addListener: function(listener) {\n this._listeners.push(listener);\n },\n removeListener: function(listener) {\n for (let i = 0; i < this._listeners.length; i++) {\n if (this._listeners[i] === listener) {\n this._listeners.splice(i, 1);\n return;\n }\n }\n },\n _fireEvent: function(type, msg) {\n for (let i = 0; i < this._listeners.length; i++) {\n const logFunction = this._listeners[i][type];\n if (logFunction) {\n logFunction(msg);\n }\n }\n },\n _listeners: []\n};\n","/**\n * @todo Document why this abstraction exists, and the relationship between\n * environment, file managers, and plugin manager\n */\n\nimport logger from '../logger';\n\nclass environment {\n constructor(externalEnvironment, fileManagers) {\n this.fileManagers = fileManagers || [];\n externalEnvironment = externalEnvironment || {};\n\n const optionalFunctions = ['encodeBase64', 'mimeLookup', 'charsetLookup', 'getSourceMapGenerator'];\n const requiredFunctions = [];\n const functions = requiredFunctions.concat(optionalFunctions);\n\n for (let i = 0; i < functions.length; i++) {\n const propName = functions[i];\n const environmentFunc = externalEnvironment[propName];\n if (environmentFunc) {\n this[propName] = environmentFunc.bind(externalEnvironment);\n } else if (i < requiredFunctions.length) {\n this.warn(`missing required function in environment - ${propName}`);\n }\n }\n }\n\n getFileManager(filename, currentDirectory, options, environment, isSync) {\n\n if (!filename) {\n logger.warn('getFileManager called with no filename.. Please report this issue. continuing.');\n }\n if (currentDirectory == null) {\n logger.warn('getFileManager called with null directory.. Please report this issue. continuing.');\n }\n\n let fileManagers = this.fileManagers;\n if (options.pluginManager) {\n fileManagers = [].concat(fileManagers).concat(options.pluginManager.getFileManagers());\n }\n for (let i = fileManagers.length - 1; i >= 0 ; i--) {\n const fileManager = fileManagers[i];\n if (fileManager[isSync ? 'supportsSync' : 'supports'](filename, currentDirectory, options, environment)) {\n return fileManager;\n }\n }\n return null;\n }\n\n addFileManager(fileManager) {\n this.fileManagers.push(fileManager);\n }\n\n clearFileManagers() {\n this.fileManagers = [];\n }\n}\n\nexport default environment;\n","class AbstractFileManager {\n getPath(filename) {\n let j = filename.lastIndexOf('?');\n if (j > 0) {\n filename = filename.slice(0, j);\n }\n j = filename.lastIndexOf('/');\n if (j < 0) {\n j = filename.lastIndexOf('\\\\');\n }\n if (j < 0) {\n return '';\n }\n return filename.slice(0, j + 1);\n }\n\n tryAppendExtension(path, ext) {\n return /(\\.[a-z]*$)|([\\?;].*)$/.test(path) ? path : path + ext;\n }\n\n tryAppendLessExtension(path) {\n return this.tryAppendExtension(path, '.less');\n };\n\n supportsSync() { return false; }\n\n alwaysMakePathsAbsolute() { return false; }\n\n isPathAbsolute(filename) {\n return (/^(?:[a-z-]+:|\\/|\\\\|#)/i).test(filename);\n }\n // TODO: pull out / replace?\n join(basePath, laterPath) {\n if (!basePath) {\n return laterPath;\n }\n return basePath + laterPath;\n };\n\n pathDiff(url, baseUrl) {\n // diff between two paths to create a relative path\n const urlParts = this.extractUrlParts(url);\n const baseUrlParts = this.extractUrlParts(baseUrl);\n\n let i;\n let max;\n let urlDirectories;\n let baseUrlDirectories;\n let diff = '';\n if (urlParts.hostPart !== baseUrlParts.hostPart) {\n return '';\n }\n max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);\n for (i = 0; i < max; i++) {\n if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; }\n }\n baseUrlDirectories = baseUrlParts.directories.slice(i);\n urlDirectories = urlParts.directories.slice(i);\n for (i = 0; i < baseUrlDirectories.length - 1; i++) {\n diff += '../';\n }\n for (i = 0; i < urlDirectories.length - 1; i++) {\n diff += `${urlDirectories[i]}/`;\n }\n return diff;\n };\n // helper function, not part of API\n extractUrlParts(url, baseUrl) {\n // urlParts[1] = protocol://hostname/ OR /\n // urlParts[2] = / if path relative to host base\n // urlParts[3] = directories\n // urlParts[4] = filename\n // urlParts[5] = parameters\n\n const urlPartsRegex = /^((?:[a-z-]+:)?\\/{2}(?:[^\\/\\?#]*\\/)|([\\/\\\\]))?((?:[^\\/\\\\\\?#]*[\\/\\\\])*)([^\\/\\\\\\?#]*)([#\\?].*)?$/i;\n\n const urlParts = url.match(urlPartsRegex);\n const returner = {};\n let rawDirectories = [];\n const directories = [];\n let i;\n let baseUrlParts;\n\n if (!urlParts) {\n throw new Error(`Could not parse sheet href - '${url}'`);\n }\n\n // Stylesheets in IE don't always return the full path\n if (baseUrl && (!urlParts[1] || urlParts[2])) {\n baseUrlParts = baseUrl.match(urlPartsRegex);\n if (!baseUrlParts) {\n throw new Error(`Could not parse page url - '${baseUrl}'`);\n }\n urlParts[1] = urlParts[1] || baseUrlParts[1] || '';\n if (!urlParts[2]) {\n urlParts[3] = baseUrlParts[3] + urlParts[3];\n }\n }\n\n if (urlParts[3]) {\n rawDirectories = urlParts[3].replace(/\\\\/g, '/').split('/');\n\n // collapse '..' and skip '.'\n for (i = 0; i < rawDirectories.length; i++) {\n\n if (rawDirectories[i] === '..') {\n directories.pop();\n }\n else if (rawDirectories[i] !== '.') {\n directories.push(rawDirectories[i]);\n }\n \n }\n }\n\n returner.hostPart = urlParts[1];\n returner.directories = directories;\n returner.rawPath = (urlParts[1] || '') + rawDirectories.join('/');\n returner.path = (urlParts[1] || '') + directories.join('/');\n returner.filename = urlParts[4];\n returner.fileUrl = returner.path + (urlParts[4] || '');\n returner.url = returner.fileUrl + (urlParts[5] || '');\n return returner;\n };\n}\n\nexport default AbstractFileManager;\n","import functionRegistry from '../functions/function-registry';\nimport LessError from '../less-error';\n\nclass AbstractPluginLoader {\n constructor() {\n // Implemented by Node.js plugin loader\n this.require = () => null\n }\n\n evalPlugin(contents, context, imports, pluginOptions, fileInfo) {\n let loader;\n let registry;\n let pluginObj;\n let localModule;\n let pluginManager;\n let filename;\n let result;\n\n pluginManager = context.pluginManager;\n\n if (fileInfo) {\n if (typeof fileInfo === 'string') {\n filename = fileInfo;\n }\n else {\n filename = fileInfo.filename;\n }\n }\n const shortname = (new this.less.FileManager()).extractUrlParts(filename).filename;\n\n if (filename) {\n pluginObj = pluginManager.get(filename);\n\n if (pluginObj) {\n result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions);\n if (result) {\n return result;\n }\n try {\n if (pluginObj.use) {\n pluginObj.use.call(this.context, pluginObj);\n }\n }\n catch (e) {\n e.message = e.message || 'Error during @plugin call';\n return new LessError(e, imports, filename);\n }\n return pluginObj;\n }\n }\n localModule = {\n exports: {},\n pluginManager,\n fileInfo\n };\n registry = functionRegistry.create();\n\n const registerPlugin = obj => {\n pluginObj = obj;\n };\n\n try {\n loader = new Function('module', 'require', 'registerPlugin', 'functions', 'tree', 'less', 'fileInfo', contents);\n loader(localModule, this.require(filename), registerPlugin, registry, this.less.tree, this.less, fileInfo);\n }\n catch (e) {\n return new LessError(e, imports, filename);\n }\n\n if (!pluginObj) {\n pluginObj = localModule.exports;\n }\n pluginObj = this.validatePlugin(pluginObj, filename, shortname);\n\n if (pluginObj instanceof LessError) {\n return pluginObj;\n }\n\n if (pluginObj) {\n pluginObj.imports = imports;\n pluginObj.filename = filename;\n\n // For < 3.x (or unspecified minVersion) - setOptions() before install()\n if (!pluginObj.minVersion || this.compareVersion('3.0.0', pluginObj.minVersion) < 0) {\n result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions);\n\n if (result) {\n return result;\n }\n }\n\n // Run on first load\n pluginManager.addPlugin(pluginObj, fileInfo.filename, registry);\n pluginObj.functions = registry.getLocalFunctions();\n\n // Need to call setOptions again because the pluginObj might have functions\n result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions);\n if (result) {\n return result;\n }\n\n // Run every @plugin call\n try {\n if (pluginObj.use) {\n pluginObj.use.call(this.context, pluginObj);\n }\n }\n catch (e) {\n e.message = e.message || 'Error during @plugin call';\n return new LessError(e, imports, filename);\n }\n\n }\n else {\n return new LessError({ message: 'Not a valid plugin' }, imports, filename);\n }\n\n return pluginObj;\n }\n\n trySetOptions(plugin, filename, name, options) {\n if (options && !plugin.setOptions) {\n return new LessError({\n message: `Options have been provided but the plugin ${name} does not support any options.`\n });\n }\n try {\n plugin.setOptions && plugin.setOptions(options);\n }\n catch (e) {\n return new LessError(e);\n }\n }\n\n validatePlugin(plugin, filename, name) {\n if (plugin) {\n // support plugins being a function\n // so that the plugin can be more usable programmatically\n if (typeof plugin === 'function') {\n plugin = new plugin();\n }\n\n if (plugin.minVersion) {\n if (this.compareVersion(plugin.minVersion, this.less.version) < 0) {\n return new LessError({\n message: `Plugin ${name} requires version ${this.versionToString(plugin.minVersion)}`\n });\n }\n }\n return plugin;\n }\n return null;\n }\n\n compareVersion(aVersion, bVersion) {\n if (typeof aVersion === 'string') {\n aVersion = aVersion.match(/^(\\d+)\\.?(\\d+)?\\.?(\\d+)?/);\n aVersion.shift();\n }\n for (let i = 0; i < aVersion.length; i++) {\n if (aVersion[i] !== bVersion[i]) {\n return parseInt(aVersion[i]) > parseInt(bVersion[i]) ? -1 : 1;\n }\n }\n return 0;\n }\n\n versionToString(version) {\n let versionString = '';\n for (let i = 0; i < version.length; i++) {\n versionString += (versionString ? '.' : '') + version[i];\n }\n return versionString;\n }\n\n printUsage(plugins) {\n for (let i = 0; i < plugins.length; i++) {\n const plugin = plugins[i];\n if (plugin.printUsage) {\n plugin.printUsage();\n }\n }\n }\n}\n\nexport default AbstractPluginLoader;\n\n","import tree from '../tree';\nconst _visitArgs = { visitDeeper: true };\nlet _hasIndexed = false;\n\nfunction _noop(node) {\n return node;\n}\n\nfunction indexNodeTypes(parent, ticker) {\n // add .typeIndex to tree node types for lookup table\n let key;\n\n let child;\n for (key in parent) { \n /* eslint guard-for-in: 0 */\n child = parent[key];\n switch (typeof child) {\n case 'function':\n // ignore bound functions directly on tree which do not have a prototype\n // or aren't nodes\n if (child.prototype && child.prototype.type) {\n child.prototype.typeIndex = ticker++;\n }\n break;\n case 'object':\n ticker = indexNodeTypes(child, ticker);\n break;\n \n }\n }\n return ticker;\n}\n\nclass Visitor {\n constructor(implementation) {\n this._implementation = implementation;\n this._visitInCache = {};\n this._visitOutCache = {};\n\n if (!_hasIndexed) {\n indexNodeTypes(tree, 1);\n _hasIndexed = true;\n }\n }\n\n visit(node) {\n if (!node) {\n return node;\n }\n\n const nodeTypeIndex = node.typeIndex;\n if (!nodeTypeIndex) {\n // MixinCall args aren't a node type?\n if (node.value && node.value.typeIndex) {\n this.visit(node.value);\n }\n return node;\n }\n\n const impl = this._implementation;\n let func = this._visitInCache[nodeTypeIndex];\n let funcOut = this._visitOutCache[nodeTypeIndex];\n const visitArgs = _visitArgs;\n let fnName;\n\n visitArgs.visitDeeper = true;\n\n if (!func) {\n fnName = `visit${node.type}`;\n func = impl[fnName] || _noop;\n funcOut = impl[`${fnName}Out`] || _noop;\n this._visitInCache[nodeTypeIndex] = func;\n this._visitOutCache[nodeTypeIndex] = funcOut;\n }\n\n if (func !== _noop) {\n const newNode = func.call(impl, node, visitArgs);\n if (node && impl.isReplacing) {\n node = newNode;\n }\n }\n\n if (visitArgs.visitDeeper && node && node.accept) {\n node.accept(this);\n }\n\n if (funcOut != _noop) {\n funcOut.call(impl, node);\n }\n\n return node;\n }\n\n visitArray(nodes, nonReplacing) {\n if (!nodes) {\n return nodes;\n }\n\n const cnt = nodes.length;\n let i;\n\n // Non-replacing\n if (nonReplacing || !this._implementation.isReplacing) {\n for (i = 0; i < cnt; i++) {\n this.visit(nodes[i]);\n }\n return nodes;\n }\n\n // Replacing\n const out = [];\n for (i = 0; i < cnt; i++) {\n const evald = this.visit(nodes[i]);\n if (evald === undefined) { continue; }\n if (!evald.splice) {\n out.push(evald);\n } else if (evald.length) {\n this.flatten(evald, out);\n }\n }\n return out;\n }\n\n flatten(arr, out) {\n if (!out) {\n out = [];\n }\n\n let cnt;\n let i;\n let item;\n let nestedCnt;\n let j;\n let nestedItem;\n\n for (i = 0, cnt = arr.length; i < cnt; i++) {\n item = arr[i];\n if (item === undefined) {\n continue;\n }\n if (!item.splice) {\n out.push(item);\n continue;\n }\n\n for (j = 0, nestedCnt = item.length; j < nestedCnt; j++) {\n nestedItem = item[j];\n if (nestedItem === undefined) {\n continue;\n }\n if (!nestedItem.splice) {\n out.push(nestedItem);\n } else if (nestedItem.length) {\n this.flatten(nestedItem, out);\n }\n }\n }\n\n return out;\n }\n}\n\nexport default Visitor;\n","class ImportSequencer {\n constructor(onSequencerEmpty) {\n this.imports = [];\n this.variableImports = [];\n this._onSequencerEmpty = onSequencerEmpty;\n this._currentDepth = 0;\n }\n\n addImport(callback) {\n const importSequencer = this;\n\n const importItem = {\n callback,\n args: null,\n isReady: false\n };\n\n this.imports.push(importItem);\n return function(...args) {\n importItem.args = Array.prototype.slice.call(args, 0);\n importItem.isReady = true;\n importSequencer.tryRun();\n };\n }\n\n addVariableImport(callback) {\n this.variableImports.push(callback);\n }\n\n tryRun() {\n this._currentDepth++;\n try {\n while (true) {\n while (this.imports.length > 0) {\n const importItem = this.imports[0];\n if (!importItem.isReady) {\n return;\n }\n this.imports = this.imports.slice(1);\n importItem.callback.apply(null, importItem.args);\n }\n if (this.variableImports.length === 0) {\n break;\n }\n const variableImport = this.variableImports[0];\n this.variableImports = this.variableImports.slice(1);\n variableImport();\n }\n } finally {\n this._currentDepth--;\n }\n if (this._currentDepth === 0 && this._onSequencerEmpty) {\n this._onSequencerEmpty();\n }\n }\n}\n\nexport default ImportSequencer;\n","import contexts from '../contexts';\nimport Visitor from './visitor';\nimport ImportSequencer from './import-sequencer';\nimport * as utils from '../utils';\n\nconst ImportVisitor = function(importer, finish) {\n\n this._visitor = new Visitor(this);\n this._importer = importer;\n this._finish = finish;\n this.context = new contexts.Eval();\n this.importCount = 0;\n this.onceFileDetectionMap = {};\n this.recursionDetector = {};\n this._sequencer = new ImportSequencer(this._onSequencerEmpty.bind(this));\n};\n\nImportVisitor.prototype = {\n isReplacing: false,\n run: function (root) {\n try {\n // process the contents\n this._visitor.visit(root);\n }\n catch (e) {\n this.error = e;\n }\n\n this.isFinished = true;\n this._sequencer.tryRun();\n },\n _onSequencerEmpty: function() {\n if (!this.isFinished) {\n return;\n }\n this._finish(this.error);\n },\n visitImport: function (importNode, visitArgs) {\n const inlineCSS = importNode.options.inline;\n\n if (!importNode.css || inlineCSS) {\n\n const context = new contexts.Eval(this.context, utils.copyArray(this.context.frames));\n const importParent = context.frames[0];\n\n this.importCount++;\n if (importNode.isVariableImport()) {\n this._sequencer.addVariableImport(this.processImportNode.bind(this, importNode, context, importParent));\n } else {\n this.processImportNode(importNode, context, importParent);\n }\n }\n visitArgs.visitDeeper = false;\n },\n processImportNode: function(importNode, context, importParent) {\n let evaldImportNode;\n const inlineCSS = importNode.options.inline;\n\n try {\n evaldImportNode = importNode.evalForImport(context);\n } catch (e) {\n if (!e.filename) { e.index = importNode.getIndex(); e.filename = importNode.fileInfo().filename; }\n // attempt to eval properly and treat as css\n importNode.css = true;\n // if that fails, this error will be thrown\n importNode.error = e;\n }\n\n if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) {\n if (evaldImportNode.options.multiple) {\n context.importMultiple = true;\n }\n\n // try appending if we haven't determined if it is css or not\n const tryAppendLessExtension = evaldImportNode.css === undefined;\n\n for (let i = 0; i < importParent.rules.length; i++) {\n if (importParent.rules[i] === importNode) {\n importParent.rules[i] = evaldImportNode;\n break;\n }\n }\n\n const onImported = this.onImported.bind(this, evaldImportNode, context);\n const sequencedOnImported = this._sequencer.addImport(onImported);\n\n this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.fileInfo(),\n evaldImportNode.options, sequencedOnImported);\n } else {\n this.importCount--;\n if (this.isFinished) {\n this._sequencer.tryRun();\n }\n }\n },\n onImported: function (importNode, context, e, root, importedAtRoot, fullPath) {\n if (e) {\n if (!e.filename) {\n e.index = importNode.getIndex(); e.filename = importNode.fileInfo().filename;\n }\n this.error = e;\n }\n\n const importVisitor = this;\n const inlineCSS = importNode.options.inline;\n const isPlugin = importNode.options.isPlugin;\n const isOptional = importNode.options.optional;\n const duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector;\n\n if (!context.importMultiple) {\n if (duplicateImport) {\n importNode.skip = true;\n } else {\n importNode.skip = () => {\n if (fullPath in importVisitor.onceFileDetectionMap) {\n return true;\n }\n importVisitor.onceFileDetectionMap[fullPath] = true;\n return false;\n };\n }\n }\n\n if (!fullPath && isOptional) {\n importNode.skip = true;\n }\n\n if (root) {\n importNode.root = root;\n importNode.importedFilename = fullPath;\n\n if (!inlineCSS && !isPlugin && (context.importMultiple || !duplicateImport)) {\n importVisitor.recursionDetector[fullPath] = true;\n\n const oldContext = this.context;\n this.context = context;\n try {\n this._visitor.visit(root);\n } catch (e) {\n this.error = e;\n }\n this.context = oldContext;\n }\n }\n\n importVisitor.importCount--;\n\n if (importVisitor.isFinished) {\n importVisitor._sequencer.tryRun();\n }\n },\n visitDeclaration: function (declNode, visitArgs) {\n if (declNode.value.type === 'DetachedRuleset') {\n this.context.frames.unshift(declNode);\n } else {\n visitArgs.visitDeeper = false;\n }\n },\n visitDeclarationOut: function(declNode) {\n if (declNode.value.type === 'DetachedRuleset') {\n this.context.frames.shift();\n }\n },\n visitAtRule: function (atRuleNode, visitArgs) {\n this.context.frames.unshift(atRuleNode);\n },\n visitAtRuleOut: function (atRuleNode) {\n this.context.frames.shift();\n },\n visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {\n this.context.frames.unshift(mixinDefinitionNode);\n },\n visitMixinDefinitionOut: function (mixinDefinitionNode) {\n this.context.frames.shift();\n },\n visitRuleset: function (rulesetNode, visitArgs) {\n this.context.frames.unshift(rulesetNode);\n },\n visitRulesetOut: function (rulesetNode) {\n this.context.frames.shift();\n },\n visitMedia: function (mediaNode, visitArgs) {\n this.context.frames.unshift(mediaNode.rules[0]);\n },\n visitMediaOut: function (mediaNode) {\n this.context.frames.shift();\n }\n};\nexport default ImportVisitor;\n","class SetTreeVisibilityVisitor {\n constructor(visible) {\n this.visible = visible;\n }\n\n run(root) {\n this.visit(root);\n }\n\n visitArray(nodes) {\n if (!nodes) {\n return nodes;\n }\n\n const cnt = nodes.length;\n let i;\n for (i = 0; i < cnt; i++) {\n this.visit(nodes[i]);\n }\n return nodes;\n }\n\n visit(node) {\n if (!node) {\n return node;\n }\n if (node.constructor === Array) {\n return this.visitArray(node);\n }\n\n if (!node.blocksVisibility || node.blocksVisibility()) {\n return node;\n }\n if (this.visible) {\n node.ensureVisibility();\n } else {\n node.ensureInvisibility();\n }\n\n node.accept(this);\n return node;\n }\n}\n\nexport default SetTreeVisibilityVisitor;","import tree from '../tree';\nimport Visitor from './visitor';\nimport logger from '../logger';\nimport * as utils from '../utils';\n\n/* jshint loopfunc:true */\n\nclass ExtendFinderVisitor {\n constructor() {\n this._visitor = new Visitor(this);\n this.contexts = [];\n this.allExtendsStack = [[]];\n }\n\n run(root) {\n root = this._visitor.visit(root);\n root.allExtends = this.allExtendsStack[0];\n return root;\n }\n\n visitDeclaration(declNode, visitArgs) {\n visitArgs.visitDeeper = false;\n }\n\n visitMixinDefinition(mixinDefinitionNode, visitArgs) {\n visitArgs.visitDeeper = false;\n }\n\n visitRuleset(rulesetNode, visitArgs) {\n if (rulesetNode.root) {\n return;\n }\n\n let i;\n let j;\n let extend;\n const allSelectorsExtendList = [];\n let extendList;\n\n // get &:extend(.a); rules which apply to all selectors in this ruleset\n const rules = rulesetNode.rules;\n\n const ruleCnt = rules ? rules.length : 0;\n for (i = 0; i < ruleCnt; i++) {\n if (rulesetNode.rules[i] instanceof tree.Extend) {\n allSelectorsExtendList.push(rules[i]);\n rulesetNode.extendOnEveryPath = true;\n }\n }\n\n // now find every selector and apply the extends that apply to all extends\n // and the ones which apply to an individual extend\n const paths = rulesetNode.paths;\n for (i = 0; i < paths.length; i++) {\n const selectorPath = paths[i];\n const selector = selectorPath[selectorPath.length - 1];\n const selExtendList = selector.extendList;\n\n extendList = selExtendList ? utils.copyArray(selExtendList).concat(allSelectorsExtendList)\n : allSelectorsExtendList;\n\n if (extendList) {\n extendList = extendList.map(allSelectorsExtend => allSelectorsExtend.clone());\n }\n\n for (j = 0; j < extendList.length; j++) {\n this.foundExtends = true;\n extend = extendList[j];\n extend.findSelfSelectors(selectorPath);\n extend.ruleset = rulesetNode;\n if (j === 0) { extend.firstExtendOnThisSelectorPath = true; }\n this.allExtendsStack[this.allExtendsStack.length - 1].push(extend);\n }\n }\n\n this.contexts.push(rulesetNode.selectors);\n }\n\n visitRulesetOut(rulesetNode) {\n if (!rulesetNode.root) {\n this.contexts.length = this.contexts.length - 1;\n }\n }\n\n visitMedia(mediaNode, visitArgs) {\n mediaNode.allExtends = [];\n this.allExtendsStack.push(mediaNode.allExtends);\n }\n\n visitMediaOut(mediaNode) {\n this.allExtendsStack.length = this.allExtendsStack.length - 1;\n }\n\n visitAtRule(atRuleNode, visitArgs) {\n atRuleNode.allExtends = [];\n this.allExtendsStack.push(atRuleNode.allExtends);\n }\n\n visitAtRuleOut(atRuleNode) {\n this.allExtendsStack.length = this.allExtendsStack.length - 1;\n }\n}\n\nclass ProcessExtendsVisitor {\n constructor() {\n this._visitor = new Visitor(this);\n }\n\n run(root) {\n const extendFinder = new ExtendFinderVisitor();\n this.extendIndices = {};\n extendFinder.run(root);\n if (!extendFinder.foundExtends) { return root; }\n root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));\n this.allExtendsStack = [root.allExtends];\n const newRoot = this._visitor.visit(root);\n this.checkExtendsForNonMatched(root.allExtends);\n return newRoot;\n }\n\n checkExtendsForNonMatched(extendList) {\n const indices = this.extendIndices;\n extendList.filter(extend => !extend.hasFoundMatches && extend.parent_ids.length == 1).forEach(extend => {\n let selector = '_unknown_';\n try {\n selector = extend.selector.toCSS({});\n }\n catch (_) {}\n\n if (!indices[`${extend.index} ${selector}`]) {\n indices[`${extend.index} ${selector}`] = true;\n logger.warn(`extend '${selector}' has no matches`);\n }\n });\n }\n\n doExtendChaining(extendsList, extendsListTarget, iterationCount) {\n //\n // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering\n // and pasting the selector we would do normally, but we are also adding an extend with the same target selector\n // this means this new extend can then go and alter other extends\n //\n // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors\n // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already\n // processed if we look at each selector at a time, as is done in visitRuleset\n\n let extendIndex;\n\n let targetExtendIndex;\n let matches;\n const extendsToAdd = [];\n let newSelector;\n const extendVisitor = this;\n let selectorPath;\n let extend;\n let targetExtend;\n let newExtend;\n\n iterationCount = iterationCount || 0;\n\n // loop through comparing every extend with every target extend.\n // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place\n // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one\n // and the second is the target.\n // the separation into two lists allows us to process a subset of chains with a bigger set, as is the\n // case when processing media queries\n for (extendIndex = 0; extendIndex < extendsList.length; extendIndex++) {\n for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) {\n\n extend = extendsList[extendIndex];\n targetExtend = extendsListTarget[targetExtendIndex];\n\n // look for circular references\n if ( extend.parent_ids.indexOf( targetExtend.object_id ) >= 0 ) { continue; }\n\n // find a match in the target extends self selector (the bit before :extend)\n selectorPath = [targetExtend.selfSelectors[0]];\n matches = extendVisitor.findMatch(extend, selectorPath);\n\n if (matches.length) {\n extend.hasFoundMatches = true;\n\n // we found a match, so for each self selector..\n extend.selfSelectors.forEach(selfSelector => {\n const info = targetExtend.visibilityInfo();\n\n // process the extend as usual\n newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector, extend.isVisible());\n\n // but now we create a new extend from it\n newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0, targetExtend.fileInfo(), info);\n newExtend.selfSelectors = newSelector;\n\n // add the extend onto the list of extends for that selector\n newSelector[newSelector.length - 1].extendList = [newExtend];\n\n // record that we need to add it.\n extendsToAdd.push(newExtend);\n newExtend.ruleset = targetExtend.ruleset;\n\n // remember its parents for circular references\n newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids);\n\n // only process the selector once.. if we have :extend(.a,.b) then multiple\n // extends will look at the same selector path, so when extending\n // we know that any others will be duplicates in terms of what is added to the css\n if (targetExtend.firstExtendOnThisSelectorPath) {\n newExtend.firstExtendOnThisSelectorPath = true;\n targetExtend.ruleset.paths.push(newSelector);\n }\n });\n }\n }\n }\n\n if (extendsToAdd.length) {\n // try to detect circular references to stop a stack overflow.\n // may no longer be needed.\n this.extendChainCount++;\n if (iterationCount > 100) {\n let selectorOne = '{unable to calculate}';\n let selectorTwo = '{unable to calculate}';\n try {\n selectorOne = extendsToAdd[0].selfSelectors[0].toCSS();\n selectorTwo = extendsToAdd[0].selector.toCSS();\n }\n catch (e) {}\n throw { message: `extend circular reference detected. One of the circular extends is currently:${selectorOne}:extend(${selectorTwo})`};\n }\n\n // now process the new extends on the existing rules so that we can handle a extending b extending c extending\n // d extending e...\n return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1));\n } else {\n return extendsToAdd;\n }\n }\n\n visitDeclaration(ruleNode, visitArgs) {\n visitArgs.visitDeeper = false;\n }\n\n visitMixinDefinition(mixinDefinitionNode, visitArgs) {\n visitArgs.visitDeeper = false;\n }\n\n visitSelector(selectorNode, visitArgs) {\n visitArgs.visitDeeper = false;\n }\n\n visitRuleset(rulesetNode, visitArgs) {\n if (rulesetNode.root) {\n return;\n }\n let matches;\n let pathIndex;\n let extendIndex;\n const allExtends = this.allExtendsStack[this.allExtendsStack.length - 1];\n const selectorsToAdd = [];\n const extendVisitor = this;\n let selectorPath;\n\n // look at each selector path in the ruleset, find any extend matches and then copy, find and replace\n\n for (extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {\n for (pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {\n selectorPath = rulesetNode.paths[pathIndex];\n\n // extending extends happens initially, before the main pass\n if (rulesetNode.extendOnEveryPath) { continue; }\n const extendList = selectorPath[selectorPath.length - 1].extendList;\n if (extendList && extendList.length) { continue; }\n\n matches = this.findMatch(allExtends[extendIndex], selectorPath);\n\n if (matches.length) {\n allExtends[extendIndex].hasFoundMatches = true;\n\n allExtends[extendIndex].selfSelectors.forEach(selfSelector => {\n let extendedSelectors;\n extendedSelectors = extendVisitor.extendSelector(matches, selectorPath, selfSelector, allExtends[extendIndex].isVisible());\n selectorsToAdd.push(extendedSelectors);\n });\n }\n }\n }\n rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd);\n }\n\n findMatch(extend, haystackSelectorPath) {\n //\n // look through the haystack selector path to try and find the needle - extend.selector\n // returns an array of selector matches that can then be replaced\n //\n let haystackSelectorIndex;\n\n let hackstackSelector;\n let hackstackElementIndex;\n let haystackElement;\n let targetCombinator;\n let i;\n const extendVisitor = this;\n const needleElements = extend.selector.elements;\n const potentialMatches = [];\n let potentialMatch;\n const matches = [];\n\n // loop through the haystack elements\n for (haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) {\n hackstackSelector = haystackSelectorPath[haystackSelectorIndex];\n\n for (hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) {\n\n haystackElement = hackstackSelector.elements[hackstackElementIndex];\n\n // if we allow elements before our match we can add a potential match every time. otherwise only at the first element.\n if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) {\n potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0,\n initialCombinator: haystackElement.combinator});\n }\n\n for (i = 0; i < potentialMatches.length; i++) {\n potentialMatch = potentialMatches[i];\n\n // selectors add \" \" onto the first element. When we use & it joins the selectors together, but if we don't\n // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to\n // work out what the resulting combinator will be\n targetCombinator = haystackElement.combinator.value;\n if (targetCombinator === '' && hackstackElementIndex === 0) {\n targetCombinator = ' ';\n }\n\n // if we don't match, null our match to indicate failure\n if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) ||\n (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) {\n potentialMatch = null;\n } else {\n potentialMatch.matched++;\n }\n\n // if we are still valid and have finished, test whether we have elements after and whether these are allowed\n if (potentialMatch) {\n potentialMatch.finished = potentialMatch.matched === needleElements.length;\n if (potentialMatch.finished &&\n (!extend.allowAfter &&\n (hackstackElementIndex + 1 < hackstackSelector.elements.length || haystackSelectorIndex + 1 < haystackSelectorPath.length))) {\n potentialMatch = null;\n }\n }\n // if null we remove, if not, we are still valid, so either push as a valid match or continue\n if (potentialMatch) {\n if (potentialMatch.finished) {\n potentialMatch.length = needleElements.length;\n potentialMatch.endPathIndex = haystackSelectorIndex;\n potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match\n potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again\n matches.push(potentialMatch);\n }\n } else {\n potentialMatches.splice(i, 1);\n i--;\n }\n }\n }\n }\n return matches;\n }\n\n isElementValuesEqual(elementValue1, elementValue2) {\n if (typeof elementValue1 === 'string' || typeof elementValue2 === 'string') {\n return elementValue1 === elementValue2;\n }\n if (elementValue1 instanceof tree.Attribute) {\n if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) {\n return false;\n }\n if (!elementValue1.value || !elementValue2.value) {\n if (elementValue1.value || elementValue2.value) {\n return false;\n }\n return true;\n }\n elementValue1 = elementValue1.value.value || elementValue1.value;\n elementValue2 = elementValue2.value.value || elementValue2.value;\n return elementValue1 === elementValue2;\n }\n elementValue1 = elementValue1.value;\n elementValue2 = elementValue2.value;\n if (elementValue1 instanceof tree.Selector) {\n if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) {\n return false;\n }\n for (let i = 0; i < elementValue1.elements.length; i++) {\n if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) {\n if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) {\n return false;\n }\n }\n if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) {\n return false;\n }\n }\n return true;\n }\n return false;\n }\n\n extendSelector(matches, selectorPath, replacementSelector, isVisible) {\n // for a set of matches, replace each match with the replacement selector\n\n let currentSelectorPathIndex = 0;\n\n let currentSelectorPathElementIndex = 0;\n let path = [];\n let matchIndex;\n let selector;\n let firstElement;\n let match;\n let newElements;\n\n for (matchIndex = 0; matchIndex < matches.length; matchIndex++) {\n match = matches[matchIndex];\n selector = selectorPath[match.pathIndex];\n firstElement = new tree.Element(\n match.initialCombinator,\n replacementSelector.elements[0].value,\n replacementSelector.elements[0].isVariable,\n replacementSelector.elements[0].getIndex(),\n replacementSelector.elements[0].fileInfo()\n );\n\n if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {\n path[path.length - 1].elements = path[path.length - 1]\n .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));\n currentSelectorPathElementIndex = 0;\n currentSelectorPathIndex++;\n }\n\n newElements = selector.elements\n .slice(currentSelectorPathElementIndex, match.index)\n .concat([firstElement])\n .concat(replacementSelector.elements.slice(1));\n\n if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) {\n path[path.length - 1].elements =\n path[path.length - 1].elements.concat(newElements);\n } else {\n path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));\n\n path.push(new tree.Selector(\n newElements\n ));\n }\n currentSelectorPathIndex = match.endPathIndex;\n currentSelectorPathElementIndex = match.endPathElementIndex;\n if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) {\n currentSelectorPathElementIndex = 0;\n currentSelectorPathIndex++;\n }\n }\n\n if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {\n path[path.length - 1].elements = path[path.length - 1]\n .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));\n currentSelectorPathIndex++;\n }\n\n path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length));\n path = path.map(currentValue => {\n // we can re-use elements here, because the visibility property matters only for selectors\n const derived = currentValue.createDerived(currentValue.elements);\n if (isVisible) {\n derived.ensureVisibility();\n } else {\n derived.ensureInvisibility();\n }\n return derived;\n });\n return path;\n }\n\n visitMedia(mediaNode, visitArgs) {\n let newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);\n newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));\n this.allExtendsStack.push(newAllExtends);\n }\n\n visitMediaOut(mediaNode) {\n const lastIndex = this.allExtendsStack.length - 1;\n this.allExtendsStack.length = lastIndex;\n }\n\n visitAtRule(atRuleNode, visitArgs) {\n let newAllExtends = atRuleNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);\n newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, atRuleNode.allExtends));\n this.allExtendsStack.push(newAllExtends);\n }\n\n visitAtRuleOut(atRuleNode) {\n const lastIndex = this.allExtendsStack.length - 1;\n this.allExtendsStack.length = lastIndex;\n }\n}\n\nexport default ProcessExtendsVisitor;\n","import Visitor from './visitor';\n\nclass JoinSelectorVisitor {\n constructor() {\n this.contexts = [[]];\n this._visitor = new Visitor(this);\n }\n\n run(root) {\n return this._visitor.visit(root);\n }\n\n visitDeclaration(declNode, visitArgs) {\n visitArgs.visitDeeper = false;\n }\n\n visitMixinDefinition(mixinDefinitionNode, visitArgs) {\n visitArgs.visitDeeper = false;\n }\n\n visitRuleset(rulesetNode, visitArgs) {\n const context = this.contexts[this.contexts.length - 1];\n const paths = [];\n let selectors;\n\n this.contexts.push(paths);\n\n if (!rulesetNode.root) {\n selectors = rulesetNode.selectors;\n if (selectors) {\n selectors = selectors.filter(selector => selector.getIsOutput());\n rulesetNode.selectors = selectors.length ? selectors : (selectors = null);\n if (selectors) { rulesetNode.joinSelectors(paths, context, selectors); }\n }\n if (!selectors) { rulesetNode.rules = null; }\n rulesetNode.paths = paths;\n }\n }\n\n visitRulesetOut(rulesetNode) {\n this.contexts.length = this.contexts.length - 1;\n }\n\n visitMedia(mediaNode, visitArgs) {\n const context = this.contexts[this.contexts.length - 1];\n mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia);\n }\n\n visitAtRule(atRuleNode, visitArgs) {\n const context = this.contexts[this.contexts.length - 1];\n if (atRuleNode.rules && atRuleNode.rules.length) {\n atRuleNode.rules[0].root = (atRuleNode.isRooted || context.length === 0 || null);\n }\n }\n}\n\nexport default JoinSelectorVisitor;\n","import tree from '../tree';\nimport Visitor from './visitor';\n\nclass CSSVisitorUtils {\n constructor(context) {\n this._visitor = new Visitor(this);\n this._context = context;\n }\n\n containsSilentNonBlockedChild(bodyRules) {\n let rule;\n if (!bodyRules) {\n return false;\n }\n for (let r = 0; r < bodyRules.length; r++) {\n rule = bodyRules[r];\n if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) {\n // the atrule contains something that was referenced (likely by extend)\n // therefore it needs to be shown in output too\n return true;\n }\n }\n return false;\n }\n\n keepOnlyVisibleChilds(owner) {\n if (owner && owner.rules) {\n owner.rules = owner.rules.filter(thing => thing.isVisible());\n }\n }\n\n isEmpty(owner) {\n return (owner && owner.rules) \n ? (owner.rules.length === 0) : true;\n }\n\n hasVisibleSelector(rulesetNode) {\n return (rulesetNode && rulesetNode.paths)\n ? (rulesetNode.paths.length > 0) : false;\n }\n\n resolveVisibility(node, originalRules) {\n if (!node.blocksVisibility()) {\n if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) {\n return ;\n }\n\n return node;\n }\n\n const compiledRulesBody = node.rules[0];\n this.keepOnlyVisibleChilds(compiledRulesBody);\n\n if (this.isEmpty(compiledRulesBody)) {\n return ;\n }\n\n node.ensureVisibility();\n node.removeVisibilityBlock();\n\n return node;\n }\n\n isVisibleRuleset(rulesetNode) {\n if (rulesetNode.firstRoot) {\n return true;\n }\n\n if (this.isEmpty(rulesetNode)) {\n return false;\n }\n\n if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) {\n return false;\n }\n\n return true;\n }\n}\n\nconst ToCSSVisitor = function(context) {\n this._visitor = new Visitor(this);\n this._context = context;\n this.utils = new CSSVisitorUtils(context);\n};\n\nToCSSVisitor.prototype = {\n isReplacing: true,\n run: function (root) {\n return this._visitor.visit(root);\n },\n\n visitDeclaration: function (declNode, visitArgs) {\n if (declNode.blocksVisibility() || declNode.variable) {\n return;\n }\n return declNode;\n },\n\n visitMixinDefinition: function (mixinNode, visitArgs) {\n // mixin definitions do not get eval'd - this means they keep state\n // so we have to clear that state here so it isn't used if toCSS is called twice\n mixinNode.frames = [];\n },\n\n visitExtend: function (extendNode, visitArgs) {\n },\n\n visitComment: function (commentNode, visitArgs) {\n if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) {\n return;\n }\n return commentNode;\n },\n\n visitMedia: function(mediaNode, visitArgs) {\n const originalRules = mediaNode.rules[0].rules;\n mediaNode.accept(this._visitor);\n visitArgs.visitDeeper = false;\n\n return this.utils.resolveVisibility(mediaNode, originalRules);\n },\n\n visitImport: function (importNode, visitArgs) {\n if (importNode.blocksVisibility()) {\n return ;\n }\n return importNode;\n },\n\n visitAtRule: function(atRuleNode, visitArgs) {\n if (atRuleNode.rules && atRuleNode.rules.length) {\n return this.visitAtRuleWithBody(atRuleNode, visitArgs);\n } else {\n return this.visitAtRuleWithoutBody(atRuleNode, visitArgs);\n }\n },\n\n visitAnonymous: function(anonymousNode, visitArgs) {\n if (!anonymousNode.blocksVisibility()) {\n anonymousNode.accept(this._visitor);\n return anonymousNode;\n }\n },\n\n visitAtRuleWithBody: function(atRuleNode, visitArgs) {\n // if there is only one nested ruleset and that one has no path, then it is\n // just fake ruleset\n function hasFakeRuleset(atRuleNode) {\n const bodyRules = atRuleNode.rules;\n return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0);\n }\n function getBodyRules(atRuleNode) {\n const nodeRules = atRuleNode.rules;\n if (hasFakeRuleset(atRuleNode)) {\n return nodeRules[0].rules;\n }\n\n return nodeRules;\n }\n // it is still true that it is only one ruleset in array\n // this is last such moment\n // process childs\n const originalRules = getBodyRules(atRuleNode);\n atRuleNode.accept(this._visitor);\n visitArgs.visitDeeper = false;\n\n if (!this.utils.isEmpty(atRuleNode)) {\n this._mergeRules(atRuleNode.rules[0].rules);\n }\n\n return this.utils.resolveVisibility(atRuleNode, originalRules);\n },\n\n visitAtRuleWithoutBody: function(atRuleNode, visitArgs) {\n if (atRuleNode.blocksVisibility()) {\n return;\n }\n\n if (atRuleNode.name === '@charset') {\n // Only output the debug info together with subsequent @charset definitions\n // a comment (or @media statement) before the actual @charset atrule would\n // be considered illegal css as it has to be on the first line\n if (this.charset) {\n if (atRuleNode.debugInfo) {\n const comment = new tree.Comment(`/* ${atRuleNode.toCSS(this._context).replace(/\\n/g, '')} */\\n`);\n comment.debugInfo = atRuleNode.debugInfo;\n return this._visitor.visit(comment);\n }\n return;\n }\n this.charset = true;\n }\n\n return atRuleNode;\n },\n\n checkValidNodes: function(rules, isRoot) {\n if (!rules) {\n return;\n }\n\n for (let i = 0; i < rules.length; i++) {\n const ruleNode = rules[i];\n if (isRoot && ruleNode instanceof tree.Declaration && !ruleNode.variable) {\n throw { message: 'Properties must be inside selector blocks. They cannot be in the root',\n index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};\n }\n if (ruleNode instanceof tree.Call) {\n throw { message: `Function '${ruleNode.name}' is undefined`,\n index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};\n }\n if (ruleNode.type && !ruleNode.allowRoot) {\n throw { message: `${ruleNode.type} node returned by a function is not valid here`,\n index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};\n }\n }\n },\n\n visitRuleset: function (rulesetNode, visitArgs) {\n // at this point rulesets are nested into each other\n let rule;\n\n const rulesets = [];\n\n this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot);\n\n if (!rulesetNode.root) {\n // remove invisible paths\n this._compileRulesetPaths(rulesetNode);\n\n // remove rulesets from this ruleset body and compile them separately\n const nodeRules = rulesetNode.rules;\n\n let nodeRuleCnt = nodeRules ? nodeRules.length : 0;\n for (let i = 0; i < nodeRuleCnt; ) {\n rule = nodeRules[i];\n if (rule && rule.rules) {\n // visit because we are moving them out from being a child\n rulesets.push(this._visitor.visit(rule));\n nodeRules.splice(i, 1);\n nodeRuleCnt--;\n continue;\n }\n i++;\n }\n // accept the visitor to remove rules and refactor itself\n // then we can decide nogw whether we want it or not\n // compile body\n if (nodeRuleCnt > 0) {\n rulesetNode.accept(this._visitor);\n } else {\n rulesetNode.rules = null;\n }\n visitArgs.visitDeeper = false;\n } else { // if (! rulesetNode.root) {\n rulesetNode.accept(this._visitor);\n visitArgs.visitDeeper = false;\n }\n\n if (rulesetNode.rules) {\n this._mergeRules(rulesetNode.rules);\n this._removeDuplicateRules(rulesetNode.rules);\n }\n\n // now decide whether we keep the ruleset\n if (this.utils.isVisibleRuleset(rulesetNode)) {\n rulesetNode.ensureVisibility();\n rulesets.splice(0, 0, rulesetNode);\n }\n\n if (rulesets.length === 1) {\n return rulesets[0];\n }\n return rulesets;\n },\n\n _compileRulesetPaths: function(rulesetNode) {\n if (rulesetNode.paths) {\n rulesetNode.paths = rulesetNode.paths\n .filter(p => {\n let i;\n if (p[0].elements[0].combinator.value === ' ') {\n p[0].elements[0].combinator = new(tree.Combinator)('');\n }\n for (i = 0; i < p.length; i++) {\n if (p[i].isVisible() && p[i].getIsOutput()) {\n return true;\n }\n }\n return false;\n });\n }\n },\n\n _removeDuplicateRules: function(rules) {\n if (!rules) { return; }\n\n // remove duplicates\n const ruleCache = {};\n\n let ruleList;\n let rule;\n let i;\n\n for (i = rules.length - 1; i >= 0 ; i--) {\n rule = rules[i];\n if (rule instanceof tree.Declaration) {\n if (!ruleCache[rule.name]) {\n ruleCache[rule.name] = rule;\n } else {\n ruleList = ruleCache[rule.name];\n if (ruleList instanceof tree.Declaration) {\n ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._context)];\n }\n const ruleCSS = rule.toCSS(this._context);\n if (ruleList.indexOf(ruleCSS) !== -1) {\n rules.splice(i, 1);\n } else {\n ruleList.push(ruleCSS);\n }\n }\n }\n }\n },\n\n _mergeRules: function(rules) {\n if (!rules) {\n return; \n }\n\n const groups = {};\n const groupsArr = [];\n\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i];\n if (rule.merge) {\n const key = rule.name;\n groups[key] ? rules.splice(i--, 1) : \n groupsArr.push(groups[key] = []);\n groups[key].push(rule);\n }\n }\n\n groupsArr.forEach(group => {\n if (group.length > 0) {\n const result = group[0];\n let space = [];\n const comma = [new tree.Expression(space)];\n group.forEach(rule => {\n if ((rule.merge === '+') && (space.length > 0)) {\n comma.push(new tree.Expression(space = []));\n }\n space.push(rule.value);\n result.important = result.important || rule.important;\n });\n result.value = new tree.Value(comma);\n }\n });\n }\n};\n\nexport default ToCSSVisitor;\n","import Visitor from './visitor';\nimport ImportVisitor from './import-visitor';\nimport MarkVisibleSelectorsVisitor from './set-tree-visibility-visitor';\nimport ExtendVisitor from './extend-visitor';\nimport JoinSelectorVisitor from './join-selector-visitor';\nimport ToCSSVisitor from './to-css-visitor';\n\nexport default {\n Visitor,\n ImportVisitor,\n MarkVisibleSelectorsVisitor,\n ExtendVisitor,\n JoinSelectorVisitor,\n ToCSSVisitor\n};\n","import chunker from './chunker';\n\nexport default () => {\n let // Less input string\n input;\n\n let // current chunk\n j;\n\n const // holds state for backtracking\n saveStack = [];\n\n let // furthest index the parser has gone to\n furthest;\n\n let // if this is furthest we got to, this is the probably cause\n furthestPossibleErrorMessage;\n\n let // chunkified input\n chunks;\n\n let // current chunk\n current;\n\n let // index of current chunk, in `input`\n currentPos;\n\n const parserInput = {};\n const CHARCODE_SPACE = 32;\n const CHARCODE_TAB = 9;\n const CHARCODE_LF = 10;\n const CHARCODE_CR = 13;\n const CHARCODE_PLUS = 43;\n const CHARCODE_COMMA = 44;\n const CHARCODE_FORWARD_SLASH = 47;\n const CHARCODE_9 = 57;\n\n function skipWhitespace(length) {\n const oldi = parserInput.i;\n const oldj = j;\n const curr = parserInput.i - currentPos;\n const endIndex = parserInput.i + current.length - curr;\n const mem = (parserInput.i += length);\n const inp = input;\n let c;\n let nextChar;\n let comment;\n\n for (; parserInput.i < endIndex; parserInput.i++) {\n c = inp.charCodeAt(parserInput.i);\n\n if (parserInput.autoCommentAbsorb && c === CHARCODE_FORWARD_SLASH) {\n nextChar = inp.charAt(parserInput.i + 1);\n if (nextChar === '/') {\n comment = {index: parserInput.i, isLineComment: true};\n let nextNewLine = inp.indexOf('\\n', parserInput.i + 2);\n if (nextNewLine < 0) {\n nextNewLine = endIndex;\n }\n parserInput.i = nextNewLine;\n comment.text = inp.substr(comment.index, parserInput.i - comment.index);\n parserInput.commentStore.push(comment);\n continue;\n } else if (nextChar === '*') {\n const nextStarSlash = inp.indexOf('*/', parserInput.i + 2);\n if (nextStarSlash >= 0) {\n comment = {\n index: parserInput.i,\n text: inp.substr(parserInput.i, nextStarSlash + 2 - parserInput.i),\n isLineComment: false\n };\n parserInput.i += comment.text.length - 1;\n parserInput.commentStore.push(comment);\n continue;\n }\n }\n break;\n }\n\n if ((c !== CHARCODE_SPACE) && (c !== CHARCODE_LF) && (c !== CHARCODE_TAB) && (c !== CHARCODE_CR)) {\n break;\n }\n }\n\n current = current.slice(length + parserInput.i - mem + curr);\n currentPos = parserInput.i;\n\n if (!current.length) {\n if (j < chunks.length - 1) {\n current = chunks[++j];\n skipWhitespace(0); // skip space at the beginning of a chunk\n return true; // things changed\n }\n parserInput.finished = true;\n }\n\n return oldi !== parserInput.i || oldj !== j;\n }\n\n parserInput.save = () => {\n currentPos = parserInput.i;\n saveStack.push( { current, i: parserInput.i, j });\n };\n parserInput.restore = possibleErrorMessage => {\n\n if (parserInput.i > furthest || (parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage)) {\n furthest = parserInput.i;\n furthestPossibleErrorMessage = possibleErrorMessage;\n }\n const state = saveStack.pop();\n current = state.current;\n currentPos = parserInput.i = state.i;\n j = state.j;\n };\n parserInput.forget = () => {\n saveStack.pop();\n };\n parserInput.isWhitespace = offset => {\n const pos = parserInput.i + (offset || 0);\n const code = input.charCodeAt(pos);\n return (code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF);\n };\n\n // Specialization of $(tok)\n parserInput.$re = tok => {\n if (parserInput.i > currentPos) {\n current = current.slice(parserInput.i - currentPos);\n currentPos = parserInput.i;\n }\n\n const m = tok.exec(current);\n if (!m) {\n return null;\n }\n\n skipWhitespace(m[0].length);\n if (typeof m === 'string') {\n return m;\n }\n\n return m.length === 1 ? m[0] : m;\n };\n\n parserInput.$char = tok => {\n if (input.charAt(parserInput.i) !== tok) {\n return null;\n }\n skipWhitespace(1);\n return tok;\n };\n\n parserInput.$str = tok => {\n const tokLength = tok.length;\n\n // https://jsperf.com/string-startswith/21\n for (let i = 0; i < tokLength; i++) {\n if (input.charAt(parserInput.i + i) !== tok.charAt(i)) {\n return null;\n }\n }\n\n skipWhitespace(tokLength);\n return tok;\n };\n\n parserInput.$quoted = loc => {\n const pos = loc || parserInput.i;\n const startChar = input.charAt(pos);\n\n if (startChar !== '\\'' && startChar !== '\"') {\n return;\n }\n const length = input.length;\n const currentPosition = pos;\n\n for (let i = 1; i + currentPosition < length; i++) {\n const nextChar = input.charAt(i + currentPosition);\n switch (nextChar) {\n case '\\\\':\n i++;\n continue;\n case '\\r':\n case '\\n':\n break;\n case startChar:\n const str = input.substr(currentPosition, i + 1);\n if (!loc && loc !== 0) {\n skipWhitespace(i + 1);\n return str\n }\n return [startChar, str];\n default:\n }\n }\n return null;\n };\n\n /**\n * Permissive parsing. Ignores everything except matching {} [] () and quotes\n * until matching token (outside of blocks)\n */\n parserInput.$parseUntil = tok => {\n let quote = '';\n let returnVal = null;\n let inComment = false;\n let blockDepth = 0;\n const blockStack = [];\n const parseGroups = [];\n const length = input.length;\n const startPos = parserInput.i;\n let lastPos = parserInput.i;\n let i = parserInput.i;\n let loop = true;\n let testChar;\n\n if (typeof tok === 'string') {\n testChar = char => char === tok\n } else {\n testChar = char => tok.test(char)\n }\n\n do {\n let prevChar;\n let nextChar = input.charAt(i);\n if (blockDepth === 0 && testChar(nextChar)) {\n returnVal = input.substr(lastPos, i - lastPos);\n if (returnVal) {\n parseGroups.push(returnVal);\n }\n else {\n parseGroups.push(' ');\n }\n returnVal = parseGroups;\n skipWhitespace(i - startPos);\n loop = false\n } else {\n if (inComment) {\n if (nextChar === '*' && \n input.charAt(i + 1) === '/') {\n i++;\n blockDepth--;\n inComment = false;\n }\n i++;\n continue;\n }\n switch (nextChar) {\n case '\\\\':\n i++;\n nextChar = input.charAt(i);\n parseGroups.push(input.substr(lastPos, i - lastPos + 1));\n lastPos = i + 1;\n break;\n case '/':\n if (input.charAt(i + 1) === '*') {\n i++;\n inComment = true;\n blockDepth++;\n }\n break;\n case '\\'':\n case '\"':\n quote = parserInput.$quoted(i);\n if (quote) {\n parseGroups.push(input.substr(lastPos, i - lastPos), quote);\n i += quote[1].length - 1;\n lastPos = i + 1;\n }\n else {\n skipWhitespace(i - startPos);\n returnVal = nextChar;\n loop = false;\n }\n break;\n case '{':\n blockStack.push('}');\n blockDepth++;\n break;\n case '(':\n blockStack.push(')');\n blockDepth++;\n break;\n case '[':\n blockStack.push(']');\n blockDepth++;\n break;\n case '}':\n case ')':\n case ']':\n const expected = blockStack.pop();\n if (nextChar === expected) {\n blockDepth--;\n } else {\n // move the parser to the error and return expected\n skipWhitespace(i - startPos);\n returnVal = expected;\n loop = false;\n }\n }\n i++;\n if (i > length) {\n loop = false;\n }\n }\n prevChar = nextChar;\n } while (loop);\n\n return returnVal ? returnVal : null;\n }\n\n parserInput.autoCommentAbsorb = true;\n parserInput.commentStore = [];\n parserInput.finished = false;\n\n // Same as $(), but don't change the state of the parser,\n // just return the match.\n parserInput.peek = tok => {\n if (typeof tok === 'string') {\n // https://jsperf.com/string-startswith/21\n for (let i = 0; i < tok.length; i++) {\n if (input.charAt(parserInput.i + i) !== tok.charAt(i)) {\n return false;\n }\n }\n return true;\n } else {\n return tok.test(current);\n }\n };\n\n // Specialization of peek()\n // TODO remove or change some currentChar calls to peekChar\n parserInput.peekChar = tok => input.charAt(parserInput.i) === tok;\n\n parserInput.currentChar = () => input.charAt(parserInput.i);\n\n parserInput.prevChar = () => input.charAt(parserInput.i - 1);\n\n parserInput.getInput = () => input;\n\n parserInput.peekNotNumeric = () => {\n const c = input.charCodeAt(parserInput.i);\n // Is the first char of the dimension 0-9, '.', '+' or '-'\n return (c > CHARCODE_9 || c < CHARCODE_PLUS) || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA;\n };\n\n parserInput.start = (str, chunkInput, failFunction) => {\n input = str;\n parserInput.i = j = currentPos = furthest = 0;\n\n // chunking apparently makes things quicker (but my tests indicate\n // it might actually make things slower in node at least)\n // and it is a non-perfect parse - it can't recognise\n // unquoted urls, meaning it can't distinguish comments\n // meaning comments with quotes or {}() in them get 'counted'\n // and then lead to parse errors.\n // In addition if the chunking chunks in the wrong place we might\n // not be able to parse a parser statement in one go\n // this is officially deprecated but can be switched on via an option\n // in the case it causes too much performance issues.\n if (chunkInput) {\n chunks = chunker(str, failFunction);\n } else {\n chunks = [str];\n }\n\n current = chunks[0];\n\n skipWhitespace(0);\n };\n\n parserInput.end = () => {\n let message;\n const isFinished = parserInput.i >= input.length;\n\n if (parserInput.i < furthest) {\n message = furthestPossibleErrorMessage;\n parserInput.i = furthest;\n }\n return {\n isFinished,\n furthest: parserInput.i,\n furthestPossibleErrorMessage: message,\n furthestReachedEnd: parserInput.i >= input.length - 1,\n furthestChar: input[parserInput.i]\n };\n };\n\n return parserInput;\n};\n","// Split the input into chunks.\nexport default (input, fail) => {\n const len = input.length;\n let level = 0;\n let parenLevel = 0;\n let lastOpening;\n let lastOpeningParen;\n let lastMultiComment;\n let lastMultiCommentEndBrace;\n const chunks = [];\n let emitFrom = 0;\n let chunkerCurrentIndex;\n let currentChunkStartIndex;\n let cc;\n let cc2;\n let matched;\n\n function emitChunk(force) {\n const len = chunkerCurrentIndex - emitFrom;\n if (((len < 512) && !force) || !len) {\n return;\n }\n chunks.push(input.slice(emitFrom, chunkerCurrentIndex + 1));\n emitFrom = chunkerCurrentIndex + 1;\n }\n\n for (chunkerCurrentIndex = 0; chunkerCurrentIndex < len; chunkerCurrentIndex++) {\n cc = input.charCodeAt(chunkerCurrentIndex);\n if (((cc >= 97) && (cc <= 122)) || (cc < 34)) {\n // a-z or whitespace\n continue;\n }\n\n switch (cc) {\n case 40: // (\n parenLevel++;\n lastOpeningParen = chunkerCurrentIndex;\n continue;\n case 41: // )\n if (--parenLevel < 0) {\n return fail('missing opening `(`', chunkerCurrentIndex);\n }\n continue;\n case 59: // ;\n if (!parenLevel) { emitChunk(); }\n continue;\n case 123: // {\n level++;\n lastOpening = chunkerCurrentIndex;\n continue;\n case 125: // }\n if (--level < 0) {\n return fail('missing opening `{`', chunkerCurrentIndex);\n }\n if (!level && !parenLevel) { emitChunk(); }\n continue;\n case 92: // \\\n if (chunkerCurrentIndex < len - 1) { chunkerCurrentIndex++; continue; }\n return fail('unescaped `\\\\`', chunkerCurrentIndex);\n case 34:\n case 39:\n case 96: // \", ' and `\n matched = 0;\n currentChunkStartIndex = chunkerCurrentIndex;\n for (chunkerCurrentIndex = chunkerCurrentIndex + 1; chunkerCurrentIndex < len; chunkerCurrentIndex++) {\n cc2 = input.charCodeAt(chunkerCurrentIndex);\n if (cc2 > 96) { continue; }\n if (cc2 == cc) { matched = 1; break; }\n if (cc2 == 92) { // \\\n if (chunkerCurrentIndex == len - 1) {\n return fail('unescaped `\\\\`', chunkerCurrentIndex);\n }\n chunkerCurrentIndex++;\n }\n }\n if (matched) { continue; }\n return fail(`unmatched \\`${String.fromCharCode(cc)}\\``, currentChunkStartIndex);\n case 47: // /, check for comment\n if (parenLevel || (chunkerCurrentIndex == len - 1)) { continue; }\n cc2 = input.charCodeAt(chunkerCurrentIndex + 1);\n if (cc2 == 47) {\n // //, find lnfeed\n for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len; chunkerCurrentIndex++) {\n cc2 = input.charCodeAt(chunkerCurrentIndex);\n if ((cc2 <= 13) && ((cc2 == 10) || (cc2 == 13))) { break; }\n }\n } else if (cc2 == 42) {\n // /*, find */\n lastMultiComment = currentChunkStartIndex = chunkerCurrentIndex;\n for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len - 1; chunkerCurrentIndex++) {\n cc2 = input.charCodeAt(chunkerCurrentIndex);\n if (cc2 == 125) { lastMultiCommentEndBrace = chunkerCurrentIndex; }\n if (cc2 != 42) { continue; }\n if (input.charCodeAt(chunkerCurrentIndex + 1) == 47) { break; }\n }\n if (chunkerCurrentIndex == len - 1) {\n return fail('missing closing `*/`', currentChunkStartIndex);\n }\n chunkerCurrentIndex++;\n }\n continue;\n case 42: // *, check for unmatched */\n if ((chunkerCurrentIndex < len - 1) && (input.charCodeAt(chunkerCurrentIndex + 1) == 47)) {\n return fail('unmatched `/*`', chunkerCurrentIndex);\n }\n continue;\n }\n }\n\n if (level !== 0) {\n if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) {\n return fail('missing closing `}` or `*/`', lastOpening);\n } else {\n return fail('missing closing `}`', lastOpening);\n }\n } else if (parenLevel !== 0) {\n return fail('missing closing `)`', lastOpeningParen);\n }\n\n emitChunk(true);\n return chunks;\n};\n","import LessError from '../less-error';\nimport tree from '../tree';\nimport visitors from '../visitors';\nimport getParserInput from './parser-input';\nimport * as utils from '../utils';\nimport functionRegistry from '../functions/function-registry';\n\n//\n// less.js - parser\n//\n// A relatively straight-forward predictive parser.\n// There is no tokenization/lexing stage, the input is parsed\n// in one sweep.\n//\n// To make the parser fast enough to run in the browser, several\n// optimization had to be made:\n//\n// - Matching and slicing on a huge input is often cause of slowdowns.\n// The solution is to chunkify the input into smaller strings.\n// The chunks are stored in the `chunks` var,\n// `j` holds the current chunk index, and `currentPos` holds\n// the index of the current chunk in relation to `input`.\n// This gives us an almost 4x speed-up.\n//\n// - In many cases, we don't need to match individual tokens;\n// for example, if a value doesn't hold any variables, operations\n// or dynamic references, the parser can effectively 'skip' it,\n// treating it as a literal.\n// An example would be '1px solid #000' - which evaluates to itself,\n// we don't need to know what the individual components are.\n// The drawback, of course is that you don't get the benefits of\n// syntax-checking on the CSS. This gives us a 50% speed-up in the parser,\n// and a smaller speed-up in the code-gen.\n//\n//\n// Token matching is done with the `$` function, which either takes\n// a terminal string or regexp, or a non-terminal function to call.\n// It also takes care of moving all the indices forwards.\n//\n\nconst Parser = function Parser(context, imports, fileInfo) {\n let parsers;\n const parserInput = getParserInput();\n\n function error(msg, type) {\n throw new LessError(\n {\n index: parserInput.i,\n filename: fileInfo.filename,\n type: type || 'Syntax',\n message: msg\n },\n imports\n );\n }\n\n function expect(arg, msg) {\n // some older browsers return typeof 'function' for RegExp\n const result = (arg instanceof Function) ? arg.call(parsers) : parserInput.$re(arg);\n if (result) {\n return result;\n }\n \n error(msg || (typeof arg === 'string'\n ? `expected '${arg}' got '${parserInput.currentChar()}'`\n : 'unexpected token'));\n }\n\n // Specialization of expect()\n function expectChar(arg, msg) {\n if (parserInput.$char(arg)) {\n return arg;\n }\n error(msg || `expected '${arg}' got '${parserInput.currentChar()}'`);\n }\n\n function getDebugInfo(index) {\n const filename = fileInfo.filename;\n\n return {\n lineNumber: utils.getLocation(index, parserInput.getInput()).line + 1,\n fileName: filename\n };\n }\n\n /**\n * Used after initial parsing to create nodes on the fly\n * \n * @param {String} str - string to parse \n * @param {Array} parseList - array of parsers to run input through e.g. [\"value\", \"important\"]\n * @param {Number} currentIndex - start number to begin indexing\n * @param {Object} fileInfo - fileInfo to attach to created nodes\n */\n function parseNode(str, parseList, currentIndex, fileInfo, callback) {\n let result;\n const returnNodes = [];\n const parser = parserInput;\n\n try {\n parser.start(str, false, function fail(msg, index) {\n callback({\n message: msg,\n index: index + currentIndex\n });\n });\n for (let x = 0, p, i; (p = parseList[x]); x++) {\n i = parser.i;\n result = parsers[p]();\n if (result) {\n result._index = i + currentIndex;\n result._fileInfo = fileInfo;\n returnNodes.push(result);\n }\n else {\n returnNodes.push(null);\n }\n }\n\n const endInfo = parser.end();\n if (endInfo.isFinished) {\n callback(null, returnNodes);\n }\n else {\n callback(true, null);\n }\n } catch (e) {\n throw new LessError({\n index: e.index + currentIndex,\n message: e.message\n }, imports, fileInfo.filename);\n }\n }\n\n //\n // The Parser\n //\n return {\n parserInput,\n imports,\n fileInfo,\n parseNode,\n //\n // Parse an input string into an abstract syntax tree,\n // @param str A string containing 'less' markup\n // @param callback call `callback` when done.\n // @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply\n //\n parse: function (str, callback, additionalData) {\n let root;\n let error = null;\n let globalVars;\n let modifyVars;\n let ignored;\n let preText = '';\n\n globalVars = (additionalData && additionalData.globalVars) ? `${Parser.serializeVars(additionalData.globalVars)}\\n` : '';\n modifyVars = (additionalData && additionalData.modifyVars) ? `\\n${Parser.serializeVars(additionalData.modifyVars)}` : '';\n\n if (context.pluginManager) {\n const preProcessors = context.pluginManager.getPreProcessors();\n for (let i = 0; i < preProcessors.length; i++) {\n str = preProcessors[i].process(str, { context, imports, fileInfo });\n }\n }\n\n if (globalVars || (additionalData && additionalData.banner)) {\n preText = ((additionalData && additionalData.banner) ? additionalData.banner : '') + globalVars;\n ignored = imports.contentsIgnoredChars;\n ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0;\n ignored[fileInfo.filename] += preText.length;\n }\n\n str = str.replace(/\\r\\n?/g, '\\n');\n // Remove potential UTF Byte Order Mark\n str = preText + str.replace(/^\\uFEFF/, '') + modifyVars;\n imports.contents[fileInfo.filename] = str;\n\n // Start with the primary rule.\n // The whole syntax tree is held under a Ruleset node,\n // with the `root` property set to true, so no `{}` are\n // output. The callback is called when the input is parsed.\n try {\n parserInput.start(str, context.chunkInput, function fail(msg, index) {\n throw new LessError({\n index,\n type: 'Parse',\n message: msg,\n filename: fileInfo.filename\n }, imports);\n });\n\n tree.Node.prototype.parse = this;\n root = new tree.Ruleset(null, this.parsers.primary());\n tree.Node.prototype.rootNode = root;\n root.root = true;\n root.firstRoot = true;\n root.functionRegistry = functionRegistry.inherit();\n \n } catch (e) {\n return callback(new LessError(e, imports, fileInfo.filename));\n }\n\n // If `i` is smaller than the `input.length - 1`,\n // it means the parser wasn't able to parse the whole\n // string, so we've got a parsing error.\n //\n // We try to extract a \\n delimited string,\n // showing the line where the parse error occurred.\n // We split it up into two parts (the part which parsed,\n // and the part which didn't), so we can color them differently.\n const endInfo = parserInput.end();\n if (!endInfo.isFinished) {\n\n let message = endInfo.furthestPossibleErrorMessage;\n\n if (!message) {\n message = 'Unrecognised input';\n if (endInfo.furthestChar === '}') {\n message += '. Possibly missing opening \\'{\\'';\n } else if (endInfo.furthestChar === ')') {\n message += '. Possibly missing opening \\'(\\'';\n } else if (endInfo.furthestReachedEnd) {\n message += '. Possibly missing something';\n }\n }\n\n error = new LessError({\n type: 'Parse',\n message,\n index: endInfo.furthest,\n filename: fileInfo.filename\n }, imports);\n }\n\n const finish = e => {\n e = error || e || imports.error;\n\n if (e) {\n if (!(e instanceof LessError)) {\n e = new LessError(e, imports, fileInfo.filename);\n }\n\n return callback(e);\n }\n else {\n return callback(null, root);\n }\n };\n\n if (context.processImports !== false) {\n new visitors.ImportVisitor(imports, finish)\n .run(root);\n } else {\n return finish();\n }\n },\n\n //\n // Here in, the parsing rules/functions\n //\n // The basic structure of the syntax tree generated is as follows:\n //\n // Ruleset -> Declaration -> Value -> Expression -> Entity\n //\n // Here's some Less code:\n //\n // .class {\n // color: #fff;\n // border: 1px solid #000;\n // width: @w + 4px;\n // > .child {...}\n // }\n //\n // And here's what the parse tree might look like:\n //\n // Ruleset (Selector '.class', [\n // Declaration (\"color\", Value ([Expression [Color #fff]]))\n // Declaration (\"border\", Value ([Expression [Dimension 1px][Keyword \"solid\"][Color #000]]))\n // Declaration (\"width\", Value ([Expression [Operation \" + \" [Variable \"@w\"][Dimension 4px]]]))\n // Ruleset (Selector [Element '>', '.child'], [...])\n // ])\n //\n // In general, most rules will try to parse a token with the `$re()` function, and if the return\n // value is truly, will return a new node, of the relevant type. Sometimes, we need to check\n // first, before parsing, that's when we use `peek()`.\n //\n parsers: parsers = {\n //\n // The `primary` rule is the *entry* and *exit* point of the parser.\n // The rules here can appear at any level of the parse tree.\n //\n // The recursive nature of the grammar is an interplay between the `block`\n // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,\n // as represented by this simplified grammar:\n //\n // primary → (ruleset | declaration)+\n // ruleset → selector+ block\n // block → '{' primary '}'\n //\n // Only at one point is the primary rule not called from the\n // block rule: at the root level.\n //\n primary: function () {\n const mixin = this.mixin;\n let root = [];\n let node;\n\n while (true) {\n while (true) {\n node = this.comment();\n if (!node) { break; }\n root.push(node);\n }\n // always process comments before deciding if finished\n if (parserInput.finished) {\n break;\n }\n if (parserInput.peek('}')) {\n break;\n }\n\n node = this.extendRule();\n if (node) {\n root = root.concat(node);\n continue;\n }\n\n node = mixin.definition() || this.declaration() || this.ruleset() ||\n mixin.call(false, false) || this.variableCall() || this.entities.call() || this.atrule();\n if (node) {\n root.push(node);\n } else {\n let foundSemiColon = false;\n while (parserInput.$char(';')) {\n foundSemiColon = true;\n }\n if (!foundSemiColon) {\n break;\n }\n }\n }\n\n return root;\n },\n\n // comments are collected by the main parsing mechanism and then assigned to nodes\n // where the current structure allows it\n comment: function () {\n if (parserInput.commentStore.length) {\n const comment = parserInput.commentStore.shift();\n return new(tree.Comment)(comment.text, comment.isLineComment, comment.index, fileInfo);\n }\n },\n\n //\n // Entities are tokens which can be found inside an Expression\n //\n entities: {\n mixinLookup: function() {\n return parsers.mixin.call(true, true);\n },\n //\n // A string, which supports escaping \" and '\n //\n // \"milky way\" 'he\\'s the one!'\n //\n quoted: function (forceEscaped) {\n let str;\n const index = parserInput.i;\n let isEscaped = false;\n\n parserInput.save();\n if (parserInput.$char('~')) {\n isEscaped = true;\n } else if (forceEscaped) {\n parserInput.restore();\n return;\n }\n\n str = parserInput.$quoted();\n if (!str) {\n parserInput.restore();\n return;\n }\n parserInput.forget();\n\n return new(tree.Quoted)(str.charAt(0), str.substr(1, str.length - 2), isEscaped, index, fileInfo);\n },\n\n //\n // A catch-all word, such as:\n //\n // black border-collapse\n //\n keyword: function () {\n const k = parserInput.$char('%') || parserInput.$re(/^\\[?(?:[\\w-]|\\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+\\]?/);\n if (k) {\n return tree.Color.fromKeyword(k) || new(tree.Keyword)(k);\n }\n },\n\n //\n // A function call\n //\n // rgb(255, 0, 255)\n //\n // The arguments are parsed with the `entities.arguments` parser.\n //\n call: function () {\n let name;\n let args;\n let func;\n const index = parserInput.i;\n\n // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18\n if (parserInput.peek(/^url\\(/i)) {\n return;\n }\n\n parserInput.save();\n\n name = parserInput.$re(/^([\\w-]+|%|progid:[\\w\\.]+)\\(/);\n if (!name) {\n parserInput.forget(); \n return;\n }\n\n name = name[1];\n func = this.customFuncCall(name);\n if (func) {\n args = func.parse();\n if (args && func.stop) {\n parserInput.forget();\n return args;\n }\n }\n\n args = this.arguments(args);\n\n if (!parserInput.$char(')')) {\n parserInput.restore('Could not parse call arguments or missing \\')\\'');\n return;\n }\n\n parserInput.forget();\n\n return new(tree.Call)(name, args, index, fileInfo);\n },\n \n //\n // Parsing rules for functions with non-standard args, e.g.:\n //\n // boolean(not(2 > 1))\n //\n // This is a quick prototype, to be modified/improved when\n // more custom-parsed funcs come (e.g. `selector(...)`)\n //\n\n customFuncCall: function (name) {\n /* Ideally the table is to be moved out of here for faster perf.,\n but it's quite tricky since it relies on all these `parsers`\n and `expect` available only here */\n return {\n alpha: f(parsers.ieAlpha, true),\n boolean: f(condition),\n 'if': f(condition)\n }[name.toLowerCase()];\n\n function f(parse, stop) {\n return {\n parse, // parsing function\n stop // when true - stop after parse() and return its result, \n // otherwise continue for plain args\n };\n }\n \n function condition() {\n return [expect(parsers.condition, 'expected condition')];\n }\n },\n\n arguments: function (prevArgs) {\n let argsComma = prevArgs || [];\n const argsSemiColon = [];\n let isSemiColonSeparated;\n let value;\n\n parserInput.save();\n\n while (true) {\n if (prevArgs) {\n prevArgs = false;\n } else {\n value = parsers.detachedRuleset() || this.assignment() || parsers.expression();\n if (!value) {\n break;\n }\n\n if (value.value && value.value.length == 1) {\n value = value.value[0];\n }\n\n argsComma.push(value);\n }\n\n if (parserInput.$char(',')) {\n continue;\n }\n\n if (parserInput.$char(';') || isSemiColonSeparated) {\n isSemiColonSeparated = true;\n value = (argsComma.length < 1) ? argsComma[0]\n : new tree.Value(argsComma);\n argsSemiColon.push(value);\n argsComma = [];\n }\n }\n\n parserInput.forget();\n return isSemiColonSeparated ? argsSemiColon : argsComma;\n },\n literal: function () {\n return this.dimension() ||\n this.color() ||\n this.quoted() ||\n this.unicodeDescriptor();\n },\n\n // Assignments are argument entities for calls.\n // They are present in ie filter properties as shown below.\n //\n // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )\n //\n\n assignment: function () {\n let key;\n let value;\n parserInput.save();\n key = parserInput.$re(/^\\w+(?=\\s?=)/i);\n if (!key) {\n parserInput.restore();\n return;\n }\n if (!parserInput.$char('=')) {\n parserInput.restore();\n return;\n }\n value = parsers.entity();\n if (value) {\n parserInput.forget();\n return new(tree.Assignment)(key, value);\n } else {\n parserInput.restore();\n }\n },\n\n //\n // Parse url() tokens\n //\n // We use a specific rule for urls, because they don't really behave like\n // standard function calls. The difference is that the argument doesn't have\n // to be enclosed within a string, so it can't be parsed as an Expression.\n //\n url: function () {\n let value;\n const index = parserInput.i;\n\n parserInput.autoCommentAbsorb = false;\n\n if (!parserInput.$str('url(')) {\n parserInput.autoCommentAbsorb = true;\n return;\n }\n\n value = this.quoted() || this.variable() || this.property() ||\n parserInput.$re(/^(?:(?:\\\\[\\(\\)'\"])|[^\\(\\)'\"])+/) || '';\n\n parserInput.autoCommentAbsorb = true;\n\n expectChar(')');\n\n return new(tree.URL)((value.value != null || \n value instanceof tree.Variable || \n value instanceof tree.Property) ?\n value : new(tree.Anonymous)(value, index), index, fileInfo);\n },\n\n //\n // A Variable entity, such as `@fink`, in\n //\n // width: @fink + 2px\n //\n // We use a different parser for variable definitions,\n // see `parsers.variable`.\n //\n variable: function () {\n let ch;\n let name;\n const index = parserInput.i;\n\n parserInput.save();\n if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^@@?[\\w-]+/))) {\n ch = parserInput.currentChar();\n if (ch === '(' || ch === '[' && !parserInput.prevChar().match(/^\\s/)) {\n // this may be a VariableCall lookup\n const result = parsers.variableCall(name);\n if (result) {\n parserInput.forget();\n return result;\n }\n }\n parserInput.forget();\n return new(tree.Variable)(name, index, fileInfo);\n }\n parserInput.restore();\n },\n\n // A variable entity using the protective {} e.g. @{var}\n variableCurly: function () {\n let curly;\n const index = parserInput.i;\n\n if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\\{([\\w-]+)\\}/))) {\n return new(tree.Variable)(`@${curly[1]}`, index, fileInfo);\n }\n },\n //\n // A Property accessor, such as `$color`, in\n //\n // background-color: $color\n //\n property: function () {\n let name;\n const index = parserInput.i;\n\n if (parserInput.currentChar() === '$' && (name = parserInput.$re(/^\\$[\\w-]+/))) {\n return new(tree.Property)(name, index, fileInfo);\n }\n },\n\n // A property entity useing the protective {} e.g. ${prop}\n propertyCurly: function () {\n let curly;\n const index = parserInput.i;\n\n if (parserInput.currentChar() === '$' && (curly = parserInput.$re(/^\\$\\{([\\w-]+)\\}/))) {\n return new(tree.Property)(`$${curly[1]}`, index, fileInfo);\n }\n },\n //\n // A Hexadecimal color\n //\n // #4F3C2F\n //\n // `rgb` and `hsl` colors are parsed through the `entities.call` parser.\n //\n color: function () {\n let rgb;\n parserInput.save();\n\n if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})([\\w.#\\[])?/))) {\n if (!rgb[2]) {\n parserInput.forget();\n return new(tree.Color)(rgb[1], undefined, rgb[0]);\n } \n }\n parserInput.restore();\n },\n\n colorKeyword: function () {\n parserInput.save();\n const autoCommentAbsorb = parserInput.autoCommentAbsorb;\n parserInput.autoCommentAbsorb = false;\n const k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/);\n parserInput.autoCommentAbsorb = autoCommentAbsorb;\n if (!k) {\n parserInput.forget();\n return;\n }\n parserInput.restore();\n const color = tree.Color.fromKeyword(k);\n if (color) {\n parserInput.$str(k);\n return color;\n }\n },\n\n //\n // A Dimension, that is, a number and a unit\n //\n // 0.5em 95%\n //\n dimension: function () {\n if (parserInput.peekNotNumeric()) {\n return;\n }\n\n const value = parserInput.$re(/^([+-]?\\d*\\.?\\d+)(%|[a-z_]+)?/i);\n if (value) {\n return new(tree.Dimension)(value[1], value[2]);\n }\n },\n\n //\n // A unicode descriptor, as is used in unicode-range\n //\n // U+0?? or U+00A1-00A9\n //\n unicodeDescriptor: function () {\n let ud;\n\n ud = parserInput.$re(/^U\\+[0-9a-fA-F?]+(\\-[0-9a-fA-F?]+)?/);\n if (ud) {\n return new(tree.UnicodeDescriptor)(ud[0]);\n }\n },\n\n //\n // JavaScript code to be evaluated\n //\n // `window.location.href`\n //\n javascript: function () {\n let js;\n const index = parserInput.i;\n\n parserInput.save();\n\n const escape = parserInput.$char('~');\n const jsQuote = parserInput.$char('`');\n\n if (!jsQuote) {\n parserInput.restore();\n return;\n }\n\n js = parserInput.$re(/^[^`]*`/);\n if (js) {\n parserInput.forget();\n return new(tree.JavaScript)(js.substr(0, js.length - 1), Boolean(escape), index, fileInfo);\n }\n parserInput.restore('invalid javascript definition');\n }\n },\n\n //\n // The variable part of a variable definition. Used in the `rule` parser\n //\n // @fink:\n //\n variable: function () {\n let name;\n\n if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\\w-]+)\\s*:/))) { return name[1]; }\n },\n\n //\n // Call a variable value to retrieve a detached ruleset\n // or a value from a detached ruleset's rules.\n //\n // @fink();\n // @fink;\n // color: @fink[@color];\n //\n variableCall: function (parsedName) {\n let lookups;\n let important;\n const i = parserInput.i;\n const inValue = !!parsedName;\n let name = parsedName;\n\n parserInput.save();\n\n if (name || (parserInput.currentChar() === '@'\n && (name = parserInput.$re(/^(@[\\w-]+)(\\(\\s*\\))?/)))) {\n\n lookups = this.mixin.ruleLookups();\n\n if (!lookups && ((inValue && parserInput.$str('()') !== '()') || (name[2] !== '()'))) {\n parserInput.restore('Missing \\'[...]\\' lookup in variable call');\n return;\n }\n\n if (!inValue) {\n name = name[1];\n }\n\n if (lookups && parsers.important()) {\n important = true;\n }\n\n const call = new tree.VariableCall(name, i, fileInfo);\n if (!inValue && parsers.end()) {\n parserInput.forget();\n return call;\n }\n else {\n parserInput.forget();\n return new tree.NamespaceValue(call, lookups, important, i, fileInfo);\n }\n }\n\n parserInput.restore();\n },\n\n //\n // extend syntax - used to extend selectors\n //\n extend: function(isRule) {\n let elements;\n let e;\n const index = parserInput.i;\n let option;\n let extendList;\n let extend;\n\n if (!parserInput.$str(isRule ? '&:extend(' : ':extend(')) {\n return;\n }\n\n do {\n option = null;\n elements = null;\n while (!(option = parserInput.$re(/^(all)(?=\\s*(\\)|,))/))) {\n e = this.element();\n if (!e) {\n break;\n }\n if (elements) {\n elements.push(e);\n } else {\n elements = [ e ];\n }\n }\n\n option = option && option[1];\n if (!elements) {\n error('Missing target selector for :extend().');\n }\n extend = new(tree.Extend)(new(tree.Selector)(elements), option, index, fileInfo);\n if (extendList) {\n extendList.push(extend);\n } else {\n extendList = [ extend ];\n }\n } while (parserInput.$char(','));\n\n expect(/^\\)/);\n\n if (isRule) {\n expect(/^;/);\n }\n\n return extendList;\n },\n\n //\n // extendRule - used in a rule to extend all the parent selectors\n //\n extendRule: function() {\n return this.extend(true);\n },\n\n //\n // Mixins\n //\n mixin: {\n //\n // A Mixin call, with an optional argument list\n //\n // #mixins > .square(#fff);\n // #mixins.square(#fff);\n // .rounded(4px, black);\n // .button;\n //\n // We can lookup / return a value using the lookup syntax:\n //\n // color: #mixin.square(#fff)[@color];\n //\n // The `while` loop is there because mixins can be\n // namespaced, but we only support the child and descendant\n // selector for now.\n //\n call: function (inValue, getLookup) {\n const s = parserInput.currentChar();\n let important = false;\n let lookups;\n const index = parserInput.i;\n let elements;\n let args;\n let hasParens;\n\n if (s !== '.' && s !== '#') { return; }\n\n parserInput.save(); // stop us absorbing part of an invalid selector\n\n elements = this.elements();\n\n if (elements) {\n if (parserInput.$char('(')) {\n args = this.args(true).args;\n expectChar(')');\n hasParens = true;\n }\n\n if (getLookup !== false) {\n lookups = this.ruleLookups();\n }\n if (getLookup === true && !lookups) {\n parserInput.restore();\n return;\n }\n\n if (inValue && !lookups && !hasParens) {\n // This isn't a valid in-value mixin call\n parserInput.restore();\n return;\n }\n\n if (!inValue && parsers.important()) {\n important = true;\n }\n\n if (inValue || parsers.end()) {\n parserInput.forget();\n const mixin = new(tree.mixin.Call)(elements, args, index, fileInfo, !lookups && important);\n if (lookups) {\n return new tree.NamespaceValue(mixin, lookups, important);\n }\n else {\n return mixin;\n }\n }\n }\n\n parserInput.restore();\n },\n /**\n * Matching elements for mixins\n * (Start with . or # and can have > )\n */\n elements: function() {\n let elements;\n let e;\n let c;\n let elem;\n let elemIndex;\n const re = /^[#.](?:[\\w-]|\\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/;\n while (true) {\n elemIndex = parserInput.i;\n e = parserInput.$re(re);\n \n if (!e) {\n break;\n }\n elem = new(tree.Element)(c, e, false, elemIndex, fileInfo);\n if (elements) {\n elements.push(elem);\n } else {\n elements = [ elem ];\n }\n c = parserInput.$char('>');\n }\n return elements;\n },\n args: function (isCall) {\n const entities = parsers.entities;\n const returner = { args:null, variadic: false };\n let expressions = [];\n const argsSemiColon = [];\n const argsComma = [];\n let isSemiColonSeparated;\n let expressionContainsNamed;\n let name;\n let nameLoop;\n let value;\n let arg;\n let expand;\n let hasSep = true;\n\n parserInput.save();\n\n while (true) {\n if (isCall) {\n arg = parsers.detachedRuleset() || parsers.expression();\n } else {\n parserInput.commentStore.length = 0;\n if (parserInput.$str('...')) {\n returner.variadic = true;\n if (parserInput.$char(';') && !isSemiColonSeparated) {\n isSemiColonSeparated = true;\n }\n (isSemiColonSeparated ? argsSemiColon : argsComma)\n .push({ variadic: true });\n break;\n }\n arg = entities.variable() || entities.property() || entities.literal() || entities.keyword() || this.call(true);\n }\n\n if (!arg || !hasSep) {\n break;\n }\n\n nameLoop = null;\n if (arg.throwAwayComments) {\n arg.throwAwayComments();\n }\n value = arg;\n let val = null;\n\n if (isCall) {\n // Variable\n if (arg.value && arg.value.length == 1) {\n val = arg.value[0];\n }\n } else {\n val = arg;\n }\n\n if (val && (val instanceof tree.Variable || val instanceof tree.Property)) {\n if (parserInput.$char(':')) {\n if (expressions.length > 0) {\n if (isSemiColonSeparated) {\n error('Cannot mix ; and , as delimiter types');\n }\n expressionContainsNamed = true;\n }\n\n value = parsers.detachedRuleset() || parsers.expression();\n\n if (!value) {\n if (isCall) {\n error('could not understand value for named argument');\n } else {\n parserInput.restore();\n returner.args = [];\n return returner;\n }\n }\n nameLoop = (name = val.name);\n } else if (parserInput.$str('...')) {\n if (!isCall) {\n returner.variadic = true;\n if (parserInput.$char(';') && !isSemiColonSeparated) {\n isSemiColonSeparated = true;\n }\n (isSemiColonSeparated ? argsSemiColon : argsComma)\n .push({ name: arg.name, variadic: true });\n break;\n } else {\n expand = true;\n }\n } else if (!isCall) {\n name = nameLoop = val.name;\n value = null;\n }\n }\n\n if (value) {\n expressions.push(value);\n }\n\n argsComma.push({ name:nameLoop, value, expand });\n\n if (parserInput.$char(',')) {\n hasSep = true;\n continue;\n }\n hasSep = parserInput.$char(';') === ';';\n\n if (hasSep || isSemiColonSeparated) {\n\n if (expressionContainsNamed) {\n error('Cannot mix ; and , as delimiter types');\n }\n\n isSemiColonSeparated = true;\n\n if (expressions.length > 1) {\n value = new(tree.Value)(expressions);\n }\n argsSemiColon.push({ name, value, expand });\n\n name = null;\n expressions = [];\n expressionContainsNamed = false;\n }\n }\n\n parserInput.forget();\n returner.args = isSemiColonSeparated ? argsSemiColon : argsComma;\n return returner;\n },\n //\n // A Mixin definition, with a list of parameters\n //\n // .rounded (@radius: 2px, @color) {\n // ...\n // }\n //\n // Until we have a finer grained state-machine, we have to\n // do a look-ahead, to make sure we don't have a mixin call.\n // See the `rule` function for more information.\n //\n // We start by matching `.rounded (`, and then proceed on to\n // the argument list, which has optional default values.\n // We store the parameters in `params`, with a `value` key,\n // if there is a value, such as in the case of `@radius`.\n //\n // Once we've got our params list, and a closing `)`, we parse\n // the `{...}` block.\n //\n definition: function () {\n let name;\n let params = [];\n let match;\n let ruleset;\n let cond;\n let variadic = false;\n if ((parserInput.currentChar() !== '.' && parserInput.currentChar() !== '#') ||\n parserInput.peek(/^[^{]*\\}/)) {\n return;\n }\n\n parserInput.save();\n\n match = parserInput.$re(/^([#.](?:[\\w-]|\\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\\s*\\(/);\n if (match) {\n name = match[1];\n\n const argInfo = this.args(false);\n params = argInfo.args;\n variadic = argInfo.variadic;\n\n // .mixincall(\"@{a}\");\n // looks a bit like a mixin definition..\n // also\n // .mixincall(@a: {rule: set;});\n // so we have to be nice and restore\n if (!parserInput.$char(')')) {\n parserInput.restore('Missing closing \\')\\'');\n return;\n }\n\n parserInput.commentStore.length = 0;\n\n if (parserInput.$str('when')) { // Guard\n cond = expect(parsers.conditions, 'expected condition');\n }\n\n ruleset = parsers.block();\n\n if (ruleset) {\n parserInput.forget();\n return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);\n } else {\n parserInput.restore();\n }\n } else {\n parserInput.forget();\n }\n },\n \n ruleLookups: function() {\n let rule;\n let args;\n const lookups = [];\n\n if (parserInput.currentChar() !== '[') { \n return;\n }\n\n while (true) {\n parserInput.save();\n args = null;\n rule = this.lookupValue();\n if (!rule && rule !== '') {\n parserInput.restore();\n break;\n }\n lookups.push(rule);\n parserInput.forget();\n }\n if (lookups.length > 0) {\n return lookups;\n }\n },\n \n lookupValue: function() {\n parserInput.save();\n \n if (!parserInput.$char('[')) { \n parserInput.restore();\n return;\n }\n \n const name = parserInput.$re(/^(?:[@$]{0,2})[_a-zA-Z0-9-]*/);\n \n if (!parserInput.$char(']')) {\n parserInput.restore();\n return;\n } \n\n if (name || name === '') {\n parserInput.forget();\n return name;\n }\n \n parserInput.restore();\n }\n },\n //\n // Entities are the smallest recognized token,\n // and can be found inside a rule's value.\n //\n entity: function () {\n const entities = this.entities;\n\n return this.comment() || entities.literal() || entities.variable() || entities.url() ||\n entities.property() || entities.call() || entities.keyword() || this.mixin.call(true) ||\n entities.javascript();\n },\n\n //\n // A Declaration terminator. Note that we use `peek()` to check for '}',\n // because the `block` rule will be expecting it, but we still need to make sure\n // it's there, if ';' was omitted.\n //\n end: function () {\n return parserInput.$char(';') || parserInput.peek('}');\n },\n\n //\n // IE's alpha function\n //\n // alpha(opacity=88)\n //\n ieAlpha: function () {\n let value;\n\n // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18\n if (!parserInput.$re(/^opacity=/i)) { return; }\n value = parserInput.$re(/^\\d+/);\n if (!value) {\n value = expect(parsers.entities.variable, 'Could not parse alpha');\n value = `@{${value.name.slice(1)}}`;\n }\n expectChar(')');\n return new tree.Quoted('', `alpha(opacity=${value})`);\n },\n\n //\n // A Selector Element\n //\n // div\n // + h1\n // #socks\n // input[type=\"text\"]\n //\n // Elements are the building blocks for Selectors,\n // they are made out of a `Combinator` (see combinator rule),\n // and an element name, such as a tag a class, or `*`.\n //\n element: function () {\n let e;\n let c;\n let v;\n const index = parserInput.i;\n\n c = this.combinator();\n\n e = parserInput.$re(/^(?:\\d+\\.\\d+|\\d+)%/) ||\n parserInput.$re(/^(?:[.#]?|:*)(?:[\\w-]|[^\\x00-\\x9f]|\\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||\n parserInput.$char('*') || parserInput.$char('&') || this.attribute() ||\n parserInput.$re(/^\\([^&()@]+\\)/) || parserInput.$re(/^[\\.#:](?=@)/) ||\n this.entities.variableCurly();\n\n if (!e) {\n parserInput.save();\n if (parserInput.$char('(')) {\n if ((v = this.selector(false)) && parserInput.$char(')')) {\n e = new(tree.Paren)(v);\n parserInput.forget();\n } else {\n parserInput.restore('Missing closing \\')\\'');\n }\n } else {\n parserInput.forget();\n }\n }\n\n if (e) { return new(tree.Element)(c, e, e instanceof tree.Variable, index, fileInfo); }\n },\n\n //\n // Combinators combine elements together, in a Selector.\n //\n // Because our parser isn't white-space sensitive, special care\n // has to be taken, when parsing the descendant combinator, ` `,\n // as it's an empty space. We have to check the previous character\n // in the input, to see if it's a ` ` character. More info on how\n // we deal with this in *combinator.js*.\n //\n combinator: function () {\n let c = parserInput.currentChar();\n\n if (c === '/') {\n parserInput.save();\n const slashedCombinator = parserInput.$re(/^\\/[a-z]+\\//i);\n if (slashedCombinator) {\n parserInput.forget();\n return new(tree.Combinator)(slashedCombinator);\n }\n parserInput.restore();\n }\n\n if (c === '>' || c === '+' || c === '~' || c === '|' || c === '^') {\n parserInput.i++;\n if (c === '^' && parserInput.currentChar() === '^') {\n c = '^^';\n parserInput.i++;\n }\n while (parserInput.isWhitespace()) { parserInput.i++; }\n return new(tree.Combinator)(c);\n } else if (parserInput.isWhitespace(-1)) {\n return new(tree.Combinator)(' ');\n } else {\n return new(tree.Combinator)(null);\n }\n },\n //\n // A CSS Selector\n // with less extensions e.g. the ability to extend and guard\n //\n // .class > div + h1\n // li a:hover\n //\n // Selectors are made out of one or more Elements, see above.\n //\n selector: function (isLess) {\n const index = parserInput.i;\n let elements;\n let extendList;\n let c;\n let e;\n let allExtends;\n let when;\n let condition;\n isLess = isLess !== false;\n while ((isLess && (extendList = this.extend())) || (isLess && (when = parserInput.$str('when'))) || (e = this.element())) {\n if (when) {\n condition = expect(this.conditions, 'expected condition');\n } else if (condition) {\n error('CSS guard can only be used at the end of selector');\n } else if (extendList) {\n if (allExtends) {\n allExtends = allExtends.concat(extendList);\n } else {\n allExtends = extendList;\n }\n } else {\n if (allExtends) { error('Extend can only be used at the end of selector'); }\n c = parserInput.currentChar();\n if (elements) {\n elements.push(e);\n } else {\n elements = [ e ];\n }\n e = null;\n }\n if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') {\n break;\n }\n }\n\n if (elements) { return new(tree.Selector)(elements, allExtends, condition, index, fileInfo); }\n if (allExtends) { error('Extend must be used to extend a selector, it cannot be used on its own'); }\n },\n selectors: function () {\n let s;\n let selectors;\n while (true) {\n s = this.selector();\n if (!s) {\n break;\n }\n if (selectors) {\n selectors.push(s);\n } else {\n selectors = [ s ];\n }\n parserInput.commentStore.length = 0;\n if (s.condition && selectors.length > 1) {\n error(\"Guards are only currently allowed on a single selector.\");\n }\n if (!parserInput.$char(',')) { break; }\n if (s.condition) {\n error(\"Guards are only currently allowed on a single selector.\");\n }\n parserInput.commentStore.length = 0;\n }\n return selectors;\n },\n attribute: function () {\n if (!parserInput.$char('[')) { return; }\n\n const entities = this.entities;\n let key;\n let val;\n let op;\n\n if (!(key = entities.variableCurly())) {\n key = expect(/^(?:[_A-Za-z0-9-\\*]*\\|)?(?:[_A-Za-z0-9-]|\\\\.)+/);\n }\n\n op = parserInput.$re(/^[|~*$^]?=/);\n if (op) {\n val = entities.quoted() || parserInput.$re(/^[0-9]+%/) || parserInput.$re(/^[\\w-]+/) || entities.variableCurly();\n }\n\n expectChar(']');\n\n return new(tree.Attribute)(key, op, val);\n },\n\n //\n // The `block` rule is used by `ruleset` and `mixin.definition`.\n // It's a wrapper around the `primary` rule, with added `{}`.\n //\n block: function () {\n let content;\n if (parserInput.$char('{') && (content = this.primary()) && parserInput.$char('}')) {\n return content;\n }\n },\n\n blockRuleset: function() {\n let block = this.block();\n\n if (block) {\n block = new tree.Ruleset(null, block);\n }\n return block;\n },\n\n detachedRuleset: function() {\n let argInfo;\n let params;\n let variadic;\n\n parserInput.save();\n if (parserInput.$re(/^[.#]\\(/)) {\n /**\n * DR args currently only implemented for each() function, and not \n * yet settable as `@dr: #(@arg) {}`\n * This should be done when DRs are merged with mixins.\n * See: https://github.com/less/less-meta/issues/16\n */\n argInfo = this.mixin.args(false);\n params = argInfo.args;\n variadic = argInfo.variadic;\n if (!parserInput.$char(')')) {\n parserInput.restore();\n return;\n }\n }\n const blockRuleset = this.blockRuleset();\n if (blockRuleset) {\n parserInput.forget();\n if (params) {\n return new tree.mixin.Definition(null, params, blockRuleset, null, variadic);\n }\n return new tree.DetachedRuleset(blockRuleset);\n }\n parserInput.restore();\n },\n\n //\n // div, .class, body > p {...}\n //\n ruleset: function () {\n let selectors;\n let rules;\n let debugInfo;\n\n parserInput.save();\n\n if (context.dumpLineNumbers) {\n debugInfo = getDebugInfo(parserInput.i);\n }\n\n selectors = this.selectors();\n\n if (selectors && (rules = this.block())) {\n parserInput.forget();\n const ruleset = new(tree.Ruleset)(selectors, rules, context.strictImports);\n if (context.dumpLineNumbers) {\n ruleset.debugInfo = debugInfo;\n }\n return ruleset;\n } else {\n parserInput.restore();\n }\n },\n declaration: function () {\n let name;\n let value;\n const index = parserInput.i;\n let hasDR;\n const c = parserInput.currentChar();\n let important;\n let merge;\n let isVariable;\n\n if (c === '.' || c === '#' || c === '&' || c === ':') { return; }\n\n parserInput.save();\n\n name = this.variable() || this.ruleProperty();\n if (name) {\n isVariable = typeof name === 'string';\n\n if (isVariable) {\n value = this.detachedRuleset();\n if (value) {\n hasDR = true;\n }\n }\n\n parserInput.commentStore.length = 0;\n if (!value) {\n // a name returned by this.ruleProperty() is always an array of the form:\n // [string-1, ..., string-n, \"\"] or [string-1, ..., string-n, \"+\"]\n // where each item is a tree.Keyword or tree.Variable\n merge = !isVariable && name.length > 1 && name.pop().value;\n\n // Custom property values get permissive parsing\n if (name[0].value && name[0].value.slice(0, 2) === '--') {\n value = this.permissiveValue();\n }\n // Try to store values as anonymous\n // If we need the value later we'll re-parse it in ruleset.parseValue\n else {\n value = this.anonymousValue();\n }\n if (value) {\n parserInput.forget();\n // anonymous values absorb the end ';' which is required for them to work\n return new(tree.Declaration)(name, value, false, merge, index, fileInfo);\n }\n\n if (!value) {\n value = this.value();\n }\n\n if (value) {\n important = this.important();\n } else if (isVariable) {\n // As a last resort, try permissiveValue\n value = this.permissiveValue();\n }\n }\n\n if (value && (this.end() || hasDR)) {\n parserInput.forget();\n return new(tree.Declaration)(name, value, important, merge, index, fileInfo);\n }\n else {\n parserInput.restore();\n }\n } else {\n parserInput.restore();\n }\n },\n anonymousValue: function () {\n const index = parserInput.i;\n const match = parserInput.$re(/^([^.#@\\$+\\/'\"*`(;{}-]*);/);\n if (match) {\n return new(tree.Anonymous)(match[1], index);\n }\n },\n /**\n * Used for custom properties, at-rules, and variables (as fallback)\n * Parses almost anything inside of {} [] () \"\" blocks\n * until it reaches outer-most tokens.\n * \n * First, it will try to parse comments and entities to reach\n * the end. This is mostly like the Expression parser except no\n * math is allowed.\n */\n permissiveValue: function (untilTokens) {\n let i;\n let e;\n let done;\n let value;\n const tok = untilTokens || ';';\n const index = parserInput.i;\n const result = [];\n\n function testCurrentChar() {\n const char = parserInput.currentChar();\n if (typeof tok === 'string') {\n return char === tok;\n } else {\n return tok.test(char);\n }\n }\n if (testCurrentChar()) {\n return;\n }\n value = [];\n do {\n e = this.comment();\n if (e) {\n value.push(e);\n continue;\n }\n e = this.entity();\n if (e) {\n value.push(e);\n }\n } while (e);\n\n done = testCurrentChar();\n\n if (value.length > 0) {\n value = new(tree.Expression)(value);\n if (done) {\n return value;\n }\n else {\n result.push(value);\n }\n // Preserve space before $parseUntil as it will not\n if (parserInput.prevChar() === ' ') {\n result.push(new tree.Anonymous(' ', index));\n }\n }\n parserInput.save();\n\n value = parserInput.$parseUntil(tok);\n\n if (value) {\n if (typeof value === 'string') {\n error(`Expected '${value}'`, 'Parse');\n }\n if (value.length === 1 && value[0] === ' ') {\n parserInput.forget();\n return new tree.Anonymous('', index);\n }\n let item;\n for (i = 0; i < value.length; i++) {\n item = value[i];\n if (Array.isArray(item)) {\n // Treat actual quotes as normal quoted values\n result.push(new tree.Quoted(item[0], item[1], true, index, fileInfo));\n }\n else {\n if (i === value.length - 1) {\n item = item.trim();\n }\n // Treat like quoted values, but replace vars like unquoted expressions\n const quote = new tree.Quoted('\\'', item, true, index, fileInfo);\n quote.variableRegex = /@([\\w-]+)/g;\n quote.propRegex = /\\$([\\w-]+)/g;\n result.push(quote);\n }\n }\n parserInput.forget();\n return new tree.Expression(result, true);\n }\n parserInput.restore();\n },\n\n //\n // An @import atrule\n //\n // @import \"lib\";\n //\n // Depending on our environment, importing is done differently:\n // In the browser, it's an XHR request, in Node, it would be a\n // file-system operation. The function used for importing is\n // stored in `import`, which we pass to the Import constructor.\n //\n 'import': function () {\n let path;\n let features;\n const index = parserInput.i;\n\n const dir = parserInput.$re(/^@import?\\s+/);\n\n if (dir) {\n const options = (dir ? this.importOptions() : null) || {};\n\n if ((path = this.entities.quoted() || this.entities.url())) {\n features = this.mediaFeatures();\n\n if (!parserInput.$char(';')) {\n parserInput.i = index;\n error('missing semi-colon or unrecognised media features on import');\n }\n features = features && new(tree.Value)(features);\n return new(tree.Import)(path, features, options, index, fileInfo);\n }\n else {\n parserInput.i = index;\n error('malformed import statement');\n }\n }\n },\n\n importOptions: function() {\n let o;\n const options = {};\n let optionName;\n let value;\n\n // list of options, surrounded by parens\n if (!parserInput.$char('(')) { return null; }\n do {\n o = this.importOption();\n if (o) {\n optionName = o;\n value = true;\n switch (optionName) {\n case 'css':\n optionName = 'less';\n value = false;\n break;\n case 'once':\n optionName = 'multiple';\n value = false;\n break;\n }\n options[optionName] = value;\n if (!parserInput.$char(',')) { break; }\n }\n } while (o);\n expectChar(')');\n return options;\n },\n\n importOption: function() {\n const opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/);\n if (opt) {\n return opt[1];\n }\n },\n\n mediaFeature: function () {\n const entities = this.entities;\n const nodes = [];\n let e;\n let p;\n parserInput.save();\n do {\n e = entities.keyword() || entities.variable() || entities.mixinLookup();\n if (e) {\n nodes.push(e);\n } else if (parserInput.$char('(')) {\n p = this.property();\n e = this.value();\n if (parserInput.$char(')')) {\n if (p && e) {\n nodes.push(new(tree.Paren)(new(tree.Declaration)(p, e, null, null, parserInput.i, fileInfo, true)));\n } else if (e) {\n nodes.push(new(tree.Paren)(e));\n } else {\n error('badly formed media feature definition');\n }\n } else {\n error('Missing closing \\')\\'', 'Parse');\n }\n }\n } while (e);\n\n parserInput.forget();\n if (nodes.length > 0) {\n return new(tree.Expression)(nodes);\n }\n },\n\n mediaFeatures: function () {\n const entities = this.entities;\n const features = [];\n let e;\n do {\n e = this.mediaFeature();\n if (e) {\n features.push(e);\n if (!parserInput.$char(',')) { break; }\n } else {\n e = entities.variable() || entities.mixinLookup();\n if (e) {\n features.push(e);\n if (!parserInput.$char(',')) { break; }\n }\n }\n } while (e);\n\n return features.length > 0 ? features : null;\n },\n\n media: function () {\n let features;\n let rules;\n let media;\n let debugInfo;\n const index = parserInput.i;\n\n if (context.dumpLineNumbers) {\n debugInfo = getDebugInfo(index);\n }\n\n parserInput.save();\n\n if (parserInput.$str('@media')) {\n features = this.mediaFeatures();\n\n rules = this.block();\n\n if (!rules) {\n error('media definitions require block statements after any features');\n }\n\n parserInput.forget();\n\n media = new(tree.Media)(rules, features, index, fileInfo);\n if (context.dumpLineNumbers) {\n media.debugInfo = debugInfo;\n }\n\n return media;\n }\n\n parserInput.restore();\n },\n\n //\n\n // A @plugin directive, used to import plugins dynamically.\n //\n // @plugin (args) \"lib\";\n //\n plugin: function () {\n let path;\n let args;\n let options;\n const index = parserInput.i;\n const dir = parserInput.$re(/^@plugin?\\s+/);\n\n if (dir) {\n args = this.pluginArgs();\n\n if (args) {\n options = {\n pluginArgs: args,\n isPlugin: true\n };\n }\n else {\n options = { isPlugin: true };\n }\n\n if ((path = this.entities.quoted() || this.entities.url())) {\n\n if (!parserInput.$char(';')) {\n parserInput.i = index;\n error('missing semi-colon on @plugin');\n }\n return new(tree.Import)(path, null, options, index, fileInfo);\n }\n else {\n parserInput.i = index;\n error('malformed @plugin statement');\n }\n }\n },\n\n pluginArgs: function() {\n // list of options, surrounded by parens\n parserInput.save();\n if (!parserInput.$char('(')) {\n parserInput.restore();\n return null;\n }\n const args = parserInput.$re(/^\\s*([^\\);]+)\\)\\s*/);\n if (args[1]) {\n parserInput.forget();\n return args[1].trim();\n }\n else { \n parserInput.restore();\n return null;\n }\n },\n\n //\n // A CSS AtRule\n //\n // @charset \"utf-8\";\n //\n atrule: function () {\n const index = parserInput.i;\n let name;\n let value;\n let rules;\n let nonVendorSpecificName;\n let hasIdentifier;\n let hasExpression;\n let hasUnknown;\n let hasBlock = true;\n let isRooted = true;\n\n if (parserInput.currentChar() !== '@') { return; }\n\n value = this['import']() || this.plugin() || this.media();\n if (value) {\n return value;\n }\n\n parserInput.save();\n\n name = parserInput.$re(/^@[a-z-]+/);\n\n if (!name) { return; }\n\n nonVendorSpecificName = name;\n if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) {\n nonVendorSpecificName = `@${name.slice(name.indexOf('-', 2) + 1)}`;\n }\n\n switch (nonVendorSpecificName) {\n case '@charset':\n hasIdentifier = true;\n hasBlock = false;\n break;\n case '@namespace':\n hasExpression = true;\n hasBlock = false;\n break;\n case '@keyframes':\n case '@counter-style':\n hasIdentifier = true;\n break;\n case '@document':\n case '@supports':\n hasUnknown = true;\n isRooted = false;\n break;\n default:\n hasUnknown = true;\n break;\n }\n\n parserInput.commentStore.length = 0;\n\n if (hasIdentifier) {\n value = this.entity();\n if (!value) {\n error(`expected ${name} identifier`);\n }\n } else if (hasExpression) {\n value = this.expression();\n if (!value) {\n error(`expected ${name} expression`);\n }\n } else if (hasUnknown) {\n value = this.permissiveValue(/^[{;]/);\n hasBlock = (parserInput.currentChar() === '{');\n if (!value) {\n if (!hasBlock && parserInput.currentChar() !== ';') {\n error(`${name} rule is missing block or ending semi-colon`);\n }\n }\n else if (!value.value) {\n value = null;\n }\n }\n\n if (hasBlock) {\n rules = this.blockRuleset();\n }\n\n if (rules || (!hasBlock && value && parserInput.$char(';'))) {\n parserInput.forget();\n return new(tree.AtRule)(name, value, rules, index, fileInfo,\n context.dumpLineNumbers ? getDebugInfo(index) : null,\n isRooted\n );\n }\n\n parserInput.restore('at-rule options not recognised');\n },\n\n //\n // A Value is a comma-delimited list of Expressions\n //\n // font-family: Baskerville, Georgia, serif;\n //\n // In a Rule, a Value represents everything after the `:`,\n // and before the `;`.\n //\n value: function () {\n let e;\n const expressions = [];\n const index = parserInput.i;\n\n do {\n e = this.expression();\n if (e) {\n expressions.push(e);\n if (!parserInput.$char(',')) { break; }\n }\n } while (e);\n\n if (expressions.length > 0) {\n return new(tree.Value)(expressions, index);\n }\n },\n important: function () {\n if (parserInput.currentChar() === '!') {\n return parserInput.$re(/^! *important/);\n }\n },\n sub: function () {\n let a;\n let e;\n\n parserInput.save();\n if (parserInput.$char('(')) {\n a = this.addition();\n if (a && parserInput.$char(')')) {\n parserInput.forget();\n e = new(tree.Expression)([a]);\n e.parens = true;\n return e;\n }\n parserInput.restore('Expected \\')\\'');\n return;\n }\n parserInput.restore();\n },\n multiplication: function () {\n let m;\n let a;\n let op;\n let operation;\n let isSpaced;\n m = this.operand();\n if (m) {\n isSpaced = parserInput.isWhitespace(-1);\n while (true) {\n if (parserInput.peek(/^\\/[*\\/]/)) {\n break;\n }\n\n parserInput.save();\n\n op = parserInput.$char('/') || parserInput.$char('*') || parserInput.$str('./');\n\n if (!op) { parserInput.forget(); break; }\n\n a = this.operand();\n\n if (!a) { parserInput.restore(); break; }\n parserInput.forget();\n\n m.parensInOp = true;\n a.parensInOp = true;\n operation = new(tree.Operation)(op, [operation || m, a], isSpaced);\n isSpaced = parserInput.isWhitespace(-1);\n }\n return operation || m;\n }\n },\n addition: function () {\n let m;\n let a;\n let op;\n let operation;\n let isSpaced;\n m = this.multiplication();\n if (m) {\n isSpaced = parserInput.isWhitespace(-1);\n while (true) {\n op = parserInput.$re(/^[-+]\\s+/) || (!isSpaced && (parserInput.$char('+') || parserInput.$char('-')));\n if (!op) {\n break;\n }\n a = this.multiplication();\n if (!a) {\n break;\n }\n\n m.parensInOp = true;\n a.parensInOp = true;\n operation = new(tree.Operation)(op, [operation || m, a], isSpaced);\n isSpaced = parserInput.isWhitespace(-1);\n }\n return operation || m;\n }\n },\n conditions: function () {\n let a;\n let b;\n const index = parserInput.i;\n let condition;\n\n a = this.condition(true);\n if (a) {\n while (true) {\n if (!parserInput.peek(/^,\\s*(not\\s*)?\\(/) || !parserInput.$char(',')) {\n break;\n }\n b = this.condition(true);\n if (!b) {\n break;\n }\n condition = new(tree.Condition)('or', condition || a, b, index);\n }\n return condition || a;\n }\n },\n condition: function (needsParens) {\n let result;\n let logical;\n let next;\n function or() {\n return parserInput.$str('or');\n }\n\n result = this.conditionAnd(needsParens);\n if (!result) {\n return ;\n }\n logical = or();\n if (logical) {\n next = this.condition(needsParens);\n if (next) {\n result = new(tree.Condition)(logical, result, next);\n } else {\n return ;\n }\n }\n return result;\n },\n conditionAnd: function (needsParens) {\n let result;\n let logical;\n let next;\n const self = this;\n function insideCondition() {\n const cond = self.negatedCondition(needsParens) || self.parenthesisCondition(needsParens);\n if (!cond && !needsParens) {\n return self.atomicCondition(needsParens);\n }\n return cond;\n }\n function and() {\n return parserInput.$str('and');\n }\n\n result = insideCondition();\n if (!result) {\n return ;\n }\n logical = and();\n if (logical) {\n next = this.conditionAnd(needsParens);\n if (next) {\n result = new(tree.Condition)(logical, result, next);\n } else {\n return ;\n }\n }\n return result;\n },\n negatedCondition: function (needsParens) {\n if (parserInput.$str('not')) {\n const result = this.parenthesisCondition(needsParens);\n if (result) {\n result.negate = !result.negate;\n }\n return result;\n }\n },\n parenthesisCondition: function (needsParens) {\n function tryConditionFollowedByParenthesis(me) {\n let body;\n parserInput.save();\n body = me.condition(needsParens);\n if (!body) {\n parserInput.restore();\n return ;\n }\n if (!parserInput.$char(')')) {\n parserInput.restore();\n return ;\n }\n parserInput.forget();\n return body;\n }\n\n let body;\n parserInput.save();\n if (!parserInput.$str('(')) {\n parserInput.restore();\n return ;\n }\n body = tryConditionFollowedByParenthesis(this);\n if (body) {\n parserInput.forget();\n return body;\n }\n\n body = this.atomicCondition(needsParens);\n if (!body) {\n parserInput.restore();\n return ;\n }\n if (!parserInput.$char(')')) {\n parserInput.restore(`expected ')' got '${parserInput.currentChar()}'`);\n return ;\n }\n parserInput.forget();\n return body;\n },\n atomicCondition: function (needsParens) {\n const entities = this.entities;\n const index = parserInput.i;\n let a;\n let b;\n let c;\n let op;\n\n function cond() {\n return this.addition() || entities.keyword() || entities.quoted() || entities.mixinLookup();\n }\n cond = cond.bind(this);\n\n a = cond();\n if (a) {\n if (parserInput.$char('>')) {\n if (parserInput.$char('=')) {\n op = '>=';\n } else {\n op = '>';\n }\n } else\n if (parserInput.$char('<')) {\n if (parserInput.$char('=')) {\n op = '<=';\n } else {\n op = '<';\n }\n } else\n if (parserInput.$char('=')) {\n if (parserInput.$char('>')) {\n op = '=>';\n } else if (parserInput.$char('<')) {\n op = '=<';\n } else {\n op = '=';\n }\n }\n if (op) {\n b = cond();\n if (b) {\n c = new(tree.Condition)(op, a, b, index, false);\n } else {\n error('expected expression');\n }\n } else {\n c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, false);\n }\n return c;\n }\n },\n\n //\n // An operand is anything that can be part of an operation,\n // such as a Color, or a Variable\n //\n operand: function () {\n const entities = this.entities;\n let negate;\n\n if (parserInput.peek(/^-[@\\$\\(]/)) {\n negate = parserInput.$char('-');\n }\n\n let o = this.sub() || entities.dimension() ||\n entities.color() || entities.variable() ||\n entities.property() || entities.call() ||\n entities.quoted(true) || entities.colorKeyword() ||\n entities.mixinLookup();\n\n if (negate) {\n o.parensInOp = true;\n o = new(tree.Negative)(o);\n }\n\n return o;\n },\n\n //\n // Expressions either represent mathematical operations,\n // or white-space delimited Entities.\n //\n // 1px solid black\n // @var * 2\n //\n expression: function () {\n const entities = [];\n let e;\n let delim;\n const index = parserInput.i;\n\n do {\n e = this.comment();\n if (e) {\n entities.push(e);\n continue;\n }\n e = this.addition() || this.entity();\n if (e) {\n entities.push(e);\n // operations do not allow keyword \"/\" dimension (e.g. small/20px) so we support that here\n if (!parserInput.peek(/^\\/[\\/*]/)) {\n delim = parserInput.$char('/');\n if (delim) {\n entities.push(new(tree.Anonymous)(delim, index));\n }\n }\n }\n } while (e);\n if (entities.length > 0) {\n return new(tree.Expression)(entities);\n }\n },\n property: function () {\n const name = parserInput.$re(/^(\\*?-?[_a-zA-Z0-9-]+)\\s*:/);\n if (name) {\n return name[1];\n }\n },\n ruleProperty: function () {\n let name = [];\n const index = [];\n let s;\n let k;\n\n parserInput.save();\n\n const simpleProperty = parserInput.$re(/^([_a-zA-Z0-9-]+)\\s*:/);\n if (simpleProperty) {\n name = [new(tree.Keyword)(simpleProperty[1])];\n parserInput.forget();\n return name;\n }\n\n function match(re) {\n const i = parserInput.i;\n const chunk = parserInput.$re(re);\n if (chunk) {\n index.push(i);\n return name.push(chunk[1]);\n }\n }\n\n match(/^(\\*?)/);\n while (true) {\n if (!match(/^((?:[\\w-]+)|(?:[@\\$]\\{[\\w-]+\\}))/)) {\n break;\n }\n }\n\n if ((name.length > 1) && match(/^((?:\\+_|\\+)?)\\s*:/)) {\n parserInput.forget();\n\n // at last, we have the complete match now. move forward,\n // convert name particles to tree objects and return:\n if (name[0] === '') {\n name.shift();\n index.shift();\n }\n for (k = 0; k < name.length; k++) {\n s = name[k];\n name[k] = (s.charAt(0) !== '@' && s.charAt(0) !== '$') ?\n new(tree.Keyword)(s) :\n (s.charAt(0) === '@' ?\n new(tree.Variable)(`@${s.slice(2, -1)}`, index[k], fileInfo) :\n new(tree.Property)(`$${s.slice(2, -1)}`, index[k], fileInfo));\n }\n return name;\n }\n parserInput.restore();\n }\n }\n };\n};\nParser.serializeVars = vars => {\n let s = '';\n\n for (const name in vars) {\n if (Object.hasOwnProperty.call(vars, name)) {\n const value = vars[name];\n s += `${((name[0] === '@') ? '' : '@') + name}: ${value}${(String(value).slice(-1) === ';') ? '' : ';'}`;\n }\n }\n\n return s;\n};\n\nexport default Parser;\n","import Dimension from '../tree/dimension';\nimport Color from '../tree/color';\nimport Quoted from '../tree/quoted';\nimport Anonymous from '../tree/anonymous';\nlet colorFunctions;\n\nfunction clamp(val) {\n return Math.min(1, Math.max(0, val));\n}\nfunction hsla(origColor, hsl) {\n const color = colorFunctions.hsla(hsl.h, hsl.s, hsl.l, hsl.a);\n if (color) {\n if (origColor.value && \n /^(rgb|hsl)/.test(origColor.value)) {\n color.value = origColor.value;\n } else {\n color.value = 'rgb';\n }\n return color;\n }\n}\nfunction toHSL(color) {\n if (color.toHSL) {\n return color.toHSL();\n } else {\n throw new Error('Argument cannot be evaluated to a color');\n }\n}\n\nfunction toHSV(color) {\n if (color.toHSV) {\n return color.toHSV();\n } else {\n throw new Error('Argument cannot be evaluated to a color');\n }\n}\n\nfunction number(n) {\n if (n instanceof Dimension) {\n return parseFloat(n.unit.is('%') ? n.value / 100 : n.value);\n } else if (typeof n === 'number') {\n return n;\n } else {\n throw {\n type: 'Argument',\n message: 'color functions take numbers as parameters'\n };\n }\n}\nfunction scaled(n, size) {\n if (n instanceof Dimension && n.unit.is('%')) {\n return parseFloat(n.value * size / 100);\n } else {\n return number(n);\n }\n}\ncolorFunctions = {\n rgb: function (r, g, b) {\n const color = colorFunctions.rgba(r, g, b, 1.0);\n if (color) {\n color.value = 'rgb';\n return color;\n }\n },\n rgba: function (r, g, b, a) {\n try {\n if (r instanceof Color) {\n if (g) {\n a = number(g);\n } else {\n a = r.alpha;\n }\n return new Color(r.rgb, a, 'rgba');\n }\n const rgb = [r, g, b].map(c => scaled(c, 255));\n a = number(a);\n return new Color(rgb, a, 'rgba');\n }\n catch (e) {}\n },\n hsl: function (h, s, l) {\n const color = colorFunctions.hsla(h, s, l, 1.0);\n if (color) {\n color.value = 'hsl';\n return color;\n }\n },\n hsla: function (h, s, l, a) {\n try {\n if (h instanceof Color) {\n if (s) {\n a = number(s);\n } else {\n a = h.alpha;\n }\n return new Color(h.rgb, a, 'hsla');\n }\n\n let m1;\n let m2;\n\n function hue(h) {\n h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);\n if (h * 6 < 1) {\n return m1 + (m2 - m1) * h * 6;\n }\n else if (h * 2 < 1) {\n return m2;\n }\n else if (h * 3 < 2) {\n return m1 + (m2 - m1) * (2 / 3 - h) * 6;\n }\n else {\n return m1;\n }\n }\n\n h = (number(h) % 360) / 360;\n s = clamp(number(s));l = clamp(number(l));a = clamp(number(a));\n\n m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;\n m1 = l * 2 - m2;\n\n const rgb = [\n hue(h + 1 / 3) * 255,\n hue(h) * 255,\n hue(h - 1 / 3) * 255\n ];\n a = number(a);\n return new Color(rgb, a, 'hsla');\n }\n catch (e) {}\n },\n\n hsv: function(h, s, v) {\n return colorFunctions.hsva(h, s, v, 1.0);\n },\n\n hsva: function(h, s, v, a) {\n h = ((number(h) % 360) / 360) * 360;\n s = number(s);v = number(v);a = number(a);\n\n let i;\n let f;\n i = Math.floor((h / 60) % 6);\n f = (h / 60) - i;\n\n const vs = [v,\n v * (1 - s),\n v * (1 - f * s),\n v * (1 - (1 - f) * s)];\n const perm = [[0, 3, 1],\n [2, 0, 1],\n [1, 0, 3],\n [1, 2, 0],\n [3, 1, 0],\n [0, 1, 2]];\n\n return colorFunctions.rgba(vs[perm[i][0]] * 255,\n vs[perm[i][1]] * 255,\n vs[perm[i][2]] * 255,\n a);\n },\n\n hue: function (color) {\n return new Dimension(toHSL(color).h);\n },\n saturation: function (color) {\n return new Dimension(toHSL(color).s * 100, '%');\n },\n lightness: function (color) {\n return new Dimension(toHSL(color).l * 100, '%');\n },\n hsvhue: function(color) {\n return new Dimension(toHSV(color).h);\n },\n hsvsaturation: function (color) {\n return new Dimension(toHSV(color).s * 100, '%');\n },\n hsvvalue: function (color) {\n return new Dimension(toHSV(color).v * 100, '%');\n },\n red: function (color) {\n return new Dimension(color.rgb[0]);\n },\n green: function (color) {\n return new Dimension(color.rgb[1]);\n },\n blue: function (color) {\n return new Dimension(color.rgb[2]);\n },\n alpha: function (color) {\n return new Dimension(toHSL(color).a);\n },\n luma: function (color) {\n return new Dimension(color.luma() * color.alpha * 100, '%');\n },\n luminance: function (color) {\n const luminance =\n (0.2126 * color.rgb[0] / 255) +\n (0.7152 * color.rgb[1] / 255) +\n (0.0722 * color.rgb[2] / 255);\n\n return new Dimension(luminance * color.alpha * 100, '%');\n },\n saturate: function (color, amount, method) {\n // filter: saturate(3.2);\n // should be kept as is, so check for color\n if (!color.rgb) {\n return null;\n }\n const hsl = toHSL(color);\n\n if (typeof method !== 'undefined' && method.value === 'relative') {\n hsl.s += hsl.s * amount.value / 100;\n }\n else {\n hsl.s += amount.value / 100;\n }\n hsl.s = clamp(hsl.s);\n return hsla(color, hsl);\n },\n desaturate: function (color, amount, method) {\n const hsl = toHSL(color);\n\n if (typeof method !== 'undefined' && method.value === 'relative') {\n hsl.s -= hsl.s * amount.value / 100;\n }\n else {\n hsl.s -= amount.value / 100;\n }\n hsl.s = clamp(hsl.s);\n return hsla(color, hsl);\n },\n lighten: function (color, amount, method) {\n const hsl = toHSL(color);\n\n if (typeof method !== 'undefined' && method.value === 'relative') {\n hsl.l += hsl.l * amount.value / 100;\n }\n else {\n hsl.l += amount.value / 100;\n }\n hsl.l = clamp(hsl.l);\n return hsla(color, hsl);\n },\n darken: function (color, amount, method) {\n const hsl = toHSL(color);\n\n if (typeof method !== 'undefined' && method.value === 'relative') {\n hsl.l -= hsl.l * amount.value / 100;\n }\n else {\n hsl.l -= amount.value / 100;\n }\n hsl.l = clamp(hsl.l);\n return hsla(color, hsl);\n },\n fadein: function (color, amount, method) {\n const hsl = toHSL(color);\n\n if (typeof method !== 'undefined' && method.value === 'relative') {\n hsl.a += hsl.a * amount.value / 100;\n }\n else {\n hsl.a += amount.value / 100;\n }\n hsl.a = clamp(hsl.a);\n return hsla(color, hsl);\n },\n fadeout: function (color, amount, method) {\n const hsl = toHSL(color);\n\n if (typeof method !== 'undefined' && method.value === 'relative') {\n hsl.a -= hsl.a * amount.value / 100;\n }\n else {\n hsl.a -= amount.value / 100;\n }\n hsl.a = clamp(hsl.a);\n return hsla(color, hsl);\n },\n fade: function (color, amount) {\n const hsl = toHSL(color);\n\n hsl.a = amount.value / 100;\n hsl.a = clamp(hsl.a);\n return hsla(color, hsl);\n },\n spin: function (color, amount) {\n const hsl = toHSL(color);\n const hue = (hsl.h + amount.value) % 360;\n\n hsl.h = hue < 0 ? 360 + hue : hue;\n\n return hsla(color, hsl);\n },\n //\n // Copyright (c) 2006-2009 Hampton Catlin, Natalie Weizenbaum, and Chris Eppstein\n // http://sass-lang.com\n //\n mix: function (color1, color2, weight) {\n if (!weight) {\n weight = new Dimension(50);\n }\n const p = weight.value / 100.0;\n const w = p * 2 - 1;\n const a = toHSL(color1).a - toHSL(color2).a;\n\n const w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;\n const w2 = 1 - w1;\n\n const rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,\n color1.rgb[1] * w1 + color2.rgb[1] * w2,\n color1.rgb[2] * w1 + color2.rgb[2] * w2];\n\n const alpha = color1.alpha * p + color2.alpha * (1 - p);\n\n return new Color(rgb, alpha);\n },\n greyscale: function (color) {\n return colorFunctions.desaturate(color, new Dimension(100));\n },\n contrast: function (color, dark, light, threshold) {\n // filter: contrast(3.2);\n // should be kept as is, so check for color\n if (!color.rgb) {\n return null;\n }\n if (typeof light === 'undefined') {\n light = colorFunctions.rgba(255, 255, 255, 1.0);\n }\n if (typeof dark === 'undefined') {\n dark = colorFunctions.rgba(0, 0, 0, 1.0);\n }\n // Figure out which is actually light and dark:\n if (dark.luma() > light.luma()) {\n const t = light;\n light = dark;\n dark = t;\n }\n if (typeof threshold === 'undefined') {\n threshold = 0.43;\n } else {\n threshold = number(threshold);\n }\n if (color.luma() < threshold) {\n return light;\n } else {\n return dark;\n }\n },\n // Changes made in 2.7.0 - Reverted in 3.0.0\n // contrast: function (color, color1, color2, threshold) {\n // // Return which of `color1` and `color2` has the greatest contrast with `color`\n // // according to the standard WCAG contrast ratio calculation.\n // // http://www.w3.org/TR/WCAG20/#contrast-ratiodef\n // // The threshold param is no longer used, in line with SASS.\n // // filter: contrast(3.2);\n // // should be kept as is, so check for color\n // if (!color.rgb) {\n // return null;\n // }\n // if (typeof color1 === 'undefined') {\n // color1 = colorFunctions.rgba(0, 0, 0, 1.0);\n // }\n // if (typeof color2 === 'undefined') {\n // color2 = colorFunctions.rgba(255, 255, 255, 1.0);\n // }\n // var contrast1, contrast2;\n // var luma = color.luma();\n // var luma1 = color1.luma();\n // var luma2 = color2.luma();\n // // Calculate contrast ratios for each color\n // if (luma > luma1) {\n // contrast1 = (luma + 0.05) / (luma1 + 0.05);\n // } else {\n // contrast1 = (luma1 + 0.05) / (luma + 0.05);\n // }\n // if (luma > luma2) {\n // contrast2 = (luma + 0.05) / (luma2 + 0.05);\n // } else {\n // contrast2 = (luma2 + 0.05) / (luma + 0.05);\n // }\n // if (contrast1 > contrast2) {\n // return color1;\n // } else {\n // return color2;\n // }\n // },\n argb: function (color) {\n return new Anonymous(color.toARGB());\n },\n color: function(c) {\n if ((c instanceof Quoted) &&\n (/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})$/i.test(c.value))) {\n const val = c.value.slice(1);\n return new Color(val, undefined, `#${val}`);\n }\n if ((c instanceof Color) || (c = Color.fromKeyword(c.value))) {\n c.value = undefined;\n return c;\n }\n throw {\n type: 'Argument',\n message: 'argument must be a color keyword or 3|4|6|8 digit hex e.g. #FFF'\n };\n },\n tint: function(color, amount) {\n return colorFunctions.mix(colorFunctions.rgb(255, 255, 255), color, amount);\n },\n shade: function(color, amount) {\n return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount);\n }\n};\n\nexport default colorFunctions;\n","import Anonymous from '../tree/anonymous';\nimport Keyword from '../tree/keyword';\n\nfunction boolean(condition) {\n return condition ? Keyword.True : Keyword.False;\n}\n\nfunction If(condition, trueValue, falseValue) {\n return condition ? trueValue\n : (falseValue || new Anonymous);\n}\n\nexport default { boolean, 'if': If };\n","import Color from '../tree/color';\n\n// Color Blending\n// ref: http://www.w3.org/TR/compositing-1\n\nfunction colorBlend(mode, color1, color2) {\n const ab = color1.alpha; // result\n\n let // backdrop\n cb;\n\n const as = color2.alpha;\n\n let // source\n cs;\n\n let ar;\n let cr;\n const r = [];\n\n ar = as + ab * (1 - as);\n for (let i = 0; i < 3; i++) {\n cb = color1.rgb[i] / 255;\n cs = color2.rgb[i] / 255;\n cr = mode(cb, cs);\n if (ar) {\n cr = (as * cs + ab * (cb -\n as * (cb + cs - cr))) / ar;\n }\n r[i] = cr * 255;\n }\n\n return new Color(r, ar);\n}\n\nconst colorBlendModeFunctions = {\n multiply: function(cb, cs) {\n return cb * cs;\n },\n screen: function(cb, cs) {\n return cb + cs - cb * cs;\n },\n overlay: function(cb, cs) {\n cb *= 2;\n return (cb <= 1) ?\n colorBlendModeFunctions.multiply(cb, cs) :\n colorBlendModeFunctions.screen(cb - 1, cs);\n },\n softlight: function(cb, cs) {\n let d = 1;\n let e = cb;\n if (cs > 0.5) {\n e = 1;\n d = (cb > 0.25) ? Math.sqrt(cb)\n : ((16 * cb - 12) * cb + 4) * cb;\n }\n return cb - (1 - 2 * cs) * e * (d - cb);\n },\n hardlight: function(cb, cs) {\n return colorBlendModeFunctions.overlay(cs, cb);\n },\n difference: function(cb, cs) {\n return Math.abs(cb - cs);\n },\n exclusion: function(cb, cs) {\n return cb + cs - 2 * cb * cs;\n },\n\n // non-w3c functions:\n average: function(cb, cs) {\n return (cb + cs) / 2;\n },\n negation: function(cb, cs) {\n return 1 - Math.abs(cb + cs - 1);\n }\n};\n\nfor (const f in colorBlendModeFunctions) {\n if (colorBlendModeFunctions.hasOwnProperty(f)) {\n colorBlend[f] = colorBlend.bind(null, colorBlendModeFunctions[f]);\n }\n}\n\nexport default colorBlend;\n","import Comment from '../tree/comment';\nimport Dimension from '../tree/dimension';\nimport Declaration from '../tree/declaration';\nimport Expression from '../tree/expression';\nimport Ruleset from '../tree/ruleset';\nimport Selector from '../tree/selector';\nimport Element from '../tree/element';\nimport Quote from '../tree/quoted';\n\nconst getItemsFromNode = node => {\n // handle non-array values as an array of length 1\n // return 'undefined' if index is invalid\n const items = Array.isArray(node.value) ?\n node.value : Array(node);\n\n return items;\n};\n\nexport default {\n _SELF: function(n) {\n return n;\n },\n extract: function(values, index) {\n index = index.value - 1; // (1-based index)\n\n return getItemsFromNode(values)[index];\n },\n length: function(values) {\n return new Dimension(getItemsFromNode(values).length);\n },\n /**\n * Creates a Less list of incremental values.\n * Modeled after Lodash's range function, also exists natively in PHP\n * \n * @param {Dimension} [start=1]\n * @param {Dimension} end - e.g. 10 or 10px - unit is added to output\n * @param {Dimension} [step=1] \n */\n range: function(start, end, step) {\n let from;\n let to;\n let stepValue = 1;\n const list = [];\n if (end) {\n to = end;\n from = start.value;\n if (step) {\n stepValue = step.value;\n }\n }\n else {\n from = 1;\n to = start;\n }\n\n for (let i = from; i <= to.value; i += stepValue) {\n list.push(new Dimension(i, to.unit));\n }\n\n return new Expression(list);\n },\n each: function(list, rs) {\n const rules = [];\n let newRules;\n let iterator;\n\n if (list.value && !(list instanceof Quote)) {\n if (Array.isArray(list.value)) {\n iterator = list.value;\n } else {\n iterator = [list.value];\n }\n } else if (list.ruleset) {\n iterator = list.ruleset.rules;\n } else if (list.rules) {\n iterator = list.rules;\n } else if (Array.isArray(list)) {\n iterator = list;\n } else {\n iterator = [list];\n }\n\n let valueName = '@value';\n let keyName = '@key';\n let indexName = '@index';\n\n if (rs.params) {\n valueName = rs.params[0] && rs.params[0].name;\n keyName = rs.params[1] && rs.params[1].name;\n indexName = rs.params[2] && rs.params[2].name;\n rs = rs.rules;\n } else {\n rs = rs.ruleset;\n }\n\n for (let i = 0; i < iterator.length; i++) {\n let key;\n let value;\n const item = iterator[i];\n if (item instanceof Declaration) {\n key = typeof item.name === 'string' ? item.name : item.name[0].value;\n value = item.value;\n } else {\n key = new Dimension(i + 1);\n value = item;\n }\n\n if (item instanceof Comment) {\n continue;\n }\n\n newRules = rs.rules.slice(0);\n if (valueName) {\n newRules.push(new Declaration(valueName,\n value,\n false, false, this.index, this.currentFileInfo));\n }\n if (indexName) {\n newRules.push(new Declaration(indexName,\n new Dimension(i + 1),\n false, false, this.index, this.currentFileInfo));\n }\n if (keyName) {\n newRules.push(new Declaration(keyName,\n key,\n false, false, this.index, this.currentFileInfo));\n }\n\n rules.push(new Ruleset([ new(Selector)([ new Element(\"\", '&') ]) ],\n newRules,\n rs.strictImports,\n rs.visibilityInfo()\n ));\n }\n\n return new Ruleset([ new(Selector)([ new Element(\"\", '&') ]) ],\n rules,\n rs.strictImports,\n rs.visibilityInfo()\n ).eval(this.context);\n }\n};\n","import Dimension from '../tree/dimension';\n\nconst MathHelper = (fn, unit, n) => {\n if (!(n instanceof Dimension)) {\n throw { type: 'Argument', message: 'argument must be a number' };\n }\n if (unit == null) {\n unit = n.unit;\n } else {\n n = n.unify();\n }\n return new Dimension(fn(parseFloat(n.value)), unit);\n};\n\nexport default MathHelper;","import mathHelper from './math-helper.js';\n\nconst mathFunctions = {\n // name, unit\n ceil: null,\n floor: null,\n sqrt: null,\n abs: null,\n tan: '',\n sin: '',\n cos: '',\n atan: 'rad',\n asin: 'rad',\n acos: 'rad'\n};\n\nfor (const f in mathFunctions) {\n if (mathFunctions.hasOwnProperty(f)) {\n mathFunctions[f] = mathHelper.bind(null, Math[f], mathFunctions[f]);\n }\n}\n\nmathFunctions.round = (n, f) => {\n const fraction = typeof f === 'undefined' ? 0 : f.value;\n return mathHelper(num => num.toFixed(fraction), null, n);\n};\n\nexport default mathFunctions;\n","import Dimension from '../tree/dimension';\nimport Anonymous from '../tree/anonymous';\nimport mathHelper from './math-helper.js';\n\nconst minMax = function (isMin, args) {\n args = Array.prototype.slice.call(args);\n switch (args.length) {\n case 0: throw { type: 'Argument', message: 'one or more arguments required' };\n }\n let i; // key is the unit.toString() for unified Dimension values,\n let j;\n let current;\n let currentUnified;\n let referenceUnified;\n let unit;\n let unitStatic;\n let unitClone;\n\n const // elems only contains original argument values.\n order = [];\n\n const values = {};\n // value is the index into the order array.\n for (i = 0; i < args.length; i++) {\n current = args[i];\n if (!(current instanceof Dimension)) {\n if (Array.isArray(args[i].value)) {\n Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value));\n }\n continue;\n }\n currentUnified = current.unit.toString() === '' && unitClone !== undefined ? new Dimension(current.value, unitClone).unify() : current.unify();\n unit = currentUnified.unit.toString() === '' && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString();\n unitStatic = unit !== '' && unitStatic === undefined || unit !== '' && order[0].unify().unit.toString() === '' ? unit : unitStatic;\n unitClone = unit !== '' && unitClone === undefined ? current.unit.toString() : unitClone;\n j = values[''] !== undefined && unit !== '' && unit === unitStatic ? values[''] : values[unit];\n if (j === undefined) {\n if (unitStatic !== undefined && unit !== unitStatic) {\n throw { type: 'Argument', message: 'incompatible types' };\n }\n values[unit] = order.length;\n order.push(current);\n continue;\n }\n referenceUnified = order[j].unit.toString() === '' && unitClone !== undefined ? new Dimension(order[j].value, unitClone).unify() : order[j].unify();\n if ( isMin && currentUnified.value < referenceUnified.value ||\n !isMin && currentUnified.value > referenceUnified.value) {\n order[j] = current;\n }\n }\n if (order.length == 1) {\n return order[0];\n }\n args = order.map(function (a) { return a.toCSS(this.context); }).join(this.context.compress ? ',' : ', ');\n return new Anonymous(`${isMin ? 'min' : 'max'}(${args})`);\n};\n\nexport default {\n min: function(...args) {\n return minMax(true, args);\n },\n max: function(...args) {\n return minMax(false, args);\n },\n convert: function (val, unit) {\n return val.convertTo(unit.value);\n },\n pi: function () {\n return new Dimension(Math.PI);\n },\n mod: function(a, b) {\n return new Dimension(a.value % b.value, a.unit);\n },\n pow: function(x, y) {\n if (typeof x === 'number' && typeof y === 'number') {\n x = new Dimension(x);\n y = new Dimension(y);\n } else if (!(x instanceof Dimension) || !(y instanceof Dimension)) {\n throw { type: 'Argument', message: 'arguments must be numbers' };\n }\n\n return new Dimension(Math.pow(x.value, y.value), x.unit);\n },\n percentage: function (n) {\n const result = mathHelper(num => num * 100, '%', n);\n\n return result;\n }\n};\n","/**\n * Plugin Manager\n */\nclass PluginManager {\n constructor(less) {\n this.less = less;\n this.visitors = [];\n this.preProcessors = [];\n this.postProcessors = [];\n this.installedPlugins = [];\n this.fileManagers = [];\n this.iterator = -1;\n this.pluginCache = {};\n this.Loader = new less.PluginLoader(less);\n }\n\n /**\n * Adds all the plugins in the array\n * @param {Array} plugins\n */\n addPlugins(plugins) {\n if (plugins) {\n for (let i = 0; i < plugins.length; i++) {\n this.addPlugin(plugins[i]);\n }\n }\n }\n\n /**\n *\n * @param plugin\n * @param {String} filename\n */\n addPlugin(plugin, filename, functionRegistry) {\n this.installedPlugins.push(plugin);\n if (filename) {\n this.pluginCache[filename] = plugin;\n }\n if (plugin.install) {\n plugin.install(this.less, this, functionRegistry || this.less.functions.functionRegistry);\n }\n }\n\n /**\n *\n * @param filename\n */\n get(filename) {\n return this.pluginCache[filename];\n }\n\n /**\n * Adds a visitor. The visitor object has options on itself to determine\n * when it should run.\n * @param visitor\n */\n addVisitor(visitor) {\n this.visitors.push(visitor);\n }\n\n /**\n * Adds a pre processor object\n * @param {object} preProcessor\n * @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import\n */\n addPreProcessor(preProcessor, priority) {\n let indexToInsertAt;\n for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) {\n if (this.preProcessors[indexToInsertAt].priority >= priority) {\n break;\n }\n }\n this.preProcessors.splice(indexToInsertAt, 0, {preProcessor, priority});\n }\n\n /**\n * Adds a post processor object\n * @param {object} postProcessor\n * @param {number} priority - guidelines 1 = before compression, 1000 = compression, 2000 = after compression\n */\n addPostProcessor(postProcessor, priority) {\n let indexToInsertAt;\n for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) {\n if (this.postProcessors[indexToInsertAt].priority >= priority) {\n break;\n }\n }\n this.postProcessors.splice(indexToInsertAt, 0, {postProcessor, priority});\n }\n\n /**\n *\n * @param manager\n */\n addFileManager(manager) {\n this.fileManagers.push(manager);\n }\n\n /**\n *\n * @returns {Array}\n * @private\n */\n getPreProcessors() {\n const preProcessors = [];\n for (let i = 0; i < this.preProcessors.length; i++) {\n preProcessors.push(this.preProcessors[i].preProcessor);\n }\n return preProcessors;\n }\n\n /**\n *\n * @returns {Array}\n * @private\n */\n getPostProcessors() {\n const postProcessors = [];\n for (let i = 0; i < this.postProcessors.length; i++) {\n postProcessors.push(this.postProcessors[i].postProcessor);\n }\n return postProcessors;\n }\n\n /**\n *\n * @returns {Array}\n * @private\n */\n getVisitors() {\n return this.visitors;\n }\n\n visitor() {\n const self = this;\n return {\n first: function() {\n self.iterator = -1;\n return self.visitors[self.iterator];\n },\n get: function() {\n self.iterator += 1;\n return self.visitors[self.iterator];\n }\n };\n }\n\n /**\n *\n * @returns {Array}\n * @private\n */\n getFileManagers() {\n return this.fileManagers;\n }\n}\n\nlet pm;\n\nfunction PluginManagerFactory(less, newFactory) {\n if (newFactory || !pm) {\n pm = new PluginManager(less);\n }\n return pm;\n};\n\n//\nexport default PluginManagerFactory;\n","import Quoted from '../tree/quoted';\nimport Anonymous from '../tree/anonymous';\nimport Quote from '../tree/quoted';\nimport JavaScript from '../tree/javascript';\n\nexport default {\n e: function (str) {\n return new Quote('\"', str instanceof JavaScript ? str.evaluated : str.value, true);\n },\n escape: function (str) {\n return new Anonymous(\n encodeURI(str.value).replace(/=/g, '%3D').replace(/:/g, '%3A').replace(/#/g, '%23').replace(/;/g, '%3B')\n .replace(/\\(/g, '%28').replace(/\\)/g, '%29'));\n },\n replace: function (string, pattern, replacement, flags) {\n let result = string.value;\n replacement = (replacement.type === 'Quoted') ?\n replacement.value : replacement.toCSS();\n result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement);\n return new Quoted(string.quote || '', result, string.escaped);\n },\n '%': function (string /* arg, arg, ... */) {\n const args = Array.prototype.slice.call(arguments, 1);\n let result = string.value;\n\n for (let i = 0; i < args.length; i++) {\n /* jshint loopfunc:true */\n result = result.replace(/%[sda]/i, token => {\n const value = ((args[i].type === 'Quoted') &&\n token.match(/s/i)) ? args[i].value : args[i].toCSS();\n return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;\n });\n }\n result = result.replace(/%%/g, '%');\n return new Quoted(string.quote || '', result, string.escaped);\n }\n};\n","import Keyword from '../tree/keyword';\nimport DetachedRuleset from '../tree/detached-ruleset';\nimport Dimension from '../tree/dimension';\nimport Color from '../tree/color';\nimport Quoted from '../tree/quoted';\nimport Anonymous from '../tree/anonymous';\nimport URL from '../tree/url';\nimport Operation from '../tree/operation';\n\nconst isa = (n, Type) => (n instanceof Type) ? Keyword.True : Keyword.False;\nconst isunit = (n, unit) => {\n if (unit === undefined) {\n throw { type: 'Argument', message: 'missing the required second argument to isunit.' };\n }\n unit = typeof unit.value === 'string' ? unit.value : unit;\n if (typeof unit !== 'string') {\n throw { type: 'Argument', message: 'Second argument to isunit should be a unit or a string.' };\n }\n return (n instanceof Dimension) && n.unit.is(unit) ? Keyword.True : Keyword.False;\n};\n\nexport default {\n isruleset: function (n) {\n return isa(n, DetachedRuleset);\n },\n iscolor: function (n) {\n return isa(n, Color);\n },\n isnumber: function (n) {\n return isa(n, Dimension);\n },\n isstring: function (n) {\n return isa(n, Quoted);\n },\n iskeyword: function (n) {\n return isa(n, Keyword);\n },\n isurl: function (n) {\n return isa(n, URL);\n },\n ispixel: function (n) {\n return isunit(n, 'px');\n },\n ispercentage: function (n) {\n return isunit(n, '%');\n },\n isem: function (n) {\n return isunit(n, 'em');\n },\n isunit,\n unit: function (val, unit) {\n if (!(val instanceof Dimension)) {\n throw { type: 'Argument',\n message: `the first argument to unit must be a number${val instanceof Operation ? '. Have you forgotten parenthesis?' : ''}` };\n }\n if (unit) {\n if (unit instanceof Keyword) {\n unit = unit.value;\n } else {\n unit = unit.toCSS();\n }\n } else {\n unit = '';\n }\n return new Dimension(val.value, unit);\n },\n 'get-unit': function (n) {\n return new Anonymous(n.unit);\n }\n};\n","import functionRegistry from './function-registry';\nimport functionCaller from './function-caller';\n\nimport boolean from './boolean';\nimport defaultFunc from './default';\nimport color from './color';\nimport colorBlending from './color-blending';\nimport dataUri from './data-uri';\nimport list from './list';\nimport math from './math';\nimport number from './number';\nimport string from './string';\nimport svg from './svg';\nimport types from './types';\n\nexport default environment => {\n const functions = { functionRegistry, functionCaller };\n\n // register functions\n functionRegistry.addMultiple(boolean);\n functionRegistry.add('default', defaultFunc.eval.bind(defaultFunc));\n functionRegistry.addMultiple(color);\n functionRegistry.addMultiple(colorBlending);\n functionRegistry.addMultiple(dataUri(environment));\n functionRegistry.addMultiple(list);\n functionRegistry.addMultiple(math);\n functionRegistry.addMultiple(number);\n functionRegistry.addMultiple(string);\n functionRegistry.addMultiple(svg(environment));\n functionRegistry.addMultiple(types);\n\n return functions;\n};\n","import Quoted from '../tree/quoted';\nimport URL from '../tree/url';\nimport * as utils from '../utils';\nimport logger from '../logger';\n\nexport default environment => {\n \n const fallback = (functionThis, node) => new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context); \n\n return { 'data-uri': function(mimetypeNode, filePathNode) {\n\n if (!filePathNode) {\n filePathNode = mimetypeNode;\n mimetypeNode = null;\n }\n\n let mimetype = mimetypeNode && mimetypeNode.value;\n let filePath = filePathNode.value;\n const currentFileInfo = this.currentFileInfo;\n const currentDirectory = currentFileInfo.rewriteUrls ?\n currentFileInfo.currentDirectory : currentFileInfo.entryPath;\n\n const fragmentStart = filePath.indexOf('#');\n let fragment = '';\n if (fragmentStart !== -1) {\n fragment = filePath.slice(fragmentStart);\n filePath = filePath.slice(0, fragmentStart);\n }\n const context = utils.clone(this.context);\n context.rawBuffer = true;\n\n const fileManager = environment.getFileManager(filePath, currentDirectory, context, environment, true);\n\n if (!fileManager) {\n return fallback(this, filePathNode);\n }\n\n let useBase64 = false;\n\n // detect the mimetype if not given\n if (!mimetypeNode) {\n\n mimetype = environment.mimeLookup(filePath);\n\n if (mimetype === 'image/svg+xml') {\n useBase64 = false;\n } else {\n // use base 64 unless it's an ASCII or UTF-8 format\n const charset = environment.charsetLookup(mimetype);\n useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;\n }\n if (useBase64) { mimetype += ';base64'; }\n }\n else {\n useBase64 = /;base64$/.test(mimetype);\n }\n\n const fileSync = fileManager.loadFileSync(filePath, currentDirectory, context, environment);\n if (!fileSync.contents) {\n logger.warn(`Skipped data-uri embedding of ${filePath} because file not found`);\n return fallback(this, filePathNode || mimetypeNode);\n }\n let buf = fileSync.contents;\n if (useBase64 && !environment.encodeBase64) {\n return fallback(this, filePathNode);\n }\n\n buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf);\n\n const uri = `data:${mimetype},${buf}${fragment}`;\n\n return new URL(new Quoted(`\"${uri}\"`, uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo);\n }};\n};\n","import Dimension from '../tree/dimension';\nimport Color from '../tree/color';\nimport Expression from '../tree/expression';\nimport Quoted from '../tree/quoted';\nimport URL from '../tree/url';\n\nexport default environment => {\n return { 'svg-gradient': function(direction) {\n let stops;\n let gradientDirectionSvg;\n let gradientType = 'linear';\n let rectangleDimension = 'x=\"0\" y=\"0\" width=\"1\" height=\"1\"';\n const renderEnv = {compress: false};\n let returner;\n const directionValue = direction.toCSS(renderEnv);\n let i;\n let color;\n let position;\n let positionValue;\n let alpha;\n\n function throwArgumentDescriptor() {\n throw { type: 'Argument',\n message: 'svg-gradient expects direction, start_color [start_position], [color position,]...,' +\n ' end_color [end_position] or direction, color list' };\n }\n\n if (arguments.length == 2) {\n if (arguments[1].value.length < 2) {\n throwArgumentDescriptor();\n }\n stops = arguments[1].value;\n } else if (arguments.length < 3) {\n throwArgumentDescriptor();\n } else {\n stops = Array.prototype.slice.call(arguments, 1);\n }\n\n switch (directionValue) {\n case 'to bottom':\n gradientDirectionSvg = 'x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\"';\n break;\n case 'to right':\n gradientDirectionSvg = 'x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\"';\n break;\n case 'to bottom right':\n gradientDirectionSvg = 'x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\"';\n break;\n case 'to top right':\n gradientDirectionSvg = 'x1=\"0%\" y1=\"100%\" x2=\"100%\" y2=\"0%\"';\n break;\n case 'ellipse':\n case 'ellipse at center':\n gradientType = 'radial';\n gradientDirectionSvg = 'cx=\"50%\" cy=\"50%\" r=\"75%\"';\n rectangleDimension = 'x=\"-50\" y=\"-50\" width=\"101\" height=\"101\"';\n break;\n default:\n throw { type: 'Argument', message: 'svg-gradient direction must be \\'to bottom\\', \\'to right\\',' +\n ' \\'to bottom right\\', \\'to top right\\' or \\'ellipse at center\\'' };\n }\n returner = `<${gradientType}Gradient id=\"g\" ${gradientDirectionSvg}>`;\n\n for (i = 0; i < stops.length; i += 1) {\n if (stops[i] instanceof Expression) {\n color = stops[i].value[0];\n position = stops[i].value[1];\n } else {\n color = stops[i];\n position = undefined;\n }\n\n if (!(color instanceof Color) || (!((i === 0 || i + 1 === stops.length) && position === undefined) && !(position instanceof Dimension))) {\n throwArgumentDescriptor();\n }\n positionValue = position ? position.toCSS(renderEnv) : i === 0 ? '0%' : '100%';\n alpha = color.alpha;\n returner += ``;\n }\n returner += ``;\n\n returner = encodeURIComponent(returner);\n\n returner = `data:image/svg+xml,${returner}`;\n return new URL(new Quoted(`'${returner}'`, returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo);\n }};\n};\n","import contexts from './contexts';\nimport visitor from './visitors';\nimport tree from './tree';\n\nexport default (root, options = {}) => {\n let evaldRoot;\n let variables = options.variables;\n const evalEnv = new contexts.Eval(options);\n\n //\n // Allows setting variables with a hash, so:\n //\n // `{ color: new tree.Color('#f01') }` will become:\n //\n // new tree.Declaration('@color',\n // new tree.Value([\n // new tree.Expression([\n // new tree.Color('#f01')\n // ])\n // ])\n // )\n //\n if (typeof variables === 'object' && !Array.isArray(variables)) {\n variables = Object.keys(variables).map(k => {\n let value = variables[k];\n\n if (!(value instanceof tree.Value)) {\n if (!(value instanceof tree.Expression)) {\n value = new tree.Expression([value]);\n }\n value = new tree.Value([value]);\n }\n return new tree.Declaration(`@${k}`, value, false, null, 0);\n });\n evalEnv.frames = [new tree.Ruleset(null, variables)];\n }\n\n const visitors = [\n new visitor.JoinSelectorVisitor(),\n new visitor.MarkVisibleSelectorsVisitor(true),\n new visitor.ExtendVisitor(),\n new visitor.ToCSSVisitor({compress: Boolean(options.compress)})\n ];\n\n const preEvalVisitors = [];\n let v;\n let visitorIterator;\n\n /**\n * first() / get() allows visitors to be added while visiting\n * \n * @todo Add scoping for visitors just like functions for @plugin; right now they're global\n */\n if (options.pluginManager) {\n visitorIterator = options.pluginManager.visitor();\n for (var i = 0; i < 2; i++) {\n visitorIterator.first();\n while ((v = visitorIterator.get())) {\n if (v.isPreEvalVisitor) {\n if (i === 0 || preEvalVisitors.indexOf(v) === -1) {\n preEvalVisitors.push(v);\n v.run(root);\n }\n }\n else {\n if (i === 0 || visitors.indexOf(v) === -1) {\n if (v.isPreVisitor) {\n visitors.unshift(v);\n }\n else {\n visitors.push(v);\n }\n }\n }\n }\n }\n }\n\n evaldRoot = root.eval(evalEnv);\n\n for (var i = 0; i < visitors.length; i++) {\n visitors[i].run(evaldRoot);\n }\n\n // Run any remaining visitors added after eval pass\n if (options.pluginManager) {\n visitorIterator.first();\n while ((v = visitorIterator.get())) {\n if (visitors.indexOf(v) === -1 && preEvalVisitors.indexOf(v) === -1) {\n v.run(evaldRoot);\n }\n }\n }\n\n return evaldRoot;\n};\n","/* global window, XMLHttpRequest */\n\nimport AbstractFileManager from '../less/environment/abstract-file-manager.js';\n\nlet options;\nlet logger;\nlet fileCache = {};\n\n// TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load\nclass FileManager extends AbstractFileManager {\n alwaysMakePathsAbsolute() {\n return true;\n }\n\n join(basePath, laterPath) {\n if (!basePath) {\n return laterPath;\n }\n return this.extractUrlParts(laterPath, basePath).path;\n }\n\n doXHR(url, type, callback, errback) {\n const xhr = new XMLHttpRequest();\n const async = options.isFileProtocol ? options.fileAsync : true;\n\n if (typeof xhr.overrideMimeType === 'function') {\n xhr.overrideMimeType('text/css');\n }\n logger.debug(`XHR: Getting '${url}'`);\n xhr.open('GET', url, async);\n xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');\n xhr.send(null);\n\n function handleResponse(xhr, callback, errback) {\n if (xhr.status >= 200 && xhr.status < 300) {\n callback(xhr.responseText,\n xhr.getResponseHeader('Last-Modified'));\n } else if (typeof errback === 'function') {\n errback(xhr.status, url);\n }\n }\n\n if (options.isFileProtocol && !options.fileAsync) {\n if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {\n callback(xhr.responseText);\n } else {\n errback(xhr.status, url);\n }\n } else if (async) {\n xhr.onreadystatechange = () => {\n if (xhr.readyState == 4) {\n handleResponse(xhr, callback, errback);\n }\n };\n } else {\n handleResponse(xhr, callback, errback);\n }\n }\n\n supports() {\n return true;\n }\n\n clearFileCache() {\n fileCache = {};\n }\n\n loadFile(filename, currentDirectory, options, environment) {\n // TODO: Add prefix support like less-node?\n // What about multiple paths?\n\n if (currentDirectory && !this.isPathAbsolute(filename)) {\n filename = currentDirectory + filename;\n }\n\n filename = options.ext ? this.tryAppendExtension(filename, options.ext) : filename;\n\n options = options || {};\n\n // sheet may be set to the stylesheet for the initial load or a collection of properties including\n // some context variables for imports\n const hrefParts = this.extractUrlParts(filename, window.location.href);\n const href = hrefParts.url;\n const self = this;\n \n return new Promise((resolve, reject) => {\n if (options.useFileCache && fileCache[href]) {\n try {\n const lessText = fileCache[href];\n return resolve({ contents: lessText, filename: href, webInfo: { lastModified: new Date() }});\n } catch (e) {\n return reject({ filename: href, message: `Error loading file ${href} error was ${e.message}` });\n }\n }\n\n self.doXHR(href, options.mime, function doXHRCallback(data, lastModified) {\n // per file cache\n fileCache[href] = data;\n\n // Use remote copy (re-parse)\n resolve({ contents: data, filename: href, webInfo: { lastModified }});\n }, function doXHRError(status, url) {\n reject({ type: 'File', message: `'${url}' wasn't found (${status})`, href });\n });\n });\n }\n}\n\nexport default (opts, log) => {\n options = opts;\n logger = log;\n return FileManager;\n}\n","import data from './data';\nimport tree from './tree';\nimport Environment from './environment/environment';\nimport AbstractFileManager from './environment/abstract-file-manager';\nimport AbstractPluginLoader from './environment/abstract-plugin-loader';\nimport visitors from './visitors';\nimport Parser from './parser/parser';\nimport Functions from './functions';\nimport contexts from './contexts';\nimport sourceMapOutput from './source-map-output';\nimport sourceMapBuilder from './source-map-builder';\nimport parseTree from './parse-tree';\nimport importManager from './import-manager';\nimport Render from './render';\nimport Parse from './parse';\nimport LessError from './less-error';\nimport transformTree from './transform-tree';\nimport * as utils from './utils';\nimport PluginManager from './plugin-manager';\nimport logger from './logger';\n\nexport default (environment, fileManagers) => {\n /**\n * @todo\n * This original code could be improved quite a bit.\n * Many classes / modules currently add side-effects / mutations to passed in objects,\n * which makes it hard to refactor and reason about. \n */\n environment = new Environment(environment, fileManagers);\n\n const SourceMapOutput = sourceMapOutput(environment);\n const SourceMapBuilder = sourceMapBuilder(SourceMapOutput, environment);\n const ParseTree = parseTree(SourceMapBuilder);\n const ImportManager = importManager(environment);\n const render = Render(environment, ParseTree, ImportManager);\n const parse = Parse(environment, ParseTree, ImportManager);\n const functions = Functions(environment);\n\n /**\n * @todo\n * This root properties / methods need to be organized.\n * It's not clear what should / must be public and why.\n */\n const initial = {\n version: [3, 10, 0],\n data,\n tree,\n Environment,\n AbstractFileManager,\n AbstractPluginLoader,\n environment,\n visitors,\n Parser,\n functions,\n contexts,\n SourceMapOutput,\n SourceMapBuilder,\n ParseTree,\n ImportManager,\n render,\n parse,\n LessError,\n transformTree,\n utils,\n PluginManager,\n logger\n };\n\n // Create a public API\n const ctor = t => function (...args) {\n return new t(...args);\n };\n\n let t;\n const api = Object.create(initial);\n for (const n in initial.tree) {\n /* eslint guard-for-in: 0 */\n t = initial.tree[n];\n if (typeof t === 'function') {\n api[n.toLowerCase()] = ctor(t);\n }\n else {\n api[n] = Object.create(null);\n for (const o in t) {\n /* eslint guard-for-in: 0 */\n api[n][o.toLowerCase()] = ctor(t[o]);\n }\n }\n }\n\n return api;\n};\n","export default environment => {\n class SourceMapOutput {\n constructor(options) {\n this._css = [];\n this._rootNode = options.rootNode;\n this._contentsMap = options.contentsMap;\n this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap;\n if (options.sourceMapFilename) {\n this._sourceMapFilename = options.sourceMapFilename.replace(/\\\\/g, '/');\n }\n this._outputFilename = options.outputFilename;\n this.sourceMapURL = options.sourceMapURL;\n if (options.sourceMapBasepath) {\n this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\\\/g, '/');\n }\n if (options.sourceMapRootpath) {\n this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\\\/g, '/');\n if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') {\n this._sourceMapRootpath += '/';\n }\n } else {\n this._sourceMapRootpath = '';\n }\n this._outputSourceFiles = options.outputSourceFiles;\n this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator();\n\n this._lineNumber = 0;\n this._column = 0;\n }\n\n removeBasepath(path) {\n if (this._sourceMapBasepath && path.indexOf(this._sourceMapBasepath) === 0) {\n path = path.substring(this._sourceMapBasepath.length);\n if (path.charAt(0) === '\\\\' || path.charAt(0) === '/') {\n path = path.substring(1);\n }\n }\n\n return path;\n }\n\n normalizeFilename(filename) {\n filename = filename.replace(/\\\\/g, '/');\n filename = this.removeBasepath(filename);\n return (this._sourceMapRootpath || '') + filename;\n }\n\n add(chunk, fileInfo, index, mapLines) {\n // ignore adding empty strings\n if (!chunk) {\n return;\n }\n\n let lines;\n let sourceLines;\n let columns;\n let sourceColumns;\n let i;\n\n if (fileInfo && fileInfo.filename) {\n let inputSource = this._contentsMap[fileInfo.filename];\n\n // remove vars/banner added to the top of the file\n if (this._contentsIgnoredCharsMap[fileInfo.filename]) {\n // adjust the index\n index -= this._contentsIgnoredCharsMap[fileInfo.filename];\n if (index < 0) { index = 0; }\n // adjust the source\n inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]);\n }\n\n // ignore empty content\n if (inputSource === undefined) {\n return;\n }\n\n inputSource = inputSource.substring(0, index);\n sourceLines = inputSource.split('\\n');\n sourceColumns = sourceLines[sourceLines.length - 1];\n }\n\n lines = chunk.split('\\n');\n columns = lines[lines.length - 1];\n\n if (fileInfo && fileInfo.filename) {\n if (!mapLines) {\n this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column},\n original: { line: sourceLines.length, column: sourceColumns.length},\n source: this.normalizeFilename(fileInfo.filename)});\n } else {\n for (i = 0; i < lines.length; i++) {\n this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0},\n original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0},\n source: this.normalizeFilename(fileInfo.filename)});\n }\n }\n }\n\n if (lines.length === 1) {\n this._column += columns.length;\n } else {\n this._lineNumber += lines.length - 1;\n this._column = columns.length;\n }\n\n this._css.push(chunk);\n }\n\n isEmpty() {\n return this._css.length === 0;\n }\n\n toCSS(context) {\n this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null });\n\n if (this._outputSourceFiles) {\n for (const filename in this._contentsMap) {\n if (this._contentsMap.hasOwnProperty(filename)) {\n let source = this._contentsMap[filename];\n if (this._contentsIgnoredCharsMap[filename]) {\n source = source.slice(this._contentsIgnoredCharsMap[filename]);\n }\n this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source);\n }\n }\n }\n\n this._rootNode.genCSS(context, this);\n\n if (this._css.length > 0) {\n let sourceMapURL;\n const sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON());\n\n if (this.sourceMapURL) {\n sourceMapURL = this.sourceMapURL;\n } else if (this._sourceMapFilename) {\n sourceMapURL = this._sourceMapFilename;\n }\n this.sourceMapURL = sourceMapURL;\n\n this.sourceMap = sourceMapContent;\n }\n\n return this._css.join('');\n }\n }\n\n return SourceMapOutput;\n};\n","export default (SourceMapOutput, environment) => {\n class SourceMapBuilder {\n constructor(options) {\n this.options = options;\n }\n\n toCSS(rootNode, options, imports) {\n const sourceMapOutput = new SourceMapOutput(\n {\n contentsIgnoredCharsMap: imports.contentsIgnoredChars,\n rootNode,\n contentsMap: imports.contents,\n sourceMapFilename: this.options.sourceMapFilename,\n sourceMapURL: this.options.sourceMapURL,\n outputFilename: this.options.sourceMapOutputFilename,\n sourceMapBasepath: this.options.sourceMapBasepath,\n sourceMapRootpath: this.options.sourceMapRootpath,\n outputSourceFiles: this.options.outputSourceFiles,\n sourceMapGenerator: this.options.sourceMapGenerator,\n sourceMapFileInline: this.options.sourceMapFileInline\n });\n\n const css = sourceMapOutput.toCSS(options);\n this.sourceMap = sourceMapOutput.sourceMap;\n this.sourceMapURL = sourceMapOutput.sourceMapURL;\n if (this.options.sourceMapInputFilename) {\n this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename);\n }\n if (this.options.sourceMapBasepath !== undefined && this.sourceMapURL !== undefined) {\n this.sourceMapURL = sourceMapOutput.removeBasepath(this.sourceMapURL);\n }\n return css + this.getCSSAppendage();\n }\n\n getCSSAppendage() {\n\n let sourceMapURL = this.sourceMapURL;\n if (this.options.sourceMapFileInline) {\n if (this.sourceMap === undefined) {\n return '';\n }\n sourceMapURL = `data:application/json;base64,${environment.encodeBase64(this.sourceMap)}`;\n }\n\n if (sourceMapURL) {\n return `/*# sourceMappingURL=${sourceMapURL} */`;\n }\n return '';\n }\n\n getExternalSourceMap() {\n return this.sourceMap;\n }\n\n setExternalSourceMap(sourceMap) {\n this.sourceMap = sourceMap;\n }\n\n isInline() {\n return this.options.sourceMapFileInline;\n }\n\n getSourceMapURL() {\n return this.sourceMapURL;\n }\n\n getOutputFilename() {\n return this.options.sourceMapOutputFilename;\n }\n\n getInputFilename() {\n return this.sourceMapInputFilename;\n }\n }\n\n return SourceMapBuilder;\n};\n","import LessError from './less-error';\nimport transformTree from './transform-tree';\nimport logger from './logger';\n\nexport default SourceMapBuilder => {\n class ParseTree {\n constructor(root, imports) {\n this.root = root;\n this.imports = imports;\n }\n\n toCSS(options) {\n let evaldRoot;\n const result = {};\n let sourceMapBuilder;\n try {\n evaldRoot = transformTree(this.root, options);\n } catch (e) {\n throw new LessError(e, this.imports);\n }\n\n try {\n const compress = Boolean(options.compress);\n if (compress) {\n logger.warn('The compress option has been deprecated. ' + \n 'We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.');\n }\n\n const toCSSOptions = {\n compress,\n dumpLineNumbers: options.dumpLineNumbers,\n strictUnits: Boolean(options.strictUnits),\n numPrecision: 8};\n\n if (options.sourceMap) {\n sourceMapBuilder = new SourceMapBuilder(options.sourceMap);\n result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports);\n } else {\n result.css = evaldRoot.toCSS(toCSSOptions);\n }\n } catch (e) {\n throw new LessError(e, this.imports);\n }\n\n if (options.pluginManager) {\n const postProcessors = options.pluginManager.getPostProcessors();\n for (let i = 0; i < postProcessors.length; i++) {\n result.css = postProcessors[i].process(result.css, { sourceMap: sourceMapBuilder, options, imports: this.imports });\n }\n }\n if (options.sourceMap) {\n result.map = sourceMapBuilder.getExternalSourceMap();\n }\n\n result.imports = [];\n for (const file in this.imports.files) {\n if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) {\n result.imports.push(file);\n }\n }\n return result;\n }\n }\n\n return ParseTree;\n};\n","import contexts from './contexts';\nimport Parser from './parser/parser';\nimport LessError from './less-error';\nimport * as utils from './utils';\nimport logger from './logger';\n\nexport default environment => {\n // FileInfo = {\n // 'rewriteUrls' - option - whether to adjust URL's to be relative\n // 'filename' - full resolved filename of current file\n // 'rootpath' - path to append to normal URLs for this node\n // 'currentDirectory' - path to the current file, absolute\n // 'rootFilename' - filename of the base file\n // 'entryPath' - absolute path to the entry file\n // 'reference' - whether the file should not be output and only output parts that are referenced\n\n class ImportManager {\n constructor(less, context, rootFileInfo) {\n this.less = less;\n this.rootFilename = rootFileInfo.filename;\n this.paths = context.paths || []; // Search paths, when importing\n this.contents = {}; // map - filename to contents of all the files\n this.contentsIgnoredChars = {}; // map - filename to lines at the beginning of each file to ignore\n this.mime = context.mime;\n this.error = null;\n this.context = context;\n // Deprecated? Unused outside of here, could be useful.\n this.queue = []; // Files which haven't been imported yet\n this.files = {}; // Holds the imported parse trees.\n }\n\n /**\n * Add an import to be imported\n * @param path - the raw path\n * @param tryAppendExtension - whether to try appending a file extension (.less or .js if the path has no extension)\n * @param currentFileInfo - the current file info (used for instance to work out relative paths)\n * @param importOptions - import options\n * @param callback - callback for when it is imported\n */\n push(path, tryAppendExtension, currentFileInfo, importOptions, callback) {\n const importManager = this;\n const pluginLoader = this.context.pluginManager.Loader;\n\n this.queue.push(path);\n\n const fileParsedFunc = (e, root, fullPath) => {\n importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue\n\n const importedEqualsRoot = fullPath === importManager.rootFilename;\n if (importOptions.optional && e) {\n callback(null, {rules:[]}, false, null);\n logger.info(`The file ${fullPath} was skipped because it was not found and the import was marked optional.`);\n }\n else {\n // Inline imports aren't cached here.\n // If we start to cache them, please make sure they won't conflict with non-inline imports of the\n // same name as they used to do before this comment and the condition below have been added.\n if (!importManager.files[fullPath] && !importOptions.inline) {\n importManager.files[fullPath] = { root, options: importOptions };\n }\n if (e && !importManager.error) { importManager.error = e; }\n callback(e, root, importedEqualsRoot, fullPath);\n }\n };\n\n const newFileInfo = {\n rewriteUrls: this.context.rewriteUrls,\n entryPath: currentFileInfo.entryPath,\n rootpath: currentFileInfo.rootpath,\n rootFilename: currentFileInfo.rootFilename\n };\n\n const fileManager = environment.getFileManager(path, currentFileInfo.currentDirectory, this.context, environment);\n\n if (!fileManager) {\n fileParsedFunc({ message: `Could not find a file-manager for ${path}` });\n return;\n }\n\n const loadFileCallback = loadedFile => {\n let plugin;\n const resolvedFilename = loadedFile.filename;\n const contents = loadedFile.contents.replace(/^\\uFEFF/, '');\n\n // Pass on an updated rootpath if path of imported file is relative and file\n // is in a (sub|sup) directory\n //\n // Examples:\n // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/',\n // then rootpath should become 'less/module/nav/'\n // - If path of imported file is '../mixins.less' and rootpath is 'less/',\n // then rootpath should become 'less/../'\n newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename);\n if (newFileInfo.rewriteUrls) {\n newFileInfo.rootpath = fileManager.join(\n (importManager.context.rootpath || ''),\n fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath));\n\n if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) {\n newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath);\n }\n }\n newFileInfo.filename = resolvedFilename;\n\n const newEnv = new contexts.Parse(importManager.context);\n\n newEnv.processImports = false;\n importManager.contents[resolvedFilename] = contents;\n\n if (currentFileInfo.reference || importOptions.reference) {\n newFileInfo.reference = true;\n }\n\n if (importOptions.isPlugin) {\n plugin = pluginLoader.evalPlugin(contents, newEnv, importManager, importOptions.pluginArgs, newFileInfo);\n if (plugin instanceof LessError) {\n fileParsedFunc(plugin, null, resolvedFilename);\n }\n else {\n fileParsedFunc(null, plugin, resolvedFilename);\n }\n } else if (importOptions.inline) {\n fileParsedFunc(null, contents, resolvedFilename);\n } else {\n\n // import (multiple) parse trees apparently get altered and can't be cached.\n // TODO: investigate why this is\n if (importManager.files[resolvedFilename]\n && !importManager.files[resolvedFilename].options.multiple\n && !importOptions.multiple) {\n\n fileParsedFunc(null, importManager.files[resolvedFilename].root, resolvedFilename);\n }\n else {\n new Parser(newEnv, importManager, newFileInfo).parse(contents, (e, root) => {\n fileParsedFunc(e, root, resolvedFilename);\n });\n }\n }\n };\n let promise;\n const context = utils.clone(this.context);\n\n if (tryAppendExtension) {\n context.ext = importOptions.isPlugin ? '.js' : '.less';\n }\n\n if (importOptions.isPlugin) {\n context.mime = 'application/javascript';\n promise = pluginLoader.loadPlugin(path, currentFileInfo.currentDirectory, context, environment, fileManager);\n }\n else {\n promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, context, environment,\n (err, loadedFile) => {\n if (err) {\n fileParsedFunc(err);\n } else {\n loadFileCallback(loadedFile);\n }\n });\n }\n if (promise) {\n promise.then(loadFileCallback, fileParsedFunc);\n }\n }\n }\n\n return ImportManager;\n};\n","let PromiseConstructor;\nimport * as utils from './utils';\n\nexport default (environment, ParseTree, ImportManager) => {\n const render = function (input, options, callback) {\n if (typeof options === 'function') {\n callback = options;\n options = utils.copyOptions(this.options, {});\n }\n else {\n options = utils.copyOptions(this.options, options || {});\n }\n\n if (!callback) {\n const self = this;\n return new Promise((resolve, reject) => {\n render.call(self, input, options, (err, output) => {\n if (err) {\n reject(err);\n } else {\n resolve(output);\n }\n });\n });\n } else {\n this.parse(input, options, (err, root, imports, options) => {\n if (err) { return callback(err); }\n\n let result;\n try {\n const parseTree = new ParseTree(root, imports);\n result = parseTree.toCSS(options);\n }\n catch (err) { return callback(err); }\n\n callback(null, result);\n });\n }\n };\n\n return render;\n};\n","let PromiseConstructor;\nimport contexts from './contexts';\nimport Parser from './parser/parser';\nimport PluginManager from './plugin-manager';\nimport LessError from './less-error';\nimport * as utils from './utils';\n\nexport default (environment, ParseTree, ImportManager) => {\n const parse = function (input, options, callback) {\n\n if (typeof options === 'function') {\n callback = options;\n options = utils.copyOptions(this.options, {});\n }\n else {\n options = utils.copyOptions(this.options, options || {});\n }\n\n if (!callback) {\n const self = this;\n return new Promise((resolve, reject) => {\n parse.call(self, input, options, (err, output) => {\n if (err) {\n reject(err);\n } else {\n resolve(output);\n }\n });\n });\n } else {\n let context;\n let rootFileInfo;\n const pluginManager = new PluginManager(this, !options.reUsePluginManager);\n\n options.pluginManager = pluginManager;\n\n context = new contexts.Parse(options);\n\n if (options.rootFileInfo) {\n rootFileInfo = options.rootFileInfo;\n } else {\n const filename = options.filename || 'input';\n const entryPath = filename.replace(/[^\\/\\\\]*$/, '');\n rootFileInfo = {\n filename,\n rewriteUrls: context.rewriteUrls,\n rootpath: context.rootpath || '',\n currentDirectory: entryPath,\n entryPath,\n rootFilename: filename\n };\n // add in a missing trailing slash\n if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== '/') {\n rootFileInfo.rootpath += '/';\n }\n }\n\n const imports = new ImportManager(this, context, rootFileInfo);\n this.importManager = imports;\n\n // TODO: allow the plugins to be just a list of paths or names\n // Do an async plugin queue like lessc\n\n if (options.plugins) {\n options.plugins.forEach(plugin => {\n let evalResult;\n let contents;\n if (plugin.fileContent) {\n contents = plugin.fileContent.replace(/^\\uFEFF/, '');\n evalResult = pluginManager.Loader.evalPlugin(contents, context, imports, plugin.options, plugin.filename);\n if (evalResult instanceof LessError) {\n return callback(evalResult);\n }\n }\n else {\n pluginManager.addPlugin(plugin);\n }\n });\n }\n\n new Parser(context, imports, rootFileInfo)\n .parse(input, (e, root) => {\n if (e) { return callback(e); }\n callback(null, root, imports, options);\n }, options);\n }\n };\n return parse;\n};\n","// TODO: Add tests for browser @plugin\n/* global window */\n\nimport AbstractPluginLoader from '../less/environment/abstract-plugin-loader.js';\n\n/**\n * Browser Plugin Loader\n */\nclass PluginLoader extends AbstractPluginLoader {\n constructor(less) {\n super();\n\n this.less = less;\n // Should we shim this.require for browser? Probably not?\n }\n\n loadPlugin(filename, basePath, context, environment, fileManager) {\n return new Promise((fulfill, reject) => {\n fileManager.loadFile(filename, basePath, context, environment)\n .then(fulfill).catch(reject);\n });\n }\n}\n\nexport default PluginLoader;\n\n","import * as utils from './utils';\nimport browser from './browser';\n\nexport default (window, less, options) => {\n\n function errorHTML(e, rootHref) {\n const id = `less-error-message:${utils.extractId(rootHref || '')}`;\n const template = '
  • {content}
  • ';\n const elem = window.document.createElement('div');\n let timer;\n let content;\n const errors = [];\n const filename = e.filename || rootHref;\n const filenameNoPath = filename.match(/([^\\/]+(\\?.*)?)$/)[1];\n\n elem.id = id;\n elem.className = 'less-error-message';\n\n content = `

    ${e.type || 'Syntax'}Error: ${e.message || 'There is an error in your .less file'}` + \n `

    in ${filenameNoPath} `;\n\n const errorline = (e, i, classname) => {\n if (e.extract[i] !== undefined) {\n errors.push(template.replace(/\\{line\\}/, (parseInt(e.line, 10) || 0) + (i - 1))\n .replace(/\\{class\\}/, classname)\n .replace(/\\{content\\}/, e.extract[i]));\n }\n };\n\n if (e.line) {\n errorline(e, 0, '');\n errorline(e, 1, 'line');\n errorline(e, 2, '');\n content += `on line ${e.line}, column ${e.column + 1}:

      ${errors.join('')}
    `;\n }\n if (e.stack && (e.extract || options.logLevel >= 4)) {\n content += `
    Stack Trace
    ${e.stack.split('\\n').slice(1).join('
    ')}`;\n }\n elem.innerHTML = content;\n\n // CSS for error messages\n browser.createCSS(window.document, [\n '.less-error-message ul, .less-error-message li {',\n 'list-style-type: none;',\n 'margin-right: 15px;',\n 'padding: 4px 0;',\n 'margin: 0;',\n '}',\n '.less-error-message label {',\n 'font-size: 12px;',\n 'margin-right: 15px;',\n 'padding: 4px 0;',\n 'color: #cc7777;',\n '}',\n '.less-error-message pre {',\n 'color: #dd6666;',\n 'padding: 4px 0;',\n 'margin: 0;',\n 'display: inline-block;',\n '}',\n '.less-error-message pre.line {',\n 'color: #ff0000;',\n '}',\n '.less-error-message h3 {',\n 'font-size: 20px;',\n 'font-weight: bold;',\n 'padding: 15px 0 5px 0;',\n 'margin: 0;',\n '}',\n '.less-error-message a {',\n 'color: #10a',\n '}',\n '.less-error-message .error {',\n 'color: red;',\n 'font-weight: bold;',\n 'padding-bottom: 2px;',\n 'border-bottom: 1px dashed red;',\n '}'\n ].join('\\n'), { title: 'error-message' });\n\n elem.style.cssText = [\n 'font-family: Arial, sans-serif',\n 'border: 1px solid #e00',\n 'background-color: #eee',\n 'border-radius: 5px',\n '-webkit-border-radius: 5px',\n '-moz-border-radius: 5px',\n 'color: #e00',\n 'padding: 15px',\n 'margin-bottom: 15px'\n ].join(';');\n\n if (options.env === 'development') {\n timer = setInterval(() => {\n const document = window.document;\n const body = document.body;\n if (body) {\n if (document.getElementById(id)) {\n body.replaceChild(elem, document.getElementById(id));\n } else {\n body.insertBefore(elem, body.firstChild);\n }\n clearInterval(timer);\n }\n }, 10);\n }\n }\n\n function removeErrorHTML(path) {\n const node = window.document.getElementById(`less-error-message:${utils.extractId(path)}`);\n if (node) {\n node.parentNode.removeChild(node);\n }\n }\n\n function removeErrorConsole(path) {\n // no action\n }\n\n function removeError(path) {\n if (!options.errorReporting || options.errorReporting === 'html') {\n removeErrorHTML(path);\n } else if (options.errorReporting === 'console') {\n removeErrorConsole(path);\n } else if (typeof options.errorReporting === 'function') {\n options.errorReporting('remove', path);\n }\n }\n\n function errorConsole(e, rootHref) {\n const template = '{line} {content}';\n const filename = e.filename || rootHref;\n const errors = [];\n let content = `${e.type || 'Syntax'}Error: ${e.message || 'There is an error in your .less file'} in ${filename}`;\n\n const errorline = (e, i, classname) => {\n if (e.extract[i] !== undefined) {\n errors.push(template.replace(/\\{line\\}/, (parseInt(e.line, 10) || 0) + (i - 1))\n .replace(/\\{class\\}/, classname)\n .replace(/\\{content\\}/, e.extract[i]));\n }\n };\n\n if (e.line) {\n errorline(e, 0, '');\n errorline(e, 1, 'line');\n errorline(e, 2, '');\n content += ` on line ${e.line}, column ${e.column + 1}:\\n${errors.join('\\n')}`;\n }\n if (e.stack && (e.extract || options.logLevel >= 4)) {\n content += `\\nStack Trace\\n${e.stack}`;\n }\n less.logger.error(content);\n }\n\n function error(e, rootHref) {\n if (!options.errorReporting || options.errorReporting === 'html') {\n errorHTML(e, rootHref);\n } else if (options.errorReporting === 'console') {\n errorConsole(e, rootHref);\n } else if (typeof options.errorReporting === 'function') {\n options.errorReporting('add', e, rootHref);\n }\n }\n\n return {\n add: error,\n remove: removeError\n };\n};\n","/**\n * Kicks off less and compiles any stylesheets\n * used in the browser distributed version of less\n * to kick-start less using the browser api\n */\n/* global window, document */\n\nimport defaultOptions from '../less/default-options';\nimport addDefaultOptions from './add-default-options';\nimport root from './index';\n\nconst options = defaultOptions();\n\nif (window.less) {\n for (const key in window.less) {\n if (window.less.hasOwnProperty(key)) {\n options[key] = window.less[key];\n }\n }\n}\naddDefaultOptions(window, options);\n\noptions.plugins = options.plugins || [];\n\nif (window.LESS_PLUGINS) {\n options.plugins = options.plugins.concat(window.LESS_PLUGINS);\n}\n\nconst less = root(window, options);\nexport default less;\n\nwindow.less = less;\n\nlet css;\nlet head;\nlet style;\n\n// Always restore page visibility\nfunction resolveOrReject(data) {\n if (data.filename) {\n console.warn(data);\n }\n if (!options.async) {\n head.removeChild(style);\n }\n}\n\nif (options.onReady) {\n if (/!watch/.test(window.location.hash)) {\n less.watch();\n }\n // Simulate synchronous stylesheet loading by hiding page rendering\n if (!options.async) {\n css = 'body { display: none !important }';\n head = document.head || document.getElementsByTagName('head')[0];\n style = document.createElement('style');\n\n style.type = 'text/css';\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n\n head.appendChild(style);\n }\n less.registerStylesheetsImmediately();\n less.pageLoadFinished = less.refresh(less.env === 'development').then(resolveOrReject, resolveOrReject);\n}\n","// Export a new default each time\nexport default () => ({\n /* Inline Javascript - @plugin still allowed */\n javascriptEnabled: false,\n\n /* Outputs a makefile import dependency list to stdout. */\n depends: false,\n\n /* (DEPRECATED) Compress using less built-in compression. \n * This does an okay job but does not utilise all the tricks of \n * dedicated css compression. */\n compress: false,\n\n /* Runs the less parser and just reports errors without any output. */\n lint: false,\n\n /* Sets available include paths.\n * If the file in an @import rule does not exist at that exact location, \n * less will look for it at the location(s) passed to this option. \n * You might use this for instance to specify a path to a library which \n * you want to be referenced simply and relatively in the less files. */\n paths: [],\n\n /* color output in the terminal */\n color: true,\n\n /* The strictImports controls whether the compiler will allow an @import inside of either \n * @media blocks or (a later addition) other selector blocks.\n * See: https://github.com/less/less.js/issues/656 */\n strictImports: false,\n\n /* Allow Imports from Insecure HTTPS Hosts */\n insecure: false,\n\n /* Allows you to add a path to every generated import and url in your css. \n * This does not affect less import statements that are processed, just ones \n * that are left in the output css. */\n rootpath: '',\n\n /* By default URLs are kept as-is, so if you import a file in a sub-directory \n * that references an image, exactly the same URL will be output in the css. \n * This option allows you to re-write URL's in imported files so that the \n * URL is always relative to the base imported file */\n rewriteUrls: false,\n\n /* How to process math \n * 0 always - eagerly try to solve all operations\n * 1 parens-division - require parens for division \"/\"\n * 2 parens | strict - require parens for all operations\n * 3 strict-legacy - legacy strict behavior (super-strict)\n */\n math: 0,\n\n /* Without this option, less attempts to guess at the output unit when it does maths. */\n strictUnits: false,\n\n /* Effectively the declaration is put at the top of your base Less file, \n * meaning it can be used but it also can be overridden if this variable \n * is defined in the file. */\n globalVars: null,\n\n /* As opposed to the global variable option, this puts the declaration at the\n * end of your base file, meaning it will override anything defined in your Less file. */\n modifyVars: null,\n\n /* This option allows you to specify a argument to go on to every URL. */\n urlArgs: ''\n});","import {addDataAttr} from './utils';\nimport browser from './browser';\n\nexport default (window, options) => {\n\n // use options from the current script tag data attribues\n addDataAttr(options, browser.currentScript(window));\n\n if (options.isFileProtocol === undefined) {\n options.isFileProtocol = /^(file|(chrome|safari)(-extension)?|resource|qrc|app):/.test(window.location.protocol);\n }\n\n // Load styles asynchronously (default: false)\n //\n // This is set to `false` by default, so that the body\n // doesn't start loading before the stylesheets are parsed.\n // Setting this to `true` can result in flickering.\n //\n options.async = options.async || false;\n options.fileAsync = options.fileAsync || false;\n\n // Interval between watch polls\n options.poll = options.poll || (options.isFileProtocol ? 1000 : 1500);\n\n options.env = options.env || (window.location.hostname == '127.0.0.1' ||\n window.location.hostname == '0.0.0.0' ||\n window.location.hostname == 'localhost' ||\n (window.location.port &&\n window.location.port.length > 0) ||\n options.isFileProtocol ? 'development'\n : 'production');\n\n const dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(window.location.hash);\n if (dumpLineNumbers) {\n options.dumpLineNumbers = dumpLineNumbers[1];\n }\n\n if (options.useFileCache === undefined) {\n options.useFileCache = true;\n }\n\n if (options.onReady === undefined) {\n options.onReady = true;\n }\n\n if (options.relativeUrls) {\n options.rewriteUrls = 'all';\n }\n};\n","//\n// index.js\n// Should expose the additional browser functions on to the less object\n//\nimport {addDataAttr} from './utils';\nimport lessRoot from '../less';\nimport browser from './browser';\nimport FM from './file-manager';\nimport PluginLoader from './plugin-loader';\nimport LogListener from './log-listener';\nimport ErrorReporting from './error-reporting';\nimport Cache from './cache';\nimport ImageSize from './image-size';\n\nexport default (window, options) => {\n const document = window.document;\n const less = lessRoot();\n\n less.options = options;\n const environment = less.environment;\n const FileManager = FM(options, less.logger);\n const fileManager = new FileManager();\n environment.addFileManager(fileManager);\n less.FileManager = FileManager;\n less.PluginLoader = PluginLoader;\n\n LogListener(less, options);\n const errors = ErrorReporting(window, less, options);\n const cache = less.cache = options.cache || Cache(window, options, less.logger);\n ImageSize(less.environment);\n\n // Setup user functions - Deprecate?\n if (options.functions) {\n less.functions.functionRegistry.addMultiple(options.functions);\n }\n\n const typePattern = /^text\\/(x-)?less$/;\n\n function clone(obj) {\n const cloned = {};\n for (const prop in obj) {\n if (obj.hasOwnProperty(prop)) {\n cloned[prop] = obj[prop];\n }\n }\n return cloned;\n }\n\n // only really needed for phantom\n function bind(func, thisArg) {\n const curryArgs = Array.prototype.slice.call(arguments, 2);\n return function() {\n const args = curryArgs.concat(Array.prototype.slice.call(arguments, 0));\n return func.apply(thisArg, args);\n };\n }\n\n function loadStyles(modifyVars) {\n const styles = document.getElementsByTagName('style');\n let style;\n\n for (let i = 0; i < styles.length; i++) {\n style = styles[i];\n if (style.type.match(typePattern)) {\n const instanceOptions = clone(options);\n instanceOptions.modifyVars = modifyVars;\n const lessText = style.innerHTML || '';\n instanceOptions.filename = document.location.href.replace(/#.*$/, '');\n\n /* jshint loopfunc:true */\n // use closure to store current style\n less.render(lessText, instanceOptions,\n bind((style, e, result) => {\n if (e) {\n errors.add(e, 'inline');\n } else {\n style.type = 'text/css';\n if (style.styleSheet) {\n style.styleSheet.cssText = result.css;\n } else {\n style.innerHTML = result.css;\n }\n }\n }, null, style));\n }\n }\n }\n\n function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {\n\n const instanceOptions = clone(options);\n addDataAttr(instanceOptions, sheet);\n instanceOptions.mime = sheet.type;\n\n if (modifyVars) {\n instanceOptions.modifyVars = modifyVars;\n }\n\n function loadInitialFileCallback(loadedFile) {\n const data = loadedFile.contents;\n const path = loadedFile.filename;\n const webInfo = loadedFile.webInfo;\n\n const newFileInfo = {\n currentDirectory: fileManager.getPath(path),\n filename: path,\n rootFilename: path,\n rewriteUrls: instanceOptions.rewriteUrls\n };\n\n newFileInfo.entryPath = newFileInfo.currentDirectory;\n newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory;\n\n if (webInfo) {\n webInfo.remaining = remaining;\n\n const css = cache.getCSS(path, webInfo, instanceOptions.modifyVars);\n if (!reload && css) {\n webInfo.local = true;\n callback(null, css, data, sheet, webInfo, path);\n return;\n }\n\n }\n\n // TODO add tests around how this behaves when reloading\n errors.remove(path);\n\n instanceOptions.rootFileInfo = newFileInfo;\n less.render(data, instanceOptions, (e, result) => {\n if (e) {\n e.href = path;\n callback(e);\n } else {\n cache.setCSS(sheet.href, webInfo.lastModified, instanceOptions.modifyVars, result.css);\n callback(null, result.css, data, sheet, webInfo, path);\n }\n });\n }\n\n fileManager.loadFile(sheet.href, null, instanceOptions, environment)\n .then(loadedFile => {\n loadInitialFileCallback(loadedFile);\n }).catch(err => {\n console.log(err);\n callback(err);\n });\n\n }\n\n function loadStyleSheets(callback, reload, modifyVars) {\n for (let i = 0; i < less.sheets.length; i++) {\n loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars);\n }\n }\n\n function initRunningMode() {\n if (less.env === 'development') {\n less.watchTimer = setInterval(() => {\n if (less.watchMode) {\n fileManager.clearFileCache();\n loadStyleSheets((e, css, _, sheet, webInfo) => {\n if (e) {\n errors.add(e, e.href || sheet.href);\n } else if (css) {\n browser.createCSS(window.document, css, sheet);\n }\n });\n }\n }, options.poll);\n }\n }\n\n //\n // Watch mode\n //\n less.watch = function () {\n if (!less.watchMode ) {\n less.env = 'development';\n initRunningMode();\n }\n this.watchMode = true;\n return true;\n };\n\n less.unwatch = function () {clearInterval(less.watchTimer); this.watchMode = false; return false; };\n\n //\n // Synchronously get all tags with the 'rel' attribute set to\n // \"stylesheet/less\".\n //\n less.registerStylesheetsImmediately = () => {\n const links = document.getElementsByTagName('link');\n less.sheets = [];\n\n for (let i = 0; i < links.length; i++) {\n if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&\n (links[i].type.match(typePattern)))) {\n less.sheets.push(links[i]);\n }\n }\n };\n\n //\n // Asynchronously get all tags with the 'rel' attribute set to\n // \"stylesheet/less\", returning a Promise.\n //\n less.registerStylesheets = () => new Promise((resolve, reject) => {\n less.registerStylesheetsImmediately();\n resolve();\n });\n\n //\n // With this function, it's possible to alter variables and re-render\n // CSS without reloading less-files\n //\n less.modifyVars = record => less.refresh(true, record, false);\n\n less.refresh = (reload, modifyVars, clearFileCache) => {\n if ((reload || clearFileCache) && clearFileCache !== false) {\n fileManager.clearFileCache();\n }\n return new Promise((resolve, reject) => {\n let startTime;\n let endTime;\n let totalMilliseconds;\n let remainingSheets;\n startTime = endTime = new Date();\n\n // Set counter for remaining unprocessed sheets\n remainingSheets = less.sheets.length;\n\n if (remainingSheets === 0) {\n\n endTime = new Date();\n totalMilliseconds = endTime - startTime;\n less.logger.info('Less has finished and no sheets were loaded.');\n resolve({\n startTime,\n endTime,\n totalMilliseconds,\n sheets: less.sheets.length\n });\n\n } else {\n // Relies on less.sheets array, callback seems to be guaranteed to be called for every element of the array\n loadStyleSheets((e, css, _, sheet, webInfo) => {\n if (e) {\n errors.add(e, e.href || sheet.href);\n reject(e);\n return;\n }\n if (webInfo.local) {\n less.logger.info(`Loading ${sheet.href} from cache.`);\n } else {\n less.logger.info(`Rendered ${sheet.href} successfully.`);\n }\n browser.createCSS(window.document, css, sheet);\n less.logger.info(`CSS for ${sheet.href} generated in ${new Date() - endTime}ms`);\n\n // Count completed sheet\n remainingSheets--;\n\n // Check if the last remaining sheet was processed and then call the promise\n if (remainingSheets === 0) {\n totalMilliseconds = new Date() - startTime;\n less.logger.info(`Less has finished. CSS generated in ${totalMilliseconds}ms`);\n resolve({\n startTime,\n endTime,\n totalMilliseconds,\n sheets: less.sheets.length\n });\n }\n endTime = new Date();\n }, reload, modifyVars);\n }\n\n loadStyles(modifyVars);\n });\n };\n\n less.refreshStyles = loadStyles;\n return less;\n};\n","export default (less, options) => {\n const logLevel_debug = 4;\n const logLevel_info = 3;\n const logLevel_warn = 2;\n const logLevel_error = 1;\n\n // The amount of logging in the javascript console.\n // 3 - Debug, information and errors\n // 2 - Information and errors\n // 1 - Errors\n // 0 - None\n // Defaults to 2\n options.logLevel = typeof options.logLevel !== 'undefined' ? options.logLevel : (options.env === 'development' ? logLevel_info : logLevel_error);\n\n if (!options.loggers) {\n options.loggers = [{\n debug: function(msg) {\n if (options.logLevel >= logLevel_debug) {\n console.log(msg);\n }\n },\n info: function(msg) {\n if (options.logLevel >= logLevel_info) {\n console.log(msg);\n }\n },\n warn: function(msg) {\n if (options.logLevel >= logLevel_warn) {\n console.warn(msg);\n }\n },\n error: function(msg) {\n if (options.logLevel >= logLevel_error) {\n console.error(msg);\n }\n }\n }];\n }\n for (let i = 0; i < options.loggers.length; i++) {\n less.logger.addListener(options.loggers[i]);\n }\n};\n","// Cache system is a bit outdated and could do with work\n\nexport default (window, options, logger) => {\n let cache = null;\n if (options.env !== 'development') {\n try {\n cache = (typeof window.localStorage === 'undefined') ? null : window.localStorage;\n } catch (_) {}\n }\n return {\n setCSS: function(path, lastModified, modifyVars, styles) {\n if (cache) {\n logger.info(`saving ${path} to cache.`);\n try {\n cache.setItem(path, styles);\n cache.setItem(`${path}:timestamp`, lastModified);\n if (modifyVars) {\n cache.setItem(`${path}:vars`, JSON.stringify(modifyVars));\n }\n } catch (e) {\n // TODO - could do with adding more robust error handling\n logger.error(`failed to save \"${path}\" to local storage for caching.`);\n }\n }\n },\n getCSS: function(path, webInfo, modifyVars) {\n const css = cache && cache.getItem(path);\n const timestamp = cache && cache.getItem(`${path}:timestamp`);\n let vars = cache && cache.getItem(`${path}:vars`);\n\n modifyVars = modifyVars || {};\n vars = vars || \"{}\"; // if not set, treat as the JSON representation of an empty object\n\n if (timestamp && webInfo.lastModified &&\n (new Date(webInfo.lastModified).valueOf() ===\n new Date(timestamp).valueOf()) &&\n JSON.stringify(modifyVars) === vars) {\n // Use local copy\n return css;\n }\n }\n };\n};\n","\nimport functionRegistry from './../less/functions/function-registry';\n\nexport default () => {\n function imageSize() {\n throw {\n type: 'Runtime',\n message: 'Image size functions are not supported in browser version of less'\n };\n }\n\n const imageFunctions = {\n 'image-size': function(filePathNode) {\n imageSize(this, filePathNode);\n return -1;\n },\n 'image-width': function(filePathNode) {\n imageSize(this, filePathNode);\n return -1;\n },\n 'image-height': function(filePathNode) {\n imageSize(this, filePathNode);\n return -1;\n }\n };\n\n functionRegistry.addMultiple(imageFunctions);\n};\n"],"names":["extractId","href","replace","addDataAttr","options","tag","opt","dataset","hasOwnProperty","JSON","parse","_","createCSS","document","styles","sheet","id","title","utils","oldStyleNode","getElementById","keepOldStyleNode","styleNode","createElement","setAttribute","media","styleSheet","appendChild","createTextNode","childNodes","length","firstChild","nodeValue","head","getElementsByTagName","nextEl","nextSibling","parentNode","insertBefore","removeChild","cssText","e","Error","currentScript","window","scripts","duration","angle","Math","PI","colors","unitConversions","Node","parent","visibilityBlocks","undefined","nodeVisible","rootNode","parsed","self","this","Object","defineProperty","get","fileInfo","getIndex","nodes","set","node","Array","isArray","forEach","_index","_fileInfo","context","strs","genCSS","add","chunk","index","push","isEmpty","join","output","value","visitor","visit","op","a","b","precision","numPrecision","Number","toFixed","info","compare","type","i","numericCompare","Color","rgb","originalForm","match","map","c","parseInt","alpha","split","_this","r","g","pow","toCSS","doNotCompress","color","colorFunction","compress","args","fround","indexOf","clamp","round","concat","toHSL","h","s","l","toRGB","splitcolor","other","_operate","toHex","max","min","d","v","x","toString","prototype","fromKeyword","keyword","key","toLowerCase","slice","Paren","eval","_noSpaceCombinators","Combinator","emptyOrWhitespace","trim","spaceOrEmpty","Element","combinator","isVariable","currentFileInfo","visibilityInfo","copyVisibilityInfo","setParent","_typeof","firstSelector","charAt","ALWAYS","PARENS_DIVISION","PARENS","STRICT_LEGACY","RewriteUrls","OFF","LOCAL","ALL","clone","_instanceof","obj","nativeMap","nativeSet","nativePromise","Map","Set","Promise","circular","depth","includeNonEnumerable","allParents","allChildren","useBuffer","Buffer","Infinity","_clone","child","proto","resolve","reject","then","err","__isArray","__isRegExp","RegExp","source","__getRegExpFlags","lastIndex","__isDate","Date","getTime","isBuffer","allocUnsafe","copy","create","getPrototypeOf","keyChild","valueChild","entryChild","attrs","getOwnPropertyDescriptor","getOwnPropertySymbols","symbols","symbol","descriptor","enumerable","allPropertyNames","getOwnPropertyNames","propertyName","__objToStr","o","call","re","flags","global","ignoreCase","multiline","clonePrototype","module","exports","getLocation","inputStream","n","line","column","copyArray","arr","cloned","prop","defaults","obj1","obj2","newObj","_defaults","CloneHelper","assign","copyOptions","opts","strictMath","math","Constants","relativeUrls","rewriteUrls","flattenArray","result","LessError","fileContentMap","currentFilename","filename","message","stack","input","contents","loc","col","callLine","lines","found","callExtract","extract","F","constructor","error","stylize","str","errorTxt","substr","Selector","elements","extendList","condition","evaldCondition","getElements","mixinElements_","visitArray","newSelector","mediaEmpty","els","parseNode","imports","sels","olen","len","mixinElements","shift","extend","createDerived","Value","Keyword","True","False","Anonymous","mapLines","rulesetLike","allowRoot","Boolean","MATH","Declaration","name","important","merge","inline","variable","lastRule","prevMath","evaldValue","mathBypass","evalName","importantScope","importantResult","pop","debugInfo","ctx","lineSeparator","dumpLineNumbers","asComment","asMediaQuery","lineNumber","fileName","filenameWithProtocol","test","Comment","isLineComment","getDebugInfo","isCompressed","contexts","copyFromOriginal","original","destination","propertiesToCopy","parseCopyProperties","Parse","paths","evalCopyProperties","isPathRelative","path","isPathLocalRelative","Eval","frames","inCalc","mathOn","calcStack","parensStack","rootpath","newPath","normalizePath","segment","segments","reverse","makeRegistry","base","_data","func","addMultiple","functions","keys","getLocalFunctions","inherit","defaultFunc","value_","error_","reset","Ruleset","selectors","rules","strictImports","_lookups","_variables","_properties","selCnt","selector","hasVariable","hasOnePassingSelector","j","toParseSelectors","rule","subRule","ruleset","originalRuleset","root","firstRoot","allowImports","functionRegistry","globalFunctionRegistry","ctxFrames","unshift","ctxSelectors","evalImports","rsRules","evalFirst","mediaBlockCount","mediaBlocks","filter","splice","resetCache","isJustParentSelector","bubbleSelectors","importRules","makeImportant","lastSelector","_rulesets","reduce","hash","variables","vars","decl","parseValue","properties","toParse","transformDeclaration","filtRules","isRuleset","foundMixins","rulesets","find","apply","ruleNodes","tabLevel","sep","tabRuleStr","tabSetStr","charsetNodeIndex","importNodeIndex","isCharset","pathSubCnt","pathCnt","currentLastRule","isRulesetLike","isVisible","joinSelector","createParenthesis","elementsToPak","originalElement","replacementParen","insideParent","createSelector","containedElement","element","addReplacementIntoPath","beginningPath","addPath","replacedElement","originalSelector","newSelectorPath","newJoinedSelector","parentEl","restOfPath","addAllReplacementsIntoPath","addPaths","mergeElementsOnToSelectors","sel","deriveSelector","deriveFrom","newPaths","replaceParentSelector","inSelector","k","currentElements","newSelectors","selectorsMultiplied","el","maybeSelector","hadParentSelector","nestedSelector","replaced","nestedPaths","replacedNewSelectors","concatenated","bind","AtRule","isRooted","createEmptySelectors","outputRuleset","mediaPathBackup","mediaBlocksBackup","mediaPath","ruleCnt","DetachedRuleset","Unit","numerator","denominator","backupUnit","sort","strictUnits","returnStr","is","unitString","toUpperCase","callback","group","mapUnit","groupName","atomicUnit","counter","count","Dimension","unit","parseFloat","isNaN","isSingular","strValue","String","isLength","convertTo","usedUnits","cancel","unify","conversions","targetUnit","applyUnit","derivedConversions","Operation","operands","isSpaced","isMathOn","toColor","operate","Expression","noSpacing","returnValue","inParenthesis","parens","parensInOp","doubleParen","outOfParenthesis","functionCaller","item","subNodes","Call","calc","currentMathContext","enterCalc","exitCalc","funcCaller","FunctionCaller","isValid","columnNumber","Variable","evaluating","frame","fun","Property","property","mergeRules","pluginManager","less","visitors","ToCSSVisitor","_mergeRules","vArr","Attribute","Quoted","content","escaped","quote","variableRegex","propRegex","that","iterativeReplace","regexp","replacementFnc","evaluatedValue","URL","val","isEvald","pathRequiresRewrite","rewritePath","urlArgs","Media","features","evalTop","evalNested","multiMedia","permute","fragment","rest","Import","css","pathValue","getPath","isPlugin","reference","containsVariables","doEval","blocksVisibility","addVisibilityBlock","registry","skip","importedFilename","newImport","evalPath","JsEvalNode","expression","evalContext","javascriptEnabled","jsify","Function","toJS","JavaScript","string","evaluateJavaScript","Assignment","Condition","negate","lvalue","rvalue","UnicodeDescriptor","Negative","Extend","option","object_id","next_id","parent_ids","allowBefore","allowAfter","selectorElements","selfElements","selfSelectors","VariableCall","detachedRuleset","callEval","NamespaceValue","ruleCall","lookups","lastDeclaration","substring","Definition","params","variadic","arity","optionalParameters","required","p","mixinEnv","evaldArguments","varargs","arg","isNamedFound","argIndex","argsLength","prependRule","_arguments","mixinFrames","evalParams","allArgsCnt","requiredArgsCnt","MixinCall","arguments","mixins","mixin","mixinPath","argValue","m","f","isRecursive","isOneFound","candidate","defaultResult","noArgumentsFilter","candidates","conditionResult","defFalseEitherCase","defNone","defTrue","defFalse","calcDefGroup","namespace","matchCondition","expand","matchArgs","MixinDefinition","format","newRules","evalCall","_setVisibilityToReplacement","replacement","msg","_fireEvent","warn","debug","addListener","listener","_listeners","removeListener","logFunction","environment","externalEnvironment","fileManagers","requiredFunctions","propName","environmentFunc","currentDirectory","isSync","logger","getFileManagers","fileManager","AbstractFileManager","lastIndexOf","ext","tryAppendExtension","basePath","laterPath","url","baseUrl","urlDirectories","baseUrlDirectories","urlParts","extractUrlParts","baseUrlParts","diff","hostPart","directories","urlPartsRegex","returner","rawDirectories","rawPath","fileUrl","AbstractPluginLoader","require","pluginOptions","pluginObj","localModule","shortname","FileManager","trySetOptions","use","loader","tree","validatePlugin","minVersion","compareVersion","addPlugin","plugin","setOptions","version","versionToString","aVersion","bVersion","versionString","plugins","printUsage","_visitArgs","visitDeeper","_hasIndexed","_noop","Visitor","implementation","_implementation","_visitInCache","_visitOutCache","indexNodeTypes","ticker","typeIndex","nodeTypeIndex","fnName","impl","funcOut","visitArgs","newNode","isReplacing","accept","nonReplacing","cnt","out","evald","flatten","nestedCnt","nestedItem","ImportSequencer","onSequencerEmpty","variableImports","_onSequencerEmpty","_currentDepth","importSequencer","importItem","isReady","tryRun","variableImport","ImportVisitor","importer","finish","_visitor","_importer","_finish","importCount","onceFileDetectionMap","recursionDetector","_sequencer","run","isFinished","visitImport","importNode","inlineCSS","importParent","isVariableImport","addVariableImport","processImportNode","evaldImportNode","evalForImport","multiple","importMultiple","tryAppendLessExtension","onImported","sequencedOnImported","addImport","importedAtRoot","fullPath","importVisitor","isOptional","optional","duplicateImport","oldContext","visitDeclaration","declNode","visitDeclarationOut","visitAtRule","atRuleNode","visitAtRuleOut","visitMixinDefinition","mixinDefinitionNode","visitMixinDefinitionOut","visitRuleset","rulesetNode","visitRulesetOut","visitMedia","mediaNode","visitMediaOut","SetTreeVisibilityVisitor","visible","ensureVisibility","ensureInvisibility","ExtendFinderVisitor","allExtendsStack","allExtends","allSelectorsExtendList","extendOnEveryPath","selectorPath","selExtendList","allSelectorsExtend","foundExtends","findSelfSelectors","firstExtendOnThisSelectorPath","ProcessExtendsVisitor","extendFinder","extendIndices","doExtendChaining","newRoot","checkExtendsForNonMatched","indices","hasFoundMatches","extendsList","extendsListTarget","iterationCount","extendIndex","targetExtendIndex","matches","targetExtend","newExtend","extendsToAdd","extendVisitor","findMatch","selfSelector","extendSelector","extendChainCount","selectorOne","selectorTwo","ruleNode","selectorNode","pathIndex","selectorsToAdd","extendedSelectors","haystackSelectorPath","haystackSelectorIndex","hackstackSelector","hackstackElementIndex","haystackElement","targetCombinator","potentialMatch","needleElements","potentialMatches","matched","initialCombinator","isElementValuesEqual","finished","endPathIndex","endPathElementIndex","elementValue1","elementValue2","replacementSelector","matchIndex","firstElement","newElements","currentSelectorPathIndex","currentSelectorPathElementIndex","currentValue","derived","newAllExtends","JoinSelectorVisitor","getIsOutput","joinSelectors","CSSVisitorUtils","_context","bodyRules","isSilent","owner","thing","originalRules","containsSilentNonBlockedChild","compiledRulesBody","keepOnlyVisibleChilds","removeVisibilityBlock","hasVisibleSelector","mixinNode","visitExtend","extendNode","visitComment","commentNode","resolveVisibility","visitAtRuleWithBody","visitAtRuleWithoutBody","visitAnonymous","anonymousNode","nodeRules","hasFakeRuleset","getBodyRules","charset","comment","checkValidNodes","isRoot","_compileRulesetPaths","nodeRuleCnt","_removeDuplicateRules","isVisibleRuleset","ruleList","ruleCache","ruleCSS","groups","groupsArr","space","comma","MarkVisibleSelectorsVisitor","ExtendVisitor","furthest","furthestPossibleErrorMessage","chunks","current","currentPos","saveStack","parserInput","CHARCODE_SPACE","CHARCODE_TAB","CHARCODE_LF","CHARCODE_CR","CHARCODE_FORWARD_SLASH","skipWhitespace","nextChar","oldi","oldj","curr","endIndex","mem","inp","charCodeAt","autoCommentAbsorb","nextNewLine","text","commentStore","nextStarSlash","save","restore","possibleErrorMessage","state","forget","isWhitespace","offset","pos","code","$re","tok","exec","$char","$str","tokLength","$quoted","startChar","currentPosition","$parseUntil","testChar","returnVal","inComment","blockDepth","blockStack","parseGroups","startPos","lastPos","loop","char","expected","peek","peekChar","currentChar","prevChar","getInput","peekNotNumeric","start","chunkInput","failFunction","fail","lastOpening","lastOpeningParen","lastMultiComment","lastMultiCommentEndBrace","chunkerCurrentIndex","currentChunkStartIndex","cc","cc2","level","parenLevel","emitFrom","emitChunk","force","fromCharCode","chunker","end","furthestReachedEnd","furthestChar","Parser","parsers","getParserInput","expect","expectChar","parseList","currentIndex","returnNodes","parser","additionalData","globalVars","modifyVars","ignored","preText","serializeVars","preProcessors","getPreProcessors","process","banner","contentsIgnoredChars","primary","endInfo","processImports","extendRule","definition","declaration","variableCall","entities","atrule","foundSemiColon","mixinLookup","quoted","forceEscaped","isEscaped","customFuncCall","stop","ieAlpha","boolean","prevArgs","isSemiColonSeparated","argsComma","argsSemiColon","assignment","literal","dimension","unicodeDescriptor","entity","ch","variableCurly","curly","propertyCurly","colorKeyword","ud","javascript","js","escape","parsedName","inValue","ruleLookups","isRule","getLookup","hasParens","elem","elemIndex","isCall","expressionContainsNamed","nameLoop","expressions","hasSep","throwAwayComments","cond","argInfo","conditions","block","lookupValue","attribute","slashedCombinator","isLess","when","blockRuleset","hasDR","ruleProperty","permissiveValue","anonymousValue","untilTokens","done","testCurrentChar","dir","importOptions","mediaFeatures","optionName","importOption","mediaFeature","pluginArgs","nonVendorSpecificName","hasIdentifier","hasExpression","hasUnknown","hasBlock","sub","addition","multiplication","operation","operand","needsParens","logical","next","conditionAnd","negatedCondition","parenthesisCondition","atomicCondition","body","me","tryConditionFollowedByParenthesis","delim","simpleProperty","colorFunctions","trueValue","falseValue","hsla","origColor","hsl","toHSV","number","rgba","size","m1","m2","hue","hsv","hsva","vs","floor","perm","saturation","lightness","hsvhue","hsvsaturation","hsvvalue","red","green","blue","luma","luminance","saturate","amount","method","desaturate","lighten","darken","fadein","fadeout","fade","spin","mix","color1","color2","weight","w","w1","w2","greyscale","contrast","dark","light","threshold","t","argb","toARGB","tint","shade","colorBlend","mode","cb","cs","ar","cr","ab","as","colorBlendModeFunctions","multiply","screen","overlay","softlight","sqrt","hardlight","difference","abs","exclusion","average","negation","getItemsFromNode","_SELF","values","range","step","from","to","stepValue","list","each","rs","iterator","Quote","valueName","keyName","indexName","MathHelper","fn","mathFunctions","ceil","tan","sin","cos","atan","asin","acos","mathHelper","fraction","num","pm","minMax","isMin","currentUnified","referenceUnified","unitStatic","unitClone","order","convert","pi","mod","y","percentage","evaluated","encodeURI","pattern","token","encodeURIComponent","isa","Type","isunit","isruleset","iscolor","isnumber","isstring","iskeyword","isurl","ispixel","ispercentage","isem","colorBlending","fallback","functionThis","mimetypeNode","filePathNode","mimetype","filePath","entryPath","fragmentStart","rawBuffer","getFileManager","useBase64","mimeLookup","charsetLookup","fileSync","loadFileSync","buf","encodeBase64","uri","dataUri","direction","stops","gradientDirectionSvg","position","positionValue","gradientType","rectangleDimension","renderEnv","directionValue","throwArgumentDescriptor","types","evaldRoot","evalEnv","visitorIterator","preEvalVisitors","first","isPreEvalVisitor","isPreVisitor","PluginManager","postProcessors","installedPlugins","pluginCache","Loader","PluginLoader","install","preProcessor","priority","indexToInsertAt","postProcessor","manager","PluginManagerFactory","newFactory","SourceMapOutput","_css","_rootNode","_contentsMap","contentsMap","_contentsIgnoredCharsMap","contentsIgnoredCharsMap","sourceMapFilename","_sourceMapFilename","_outputFilename","outputFilename","sourceMapURL","sourceMapBasepath","_sourceMapBasepath","sourceMapRootpath","_sourceMapRootpath","_outputSourceFiles","outputSourceFiles","_sourceMapGeneratorConstructor","getSourceMapGenerator","_lineNumber","_column","removeBasepath","sourceLines","columns","sourceColumns","inputSource","_sourceMapGenerator","addMapping","generated","normalizeFilename","file","sourceRoot","setSourceContent","sourceMapContent","stringify","toJSON","sourceMap","sourceMapOutput","Environment","SourceMapBuilder","sourceMapOutputFilename","sourceMapGenerator","sourceMapFileInline","sourceMapInputFilename","getCSSAppendage","sourceMapBuilder","ParseTree","transformTree","toCSSOptions","getPostProcessors","getExternalSourceMap","files","rootFilename","parseTree","ImportManager","rootFileInfo","mime","queue","importManager","pluginLoader","fileParsedFunc","importedEqualsRoot","newFileInfo","promise","loadFileCallback","loadedFile","resolvedFilename","pathDiff","isPathAbsolute","alwaysMakePathsAbsolute","newEnv","evalPlugin","loadPlugin","loadFile","render","Render","reUsePluginManager","evalResult","fileContent","Functions","initial","data","ctor","api","fileCache","errback","xhr","XMLHttpRequest","async","isFileProtocol","fileAsync","handleResponse","status","responseText","getResponseHeader","overrideMimeType","open","setRequestHeader","send","onreadystatechange","readyState","location","useFileCache","lessText","webInfo","lastModified","doXHR","log","fulfill","catch","rootHref","errorReporting","errors","errorline","classname","logLevel","errorConsole","timer","filenameNoPath","className","innerHTML","browser","style","env","setInterval","replaceChild","clearInterval","errorHTML","remove","removeErrorHTML","depends","lint","insecure","protocol","poll","hostname","port","onReady","addDefaultOptions","LESS_PLUGINS","lessRoot","FM","addFileManager","loggers","console","LogListener","ErrorReporting","cache","localStorage","setCSS","setItem","getCSS","getItem","timestamp","valueOf","Cache","imageSize","imageFunctions","ImageSize","typePattern","thisArg","curryArgs","loadStyles","instanceOptions","loadStyleSheet","reload","remaining","local","loadInitialFileCallback","loadStyleSheets","sheets","watch","watchMode","watchTimer","clearFileCache","unwatch","registerStylesheetsImmediately","links","rel","registerStylesheets","record","refresh","startTime","endTime","totalMilliseconds","remainingSheets","refreshStyles","resolveOrReject","pageLoadFinished"],"mappings":";;;;;;;;;0LACO,SAASA,EAAUC,UACfA,EAAKC,QAAQ,sBAAuB,IACtCA,QAAQ,uBAAwB,IAChCA,QAAQ,MAAO,IACfA,QAAQ,eAAgB,IACxBA,QAAQ,aAAc,KACtBA,QAAQ,MAAO,KAGjB,SAASC,EAAYC,EAASC,OAC5B,IAAMC,KAAOD,EAAIE,WACdF,EAAIE,QAAQC,eAAeF,MACf,QAARA,GAAyB,oBAARA,GAAqC,aAARA,GAA8B,mBAARA,EACpEF,EAAQE,GAAOD,EAAIE,QAAQD,YAGvBF,EAAQE,GAAOG,KAAKC,MAAML,EAAIE,QAAQD,IAE1C,MAAOK,WCjBR,CACXC,UAAW,SAAUC,EAAUC,EAAQC,OAE7Bd,EAAOc,EAAMd,MAAQ,GAGrBe,iBAAaD,EAAME,OAASC,EAAgBjB,IAG5CkB,EAAeN,EAASO,eAAeJ,GACzCK,GAAmB,EAGjBC,EAAYT,EAASU,cAAc,SACzCD,EAAUE,aAAa,OAAQ,YAC3BT,EAAMU,OACNH,EAAUE,aAAa,QAAST,EAAMU,OAE1CH,EAAUN,GAAKA,EAEVM,EAAUI,aACXJ,EAAUK,YAAYd,EAASe,eAAed,IAG9CO,EAAqC,OAAjBF,GAAyBA,EAAaU,WAAWC,OAAS,GAAKR,EAAUO,WAAWC,OAAS,GAC7GX,EAAaY,WAAWC,YAAcV,EAAUS,WAAWC,eAG7DC,EAAOpB,EAASqB,qBAAqB,QAAQ,MAI9B,OAAjBf,IAA8C,IAArBE,EAA4B,KAC/Cc,EAASpB,GAASA,EAAMqB,aAAe,KACzCD,EACAA,EAAOE,WAAWC,aAAahB,EAAWa,GAE1CF,EAAKN,YAAYL,MAGrBH,IAAqC,IAArBE,GAChBF,EAAakB,WAAWE,YAAYpB,GAMpCG,EAAUI,eAENJ,EAAUI,WAAWc,QAAU1B,EACjC,MAAO2B,SACC,IAAIC,MAAM,2CAI5BC,cAAe,SAASC,OAGVC,EAFJhC,EAAW+B,EAAO/B,gBACjBA,EAAS8B,gBACNE,EAAUhC,EAASqB,qBAAqB,WAC/BW,EAAQf,OAAS,s7DC7D7B,WACC,uBACG,eACR,qBACM,gBACL,gBACA,iBACC,gBACD,yBACS,eACV,qBACM,gBACL,oBACI,oBACA,qBACC,oBACD,gBACJ,yBACS,mBACN,kBACD,eACH,mBACI,mBACA,wBACK,mBACL,mBACA,oBACC,oBACA,sBACE,yBACG,qBACJ,qBACA,kBACH,qBACG,uBACE,wBACC,wBACA,wBACA,wBACA,qBACH,mBACF,sBACG,kBACJ,kBACA,qBACG,oBACD,sBACE,sBACA,kBACJ,oBACE,qBACC,eACN,oBACK,eACL,eACA,gBACC,sBACM,mBACH,kBACD,oBACE,iBACH,gBACD,gBACA,mBACG,wBACK,oBACJ,uBACG,oBACH,qBACC,oBACD,+BACW,oBACX,oBACA,qBACC,oBACD,sBACE,wBACE,uBACD,yBACE,yBACA,yBACA,sBACH,eACP,oBACK,gBACJ,kBACE,iBACD,2BACU,qBACN,uBACE,uBACA,yBACE,0BACC,4BACE,0BACF,0BACA,uBACH,oBACH,oBACA,mBACD,sBACG,eACP,kBACG,gBACF,oBACI,iBACH,oBACG,iBACH,wBACO,oBACJ,wBACI,wBACA,qBACH,oBACD,eACL,eACA,eACA,qBACM,iBACJ,wBACO,cACV,oBACM,oBACA,sBACE,iBACL,qBACI,mBACF,mBACA,iBACF,iBACA,kBACC,oBACE,oBACA,oBACA,eACL,sBACO,oBACF,cACN,eACC,kBACG,iBACD,oBACG,iBACH,gBACD,gBACA,qBACK,iBACJ,sBACK,aCpJH,CACXA,OAAQ,GACC,KACC,OACA,QACA,SACA,MAAS,MACT,MAAS,MACT,MAAS,GAAK,IAExBgB,SAAU,GACD,KACC,MAEVC,MAAO,KACI,GAAK,EAAIC,KAAKC,QACd,EAAI,SACH,WACA,MCfD,CAAEC,OAAAA,EAAQC,gBAAAA,GCHnBC,yCAEOC,OAAS,UACTC,sBAAmBC,OACnBC,iBAAcD,OACdE,SAAW,UACXC,OAAS,SAERC,EAAOC,KACbC,OAAOC,eAAeF,KAAM,kBAAmB,CAC3CG,IAAK,kBAAoBJ,EAAKK,cAElCH,OAAOC,eAAeF,KAAM,QAAS,CACjCG,IAAK,kBAAoBJ,EAAKM,0DAK5BC,EAAOb,YACJc,EAAIC,GACLA,GAAQA,aAAgB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"} \ No newline at end of file diff --git a/index.js b/index.js index 6bcc62066..2097ad092 100644 --- a/index.js +++ b/index.js @@ -1 +1 @@ -module.exports = require('./lib/less-node'); +module.exports = require('./dist/less.cjs.js'); diff --git a/lib/less-browser/add-default-options.js b/lib/less-browser/add-default-options.js index 981e0e4e5..d839595f9 100644 --- a/lib/less-browser/add-default-options.js +++ b/lib/less-browser/add-default-options.js @@ -1,7 +1,7 @@ -var addDataAttr = require('./utils').addDataAttr, - browser = require('./browser'); +import {addDataAttr} from './utils'; +import browser from './browser'; -module.exports = function(window, options) { +export default (window, options) => { // use options from the current script tag data attribues addDataAttr(options, browser.currentScript(window)); @@ -30,7 +30,7 @@ module.exports = function(window, options) { options.isFileProtocol ? 'development' : 'production'); - var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(window.location.hash); + const dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(window.location.hash); if (dumpLineNumbers) { options.dumpLineNumbers = dumpLineNumbers[1]; } diff --git a/lib/less-browser/bootstrap.js b/lib/less-browser/bootstrap.js index cf1ab4757..aa01c64b3 100644 --- a/lib/less-browser/bootstrap.js +++ b/lib/less-browser/bootstrap.js @@ -5,21 +5,20 @@ */ /* global window, document */ -// TODO - consider switching this out for a recommendation for this polyfill? -// -// Browsers have good Promise support -require('promise/polyfill'); +import defaultOptions from '../less/default-options'; +import addDefaultOptions from './add-default-options'; +import root from './index'; -var options = require('../less/default-options')(); +const options = defaultOptions(); if (window.less) { - for (var key in window.less) { + for (const key in window.less) { if (window.less.hasOwnProperty(key)) { options[key] = window.less[key]; } } } -require('./add-default-options')(window, options); +addDefaultOptions(window, options); options.plugins = options.plugins || []; @@ -27,11 +26,14 @@ if (window.LESS_PLUGINS) { options.plugins = options.plugins.concat(window.LESS_PLUGINS); } -var less = module.exports = require('./index')(window, options); +const less = root(window, options); +export default less; window.less = less; -var css, head, style; +let css; +let head; +let style; // Always restore page visibility function resolveOrReject(data) { diff --git a/lib/less-browser/browser.js b/lib/less-browser/browser.js index defc97728..58f339ccf 100644 --- a/lib/less-browser/browser.js +++ b/lib/less-browser/browser.js @@ -1,18 +1,19 @@ -var utils = require('./utils'); -module.exports = { +import * as utils from './utils'; + +export default { createCSS: function (document, styles, sheet) { // Strip the query-string - var href = sheet.href || ''; + const href = sheet.href || ''; // If there is no title set, use the filename, minus the extension - var id = 'less:' + (sheet.title || utils.extractId(href)); + const id = `less:${sheet.title || utils.extractId(href)}`; // If this has already been inserted into the DOM, we may need to replace it - var oldStyleNode = document.getElementById(id); - var keepOldStyleNode = false; + const oldStyleNode = document.getElementById(id); + let keepOldStyleNode = false; // Create a new stylesheet node for insertion or (if necessary) replacement - var styleNode = document.createElement('style'); + const styleNode = document.createElement('style'); styleNode.setAttribute('type', 'text/css'); if (sheet.media) { styleNode.setAttribute('media', sheet.media); @@ -27,12 +28,12 @@ module.exports = { oldStyleNode.firstChild.nodeValue === styleNode.firstChild.nodeValue); } - var head = document.getElementsByTagName('head')[0]; + const head = document.getElementsByTagName('head')[0]; // If there is no oldStyleNode, just append; otherwise, only append if we need // to replace oldStyleNode with an updated stylesheet if (oldStyleNode === null || keepOldStyleNode === false) { - var nextEl = sheet && sheet.nextSibling || null; + const nextEl = sheet && sheet.nextSibling || null; if (nextEl) { nextEl.parentNode.insertBefore(styleNode, nextEl); } else { @@ -55,9 +56,9 @@ module.exports = { } }, currentScript: function(window) { - var document = window.document; - return document.currentScript || (function() { - var scripts = document.getElementsByTagName('script'); + const document = window.document; + return document.currentScript || (() => { + const scripts = document.getElementsByTagName('script'); return scripts[scripts.length - 1]; })(); } diff --git a/lib/less-browser/cache.js b/lib/less-browser/cache.js index 827bc2519..5322c17b8 100644 --- a/lib/less-browser/cache.js +++ b/lib/less-browser/cache.js @@ -1,7 +1,7 @@ // Cache system is a bit outdated and could do with work -module.exports = function(window, options, logger) { - var cache = null; +export default (window, options, logger) => { + let cache = null; if (options.env !== 'development') { try { cache = (typeof window.localStorage === 'undefined') ? null : window.localStorage; @@ -10,23 +10,23 @@ module.exports = function(window, options, logger) { return { setCSS: function(path, lastModified, modifyVars, styles) { if (cache) { - logger.info('saving ' + path + ' to cache.'); + logger.info(`saving ${path} to cache.`); try { cache.setItem(path, styles); - cache.setItem(path + ':timestamp', lastModified); + cache.setItem(`${path}:timestamp`, lastModified); if (modifyVars) { - cache.setItem(path + ':vars', JSON.stringify(modifyVars)); + cache.setItem(`${path}:vars`, JSON.stringify(modifyVars)); } } catch (e) { // TODO - could do with adding more robust error handling - logger.error('failed to save "' + path + '" to local storage for caching.'); + logger.error(`failed to save "${path}" to local storage for caching.`); } } }, getCSS: function(path, webInfo, modifyVars) { - var css = cache && cache.getItem(path), - timestamp = cache && cache.getItem(path + ':timestamp'), - vars = cache && cache.getItem(path + ':vars'); + const css = cache && cache.getItem(path); + const timestamp = cache && cache.getItem(`${path}:timestamp`); + let vars = cache && cache.getItem(`${path}:vars`); modifyVars = modifyVars || {}; vars = vars || "{}"; // if not set, treat as the JSON representation of an empty object diff --git a/lib/less-browser/error-reporting.js b/lib/less-browser/error-reporting.js index 65df6ec13..c5606b643 100644 --- a/lib/less-browser/error-reporting.js +++ b/lib/less-browser/error-reporting.js @@ -1,22 +1,25 @@ -var utils = require('./utils'), - browser = require('./browser'); +import * as utils from './utils'; +import browser from './browser'; -module.exports = function(window, less, options) { +export default (window, less, options) => { function errorHTML(e, rootHref) { - var id = 'less-error-message:' + utils.extractId(rootHref || ''); - var template = '
  • {content}
  • '; - var elem = window.document.createElement('div'), timer, content, errors = []; - var filename = e.filename || rootHref; - var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; + const id = `less-error-message:${utils.extractId(rootHref || '')}`; + const template = '
  • {content}
  • '; + const elem = window.document.createElement('div'); + let timer; + let content; + const errors = []; + const filename = e.filename || rootHref; + const filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; elem.id = id; elem.className = 'less-error-message'; - content = '

    ' + (e.type || 'Syntax') + 'Error: ' + (e.message || 'There is an error in your .less file') + - '

    ' + '

    in ' + filenameNoPath + ' '; + content = `

    ${e.type || 'Syntax'}Error: ${e.message || 'There is an error in your .less file'}` + + `

    in ${filenameNoPath} `; - var errorline = function (e, i, classname) { + const errorline = (e, i, classname) => { if (e.extract[i] !== undefined) { errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1)) .replace(/\{class\}/, classname) @@ -28,11 +31,10 @@ module.exports = function(window, less, options) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); - content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + - '
      ' + errors.join('') + '
    '; + content += `on line ${e.line}, column ${e.column + 1}:

      ${errors.join('')}
    `; } if (e.stack && (e.extract || options.logLevel >= 4)) { - content += '
    Stack Trace
    ' + e.stack.split('\n').slice(1).join('
    '); + content += `
    Stack Trace
    ${e.stack.split('\n').slice(1).join('
    ')}`; } elem.innerHTML = content; @@ -89,9 +91,9 @@ module.exports = function(window, less, options) { ].join(';'); if (options.env === 'development') { - timer = setInterval(function () { - var document = window.document, - body = document.body; + timer = setInterval(() => { + const document = window.document; + const body = document.body; if (body) { if (document.getElementById(id)) { body.replaceChild(elem, document.getElementById(id)); @@ -105,7 +107,7 @@ module.exports = function(window, less, options) { } function removeErrorHTML(path) { - var node = window.document.getElementById('less-error-message:' + utils.extractId(path)); + const node = window.document.getElementById(`less-error-message:${utils.extractId(path)}`); if (node) { node.parentNode.removeChild(node); } @@ -126,13 +128,12 @@ module.exports = function(window, less, options) { } function errorConsole(e, rootHref) { - var template = '{line} {content}'; - var filename = e.filename || rootHref; - var errors = []; - var content = (e.type || 'Syntax') + 'Error: ' + (e.message || 'There is an error in your .less file') + - ' in ' + filename; + const template = '{line} {content}'; + const filename = e.filename || rootHref; + const errors = []; + let content = `${e.type || 'Syntax'}Error: ${e.message || 'There is an error in your .less file'} in ${filename}`; - var errorline = function (e, i, classname) { + const errorline = (e, i, classname) => { if (e.extract[i] !== undefined) { errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1)) .replace(/\{class\}/, classname) @@ -144,11 +145,10 @@ module.exports = function(window, less, options) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); - content += ' on line ' + e.line + ', column ' + (e.column + 1) + ':\n' + - errors.join('\n'); + content += ` on line ${e.line}, column ${e.column + 1}:\n${errors.join('\n')}`; } if (e.stack && (e.extract || options.logLevel >= 4)) { - content += '\nStack Trace\n' + e.stack; + content += `\nStack Trace\n${e.stack}`; } less.logger.error(content); } diff --git a/lib/less-browser/file-manager.js b/lib/less-browser/file-manager.js index b59e0a402..6a74aee99 100644 --- a/lib/less-browser/file-manager.js +++ b/lib/less-browser/file-manager.js @@ -1,35 +1,32 @@ /* global window, XMLHttpRequest */ -module.exports = function(options, logger) { +import AbstractFileManager from '../less/environment/abstract-file-manager.js'; - var AbstractFileManager = require('../less/environment/abstract-file-manager.js'); +let options; +let logger; +let fileCache = {}; - var fileCache = {}; - - // TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load - var FileManager = function() { - }; - - FileManager.prototype = new AbstractFileManager(); - - FileManager.prototype.alwaysMakePathsAbsolute = function alwaysMakePathsAbsolute() { +// TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load +class FileManager extends AbstractFileManager { + alwaysMakePathsAbsolute() { return true; - }; - FileManager.prototype.join = function join(basePath, laterPath) { + } + + join(basePath, laterPath) { if (!basePath) { return laterPath; } return this.extractUrlParts(laterPath, basePath).path; - }; - FileManager.prototype.doXHR = function doXHR(url, type, callback, errback) { + } - var xhr = new XMLHttpRequest(); - var async = options.isFileProtocol ? options.fileAsync : true; + doXHR(url, type, callback, errback) { + const xhr = new XMLHttpRequest(); + const async = options.isFileProtocol ? options.fileAsync : true; if (typeof xhr.overrideMimeType === 'function') { xhr.overrideMimeType('text/css'); } - logger.debug('XHR: Getting \'' + url + '\''); + logger.debug(`XHR: Getting '${url}'`); xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); @@ -50,7 +47,7 @@ module.exports = function(options, logger) { errback(xhr.status, url); } } else if (async) { - xhr.onreadystatechange = function () { + xhr.onreadystatechange = () => { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } @@ -58,16 +55,17 @@ module.exports = function(options, logger) { } else { handleResponse(xhr, callback, errback); } - }; - FileManager.prototype.supports = function(filename, currentDirectory, options, environment) { + } + + supports() { return true; - }; + } - FileManager.prototype.clearFileCache = function() { + clearFileCache() { fileCache = {}; - }; + } - FileManager.prototype.loadFile = function loadFile(filename, currentDirectory, options, environment) { + loadFile(filename, currentDirectory, options, environment) { // TODO: Add prefix support like less-node? // What about multiple paths? @@ -81,17 +79,17 @@ module.exports = function(options, logger) { // sheet may be set to the stylesheet for the initial load or a collection of properties including // some context variables for imports - var hrefParts = this.extractUrlParts(filename, window.location.href); - var href = hrefParts.url; - var self = this; + const hrefParts = this.extractUrlParts(filename, window.location.href); + const href = hrefParts.url; + const self = this; - return new Promise(function(resolve, reject) { + return new Promise((resolve, reject) => { if (options.useFileCache && fileCache[href]) { try { - var lessText = fileCache[href]; + const lessText = fileCache[href]; return resolve({ contents: lessText, filename: href, webInfo: { lastModified: new Date() }}); } catch (e) { - return reject({ filename: href, message: 'Error loading file ' + href + ' error was ' + e.message }); + return reject({ filename: href, message: `Error loading file ${href} error was ${e.message}` }); } } @@ -100,12 +98,16 @@ module.exports = function(options, logger) { fileCache[href] = data; // Use remote copy (re-parse) - resolve({ contents: data, filename: href, webInfo: { lastModified: lastModified }}); + resolve({ contents: data, filename: href, webInfo: { lastModified }}); }, function doXHRError(status, url) { - reject({ type: 'File', message: '\'' + url + '\' wasn\'t found (' + status + ')', href: href }); + reject({ type: 'File', message: `'${url}' wasn't found (${status})`, href }); }); }); - }; + } +} +export default (opts, log) => { + options = opts; + logger = log; return FileManager; -}; +} diff --git a/lib/less-browser/image-size.js b/lib/less-browser/image-size.js index 439336c19..8e3caccdf 100644 --- a/lib/less-browser/image-size.js +++ b/lib/less-browser/image-size.js @@ -1,7 +1,7 @@ -module.exports = function() { - var functionRegistry = require('./../less/functions/function-registry'); +import functionRegistry from './../less/functions/function-registry'; +export default () => { function imageSize() { throw { type: 'Runtime', @@ -9,7 +9,7 @@ module.exports = function() { }; } - var imageFunctions = { + const imageFunctions = { 'image-size': function(filePathNode) { imageSize(this, filePathNode); return -1; diff --git a/lib/less-browser/index.js b/lib/less-browser/index.js index 654072c8b..6ec83bb50 100644 --- a/lib/less-browser/index.js +++ b/lib/less-browser/index.js @@ -2,36 +2,43 @@ // index.js // Should expose the additional browser functions on to the less object // -var addDataAttr = require('./utils').addDataAttr, - browser = require('./browser'); +import {addDataAttr} from './utils'; +import lessRoot from '../less'; +import browser from './browser'; +import FM from './file-manager'; +import PluginLoader from './plugin-loader'; +import LogListener from './log-listener'; +import ErrorReporting from './error-reporting'; +import Cache from './cache'; +import ImageSize from './image-size'; + +export default (window, options) => { + const document = window.document; + const less = lessRoot(); -module.exports = function(window, options) { - var document = window.document; - var less = require('../less')(); - less.options = options; - var environment = less.environment, - FileManager = require('./file-manager')(options, less.logger), - fileManager = new FileManager(); + const environment = less.environment; + const FileManager = FM(options, less.logger); + const fileManager = new FileManager(); environment.addFileManager(fileManager); less.FileManager = FileManager; - less.PluginLoader = require('./plugin-loader'); + less.PluginLoader = PluginLoader; - require('./log-listener')(less, options); - var errors = require('./error-reporting')(window, less, options); - var cache = less.cache = options.cache || require('./cache')(window, options, less.logger); - require('./image-size')(less.environment); + LogListener(less, options); + const errors = ErrorReporting(window, less, options); + const cache = less.cache = options.cache || Cache(window, options, less.logger); + ImageSize(less.environment); // Setup user functions - Deprecate? if (options.functions) { less.functions.functionRegistry.addMultiple(options.functions); } - var typePattern = /^text\/(x-)?less$/; + const typePattern = /^text\/(x-)?less$/; function clone(obj) { - var cloned = {}; - for (var prop in obj) { + const cloned = {}; + for (const prop in obj) { if (obj.hasOwnProperty(prop)) { cloned[prop] = obj[prop]; } @@ -41,47 +48,47 @@ module.exports = function(window, options) { // only really needed for phantom function bind(func, thisArg) { - var curryArgs = Array.prototype.slice.call(arguments, 2); + const curryArgs = Array.prototype.slice.call(arguments, 2); return function() { - var args = curryArgs.concat(Array.prototype.slice.call(arguments, 0)); + const args = curryArgs.concat(Array.prototype.slice.call(arguments, 0)); return func.apply(thisArg, args); }; } function loadStyles(modifyVars) { - var styles = document.getElementsByTagName('style'), - style; + const styles = document.getElementsByTagName('style'); + let style; - for (var i = 0; i < styles.length; i++) { + for (let i = 0; i < styles.length; i++) { style = styles[i]; if (style.type.match(typePattern)) { - var instanceOptions = clone(options); + const instanceOptions = clone(options); instanceOptions.modifyVars = modifyVars; - var lessText = style.innerHTML || ''; + const lessText = style.innerHTML || ''; instanceOptions.filename = document.location.href.replace(/#.*$/, ''); /* jshint loopfunc:true */ // use closure to store current style less.render(lessText, instanceOptions, - bind(function(style, e, result) { - if (e) { - errors.add(e, 'inline'); + bind((style, e, result) => { + if (e) { + errors.add(e, 'inline'); + } else { + style.type = 'text/css'; + if (style.styleSheet) { + style.styleSheet.cssText = result.css; } else { - style.type = 'text/css'; - if (style.styleSheet) { - style.styleSheet.cssText = result.css; - } else { - style.innerHTML = result.css; - } + style.innerHTML = result.css; } - }, null, style)); + } + }, null, style)); } } } function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) { - var instanceOptions = clone(options); + const instanceOptions = clone(options); addDataAttr(instanceOptions, sheet); instanceOptions.mime = sheet.type; @@ -90,12 +97,11 @@ module.exports = function(window, options) { } function loadInitialFileCallback(loadedFile) { + const data = loadedFile.contents; + const path = loadedFile.filename; + const webInfo = loadedFile.webInfo; - var data = loadedFile.contents, - path = loadedFile.filename, - webInfo = loadedFile.webInfo; - - var newFileInfo = { + const newFileInfo = { currentDirectory: fileManager.getPath(path), filename: path, rootFilename: path, @@ -108,7 +114,7 @@ module.exports = function(window, options) { if (webInfo) { webInfo.remaining = remaining; - var css = cache.getCSS(path, webInfo, instanceOptions.modifyVars); + const css = cache.getCSS(path, webInfo, instanceOptions.modifyVars); if (!reload && css) { webInfo.local = true; callback(null, css, data, sheet, webInfo, path); @@ -121,7 +127,7 @@ module.exports = function(window, options) { errors.remove(path); instanceOptions.rootFileInfo = newFileInfo; - less.render(data, instanceOptions, function(e, result) { + less.render(data, instanceOptions, (e, result) => { if (e) { e.href = path; callback(e); @@ -133,9 +139,9 @@ module.exports = function(window, options) { } fileManager.loadFile(sheet.href, null, instanceOptions, environment) - .then(function(loadedFile) { + .then(loadedFile => { loadInitialFileCallback(loadedFile); - }).catch(function(err) { + }).catch(err => { console.log(err); callback(err); }); @@ -143,17 +149,17 @@ module.exports = function(window, options) { } function loadStyleSheets(callback, reload, modifyVars) { - for (var i = 0; i < less.sheets.length; i++) { + for (let i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars); } } function initRunningMode() { if (less.env === 'development') { - less.watchTimer = setInterval(function () { + less.watchTimer = setInterval(() => { if (less.watchMode) { fileManager.clearFileCache(); - loadStyleSheets(function (e, css, _, sheet, webInfo) { + loadStyleSheets((e, css, _, sheet, webInfo) => { if (e) { errors.add(e, e.href || sheet.href); } else if (css) { @@ -183,11 +189,11 @@ module.exports = function(window, options) { // Synchronously get all tags with the 'rel' attribute set to // "stylesheet/less". // - less.registerStylesheetsImmediately = function() { - var links = document.getElementsByTagName('link'); + less.registerStylesheetsImmediately = () => { + const links = document.getElementsByTagName('link'); less.sheets = []; - for (var i = 0; i < links.length; i++) { + for (let i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); @@ -199,27 +205,26 @@ module.exports = function(window, options) { // Asynchronously get all tags with the 'rel' attribute set to // "stylesheet/less", returning a Promise. // - less.registerStylesheets = function() { - return new Promise(function(resolve, reject) { - less.registerStylesheetsImmediately(); - resolve(); - }); - }; + less.registerStylesheets = () => new Promise((resolve, reject) => { + less.registerStylesheetsImmediately(); + resolve(); + }); // // With this function, it's possible to alter variables and re-render // CSS without reloading less-files // - less.modifyVars = function(record) { - return less.refresh(true, record, false); - }; + less.modifyVars = record => less.refresh(true, record, false); - less.refresh = function (reload, modifyVars, clearFileCache) { + less.refresh = (reload, modifyVars, clearFileCache) => { if ((reload || clearFileCache) && clearFileCache !== false) { fileManager.clearFileCache(); } - return new Promise(function (resolve, reject) { - var startTime, endTime, totalMilliseconds, remainingSheets; + return new Promise((resolve, reject) => { + let startTime; + let endTime; + let totalMilliseconds; + let remainingSheets; startTime = endTime = new Date(); // Set counter for remaining unprocessed sheets @@ -231,27 +236,27 @@ module.exports = function(window, options) { totalMilliseconds = endTime - startTime; less.logger.info('Less has finished and no sheets were loaded.'); resolve({ - startTime: startTime, - endTime: endTime, - totalMilliseconds: totalMilliseconds, + startTime, + endTime, + totalMilliseconds, sheets: less.sheets.length }); } else { // Relies on less.sheets array, callback seems to be guaranteed to be called for every element of the array - loadStyleSheets(function (e, css, _, sheet, webInfo) { + loadStyleSheets((e, css, _, sheet, webInfo) => { if (e) { errors.add(e, e.href || sheet.href); reject(e); return; } if (webInfo.local) { - less.logger.info('Loading ' + sheet.href + ' from cache.'); + less.logger.info(`Loading ${sheet.href} from cache.`); } else { - less.logger.info('Rendered ' + sheet.href + ' successfully.'); + less.logger.info(`Rendered ${sheet.href} successfully.`); } browser.createCSS(window.document, css, sheet); - less.logger.info('CSS for ' + sheet.href + ' generated in ' + (new Date() - endTime) + 'ms'); + less.logger.info(`CSS for ${sheet.href} generated in ${new Date() - endTime}ms`); // Count completed sheet remainingSheets--; @@ -259,11 +264,11 @@ module.exports = function(window, options) { // Check if the last remaining sheet was processed and then call the promise if (remainingSheets === 0) { totalMilliseconds = new Date() - startTime; - less.logger.info('Less has finished. CSS generated in ' + totalMilliseconds + 'ms'); + less.logger.info(`Less has finished. CSS generated in ${totalMilliseconds}ms`); resolve({ - startTime: startTime, - endTime: endTime, - totalMilliseconds: totalMilliseconds, + startTime, + endTime, + totalMilliseconds, sheets: less.sheets.length }); } diff --git a/lib/less-browser/log-listener.js b/lib/less-browser/log-listener.js index a145392a5..553da8951 100644 --- a/lib/less-browser/log-listener.js +++ b/lib/less-browser/log-listener.js @@ -1,9 +1,8 @@ -module.exports = function(less, options) { - - var logLevel_debug = 4, - logLevel_info = 3, - logLevel_warn = 2, - logLevel_error = 1; +export default (less, options) => { + const logLevel_debug = 4; + const logLevel_info = 3; + const logLevel_warn = 2; + const logLevel_error = 1; // The amount of logging in the javascript console. // 3 - Debug, information and errors @@ -37,7 +36,7 @@ module.exports = function(less, options) { } }]; } - for (var i = 0; i < options.loggers.length; i++) { + for (let i = 0; i < options.loggers.length; i++) { less.logger.addListener(options.loggers[i]); } }; diff --git a/lib/less-browser/plugin-loader.js b/lib/less-browser/plugin-loader.js index 3fabd5a05..2ae1d7e75 100644 --- a/lib/less-browser/plugin-loader.js +++ b/lib/less-browser/plugin-loader.js @@ -1,24 +1,26 @@ // TODO: Add tests for browser @plugin /* global window */ -var AbstractPluginLoader = require('../less/environment/abstract-plugin-loader.js'); +import AbstractPluginLoader from '../less/environment/abstract-plugin-loader.js'; /** * Browser Plugin Loader */ -var PluginLoader = function(less) { - this.less = less; - // Should we shim this.require for browser? Probably not? -}; +class PluginLoader extends AbstractPluginLoader { + constructor(less) { + super(); -PluginLoader.prototype = new AbstractPluginLoader(); + this.less = less; + // Should we shim this.require for browser? Probably not? + } -PluginLoader.prototype.loadPlugin = function(filename, basePath, context, environment, fileManager) { - return new Promise(function(fulfill, reject) { - fileManager.loadFile(filename, basePath, context, environment) - .then(fulfill).catch(reject); - }); -}; + loadPlugin(filename, basePath, context, environment, fileManager) { + return new Promise((fulfill, reject) => { + fileManager.loadFile(filename, basePath, context, environment) + .then(fulfill).catch(reject); + }); + } +} -module.exports = PluginLoader; +export default PluginLoader; diff --git a/lib/less-browser/utils.js b/lib/less-browser/utils.js index 80e73233b..2a9915cc3 100644 --- a/lib/less-browser/utils.js +++ b/lib/less-browser/utils.js @@ -1,24 +1,24 @@ -module.exports = { - extractId: function(href) { - return href.replace(/^[a-z-]+:\/+?[^\/]+/, '') // Remove protocol & domain - .replace(/[\?\&]livereload=\w+/, '') // Remove LiveReload cachebuster - .replace(/^\//, '') // Remove root / - .replace(/\.[a-zA-Z]+$/, '') // Remove simple extension - .replace(/[^\.\w-]+/g, '-') // Replace illegal characters - .replace(/\./g, ':'); // Replace dots with colons(for valid id) - }, - addDataAttr: function(options, tag) { - for (var opt in tag.dataset) { - if (tag.dataset.hasOwnProperty(opt)) { - if (opt === 'env' || opt === 'dumpLineNumbers' || opt === 'rootpath' || opt === 'errorReporting') { - options[opt] = tag.dataset[opt]; - } else { - try { - options[opt] = JSON.parse(tag.dataset[opt]); - } - catch (_) {} + +export function extractId(href) { + return href.replace(/^[a-z-]+:\/+?[^\/]+/, '') // Remove protocol & domain + .replace(/[\?\&]livereload=\w+/, '') // Remove LiveReload cachebuster + .replace(/^\//, '') // Remove root / + .replace(/\.[a-zA-Z]+$/, '') // Remove simple extension + .replace(/[^\.\w-]+/g, '-') // Replace illegal characters + .replace(/\./g, ':'); // Replace dots with colons(for valid id) +} + +export function addDataAttr(options, tag) { + for (const opt in tag.dataset) { + if (tag.dataset.hasOwnProperty(opt)) { + if (opt === 'env' || opt === 'dumpLineNumbers' || opt === 'rootpath' || opt === 'errorReporting') { + options[opt] = tag.dataset[opt]; + } else { + try { + options[opt] = JSON.parse(tag.dataset[opt]); } + catch (_) {} } } } -}; +} diff --git a/lib/less-node/environment.js b/lib/less-node/environment.js index c3eae6a05..a9b790c9b 100644 --- a/lib/less-node/environment.js +++ b/lib/less-node/environment.js @@ -1,7 +1,7 @@ -module.exports = { +export default { encodeBase64: function encodeBase64(str) { // Avoid Buffer constructor on newer versions of Node.js. - var buffer = (Buffer.from ? Buffer.from(str) : (new Buffer(str))); + const buffer = (Buffer.from ? Buffer.from(str) : (new Buffer(str))); return buffer.toString('base64'); }, mimeLookup: function (filename) { diff --git a/lib/less-node/file-manager.js b/lib/less-node/file-manager.js index 7bec25d04..886b06c93 100644 --- a/lib/less-node/file-manager.js +++ b/lib/less-node/file-manager.js @@ -1,176 +1,177 @@ -var path = require('path'), - fs = require('./fs'), - PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise, - AbstractFileManager = require('../less/environment/abstract-file-manager.js'); +import path from 'path'; +import fs from './fs'; +import AbstractFileManager from '../less/environment/abstract-file-manager.js'; -var FileManager = function() { - this.contents = {}; -}; +class FileManager extends AbstractFileManager { + constructor() { + super(); -FileManager.prototype = new AbstractFileManager(); + this.contents = {}; + } -FileManager.prototype.supports = function(filename, currentDirectory, options, environment) { - return true; -}; -FileManager.prototype.supportsSync = function(filename, currentDirectory, options, environment) { - return true; -}; + supports(filename, currentDirectory, options, environment) { + return true; + } -FileManager.prototype.loadFile = function(filename, currentDirectory, options, environment, callback) { + supportsSync(filename, currentDirectory, options, environment) { + return true; + } - var fullFilename, - isAbsoluteFilename = this.isPathAbsolute(filename), - filenamesTried = [], - self = this, - prefix = filename.slice(0, 1), - explicit = prefix === '.' || prefix === '/', - result = null, - isNodeModule = false, - npmPrefix = 'npm://'; + loadFile(filename, currentDirectory, options, environment, callback) { + let fullFilename; + const isAbsoluteFilename = this.isPathAbsolute(filename); + const filenamesTried = []; + const self = this; + const prefix = filename.slice(0, 1); + const explicit = prefix === '.' || prefix === '/'; + let result = null; + let isNodeModule = false; + const npmPrefix = 'npm://'; - options = options || {}; + options = options || {}; - var paths = isAbsoluteFilename ? [''] : [currentDirectory]; + const paths = isAbsoluteFilename ? [''] : [currentDirectory]; - if (options.paths) { paths.push.apply(paths, options.paths); } + if (options.paths) { paths.push(...options.paths); } - if (!isAbsoluteFilename && paths.indexOf('.') === -1) { paths.push('.'); } + if (!isAbsoluteFilename && paths.indexOf('.') === -1) { paths.push('.'); } - var prefixes = options.prefixes || ['']; - var fileParts = this.extractUrlParts(filename); + const prefixes = options.prefixes || ['']; + const fileParts = this.extractUrlParts(filename); - if (options.syncImport) { - getFileData(returnData, returnData); - if (callback) { - callback(result.error, result); + if (options.syncImport) { + getFileData(returnData, returnData); + if (callback) { + callback(result.error, result); + } + else { + return result; + } } else { - return result; + // promise is guaranteed to be asyncronous + // which helps as it allows the file handle + // to be closed before it continues with the next file + return new Promise(getFileData); } - } - else { - // promise is guaranteed to be asyncronous - // which helps as it allows the file handle - // to be closed before it continues with the next file - return new PromiseConstructor(getFileData); - } - function returnData(data) { - if (!data.filename) { - result = { error: data }; - } - else { - result = data; + function returnData(data) { + if (!data.filename) { + result = { error: data }; + } + else { + result = data; + } } - } - function getFileData(fulfill, reject) { - (function tryPathIndex(i) { - if (i < paths.length) { - (function tryPrefix(j) { - if (j < prefixes.length) { - isNodeModule = false; - fullFilename = fileParts.rawPath + prefixes[j] + fileParts.filename; + function getFileData(fulfill, reject) { + (function tryPathIndex(i) { + if (i < paths.length) { + (function tryPrefix(j) { + if (j < prefixes.length) { + isNodeModule = false; + fullFilename = fileParts.rawPath + prefixes[j] + fileParts.filename; - if (paths[i]) { - fullFilename = path.join(paths[i], fullFilename); - } - - if (!explicit && paths[i] === '.') { - try { - fullFilename = require.resolve(fullFilename); - isNodeModule = true; - } - catch (e) { - filenamesTried.push(npmPrefix + fullFilename); - tryWithExtension(); + if (paths[i]) { + fullFilename = path.join(paths[i], fullFilename); } - } - else { - tryWithExtension(); - } - function tryWithExtension() { - var extFilename = options.ext ? self.tryAppendExtension(fullFilename, options.ext) : fullFilename; - - if (extFilename !== fullFilename && !explicit && paths[i] === '.') { + if (!explicit && paths[i] === '.') { try { - fullFilename = require.resolve(extFilename); + fullFilename = require.resolve(fullFilename); isNodeModule = true; } catch (e) { - filenamesTried.push(npmPrefix + extFilename); - fullFilename = extFilename; + filenamesTried.push(npmPrefix + fullFilename); + tryWithExtension(); } } else { - fullFilename = extFilename; + tryWithExtension(); } - } - var modified = false; + function tryWithExtension() { + const extFilename = options.ext ? self.tryAppendExtension(fullFilename, options.ext) : fullFilename; - if (self.contents[fullFilename]) { - try { - var stat = fs.statSync.apply(this, [fullFilename]); - if (stat.mtime.getTime() === self.contents[fullFilename].mtime.getTime()) { - fulfill({ contents: self.contents[fullFilename].data, filename: fullFilename}); + if (extFilename !== fullFilename && !explicit && paths[i] === '.') { + try { + fullFilename = require.resolve(extFilename); + isNodeModule = true; + } + catch (e) { + filenamesTried.push(npmPrefix + extFilename); + fullFilename = extFilename; + } } else { - modified = true; + fullFilename = extFilename; } } - catch (e) { - modified = true; - } - } - if (modified || !self.contents[fullFilename]) { - var readFileArgs = [fullFilename]; - if (!options.rawBuffer) { - readFileArgs.push('utf-8'); - } - if (options.syncImport) { + + let modified = false; + + if (self.contents[fullFilename]) { try { - var data = fs.readFileSync.apply(this, readFileArgs); var stat = fs.statSync.apply(this, [fullFilename]); - self.contents[fullFilename] = { data: data, mtime: stat.mtime }; - fulfill({ contents: data, filename: fullFilename}); + if (stat.mtime.getTime() === self.contents[fullFilename].mtime.getTime()) { + fulfill({ contents: self.contents[fullFilename].data, filename: fullFilename}); + } + else { + modified = true; + } } catch (e) { - filenamesTried.push(isNodeModule ? npmPrefix + fullFilename : fullFilename); - return tryPrefix(j + 1); + modified = true; } } - else { - readFileArgs.push(function(e, data) { - if (e) { + if (modified || !self.contents[fullFilename]) { + const readFileArgs = [fullFilename]; + if (!options.rawBuffer) { + readFileArgs.push('utf-8'); + } + if (options.syncImport) { + try { + const data = fs.readFileSync.apply(this, readFileArgs); + var stat = fs.statSync.apply(this, [fullFilename]); + self.contents[fullFilename] = { data, mtime: stat.mtime }; + fulfill({ contents: data, filename: fullFilename}); + } + catch (e) { filenamesTried.push(isNodeModule ? npmPrefix + fullFilename : fullFilename); return tryPrefix(j + 1); } - var stat = fs.statSync.apply(this, [fullFilename]); - self.contents[fullFilename] = { data: data, mtime: stat.mtime }; - fulfill({ contents: data, filename: fullFilename}); - }); - fs.readFile.apply(this, readFileArgs); + } + else { + readFileArgs.push(function(e, data) { + if (e) { + filenamesTried.push(isNodeModule ? npmPrefix + fullFilename : fullFilename); + return tryPrefix(j + 1); + } + const stat = fs.statSync.apply(this, [fullFilename]); + self.contents[fullFilename] = { data, mtime: stat.mtime }; + fulfill({ contents: data, filename: fullFilename}); + }); + fs.readFile.apply(this, readFileArgs); + } + } } - - } - else { - tryPathIndex(i + 1); - } - })(0); - } else { - reject({ type: 'File', message: '\'' + filename + '\' wasn\'t found. Tried - ' + filenamesTried.join(',') }); - } - }(0)); + else { + tryPathIndex(i + 1); + } + })(0); + } else { + reject({ type: 'File', message: `'${filename}' wasn't found. Tried - ${filenamesTried.join(',')}` }); + } + }(0)); + } } -}; -FileManager.prototype.loadFileSync = function(filename, currentDirectory, options, environment) { - options.syncImport = true; - return this.loadFile(filename, currentDirectory, options, environment); -}; + loadFileSync(filename, currentDirectory, options, environment) { + options.syncImport = true; + return this.loadFile(filename, currentDirectory, options, environment); + } +} -module.exports = FileManager; +export default FileManager; diff --git a/lib/less-node/fs.js b/lib/less-node/fs.js index 89986b627..be71f8f2e 100644 --- a/lib/less-node/fs.js +++ b/lib/less-node/fs.js @@ -1,4 +1,4 @@ -var fs; +let fs; try { fs = require('graceful-fs'); @@ -7,4 +7,4 @@ catch (e) { fs = require('fs'); } -module.exports = fs; +export default fs; diff --git a/lib/less-node/image-size.js b/lib/less-node/image-size.js index f80a4546b..18123f317 100644 --- a/lib/less-node/image-size.js +++ b/lib/less-node/image-size.js @@ -1,54 +1,55 @@ -module.exports = function(environment) { - var Dimension = require('../less/tree/dimension'), - Expression = require('../less/tree/expression'), - functionRegistry = require('./../less/functions/function-registry'); +import Dimension from '../less/tree/dimension'; +import Expression from '../less/tree/expression'; +import functionRegistry from './../less/functions/function-registry'; + +export default environment => { function imageSize(functionContext, filePathNode) { - var filePath = filePathNode.value; - var currentFileInfo = functionContext.currentFileInfo; - var currentDirectory = currentFileInfo.rewriteUrls ? - currentFileInfo.currentDirectory : currentFileInfo.entryPath; + let filePath = filePathNode.value; + const currentFileInfo = functionContext.currentFileInfo; + const currentDirectory = currentFileInfo.rewriteUrls ? + currentFileInfo.currentDirectory : currentFileInfo.entryPath; - var fragmentStart = filePath.indexOf('#'); - var fragment = ''; + const fragmentStart = filePath.indexOf('#'); + let fragment = ''; if (fragmentStart !== -1) { fragment = filePath.slice(fragmentStart); filePath = filePath.slice(0, fragmentStart); } - var fileManager = environment.getFileManager(filePath, currentDirectory, functionContext.context, environment, true); + const fileManager = environment.getFileManager(filePath, currentDirectory, functionContext.context, environment, true); if (!fileManager) { throw { type: 'File', - message: 'Can not set up FileManager for ' + filePathNode + message: `Can not set up FileManager for ${filePathNode}` }; } - var fileSync = fileManager.loadFileSync(filePath, currentDirectory, functionContext.context, environment); + const fileSync = fileManager.loadFileSync(filePath, currentDirectory, functionContext.context, environment); if (fileSync.error) { throw fileSync.error; } - var sizeOf = require('image-size'); + const sizeOf = require('image-size'); return sizeOf(fileSync.filename); } - var imageFunctions = { + const imageFunctions = { 'image-size': function(filePathNode) { - var size = imageSize(this, filePathNode); + const size = imageSize(this, filePathNode); return new Expression([ new Dimension(size.width, 'px'), new Dimension(size.height, 'px') ]); }, 'image-width': function(filePathNode) { - var size = imageSize(this, filePathNode); + const size = imageSize(this, filePathNode); return new Dimension(size.width, 'px'); }, 'image-height': function(filePathNode) { - var size = imageSize(this, filePathNode); + const size = imageSize(this, filePathNode); return new Dimension(size.height, 'px'); } }; diff --git a/lib/less-node/index.js b/lib/less-node/index.js index d485aa9c2..ae08a8952 100644 --- a/lib/less-node/index.js +++ b/lib/less-node/index.js @@ -1,23 +1,27 @@ -var environment = require('./environment'), - FileManager = require('./file-manager'), - UrlFileManager = require('./url-file-manager'), - createFromEnvironment = require('../less'), - less = createFromEnvironment(environment, [new FileManager(), new UrlFileManager()]), - lesscHelper = require('./lessc-helper'), - path = require('path'); +import environment from './environment'; +import FileManager from './file-manager'; +import UrlFileManager from './url-file-manager'; +import createFromEnvironment from '../less'; +import lesscHelper from './lessc-helper'; +import PluginLoader from './plugin-loader'; +import fs from './fs'; +import defaultOptions from '../less/default-options'; +import imageSize from './image-size'; + +const less = createFromEnvironment(environment, [new FileManager(), new UrlFileManager()]); // allow people to create less with their own environment less.createFromEnvironment = createFromEnvironment; less.lesscHelper = lesscHelper; -less.PluginLoader = require('./plugin-loader'); -less.fs = require('./fs'); +less.PluginLoader = PluginLoader; +less.fs = fs; less.FileManager = FileManager; less.UrlFileManager = UrlFileManager; // Set up options -less.options = require('../less/default-options')(); +less.options = defaultOptions(); // provide image-size functionality -require('./image-size')(less.environment); +imageSize(less.environment); -module.exports = less; +export default less; diff --git a/lib/less-node/lessc-helper.js b/lib/less-node/lessc-helper.js index 4d33733e4..c2c12d1c2 100644 --- a/lib/less-node/lessc-helper.js +++ b/lib/less-node/lessc-helper.js @@ -1,11 +1,11 @@ // lessc_helper.js // // helper functions for lessc -var lessc_helper = { +const lessc_helper = { // Stylize a string stylize : function(str, style) { - var styles = { + const styles = { 'reset' : [0, 0], 'bold' : [1, 22], 'inverse' : [7, 27], @@ -15,8 +15,7 @@ var lessc_helper = { 'red' : [31, 39], 'grey' : [90, 39] }; - return '\x1b[' + styles[style][0] + 'm' + str + - '\x1b[' + styles[style][1] + 'm'; + return `\x1b[${styles[style][0]}m${str}\x1b[${styles[style][1]}m`; }, // Print command line options @@ -87,4 +86,4 @@ var lessc_helper = { }; // Exports helper functions -for (var h in lessc_helper) { if (lessc_helper.hasOwnProperty(h)) { exports[h] = lessc_helper[h]; }} +for (const h in lessc_helper) { if (lessc_helper.hasOwnProperty(h)) { exports[h] = lessc_helper[h]; }} diff --git a/lib/less-node/plugin-loader.js b/lib/less-node/plugin-loader.js index 8e6f4fbfc..8bdcb42ef 100644 --- a/lib/less-node/plugin-loader.js +++ b/lib/less-node/plugin-loader.js @@ -1,52 +1,53 @@ -var path = require('path'), - PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise, - AbstractPluginLoader = require('../less/environment/abstract-plugin-loader.js'); +import path from 'path'; +import AbstractPluginLoader from '../less/environment/abstract-plugin-loader.js'; /** * Node Plugin Loader */ -var PluginLoader = function(less) { - this.less = less; - this.require = function(prefix) { - prefix = path.dirname(prefix); - return function(id) { - var str = id.substr(0, 2); - if (str === '..' || str === './') { - return require(path.join(prefix, id)); - } - else { - return require(id); - } - }; - }; -}; - -PluginLoader.prototype = new AbstractPluginLoader(); +class PluginLoader extends AbstractPluginLoader { + constructor(less) { + super(); -PluginLoader.prototype.loadPlugin = function(filename, basePath, context, environment, fileManager) { - var prefix = filename.slice(0, 1); - var explicit = prefix === '.' || prefix === '/' || filename.slice(-3).toLowerCase() === '.js'; - if (!explicit) { - context.prefixes = ['less-plugin-', '']; + this.less = less; + this.require = prefix => { + prefix = path.dirname(prefix); + return id => { + const str = id.substr(0, 2); + if (str === '..' || str === './') { + return require(path.join(prefix, id)); + } + else { + return require(id); + } + }; + }; } - return new PromiseConstructor(function(fulfill, reject) { - fileManager.loadFile(filename, basePath, context, environment).then( - function(data) { - try { - fulfill(data); - } - catch (e) { - console.log(e); - reject(e); + loadPlugin(filename, basePath, context, environment, fileManager) { + const prefix = filename.slice(0, 1); + const explicit = prefix === '.' || prefix === '/' || filename.slice(-3).toLowerCase() === '.js'; + if (!explicit) { + context.prefixes = ['less-plugin-', '']; + } + + return new Promise((fulfill, reject) => { + fileManager.loadFile(filename, basePath, context, environment).then( + data => { + try { + fulfill(data); + } + catch (e) { + console.log(e); + reject(e); + } } - } - ).catch(function(err) { - reject(err); + ).catch(err => { + reject(err); + }); }); - }); -}; + } +} -module.exports = PluginLoader; +export default PluginLoader; diff --git a/lib/less-node/url-file-manager.js b/lib/less-node/url-file-manager.js index a9dbb1c47..b956f05b0 100644 --- a/lib/less-node/url-file-manager.js +++ b/lib/less-node/url-file-manager.js @@ -1,56 +1,49 @@ -var isUrlRe = /^(?:https?:)?\/\//i, - url = require('url'), - request, - PromiseConstructor, - AbstractFileManager = require('../less/environment/abstract-file-manager.js'), - logger = require('../less/logger'); - -var UrlFileManager = function() { -}; - -UrlFileManager.prototype = new AbstractFileManager(); - -UrlFileManager.prototype.supports = function(filename, currentDirectory, options, environment) { - return isUrlRe.test( filename ) || isUrlRe.test(currentDirectory); -}; - -UrlFileManager.prototype.loadFile = function(filename, currentDirectory, options, environment) { - if (!PromiseConstructor) { - PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise; +const isUrlRe = /^(?:https?:)?\/\//i; +import url from 'url'; +let request; +import AbstractFileManager from '../less/environment/abstract-file-manager.js'; +import logger from '../less/logger'; + +class UrlFileManager extends AbstractFileManager { + supports(filename, currentDirectory, options, environment) { + return isUrlRe.test( filename ) || isUrlRe.test(currentDirectory); } - return new PromiseConstructor(function(fulfill, reject) { - if (request === undefined) { - try { request = require('request'); } - catch (e) { request = null; } - } - if (!request) { - reject({ type: 'File', message: 'optional dependency \'request\' required to import over http(s)\n' }); - return; - } - - var urlStr = isUrlRe.test( filename ) ? filename : url.resolve(currentDirectory, filename), - urlObj = url.parse(urlStr); - - if (!urlObj.protocol) { - urlObj.protocol = 'http'; - urlStr = urlObj.format(); - } - request.get({uri: urlStr, strictSSL: !options.insecure }, function (error, res, body) { - if (error) { - reject({ type: 'File', message: 'resource \'' + urlStr + '\' gave this Error:\n ' + error + '\n' }); - return; + loadFile(filename, currentDirectory, options, environment) { + return new Promise((fulfill, reject) => { + if (request === undefined) { + try { request = require('request'); } + catch (e) { request = null; } } - if (res && res.statusCode === 404) { - reject({ type: 'File', message: 'resource \'' + urlStr + '\' was not found\n' }); + if (!request) { + reject({ type: 'File', message: 'optional dependency \'request\' required to import over http(s)\n' }); return; } - if (!body) { - logger.warn('Warning: Empty body (HTTP ' + res.statusCode + ') returned by "' + urlStr + '"'); + + let urlStr = isUrlRe.test( filename ) ? filename : url.resolve(currentDirectory, filename); + const urlObj = url.parse(urlStr); + + if (!urlObj.protocol) { + urlObj.protocol = 'http'; + urlStr = urlObj.format(); } - fulfill({ contents: body, filename: urlStr }); + + request.get({uri: urlStr, strictSSL: !options.insecure }, (error, res, body) => { + if (error) { + reject({ type: 'File', message: `resource '${urlStr}' gave this Error:\n ${error}\n` }); + return; + } + if (res && res.statusCode === 404) { + reject({ type: 'File', message: `resource '${urlStr}' was not found\n` }); + return; + } + if (!body) { + logger.warn(`Warning: Empty body (HTTP ${res.statusCode}) returned by "${urlStr}"`); + } + fulfill({ contents: body, filename: urlStr }); + }); }); - }); -}; + } +} -module.exports = UrlFileManager; +export default UrlFileManager; diff --git a/lib/less/constants.js b/lib/less/constants.js index ac20cc7a6..3c57c7ec6 100644 --- a/lib/less/constants.js +++ b/lib/less/constants.js @@ -1,13 +1,13 @@ -module.exports = { - Math: { - ALWAYS: 0, - PARENS_DIVISION: 1, - PARENS: 2, - STRICT_LEGACY: 3 - }, - RewriteUrls: { - OFF: 0, - LOCAL: 1, - ALL: 2 - } + +export const Math = { + ALWAYS: 0, + PARENS_DIVISION: 1, + PARENS: 2, + STRICT_LEGACY: 3 +}; + +export const RewriteUrls = { + OFF: 0, + LOCAL: 1, + ALL: 2 }; \ No newline at end of file diff --git a/lib/less/contexts.js b/lib/less/contexts.js index 1f87f1ee1..829760a6e 100644 --- a/lib/less/contexts.js +++ b/lib/less/contexts.js @@ -1,11 +1,11 @@ -var contexts = {}; -module.exports = contexts; -var Constants = require('./constants'); +const contexts = {}; +export default contexts; +import * as Constants from './constants'; -var copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) { +const copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) { if (!original) { return; } - for (var i = 0; i < propertiesToCopy.length; i++) { + for (let i = 0; i < propertiesToCopy.length; i++) { if (original.hasOwnProperty(propertiesToCopy[i])) { destination[propertiesToCopy[i]] = original[propertiesToCopy[i]]; } @@ -15,7 +15,7 @@ var copyFromOriginal = function copyFromOriginal(original, destination, properti /* parse is used whilst parsing */ -var parseCopyProperties = [ +const parseCopyProperties = [ // options 'paths', // option - unmodified - paths to search for imports on 'rewriteUrls', // option - whether to adjust URL's to be relative @@ -30,7 +30,7 @@ var parseCopyProperties = [ 'useFileCache', // browser only - whether to use the per file session cache // context 'processImports', // option & context - whether to process imports. if false then imports will not be imported. - // Used by the import manager to stop multiple import visitors being created. + // Used by the import manager to stop multiple import visitors being created. 'pluginManager' // Used as the plugin manager for the session ]; @@ -40,10 +40,9 @@ contexts.Parse = function(options) { if (typeof this.paths === 'string') { this.paths = [this.paths]; } }; -var evalCopyProperties = [ +const evalCopyProperties = [ 'paths', // additional include paths 'compress', // whether to compress - 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri) 'math', // whether math has to be within parenthesis 'strictUnits', // whether units need to evaluate correctly 'sourceMap', // whether to output a source map @@ -55,112 +54,111 @@ var evalCopyProperties = [ 'rewriteUrls' // option - whether to adjust URL's to be relative ]; -contexts.Eval = function(options, frames) { - copyFromOriginal(options, this, evalCopyProperties); +function isPathRelative(path) { + return !/^(?:[a-z-]+:|\/|#)/i.test(path); +} - if (typeof this.paths === 'string') { this.paths = [this.paths]; } +function isPathLocalRelative(path) { + return path.charAt(0) === '.'; +} - this.frames = frames || []; - this.importantScope = this.importantScope || []; -}; +contexts.Eval = class { + constructor(options, frames) { + copyFromOriginal(options, this, evalCopyProperties); -contexts.Eval.prototype.enterCalc = function () { - if (!this.calcStack) { - this.calcStack = []; - } - this.calcStack.push(true); - this.inCalc = true; -}; + if (typeof this.paths === 'string') { this.paths = [this.paths]; } -contexts.Eval.prototype.exitCalc = function () { - this.calcStack.pop(); - if (!this.calcStack) { + this.frames = frames || []; + this.importantScope = this.importantScope || []; this.inCalc = false; + this.mathOn = true; } -}; -contexts.Eval.prototype.inParenthesis = function () { - if (!this.parensStack) { - this.parensStack = []; + enterCalc() { + if (!this.calcStack) { + this.calcStack = []; + } + this.calcStack.push(true); + this.inCalc = true; } - this.parensStack.push(true); -}; - -contexts.Eval.prototype.outOfParenthesis = function () { - this.parensStack.pop(); -}; -contexts.Eval.prototype.inCalc = false; -contexts.Eval.prototype.mathOn = true; -contexts.Eval.prototype.isMathOn = function (op) { - if (!this.mathOn) { - return false; - } - if (op === '/' && this.math !== Constants.Math.ALWAYS && (!this.parensStack || !this.parensStack.length)) { - return false; - } - if (this.math > Constants.Math.PARENS_DIVISION) { - return this.parensStack && this.parensStack.length; + exitCalc() { + this.calcStack.pop(); + if (!this.calcStack) { + this.inCalc = false; + } } - return true; -}; -contexts.Eval.prototype.pathRequiresRewrite = function (path) { - var isRelative = this.rewriteUrls === Constants.RewriteUrls.LOCAL ? isPathLocalRelative : isPathRelative; + inParenthesis() { + if (!this.parensStack) { + this.parensStack = []; + } + this.parensStack.push(true); + }; - return isRelative(path); -}; + outOfParenthesis() { + this.parensStack.pop(); + }; -contexts.Eval.prototype.rewritePath = function (path, rootpath) { - var newPath; + isMathOn(op) { + if (!this.mathOn) { + return false; + } + if (op === '/' && this.math !== Constants.Math.ALWAYS && (!this.parensStack || !this.parensStack.length)) { + return false; + } + if (this.math > Constants.Math.PARENS_DIVISION) { + return this.parensStack && this.parensStack.length; + } + return true; + } - rootpath = rootpath || ''; - newPath = this.normalizePath(rootpath + path); + pathRequiresRewrite(path) { + const isRelative = this.rewriteUrls === Constants.RewriteUrls.LOCAL ? isPathLocalRelative : isPathRelative; - // If a path was explicit relative and the rootpath was not an absolute path - // we must ensure that the new path is also explicit relative. - if (isPathLocalRelative(path) && - isPathRelative(rootpath) && - isPathLocalRelative(newPath) === false) { - newPath = './' + newPath; + return isRelative(path); } - return newPath; -}; + rewritePath(path, rootpath) { + let newPath; + + rootpath = rootpath || ''; + newPath = this.normalizePath(rootpath + path); -contexts.Eval.prototype.normalizePath = function (path) { - var - segments = path.split('/').reverse(), - segment; - - path = []; - while (segments.length !== 0) { - segment = segments.pop(); - switch ( segment ) { - case '.': - break; - case '..': - if ((path.length === 0) || (path[path.length - 1] === '..')) { - path.push( segment ); - } else { - path.pop(); - } - break; - default: - path.push(segment); - break; + // If a path was explicit relative and the rootpath was not an absolute path + // we must ensure that the new path is also explicit relative. + if (isPathLocalRelative(path) && + isPathRelative(rootpath) && + isPathLocalRelative(newPath) === false) { + newPath = `./${newPath}`; } - } - return path.join('/'); -}; + return newPath; + } -function isPathRelative(path) { - return !/^(?:[a-z-]+:|\/|#)/i.test(path); -} + normalizePath(path) { + const segments = path.split('/').reverse(); + let segment; + + path = []; + while (segments.length !== 0) { + segment = segments.pop(); + switch ( segment ) { + case '.': + break; + case '..': + if ((path.length === 0) || (path[path.length - 1] === '..')) { + path.push( segment ); + } else { + path.pop(); + } + break; + default: + path.push(segment); + break; + } + } -function isPathLocalRelative(path) { - return path.charAt(0) === '.'; + return path.join('/'); + } } - -// todo - do the same for the toCSS ? diff --git a/lib/less/data/colors.js b/lib/less/data/colors.js index af30a6b6a..3bf17a1f1 100644 --- a/lib/less/data/colors.js +++ b/lib/less/data/colors.js @@ -1,4 +1,4 @@ -module.exports = { +export default { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', diff --git a/lib/less/data/index.js b/lib/less/data/index.js index ced7f71e8..1a7d75bc4 100644 --- a/lib/less/data/index.js +++ b/lib/less/data/index.js @@ -1,4 +1,4 @@ -module.exports = { - colors: require('./colors'), - unitConversions: require('./unit-conversions') -}; +import colors from './colors'; +import unitConversions from './unit-conversions'; + +export default { colors, unitConversions }; diff --git a/lib/less/data/unit-conversions.js b/lib/less/data/unit-conversions.js index da292ab24..1c1593e07 100644 --- a/lib/less/data/unit-conversions.js +++ b/lib/less/data/unit-conversions.js @@ -1,4 +1,4 @@ -module.exports = { +export default { length: { 'm': 1, 'cm': 0.01, diff --git a/lib/less/default-options.js b/lib/less/default-options.js index 3ac87d36e..a87b84333 100644 --- a/lib/less/default-options.js +++ b/lib/less/default-options.js @@ -1,73 +1,68 @@ // Export a new default each time -module.exports = function() { - return { - /* Inline Javascript - @plugin still allowed */ - javascriptEnabled: false, +export default () => ({ + /* Inline Javascript - @plugin still allowed */ + javascriptEnabled: false, - /* Outputs a makefile import dependency list to stdout. */ - depends: false, + /* Outputs a makefile import dependency list to stdout. */ + depends: false, - /* (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, + /* (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, - /* Runs the less parser and just reports errors without any output. */ - lint: false, + /* Runs the less parser and just reports errors without any output. */ + lint: false, - /* Sets available include paths. - * If the file in an @import rule does not exist at that exact location, - * less will look for it at the location(s) passed to this option. - * You might use this for instance to specify a path to a library which - * you want to be referenced simply and relatively in the less files. */ - paths: [], + /* Sets available include paths. + * If the file in an @import rule does not exist at that exact location, + * less will look for it at the location(s) passed to this option. + * You might use this for instance to specify a path to a library which + * you want to be referenced simply and relatively in the less files. */ + paths: [], - /* color output in the terminal */ - color: true, + /* color output in the terminal */ + color: true, - /* The strictImports controls whether the compiler will allow an @import inside of either - * @media blocks or (a later addition) other selector blocks. - * See: https://github.com/less/less.js/issues/656 */ - strictImports: false, + /* The strictImports controls whether the compiler will allow an @import inside of either + * @media blocks or (a later addition) other selector blocks. + * See: https://github.com/less/less.js/issues/656 */ + strictImports: false, - /* Allow Imports from Insecure HTTPS Hosts */ - insecure: false, + /* Allow Imports from Insecure HTTPS Hosts */ + insecure: false, - /* Allows you to add a path to every generated import and url in your css. - * This does not affect less import statements that are processed, just ones - * that are left in the output css. */ - rootpath: '', + /* Allows you to add a path to every generated import and url in your css. + * This does not affect less import statements that are processed, just ones + * that are left in the output css. */ + rootpath: '', - /* By default URLs are kept as-is, so if you import a file in a sub-directory - * that references an image, exactly the same URL will be output in the css. - * This option allows you to re-write URL's in imported files so that the - * URL is always relative to the base imported file */ - rewriteUrls: false, + /* By default URLs are kept as-is, so if you import a file in a sub-directory + * that references an image, exactly the same URL will be output in the css. + * This option allows you to re-write URL's in imported files so that the + * URL is always relative to the base imported file */ + rewriteUrls: false, - /* Compatibility with IE8. Used for limiting data-uri length */ - ieCompat: false, // true until 3.0 + /* 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, - /* 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, - /* Without this option, less attempts to guess at the output unit when it does maths. */ - strictUnits: false, + /* Effectively the declaration is put at the top of your base Less file, + * meaning it can be used but it also can be overridden if this variable + * is defined in the file. */ + globalVars: null, - /* Effectively the declaration is put at the top of your base Less file, - * meaning it can be used but it also can be overridden if this variable - * is defined in the file. */ - globalVars: null, + /* As opposed to the global variable option, this puts the declaration at the + * end of your base file, meaning it will override anything defined in your Less file. */ + modifyVars: null, - /* As opposed to the global variable option, this puts the declaration at the - * end of your base file, meaning it will override anything defined in your Less file. */ - modifyVars: null, - - /* This option allows you to specify a argument to go on to every URL. */ - urlArgs: '' - } -} \ No newline at end of file + /* This option allows you to specify a argument to go on to every URL. */ + urlArgs: '' +}); \ No newline at end of file diff --git a/lib/less/environment/abstract-file-manager.js b/lib/less/environment/abstract-file-manager.js index 36428f061..937bb931a 100644 --- a/lib/less/environment/abstract-file-manager.js +++ b/lib/less/environment/abstract-file-manager.js @@ -1,123 +1,127 @@ -var abstractFileManager = function() { -}; - -abstractFileManager.prototype.getPath = function (filename) { - var j = filename.lastIndexOf('?'); - if (j > 0) { - filename = filename.slice(0, j); - } - j = filename.lastIndexOf('/'); - if (j < 0) { - j = filename.lastIndexOf('\\'); - } - if (j < 0) { - return ''; +class AbstractFileManager { + getPath(filename) { + let j = filename.lastIndexOf('?'); + if (j > 0) { + filename = filename.slice(0, j); + } + j = filename.lastIndexOf('/'); + if (j < 0) { + j = filename.lastIndexOf('\\'); + } + if (j < 0) { + return ''; + } + return filename.slice(0, j + 1); } - return filename.slice(0, j + 1); -}; - -abstractFileManager.prototype.tryAppendExtension = function(path, ext) { - return /(\.[a-z]*$)|([\?;].*)$/.test(path) ? path : path + ext; -}; - -abstractFileManager.prototype.tryAppendLessExtension = function(path) { - return this.tryAppendExtension(path, '.less'); -}; - -abstractFileManager.prototype.supportsSync = function() { - return false; -}; - -abstractFileManager.prototype.alwaysMakePathsAbsolute = function() { - return false; -}; - -abstractFileManager.prototype.isPathAbsolute = function(filename) { - return (/^(?:[a-z-]+:|\/|\\|#)/i).test(filename); -}; -// TODO: pull out / replace? -abstractFileManager.prototype.join = function(basePath, laterPath) { - if (!basePath) { - return laterPath; + + tryAppendExtension(path, ext) { + return /(\.[a-z]*$)|([\?;].*)$/.test(path) ? path : path + ext; } - return basePath + laterPath; -}; -abstractFileManager.prototype.pathDiff = function pathDiff(url, baseUrl) { - // diff between two paths to create a relative path + tryAppendLessExtension(path) { + return this.tryAppendExtension(path, '.less'); + }; - 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 -abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, baseUrl) { - // urlParts[1] = protocol://hostname/ OR / - // urlParts[2] = / if path relative to host base - // urlParts[3] = directories - // urlParts[4] = filename - // urlParts[5] = parameters - - var urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i, - urlParts = url.match(urlPartsRegex), - returner = {}, rawDirectories = [], directories = [], i, baseUrlParts; - - if (!urlParts) { - throw new Error('Could not parse sheet href - \'' + url + '\''); - } + supportsSync() { return false; } + + alwaysMakePathsAbsolute() { return false; } - // 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 + '\''); + isPathAbsolute(filename) { + return (/^(?:[a-z-]+:|\/|\\|#)/i).test(filename); + } + // TODO: pull out / replace? + join(basePath, laterPath) { + if (!basePath) { + return laterPath; } - urlParts[1] = urlParts[1] || baseUrlParts[1] || ''; - if (!urlParts[2]) { - urlParts[3] = baseUrlParts[3] + urlParts[3]; + return basePath + laterPath; + }; + + pathDiff(url, baseUrl) { + // diff between two paths to create a relative path + const urlParts = this.extractUrlParts(url); + const baseUrlParts = this.extractUrlParts(baseUrl); + + let i; + let max; + let urlDirectories; + let baseUrlDirectories; + let 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(url, baseUrl) { + // urlParts[1] = protocol://hostname/ OR / + // urlParts[2] = / if path relative to host base + // urlParts[3] = directories + // urlParts[4] = filename + // urlParts[5] = parameters + + const urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i; + + const urlParts = url.match(urlPartsRegex); + const returner = {}; + let rawDirectories = []; + const directories = []; + let i; + let baseUrlParts; + + if (!urlParts) { + throw new Error(`Could not parse sheet href - '${url}'`); } - } - if (urlParts[3]) { - rawDirectories = urlParts[3].replace(/\\/g, '/').split('/'); + // 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]; + } + } - // collapse '..' and skip '.' - for (i = 0; i < rawDirectories.length; i++) { + if (urlParts[3]) { + rawDirectories = urlParts[3].replace(/\\/g, '/').split('/'); - if (rawDirectories[i] === '..') { - directories.pop(); - } - else if (rawDirectories[i] !== '.') { - directories.push(rawDirectories[i]); + // collapse '..' and skip '.' + for (i = 0; i < rawDirectories.length; i++) { + + if (rawDirectories[i] === '..') { + directories.pop(); + } + else if (rawDirectories[i] !== '.') { + directories.push(rawDirectories[i]); + } + } - } - } - returner.hostPart = urlParts[1]; - returner.directories = directories; - returner.rawPath = (urlParts[1] || '') + rawDirectories.join('/'); - returner.path = (urlParts[1] || '') + directories.join('/'); - returner.filename = urlParts[4]; - returner.fileUrl = returner.path + (urlParts[4] || ''); - returner.url = returner.fileUrl + (urlParts[5] || ''); - return returner; -}; - -module.exports = abstractFileManager; + returner.hostPart = urlParts[1]; + returner.directories = directories; + returner.rawPath = (urlParts[1] || '') + rawDirectories.join('/'); + returner.path = (urlParts[1] || '') + directories.join('/'); + returner.filename = urlParts[4]; + returner.fileUrl = returner.path + (urlParts[4] || ''); + returner.url = returner.fileUrl + (urlParts[5] || ''); + return returner; + }; +} + +export default AbstractFileManager; diff --git a/lib/less/environment/abstract-plugin-loader.js b/lib/less/environment/abstract-plugin-loader.js index ba3b6771a..50caeb4bb 100644 --- a/lib/less/environment/abstract-plugin-loader.js +++ b/lib/less/environment/abstract-plugin-loader.js @@ -1,43 +1,105 @@ -var functionRegistry = require('../functions/function-registry'), - LessError = require('../less-error'); +import functionRegistry from '../functions/function-registry'; +import LessError from '../less-error'; -var AbstractPluginLoader = function() { - // Implemented by Node.js plugin loader - this.require = function() { - return null; +class AbstractPluginLoader { + constructor() { + // Implemented by Node.js plugin loader + this.require = () => null } -}; -AbstractPluginLoader.prototype.evalPlugin = function(contents, context, imports, pluginOptions, fileInfo) { + evalPlugin(contents, context, imports, pluginOptions, fileInfo) { + let loader; + let registry; + let pluginObj; + let localModule; + let pluginManager; + let filename; + let result; + + pluginManager = context.pluginManager; - var loader, - registry, - pluginObj, - localModule, - pluginManager, - filename, - result; + if (fileInfo) { + if (typeof fileInfo === 'string') { + filename = fileInfo; + } + else { + filename = fileInfo.filename; + } + } + const shortname = (new this.less.FileManager()).extractUrlParts(filename).filename; - pluginManager = context.pluginManager; + if (filename) { + pluginObj = pluginManager.get(filename); - if (fileInfo) { - if (typeof fileInfo === 'string') { - filename = fileInfo; + if (pluginObj) { + result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); + if (result) { + return result; + } + try { + if (pluginObj.use) { + pluginObj.use.call(this.context, pluginObj); + } + } + catch (e) { + e.message = e.message || 'Error during @plugin call'; + return new LessError(e, imports, filename); + } + return pluginObj; + } } - else { - filename = fileInfo.filename; + localModule = { + exports: {}, + pluginManager, + fileInfo + }; + registry = functionRegistry.create(); + + const registerPlugin = obj => { + pluginObj = obj; + }; + + try { + loader = new Function('module', 'require', 'registerPlugin', 'functions', 'tree', 'less', 'fileInfo', contents); + loader(localModule, this.require(filename), registerPlugin, registry, this.less.tree, this.less, fileInfo); + } + catch (e) { + return new LessError(e, imports, filename); } - } - var shortname = (new this.less.FileManager()).extractUrlParts(filename).filename; - if (filename) { - pluginObj = pluginManager.get(filename); + if (!pluginObj) { + pluginObj = localModule.exports; + } + pluginObj = this.validatePlugin(pluginObj, filename, shortname); + + if (pluginObj instanceof LessError) { + return pluginObj; + } if (pluginObj) { + pluginObj.imports = imports; + pluginObj.filename = filename; + + // For < 3.x (or unspecified minVersion) - setOptions() before install() + if (!pluginObj.minVersion || this.compareVersion('3.0.0', pluginObj.minVersion) < 0) { + result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); + + if (result) { + return result; + } + } + + // Run on first load + pluginManager.addPlugin(pluginObj, fileInfo.filename, registry); + pluginObj.functions = registry.getLocalFunctions(); + + // Need to call setOptions again because the pluginObj might have functions result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); if (result) { return result; } + + // Run every @plugin call try { if (pluginObj.use) { pluginObj.use.call(this.context, pluginObj); @@ -47,143 +109,79 @@ AbstractPluginLoader.prototype.evalPlugin = function(contents, context, imports, e.message = e.message || 'Error during @plugin call'; return new LessError(e, imports, filename); } - return pluginObj; - } - } - localModule = { - exports: {}, - pluginManager: pluginManager, - fileInfo: fileInfo - }; - registry = functionRegistry.create(); - - var registerPlugin = function(obj) { - pluginObj = obj; - }; - - try { - loader = new Function('module', 'require', 'registerPlugin', 'functions', 'tree', 'less', 'fileInfo', contents); - loader(localModule, this.require(filename), registerPlugin, registry, this.less.tree, this.less, fileInfo); - } - catch (e) { - return new LessError(e, imports, filename); - } - if (!pluginObj) { - pluginObj = localModule.exports; - } - pluginObj = this.validatePlugin(pluginObj, filename, shortname); + } + else { + return new LessError({ message: 'Not a valid plugin' }, imports, filename); + } - if (pluginObj instanceof LessError) { return pluginObj; } - if (pluginObj) { - pluginObj.imports = imports; - pluginObj.filename = filename; - - // For < 3.x (or unspecified minVersion) - setOptions() before install() - if (!pluginObj.minVersion || this.compareVersion('3.0.0', pluginObj.minVersion) < 0) { - result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); - - if (result) { - return result; - } - } - - // Run on first load - pluginManager.addPlugin(pluginObj, fileInfo.filename, registry); - pluginObj.functions = registry.getLocalFunctions(); - - // Need to call setOptions again because the pluginObj might have functions - result = this.trySetOptions(pluginObj, filename, shortname, pluginOptions); - if (result) { - return result; + trySetOptions(plugin, filename, name, options) { + if (options && !plugin.setOptions) { + return new LessError({ + message: `Options have been provided but the plugin ${name} does not support any options.` + }); } - - // Run every @plugin call try { - if (pluginObj.use) { - pluginObj.use.call(this.context, pluginObj); - } + plugin.setOptions && plugin.setOptions(options); } catch (e) { - e.message = e.message || 'Error during @plugin call'; - return new LessError(e, imports, filename); + return new LessError(e); } - - } - else { - return new LessError({ message: 'Not a valid plugin' }, imports, filename); } - return pluginObj; - -}; + validatePlugin(plugin, filename, name) { + if (plugin) { + // support plugins being a function + // so that the plugin can be more usable programmatically + if (typeof plugin === 'function') { + plugin = new plugin(); + } -AbstractPluginLoader.prototype.trySetOptions = function(plugin, filename, name, options) { - if (options && !plugin.setOptions) { - return new LessError({ - message: 'Options have been provided but the plugin ' + - name + ' does not support any options.' - }); - } - try { - plugin.setOptions && plugin.setOptions(options); - } - catch (e) { - return new LessError(e); - } -}; - -AbstractPluginLoader.prototype.validatePlugin = function(plugin, filename, name) { - if (plugin) { - // support plugins being a function - // so that the plugin can be more usable programmatically - if (typeof plugin === 'function') { - plugin = new plugin(); - } - - if (plugin.minVersion) { - if (this.compareVersion(plugin.minVersion, this.less.version) < 0) { - return new LessError({ - message: 'Plugin ' + name + ' requires version ' + - this.versionToString(plugin.minVersion) - }); + if (plugin.minVersion) { + if (this.compareVersion(plugin.minVersion, this.less.version) < 0) { + return new LessError({ + message: `Plugin ${name} requires version ${this.versionToString(plugin.minVersion)}` + }); + } } + return plugin; } - return plugin; + return null; } - return null; -}; -AbstractPluginLoader.prototype.compareVersion = function(aVersion, bVersion) { - if (typeof aVersion === 'string') { - aVersion = aVersion.match(/^(\d+)\.?(\d+)?\.?(\d+)?/); - aVersion.shift(); - } - for (var i = 0; i < aVersion.length; i++) { - if (aVersion[i] !== bVersion[i]) { - return parseInt(aVersion[i]) > parseInt(bVersion[i]) ? -1 : 1; + compareVersion(aVersion, bVersion) { + if (typeof aVersion === 'string') { + aVersion = aVersion.match(/^(\d+)\.?(\d+)?\.?(\d+)?/); + aVersion.shift(); + } + for (let i = 0; i < aVersion.length; i++) { + if (aVersion[i] !== bVersion[i]) { + return parseInt(aVersion[i]) > parseInt(bVersion[i]) ? -1 : 1; + } } + return 0; } - return 0; -}; -AbstractPluginLoader.prototype.versionToString = function(version) { - var versionString = ''; - for (var i = 0; i < version.length; i++) { - versionString += (versionString ? '.' : '') + version[i]; + + versionToString(version) { + let versionString = ''; + for (let i = 0; i < version.length; i++) { + versionString += (versionString ? '.' : '') + version[i]; + } + return versionString; } - return versionString; -}; -AbstractPluginLoader.prototype.printUsage = function(plugins) { - for (var i = 0; i < plugins.length; i++) { - var plugin = plugins[i]; - if (plugin.printUsage) { - plugin.printUsage(); + + printUsage(plugins) { + for (let i = 0; i < plugins.length; i++) { + const plugin = plugins[i]; + if (plugin.printUsage) { + plugin.printUsage(); + } } } -}; +} -module.exports = AbstractPluginLoader; +export default AbstractPluginLoader; diff --git a/lib/less/environment/environment-api.js b/lib/less/environment/environment-api.js index ae6beff40..88d2927ea 100644 --- a/lib/less/environment/environment-api.js +++ b/lib/less/environment/environment-api.js @@ -1,4 +1,4 @@ -module.exports = { +export default { /** * Converts a string to a base 64 string * @param str diff --git a/lib/less/environment/environment.js b/lib/less/environment/environment.js index 926d48f32..340c8e14b 100644 --- a/lib/less/environment/environment.js +++ b/lib/less/environment/environment.js @@ -3,54 +3,57 @@ * environment, file managers, and plugin manager */ -var logger = require('../logger'); -var environment = function(externalEnvironment, fileManagers) { - this.fileManagers = fileManagers || []; - externalEnvironment = externalEnvironment || {}; - - var optionalFunctions = ['encodeBase64', 'mimeLookup', 'charsetLookup', 'getSourceMapGenerator'], - requiredFunctions = [], - functions = requiredFunctions.concat(optionalFunctions); - - for (var i = 0; i < functions.length; i++) { - var propName = functions[i], - environmentFunc = externalEnvironment[propName]; - if (environmentFunc) { - this[propName] = environmentFunc.bind(externalEnvironment); - } else if (i < requiredFunctions.length) { - this.warn('missing required function in environment - ' + propName); +import logger from '../logger'; + +class environment { + constructor(externalEnvironment, fileManagers) { + this.fileManagers = fileManagers || []; + externalEnvironment = externalEnvironment || {}; + + const optionalFunctions = ['encodeBase64', 'mimeLookup', 'charsetLookup', 'getSourceMapGenerator']; + const requiredFunctions = []; + const functions = requiredFunctions.concat(optionalFunctions); + + for (let i = 0; i < functions.length; i++) { + const propName = functions[i]; + const environmentFunc = externalEnvironment[propName]; + if (environmentFunc) { + this[propName] = environmentFunc.bind(externalEnvironment); + } else if (i < requiredFunctions.length) { + this.warn(`missing required function in environment - ${propName}`); + } } } -}; -environment.prototype.getFileManager = function (filename, currentDirectory, options, environment, isSync) { + getFileManager(filename, currentDirectory, options, environment, isSync) { - if (!filename) { - logger.warn('getFileManager called with no filename.. Please report this issue. continuing.'); - } - if (currentDirectory == null) { - logger.warn('getFileManager called with null directory.. Please report this issue. continuing.'); - } + if (!filename) { + logger.warn('getFileManager called with no filename.. Please report this issue. continuing.'); + } + if (currentDirectory == null) { + logger.warn('getFileManager called with null directory.. Please report this issue. continuing.'); + } - var fileManagers = this.fileManagers; - if (options.pluginManager) { - fileManagers = [].concat(fileManagers).concat(options.pluginManager.getFileManagers()); - } - for (var i = fileManagers.length - 1; i >= 0 ; i--) { - var fileManager = fileManagers[i]; - if (fileManager[isSync ? 'supportsSync' : 'supports'](filename, currentDirectory, options, environment)) { - return fileManager; + let fileManagers = this.fileManagers; + if (options.pluginManager) { + fileManagers = [].concat(fileManagers).concat(options.pluginManager.getFileManagers()); + } + for (let i = fileManagers.length - 1; i >= 0 ; i--) { + const fileManager = fileManagers[i]; + if (fileManager[isSync ? 'supportsSync' : 'supports'](filename, currentDirectory, options, environment)) { + return fileManager; + } } + return null; } - return null; -}; -environment.prototype.addFileManager = function (fileManager) { - this.fileManagers.push(fileManager); -}; + addFileManager(fileManager) { + this.fileManagers.push(fileManager); + } -environment.prototype.clearFileManagers = function () { - this.fileManagers = []; -}; + clearFileManagers() { + this.fileManagers = []; + } +} -module.exports = environment; +export default environment; diff --git a/lib/less/environment/file-manager-api.js b/lib/less/environment/file-manager-api.js index c4d043e6d..15cebeda0 100644 --- a/lib/less/environment/file-manager-api.js +++ b/lib/less/environment/file-manager-api.js @@ -1,4 +1,4 @@ -module.exports = { +export default { /** * Given the full path to a file, return the path component * Provided by AbstractFileManager diff --git a/lib/less/functions/boolean.js b/lib/less/functions/boolean.js index 829ee207a..97b514a93 100644 --- a/lib/less/functions/boolean.js +++ b/lib/less/functions/boolean.js @@ -1,15 +1,13 @@ +import Anonymous from '../tree/anonymous'; +import Keyword from '../tree/keyword'; -var functionRegistry = require('./function-registry'), - Anonymous = require('../tree/anonymous'), - Keyword = require('../tree/keyword'); +function boolean(condition) { + return condition ? Keyword.True : Keyword.False; +} -functionRegistry.addMultiple({ - boolean: function(condition) { - return condition ? Keyword.True : Keyword.False; - }, +function If(condition, trueValue, falseValue) { + return condition ? trueValue + : (falseValue || new Anonymous); +} - 'if': function(condition, trueValue, falseValue) { - return condition ? trueValue - : (falseValue || new Anonymous); - } -}); +export default { boolean, 'if': If }; diff --git a/lib/less/functions/color-blending.js b/lib/less/functions/color-blending.js index e34979e39..9f01626d2 100644 --- a/lib/less/functions/color-blending.js +++ b/lib/less/functions/color-blending.js @@ -1,16 +1,25 @@ -var Color = require('../tree/color'), - functionRegistry = require('./function-registry'); +import Color from '../tree/color'; // Color Blending // ref: http://www.w3.org/TR/compositing-1 function colorBlend(mode, color1, color2) { - var ab = color1.alpha, cb, // backdrop - as = color2.alpha, cs, // source - ar, cr, r = []; // result + const ab = color1.alpha; // result + + let // backdrop + cb; + + const as = color2.alpha; + + let // source + cs; + + let ar; + let cr; + const r = []; ar = as + ab * (1 - as); - for (var i = 0; i < 3; i++) { + for (let i = 0; i < 3; i++) { cb = color1.rgb[i] / 255; cs = color2.rgb[i] / 255; cr = mode(cb, cs); @@ -24,7 +33,7 @@ function colorBlend(mode, color1, color2) { return new Color(r, ar); } -var colorBlendModeFunctions = { +const colorBlendModeFunctions = { multiply: function(cb, cs) { return cb * cs; }, @@ -38,7 +47,8 @@ var colorBlendModeFunctions = { colorBlendModeFunctions.screen(cb - 1, cs); }, softlight: function(cb, cs) { - var d = 1, e = cb; + let d = 1; + let e = cb; if (cs > 0.5) { e = 1; d = (cb > 0.25) ? Math.sqrt(cb) @@ -65,10 +75,10 @@ var colorBlendModeFunctions = { } }; -for (var f in colorBlendModeFunctions) { +for (const f in colorBlendModeFunctions) { if (colorBlendModeFunctions.hasOwnProperty(f)) { colorBlend[f] = colorBlend.bind(null, colorBlendModeFunctions[f]); } } -functionRegistry.addMultiple(colorBlend); +export default colorBlend; diff --git a/lib/less/functions/color.js b/lib/less/functions/color.js index a9b5198e8..ba0e0baf6 100644 --- a/lib/less/functions/color.js +++ b/lib/less/functions/color.js @@ -1,15 +1,14 @@ -var Dimension = require('../tree/dimension'), - Color = require('../tree/color'), - Quoted = require('../tree/quoted'), - Anonymous = require('../tree/anonymous'), - functionRegistry = require('./function-registry'), - colorFunctions; +import Dimension from '../tree/dimension'; +import Color from '../tree/color'; +import Quoted from '../tree/quoted'; +import Anonymous from '../tree/anonymous'; +let colorFunctions; function clamp(val) { return Math.min(1, Math.max(0, val)); } function hsla(origColor, hsl) { - var color = colorFunctions.hsla(hsl.h, hsl.s, hsl.l, hsl.a); + const color = colorFunctions.hsla(hsl.h, hsl.s, hsl.l, hsl.a); if (color) { if (origColor.value && /^(rgb|hsl)/.test(origColor.value)) { @@ -57,7 +56,7 @@ function scaled(n, size) { } colorFunctions = { rgb: function (r, g, b) { - var color = colorFunctions.rgba(r, g, b, 1.0); + const color = colorFunctions.rgba(r, g, b, 1.0); if (color) { color.value = 'rgb'; return color; @@ -73,14 +72,14 @@ colorFunctions = { } return new Color(r.rgb, a, 'rgba'); } - var rgb = [r, g, b].map(function (c) { return scaled(c, 255); }); + const rgb = [r, g, b].map(c => scaled(c, 255)); a = number(a); return new Color(rgb, a, 'rgba'); } catch (e) {} }, hsl: function (h, s, l) { - var color = colorFunctions.hsla(h, s, l, 1.0); + const color = colorFunctions.hsla(h, s, l, 1.0); if (color) { color.value = 'hsl'; return color; @@ -97,7 +96,8 @@ colorFunctions = { return new Color(h.rgb, a, 'hsla'); } - var m1, m2; + let m1; + let m2; function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); @@ -116,12 +116,12 @@ colorFunctions = { } h = (number(h) % 360) / 360; - s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a)); + s = clamp(number(s));l = clamp(number(l));a = clamp(number(a)); m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; m1 = l * 2 - m2; - var rgb = [ + const rgb = [ hue(h + 1 / 3) * 255, hue(h) * 255, hue(h - 1 / 3) * 255 @@ -138,17 +138,18 @@ colorFunctions = { hsva: function(h, s, v, a) { h = ((number(h) % 360) / 360) * 360; - s = number(s); v = number(v); a = number(a); + s = number(s);v = number(v);a = number(a); - var i, f; + let i; + let f; i = Math.floor((h / 60) % 6); f = (h / 60) - i; - var vs = [v, + const vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; - var perm = [[0, 3, 1], + const perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], @@ -195,7 +196,7 @@ colorFunctions = { return new Dimension(color.luma() * color.alpha * 100, '%'); }, luminance: function (color) { - var luminance = + const luminance = (0.2126 * color.rgb[0] / 255) + (0.7152 * color.rgb[1] / 255) + (0.0722 * color.rgb[2] / 255); @@ -208,7 +209,7 @@ colorFunctions = { if (!color.rgb) { return null; } - var hsl = toHSL(color); + const hsl = toHSL(color); if (typeof method !== 'undefined' && method.value === 'relative') { hsl.s += hsl.s * amount.value / 100; @@ -220,7 +221,7 @@ colorFunctions = { return hsla(color, hsl); }, desaturate: function (color, amount, method) { - var hsl = toHSL(color); + const hsl = toHSL(color); if (typeof method !== 'undefined' && method.value === 'relative') { hsl.s -= hsl.s * amount.value / 100; @@ -232,7 +233,7 @@ colorFunctions = { return hsla(color, hsl); }, lighten: function (color, amount, method) { - var hsl = toHSL(color); + const hsl = toHSL(color); if (typeof method !== 'undefined' && method.value === 'relative') { hsl.l += hsl.l * amount.value / 100; @@ -244,7 +245,7 @@ colorFunctions = { return hsla(color, hsl); }, darken: function (color, amount, method) { - var hsl = toHSL(color); + const hsl = toHSL(color); if (typeof method !== 'undefined' && method.value === 'relative') { hsl.l -= hsl.l * amount.value / 100; @@ -256,7 +257,7 @@ colorFunctions = { return hsla(color, hsl); }, fadein: function (color, amount, method) { - var hsl = toHSL(color); + const hsl = toHSL(color); if (typeof method !== 'undefined' && method.value === 'relative') { hsl.a += hsl.a * amount.value / 100; @@ -268,7 +269,7 @@ colorFunctions = { return hsla(color, hsl); }, fadeout: function (color, amount, method) { - var hsl = toHSL(color); + const hsl = toHSL(color); if (typeof method !== 'undefined' && method.value === 'relative') { hsl.a -= hsl.a * amount.value / 100; @@ -280,15 +281,15 @@ colorFunctions = { return hsla(color, hsl); }, fade: function (color, amount) { - var hsl = toHSL(color); + const hsl = toHSL(color); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(color, hsl); }, spin: function (color, amount) { - var hsl = toHSL(color); - var hue = (hsl.h + amount.value) % 360; + const hsl = toHSL(color); + const hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; @@ -302,18 +303,18 @@ colorFunctions = { if (!weight) { weight = new Dimension(50); } - var p = weight.value / 100.0; - var w = p * 2 - 1; - var a = toHSL(color1).a - toHSL(color2).a; + const p = weight.value / 100.0; + const w = p * 2 - 1; + const a = toHSL(color1).a - toHSL(color2).a; - var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; - var w2 = 1 - w1; + const w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; + const w2 = 1 - w1; - var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, + const rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; - var alpha = color1.alpha * p + color2.alpha * (1 - p); + const alpha = color1.alpha * p + color2.alpha * (1 - p); return new Color(rgb, alpha); }, @@ -334,7 +335,7 @@ colorFunctions = { } // Figure out which is actually light and dark: if (dark.luma() > light.luma()) { - var t = light; + const t = light; light = dark; dark = t; } @@ -393,8 +394,8 @@ colorFunctions = { color: function(c) { if ((c instanceof Quoted) && (/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})$/i.test(c.value))) { - var val = c.value.slice(1); - return new Color(val, undefined, '#' + val); + const val = c.value.slice(1); + return new Color(val, undefined, `#${val}`); } if ((c instanceof Color) || (c = Color.fromKeyword(c.value))) { c.value = undefined; @@ -412,4 +413,5 @@ colorFunctions = { return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount); } }; -functionRegistry.addMultiple(colorFunctions); + +export default colorFunctions; diff --git a/lib/less/functions/data-uri.js b/lib/less/functions/data-uri.js index b2452505e..3c09c507f 100644 --- a/lib/less/functions/data-uri.js +++ b/lib/less/functions/data-uri.js @@ -1,42 +1,41 @@ -module.exports = function(environment) { - var Quoted = require('../tree/quoted'), - URL = require('../tree/url'), - utils = require('../utils'), - functionRegistry = require('./function-registry'), - fallback = function(functionThis, node) { - return new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context); - }, - logger = require('../logger'); +import Quoted from '../tree/quoted'; +import URL from '../tree/url'; +import * as utils from '../utils'; +import logger from '../logger'; - functionRegistry.add('data-uri', function(mimetypeNode, filePathNode) { +export default environment => { + + const fallback = (functionThis, node) => new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context); + + return { 'data-uri': function(mimetypeNode, filePathNode) { if (!filePathNode) { filePathNode = mimetypeNode; mimetypeNode = null; } - var mimetype = mimetypeNode && mimetypeNode.value; - var filePath = filePathNode.value; - var currentFileInfo = this.currentFileInfo; - var currentDirectory = currentFileInfo.rewriteUrls ? + let mimetype = mimetypeNode && mimetypeNode.value; + let filePath = filePathNode.value; + const currentFileInfo = this.currentFileInfo; + const currentDirectory = currentFileInfo.rewriteUrls ? currentFileInfo.currentDirectory : currentFileInfo.entryPath; - var fragmentStart = filePath.indexOf('#'); - var fragment = ''; + const fragmentStart = filePath.indexOf('#'); + let fragment = ''; if (fragmentStart !== -1) { fragment = filePath.slice(fragmentStart); filePath = filePath.slice(0, fragmentStart); } - var context = utils.clone(this.context); + const context = utils.clone(this.context); context.rawBuffer = true; - var fileManager = environment.getFileManager(filePath, currentDirectory, context, environment, true); + const fileManager = environment.getFileManager(filePath, currentDirectory, context, environment, true); if (!fileManager) { return fallback(this, filePathNode); } - var useBase64 = false; + let useBase64 = false; // detect the mimetype if not given if (!mimetypeNode) { @@ -47,7 +46,7 @@ module.exports = function(environment) { useBase64 = false; } else { // use base 64 unless it's an ASCII or UTF-8 format - var charset = environment.charsetLookup(mimetype); + const charset = environment.charsetLookup(mimetype); useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; } if (useBase64) { mimetype += ';base64'; } @@ -56,33 +55,20 @@ module.exports = function(environment) { useBase64 = /;base64$/.test(mimetype); } - var fileSync = fileManager.loadFileSync(filePath, currentDirectory, context, environment); + const fileSync = fileManager.loadFileSync(filePath, currentDirectory, context, environment); if (!fileSync.contents) { - logger.warn('Skipped data-uri embedding of ' + filePath + ' because file not found'); + logger.warn(`Skipped data-uri embedding of ${filePath} because file not found`); return fallback(this, filePathNode || mimetypeNode); } - var buf = fileSync.contents; + let buf = fileSync.contents; if (useBase64 && !environment.encodeBase64) { return fallback(this, filePathNode); } buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf); - var uri = 'data:' + mimetype + ',' + buf + fragment; - - // IE8 cannot handle a data-uri larger than 32,768 characters. If this is exceeded - // and the --ieCompat flag is enabled, return a normal url() instead. - var DATA_URI_MAX = 32768; - if (uri.length >= DATA_URI_MAX) { - - if (this.context.ieCompat !== false) { - logger.warn('Skipped data-uri embedding of ' + filePath + ' because its size (' + uri.length + - ' characters) exceeds IE8-safe ' + DATA_URI_MAX + ' characters!'); - - return fallback(this, filePathNode || mimetypeNode); - } - } + const uri = `data:${mimetype},${buf}${fragment}`; - return new URL(new Quoted('"' + uri + '"', uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); - }); + return new URL(new Quoted(`"${uri}"`, uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); + }}; }; diff --git a/lib/less/functions/default.js b/lib/less/functions/default.js index 194dd3980..fc7fd63aa 100644 --- a/lib/less/functions/default.js +++ b/lib/less/functions/default.js @@ -1,9 +1,9 @@ -var Keyword = require('../tree/keyword'), - functionRegistry = require('./function-registry'); +import Keyword from '../tree/keyword'; -var defaultFunc = { +const defaultFunc = { eval: function () { - var v = this.value_, e = this.error_; + const v = this.value_; + const e = this.error_; if (e) { throw e; } @@ -22,6 +22,4 @@ var defaultFunc = { } }; -functionRegistry.add('default', defaultFunc.eval.bind(defaultFunc)); - -module.exports = defaultFunc; +export default defaultFunc; diff --git a/lib/less/functions/function-caller.js b/lib/less/functions/function-caller.js index 1062e7f50..76b4c413c 100644 --- a/lib/less/functions/function-caller.js +++ b/lib/less/functions/function-caller.js @@ -1,46 +1,49 @@ -var Expression = require('../tree/expression'); +import Expression from '../tree/expression'; -var functionCaller = function(name, context, index, currentFileInfo) { - this.name = name.toLowerCase(); - this.index = index; - this.context = context; - this.currentFileInfo = currentFileInfo; +class functionCaller { + constructor(name, context, index, currentFileInfo) { + this.name = name.toLowerCase(); + this.index = index; + this.context = context; + this.currentFileInfo = currentFileInfo; - this.func = context.frames[0].functionRegistry.get(this.name); -}; -functionCaller.prototype.isValid = function() { - return Boolean(this.func); -}; + this.func = context.frames[0].functionRegistry.get(this.name); + } + + isValid() { + return Boolean(this.func); + } -functionCaller.prototype.call = function(args) { - // This code is terrible and should be replaced as per this issue... - // https://github.com/less/less.js/issues/2477 - if (Array.isArray(args)) { - args = args.filter(function (item) { - if (item.type === 'Comment') { - return false; - } - return true; - }) - .map(function(item) { - if (item.type === 'Expression') { - var subNodes = item.value.filter(function (item) { - if (item.type === 'Comment') { - return false; + call(args) { + // This code is terrible and should be replaced as per this issue... + // https://github.com/less/less.js/issues/2477 + if (Array.isArray(args)) { + args = args.filter(item => { + if (item.type === 'Comment') { + return false; + } + return true; + }) + .map(item => { + if (item.type === 'Expression') { + const subNodes = item.value.filter(item => { + if (item.type === 'Comment') { + return false; + } + return true; + }); + if (subNodes.length === 1) { + return subNodes[0]; + } else { + return new Expression(subNodes); + } } - return true; + return item; }); - if (subNodes.length === 1) { - return subNodes[0]; - } else { - return new Expression(subNodes); - } - } - return item; - }); - } + } - return this.func.apply(this, args); -}; + return this.func(...args); + } +} -module.exports = functionCaller; +export default functionCaller; diff --git a/lib/less/functions/function-registry.js b/lib/less/functions/function-registry.js index d314355a4..912a5acb7 100644 --- a/lib/less/functions/function-registry.js +++ b/lib/less/functions/function-registry.js @@ -13,9 +13,9 @@ function makeRegistry( base ) { }, addMultiple: function(functions) { Object.keys(functions).forEach( - function(name) { + name => { this.add(name, functions[name]); - }.bind(this)); + }); }, get: function(name) { return this._data[name] || ( base && base.get( name )); @@ -32,4 +32,4 @@ function makeRegistry( base ) { }; } -module.exports = makeRegistry( null ); \ No newline at end of file +export default makeRegistry( null ); \ No newline at end of file diff --git a/lib/less/functions/index.js b/lib/less/functions/index.js index a9f8aaffa..046da784c 100644 --- a/lib/less/functions/index.js +++ b/lib/less/functions/index.js @@ -1,21 +1,33 @@ -module.exports = function(environment) { - var functions = { - functionRegistry: require('./function-registry'), - functionCaller: require('./function-caller') - }; +import functionRegistry from './function-registry'; +import functionCaller from './function-caller'; + +import boolean from './boolean'; +import defaultFunc from './default'; +import color from './color'; +import colorBlending from './color-blending'; +import dataUri from './data-uri'; +import list from './list'; +import math from './math'; +import number from './number'; +import string from './string'; +import svg from './svg'; +import types from './types'; + +export default environment => { + const functions = { functionRegistry, functionCaller }; // register functions - require('./boolean'); - require('./default'); - require('./color'); - require('./color-blending'); - require('./data-uri')(environment); - require('./list'); - require('./math'); - require('./number'); - require('./string'); - require('./svg')(environment); - require('./types'); + functionRegistry.addMultiple(boolean); + functionRegistry.add('default', defaultFunc.eval.bind(defaultFunc)); + functionRegistry.addMultiple(color); + functionRegistry.addMultiple(colorBlending); + functionRegistry.addMultiple(dataUri(environment)); + functionRegistry.addMultiple(list); + functionRegistry.addMultiple(math); + functionRegistry.addMultiple(number); + functionRegistry.addMultiple(string); + functionRegistry.addMultiple(svg(environment)); + functionRegistry.addMultiple(types); return functions; }; diff --git a/lib/less/functions/list.js b/lib/less/functions/list.js index 8c2523398..da57b16e7 100644 --- a/lib/less/functions/list.js +++ b/lib/less/functions/list.js @@ -1,23 +1,22 @@ -var Comment = require('../tree/comment'), - Dimension = require('../tree/dimension'), - Declaration = require('../tree/declaration'), - Expression = require('../tree/expression'), - Ruleset = require('../tree/ruleset'), - Selector = require('../tree/selector'), - Element = require('../tree/element'), - Quote = require('../tree/quoted'), - functionRegistry = require('./function-registry'); +import Comment from '../tree/comment'; +import Dimension from '../tree/dimension'; +import Declaration from '../tree/declaration'; +import Expression from '../tree/expression'; +import Ruleset from '../tree/ruleset'; +import Selector from '../tree/selector'; +import Element from '../tree/element'; +import Quote from '../tree/quoted'; -var getItemsFromNode = function(node) { +const getItemsFromNode = node => { // handle non-array values as an array of length 1 // return 'undefined' if index is invalid - var items = Array.isArray(node.value) ? + const items = Array.isArray(node.value) ? node.value : Array(node); return items; }; -functionRegistry.addMultiple({ +export default { _SELF: function(n) { return n; }, @@ -38,7 +37,10 @@ functionRegistry.addMultiple({ * @param {Dimension} [step=1] */ range: function(start, end, step) { - var from, to, stepValue = 1, list = []; + let from; + let to; + let stepValue = 1; + const list = []; if (end) { to = end; from = start.value; @@ -51,14 +53,16 @@ functionRegistry.addMultiple({ to = start; } - for (var i = from; i <= to.value; i += stepValue) { + for (let i = from; i <= to.value; i += stepValue) { list.push(new Dimension(i, to.unit)); } return new Expression(list); }, each: function(list, rs) { - var rules = [], newRules, iterator; + const rules = []; + let newRules; + let iterator; if (list.value && !(list instanceof Quote)) { if (Array.isArray(list.value)) { @@ -76,9 +80,9 @@ functionRegistry.addMultiple({ iterator = [list]; } - var valueName = '@value', - keyName = '@key', - indexName = '@index'; + let valueName = '@value'; + let keyName = '@key'; + let indexName = '@index'; if (rs.params) { valueName = rs.params[0] && rs.params[0].name; @@ -89,8 +93,10 @@ functionRegistry.addMultiple({ rs = rs.ruleset; } - for (var i = 0; i < iterator.length; i++) { - var key, value, item = iterator[i]; + for (let i = 0; i < iterator.length; i++) { + let key; + let value; + const item = iterator[i]; if (item instanceof Declaration) { key = typeof item.name === 'string' ? item.name : item.name[0].value; value = item.value; @@ -98,7 +104,7 @@ functionRegistry.addMultiple({ key = new Dimension(i + 1); value = item; } - + if (item instanceof Comment) { continue; } @@ -119,7 +125,7 @@ functionRegistry.addMultiple({ key, false, false, this.index, this.currentFileInfo)); } - + rules.push(new Ruleset([ new(Selector)([ new Element("", '&') ]) ], newRules, rs.strictImports, @@ -128,10 +134,9 @@ functionRegistry.addMultiple({ } return new Ruleset([ new(Selector)([ new Element("", '&') ]) ], - rules, - rs.strictImports, - rs.visibilityInfo() - ).eval(this.context); - + rules, + rs.strictImports, + rs.visibilityInfo() + ).eval(this.context); } -}); +}; diff --git a/lib/less/functions/math-helper.js b/lib/less/functions/math-helper.js index 41b51295a..ed6deaa75 100644 --- a/lib/less/functions/math-helper.js +++ b/lib/less/functions/math-helper.js @@ -1,8 +1,6 @@ -var Dimension = require('../tree/dimension'); +import Dimension from '../tree/dimension'; -var MathHelper = function() { -}; -MathHelper._math = function (fn, unit, n) { +const MathHelper = (fn, unit, n) => { if (!(n instanceof Dimension)) { throw { type: 'Argument', message: 'argument must be a number' }; } @@ -13,4 +11,5 @@ MathHelper._math = function (fn, unit, n) { } return new Dimension(fn(parseFloat(n.value)), unit); }; -module.exports = MathHelper; \ No newline at end of file + +export default MathHelper; \ No newline at end of file diff --git a/lib/less/functions/math.js b/lib/less/functions/math.js index 31fc30abd..f025dc2e2 100644 --- a/lib/less/functions/math.js +++ b/lib/less/functions/math.js @@ -1,7 +1,6 @@ -var functionRegistry = require('./function-registry'), - mathHelper = require('./math-helper.js'); +import mathHelper from './math-helper.js'; -var mathFunctions = { +const mathFunctions = { // name, unit ceil: null, floor: null, @@ -15,15 +14,15 @@ var mathFunctions = { acos: 'rad' }; -for (var f in mathFunctions) { +for (const f in mathFunctions) { if (mathFunctions.hasOwnProperty(f)) { - mathFunctions[f] = mathHelper._math.bind(null, Math[f], mathFunctions[f]); + mathFunctions[f] = mathHelper.bind(null, Math[f], mathFunctions[f]); } } -mathFunctions.round = function (n, f) { - var fraction = typeof f === 'undefined' ? 0 : f.value; - return mathHelper._math(function(num) { return num.toFixed(fraction); }, null, n); +mathFunctions.round = (n, f) => { + const fraction = typeof f === 'undefined' ? 0 : f.value; + return mathHelper(num => num.toFixed(fraction), null, n); }; -functionRegistry.addMultiple(mathFunctions); +export default mathFunctions; diff --git a/lib/less/functions/number.js b/lib/less/functions/number.js index fc085a91e..2575c9288 100644 --- a/lib/less/functions/number.js +++ b/lib/less/functions/number.js @@ -1,16 +1,25 @@ -var Dimension = require('../tree/dimension'), - Anonymous = require('../tree/anonymous'), - functionRegistry = require('./function-registry'), - mathHelper = require('./math-helper.js'); +import Dimension from '../tree/dimension'; +import Anonymous from '../tree/anonymous'; +import mathHelper from './math-helper.js'; -var minMax = function (isMin, args) { +const minMax = function (isMin, args) { args = Array.prototype.slice.call(args); switch (args.length) { case 0: throw { type: 'Argument', message: 'one or more arguments required' }; } - var i, j, current, currentUnified, referenceUnified, unit, unitStatic, unitClone, - order = [], // elems only contains original argument values. - values = {}; // key is the unit.toString() for unified Dimension values, + let i; // key is the unit.toString() for unified Dimension values, + let j; + let current; + let currentUnified; + let referenceUnified; + let unit; + let unitStatic; + let unitClone; + + const // elems only contains original argument values. + order = []; + + const values = {}; // value is the index into the order array. for (i = 0; i < args.length; i++) { current = args[i]; @@ -43,14 +52,15 @@ var minMax = function (isMin, args) { return order[0]; } args = order.map(function (a) { return a.toCSS(this.context); }).join(this.context.compress ? ',' : ', '); - return new Anonymous((isMin ? 'min' : 'max') + '(' + args + ')'); + return new Anonymous(`${isMin ? 'min' : 'max'}(${args})`); }; -functionRegistry.addMultiple({ - min: function () { - return minMax(true, arguments); + +export default { + min: function(...args) { + return minMax(true, args); }, - max: function () { - return minMax(false, arguments); + max: function(...args) { + return minMax(false, args); }, convert: function (val, unit) { return val.convertTo(unit.value); @@ -72,10 +82,8 @@ functionRegistry.addMultiple({ return new Dimension(Math.pow(x.value, y.value), x.unit); }, percentage: function (n) { - var result = mathHelper._math(function(num) { - return num * 100; - }, '%', n); + const result = mathHelper(num => num * 100, '%', n); return result; } -}); +}; diff --git a/lib/less/functions/string.js b/lib/less/functions/string.js index a04311cc2..e2fc569ff 100644 --- a/lib/less/functions/string.js +++ b/lib/less/functions/string.js @@ -1,10 +1,9 @@ -var Quoted = require('../tree/quoted'), - Anonymous = require('../tree/anonymous'), - Quote = require('../tree/quoted'), - JavaScript = require('../tree/javascript'), - functionRegistry = require('./function-registry'); +import Quoted from '../tree/quoted'; +import Anonymous from '../tree/anonymous'; +import Quote from '../tree/quoted'; +import JavaScript from '../tree/javascript'; -functionRegistry.addMultiple({ +export default { e: function (str) { return new Quote('"', str instanceof JavaScript ? str.evaluated : str.value, true); }, @@ -14,20 +13,20 @@ functionRegistry.addMultiple({ .replace(/\(/g, '%28').replace(/\)/g, '%29')); }, replace: function (string, pattern, replacement, flags) { - var result = string.value; + let result = string.value; replacement = (replacement.type === 'Quoted') ? replacement.value : replacement.toCSS(); result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement); return new Quoted(string.quote || '', result, string.escaped); }, '%': function (string /* arg, arg, ... */) { - var args = Array.prototype.slice.call(arguments, 1), - result = string.value; + const args = Array.prototype.slice.call(arguments, 1); + let result = string.value; - for (var i = 0; i < args.length; i++) { + for (let i = 0; i < args.length; i++) { /* jshint loopfunc:true */ - result = result.replace(/%[sda]/i, function(token) { - var value = ((args[i].type === 'Quoted') && + result = result.replace(/%[sda]/i, token => { + const value = ((args[i].type === 'Quoted') && token.match(/s/i)) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); @@ -35,4 +34,4 @@ functionRegistry.addMultiple({ result = result.replace(/%%/g, '%'); return new Quoted(string.quote || '', result, string.escaped); } -}); +}; diff --git a/lib/less/functions/svg.js b/lib/less/functions/svg.js index 35df75a8c..3df96d66f 100644 --- a/lib/less/functions/svg.js +++ b/lib/less/functions/svg.js @@ -1,21 +1,23 @@ -module.exports = function(environment) { - var Dimension = require('../tree/dimension'), - Color = require('../tree/color'), - Expression = require('../tree/expression'), - Quoted = require('../tree/quoted'), - URL = require('../tree/url'), - functionRegistry = require('./function-registry'); +import Dimension from '../tree/dimension'; +import Color from '../tree/color'; +import Expression from '../tree/expression'; +import Quoted from '../tree/quoted'; +import URL from '../tree/url'; - functionRegistry.add('svg-gradient', function(direction) { - - var stops, - gradientDirectionSvg, - gradientType = 'linear', - rectangleDimension = 'x="0" y="0" width="1" height="1"', - renderEnv = {compress: false}, - returner, - directionValue = direction.toCSS(renderEnv), - i, color, position, positionValue, alpha; +export default environment => { + return { 'svg-gradient': function(direction) { + let stops; + let gradientDirectionSvg; + let gradientType = 'linear'; + let rectangleDimension = 'x="0" y="0" width="1" height="1"'; + const renderEnv = {compress: false}; + let returner; + const directionValue = direction.toCSS(renderEnv); + let i; + let color; + let position; + let positionValue; + let alpha; function throwArgumentDescriptor() { throw { type: 'Argument', @@ -57,8 +59,7 @@ module.exports = function(environment) { throw { type: 'Argument', message: 'svg-gradient direction must be \'to bottom\', \'to right\',' + ' \'to bottom right\', \'to top right\' or \'ellipse at center\'' }; } - returner = '' + - '<' + gradientType + 'Gradient id="g" ' + gradientDirectionSvg + '>'; + returner = `<${gradientType}Gradient id="g" ${gradientDirectionSvg}>`; for (i = 0; i < stops.length; i += 1) { if (stops[i] instanceof Expression) { @@ -74,14 +75,13 @@ module.exports = function(environment) { } positionValue = position ? position.toCSS(renderEnv) : i === 0 ? '0%' : '100%'; alpha = color.alpha; - returner += ''; + returner += ``; } - returner += '' + - ''; + returner += ``; returner = encodeURIComponent(returner); - returner = 'data:image/svg+xml,' + returner; - return new URL(new Quoted('\'' + returner + '\'', returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); - }); + returner = `data:image/svg+xml,${returner}`; + return new URL(new Quoted(`'${returner}'`, returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo); + }}; }; diff --git a/lib/less/functions/types.js b/lib/less/functions/types.js index 219bcf23e..6f1aff30f 100644 --- a/lib/less/functions/types.js +++ b/lib/less/functions/types.js @@ -1,28 +1,25 @@ -var Keyword = require('../tree/keyword'), - DetachedRuleset = require('../tree/detached-ruleset'), - Dimension = require('../tree/dimension'), - Color = require('../tree/color'), - Quoted = require('../tree/quoted'), - Anonymous = require('../tree/anonymous'), - URL = require('../tree/url'), - Operation = require('../tree/operation'), - functionRegistry = require('./function-registry'); +import Keyword from '../tree/keyword'; +import DetachedRuleset from '../tree/detached-ruleset'; +import Dimension from '../tree/dimension'; +import Color from '../tree/color'; +import Quoted from '../tree/quoted'; +import Anonymous from '../tree/anonymous'; +import URL from '../tree/url'; +import Operation from '../tree/operation'; -var isa = function (n, Type) { - return (n instanceof Type) ? Keyword.True : Keyword.False; - }, - isunit = function (n, unit) { - if (unit === undefined) { - throw { type: 'Argument', message: 'missing the required second argument to isunit.' }; - } - unit = typeof unit.value === 'string' ? unit.value : unit; - if (typeof unit !== 'string') { - throw { type: 'Argument', message: 'Second argument to isunit should be a unit or a string.' }; - } - return (n instanceof Dimension) && n.unit.is(unit) ? Keyword.True : Keyword.False; - }; +const isa = (n, Type) => (n instanceof Type) ? Keyword.True : Keyword.False; +const isunit = (n, unit) => { + if (unit === undefined) { + throw { type: 'Argument', message: 'missing the required second argument to isunit.' }; + } + unit = typeof unit.value === 'string' ? unit.value : unit; + if (typeof unit !== 'string') { + throw { type: 'Argument', message: 'Second argument to isunit should be a unit or a string.' }; + } + return (n instanceof Dimension) && n.unit.is(unit) ? Keyword.True : Keyword.False; +}; -functionRegistry.addMultiple({ +export default { isruleset: function (n) { return isa(n, DetachedRuleset); }, @@ -50,12 +47,11 @@ functionRegistry.addMultiple({ isem: function (n) { return isunit(n, 'em'); }, - isunit: isunit, + isunit, unit: function (val, unit) { if (!(val instanceof Dimension)) { throw { type: 'Argument', - message: 'the first argument to unit must be a number' + - (val instanceof Operation ? '. Have you forgotten parenthesis?' : '') }; + message: `the first argument to unit must be a number${val instanceof Operation ? '. Have you forgotten parenthesis?' : ''}` }; } if (unit) { if (unit instanceof Keyword) { @@ -71,4 +67,4 @@ functionRegistry.addMultiple({ 'get-unit': function (n) { return new Anonymous(n.unit); } -}); +}; diff --git a/lib/less/import-manager.js b/lib/less/import-manager.js index b44f9a335..471484505 100644 --- a/lib/less/import-manager.js +++ b/lib/less/import-manager.js @@ -1,12 +1,10 @@ -var contexts = require('./contexts'), - Parser = require('./parser/parser'), - LessError = require('./less-error'), - utils = require('./utils'), - PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise, - logger = require('./logger'); - -module.exports = function(environment) { +import contexts from './contexts'; +import Parser from './parser/parser'; +import LessError from './less-error'; +import * as utils from './utils'; +import logger from './logger'; +export default environment => { // FileInfo = { // 'rewriteUrls' - option - whether to adjust URL's to be relative // 'filename' - full resolved filename of current file @@ -16,153 +14,156 @@ module.exports = function(environment) { // 'entryPath' - absolute path to the entry file // 'reference' - whether the file should not be output and only output parts that are referenced - var ImportManager = function(less, context, rootFileInfo) { - this.less = less; - this.rootFilename = rootFileInfo.filename; - this.paths = context.paths || []; // Search paths, when importing - this.contents = {}; // map - filename to contents of all the files - this.contentsIgnoredChars = {}; // map - filename to lines at the beginning of each file to ignore - this.mime = context.mime; - this.error = null; - this.context = context; - // Deprecated? Unused outside of here, could be useful. - this.queue = []; // Files which haven't been imported yet - this.files = {}; // Holds the imported parse trees. - }; - - /** - * Add an import to be imported - * @param path - the raw path - * @param tryAppendExtension - whether to try appending a file extension (.less or .js if the path has no extension) - * @param currentFileInfo - the current file info (used for instance to work out relative paths) - * @param importOptions - import options - * @param callback - callback for when it is imported - */ - ImportManager.prototype.push = function (path, tryAppendExtension, currentFileInfo, importOptions, callback) { - var importManager = this, - pluginLoader = this.context.pluginManager.Loader; - - this.queue.push(path); - - var fileParsedFunc = function (e, root, fullPath) { - importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue - - var importedEqualsRoot = fullPath === importManager.rootFilename; - if (importOptions.optional && e) { - callback(null, {rules:[]}, false, null); - logger.info('The file ' + fullPath + ' was skipped because it was not found and the import was marked optional.'); - } - else { - // Inline imports aren't cached here. - // If we start to cache them, please make sure they won't conflict with non-inline imports of the - // same name as they used to do before this comment and the condition below have been added. - if (!importManager.files[fullPath] && !importOptions.inline) { - importManager.files[fullPath] = { root: root, options: importOptions }; - } - if (e && !importManager.error) { importManager.error = e; } - callback(e, root, importedEqualsRoot, fullPath); - } - }; - - var newFileInfo = { - rewriteUrls: this.context.rewriteUrls, - entryPath: currentFileInfo.entryPath, - rootpath: currentFileInfo.rootpath, - rootFilename: currentFileInfo.rootFilename - }; - - var fileManager = environment.getFileManager(path, currentFileInfo.currentDirectory, this.context, environment); - - if (!fileManager) { - fileParsedFunc({ message: 'Could not find a file-manager for ' + path }); - return; + class ImportManager { + constructor(less, context, rootFileInfo) { + this.less = less; + this.rootFilename = rootFileInfo.filename; + this.paths = context.paths || []; // Search paths, when importing + this.contents = {}; // map - filename to contents of all the files + this.contentsIgnoredChars = {}; // map - filename to lines at the beginning of each file to ignore + this.mime = context.mime; + this.error = null; + this.context = context; + // Deprecated? Unused outside of here, could be useful. + this.queue = []; // Files which haven't been imported yet + this.files = {}; // Holds the imported parse trees. } - var loadFileCallback = function(loadedFile) { - var plugin, - resolvedFilename = loadedFile.filename, - contents = loadedFile.contents.replace(/^\uFEFF/, ''); - - // Pass on an updated rootpath if path of imported file is relative and file - // is in a (sub|sup) directory - // - // Examples: - // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/', - // then rootpath should become 'less/module/nav/' - // - If path of imported file is '../mixins.less' and rootpath is 'less/', - // then rootpath should become 'less/../' - newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename); - if (newFileInfo.rewriteUrls) { - newFileInfo.rootpath = fileManager.join( - (importManager.context.rootpath || ''), - fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath)); - - if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) { - newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath); + /** + * Add an import to be imported + * @param path - the raw path + * @param tryAppendExtension - whether to try appending a file extension (.less or .js if the path has no extension) + * @param currentFileInfo - the current file info (used for instance to work out relative paths) + * @param importOptions - import options + * @param callback - callback for when it is imported + */ + push(path, tryAppendExtension, currentFileInfo, importOptions, callback) { + const importManager = this; + const pluginLoader = this.context.pluginManager.Loader; + + this.queue.push(path); + + const fileParsedFunc = (e, root, fullPath) => { + importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue + + const importedEqualsRoot = fullPath === importManager.rootFilename; + if (importOptions.optional && e) { + callback(null, {rules:[]}, false, null); + logger.info(`The file ${fullPath} was skipped because it was not found and the import was marked optional.`); } - } - newFileInfo.filename = resolvedFilename; + else { + // Inline imports aren't cached here. + // If we start to cache them, please make sure they won't conflict with non-inline imports of the + // same name as they used to do before this comment and the condition below have been added. + if (!importManager.files[fullPath] && !importOptions.inline) { + importManager.files[fullPath] = { root, options: importOptions }; + } + if (e && !importManager.error) { importManager.error = e; } + callback(e, root, importedEqualsRoot, fullPath); + } + }; - var newEnv = new contexts.Parse(importManager.context); + const newFileInfo = { + rewriteUrls: this.context.rewriteUrls, + entryPath: currentFileInfo.entryPath, + rootpath: currentFileInfo.rootpath, + rootFilename: currentFileInfo.rootFilename + }; - newEnv.processImports = false; - importManager.contents[resolvedFilename] = contents; + const fileManager = environment.getFileManager(path, currentFileInfo.currentDirectory, this.context, environment); - if (currentFileInfo.reference || importOptions.reference) { - newFileInfo.reference = true; + if (!fileManager) { + fileParsedFunc({ message: `Could not find a file-manager for ${path}` }); + return; } - if (importOptions.isPlugin) { - plugin = pluginLoader.evalPlugin(contents, newEnv, importManager, importOptions.pluginArgs, newFileInfo); - if (plugin instanceof LessError) { - fileParsedFunc(plugin, null, resolvedFilename); - } - else { - fileParsedFunc(null, plugin, resolvedFilename); + const loadFileCallback = loadedFile => { + let plugin; + const resolvedFilename = loadedFile.filename; + const contents = loadedFile.contents.replace(/^\uFEFF/, ''); + + // Pass on an updated rootpath if path of imported file is relative and file + // is in a (sub|sup) directory + // + // Examples: + // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/', + // then rootpath should become 'less/module/nav/' + // - If path of imported file is '../mixins.less' and rootpath is 'less/', + // then rootpath should become 'less/../' + newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename); + if (newFileInfo.rewriteUrls) { + newFileInfo.rootpath = fileManager.join( + (importManager.context.rootpath || ''), + fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath)); + + if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) { + newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath); + } } - } else if (importOptions.inline) { - fileParsedFunc(null, contents, resolvedFilename); - } else { + newFileInfo.filename = resolvedFilename; - // import (multiple) parse trees apparently get altered and can't be cached. - // TODO: investigate why this is - if (importManager.files[resolvedFilename] - && !importManager.files[resolvedFilename].options.multiple - && !importOptions.multiple) { + const newEnv = new contexts.Parse(importManager.context); - fileParsedFunc(null, importManager.files[resolvedFilename].root, resolvedFilename); - } - else { - new Parser(newEnv, importManager, newFileInfo).parse(contents, function (e, root) { - fileParsedFunc(e, root, resolvedFilename); - }); + newEnv.processImports = false; + importManager.contents[resolvedFilename] = contents; + + if (currentFileInfo.reference || importOptions.reference) { + newFileInfo.reference = true; } - } - }; - var promise, context = utils.clone(this.context); - if (tryAppendExtension) { - context.ext = importOptions.isPlugin ? '.js' : '.less'; - } + if (importOptions.isPlugin) { + plugin = pluginLoader.evalPlugin(contents, newEnv, importManager, importOptions.pluginArgs, newFileInfo); + if (plugin instanceof LessError) { + fileParsedFunc(plugin, null, resolvedFilename); + } + else { + fileParsedFunc(null, plugin, resolvedFilename); + } + } else if (importOptions.inline) { + fileParsedFunc(null, contents, resolvedFilename); + } else { - if (importOptions.isPlugin) { - context.mime = 'application/javascript'; - promise = pluginLoader.loadPlugin(path, currentFileInfo.currentDirectory, context, environment, fileManager); - } - else { - promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, context, environment, - function(err, loadedFile) { - if (err) { - fileParsedFunc(err); - } else { - loadFileCallback(loadedFile); + // import (multiple) parse trees apparently get altered and can't be cached. + // TODO: investigate why this is + if (importManager.files[resolvedFilename] + && !importManager.files[resolvedFilename].options.multiple + && !importOptions.multiple) { + + fileParsedFunc(null, importManager.files[resolvedFilename].root, resolvedFilename); } - }); - } - if (promise) { - promise.then(loadFileCallback, fileParsedFunc); + else { + new Parser(newEnv, importManager, newFileInfo).parse(contents, (e, root) => { + fileParsedFunc(e, root, resolvedFilename); + }); + } + } + }; + let promise; + const context = utils.clone(this.context); + + if (tryAppendExtension) { + context.ext = importOptions.isPlugin ? '.js' : '.less'; + } + + if (importOptions.isPlugin) { + context.mime = 'application/javascript'; + promise = pluginLoader.loadPlugin(path, currentFileInfo.currentDirectory, context, environment, fileManager); + } + else { + promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, context, environment, + (err, loadedFile) => { + if (err) { + fileParsedFunc(err); + } else { + loadFileCallback(loadedFile); + } + }); + } + if (promise) { + promise.then(loadFileCallback, fileParsedFunc); + } } + } - }; return ImportManager; }; diff --git a/lib/less/index.js b/lib/less/index.js index b1b63f718..7f4121546 100644 --- a/lib/less/index.js +++ b/lib/less/index.js @@ -1,42 +1,79 @@ -module.exports = function(environment, fileManagers) { - var SourceMapOutput, SourceMapBuilder, ParseTree, ImportManager, Environment; +import data from './data'; +import tree from './tree'; +import Environment from './environment/environment'; +import AbstractFileManager from './environment/abstract-file-manager'; +import AbstractPluginLoader from './environment/abstract-plugin-loader'; +import visitors from './visitors'; +import Parser from './parser/parser'; +import Functions from './functions'; +import contexts from './contexts'; +import sourceMapOutput from './source-map-output'; +import sourceMapBuilder from './source-map-builder'; +import parseTree from './parse-tree'; +import importManager from './import-manager'; +import Render from './render'; +import Parse from './parse'; +import LessError from './less-error'; +import transformTree from './transform-tree'; +import * as utils from './utils'; +import PluginManager from './plugin-manager'; +import logger from './logger'; - var initial = { - version: [3, 9, 0], - data: require('./data'), - tree: require('./tree'), - Environment: (Environment = require('./environment/environment')), - AbstractFileManager: require('./environment/abstract-file-manager'), - AbstractPluginLoader: require('./environment/abstract-plugin-loader'), - environment: (environment = new Environment(environment, fileManagers)), - visitors: require('./visitors'), - Parser: require('./parser/parser'), - functions: require('./functions')(environment), - contexts: require('./contexts'), - SourceMapOutput: (SourceMapOutput = require('./source-map-output')(environment)), - SourceMapBuilder: (SourceMapBuilder = require('./source-map-builder')(SourceMapOutput, environment)), - ParseTree: (ParseTree = require('./parse-tree')(SourceMapBuilder)), - ImportManager: (ImportManager = require('./import-manager')(environment)), - render: require('./render')(environment, ParseTree, ImportManager), - parse: require('./parse')(environment, ParseTree, ImportManager), - LessError: require('./less-error'), - transformTree: require('./transform-tree'), - utils: require('./utils'), - PluginManager: require('./plugin-manager'), - logger: require('./logger') +export default (environment, fileManagers) => { + /** + * @todo + * This original code could be improved quite a bit. + * Many classes / modules currently add side-effects / mutations to passed in objects, + * which makes it hard to refactor and reason about. + */ + environment = new Environment(environment, fileManagers); + + const SourceMapOutput = sourceMapOutput(environment); + const SourceMapBuilder = sourceMapBuilder(SourceMapOutput, environment); + const ParseTree = parseTree(SourceMapBuilder); + const ImportManager = importManager(environment); + const render = Render(environment, ParseTree, ImportManager); + const parse = Parse(environment, ParseTree, ImportManager); + const functions = Functions(environment); + + /** + * @todo + * This root properties / methods need to be organized. + * It's not clear what should / must be public and why. + */ + const initial = { + version: [3, 10, 0], + data, + tree, + Environment, + AbstractFileManager, + AbstractPluginLoader, + environment, + visitors, + Parser, + functions, + contexts, + SourceMapOutput, + SourceMapBuilder, + ParseTree, + ImportManager, + render, + parse, + LessError, + transformTree, + utils, + PluginManager, + logger }; // Create a public API - - var ctor = function(t) { - return function() { - var obj = Object.create(t.prototype); - t.apply(obj, Array.prototype.slice.call(arguments, 0)); - return obj; - }; + const ctor = t => function (...args) { + return new t(...args); }; - var t, api = Object.create(initial); - for (var n in initial.tree) { + + let t; + const api = Object.create(initial); + for (const n in initial.tree) { /* eslint guard-for-in: 0 */ t = initial.tree[n]; if (typeof t === 'function') { @@ -44,7 +81,7 @@ module.exports = function(environment, fileManagers) { } else { api[n] = Object.create(null); - for (var o in t) { + for (const o in t) { /* eslint guard-for-in: 0 */ api[n][o.toLowerCase()] = ctor(t[o]); } diff --git a/lib/less/less-error.js b/lib/less/less-error.js index 151455026..a9a0f2f19 100644 --- a/lib/less/less-error.js +++ b/lib/less/less-error.js @@ -1,4 +1,4 @@ -var utils = require('./utils'); +import * as utils from './utils'; /** * This is a centralized class of any error that could be thrown internally (mostly by the parser). * Besides standard .message it keeps some additional data like a path to the file where the error @@ -21,21 +21,21 @@ var utils = require('./utils'); * @param {Object} fileContentMap - An object with file contents in 'contents' property (like importManager) @todo - move to fileManager? * @param {string} [currentFilename] */ -var LessError = module.exports = function LessError(e, fileContentMap, currentFilename) { +const LessError = function LessError(e, fileContentMap, currentFilename) { Error.call(this); - var filename = e.filename || currentFilename; + const filename = e.filename || currentFilename; this.message = e.message; this.stack = e.stack; if (fileContentMap && filename) { - var input = fileContentMap.contents[filename], - loc = utils.getLocation(e.index, input), - line = loc.line, - col = loc.column, - callLine = e.call && utils.getLocation(e.call, input).line, - lines = input ? input.split('\n') : ''; + const input = fileContentMap.contents[filename]; + const loc = utils.getLocation(e.index, input); + const line = loc.line; + const col = loc.column; + const callLine = e.call && utils.getLocation(e.call, input).line; + const lines = input ? input.split('\n') : ''; this.type = e.type || 'Syntax'; this.filename = filename; @@ -44,7 +44,7 @@ var LessError = module.exports = function LessError(e, fileContentMap, currentFi this.column = col; if (!this.line && this.stack) { - var found = this.stack.match(/(|Function):(\d+):(\d+)/); + const found = this.stack.match(/(|Function):(\d+):(\d+)/); if (found) { if (found[2]) { @@ -64,13 +64,12 @@ var LessError = module.exports = function LessError(e, fileContentMap, currentFi lines[this.line - 1], lines[this.line] ]; - } }; if (typeof Object.create === 'undefined') { - var F = function () {}; + const F = () => {}; F.prototype = Error.prototype; LessError.prototype = new F(); } else { @@ -86,28 +85,26 @@ LessError.prototype.constructor = LessError; * @param {Object} options * @returns {string} */ -LessError.prototype.toString = function(options) { - options = options || {}; - - var message = ''; - var extract = this.extract || []; - var error = []; - var stylize = function (str) { return str; }; +LessError.prototype.toString = function(options = {}) { + let message = ''; + const extract = this.extract || []; + let error = []; + let stylize = str => str; if (options.stylize) { - var type = typeof options.stylize; + const type = typeof options.stylize; if (type !== 'function') { - throw Error('options.stylize should be a function, got a ' + type + '!'); + throw Error(`options.stylize should be a function, got a ${type}!`); } stylize = options.stylize; } if (this.line !== null) { if (typeof extract[0] === 'string') { - error.push(stylize((this.line - 1) + ' ' + extract[0], 'grey')); + error.push(stylize(`${this.line - 1} ${extract[0]}`, 'grey')); } if (typeof extract[1] === 'string') { - var errorTxt = this.line + ' '; + let errorTxt = `${this.line} `; if (extract[1]) { errorTxt += extract[1].slice(0, this.column) + stylize(stylize(stylize(extract[1].substr(this.column, 1), 'bold') + @@ -117,25 +114,27 @@ LessError.prototype.toString = function(options) { } if (typeof extract[2] === 'string') { - error.push(stylize((this.line + 1) + ' ' + extract[2], 'grey')); + error.push(stylize(`${this.line + 1} ${extract[2]}`, 'grey')); } - error = error.join('\n') + stylize('', 'reset') + '\n'; + error = `${error.join('\n') + stylize('', 'reset')}\n`; } - message += stylize(this.type + 'Error: ' + this.message, 'red'); + message += stylize(`${this.type}Error: ${this.message}`, 'red'); if (this.filename) { message += stylize(' in ', 'red') + this.filename; } if (this.line) { - message += stylize(' on line ' + this.line + ', column ' + (this.column + 1) + ':', 'grey'); + message += stylize(` on line ${this.line}, column ${this.column + 1}:`, 'grey'); } - message += '\n' + error; + message += `\n${error}`; if (this.callLine) { - message += stylize('from ', 'red') + (this.filename || '') + '/n'; - message += stylize(this.callLine, 'grey') + ' ' + this.callExtract + '/n'; + message += `${stylize('from ', 'red') + (this.filename || '')}/n`; + message += `${stylize(this.callLine, 'grey')} ${this.callExtract}/n`; } return message; }; + +export default LessError; \ No newline at end of file diff --git a/lib/less/logger.js b/lib/less/logger.js index 621e57e24..ea83d7fdc 100644 --- a/lib/less/logger.js +++ b/lib/less/logger.js @@ -1,4 +1,4 @@ -module.exports = { +export default { error: function(msg) { this._fireEvent('error', msg); }, @@ -15,7 +15,7 @@ module.exports = { this._listeners.push(listener); }, removeListener: function(listener) { - for (var i = 0; i < this._listeners.length; i++) { + for (let i = 0; i < this._listeners.length; i++) { if (this._listeners[i] === listener) { this._listeners.splice(i, 1); return; @@ -23,8 +23,8 @@ module.exports = { } }, _fireEvent: function(type, msg) { - for (var i = 0; i < this._listeners.length; i++) { - var logFunction = this._listeners[i][type]; + for (let i = 0; i < this._listeners.length; i++) { + const logFunction = this._listeners[i][type]; if (logFunction) { logFunction(msg); } diff --git a/lib/less/parse-tree.js b/lib/less/parse-tree.js index d601af987..462de6fd5 100644 --- a/lib/less/parse-tree.js +++ b/lib/less/parse-tree.js @@ -1,60 +1,66 @@ -var LessError = require('./less-error'), - transformTree = require('./transform-tree'), - logger = require('./logger'); - -module.exports = function(SourceMapBuilder) { - var ParseTree = function(root, imports) { - this.root = root; - this.imports = imports; - }; - - ParseTree.prototype.toCSS = function(options) { - var evaldRoot, result = {}, sourceMapBuilder; - try { - evaldRoot = transformTree(this.root, options); - } catch (e) { - throw new LessError(e, this.imports); +import LessError from './less-error'; +import transformTree from './transform-tree'; +import logger from './logger'; + +export default SourceMapBuilder => { + class ParseTree { + constructor(root, imports) { + this.root = root; + this.imports = imports; } - try { - var compress = Boolean(options.compress); - if (compress) { - logger.warn('The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.'); + toCSS(options) { + let evaldRoot; + const result = {}; + let sourceMapBuilder; + try { + evaldRoot = transformTree(this.root, options); + } catch (e) { + throw new LessError(e, this.imports); } - var toCSSOptions = { - compress: compress, - dumpLineNumbers: options.dumpLineNumbers, - strictUnits: Boolean(options.strictUnits), - numPrecision: 8}; + try { + const compress = Boolean(options.compress); + if (compress) { + logger.warn('The compress option has been deprecated. ' + + 'We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.'); + } - if (options.sourceMap) { - sourceMapBuilder = new SourceMapBuilder(options.sourceMap); - result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports); - } else { - result.css = evaldRoot.toCSS(toCSSOptions); + const toCSSOptions = { + compress, + dumpLineNumbers: options.dumpLineNumbers, + strictUnits: Boolean(options.strictUnits), + numPrecision: 8}; + + if (options.sourceMap) { + sourceMapBuilder = new SourceMapBuilder(options.sourceMap); + result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports); + } else { + result.css = evaldRoot.toCSS(toCSSOptions); + } + } catch (e) { + throw new LessError(e, this.imports); } - } catch (e) { - throw new LessError(e, this.imports); - } - if (options.pluginManager) { - var postProcessors = options.pluginManager.getPostProcessors(); - for (var i = 0; i < postProcessors.length; i++) { - result.css = postProcessors[i].process(result.css, { sourceMap: sourceMapBuilder, options: options, imports: this.imports }); + if (options.pluginManager) { + const postProcessors = options.pluginManager.getPostProcessors(); + for (let i = 0; i < postProcessors.length; i++) { + result.css = postProcessors[i].process(result.css, { sourceMap: sourceMapBuilder, options, imports: this.imports }); + } + } + if (options.sourceMap) { + result.map = sourceMapBuilder.getExternalSourceMap(); } - } - if (options.sourceMap) { - result.map = sourceMapBuilder.getExternalSourceMap(); - } - result.imports = []; - for (var file in this.imports.files) { - if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) { - result.imports.push(file); + result.imports = []; + for (const file in this.imports.files) { + if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) { + result.imports.push(file); + } } + return result; } - return result; - }; + } + return ParseTree; }; diff --git a/lib/less/parse.js b/lib/less/parse.js index 623e70431..159dd956f 100644 --- a/lib/less/parse.js +++ b/lib/less/parse.js @@ -1,12 +1,12 @@ -var PromiseConstructor, - contexts = require('./contexts'), - Parser = require('./parser/parser'), - PluginManager = require('./plugin-manager'), - LessError = require('./less-error'), - utils = require('./utils'); +let PromiseConstructor; +import contexts from './contexts'; +import Parser from './parser/parser'; +import PluginManager from './plugin-manager'; +import LessError from './less-error'; +import * as utils from './utils'; -module.exports = function(environment, ParseTree, ImportManager) { - var parse = function (input, options, callback) { +export default (environment, ParseTree, ImportManager) => { + const parse = function (input, options, callback) { if (typeof options === 'function') { callback = options; @@ -17,12 +17,9 @@ module.exports = function(environment, ParseTree, ImportManager) { } if (!callback) { - if (!PromiseConstructor) { - PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise; - } - var self = this; - return new PromiseConstructor(function (resolve, reject) { - parse.call(self, input, options, function(err, output) { + const self = this; + return new Promise((resolve, reject) => { + parse.call(self, input, options, (err, output) => { if (err) { reject(err); } else { @@ -31,9 +28,9 @@ module.exports = function(environment, ParseTree, ImportManager) { }); }); } else { - var context, - rootFileInfo, - pluginManager = new PluginManager(this, !options.reUsePluginManager); + let context; + let rootFileInfo; + const pluginManager = new PluginManager(this, !options.reUsePluginManager); options.pluginManager = pluginManager; @@ -42,14 +39,14 @@ module.exports = function(environment, ParseTree, ImportManager) { if (options.rootFileInfo) { rootFileInfo = options.rootFileInfo; } else { - var filename = options.filename || 'input'; - var entryPath = filename.replace(/[^\/\\]*$/, ''); + const filename = options.filename || 'input'; + const entryPath = filename.replace(/[^\/\\]*$/, ''); rootFileInfo = { - filename: filename, + filename, rewriteUrls: context.rewriteUrls, rootpath: context.rootpath || '', currentDirectory: entryPath, - entryPath: entryPath, + entryPath, rootFilename: filename }; // add in a missing trailing slash @@ -58,15 +55,16 @@ module.exports = function(environment, ParseTree, ImportManager) { } } - var imports = new ImportManager(this, context, rootFileInfo); + const imports = new ImportManager(this, context, rootFileInfo); this.importManager = imports; // TODO: allow the plugins to be just a list of paths or names // Do an async plugin queue like lessc if (options.plugins) { - options.plugins.forEach(function(plugin) { - var evalResult, contents; + options.plugins.forEach(plugin => { + let evalResult; + let contents; if (plugin.fileContent) { contents = plugin.fileContent.replace(/^\uFEFF/, ''); evalResult = pluginManager.Loader.evalPlugin(contents, context, imports, plugin.options, plugin.filename); @@ -81,7 +79,7 @@ module.exports = function(environment, ParseTree, ImportManager) { } new Parser(context, imports, rootFileInfo) - .parse(input, function (e, root) { + .parse(input, (e, root) => { if (e) { return callback(e); } callback(null, root, imports, options); }, options); diff --git a/lib/less/parser/chunker.js b/lib/less/parser/chunker.js index 6a674758f..9c35f3f5a 100644 --- a/lib/less/parser/chunker.js +++ b/lib/less/parser/chunker.js @@ -1,12 +1,22 @@ // Split the input into chunks. -module.exports = function (input, fail) { - var len = input.length, level = 0, parenLevel = 0, - lastOpening, lastOpeningParen, lastMultiComment, lastMultiCommentEndBrace, - chunks = [], emitFrom = 0, - chunkerCurrentIndex, currentChunkStartIndex, cc, cc2, matched; +export default (input, fail) => { + const len = input.length; + let level = 0; + let parenLevel = 0; + let lastOpening; + let lastOpeningParen; + let lastMultiComment; + let lastMultiCommentEndBrace; + const chunks = []; + let emitFrom = 0; + let chunkerCurrentIndex; + let currentChunkStartIndex; + let cc; + let cc2; + let matched; function emitChunk(force) { - var len = chunkerCurrentIndex - emitFrom; + const len = chunkerCurrentIndex - emitFrom; if (((len < 512) && !force) || !len) { return; } @@ -64,7 +74,7 @@ module.exports = function (input, fail) { } } if (matched) { continue; } - return fail('unmatched `' + String.fromCharCode(cc) + '`', currentChunkStartIndex); + return fail(`unmatched \`${String.fromCharCode(cc)}\``, currentChunkStartIndex); case 47: // /, check for comment if (parenLevel || (chunkerCurrentIndex == len - 1)) { continue; } cc2 = input.charCodeAt(chunkerCurrentIndex + 1); diff --git a/lib/less/parser/parser-input.js b/lib/less/parser/parser-input.js index 436fd0448..8e93a38a7 100644 --- a/lib/less/parser/parser-input.js +++ b/lib/less/parser/parser-input.js @@ -1,32 +1,50 @@ -var chunker = require('./chunker'); - -module.exports = function() { - var input, // Less input string - j, // current chunk - saveStack = [], // holds state for backtracking - furthest, // furthest index the parser has gone to - furthestPossibleErrorMessage, // if this is furthest we got to, this is the probably cause - chunks, // chunkified input - current, // current chunk - currentPos, // index of current chunk, in `input` - parserInput = {}; - - var CHARCODE_SPACE = 32, - CHARCODE_TAB = 9, - CHARCODE_LF = 10, - CHARCODE_CR = 13, - CHARCODE_PLUS = 43, - CHARCODE_COMMA = 44, - CHARCODE_FORWARD_SLASH = 47, - CHARCODE_9 = 57; +import chunker from './chunker'; + +export default () => { + let // Less input string + input; + + let // current chunk + j; + + const // holds state for backtracking + saveStack = []; + + let // furthest index the parser has gone to + furthest; + + let // if this is furthest we got to, this is the probably cause + furthestPossibleErrorMessage; + + let // chunkified input + chunks; + + let // current chunk + current; + + let // index of current chunk, in `input` + currentPos; + + const parserInput = {}; + const CHARCODE_SPACE = 32; + const CHARCODE_TAB = 9; + const CHARCODE_LF = 10; + const CHARCODE_CR = 13; + const CHARCODE_PLUS = 43; + const CHARCODE_COMMA = 44; + const CHARCODE_FORWARD_SLASH = 47; + const CHARCODE_9 = 57; function skipWhitespace(length) { - var oldi = parserInput.i, oldj = j, - curr = parserInput.i - currentPos, - endIndex = parserInput.i + current.length - curr, - mem = (parserInput.i += length), - inp = input, - c, nextChar, comment; + const oldi = parserInput.i; + const oldj = j; + const curr = parserInput.i - currentPos; + const endIndex = parserInput.i + current.length - curr; + const mem = (parserInput.i += length); + const inp = input; + let c; + let nextChar; + let comment; for (; parserInput.i < endIndex; parserInput.i++) { c = inp.charCodeAt(parserInput.i); @@ -35,7 +53,7 @@ module.exports = function() { nextChar = inp.charAt(parserInput.i + 1); if (nextChar === '/') { comment = {index: parserInput.i, isLineComment: true}; - var nextNewLine = inp.indexOf('\n', parserInput.i + 2); + let nextNewLine = inp.indexOf('\n', parserInput.i + 2); if (nextNewLine < 0) { nextNewLine = endIndex; } @@ -44,7 +62,7 @@ module.exports = function() { parserInput.commentStore.push(comment); continue; } else if (nextChar === '*') { - var nextStarSlash = inp.indexOf('*/', parserInput.i + 2); + const nextStarSlash = inp.indexOf('*/', parserInput.i + 2); if (nextStarSlash >= 0) { comment = { index: parserInput.i, @@ -79,38 +97,38 @@ module.exports = function() { return oldi !== parserInput.i || oldj !== j; } - parserInput.save = function() { + parserInput.save = () => { currentPos = parserInput.i; - saveStack.push( { current: current, i: parserInput.i, j: j }); + saveStack.push( { current, i: parserInput.i, j }); }; - parserInput.restore = function(possibleErrorMessage) { + parserInput.restore = possibleErrorMessage => { if (parserInput.i > furthest || (parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage)) { furthest = parserInput.i; furthestPossibleErrorMessage = possibleErrorMessage; } - var state = saveStack.pop(); + const state = saveStack.pop(); current = state.current; currentPos = parserInput.i = state.i; j = state.j; }; - parserInput.forget = function() { + parserInput.forget = () => { saveStack.pop(); }; - parserInput.isWhitespace = function (offset) { - var pos = parserInput.i + (offset || 0), - code = input.charCodeAt(pos); + parserInput.isWhitespace = offset => { + const pos = parserInput.i + (offset || 0); + const code = input.charCodeAt(pos); return (code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF); }; // Specialization of $(tok) - parserInput.$re = function(tok) { + parserInput.$re = tok => { if (parserInput.i > currentPos) { current = current.slice(parserInput.i - currentPos); currentPos = parserInput.i; } - var m = tok.exec(current); + const m = tok.exec(current); if (!m) { return null; } @@ -123,7 +141,7 @@ module.exports = function() { return m.length === 1 ? m[0] : m; }; - parserInput.$char = function(tok) { + parserInput.$char = tok => { if (input.charAt(parserInput.i) !== tok) { return null; } @@ -131,11 +149,11 @@ module.exports = function() { return tok; }; - parserInput.$str = function(tok) { - var tokLength = tok.length; + parserInput.$str = tok => { + const tokLength = tok.length; // https://jsperf.com/string-startswith/21 - for (var i = 0; i < tokLength; i++) { + for (let i = 0; i < tokLength; i++) { if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { return null; } @@ -145,18 +163,18 @@ module.exports = function() { return tok; }; - parserInput.$quoted = function(loc) { - var pos = loc || parserInput.i, - startChar = input.charAt(pos); + parserInput.$quoted = loc => { + const pos = loc || parserInput.i; + const startChar = input.charAt(pos); if (startChar !== '\'' && startChar !== '"') { return; } - var length = input.length, - currentPosition = pos; + const length = input.length; + const currentPosition = pos; - for (var i = 1; i + currentPosition < length; i++) { - var nextChar = input.charAt(i + currentPosition); + for (let i = 1; i + currentPosition < length; i++) { + const nextChar = input.charAt(i + currentPosition); switch (nextChar) { case '\\': i++; @@ -165,7 +183,7 @@ module.exports = function() { case '\n': break; case startChar: - var str = input.substr(currentPosition, i + 1); + const str = input.substr(currentPosition, i + 1); if (!loc && loc !== 0) { skipWhitespace(i + 1); return str @@ -181,32 +199,29 @@ module.exports = function() { * Permissive parsing. Ignores everything except matching {} [] () and quotes * until matching token (outside of blocks) */ - parserInput.$parseUntil = function(tok) { - var quote = '', - returnVal = null, - inComment = false, - blockDepth = 0, - blockStack = [], - parseGroups = [], - length = input.length, - startPos = parserInput.i, - lastPos = parserInput.i, - i = parserInput.i, - loop = true, - testChar; + parserInput.$parseUntil = tok => { + let quote = ''; + let returnVal = null; + let inComment = false; + let blockDepth = 0; + const blockStack = []; + const parseGroups = []; + const length = input.length; + const startPos = parserInput.i; + let lastPos = parserInput.i; + let i = parserInput.i; + let loop = true; + let testChar; if (typeof tok === 'string') { - testChar = function(char) { - return char === tok; - } + testChar = char => char === tok } else { - testChar = function(char) { - return tok.test(char); - } + testChar = char => tok.test(char) } do { - var prevChar, nextChar = input.charAt(i); + let prevChar; + let nextChar = input.charAt(i); if (blockDepth === 0 && testChar(nextChar)) { returnVal = input.substr(lastPos, i - lastPos); if (returnVal) { @@ -272,7 +287,7 @@ module.exports = function() { case '}': case ')': case ']': - var expected = blockStack.pop(); + const expected = blockStack.pop(); if (nextChar === expected) { blockDepth--; } else { @@ -299,10 +314,10 @@ module.exports = function() { // Same as $(), but don't change the state of the parser, // just return the match. - parserInput.peek = function(tok) { + parserInput.peek = tok => { if (typeof tok === 'string') { // https://jsperf.com/string-startswith/21 - for (var i = 0; i < tok.length; i++) { + for (let i = 0; i < tok.length; i++) { if (input.charAt(parserInput.i + i) !== tok.charAt(i)) { return false; } @@ -315,29 +330,21 @@ module.exports = function() { // Specialization of peek() // TODO remove or change some currentChar calls to peekChar - parserInput.peekChar = function(tok) { - return input.charAt(parserInput.i) === tok; - }; + parserInput.peekChar = tok => input.charAt(parserInput.i) === tok; - parserInput.currentChar = function() { - return input.charAt(parserInput.i); - }; + parserInput.currentChar = () => input.charAt(parserInput.i); - parserInput.prevChar = function() { - return input.charAt(parserInput.i - 1); - }; + parserInput.prevChar = () => input.charAt(parserInput.i - 1); - parserInput.getInput = function() { - return input; - }; + parserInput.getInput = () => input; - parserInput.peekNotNumeric = function() { - var c = input.charCodeAt(parserInput.i); + parserInput.peekNotNumeric = () => { + const c = input.charCodeAt(parserInput.i); // Is the first char of the dimension 0-9, '.', '+' or '-' return (c > CHARCODE_9 || c < CHARCODE_PLUS) || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA; }; - parserInput.start = function(str, chunkInput, failFunction) { + parserInput.start = (str, chunkInput, failFunction) => { input = str; parserInput.i = j = currentPos = furthest = 0; @@ -362,16 +369,16 @@ module.exports = function() { skipWhitespace(0); }; - parserInput.end = function() { - var message, - isFinished = parserInput.i >= input.length; + parserInput.end = () => { + let message; + const isFinished = parserInput.i >= input.length; if (parserInput.i < furthest) { message = furthestPossibleErrorMessage; parserInput.i = furthest; } return { - isFinished: isFinished, + isFinished, furthest: parserInput.i, furthestPossibleErrorMessage: message, furthestReachedEnd: parserInput.i >= input.length - 1, diff --git a/lib/less/parser/parser.js b/lib/less/parser/parser.js index 1faa1116a..44e194805 100644 --- a/lib/less/parser/parser.js +++ b/lib/less/parser/parser.js @@ -1,9 +1,9 @@ -var LessError = require('../less-error'), - tree = require('../tree'), - visitors = require('../visitors'), - getParserInput = require('./parser-input'), - utils = require('../utils'), - functionRegistry = require('../functions/function-registry'); +import LessError from '../less-error'; +import tree from '../tree'; +import visitors from '../visitors'; +import getParserInput from './parser-input'; +import * as utils from '../utils'; +import functionRegistry from '../functions/function-registry'; // // less.js - parser @@ -38,9 +38,9 @@ var LessError = require('../less-error'), // It also takes care of moving all the indices forwards. // -var Parser = function Parser(context, imports, fileInfo) { - var parsers, - parserInput = getParserInput(); +const Parser = function Parser(context, imports, fileInfo) { + let parsers; + const parserInput = getParserInput(); function error(msg, type) { throw new LessError( @@ -56,13 +56,13 @@ var Parser = function Parser(context, imports, fileInfo) { function expect(arg, msg) { // some older browsers return typeof 'function' for RegExp - var result = (arg instanceof Function) ? arg.call(parsers) : parserInput.$re(arg); + const result = (arg instanceof Function) ? arg.call(parsers) : parserInput.$re(arg); if (result) { return result; } error(msg || (typeof arg === 'string' - ? 'expected \'' + arg + '\' got \'' + parserInput.currentChar() + '\'' + ? `expected '${arg}' got '${parserInput.currentChar()}'` : 'unexpected token')); } @@ -71,11 +71,11 @@ var Parser = function Parser(context, imports, fileInfo) { if (parserInput.$char(arg)) { return arg; } - error(msg || 'expected \'' + arg + '\' got \'' + parserInput.currentChar() + '\''); + error(msg || `expected '${arg}' got '${parserInput.currentChar()}'`); } function getDebugInfo(index) { - var filename = fileInfo.filename; + const filename = fileInfo.filename; return { lineNumber: utils.getLocation(index, parserInput.getInput()).line + 1, @@ -92,8 +92,9 @@ var Parser = function Parser(context, imports, fileInfo) { * @param {Object} fileInfo - fileInfo to attach to created nodes */ function parseNode(str, parseList, currentIndex, fileInfo, callback) { - var result, returnNodes = []; - var parser = parserInput; + let result; + const returnNodes = []; + const parser = parserInput; try { parser.start(str, false, function fail(msg, index) { @@ -102,7 +103,7 @@ var Parser = function Parser(context, imports, fileInfo) { index: index + currentIndex }); }); - for (var x = 0, p, i; (p = parseList[x]); x++) { + for (let x = 0, p, i; (p = parseList[x]); x++) { i = parser.i; result = parsers[p](); if (result) { @@ -115,7 +116,7 @@ var Parser = function Parser(context, imports, fileInfo) { } } - var endInfo = parser.end(); + const endInfo = parser.end(); if (endInfo.isFinished) { callback(null, returnNodes); } @@ -129,15 +130,15 @@ var Parser = function Parser(context, imports, fileInfo) { }, imports, fileInfo.filename); } } - + // // The Parser // return { - parserInput: parserInput, - imports: imports, - fileInfo: fileInfo, - parseNode: parseNode, + parserInput, + imports, + fileInfo, + parseNode, // // Parse an input string into an abstract syntax tree, // @param str A string containing 'less' markup @@ -145,15 +146,20 @@ var Parser = function Parser(context, imports, fileInfo) { // @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply // parse: function (str, callback, additionalData) { - var root, error = null, globalVars, modifyVars, ignored, preText = ''; + let root; + let error = null; + let globalVars; + let modifyVars; + let ignored; + let preText = ''; - globalVars = (additionalData && additionalData.globalVars) ? Parser.serializeVars(additionalData.globalVars) + '\n' : ''; - modifyVars = (additionalData && additionalData.modifyVars) ? '\n' + Parser.serializeVars(additionalData.modifyVars) : ''; + globalVars = (additionalData && additionalData.globalVars) ? `${Parser.serializeVars(additionalData.globalVars)}\n` : ''; + modifyVars = (additionalData && additionalData.modifyVars) ? `\n${Parser.serializeVars(additionalData.modifyVars)}` : ''; if (context.pluginManager) { - var preProcessors = context.pluginManager.getPreProcessors(); - for (var i = 0; i < preProcessors.length; i++) { - str = preProcessors[i].process(str, { context: context, imports: imports, fileInfo: fileInfo }); + const preProcessors = context.pluginManager.getPreProcessors(); + for (let i = 0; i < preProcessors.length; i++) { + str = preProcessors[i].process(str, { context, imports, fileInfo }); } } @@ -176,7 +182,7 @@ var Parser = function Parser(context, imports, fileInfo) { try { parserInput.start(str, context.chunkInput, function fail(msg, index) { throw new LessError({ - index: index, + index, type: 'Parse', message: msg, filename: fileInfo.filename @@ -202,10 +208,10 @@ var Parser = function Parser(context, imports, fileInfo) { // showing the line where the parse error occurred. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. - var endInfo = parserInput.end(); + const endInfo = parserInput.end(); if (!endInfo.isFinished) { - var message = endInfo.furthestPossibleErrorMessage; + let message = endInfo.furthestPossibleErrorMessage; if (!message) { message = 'Unrecognised input'; @@ -220,13 +226,13 @@ var Parser = function Parser(context, imports, fileInfo) { error = new LessError({ type: 'Parse', - message: message, + message, index: endInfo.furthest, filename: fileInfo.filename }, imports); } - var finish = function (e) { + const finish = e => { e = error || e || imports.error; if (e) { @@ -295,7 +301,9 @@ var Parser = function Parser(context, imports, fileInfo) { // block rule: at the root level. // primary: function () { - var mixin = this.mixin, root = [], node; + const mixin = this.mixin; + let root = []; + let node; while (true) { while (true) { @@ -322,7 +330,7 @@ var Parser = function Parser(context, imports, fileInfo) { if (node) { root.push(node); } else { - var foundSemiColon = false; + let foundSemiColon = false; while (parserInput.$char(';')) { foundSemiColon = true; } @@ -339,7 +347,7 @@ var Parser = function Parser(context, imports, fileInfo) { // where the current structure allows it comment: function () { if (parserInput.commentStore.length) { - var comment = parserInput.commentStore.shift(); + const comment = parserInput.commentStore.shift(); return new(tree.Comment)(comment.text, comment.isLineComment, comment.index, fileInfo); } }, @@ -357,7 +365,9 @@ var Parser = function Parser(context, imports, fileInfo) { // "milky way" 'he\'s the one!' // quoted: function (forceEscaped) { - var str, index = parserInput.i, isEscaped = false; + let str; + const index = parserInput.i; + let isEscaped = false; parserInput.save(); if (parserInput.$char('~')) { @@ -383,7 +393,7 @@ var Parser = function Parser(context, imports, fileInfo) { // black border-collapse // keyword: function () { - var k = parserInput.$char('%') || parserInput.$re(/^\[?(?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+\]?/); + const k = parserInput.$char('%') || parserInput.$re(/^\[?(?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+\]?/); if (k) { return tree.Color.fromKeyword(k) || new(tree.Keyword)(k); } @@ -397,7 +407,10 @@ var Parser = function Parser(context, imports, fileInfo) { // The arguments are parsed with the `entities.arguments` parser. // call: function () { - var name, args, func, index = parserInput.i; + let name; + let args; + let func; + const index = parserInput.i; // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 if (parserInput.peek(/^url\(/i)) { @@ -430,7 +443,7 @@ var Parser = function Parser(context, imports, fileInfo) { } parserInput.forget(); - + return new(tree.Call)(name, args, index, fileInfo); }, @@ -455,9 +468,9 @@ var Parser = function Parser(context, imports, fileInfo) { function f(parse, stop) { return { - parse: parse, // parsing function - stop: stop // when true - stop after parse() and return its result, - // otherwise continue for plain args + parse, // parsing function + stop // when true - stop after parse() and return its result, + // otherwise continue for plain args }; } @@ -467,9 +480,10 @@ var Parser = function Parser(context, imports, fileInfo) { }, arguments: function (prevArgs) { - var argsComma = prevArgs || [], - argsSemiColon = [], - isSemiColonSeparated, value; + let argsComma = prevArgs || []; + const argsSemiColon = []; + let isSemiColonSeparated; + let value; parserInput.save(); @@ -519,7 +533,8 @@ var Parser = function Parser(context, imports, fileInfo) { // assignment: function () { - var key, value; + let key; + let value; parserInput.save(); key = parserInput.$re(/^\w+(?=\s?=)/i); if (!key) { @@ -547,7 +562,8 @@ var Parser = function Parser(context, imports, fileInfo) { // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { - var value, index = parserInput.i; + let value; + const index = parserInput.i; parserInput.autoCommentAbsorb = false; @@ -578,14 +594,16 @@ var Parser = function Parser(context, imports, fileInfo) { // see `parsers.variable`. // variable: function () { - var ch, name, index = parserInput.i; + let ch; + let name; + const index = parserInput.i; parserInput.save(); if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^@@?[\w-]+/))) { ch = parserInput.currentChar(); if (ch === '(' || ch === '[' && !parserInput.prevChar().match(/^\s/)) { // this may be a VariableCall lookup - var result = parsers.variableCall(name); + const result = parsers.variableCall(name); if (result) { parserInput.forget(); return result; @@ -599,10 +617,11 @@ var Parser = function Parser(context, imports, fileInfo) { // A variable entity using the protective {} e.g. @{var} variableCurly: function () { - var curly, index = parserInput.i; + let curly; + const index = parserInput.i; if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\{([\w-]+)\}/))) { - return new(tree.Variable)('@' + curly[1], index, fileInfo); + return new(tree.Variable)(`@${curly[1]}`, index, fileInfo); } }, // @@ -611,7 +630,8 @@ var Parser = function Parser(context, imports, fileInfo) { // background-color: $color // property: function () { - var name, index = parserInput.i; + let name; + const index = parserInput.i; if (parserInput.currentChar() === '$' && (name = parserInput.$re(/^\$[\w-]+/))) { return new(tree.Property)(name, index, fileInfo); @@ -620,10 +640,11 @@ var Parser = function Parser(context, imports, fileInfo) { // A property entity useing the protective {} e.g. ${prop} propertyCurly: function () { - var curly, index = parserInput.i; + let curly; + const index = parserInput.i; if (parserInput.currentChar() === '$' && (curly = parserInput.$re(/^\$\{([\w-]+)\}/))) { - return new(tree.Property)('$' + curly[1], index, fileInfo); + return new(tree.Property)(`$${curly[1]}`, index, fileInfo); } }, // @@ -634,7 +655,7 @@ var Parser = function Parser(context, imports, fileInfo) { // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { - var rgb; + let rgb; parserInput.save(); if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})([\w.#\[])?/))) { @@ -648,16 +669,16 @@ var Parser = function Parser(context, imports, fileInfo) { colorKeyword: function () { parserInput.save(); - var autoCommentAbsorb = parserInput.autoCommentAbsorb; + const autoCommentAbsorb = parserInput.autoCommentAbsorb; parserInput.autoCommentAbsorb = false; - var k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/); + const k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/); parserInput.autoCommentAbsorb = autoCommentAbsorb; if (!k) { parserInput.forget(); return; } parserInput.restore(); - var color = tree.Color.fromKeyword(k); + const color = tree.Color.fromKeyword(k); if (color) { parserInput.$str(k); return color; @@ -674,7 +695,7 @@ var Parser = function Parser(context, imports, fileInfo) { return; } - var value = parserInput.$re(/^([+-]?\d*\.?\d+)(%|[a-z_]+)?/i); + const value = parserInput.$re(/^([+-]?\d*\.?\d+)(%|[a-z_]+)?/i); if (value) { return new(tree.Dimension)(value[1], value[2]); } @@ -686,7 +707,7 @@ var Parser = function Parser(context, imports, fileInfo) { // U+0?? or U+00A1-00A9 // unicodeDescriptor: function () { - var ud; + let ud; ud = parserInput.$re(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/); if (ud) { @@ -700,12 +721,13 @@ var Parser = function Parser(context, imports, fileInfo) { // `window.location.href` // javascript: function () { - var js, index = parserInput.i; + let js; + const index = parserInput.i; parserInput.save(); - var escape = parserInput.$char('~'); - var jsQuote = parserInput.$char('`'); + const escape = parserInput.$char('~'); + const jsQuote = parserInput.$char('`'); if (!jsQuote) { parserInput.restore(); @@ -727,7 +749,7 @@ var Parser = function Parser(context, imports, fileInfo) { // @fink: // variable: function () { - var name; + let name; if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) { return name[1]; } }, @@ -741,8 +763,11 @@ var Parser = function Parser(context, imports, fileInfo) { // color: @fink[@color]; // variableCall: function (parsedName) { - var lookups, important, i = parserInput.i, - inValue = !!parsedName, name = parsedName; + let lookups; + let important; + const i = parserInput.i; + const inValue = !!parsedName; + let name = parsedName; parserInput.save(); @@ -764,7 +789,7 @@ var Parser = function Parser(context, imports, fileInfo) { important = true; } - var call = new tree.VariableCall(name, i, fileInfo); + const call = new tree.VariableCall(name, i, fileInfo); if (!inValue && parsers.end()) { parserInput.forget(); return call; @@ -782,7 +807,12 @@ var Parser = function Parser(context, imports, fileInfo) { // extend syntax - used to extend selectors // extend: function(isRule) { - var elements, e, index = parserInput.i, option, extendList, extend; + let elements; + let e; + const index = parserInput.i; + let option; + let extendList; + let extend; if (!parserInput.$str(isRule ? '&:extend(' : ':extend(')) { return; @@ -852,8 +882,13 @@ var Parser = function Parser(context, imports, fileInfo) { // selector for now. // call: function (inValue, getLookup) { - var s = parserInput.currentChar(), important = false, lookups, - index = parserInput.i, elements, args, hasParens; + const s = parserInput.currentChar(); + let important = false; + let lookups; + const index = parserInput.i; + let elements; + let args; + let hasParens; if (s !== '.' && s !== '#') { return; } @@ -888,7 +923,7 @@ var Parser = function Parser(context, imports, fileInfo) { if (inValue || parsers.end()) { parserInput.forget(); - var mixin = new(tree.mixin.Call)(elements, args, index, fileInfo, !lookups && important); + const mixin = new(tree.mixin.Call)(elements, args, index, fileInfo, !lookups && important); if (lookups) { return new tree.NamespaceValue(mixin, lookups, important); } @@ -905,8 +940,12 @@ var Parser = function Parser(context, imports, fileInfo) { * (Start with . or # and can have > ) */ elements: function() { - var elements, e, c, elem, elemIndex, - re = /^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/; + let elements; + let e; + let c; + let elem; + let elemIndex; + const re = /^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/; while (true) { elemIndex = parserInput.i; e = parserInput.$re(re); @@ -925,11 +964,19 @@ var Parser = function Parser(context, imports, fileInfo) { return elements; }, args: function (isCall) { - var entities = parsers.entities, - returner = { args:null, variadic: false }, - expressions = [], argsSemiColon = [], argsComma = [], - isSemiColonSeparated, expressionContainsNamed, name, nameLoop, - value, arg, expand, hasSep = true; + const entities = parsers.entities; + const returner = { args:null, variadic: false }; + let expressions = []; + const argsSemiColon = []; + const argsComma = []; + let isSemiColonSeparated; + let expressionContainsNamed; + let name; + let nameLoop; + let value; + let arg; + let expand; + let hasSep = true; parserInput.save(); @@ -959,7 +1006,7 @@ var Parser = function Parser(context, imports, fileInfo) { arg.throwAwayComments(); } value = arg; - var val = null; + let val = null; if (isCall) { // Variable @@ -1013,7 +1060,7 @@ var Parser = function Parser(context, imports, fileInfo) { expressions.push(value); } - argsComma.push({ name:nameLoop, value:value, expand:expand }); + argsComma.push({ name:nameLoop, value, expand }); if (parserInput.$char(',')) { hasSep = true; @@ -1032,7 +1079,7 @@ var Parser = function Parser(context, imports, fileInfo) { if (expressions.length > 1) { value = new(tree.Value)(expressions); } - argsSemiColon.push({ name:name, value:value, expand:expand }); + argsSemiColon.push({ name, value, expand }); name = null; expressions = []; @@ -1064,7 +1111,12 @@ var Parser = function Parser(context, imports, fileInfo) { // the `{...}` block. // definition: function () { - var name, params = [], match, ruleset, cond, variadic = false; + let name; + let params = []; + let match; + let ruleset; + let cond; + let variadic = false; if ((parserInput.currentChar() !== '.' && parserInput.currentChar() !== '#') || parserInput.peek(/^[^{]*\}/)) { return; @@ -1076,7 +1128,7 @@ var Parser = function Parser(context, imports, fileInfo) { if (match) { name = match[1]; - var argInfo = this.args(false); + const argInfo = this.args(false); params = argInfo.args; variadic = argInfo.variadic; @@ -1110,12 +1162,14 @@ var Parser = function Parser(context, imports, fileInfo) { }, ruleLookups: function() { - var rule, args, lookups = []; + let rule; + let args; + const lookups = []; if (parserInput.currentChar() !== '[') { return; } - + while (true) { parserInput.save(); args = null; @@ -1140,7 +1194,7 @@ var Parser = function Parser(context, imports, fileInfo) { return; } - var name = parserInput.$re(/^(?:[@$]{0,2})[_a-zA-Z0-9-]*/); + const name = parserInput.$re(/^(?:[@$]{0,2})[_a-zA-Z0-9-]*/); if (!parserInput.$char(']')) { parserInput.restore(); @@ -1160,7 +1214,7 @@ var Parser = function Parser(context, imports, fileInfo) { // and can be found inside a rule's value. // entity: function () { - var entities = this.entities; + const entities = this.entities; return this.comment() || entities.literal() || entities.variable() || entities.url() || entities.property() || entities.call() || entities.keyword() || this.mixin.call(true) || @@ -1182,17 +1236,17 @@ var Parser = function Parser(context, imports, fileInfo) { // alpha(opacity=88) // ieAlpha: function () { - var value; + let value; // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18 if (!parserInput.$re(/^opacity=/i)) { return; } value = parserInput.$re(/^\d+/); if (!value) { value = expect(parsers.entities.variable, 'Could not parse alpha'); - value = '@{' + value.name.slice(1) + '}'; + value = `@{${value.name.slice(1)}}`; } expectChar(')'); - return new tree.Quoted('', 'alpha(opacity=' + value + ')'); + return new tree.Quoted('', `alpha(opacity=${value})`); }, // @@ -1208,7 +1262,10 @@ var Parser = function Parser(context, imports, fileInfo) { // and an element name, such as a tag a class, or `*`. // element: function () { - var e, c, v, index = parserInput.i; + let e; + let c; + let v; + const index = parserInput.i; c = this.combinator(); @@ -1245,11 +1302,11 @@ var Parser = function Parser(context, imports, fileInfo) { // we deal with this in *combinator.js*. // combinator: function () { - var c = parserInput.currentChar(); + let c = parserInput.currentChar(); if (c === '/') { parserInput.save(); - var slashedCombinator = parserInput.$re(/^\/[a-z]+\//i); + const slashedCombinator = parserInput.$re(/^\/[a-z]+\//i); if (slashedCombinator) { parserInput.forget(); return new(tree.Combinator)(slashedCombinator); @@ -1281,7 +1338,14 @@ var Parser = function Parser(context, imports, fileInfo) { // Selectors are made out of one or more Elements, see above. // selector: function (isLess) { - var index = parserInput.i, elements, extendList, c, e, allExtends, when, condition; + const index = parserInput.i; + let elements; + let extendList; + let c; + let e; + let allExtends; + let when; + let condition; isLess = isLess !== false; while ((isLess && (extendList = this.extend())) || (isLess && (when = parserInput.$str('when'))) || (e = this.element())) { if (when) { @@ -1313,7 +1377,8 @@ var Parser = function Parser(context, imports, fileInfo) { if (allExtends) { error('Extend must be used to extend a selector, it cannot be used on its own'); } }, selectors: function () { - var s, selectors; + let s; + let selectors; while (true) { s = this.selector(); if (!s) { @@ -1339,8 +1404,10 @@ var Parser = function Parser(context, imports, fileInfo) { attribute: function () { if (!parserInput.$char('[')) { return; } - var entities = this.entities, - key, val, op; + const entities = this.entities; + let key; + let val; + let op; if (!(key = entities.variableCurly())) { key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/); @@ -1361,14 +1428,14 @@ var Parser = function Parser(context, imports, fileInfo) { // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { - var content; + let content; if (parserInput.$char('{') && (content = this.primary()) && parserInput.$char('}')) { return content; } }, blockRuleset: function() { - var block = this.block(); + let block = this.block(); if (block) { block = new tree.Ruleset(null, block); @@ -1377,7 +1444,9 @@ var Parser = function Parser(context, imports, fileInfo) { }, detachedRuleset: function() { - var argInfo, params, variadic; + let argInfo; + let params; + let variadic; parserInput.save(); if (parserInput.$re(/^[.#]\(/)) { @@ -1395,7 +1464,7 @@ var Parser = function Parser(context, imports, fileInfo) { return; } } - var blockRuleset = this.blockRuleset(); + const blockRuleset = this.blockRuleset(); if (blockRuleset) { parserInput.forget(); if (params) { @@ -1410,7 +1479,9 @@ var Parser = function Parser(context, imports, fileInfo) { // div, .class, body > p {...} // ruleset: function () { - var selectors, rules, debugInfo; + let selectors; + let rules; + let debugInfo; parserInput.save(); @@ -1422,7 +1493,7 @@ var Parser = function Parser(context, imports, fileInfo) { if (selectors && (rules = this.block())) { parserInput.forget(); - var ruleset = new(tree.Ruleset)(selectors, rules, context.strictImports); + const ruleset = new(tree.Ruleset)(selectors, rules, context.strictImports); if (context.dumpLineNumbers) { ruleset.debugInfo = debugInfo; } @@ -1432,8 +1503,14 @@ var Parser = function Parser(context, imports, fileInfo) { } }, declaration: function () { - var name, value, index = parserInput.i, hasDR, - c = parserInput.currentChar(), important, merge, isVariable; + let name; + let value; + const index = parserInput.i; + let hasDR; + const c = parserInput.currentChar(); + let important; + let merge; + let isVariable; if (c === '.' || c === '#' || c === '&' || c === ':') { return; } @@ -1469,7 +1546,7 @@ var Parser = function Parser(context, imports, fileInfo) { if (value) { parserInput.forget(); // anonymous values absorb the end ';' which is required for them to work - return new (tree.Declaration)(name, value, false, merge, index, fileInfo); + return new(tree.Declaration)(name, value, false, merge, index, fileInfo); } if (!value) { @@ -1486,7 +1563,7 @@ var Parser = function Parser(context, imports, fileInfo) { if (value && (this.end() || hasDR)) { parserInput.forget(); - return new (tree.Declaration)(name, value, important, merge, index, fileInfo); + return new(tree.Declaration)(name, value, important, merge, index, fileInfo); } else { parserInput.restore(); @@ -1496,8 +1573,8 @@ var Parser = function Parser(context, imports, fileInfo) { } }, anonymousValue: function () { - var index = parserInput.i; - var match = parserInput.$re(/^([^.#@\$+\/'"*`(;{}-]*);/); + const index = parserInput.i; + const match = parserInput.$re(/^([^.#@\$+\/'"*`(;{}-]*);/); if (match) { return new(tree.Anonymous)(match[1], index); } @@ -1512,12 +1589,16 @@ var Parser = function Parser(context, imports, fileInfo) { * math is allowed. */ permissiveValue: function (untilTokens) { - var i, e, done, value, - tok = untilTokens || ';', - index = parserInput.i, result = []; + let i; + let e; + let done; + let value; + const tok = untilTokens || ';'; + const index = parserInput.i; + const result = []; function testCurrentChar() { - var char = parserInput.currentChar(); + const char = parserInput.currentChar(); if (typeof tok === 'string') { return char === tok; } else { @@ -1541,7 +1622,7 @@ var Parser = function Parser(context, imports, fileInfo) { } while (e); done = testCurrentChar(); - + if (value.length > 0) { value = new(tree.Expression)(value); if (done) { @@ -1556,18 +1637,18 @@ var Parser = function Parser(context, imports, fileInfo) { } } parserInput.save(); - + value = parserInput.$parseUntil(tok); if (value) { if (typeof value === 'string') { - error('Expected \'' + value + '\'', 'Parse'); + error(`Expected '${value}'`, 'Parse'); } if (value.length === 1 && value[0] === ' ') { parserInput.forget(); return new tree.Anonymous('', index); } - var item; + let item; for (i = 0; i < value.length; i++) { item = value[i]; if (Array.isArray(item)) { @@ -1579,7 +1660,7 @@ var Parser = function Parser(context, imports, fileInfo) { item = item.trim(); } // Treat like quoted values, but replace vars like unquoted expressions - var quote = new tree.Quoted('\'', item, true, index, fileInfo); + const quote = new tree.Quoted('\'', item, true, index, fileInfo); quote.variableRegex = /@([\w-]+)/g; quote.propRegex = /\$([\w-]+)/g; result.push(quote); @@ -1602,12 +1683,14 @@ var Parser = function Parser(context, imports, fileInfo) { // stored in `import`, which we pass to the Import constructor. // 'import': function () { - var path, features, index = parserInput.i; + let path; + let features; + const index = parserInput.i; - var dir = parserInput.$re(/^@import?\s+/); + const dir = parserInput.$re(/^@import?\s+/); if (dir) { - var options = (dir ? this.importOptions() : null) || {}; + const options = (dir ? this.importOptions() : null) || {}; if ((path = this.entities.quoted() || this.entities.url())) { features = this.mediaFeatures(); @@ -1627,7 +1710,10 @@ var Parser = function Parser(context, imports, fileInfo) { }, importOptions: function() { - var o, options = {}, optionName, value; + let o; + const options = {}; + let optionName; + let value; // list of options, surrounded by parens if (!parserInput.$char('(')) { return null; } @@ -1655,14 +1741,17 @@ var Parser = function Parser(context, imports, fileInfo) { }, importOption: function() { - var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/); + const opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/); if (opt) { return opt[1]; } }, mediaFeature: function () { - var entities = this.entities, nodes = [], e, p; + const entities = this.entities; + const nodes = []; + let e; + let p; parserInput.save(); do { e = entities.keyword() || entities.variable() || entities.mixinLookup(); @@ -1692,7 +1781,9 @@ var Parser = function Parser(context, imports, fileInfo) { }, mediaFeatures: function () { - var entities = this.entities, features = [], e; + const entities = this.entities; + const features = []; + let e; do { e = this.mediaFeature(); if (e) { @@ -1711,7 +1802,11 @@ var Parser = function Parser(context, imports, fileInfo) { }, media: function () { - var features, rules, media, debugInfo, index = parserInput.i; + let features; + let rules; + let media; + let debugInfo; + const index = parserInput.i; if (context.dumpLineNumbers) { debugInfo = getDebugInfo(index); @@ -1748,9 +1843,11 @@ var Parser = function Parser(context, imports, fileInfo) { // @plugin (args) "lib"; // plugin: function () { - var path, args, options, - index = parserInput.i, - dir = parserInput.$re(/^@plugin?\s+/); + let path; + let args; + let options; + const index = parserInput.i; + const dir = parserInput.$re(/^@plugin?\s+/); if (dir) { args = this.pluginArgs(); @@ -1787,7 +1884,7 @@ var Parser = function Parser(context, imports, fileInfo) { parserInput.restore(); return null; } - var args = parserInput.$re(/^\s*([^\);]+)\)\s*/); + const args = parserInput.$re(/^\s*([^\);]+)\)\s*/); if (args[1]) { parserInput.forget(); return args[1].trim(); @@ -1804,8 +1901,16 @@ var Parser = function Parser(context, imports, fileInfo) { // @charset "utf-8"; // atrule: function () { - var index = parserInput.i, name, value, rules, nonVendorSpecificName, - hasIdentifier, hasExpression, hasUnknown, hasBlock = true, isRooted = true; + const index = parserInput.i; + let name; + let value; + let rules; + let nonVendorSpecificName; + let hasIdentifier; + let hasExpression; + let hasUnknown; + let hasBlock = true; + let isRooted = true; if (parserInput.currentChar() !== '@') { return; } @@ -1822,7 +1927,7 @@ var Parser = function Parser(context, imports, fileInfo) { nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { - nonVendorSpecificName = '@' + name.slice(name.indexOf('-', 2) + 1); + nonVendorSpecificName = `@${name.slice(name.indexOf('-', 2) + 1)}`; } switch (nonVendorSpecificName) { @@ -1853,19 +1958,19 @@ var Parser = function Parser(context, imports, fileInfo) { if (hasIdentifier) { value = this.entity(); if (!value) { - error('expected ' + name + ' identifier'); + error(`expected ${name} identifier`); } } else if (hasExpression) { value = this.expression(); if (!value) { - error('expected ' + name + ' expression'); + error(`expected ${name} expression`); } } else if (hasUnknown) { value = this.permissiveValue(/^[{;]/); hasBlock = (parserInput.currentChar() === '{'); if (!value) { if (!hasBlock && parserInput.currentChar() !== ';') { - error(name + ' rule is missing block or ending semi-colon'); + error(`${name} rule is missing block or ending semi-colon`); } } else if (!value.value) { @@ -1879,7 +1984,7 @@ var Parser = function Parser(context, imports, fileInfo) { if (rules || (!hasBlock && value && parserInput.$char(';'))) { parserInput.forget(); - return new (tree.AtRule)(name, value, rules, index, fileInfo, + return new(tree.AtRule)(name, value, rules, index, fileInfo, context.dumpLineNumbers ? getDebugInfo(index) : null, isRooted ); @@ -1897,7 +2002,9 @@ var Parser = function Parser(context, imports, fileInfo) { // and before the `;`. // value: function () { - var e, expressions = [], index = parserInput.i; + let e; + const expressions = []; + const index = parserInput.i; do { e = this.expression(); @@ -1917,7 +2024,8 @@ var Parser = function Parser(context, imports, fileInfo) { } }, sub: function () { - var a, e; + let a; + let e; parserInput.save(); if (parserInput.$char('(')) { @@ -1934,7 +2042,11 @@ var Parser = function Parser(context, imports, fileInfo) { parserInput.restore(); }, multiplication: function () { - var m, a, op, operation, isSpaced; + let m; + let a; + let op; + let operation; + let isSpaced; m = this.operand(); if (m) { isSpaced = parserInput.isWhitespace(-1); @@ -1963,7 +2075,11 @@ var Parser = function Parser(context, imports, fileInfo) { } }, addition: function () { - var m, a, op, operation, isSpaced; + let m; + let a; + let op; + let operation; + let isSpaced; m = this.multiplication(); if (m) { isSpaced = parserInput.isWhitespace(-1); @@ -1986,7 +2102,10 @@ var Parser = function Parser(context, imports, fileInfo) { } }, conditions: function () { - var a, b, index = parserInput.i, condition; + let a; + let b; + const index = parserInput.i; + let condition; a = this.condition(true); if (a) { @@ -2004,7 +2123,9 @@ var Parser = function Parser(context, imports, fileInfo) { } }, condition: function (needsParens) { - var result, logical, next; + let result; + let logical; + let next; function or() { return parserInput.$str('or'); } @@ -2025,9 +2146,12 @@ var Parser = function Parser(context, imports, fileInfo) { return result; }, conditionAnd: function (needsParens) { - var result, logical, next, self = this; + let result; + let logical; + let next; + const self = this; function insideCondition() { - var cond = self.negatedCondition(needsParens) || self.parenthesisCondition(needsParens); + const cond = self.negatedCondition(needsParens) || self.parenthesisCondition(needsParens); if (!cond && !needsParens) { return self.atomicCondition(needsParens); } @@ -2054,7 +2178,7 @@ var Parser = function Parser(context, imports, fileInfo) { }, negatedCondition: function (needsParens) { if (parserInput.$str('not')) { - var result = this.parenthesisCondition(needsParens); + const result = this.parenthesisCondition(needsParens); if (result) { result.negate = !result.negate; } @@ -2063,7 +2187,7 @@ var Parser = function Parser(context, imports, fileInfo) { }, parenthesisCondition: function (needsParens) { function tryConditionFollowedByParenthesis(me) { - var body; + let body; parserInput.save(); body = me.condition(needsParens); if (!body) { @@ -2078,7 +2202,7 @@ var Parser = function Parser(context, imports, fileInfo) { return body; } - var body; + let body; parserInput.save(); if (!parserInput.$str('(')) { parserInput.restore(); @@ -2096,14 +2220,19 @@ var Parser = function Parser(context, imports, fileInfo) { return ; } if (!parserInput.$char(')')) { - parserInput.restore('expected \')\' got \'' + parserInput.currentChar() + '\''); + parserInput.restore(`expected ')' got '${parserInput.currentChar()}'`); return ; } parserInput.forget(); return body; }, atomicCondition: function (needsParens) { - var entities = this.entities, index = parserInput.i, a, b, c, op; + const entities = this.entities; + const index = parserInput.i; + let a; + let b; + let c; + let op; function cond() { return this.addition() || entities.keyword() || entities.quoted() || entities.mixinLookup(); @@ -2154,13 +2283,14 @@ var Parser = function Parser(context, imports, fileInfo) { // such as a Color, or a Variable // operand: function () { - var entities = this.entities, negate; + const entities = this.entities; + let negate; if (parserInput.peek(/^-[@\$\(]/)) { negate = parserInput.$char('-'); } - var o = this.sub() || entities.dimension() || + let o = this.sub() || entities.dimension() || entities.color() || entities.variable() || entities.property() || entities.call() || entities.quoted(true) || entities.colorKeyword() || @@ -2182,7 +2312,10 @@ var Parser = function Parser(context, imports, fileInfo) { // @var * 2 // expression: function () { - var entities = [], e, delim, index = parserInput.i; + const entities = []; + let e; + let delim; + const index = parserInput.i; do { e = this.comment(); @@ -2207,17 +2340,20 @@ var Parser = function Parser(context, imports, fileInfo) { } }, property: function () { - var name = parserInput.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/); + const name = parserInput.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/); if (name) { return name[1]; } }, ruleProperty: function () { - var name = [], index = [], s, k; + let name = []; + const index = []; + let s; + let k; parserInput.save(); - var simpleProperty = parserInput.$re(/^([_a-zA-Z0-9-]+)\s*:/); + const simpleProperty = parserInput.$re(/^([_a-zA-Z0-9-]+)\s*:/); if (simpleProperty) { name = [new(tree.Keyword)(simpleProperty[1])]; parserInput.forget(); @@ -2225,8 +2361,8 @@ var Parser = function Parser(context, imports, fileInfo) { } function match(re) { - var i = parserInput.i, - chunk = parserInput.$re(re); + const i = parserInput.i; + const chunk = parserInput.$re(re); if (chunk) { index.push(i); return name.push(chunk[1]); @@ -2254,8 +2390,8 @@ var Parser = function Parser(context, imports, fileInfo) { name[k] = (s.charAt(0) !== '@' && s.charAt(0) !== '$') ? new(tree.Keyword)(s) : (s.charAt(0) === '@' ? - new(tree.Variable)('@' + s.slice(2, -1), index[k], fileInfo) : - new(tree.Property)('$' + s.slice(2, -1), index[k], fileInfo)); + new(tree.Variable)(`@${s.slice(2, -1)}`, index[k], fileInfo) : + new(tree.Property)(`$${s.slice(2, -1)}`, index[k], fileInfo)); } return name; } @@ -2264,18 +2400,17 @@ var Parser = function Parser(context, imports, fileInfo) { } }; }; -Parser.serializeVars = function(vars) { - var s = ''; +Parser.serializeVars = vars => { + let s = ''; - for (var name in vars) { + for (const name in vars) { if (Object.hasOwnProperty.call(vars, name)) { - var value = vars[name]; - s += ((name[0] === '@') ? '' : '@') + name + ': ' + value + - ((String(value).slice(-1) === ';') ? '' : ';'); + const value = vars[name]; + s += `${((name[0] === '@') ? '' : '@') + name}: ${value}${(String(value).slice(-1) === ';') ? '' : ';'}`; } } return s; }; -module.exports = Parser; +export default Parser; diff --git a/lib/less/plugin-manager.js b/lib/less/plugin-manager.js index 7431c5b1f..977b1c5ee 100644 --- a/lib/less/plugin-manager.js +++ b/lib/less/plugin-manager.js @@ -1,155 +1,168 @@ /** * Plugin Manager */ -var PluginManager = function(less) { - this.less = less; - this.visitors = []; - this.preProcessors = []; - this.postProcessors = []; - this.installedPlugins = []; - this.fileManagers = []; - this.iterator = -1; - this.pluginCache = {}; - this.Loader = new less.PluginLoader(less); -}; +class PluginManager { + constructor(less) { + this.less = less; + this.visitors = []; + this.preProcessors = []; + this.postProcessors = []; + this.installedPlugins = []; + this.fileManagers = []; + this.iterator = -1; + this.pluginCache = {}; + this.Loader = new less.PluginLoader(less); + } -var pm, PluginManagerFactory = function(less, newFactory) { - if (newFactory || !pm) { - pm = new PluginManager(less); + /** + * Adds all the plugins in the array + * @param {Array} plugins + */ + addPlugins(plugins) { + if (plugins) { + for (let i = 0; i < plugins.length; i++) { + this.addPlugin(plugins[i]); + } } - return pm; - }; + } -/** - * Adds all the plugins in the array - * @param {Array} plugins - */ -PluginManager.prototype.addPlugins = function(plugins) { - if (plugins) { - for (var i = 0; i < plugins.length; i++) { - this.addPlugin(plugins[i]); + /** + * + * @param plugin + * @param {String} filename + */ + addPlugin(plugin, filename, functionRegistry) { + this.installedPlugins.push(plugin); + if (filename) { + this.pluginCache[filename] = plugin; + } + if (plugin.install) { + plugin.install(this.less, this, functionRegistry || this.less.functions.functionRegistry); } } -}; -/** - * - * @param plugin - * @param {String} filename - */ -PluginManager.prototype.addPlugin = function(plugin, filename, functionRegistry) { - this.installedPlugins.push(plugin); - if (filename) { - this.pluginCache[filename] = plugin; + + /** + * + * @param filename + */ + get(filename) { + return this.pluginCache[filename]; } - if (plugin.install) { - plugin.install(this.less, this, functionRegistry || this.less.functions.functionRegistry); + + /** + * Adds a visitor. The visitor object has options on itself to determine + * when it should run. + * @param visitor + */ + addVisitor(visitor) { + this.visitors.push(visitor); } -}; -/** - * - * @param filename - */ -PluginManager.prototype.get = function(filename) { - return this.pluginCache[filename]; -}; -/** - * Adds a visitor. The visitor object has options on itself to determine - * when it should run. - * @param visitor - */ -PluginManager.prototype.addVisitor = function(visitor) { - this.visitors.push(visitor); -}; -/** - * Adds a pre processor object - * @param {object} preProcessor - * @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import - */ -PluginManager.prototype.addPreProcessor = function(preProcessor, priority) { - var indexToInsertAt; - for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) { - if (this.preProcessors[indexToInsertAt].priority >= priority) { - break; + /** + * Adds a pre processor object + * @param {object} preProcessor + * @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import + */ + addPreProcessor(preProcessor, priority) { + let indexToInsertAt; + for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) { + if (this.preProcessors[indexToInsertAt].priority >= priority) { + break; + } } + this.preProcessors.splice(indexToInsertAt, 0, {preProcessor, priority}); } - this.preProcessors.splice(indexToInsertAt, 0, {preProcessor: preProcessor, priority: priority}); -}; -/** - * Adds a post processor object - * @param {object} postProcessor - * @param {number} priority - guidelines 1 = before compression, 1000 = compression, 2000 = after compression - */ -PluginManager.prototype.addPostProcessor = function(postProcessor, priority) { - var indexToInsertAt; - for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) { - if (this.postProcessors[indexToInsertAt].priority >= priority) { - break; + + /** + * Adds a post processor object + * @param {object} postProcessor + * @param {number} priority - guidelines 1 = before compression, 1000 = compression, 2000 = after compression + */ + addPostProcessor(postProcessor, priority) { + let indexToInsertAt; + for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) { + if (this.postProcessors[indexToInsertAt].priority >= priority) { + break; + } } + this.postProcessors.splice(indexToInsertAt, 0, {postProcessor, priority}); } - this.postProcessors.splice(indexToInsertAt, 0, {postProcessor: postProcessor, priority: priority}); -}; -/** - * - * @param manager - */ -PluginManager.prototype.addFileManager = function(manager) { - this.fileManagers.push(manager); -}; -/** - * - * @returns {Array} - * @private - */ -PluginManager.prototype.getPreProcessors = function() { - var preProcessors = []; - for (var i = 0; i < this.preProcessors.length; i++) { - preProcessors.push(this.preProcessors[i].preProcessor); + + /** + * + * @param manager + */ + addFileManager(manager) { + this.fileManagers.push(manager); } - return preProcessors; -}; -/** - * - * @returns {Array} - * @private - */ -PluginManager.prototype.getPostProcessors = function() { - var postProcessors = []; - for (var i = 0; i < this.postProcessors.length; i++) { - postProcessors.push(this.postProcessors[i].postProcessor); + + /** + * + * @returns {Array} + * @private + */ + getPreProcessors() { + const preProcessors = []; + for (let i = 0; i < this.preProcessors.length; i++) { + preProcessors.push(this.preProcessors[i].preProcessor); + } + return preProcessors; } - return postProcessors; -}; -/** - * - * @returns {Array} - * @private - */ -PluginManager.prototype.getVisitors = function() { - return this.visitors; -}; -PluginManager.prototype.visitor = function() { - var self = this; - return { - first: function() { - self.iterator = -1; - return self.visitors[self.iterator]; - }, - get: function() { - self.iterator += 1; - return self.visitors[self.iterator]; + /** + * + * @returns {Array} + * @private + */ + getPostProcessors() { + const postProcessors = []; + for (let i = 0; i < this.postProcessors.length; i++) { + postProcessors.push(this.postProcessors[i].postProcessor); } - }; -}; -/** - * - * @returns {Array} - * @private - */ -PluginManager.prototype.getFileManagers = function() { - return this.fileManagers; + return postProcessors; + } + + /** + * + * @returns {Array} + * @private + */ + getVisitors() { + return this.visitors; + } + + visitor() { + const self = this; + return { + first: function() { + self.iterator = -1; + return self.visitors[self.iterator]; + }, + get: function() { + self.iterator += 1; + return self.visitors[self.iterator]; + } + }; + } + + /** + * + * @returns {Array} + * @private + */ + getFileManagers() { + return this.fileManagers; + } +} + +let pm; + +function PluginManagerFactory(less, newFactory) { + if (newFactory || !pm) { + pm = new PluginManager(less); + } + return pm; }; // -module.exports = PluginManagerFactory; +export default PluginManagerFactory; diff --git a/lib/less/render.js b/lib/less/render.js index 8ea6f9eaa..faa8d5e45 100644 --- a/lib/less/render.js +++ b/lib/less/render.js @@ -1,8 +1,8 @@ -var PromiseConstructor, - utils = require('./utils'); +let PromiseConstructor; +import * as utils from './utils'; -module.exports = function(environment, ParseTree, ImportManager) { - var render = function (input, options, callback) { +export default (environment, ParseTree, ImportManager) => { + const render = function (input, options, callback) { if (typeof options === 'function') { callback = options; options = utils.copyOptions(this.options, {}); @@ -12,12 +12,9 @@ module.exports = function(environment, ParseTree, ImportManager) { } if (!callback) { - if (!PromiseConstructor) { - PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise; - } - var self = this; - return new PromiseConstructor(function (resolve, reject) { - render.call(self, input, options, function(err, output) { + const self = this; + return new Promise((resolve, reject) => { + render.call(self, input, options, (err, output) => { if (err) { reject(err); } else { @@ -26,12 +23,12 @@ module.exports = function(environment, ParseTree, ImportManager) { }); }); } else { - this.parse(input, options, function(err, root, imports, options) { + this.parse(input, options, (err, root, imports, options) => { if (err) { return callback(err); } - var result; + let result; try { - var parseTree = new ParseTree(root, imports); + const parseTree = new ParseTree(root, imports); result = parseTree.toCSS(options); } catch (err) { return callback(err); } diff --git a/lib/less/source-map-builder.js b/lib/less/source-map-builder.js index 140396768..be798eb00 100644 --- a/lib/less/source-map-builder.js +++ b/lib/less/source-map-builder.js @@ -1,72 +1,77 @@ -module.exports = function (SourceMapOutput, environment) { +export default (SourceMapOutput, environment) => { + class SourceMapBuilder { + constructor(options) { + this.options = options; + } - var SourceMapBuilder = function (options) { - this.options = options; - }; + toCSS(rootNode, options, imports) { + const sourceMapOutput = new SourceMapOutput( + { + contentsIgnoredCharsMap: imports.contentsIgnoredChars, + rootNode, + contentsMap: imports.contents, + sourceMapFilename: this.options.sourceMapFilename, + sourceMapURL: this.options.sourceMapURL, + outputFilename: this.options.sourceMapOutputFilename, + sourceMapBasepath: this.options.sourceMapBasepath, + sourceMapRootpath: this.options.sourceMapRootpath, + outputSourceFiles: this.options.outputSourceFiles, + sourceMapGenerator: this.options.sourceMapGenerator, + sourceMapFileInline: this.options.sourceMapFileInline + }); - SourceMapBuilder.prototype.toCSS = function(rootNode, options, imports) { - var sourceMapOutput = new SourceMapOutput( - { - contentsIgnoredCharsMap: imports.contentsIgnoredChars, - rootNode: rootNode, - contentsMap: imports.contents, - sourceMapFilename: this.options.sourceMapFilename, - sourceMapURL: this.options.sourceMapURL, - outputFilename: this.options.sourceMapOutputFilename, - sourceMapBasepath: this.options.sourceMapBasepath, - sourceMapRootpath: this.options.sourceMapRootpath, - outputSourceFiles: this.options.outputSourceFiles, - sourceMapGenerator: this.options.sourceMapGenerator, - sourceMapFileInline: this.options.sourceMapFileInline - }); + const css = sourceMapOutput.toCSS(options); + this.sourceMap = sourceMapOutput.sourceMap; + this.sourceMapURL = sourceMapOutput.sourceMapURL; + if (this.options.sourceMapInputFilename) { + this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename); + } + if (this.options.sourceMapBasepath !== undefined && this.sourceMapURL !== undefined) { + this.sourceMapURL = sourceMapOutput.removeBasepath(this.sourceMapURL); + } + return css + this.getCSSAppendage(); + } + + getCSSAppendage() { + + let sourceMapURL = this.sourceMapURL; + if (this.options.sourceMapFileInline) { + if (this.sourceMap === undefined) { + return ''; + } + sourceMapURL = `data:application/json;base64,${environment.encodeBase64(this.sourceMap)}`; + } - var css = sourceMapOutput.toCSS(options); - this.sourceMap = sourceMapOutput.sourceMap; - this.sourceMapURL = sourceMapOutput.sourceMapURL; - if (this.options.sourceMapInputFilename) { - this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename); + if (sourceMapURL) { + return `/*# sourceMappingURL=${sourceMapURL} */`; + } + return ''; } - if (this.options.sourceMapBasepath !== undefined && this.sourceMapURL !== undefined) { - this.sourceMapURL = sourceMapOutput.removeBasepath(this.sourceMapURL); + + getExternalSourceMap() { + return this.sourceMap; } - return css + this.getCSSAppendage(); - }; - SourceMapBuilder.prototype.getCSSAppendage = function() { + setExternalSourceMap(sourceMap) { + this.sourceMap = sourceMap; + } - var sourceMapURL = this.sourceMapURL; - if (this.options.sourceMapFileInline) { - if (this.sourceMap === undefined) { - return ''; - } - sourceMapURL = 'data:application/json;base64,' + environment.encodeBase64(this.sourceMap); + isInline() { + return this.options.sourceMapFileInline; } - if (sourceMapURL) { - return '/*# sourceMappingURL=' + sourceMapURL + ' */'; + getSourceMapURL() { + return this.sourceMapURL; } - return ''; - }; - SourceMapBuilder.prototype.getExternalSourceMap = function() { - return this.sourceMap; - }; - SourceMapBuilder.prototype.setExternalSourceMap = function(sourceMap) { - this.sourceMap = sourceMap; - }; + getOutputFilename() { + return this.options.sourceMapOutputFilename; + } - SourceMapBuilder.prototype.isInline = function() { - return this.options.sourceMapFileInline; - }; - SourceMapBuilder.prototype.getSourceMapURL = function() { - return this.sourceMapURL; - }; - SourceMapBuilder.prototype.getOutputFilename = function() { - return this.options.sourceMapOutputFilename; - }; - SourceMapBuilder.prototype.getInputFilename = function() { - return this.sourceMapInputFilename; - }; + getInputFilename() { + return this.sourceMapInputFilename; + } + } return SourceMapBuilder; }; diff --git a/lib/less/source-map-output.js b/lib/less/source-map-output.js index 8659535e7..d30966e8e 100644 --- a/lib/less/source-map-output.js +++ b/lib/less/source-map-output.js @@ -1,149 +1,149 @@ -module.exports = function (environment) { - - var SourceMapOutput = function (options) { - this._css = []; - this._rootNode = options.rootNode; - this._contentsMap = options.contentsMap; - this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap; - if (options.sourceMapFilename) { - this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/'); - } - this._outputFilename = options.outputFilename; - this.sourceMapURL = options.sourceMapURL; - if (options.sourceMapBasepath) { - this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/'); - } - if (options.sourceMapRootpath) { - this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/'); - if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') { - this._sourceMapRootpath += '/'; +export default environment => { + class SourceMapOutput { + constructor(options) { + this._css = []; + this._rootNode = options.rootNode; + this._contentsMap = options.contentsMap; + this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap; + if (options.sourceMapFilename) { + this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/'); } - } else { - this._sourceMapRootpath = ''; - } - this._outputSourceFiles = options.outputSourceFiles; - this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator(); - - this._lineNumber = 0; - this._column = 0; - }; - - SourceMapOutput.prototype.removeBasepath = function(path) { - if (this._sourceMapBasepath && path.indexOf(this._sourceMapBasepath) === 0) { - path = path.substring(this._sourceMapBasepath.length); - if (path.charAt(0) === '\\' || path.charAt(0) === '/') { - path = path.substring(1); + this._outputFilename = options.outputFilename; + this.sourceMapURL = options.sourceMapURL; + if (options.sourceMapBasepath) { + this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/'); } - } - - return path; - }; + if (options.sourceMapRootpath) { + this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/'); + if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') { + this._sourceMapRootpath += '/'; + } + } else { + this._sourceMapRootpath = ''; + } + this._outputSourceFiles = options.outputSourceFiles; + this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator(); - SourceMapOutput.prototype.normalizeFilename = function(filename) { - filename = filename.replace(/\\/g, '/'); - filename = this.removeBasepath(filename); - return (this._sourceMapRootpath || '') + filename; - }; + this._lineNumber = 0; + this._column = 0; + } - SourceMapOutput.prototype.add = function(chunk, fileInfo, index, mapLines) { + removeBasepath(path) { + if (this._sourceMapBasepath && path.indexOf(this._sourceMapBasepath) === 0) { + path = path.substring(this._sourceMapBasepath.length); + if (path.charAt(0) === '\\' || path.charAt(0) === '/') { + path = path.substring(1); + } + } - // ignore adding empty strings - if (!chunk) { - return; + return path; } - var lines, - sourceLines, - columns, - sourceColumns, - i; - - if (fileInfo && fileInfo.filename) { - var inputSource = this._contentsMap[fileInfo.filename]; - - // remove vars/banner added to the top of the file - if (this._contentsIgnoredCharsMap[fileInfo.filename]) { - // adjust the index - index -= this._contentsIgnoredCharsMap[fileInfo.filename]; - if (index < 0) { index = 0; } - // adjust the source - inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]); - } + normalizeFilename(filename) { + filename = filename.replace(/\\/g, '/'); + filename = this.removeBasepath(filename); + return (this._sourceMapRootpath || '') + filename; + } - // ignore empty content - if (inputSource === undefined) { + add(chunk, fileInfo, index, mapLines) { + // ignore adding empty strings + if (!chunk) { return; } - inputSource = inputSource.substring(0, index); - sourceLines = inputSource.split('\n'); - sourceColumns = sourceLines[sourceLines.length - 1]; - } + let lines; + let sourceLines; + let columns; + let sourceColumns; + let i; + + if (fileInfo && fileInfo.filename) { + let inputSource = this._contentsMap[fileInfo.filename]; + + // remove vars/banner added to the top of the file + if (this._contentsIgnoredCharsMap[fileInfo.filename]) { + // adjust the index + index -= this._contentsIgnoredCharsMap[fileInfo.filename]; + if (index < 0) { index = 0; } + // adjust the source + inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]); + } + + // ignore empty content + if (inputSource === undefined) { + return; + } + + inputSource = inputSource.substring(0, index); + sourceLines = inputSource.split('\n'); + sourceColumns = sourceLines[sourceLines.length - 1]; + } - lines = chunk.split('\n'); - columns = lines[lines.length - 1]; + lines = chunk.split('\n'); + columns = lines[lines.length - 1]; - if (fileInfo && fileInfo.filename) { - if (!mapLines) { - this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column}, - original: { line: sourceLines.length, column: sourceColumns.length}, - source: this.normalizeFilename(fileInfo.filename)}); - } else { - for (i = 0; i < lines.length; i++) { - this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0}, - original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0}, + if (fileInfo && fileInfo.filename) { + if (!mapLines) { + this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column}, + original: { line: sourceLines.length, column: sourceColumns.length}, source: this.normalizeFilename(fileInfo.filename)}); + } else { + for (i = 0; i < lines.length; i++) { + this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0}, + original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0}, + source: this.normalizeFilename(fileInfo.filename)}); + } } } - } - - if (lines.length === 1) { - this._column += columns.length; - } else { - this._lineNumber += lines.length - 1; - this._column = columns.length; - } - this._css.push(chunk); - }; + if (lines.length === 1) { + this._column += columns.length; + } else { + this._lineNumber += lines.length - 1; + this._column = columns.length; + } - SourceMapOutput.prototype.isEmpty = function() { - return this._css.length === 0; - }; + this._css.push(chunk); + } - SourceMapOutput.prototype.toCSS = function(context) { - this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null }); + isEmpty() { + return this._css.length === 0; + } - if (this._outputSourceFiles) { - for (var filename in this._contentsMap) { - if (this._contentsMap.hasOwnProperty(filename)) { - var source = this._contentsMap[filename]; - if (this._contentsIgnoredCharsMap[filename]) { - source = source.slice(this._contentsIgnoredCharsMap[filename]); + toCSS(context) { + this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null }); + + if (this._outputSourceFiles) { + for (const filename in this._contentsMap) { + if (this._contentsMap.hasOwnProperty(filename)) { + let source = this._contentsMap[filename]; + if (this._contentsIgnoredCharsMap[filename]) { + source = source.slice(this._contentsIgnoredCharsMap[filename]); + } + this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source); } - this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source); } } - } - this._rootNode.genCSS(context, this); + this._rootNode.genCSS(context, this); + + if (this._css.length > 0) { + let sourceMapURL; + const sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON()); - if (this._css.length > 0) { - var sourceMapURL, - sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON()); + if (this.sourceMapURL) { + sourceMapURL = this.sourceMapURL; + } else if (this._sourceMapFilename) { + sourceMapURL = this._sourceMapFilename; + } + this.sourceMapURL = sourceMapURL; - if (this.sourceMapURL) { - sourceMapURL = this.sourceMapURL; - } else if (this._sourceMapFilename) { - sourceMapURL = this._sourceMapFilename; + this.sourceMap = sourceMapContent; } - this.sourceMapURL = sourceMapURL; - this.sourceMap = sourceMapContent; + return this._css.join(''); } - - return this._css.join(''); - }; + } return SourceMapOutput; }; diff --git a/lib/less/transform-tree.js b/lib/less/transform-tree.js index 3799da454..79eee5064 100644 --- a/lib/less/transform-tree.js +++ b/lib/less/transform-tree.js @@ -1,12 +1,11 @@ -var contexts = require('./contexts'), - visitor = require('./visitors'), - tree = require('./tree'); +import contexts from './contexts'; +import visitor from './visitors'; +import tree from './tree'; -module.exports = function(root, options) { - options = options || {}; - var evaldRoot, - variables = options.variables, - evalEnv = new contexts.Eval(options); +export default (root, options = {}) => { + let evaldRoot; + let variables = options.variables; + const evalEnv = new contexts.Eval(options); // // Allows setting variables with a hash, so: @@ -22,8 +21,8 @@ module.exports = function(root, options) { // ) // if (typeof variables === 'object' && !Array.isArray(variables)) { - variables = Object.keys(variables).map(function (k) { - var value = variables[k]; + variables = Object.keys(variables).map(k => { + let value = variables[k]; if (!(value instanceof tree.Value)) { if (!(value instanceof tree.Expression)) { @@ -31,17 +30,21 @@ module.exports = function(root, options) { } value = new tree.Value([value]); } - return new tree.Declaration('@' + k, value, false, null, 0); + return new tree.Declaration(`@${k}`, value, false, null, 0); }); evalEnv.frames = [new tree.Ruleset(null, variables)]; } - var visitors = [ - new visitor.JoinSelectorVisitor(), - new visitor.MarkVisibleSelectorsVisitor(true), - new visitor.ExtendVisitor(), - new visitor.ToCSSVisitor({compress: Boolean(options.compress)}) - ], preEvalVisitors = [], v, visitorIterator; + const visitors = [ + new visitor.JoinSelectorVisitor(), + new visitor.MarkVisibleSelectorsVisitor(true), + new visitor.ExtendVisitor(), + new visitor.ToCSSVisitor({compress: Boolean(options.compress)}) + ]; + + const preEvalVisitors = []; + let v; + let visitorIterator; /** * first() / get() allows visitors to be added while visiting @@ -72,7 +75,7 @@ module.exports = function(root, options) { } } } - + evaldRoot = root.eval(evalEnv); for (var i = 0; i < visitors.length; i++) { diff --git a/lib/less/tree/anonymous.js b/lib/less/tree/anonymous.js index 2e8edee5b..92bad4942 100644 --- a/lib/less/tree/anonymous.js +++ b/lib/less/tree/anonymous.js @@ -1,29 +1,37 @@ -var Node = require('./node'); +import Node from './node'; -var Anonymous = function (value, index, currentFileInfo, mapLines, rulesetLike, visibilityInfo) { - this.value = value; - this._index = index; - this._fileInfo = currentFileInfo; - this.mapLines = mapLines; - this.rulesetLike = (typeof rulesetLike === 'undefined') ? false : rulesetLike; - this.allowRoot = true; - this.copyVisibilityInfo(visibilityInfo); -}; -Anonymous.prototype = new Node(); -Anonymous.prototype.type = 'Anonymous'; -Anonymous.prototype.eval = function () { - return new Anonymous(this.value, this._index, this._fileInfo, this.mapLines, this.rulesetLike, this.visibilityInfo()); -}; -Anonymous.prototype.compare = function (other) { - return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; -}; -Anonymous.prototype.isRulesetLike = function() { - return this.rulesetLike; -}; -Anonymous.prototype.genCSS = function (context, output) { - this.nodeVisible = Boolean(this.value); - if (this.nodeVisible) { - output.add(this.value, this._fileInfo, this._index, this.mapLines); +class Anonymous extends Node { + constructor(value, index, currentFileInfo, mapLines, rulesetLike, visibilityInfo) { + super(); + + this.value = value; + this._index = index; + this._fileInfo = currentFileInfo; + this.mapLines = mapLines; + this.rulesetLike = (typeof rulesetLike === 'undefined') ? false : rulesetLike; + this.allowRoot = true; + this.copyVisibilityInfo(visibilityInfo); + } + + eval() { + return new Anonymous(this.value, this._index, this._fileInfo, this.mapLines, this.rulesetLike, this.visibilityInfo()); + } + + compare(other) { + return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; } -}; -module.exports = Anonymous; + + isRulesetLike() { + return this.rulesetLike; + } + + genCSS(context, output) { + this.nodeVisible = Boolean(this.value); + if (this.nodeVisible) { + output.add(this.value, this._fileInfo, this._index, this.mapLines); + } + } +} + +Anonymous.prototype.type = 'Anonymous'; +export default Anonymous; diff --git a/lib/less/tree/assignment.js b/lib/less/tree/assignment.js index 56e069131..0776f43a0 100644 --- a/lib/less/tree/assignment.js +++ b/lib/less/tree/assignment.js @@ -1,27 +1,33 @@ -var Node = require('./node'); +import Node from './node'; -var Assignment = function (key, val) { - this.key = key; - this.value = val; -}; +class Assignment extends Node { + constructor(key, val) { + super(); -Assignment.prototype = new Node(); -Assignment.prototype.type = 'Assignment'; -Assignment.prototype.accept = function (visitor) { - this.value = visitor.visit(this.value); -}; -Assignment.prototype.eval = function (context) { - if (this.value.eval) { - return new Assignment(this.key, this.value.eval(context)); + this.key = key; + this.value = val; + } + + accept(visitor) { + this.value = visitor.visit(this.value); + } + + eval(context) { + if (this.value.eval) { + return new Assignment(this.key, this.value.eval(context)); + } + return this; } - return this; -}; -Assignment.prototype.genCSS = function (context, output) { - output.add(this.key + '='); - if (this.value.genCSS) { - this.value.genCSS(context, output); - } else { - output.add(this.value); + + genCSS(context, output) { + output.add(`${this.key}=`); + if (this.value.genCSS) { + this.value.genCSS(context, output); + } else { + output.add(this.value); + } } -}; -module.exports = Assignment; +} + +Assignment.prototype.type = 'Assignment'; +export default Assignment; diff --git a/lib/less/tree/atrule.js b/lib/less/tree/atrule.js index 3dc300609..350a6f62a 100644 --- a/lib/less/tree/atrule.js +++ b/lib/less/tree/atrule.js @@ -1,136 +1,165 @@ -var Node = require('./node'), - Selector = require('./selector'), - Ruleset = require('./ruleset'), - Anonymous = require('./anonymous'); - -var AtRule = function (name, value, rules, index, currentFileInfo, debugInfo, isRooted, visibilityInfo) { - var i; - - this.name = name; - this.value = (value instanceof Node) ? value : (value ? new Anonymous(value) : value); - if (rules) { - if (Array.isArray(rules)) { - this.rules = rules; - } else { - this.rules = [rules]; - this.rules[0].selectors = (new Selector([], null, null, index, currentFileInfo)).createEmptySelectors(); - } - for (i = 0; i < this.rules.length; i++) { - this.rules[i].allowImports = true; +import Node from './node'; +import Selector from './selector'; +import Ruleset from './ruleset'; +import Anonymous from './anonymous'; + +class AtRule extends Node { + constructor( + name, + value, + rules, + index, + currentFileInfo, + debugInfo, + isRooted, + visibilityInfo + ) { + super(); + + let i; + + this.name = name; + this.value = (value instanceof Node) ? value : (value ? new Anonymous(value) : value); + if (rules) { + if (Array.isArray(rules)) { + this.rules = rules; + } else { + this.rules = [rules]; + this.rules[0].selectors = (new Selector([], null, null, index, currentFileInfo)).createEmptySelectors(); + } + for (i = 0; i < this.rules.length; i++) { + this.rules[i].allowImports = true; + } + this.setParent(this.rules, this); } - this.setParent(this.rules, this); + this._index = index; + this._fileInfo = currentFileInfo; + this.debugInfo = debugInfo; + this.isRooted = isRooted || false; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; } - this._index = index; - this._fileInfo = currentFileInfo; - this.debugInfo = debugInfo; - this.isRooted = isRooted || false; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; -}; - -AtRule.prototype = new Node(); -AtRule.prototype.type = 'AtRule'; -AtRule.prototype.accept = function (visitor) { - var value = this.value, rules = this.rules; - if (rules) { - this.rules = visitor.visitArray(rules); - } - if (value) { - this.value = visitor.visit(value); - } -}; -AtRule.prototype.isRulesetLike = function() { - return this.rules || !this.isCharset(); -}; -AtRule.prototype.isCharset = function() { - return '@charset' === this.name; -}; -AtRule.prototype.genCSS = function (context, output) { - var value = this.value, rules = this.rules; - output.add(this.name, this.fileInfo(), this.getIndex()); - if (value) { - output.add(' '); - value.genCSS(context, output); + + accept(visitor) { + const value = this.value; + const rules = this.rules; + if (rules) { + this.rules = visitor.visitArray(rules); + } + if (value) { + this.value = visitor.visit(value); + } } - if (rules) { - this.outputRuleset(context, output, rules); - } else { - output.add(';'); + + isRulesetLike() { + return this.rules || !this.isCharset(); } -}; -AtRule.prototype.eval = function (context) { - var mediaPathBackup, mediaBlocksBackup, value = this.value, rules = this.rules; - - // media stored inside other atrule should not bubble over it - // backpup media bubbling information - mediaPathBackup = context.mediaPath; - mediaBlocksBackup = context.mediaBlocks; - // deleted media bubbling information - context.mediaPath = []; - context.mediaBlocks = []; - - if (value) { - value = value.eval(context); + + isCharset() { + return '@charset' === this.name; } - if (rules) { - // assuming that there is only one rule at this point - that is how parser constructs the rule - rules = [rules[0].eval(context)]; - rules[0].root = true; + + genCSS(context, output) { + const value = this.value; + const rules = this.rules; + output.add(this.name, this.fileInfo(), this.getIndex()); + if (value) { + output.add(' '); + value.genCSS(context, output); + } + if (rules) { + this.outputRuleset(context, output, rules); + } else { + output.add(';'); + } } - // restore media bubbling information - context.mediaPath = mediaPathBackup; - context.mediaBlocks = mediaBlocksBackup; - - return new AtRule(this.name, value, rules, - this.getIndex(), this.fileInfo(), this.debugInfo, this.isRooted, this.visibilityInfo()); -}; -AtRule.prototype.variable = function (name) { - if (this.rules) { - // assuming that there is only one rule at this point - that is how parser constructs the rule - return Ruleset.prototype.variable.call(this.rules[0], name); + + eval(context) { + let mediaPathBackup; + let mediaBlocksBackup; + let value = this.value; + let rules = this.rules; + + // media stored inside other atrule should not bubble over it + // backpup media bubbling information + mediaPathBackup = context.mediaPath; + mediaBlocksBackup = context.mediaBlocks; + // deleted media bubbling information + context.mediaPath = []; + context.mediaBlocks = []; + + if (value) { + value = value.eval(context); + } + if (rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + rules = [rules[0].eval(context)]; + rules[0].root = true; + } + // restore media bubbling information + context.mediaPath = mediaPathBackup; + context.mediaBlocks = mediaBlocksBackup; + + return new AtRule(this.name, value, rules, + this.getIndex(), this.fileInfo(), this.debugInfo, this.isRooted, this.visibilityInfo()); } -}; -AtRule.prototype.find = function () { - if (this.rules) { - // assuming that there is only one rule at this point - that is how parser constructs the rule - return Ruleset.prototype.find.apply(this.rules[0], arguments); + + variable(name) { + if (this.rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + return Ruleset.prototype.variable.call(this.rules[0], name); + } } -}; -AtRule.prototype.rulesets = function () { - if (this.rules) { - // assuming that there is only one rule at this point - that is how parser constructs the rule - return Ruleset.prototype.rulesets.apply(this.rules[0]); + + find(...args) { + if (this.rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + return Ruleset.prototype.find.apply(this.rules[0], args); + } } -}; -AtRule.prototype.outputRuleset = function (context, output, rules) { - var ruleCnt = rules.length, i; - context.tabLevel = (context.tabLevel | 0) + 1; - - // Compressed - if (context.compress) { - output.add('{'); - for (i = 0; i < ruleCnt; i++) { - rules[i].genCSS(context, output); + + rulesets() { + if (this.rules) { + // assuming that there is only one rule at this point - that is how parser constructs the rule + return Ruleset.prototype.rulesets.apply(this.rules[0]); } - output.add('}'); - context.tabLevel--; - return; } - // Non-compressed - var tabSetStr = '\n' + Array(context.tabLevel).join(' '), tabRuleStr = tabSetStr + ' '; - if (!ruleCnt) { - output.add(' {' + tabSetStr + '}'); - } else { - output.add(' {' + tabRuleStr); - rules[0].genCSS(context, output); - for (i = 1; i < ruleCnt; i++) { - output.add(tabRuleStr); - rules[i].genCSS(context, output); + outputRuleset(context, output, rules) { + const ruleCnt = rules.length; + let i; + context.tabLevel = (context.tabLevel | 0) + 1; + + // Compressed + if (context.compress) { + output.add('{'); + for (i = 0; i < ruleCnt; i++) { + rules[i].genCSS(context, output); + } + output.add('}'); + context.tabLevel--; + return; } - output.add(tabSetStr + '}'); + + // Non-compressed + const tabSetStr = `\n${Array(context.tabLevel).join(' ')}`; + + const tabRuleStr = `${tabSetStr} `; + if (!ruleCnt) { + output.add(` {${tabSetStr}}`); + } else { + output.add(` {${tabRuleStr}`); + rules[0].genCSS(context, output); + for (i = 1; i < ruleCnt; i++) { + output.add(tabRuleStr); + rules[i].genCSS(context, output); + } + output.add(`${tabSetStr}}`); + } + + context.tabLevel--; } +} - context.tabLevel--; -}; -module.exports = AtRule; +AtRule.prototype.type = 'AtRule'; +export default AtRule; diff --git a/lib/less/tree/attribute.js b/lib/less/tree/attribute.js index fe01e6971..214803b2b 100644 --- a/lib/less/tree/attribute.js +++ b/lib/less/tree/attribute.js @@ -1,27 +1,34 @@ -var Node = require('./node'); - -var Attribute = function (key, op, value) { - this.key = key; - this.op = op; - this.value = value; -}; -Attribute.prototype = new Node(); -Attribute.prototype.type = 'Attribute'; -Attribute.prototype.eval = function (context) { - return new Attribute(this.key.eval ? this.key.eval(context) : this.key, - this.op, (this.value && this.value.eval) ? this.value.eval(context) : this.value); -}; -Attribute.prototype.genCSS = function (context, output) { - output.add(this.toCSS(context)); -}; -Attribute.prototype.toCSS = function (context) { - var value = this.key.toCSS ? this.key.toCSS(context) : this.key; - - if (this.op) { - value += this.op; - value += (this.value.toCSS ? this.value.toCSS(context) : this.value); +import Node from './node'; + +class Attribute extends Node { + constructor(key, op, value) { + super(); + + this.key = key; + this.op = op; + this.value = value; + } + + eval(context) { + return new Attribute(this.key.eval ? this.key.eval(context) : this.key, + this.op, (this.value && this.value.eval) ? this.value.eval(context) : this.value); + } + + genCSS(context, output) { + output.add(this.toCSS(context)); + } + + toCSS(context) { + let value = this.key.toCSS ? this.key.toCSS(context) : this.key; + + if (this.op) { + value += this.op; + value += (this.value.toCSS ? this.value.toCSS(context) : this.value); + } + + return `[${value}]`; } +} - return '[' + value + ']'; -}; -module.exports = Attribute; +Attribute.prototype.type = 'Attribute'; +export default Attribute; diff --git a/lib/less/tree/call.js b/lib/less/tree/call.js index 627b13b89..eb9b161d1 100644 --- a/lib/less/tree/call.js +++ b/lib/less/tree/call.js @@ -1,97 +1,105 @@ -var Node = require('./node'), - Anonymous = require('./anonymous'), - FunctionCaller = require('../functions/function-caller'); +import Node from './node'; +import Anonymous from './anonymous'; +import FunctionCaller from '../functions/function-caller'; + // // A function call node. // -var Call = function (name, args, index, currentFileInfo) { - this.name = name; - this.args = args; - this.calc = name === 'calc'; - this._index = index; - this._fileInfo = currentFileInfo; -}; -Call.prototype = new Node(); -Call.prototype.type = 'Call'; -Call.prototype.accept = function (visitor) { - if (this.args) { - this.args = visitor.visitArray(this.args); - } -}; -// -// When evaluating a function call, -// we either find the function in the functionRegistry, -// in which case we call it, passing the evaluated arguments, -// if this returns null or we cannot find the function, we -// simply print it out as it appeared originally [2]. -// -// The reason why we evaluate the arguments, is in the case where -// we try to pass a variable to a function, like: `saturate(@color)`. -// The function should receive the value, not the variable. -// -Call.prototype.eval = function (context) { - /** - * Turn off math for calc(), and switch back on for evaluating nested functions - */ - var currentMathContext = context.mathOn; - context.mathOn = !this.calc; - if (this.calc || context.inCalc) { - context.enterCalc(); +class Call extends Node { + constructor(name, args, index, currentFileInfo) { + super(); + + this.name = name; + this.args = args; + this.calc = name === 'calc'; + this._index = index; + this._fileInfo = currentFileInfo; } - var args = this.args.map(function (a) { return a.eval(context); }); - if (this.calc || context.inCalc) { - context.exitCalc(); + + accept(visitor) { + if (this.args) { + this.args = visitor.visitArray(this.args); + } } - context.mathOn = currentMathContext; - var result, funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo()); - - if (funcCaller.isValid()) { - try { - result = funcCaller.call(args); - } catch (e) { - throw { - type: e.type || 'Runtime', - message: 'error evaluating function `' + this.name + '`' + - (e.message ? ': ' + e.message : ''), - index: this.getIndex(), - filename: this.fileInfo().filename, - line: e.lineNumber, - column: e.columnNumber - }; + // + // When evaluating a function call, + // we either find the function in the functionRegistry, + // in which case we call it, passing the evaluated arguments, + // if this returns null or we cannot find the function, we + // simply print it out as it appeared originally [2]. + // + // The reason why we evaluate the arguments, is in the case where + // we try to pass a variable to a function, like: `saturate(@color)`. + // The function should receive the value, not the variable. + // + eval(context) { + /** + * Turn off math for calc(), and switch back on for evaluating nested functions + */ + const currentMathContext = context.mathOn; + context.mathOn = !this.calc; + if (this.calc || context.inCalc) { + context.enterCalc(); } + const args = this.args.map(a => a.eval(context)); + if (this.calc || context.inCalc) { + context.exitCalc(); + } + context.mathOn = currentMathContext; - if (result !== null && result !== undefined) { - // Results that that are not nodes are cast as Anonymous nodes - // Falsy values or booleans are returned as empty nodes - if (!(result instanceof Node)) { - if (!result || result === true) { - result = new Anonymous(null); - } - else { - result = new Anonymous(result.toString()); + let result; + const funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo()); + + if (funcCaller.isValid()) { + try { + result = funcCaller.call(args); + } catch (e) { + throw { + type: e.type || 'Runtime', + message: `error evaluating function \`${this.name}\`${e.message ? `: ${e.message}` : ''}`, + index: this.getIndex(), + filename: this.fileInfo().filename, + line: e.lineNumber, + column: e.columnNumber + }; + } + + if (result !== null && result !== undefined) { + // Results that that are not nodes are cast as Anonymous nodes + // Falsy values or booleans are returned as empty nodes + if (!(result instanceof Node)) { + if (!result || result === true) { + result = new Anonymous(null); + } + else { + result = new Anonymous(result.toString()); + } + } - + result._index = this._index; + result._fileInfo = this._fileInfo; + return result; } - result._index = this._index; - result._fileInfo = this._fileInfo; - return result; + } + return new Call(this.name, args, this.getIndex(), this.fileInfo()); } - return new Call(this.name, args, this.getIndex(), this.fileInfo()); -}; -Call.prototype.genCSS = function (context, output) { - output.add(this.name + '(', this.fileInfo(), this.getIndex()); + genCSS(context, output) { + output.add(`${this.name}(`, this.fileInfo(), this.getIndex()); - for (var i = 0; i < this.args.length; i++) { - this.args[i].genCSS(context, output); - if (i + 1 < this.args.length) { - output.add(', '); + for (let i = 0; i < this.args.length; i++) { + this.args[i].genCSS(context, output); + if (i + 1 < this.args.length) { + output.add(', '); + } } + + output.add(')'); } +} - output.add(')'); -}; -module.exports = Call; +Call.prototype.type = 'Call'; +export default Call; diff --git a/lib/less/tree/color.js b/lib/less/tree/color.js index e639f432e..f945def20 100644 --- a/lib/less/tree/color.js +++ b/lib/less/tree/color.js @@ -1,219 +1,236 @@ -var Node = require('./node'), - colors = require('../data/colors'); +import Node from './node'; +import colors from '../data/colors'; // // RGB Colors - #ff0014, #eee // -var Color = function (rgb, a, originalForm) { - var self = this; - // - // The end goal here, is to parse the arguments - // into an integer triplet, such as `128, 255, 0` - // - // This facilitates operations and conversions. - // - if (Array.isArray(rgb)) { - this.rgb = rgb; - } else if (rgb.length >= 6) { - this.rgb = []; - rgb.match(/.{2}/g).map(function (c, i) { - if (i < 3) { - self.rgb.push(parseInt(c, 16)); - } else { - self.alpha = (parseInt(c, 16)) / 255; - } - }); - } else { - this.rgb = []; - rgb.split('').map(function (c, i) { - if (i < 3) { - self.rgb.push(parseInt(c + c, 16)); - } else { - self.alpha = (parseInt(c + c, 16)) / 255; - } - }); - } - this.alpha = this.alpha || (typeof a === 'number' ? a : 1); - if (typeof originalForm !== 'undefined') { - this.value = originalForm; +class Color extends Node { + constructor(rgb, a, originalForm) { + super(); + + const self = this; + // + // The end goal here, is to parse the arguments + // into an integer triplet, such as `128, 255, 0` + // + // This facilitates operations and conversions. + // + if (Array.isArray(rgb)) { + this.rgb = rgb; + } else if (rgb.length >= 6) { + this.rgb = []; + rgb.match(/.{2}/g).map((c, i) => { + if (i < 3) { + self.rgb.push(parseInt(c, 16)); + } else { + self.alpha = (parseInt(c, 16)) / 255; + } + }); + } else { + this.rgb = []; + rgb.split('').map((c, i) => { + if (i < 3) { + self.rgb.push(parseInt(c + c, 16)); + } else { + self.alpha = (parseInt(c + c, 16)) / 255; + } + }); + } + this.alpha = this.alpha || (typeof a === 'number' ? a : 1); + if (typeof originalForm !== 'undefined') { + this.value = originalForm; + } } -}; -Color.prototype = new Node(); -Color.prototype.type = 'Color'; + luma() { + let r = this.rgb[0] / 255; + let g = this.rgb[1] / 255; + let b = this.rgb[2] / 255; -function clamp(v, max) { - return Math.min(Math.max(v, 0), max); -} + r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4); + g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4); + b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4); -function toHex(v) { - return '#' + v.map(function (c) { - c = clamp(Math.round(c), 255); - return (c < 16 ? '0' : '') + c.toString(16); - }).join(''); -} - -Color.prototype.luma = function () { - var r = this.rgb[0] / 255, - g = this.rgb[1] / 255, - b = this.rgb[2] / 255; - - r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4); - g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4); - b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4); - - return 0.2126 * r + 0.7152 * g + 0.0722 * b; -}; -Color.prototype.genCSS = function (context, output) { - output.add(this.toCSS(context)); -}; -Color.prototype.toCSS = function (context, doNotCompress) { - var compress = context && context.compress && !doNotCompress, color, alpha, - colorFunction, args = []; + return 0.2126 * r + 0.7152 * g + 0.0722 * b; + } - // `value` is set if this color was originally - // converted from a named color string so we need - // to respect this and try to output named color too. - alpha = this.fround(context, this.alpha); + genCSS(context, output) { + output.add(this.toCSS(context)); + } - if (this.value) { - if (this.value.indexOf('rgb') === 0) { - if (alpha < 1) { - colorFunction = 'rgba'; - } - } else if (this.value.indexOf('hsl') === 0) { - if (alpha < 1) { - colorFunction = 'hsla'; + toCSS(context, doNotCompress) { + const compress = context && context.compress && !doNotCompress; + let color; + let alpha; + let colorFunction; + let args = []; + + // `value` is set if this color was originally + // converted from a named color string so we need + // to respect this and try to output named color too. + alpha = this.fround(context, this.alpha); + + if (this.value) { + if (this.value.indexOf('rgb') === 0) { + if (alpha < 1) { + colorFunction = 'rgba'; + } + } else if (this.value.indexOf('hsl') === 0) { + if (alpha < 1) { + colorFunction = 'hsla'; + } else { + colorFunction = 'hsl'; + } } else { - colorFunction = 'hsl'; + return this.value; } } else { - return this.value; + if (alpha < 1) { + colorFunction = 'rgba'; + } } - } else { - if (alpha < 1) { - colorFunction = 'rgba'; + + switch (colorFunction) { + case 'rgba': + args = this.rgb.map(c => clamp(Math.round(c), 255)).concat(clamp(alpha, 1)); + break; + case 'hsla': + args.push(clamp(alpha, 1)); + case 'hsl': + color = this.toHSL(); + args = [ + this.fround(context, color.h), + `${this.fround(context, color.s * 100)}%`, + `${this.fround(context, color.l * 100)}%` + ].concat(args); } - } - switch (colorFunction) { - case 'rgba': - args = this.rgb.map(function (c) { - return clamp(Math.round(c), 255); - }).concat(clamp(alpha, 1)); - break; - case 'hsla': - args.push(clamp(alpha, 1)); - case 'hsl': - color = this.toHSL(); - args = [ - this.fround(context, color.h), - this.fround(context, color.s * 100) + '%', - this.fround(context, color.l * 100) + '%' - ].concat(args); + if (colorFunction) { + // Values are capped between `0` and `255`, rounded and zero-padded. + return `${colorFunction}(${args.join(`,${compress ? '' : ' '}`)})`; + } + + color = this.toRGB(); + + if (compress) { + const splitcolor = color.split(''); + + // Convert color to short format + if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) { + color = `#${splitcolor[1]}${splitcolor[3]}${splitcolor[5]}`; + } + } + + return color; } - if (colorFunction) { - // Values are capped between `0` and `255`, rounded and zero-padded. - return colorFunction + '(' + args.join(',' + (compress ? '' : ' ')) + ')'; + // + // Operations have to be done per-channel, if not, + // channels will spill onto each other. Once we have + // our result, in the form of an integer triplet, + // we create a new Color node to hold the result. + // + operate(context, op, other) { + const rgb = new Array(3); + const alpha = this.alpha * (1 - other.alpha) + other.alpha; + for (let c = 0; c < 3; c++) { + rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]); + } + return new Color(rgb, alpha); } - color = this.toRGB(); + toRGB() { + return toHex(this.rgb); + } - if (compress) { - var splitcolor = color.split(''); + toHSL() { + const r = this.rgb[0] / 255; + const g = this.rgb[1] / 255; + const b = this.rgb[2] / 255; + const a = this.alpha; + const max = Math.max(r, g, b); + const min = Math.min(r, g, b); + let h; + let s; + const l = (max + min) / 2; + const d = max - min; + + if (max === min) { + h = s = 0; + } else { + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - // Convert color to short format - if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) { - color = '#' + splitcolor[1] + splitcolor[3] + splitcolor[5]; + switch (max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; } + return { h: h * 360, s, l, a }; } - return color; -}; + // Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript + toHSV() { + const r = this.rgb[0] / 255; + const g = this.rgb[1] / 255; + const b = this.rgb[2] / 255; + const a = this.alpha; + const max = Math.max(r, g, b); + const min = Math.min(r, g, b); + let h; + let s; + const v = max; + + const d = max - min; + if (max === 0) { + s = 0; + } else { + s = d / max; + } -// -// Operations have to be done per-channel, if not, -// channels will spill onto each other. Once we have -// our result, in the form of an integer triplet, -// we create a new Color node to hold the result. -// -Color.prototype.operate = function (context, op, other) { - var rgb = new Array(3); - var alpha = this.alpha * (1 - other.alpha) + other.alpha; - for (var c = 0; c < 3; c++) { - rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]); - } - return new Color(rgb, alpha); -}; -Color.prototype.toRGB = function () { - return toHex(this.rgb); -}; -Color.prototype.toHSL = function () { - var r = this.rgb[0] / 255, - g = this.rgb[1] / 255, - b = this.rgb[2] / 255, - a = this.alpha; - - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h, s, l = (max + min) / 2, d = max - min; - - if (max === min) { - h = s = 0; - } else { - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - - switch (max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; + if (max === min) { + h = 0; + } else { + switch (max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; } - h /= 6; + return { h: h * 360, s, v, a }; } - return { h: h * 360, s: s, l: l, a: a }; -}; -// Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript -Color.prototype.toHSV = function () { - var r = this.rgb[0] / 255, - g = this.rgb[1] / 255, - b = this.rgb[2] / 255, - a = this.alpha; - - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h, s, v = max; - - var d = max - min; - if (max === 0) { - s = 0; - } else { - s = d / max; + + toARGB() { + return toHex([this.alpha * 255].concat(this.rgb)); } - if (max === min) { - h = 0; - } else { - switch (max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; + compare(x) { + return (x.rgb && + x.rgb[0] === this.rgb[0] && + x.rgb[1] === this.rgb[1] && + x.rgb[2] === this.rgb[2] && + x.alpha === this.alpha) ? 0 : undefined; } - return { h: h * 360, s: s, v: v, a: a }; -}; -Color.prototype.toARGB = function () { - return toHex([this.alpha * 255].concat(this.rgb)); -}; -Color.prototype.compare = function (x) { - return (x.rgb && - x.rgb[0] === this.rgb[0] && - x.rgb[1] === this.rgb[1] && - x.rgb[2] === this.rgb[2] && - x.alpha === this.alpha) ? 0 : undefined; -}; +} + +Color.prototype.type = 'Color'; + +function clamp(v, max) { + return Math.min(Math.max(v, 0), max); +} + +function toHex(v) { + return `#${v.map(c => { + c = clamp(Math.round(c), 255); + return (c < 16 ? '0' : '') + c.toString(16); + }).join('')}`; +} -Color.fromKeyword = function(keyword) { - var c, key = keyword.toLowerCase(); +Color.fromKeyword = keyword => { + let c; + const key = keyword.toLowerCase(); if (colors.hasOwnProperty(key)) { c = new Color(colors[key].slice(1)); } @@ -226,4 +243,4 @@ Color.fromKeyword = function(keyword) { return c; } }; -module.exports = Color; +export default Color; diff --git a/lib/less/tree/combinator.js b/lib/less/tree/combinator.js index fcb2b776c..3740a3b5d 100644 --- a/lib/less/tree/combinator.js +++ b/lib/less/tree/combinator.js @@ -1,23 +1,29 @@ -var Node = require('./node'); - -var Combinator = function (value) { - if (value === ' ') { - this.value = ' '; - this.emptyOrWhitespace = true; - } else { - this.value = value ? value.trim() : ''; - this.emptyOrWhitespace = this.value === ''; - } -}; -Combinator.prototype = new Node(); -Combinator.prototype.type = 'Combinator'; -var _noSpaceCombinators = { +import Node from './node'; +const _noSpaceCombinators = { '': true, ' ': true, '|': true }; -Combinator.prototype.genCSS = function (context, output) { - var spaceOrEmpty = (context.compress || _noSpaceCombinators[this.value]) ? '' : ' '; - output.add(spaceOrEmpty + this.value + spaceOrEmpty); -}; -module.exports = Combinator; + +class Combinator extends Node { + constructor(value) { + super(); + + if (value === ' ') { + this.value = ' '; + this.emptyOrWhitespace = true; + } else { + this.value = value ? value.trim() : ''; + this.emptyOrWhitespace = this.value === ''; + } + } + + genCSS(context, output) { + const spaceOrEmpty = (context.compress || _noSpaceCombinators[this.value]) ? '' : ' '; + output.add(spaceOrEmpty + this.value + spaceOrEmpty); + } +} + +Combinator.prototype.type = 'Combinator'; + +export default Combinator; diff --git a/lib/less/tree/comment.js b/lib/less/tree/comment.js index ec029a6ba..8ed53c97c 100644 --- a/lib/less/tree/comment.js +++ b/lib/less/tree/comment.js @@ -1,23 +1,29 @@ -var Node = require('./node'), - getDebugInfo = require('./debug-info'); +import Node from './node'; +import getDebugInfo from './debug-info'; -var Comment = function (value, isLineComment, index, currentFileInfo) { - this.value = value; - this.isLineComment = isLineComment; - this._index = index; - this._fileInfo = currentFileInfo; - this.allowRoot = true; -}; -Comment.prototype = new Node(); -Comment.prototype.type = 'Comment'; -Comment.prototype.genCSS = function (context, output) { - if (this.debugInfo) { - output.add(getDebugInfo(context, this), this.fileInfo(), this.getIndex()); +class Comment extends Node { + constructor(value, isLineComment, index, currentFileInfo) { + super(); + + this.value = value; + this.isLineComment = isLineComment; + this._index = index; + this._fileInfo = currentFileInfo; + this.allowRoot = true; + } + + genCSS(context, output) { + if (this.debugInfo) { + output.add(getDebugInfo(context, this), this.fileInfo(), this.getIndex()); + } + output.add(this.value); } - output.add(this.value); -}; -Comment.prototype.isSilent = function(context) { - var isCompressed = context.compress && this.value[2] !== '!'; - return this.isLineComment || isCompressed; -}; -module.exports = Comment; + + isSilent(context) { + const isCompressed = context.compress && this.value[2] !== '!'; + return this.isLineComment || isCompressed; + } +} + +Comment.prototype.type = 'Comment'; +export default Comment; diff --git a/lib/less/tree/condition.js b/lib/less/tree/condition.js index 64177f6e3..857624baa 100644 --- a/lib/less/tree/condition.js +++ b/lib/less/tree/condition.js @@ -1,37 +1,43 @@ -var Node = require('./node'); +import Node from './node'; -var Condition = function (op, l, r, i, negate) { - this.op = op.trim(); - this.lvalue = l; - this.rvalue = r; - this._index = i; - this.negate = negate; -}; -Condition.prototype = new Node(); -Condition.prototype.type = 'Condition'; -Condition.prototype.accept = function (visitor) { - this.lvalue = visitor.visit(this.lvalue); - this.rvalue = visitor.visit(this.rvalue); -}; -Condition.prototype.eval = function (context) { - var result = (function (op, a, b) { - switch (op) { - case 'and': return a && b; - case 'or': return a || b; - default: - switch (Node.compare(a, b)) { - case -1: - return op === '<' || op === '=<' || op === '<='; - case 0: - return op === '=' || op === '>=' || op === '=<' || op === '<='; - case 1: - return op === '>' || op === '>='; - default: - return false; - } - } - })(this.op, this.lvalue.eval(context), this.rvalue.eval(context)); +class Condition extends Node { + constructor(op, l, r, i, negate) { + super(); + + this.op = op.trim(); + this.lvalue = l; + this.rvalue = r; + this._index = i; + this.negate = negate; + } + + accept(visitor) { + this.lvalue = visitor.visit(this.lvalue); + this.rvalue = visitor.visit(this.rvalue); + } - return this.negate ? !result : result; -}; -module.exports = Condition; + eval(context) { + const result = ((op, a, b) => { + switch (op) { + case 'and': return a && b; + case 'or': return a || b; + default: + switch (Node.compare(a, b)) { + case -1: + return op === '<' || op === '=<' || op === '<='; + case 0: + return op === '=' || op === '>=' || op === '=<' || op === '<='; + case 1: + return op === '>' || op === '>='; + default: + return false; + } + } + })(this.op, this.lvalue.eval(context), this.rvalue.eval(context)); + + return this.negate ? !result : result; + } +} + +Condition.prototype.type = 'Condition'; +export default Condition; diff --git a/lib/less/tree/debug-info.js b/lib/less/tree/debug-info.js index 56fb2246e..096386d11 100644 --- a/lib/less/tree/debug-info.js +++ b/lib/less/tree/debug-info.js @@ -1,5 +1,5 @@ -var debugInfo = function(context, ctx, lineSeparator) { - var result = ''; +const debugInfo = (context, ctx, lineSeparator) => { + let result = ''; if (context.dumpLineNumbers && !context.compress) { switch (context.dumpLineNumbers) { case 'comments': @@ -16,23 +16,19 @@ var debugInfo = function(context, ctx, lineSeparator) { return result; }; -debugInfo.asComment = function(ctx) { - return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; -}; +debugInfo.asComment = ctx => `/* line ${ctx.debugInfo.lineNumber}, ${ctx.debugInfo.fileName} */\n`; -debugInfo.asMediaQuery = function(ctx) { - var filenameWithProtocol = ctx.debugInfo.fileName; +debugInfo.asMediaQuery = ctx => { + let filenameWithProtocol = ctx.debugInfo.fileName; if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) { - filenameWithProtocol = 'file://' + filenameWithProtocol; + filenameWithProtocol = `file://${filenameWithProtocol}`; } - return '@media -sass-debug-info{filename{font-family:' + - filenameWithProtocol.replace(/([.:\/\\])/g, function (a) { - if (a == '\\') { - a = '\/'; - } - return '\\' + a; - }) + - '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; + return `@media -sass-debug-info{filename{font-family:${filenameWithProtocol.replace(/([.:\/\\])/g, a => { + if (a == '\\') { + a = '\/'; + } + return `\\${a}`; + })}}line{font-family:\\00003${ctx.debugInfo.lineNumber}}}\n`; }; -module.exports = debugInfo; +export default debugInfo; diff --git a/lib/less/tree/declaration.js b/lib/less/tree/declaration.js index d6232ba7c..74834e0fe 100644 --- a/lib/less/tree/declaration.js +++ b/lib/less/tree/declaration.js @@ -1,102 +1,115 @@ -var Node = require('./node'), - Value = require('./value'), - Keyword = require('./keyword'), - Anonymous = require('./anonymous'), - MATH = require('../constants').Math; +import Node from './node'; +import Value from './value'; +import Keyword from './keyword'; +import Anonymous from './anonymous'; +import * as Constants from '../constants'; +const MATH = Constants.Math; -var Declaration = function (name, value, important, merge, index, currentFileInfo, inline, variable) { - this.name = name; - this.value = (value instanceof Node) ? value : new Value([value ? new Anonymous(value) : null]); - this.important = important ? ' ' + important.trim() : ''; - this.merge = merge; - this._index = index; - this._fileInfo = currentFileInfo; - this.inline = inline || false; - this.variable = (variable !== undefined) ? variable - : (name.charAt && (name.charAt(0) === '@')); - this.allowRoot = true; - this.setParent(this.value, this); -}; -function evalName(context, name) { - var value = '', i, n = name.length, - output = {add: function (s) {value += s;}}; - for (i = 0; i < n; i++) { - name[i].eval(context).genCSS(context, output); - } - return value; -} +class Declaration extends Node { + constructor(name, value, important, merge, index, currentFileInfo, inline, variable) { + super(); -Declaration.prototype = new Node(); -Declaration.prototype.type = 'Declaration'; -Declaration.prototype.genCSS = function (context, output) { - output.add(this.name + (context.compress ? ':' : ': '), this.fileInfo(), this.getIndex()); - try { - this.value.genCSS(context, output); - } - catch (e) { - e.index = this._index; - e.filename = this._fileInfo.filename; - throw e; - } - output.add(this.important + ((this.inline || (context.lastRule && context.compress)) ? '' : ';'), this._fileInfo, this._index); -}; -Declaration.prototype.eval = function (context) { - var mathBypass = false, prevMath, name = this.name, evaldValue, variable = this.variable; - if (typeof name !== 'string') { - // expand 'primitive' name directly to get - // things faster (~10% for benchmark.less): - name = (name.length === 1) && (name[0] instanceof Keyword) ? - name[0].value : evalName(context, name); - variable = false; // never treat expanded interpolation as new variable name + this.name = name; + this.value = (value instanceof Node) ? value : new Value([value ? new Anonymous(value) : null]); + this.important = important ? ` ${important.trim()}` : ''; + this.merge = merge; + this._index = index; + this._fileInfo = currentFileInfo; + this.inline = inline || false; + this.variable = (variable !== undefined) ? variable + : (name.charAt && (name.charAt(0) === '@')); + this.allowRoot = true; + this.setParent(this.value, this); } - // @todo remove when parens-division is default - if (name === 'font' && context.math === MATH.ALWAYS) { - mathBypass = true; - prevMath = context.math; - context.math = MATH.PARENS_DIVISION; + genCSS(context, output) { + output.add(this.name + (context.compress ? ':' : ': '), this.fileInfo(), this.getIndex()); + try { + this.value.genCSS(context, output); + } + catch (e) { + e.index = this._index; + e.filename = this._fileInfo.filename; + throw e; + } + output.add(this.important + ((this.inline || (context.lastRule && context.compress)) ? '' : ';'), this._fileInfo, this._index); } - try { - context.importantScope.push({}); - evaldValue = this.value.eval(context); - if (!this.variable && evaldValue.type === 'DetachedRuleset') { - throw { message: 'Rulesets cannot be evaluated on a property.', - index: this.getIndex(), filename: this.fileInfo().filename }; + eval(context) { + let mathBypass = false; + let prevMath; + let name = this.name; + let evaldValue; + let variable = this.variable; + if (typeof name !== 'string') { + // expand 'primitive' name directly to get + // things faster (~10% for benchmark.less): + name = (name.length === 1) && (name[0] instanceof Keyword) ? + name[0].value : evalName(context, name); + variable = false; // never treat expanded interpolation as new variable name } - var important = this.important, - importantResult = context.importantScope.pop(); - if (!important && importantResult.important) { - important = importantResult.important; + + // @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({}); + evaldValue = this.value.eval(context); - return new Declaration(name, - evaldValue, - important, - this.merge, - this.getIndex(), this.fileInfo(), this.inline, - variable); - } - catch (e) { - if (typeof e.index !== 'number') { - e.index = this.getIndex(); - e.filename = this.fileInfo().filename; + if (!this.variable && evaldValue.type === 'DetachedRuleset') { + throw { message: 'Rulesets cannot be evaluated on a property.', + index: this.getIndex(), filename: this.fileInfo().filename }; + } + let important = this.important; + const importantResult = context.importantScope.pop(); + if (!important && importantResult.important) { + important = importantResult.important; + } + + return new Declaration(name, + evaldValue, + important, + this.merge, + this.getIndex(), this.fileInfo(), this.inline, + variable); } - throw e; - } - finally { - if (mathBypass) { - context.math = prevMath; + catch (e) { + if (typeof e.index !== 'number') { + e.index = this.getIndex(); + e.filename = this.fileInfo().filename; + } + throw e; } + finally { + if (mathBypass) { + context.math = prevMath; + } + } + } + + makeImportant() { + return new Declaration(this.name, + this.value, + '!important', + this.merge, + this.getIndex(), this.fileInfo(), this.inline); + } +} + +function evalName(context, name) { + let value = ''; + let i; + const n = name.length; + const output = {add: function (s) {value += s;}}; + for (i = 0; i < n; i++) { + name[i].eval(context).genCSS(context, output); } -}; -Declaration.prototype.makeImportant = function () { - return new Declaration(this.name, - this.value, - '!important', - this.merge, - this.getIndex(), this.fileInfo(), this.inline); -}; + return value; +} -module.exports = Declaration; \ No newline at end of file +Declaration.prototype.type = 'Declaration'; +export default Declaration; \ No newline at end of file diff --git a/lib/less/tree/detached-ruleset.js b/lib/less/tree/detached-ruleset.js index c2c1f4c35..9448e1366 100644 --- a/lib/less/tree/detached-ruleset.js +++ b/lib/less/tree/detached-ruleset.js @@ -1,23 +1,30 @@ -var Node = require('./node'), - contexts = require('../contexts'), - utils = require('../utils'); +import Node from './node'; +import contexts from '../contexts'; +import * as utils from '../utils'; + +class DetachedRuleset extends Node { + constructor(ruleset, frames) { + super(); + + this.ruleset = ruleset; + this.frames = frames; + this.setParent(this.ruleset, this); + } + + accept(visitor) { + this.ruleset = visitor.visit(this.ruleset); + } + + eval(context) { + const frames = this.frames || utils.copyArray(context.frames); + return new DetachedRuleset(this.ruleset, frames); + } + + callEval(context) { + return this.ruleset.eval(this.frames ? new contexts.Eval(context, this.frames.concat(context.frames)) : context); + } +} -var DetachedRuleset = function (ruleset, frames) { - this.ruleset = ruleset; - this.frames = frames; - this.setParent(this.ruleset, this); -}; -DetachedRuleset.prototype = new Node(); DetachedRuleset.prototype.type = 'DetachedRuleset'; DetachedRuleset.prototype.evalFirst = true; -DetachedRuleset.prototype.accept = function (visitor) { - this.ruleset = visitor.visit(this.ruleset); -}; -DetachedRuleset.prototype.eval = function (context) { - var frames = this.frames || utils.copyArray(context.frames); - return new DetachedRuleset(this.ruleset, frames); -}; -DetachedRuleset.prototype.callEval = function (context) { - return this.ruleset.eval(this.frames ? new contexts.Eval(context, this.frames.concat(context.frames)) : context); -}; -module.exports = DetachedRuleset; +export default DetachedRuleset; diff --git a/lib/less/tree/dimension.js b/lib/less/tree/dimension.js index b850e8e8b..314a6b936 100644 --- a/lib/less/tree/dimension.js +++ b/lib/less/tree/dimension.js @@ -1,161 +1,179 @@ -var Node = require('./node'), - unitConversions = require('../data/unit-conversions'), - Unit = require('./unit'), - Color = require('./color'); +import Node from './node'; +import unitConversions from '../data/unit-conversions'; +import Unit from './unit'; +import Color from './color'; // // A number with a unit // -var Dimension = function (value, unit) { - this.value = parseFloat(value); - if (isNaN(this.value)) { - throw new Error('Dimension is not a number.'); +class Dimension extends Node { + constructor(value, unit) { + super(); + + this.value = parseFloat(value); + if (isNaN(this.value)) { + throw new Error('Dimension is not a number.'); + } + this.unit = (unit && unit instanceof Unit) ? unit : + new Unit(unit ? [unit] : undefined); + this.setParent(this.unit, this); } - this.unit = (unit && unit instanceof Unit) ? unit : - new Unit(unit ? [unit] : undefined); - this.setParent(this.unit, this); -}; -Dimension.prototype = new Node(); -Dimension.prototype.type = 'Dimension'; -Dimension.prototype.accept = function (visitor) { - this.unit = visitor.visit(this.unit); -}; -Dimension.prototype.eval = function (context) { - return this; -}; -Dimension.prototype.toColor = function () { - return new Color([this.value, this.value, this.value]); -}; -Dimension.prototype.genCSS = function (context, output) { - if ((context && context.strictUnits) && !this.unit.isSingular()) { - throw new Error('Multiple units in dimension. Correct the units or use the unit function. Bad unit: ' + this.unit.toString()); + accept(visitor) { + this.unit = visitor.visit(this.unit); } - var value = this.fround(context, this.value), - strValue = String(value); + eval(context) { + return this; + } - if (value !== 0 && value < 0.000001 && value > -0.000001) { - // would be output 1e-6 etc. - strValue = value.toFixed(20).replace(/0+$/, ''); + toColor() { + return new Color([this.value, this.value, this.value]); } - if (context && context.compress) { - // Zero values doesn't need a unit - if (value === 0 && this.unit.isLength()) { - output.add(strValue); - return; + genCSS(context, output) { + if ((context && context.strictUnits) && !this.unit.isSingular()) { + throw new Error(`Multiple units in dimension. Correct the units or use the unit function. Bad unit: ${this.unit.toString()}`); } - // Float values doesn't need a leading zero - if (value > 0 && value < 1) { - strValue = (strValue).substr(1); + const value = this.fround(context, this.value); + let strValue = String(value); + + if (value !== 0 && value < 0.000001 && value > -0.000001) { + // would be output 1e-6 etc. + strValue = value.toFixed(20).replace(/0+$/, ''); } - } - output.add(strValue); - this.unit.genCSS(context, output); -}; - -// In an operation between two Dimensions, -// we default to the first Dimension's unit, -// so `1px + 2` will yield `3px`. -Dimension.prototype.operate = function (context, op, other) { - /* jshint noempty:false */ - var value = this._operate(context, op, this.value, other.value), - unit = this.unit.clone(); - - if (op === '+' || op === '-') { - if (unit.numerator.length === 0 && unit.denominator.length === 0) { - unit = other.unit.clone(); - if (this.unit.backupUnit) { - unit.backupUnit = this.unit.backupUnit; + if (context && context.compress) { + // Zero values doesn't need a unit + if (value === 0 && this.unit.isLength()) { + output.add(strValue); + return; } - } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) { - // do nothing - } else { - other = other.convertTo(this.unit.usedUnits()); - if (context.strictUnits && other.unit.toString() !== unit.toString()) { - throw new Error('Incompatible units. Change the units or use the unit function. Bad units: \'' + unit.toString() + - '\' and \'' + other.unit.toString() + '\'.'); + // Float values doesn't need a leading zero + if (value > 0 && value < 1) { + strValue = (strValue).substr(1); } - - value = this._operate(context, op, this.value, other.value); } - } else if (op === '*') { - unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); - unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); - unit.cancel(); - } else if (op === '/') { - unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); - unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); - unit.cancel(); + + output.add(strValue); + this.unit.genCSS(context, output); } - return new Dimension(value, unit); -}; -Dimension.prototype.compare = function (other) { - var a, b; - if (!(other instanceof Dimension)) { - return undefined; + // In an operation between two Dimensions, + // we default to the first Dimension's unit, + // so `1px + 2` will yield `3px`. + operate(context, op, other) { + /* jshint noempty:false */ + let value = this._operate(context, op, this.value, other.value); + + let unit = this.unit.clone(); + + if (op === '+' || op === '-') { + if (unit.numerator.length === 0 && unit.denominator.length === 0) { + unit = other.unit.clone(); + if (this.unit.backupUnit) { + unit.backupUnit = this.unit.backupUnit; + } + } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) { + // do nothing + } else { + other = other.convertTo(this.unit.usedUnits()); + + if (context.strictUnits && other.unit.toString() !== unit.toString()) { + throw new Error(`Incompatible units. Change the units or use the unit function. ` + + `Bad units: '${unit.toString()}' and '${other.unit.toString()}'.`); + } + + value = this._operate(context, op, this.value, other.value); + } + } else if (op === '*') { + unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); + unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); + unit.cancel(); + } else if (op === '/') { + unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); + unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); + unit.cancel(); + } + return new Dimension(value, unit); } - if (this.unit.isEmpty() || other.unit.isEmpty()) { - a = this; - b = other; - } else { - a = this.unify(); - b = other.unify(); - if (a.unit.compare(b.unit) !== 0) { + compare(other) { + let a; + let b; + + if (!(other instanceof Dimension)) { return undefined; } - } - return Node.numericCompare(a.value, b.value); -}; -Dimension.prototype.unify = function () { - return this.convertTo({ length: 'px', duration: 's', angle: 'rad' }); -}; -Dimension.prototype.convertTo = function (conversions) { - var value = this.value, unit = this.unit.clone(), - i, groupName, group, targetUnit, derivedConversions = {}, applyUnit; - - if (typeof conversions === 'string') { - for (i in unitConversions) { - if (unitConversions[i].hasOwnProperty(conversions)) { - derivedConversions = {}; - derivedConversions[i] = conversions; + if (this.unit.isEmpty() || other.unit.isEmpty()) { + a = this; + b = other; + } else { + a = this.unify(); + b = other.unify(); + if (a.unit.compare(b.unit) !== 0) { + return undefined; } } - conversions = derivedConversions; + + return Node.numericCompare(a.value, b.value); + } + + unify() { + return this.convertTo({ length: 'px', duration: 's', angle: 'rad' }); } - applyUnit = function (atomicUnit, denominator) { - /* jshint loopfunc:true */ - if (group.hasOwnProperty(atomicUnit)) { - if (denominator) { - value = value / (group[atomicUnit] / group[targetUnit]); - } else { - value = value * (group[atomicUnit] / group[targetUnit]); - } - return targetUnit; + convertTo(conversions) { + let value = this.value; + const unit = this.unit.clone(); + let i; + let groupName; + let group; + let targetUnit; + let derivedConversions = {}; + let applyUnit; + + if (typeof conversions === 'string') { + for (i in unitConversions) { + if (unitConversions[i].hasOwnProperty(conversions)) { + derivedConversions = {}; + derivedConversions[i] = conversions; + } + } + conversions = derivedConversions; } + applyUnit = (atomicUnit, denominator) => { + /* jshint loopfunc:true */ + if (group.hasOwnProperty(atomicUnit)) { + if (denominator) { + value = value / (group[atomicUnit] / group[targetUnit]); + } else { + value = value * (group[atomicUnit] / group[targetUnit]); + } + + return targetUnit; + } - return atomicUnit; - }; + return atomicUnit; + }; - for (groupName in conversions) { - if (conversions.hasOwnProperty(groupName)) { - targetUnit = conversions[groupName]; - group = unitConversions[groupName]; + for (groupName in conversions) { + if (conversions.hasOwnProperty(groupName)) { + targetUnit = conversions[groupName]; + group = unitConversions[groupName]; - unit.map(applyUnit); + unit.map(applyUnit); + } } - } - unit.cancel(); + unit.cancel(); + + return new Dimension(value, unit); + } +} - return new Dimension(value, unit); -}; -module.exports = Dimension; +Dimension.prototype.type = 'Dimension'; +export default Dimension; diff --git a/lib/less/tree/element.js b/lib/less/tree/element.js index 13fa3b2ba..b96d2da21 100644 --- a/lib/less/tree/element.js +++ b/lib/less/tree/element.js @@ -1,64 +1,73 @@ -var Node = require('./node'), - Paren = require('./paren'), - Combinator = require('./combinator'); +import Node from './node'; +import Paren from './paren'; +import Combinator from './combinator'; -var Element = function (combinator, value, isVariable, index, currentFileInfo, visibilityInfo) { - this.combinator = combinator instanceof Combinator ? - combinator : new Combinator(combinator); +class Element extends Node { + constructor(combinator, value, isVariable, index, currentFileInfo, visibilityInfo) { + super(); - if (typeof value === 'string') { - this.value = value.trim(); - } else if (value) { - this.value = value; - } else { - this.value = ''; + this.combinator = combinator instanceof Combinator ? + combinator : new Combinator(combinator); + + if (typeof value === 'string') { + this.value = value.trim(); + } else if (value) { + this.value = value; + } else { + this.value = ''; + } + this.isVariable = isVariable; + this._index = index; + this._fileInfo = currentFileInfo; + this.copyVisibilityInfo(visibilityInfo); + this.setParent(this.combinator, this); } - this.isVariable = isVariable; - this._index = index; - this._fileInfo = currentFileInfo; - this.copyVisibilityInfo(visibilityInfo); - this.setParent(this.combinator, this); -}; -Element.prototype = new Node(); -Element.prototype.type = 'Element'; -Element.prototype.accept = function (visitor) { - var value = this.value; - this.combinator = visitor.visit(this.combinator); - if (typeof value === 'object') { - this.value = visitor.visit(value); + + accept(visitor) { + const value = this.value; + this.combinator = visitor.visit(this.combinator); + if (typeof value === 'object') { + this.value = visitor.visit(value); + } } -}; -Element.prototype.eval = function (context) { - return new Element(this.combinator, - this.value.eval ? this.value.eval(context) : this.value, - this.isVariable, - this.getIndex(), - this.fileInfo(), this.visibilityInfo()); -}; -Element.prototype.clone = function () { - return new Element(this.combinator, - this.value, - this.isVariable, - this.getIndex(), - this.fileInfo(), this.visibilityInfo()); -}; -Element.prototype.genCSS = function (context, output) { - output.add(this.toCSS(context), this.fileInfo(), this.getIndex()); -}; -Element.prototype.toCSS = function (context) { - context = context || {}; - var value = this.value, firstSelector = context.firstSelector; - if (value instanceof Paren) { - // selector in parens should not be affected by outer selector - // flags (breaks only interpolated selectors - see #1973) - context.firstSelector = true; + + eval(context) { + return new Element(this.combinator, + this.value.eval ? this.value.eval(context) : this.value, + this.isVariable, + this.getIndex(), + this.fileInfo(), this.visibilityInfo()); } - value = value.toCSS ? value.toCSS(context) : value; - context.firstSelector = firstSelector; - if (value === '' && this.combinator.value.charAt(0) === '&') { - return ''; - } else { - return this.combinator.toCSS(context) + value; + + clone() { + return new Element(this.combinator, + this.value, + this.isVariable, + this.getIndex(), + this.fileInfo(), this.visibilityInfo()); } -}; -module.exports = Element; + + genCSS(context, output) { + output.add(this.toCSS(context), this.fileInfo(), this.getIndex()); + } + + toCSS(context = {}) { + let value = this.value; + const firstSelector = context.firstSelector; + if (value instanceof Paren) { + // selector in parens should not be affected by outer selector + // flags (breaks only interpolated selectors - see #1973) + context.firstSelector = true; + } + value = value.toCSS ? value.toCSS(context) : value; + context.firstSelector = firstSelector; + if (value === '' && this.combinator.value.charAt(0) === '&') { + return ''; + } else { + return this.combinator.toCSS(context) + value; + } + } +} + +Element.prototype.type = 'Element'; +export default Element; diff --git a/lib/less/tree/expression.js b/lib/less/tree/expression.js index 4587bcc2e..d1be1a9ac 100644 --- a/lib/less/tree/expression.js +++ b/lib/less/tree/expression.js @@ -1,65 +1,74 @@ -var Node = require('./node'), - Paren = require('./paren'), - Comment = require('./comment'), - Dimension = require('./dimension'), - MATH = require('../constants').Math; +import Node from './node'; +import Paren from './paren'; +import Comment from './comment'; +import Dimension from './dimension'; +import * as Constants from '../constants'; +const MATH = Constants.Math; -var Expression = function (value, noSpacing) { - this.value = value; - this.noSpacing = noSpacing; - if (!value) { - throw new Error('Expression requires an array parameter'); +class Expression extends Node { + constructor(value, noSpacing) { + super(); + + this.value = value; + this.noSpacing = noSpacing; + if (!value) { + throw new Error('Expression requires an array parameter'); + } } -}; -Expression.prototype = new Node(); -Expression.prototype.type = 'Expression'; -Expression.prototype.accept = function (visitor) { - this.value = visitor.visitArray(this.value); -}; -Expression.prototype.eval = function (context) { - var returnValue, - mathOn = context.isMathOn(), - inParenthesis = this.parens && - (context.math !== MATH.STRICT_LEGACY || !this.parensInOp), - doubleParen = false; - if (inParenthesis) { - context.inParenthesis(); + + accept(visitor) { + this.value = visitor.visitArray(this.value); } - if (this.value.length > 1) { - returnValue = new Expression(this.value.map(function (e) { - if (!e.eval) { - return e; + + eval(context) { + let returnValue; + const mathOn = context.isMathOn(); + + const inParenthesis = this.parens && + (context.math !== MATH.STRICT_LEGACY || !this.parensInOp); + + let doubleParen = false; + if (inParenthesis) { + context.inParenthesis(); + } + if (this.value.length > 1) { + returnValue = new Expression(this.value.map(e => { + if (!e.eval) { + return e; + } + return e.eval(context); + }), this.noSpacing); + } else if (this.value.length === 1) { + if (this.value[0].parens && !this.value[0].parensInOp && !context.inCalc) { + doubleParen = true; } - return e.eval(context); - }), this.noSpacing); - } else if (this.value.length === 1) { - if (this.value[0].parens && !this.value[0].parensInOp && !context.inCalc) { - doubleParen = true; + returnValue = this.value[0].eval(context); + } else { + returnValue = this; } - returnValue = this.value[0].eval(context); - } else { - returnValue = this; - } - if (inParenthesis) { - context.outOfParenthesis(); - } - if (this.parens && this.parensInOp && !mathOn && !doubleParen - && (!(returnValue instanceof Dimension))) { - returnValue = new Paren(returnValue); + if (inParenthesis) { + context.outOfParenthesis(); + } + if (this.parens && this.parensInOp && !mathOn && !doubleParen + && (!(returnValue instanceof Dimension))) { + returnValue = new Paren(returnValue); + } + return returnValue; } - return returnValue; -}; -Expression.prototype.genCSS = function (context, output) { - for (var i = 0; i < this.value.length; i++) { - this.value[i].genCSS(context, output); - if (!this.noSpacing && i + 1 < this.value.length) { - output.add(' '); + + genCSS(context, output) { + for (let i = 0; i < this.value.length; i++) { + this.value[i].genCSS(context, output); + if (!this.noSpacing && i + 1 < this.value.length) { + output.add(' '); + } } } -}; -Expression.prototype.throwAwayComments = function () { - this.value = this.value.filter(function(v) { - return !(v instanceof Comment); - }); -}; -module.exports = Expression; + + throwAwayComments() { + this.value = this.value.filter(v => !(v instanceof Comment)); + } +} + +Expression.prototype.type = 'Expression'; +export default Expression; diff --git a/lib/less/tree/extend.js b/lib/less/tree/extend.js index a716fc74e..d78bf92ca 100644 --- a/lib/less/tree/extend.js +++ b/lib/less/tree/extend.js @@ -1,58 +1,66 @@ -var Node = require('./node'), - Selector = require('./selector'); - -var Extend = function Extend(selector, option, index, currentFileInfo, visibilityInfo) { - this.selector = selector; - this.option = option; - this.object_id = Extend.next_id++; - this.parent_ids = [this.object_id]; - this._index = index; - this._fileInfo = currentFileInfo; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; - - switch (option) { - case 'all': - this.allowBefore = true; - this.allowAfter = true; - break; - default: - this.allowBefore = false; - this.allowAfter = false; - break; +import Node from './node'; +import Selector from './selector'; + +class Extend extends Node { + constructor(selector, option, index, currentFileInfo, visibilityInfo) { + super(); + + this.selector = selector; + this.option = option; + this.object_id = Extend.next_id++; + this.parent_ids = [this.object_id]; + this._index = index; + this._fileInfo = currentFileInfo; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + + switch (option) { + case 'all': + this.allowBefore = true; + this.allowAfter = true; + break; + default: + this.allowBefore = false; + this.allowAfter = false; + break; + } + this.setParent(this.selector, this); } - this.setParent(this.selector, this); -}; -Extend.next_id = 0; -Extend.prototype = new Node(); -Extend.prototype.type = 'Extend'; -Extend.prototype.accept = function (visitor) { - this.selector = visitor.visit(this.selector); -}; -Extend.prototype.eval = function (context) { - return new Extend(this.selector.eval(context), this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); -}; -Extend.prototype.clone = function (context) { - return new Extend(this.selector, this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); -}; -// it concatenates (joins) all selectors in selector array -Extend.prototype.findSelfSelectors = function (selectors) { - var selfElements = [], - i, - selectorElements; - - for (i = 0; i < selectors.length; i++) { - selectorElements = selectors[i].elements; - // duplicate the logic in genCSS function inside the selector node. - // future TODO - move both logics into the selector joiner visitor - if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === '') { - selectorElements[0].combinator.value = ' '; + accept(visitor) { + this.selector = visitor.visit(this.selector); + } + + eval(context) { + return new Extend(this.selector.eval(context), this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } + + clone(context) { + return new Extend(this.selector, this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + } + + // it concatenates (joins) all selectors in selector array + findSelfSelectors(selectors) { + let selfElements = []; + let i; + let selectorElements; + + for (i = 0; i < selectors.length; i++) { + selectorElements = selectors[i].elements; + // duplicate the logic in genCSS function inside the selector node. + // future TODO - move both logics into the selector joiner visitor + if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === '') { + selectorElements[0].combinator.value = ' '; + } + selfElements = selfElements.concat(selectors[i].elements); } - selfElements = selfElements.concat(selectors[i].elements); + + this.selfSelectors = [new Selector(selfElements)]; + this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo()); } +} + +Extend.next_id = 0; - this.selfSelectors = [new Selector(selfElements)]; - this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo()); -}; -module.exports = Extend; +Extend.prototype.type = 'Extend'; +export default Extend; diff --git a/lib/less/tree/import.js b/lib/less/tree/import.js index 8d2c0c8b7..394cde102 100644 --- a/lib/less/tree/import.js +++ b/lib/less/tree/import.js @@ -1,11 +1,11 @@ -var Node = require('./node'), - Media = require('./media'), - URL = require('./url'), - Quoted = require('./quoted'), - Ruleset = require('./ruleset'), - Anonymous = require('./anonymous'), - utils = require('../utils'), - LessError = require('../less-error'); +import Node from './node'; +import Media from './media'; +import URL from './url'; +import Quoted from './quoted'; +import Ruleset from './ruleset'; +import Anonymous from './anonymous'; +import * as utils from '../utils'; +import LessError from '../less-error'; // // CSS @import node @@ -19,163 +19,166 @@ var Node = require('./node'), // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // -var Import = function (path, features, options, index, currentFileInfo, visibilityInfo) { - this.options = options; - this._index = index; - this._fileInfo = currentFileInfo; - this.path = path; - this.features = features; - this.allowRoot = true; - - if (this.options.less !== undefined || this.options.inline) { - this.css = !this.options.less || this.options.inline; - } else { - var pathValue = this.getPath(); - if (pathValue && /[#\.\&\?]css([\?;].*)?$/.test(pathValue)) { - this.css = true; +class Import extends Node { + constructor(path, features, options, index, currentFileInfo, visibilityInfo) { + super(); + + this.options = options; + this._index = index; + this._fileInfo = currentFileInfo; + this.path = path; + this.features = features; + this.allowRoot = true; + + if (this.options.less !== undefined || this.options.inline) { + this.css = !this.options.less || this.options.inline; + } else { + const pathValue = this.getPath(); + if (pathValue && /[#\.\&\?]css([\?;].*)?$/.test(pathValue)) { + this.css = true; + } } + this.copyVisibilityInfo(visibilityInfo); + this.setParent(this.features, this); + this.setParent(this.path, this); } - this.copyVisibilityInfo(visibilityInfo); - this.setParent(this.features, this); - this.setParent(this.path, this); -}; -// -// The actual import node doesn't return anything, when converted to CSS. -// The reason is that it's used at the evaluation stage, so that the rules -// it imports can be treated like any other rules. -// -// In `eval`, we make sure all Import nodes get evaluated, recursively, so -// we end up with a flat structure, which can easily be imported in the parent -// ruleset. -// -Import.prototype = new Node(); -Import.prototype.type = 'Import'; -Import.prototype.accept = function (visitor) { - if (this.features) { - this.features = visitor.visit(this.features); - } - this.path = visitor.visit(this.path); - if (!this.options.isPlugin && !this.options.inline && this.root) { - this.root = visitor.visit(this.root); - } -}; -Import.prototype.genCSS = function (context, output) { - if (this.css && this.path._fileInfo.reference === undefined) { - output.add('@import ', this._fileInfo, this._index); - this.path.genCSS(context, output); + accept(visitor) { if (this.features) { - output.add(' '); - this.features.genCSS(context, output); + this.features = visitor.visit(this.features); + } + this.path = visitor.visit(this.path); + if (!this.options.isPlugin && !this.options.inline && this.root) { + this.root = visitor.visit(this.root); } - output.add(';'); } -}; -Import.prototype.getPath = function () { - return (this.path instanceof URL) ? - this.path.value.value : this.path.value; -}; -Import.prototype.isVariableImport = function () { - var path = this.path; - if (path instanceof URL) { - path = path.value; + + genCSS(context, output) { + if (this.css && this.path._fileInfo.reference === undefined) { + output.add('@import ', this._fileInfo, this._index); + this.path.genCSS(context, output); + if (this.features) { + output.add(' '); + this.features.genCSS(context, output); + } + output.add(';'); + } } - if (path instanceof Quoted) { - return path.containsVariables(); + + getPath() { + return (this.path instanceof URL) ? + this.path.value.value : this.path.value; } - return true; -}; -Import.prototype.evalForImport = function (context) { - var path = this.path; + isVariableImport() { + let path = this.path; + if (path instanceof URL) { + path = path.value; + } + if (path instanceof Quoted) { + return path.containsVariables(); + } - if (path instanceof URL) { - path = path.value; + return true; } - return new Import(path.eval(context), this.features, this.options, this._index, this._fileInfo, this.visibilityInfo()); -}; -Import.prototype.evalPath = function (context) { - var path = this.path.eval(context); - var fileInfo = this._fileInfo; - - if (!(path instanceof URL)) { - // Add the rootpath if the URL requires a rewrite - var pathValue = path.value; - if (fileInfo && - pathValue && - context.pathRequiresRewrite(pathValue)) { - path.value = context.rewritePath(pathValue, fileInfo.rootpath); - } else { - path.value = context.normalizePath(path.value); + evalForImport(context) { + let path = this.path; + + if (path instanceof URL) { + path = path.value; } + + return new Import(path.eval(context), this.features, this.options, this._index, this._fileInfo, this.visibilityInfo()); } - return path; -}; -Import.prototype.eval = function (context) { - var result = this.doEval(context); - if (this.options.reference || this.blocksVisibility()) { - if (result.length || result.length === 0) { - result.forEach(function (node) { - node.addVisibilityBlock(); + evalPath(context) { + const path = this.path.eval(context); + const fileInfo = this._fileInfo; + + if (!(path instanceof URL)) { + // Add the rootpath if the URL requires a rewrite + const pathValue = path.value; + if (fileInfo && + pathValue && + context.pathRequiresRewrite(pathValue)) { + path.value = context.rewritePath(pathValue, fileInfo.rootpath); + } else { + path.value = context.normalizePath(path.value); } - ); - } else { - result.addVisibilityBlock(); } + + return path; } - return result; -}; -Import.prototype.doEval = function (context) { - var ruleset, registry, - features = this.features && this.features.eval(context); - - if (this.options.isPlugin) { - if (this.root && this.root.eval) { - try { - this.root.eval(context); - } - catch (e) { - e.message = 'Plugin error during evaluation'; - throw new LessError(e, this.root.imports, this.root.filename); + + eval(context) { + const result = this.doEval(context); + if (this.options.reference || this.blocksVisibility()) { + if (result.length || result.length === 0) { + result.forEach(node => { + node.addVisibilityBlock(); + } + ); + } else { + result.addVisibilityBlock(); } } - registry = context.frames[0] && context.frames[0].functionRegistry; - if ( registry && this.root && this.root.functions ) { - registry.addMultiple( this.root.functions ); - } - - return []; + return result; } - if (this.skip) { - if (typeof this.skip === 'function') { - this.skip = this.skip(); - } - if (this.skip) { + doEval(context) { + let ruleset; + let registry; + const features = this.features && this.features.eval(context); + + if (this.options.isPlugin) { + if (this.root && this.root.eval) { + try { + this.root.eval(context); + } + catch (e) { + e.message = 'Plugin error during evaluation'; + throw new LessError(e, this.root.imports, this.root.filename); + } + } + registry = context.frames[0] && context.frames[0].functionRegistry; + if ( registry && this.root && this.root.functions ) { + registry.addMultiple( this.root.functions ); + } + return []; } - } - if (this.options.inline) { - var contents = new Anonymous(this.root, 0, - { - filename: this.importedFilename, - reference: this.path._fileInfo && this.path._fileInfo.reference - }, true, true); - - return this.features ? new Media([contents], this.features.value) : [contents]; - } else if (this.css) { - var newImport = new Import(this.evalPath(context), features, this.options, this._index); - if (!newImport.css && this.error) { - throw this.error; + + if (this.skip) { + if (typeof this.skip === 'function') { + this.skip = this.skip(); + } + if (this.skip) { + return []; + } } - return newImport; - } else { - ruleset = new Ruleset(null, utils.copyArray(this.root.rules)); - ruleset.evalImports(context); + if (this.options.inline) { + const contents = new Anonymous(this.root, 0, + { + filename: this.importedFilename, + reference: this.path._fileInfo && this.path._fileInfo.reference + }, true, true); - return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules; + return this.features ? new Media([contents], this.features.value) : [contents]; + } else if (this.css) { + const newImport = new Import(this.evalPath(context), features, this.options, this._index); + if (!newImport.css && this.error) { + throw this.error; + } + return newImport; + } else { + ruleset = new Ruleset(null, utils.copyArray(this.root.rules)); + ruleset.evalImports(context); + + return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules; + } } -}; -module.exports = Import; +} + +Import.prototype.type = 'Import'; +export default Import; diff --git a/lib/less/tree/index.js b/lib/less/tree/index.js index d5972a604..912697c75 100644 --- a/lib/less/tree/index.js +++ b/lib/less/tree/index.js @@ -1,42 +1,54 @@ -var tree = Object.create(null); +const tree = Object.create(null); -tree.Node = require('./node'); -tree.Color = require('./color'); -tree.AtRule = require('./atrule'); -tree.DetachedRuleset = require('./detached-ruleset'); -tree.Operation = require('./operation'); -tree.Dimension = require('./dimension'); -tree.Unit = require('./unit'); -tree.Keyword = require('./keyword'); -tree.Variable = require('./variable'); -tree.Property = require('./property'); -tree.Ruleset = require('./ruleset'); -tree.Element = require('./element'); -tree.Attribute = require('./attribute'); -tree.Combinator = require('./combinator'); -tree.Selector = require('./selector'); -tree.Quoted = require('./quoted'); -tree.Expression = require('./expression'); -tree.Declaration = require('./declaration'); -tree.Call = require('./call'); -tree.URL = require('./url'); -tree.Import = require('./import'); -tree.mixin = { - Call: require('./mixin-call'), - Definition: require('./mixin-definition') -}; -tree.Comment = require('./comment'); -tree.Anonymous = require('./anonymous'); -tree.Value = require('./value'); -tree.JavaScript = require('./javascript'); -tree.Assignment = require('./assignment'); -tree.Condition = require('./condition'); -tree.Paren = require('./paren'); -tree.Media = require('./media'); -tree.UnicodeDescriptor = require('./unicode-descriptor'); -tree.Negative = require('./negative'); -tree.Extend = require('./extend'); -tree.VariableCall = require('./variable-call'); -tree.NamespaceValue = require('./namespace-value'); +import Node from './node'; +import Color from './color'; +import AtRule from './atrule'; +import DetachedRuleset from './detached-ruleset'; +import Operation from './operation'; +import Dimension from './dimension'; +import Unit from './unit'; +import Keyword from './keyword'; +import Variable from './variable'; +import Property from './property'; +import Ruleset from './ruleset'; +import Element from './element'; +import Attribute from './attribute'; +import Combinator from './combinator'; +import Selector from './selector'; +import Quoted from './quoted'; +import Expression from './expression'; +import Declaration from './declaration'; +import Call from './call'; +import URL from './url'; +import Import from './import'; +import Comment from './comment'; +import Anonymous from './anonymous'; +import Value from './value'; +import JavaScript from './javascript'; +import Assignment from './assignment'; +import Condition from './condition'; +import Paren from './paren'; +import Media from './media'; +import UnicodeDescriptor from './unicode-descriptor'; +import Negative from './negative'; +import Extend from './extend'; +import VariableCall from './variable-call'; +import NamespaceValue from './namespace-value'; -module.exports = tree; +// mixins +import MixinCall from './mixin-call'; +import MixinDefinition from './mixin-definition'; + +export default { + Node, Color, AtRule, DetachedRuleset, Operation, + Dimension, Unit, Keyword, Variable, Property, + Ruleset, Element, Attribute, Combinator, Selector, + Quoted, Expression, Declaration, Call, URL, Import, + Comment, Anonymous, Value, JavaScript, Assignment, + Condition, Paren, Media, UnicodeDescriptor, Negative, + Extend, VariableCall, NamespaceValue, + mixin: { + Call: MixinCall, + Definition: MixinDefinition + } +}; \ No newline at end of file diff --git a/lib/less/tree/javascript.js b/lib/less/tree/javascript.js index 9e77e797d..f4e373328 100644 --- a/lib/less/tree/javascript.js +++ b/lib/less/tree/javascript.js @@ -1,29 +1,33 @@ -var JsEvalNode = require('./js-eval-node'), - Dimension = require('./dimension'), - Quoted = require('./quoted'), - Anonymous = require('./anonymous'); +import JsEvalNode from './js-eval-node'; +import Dimension from './dimension'; +import Quoted from './quoted'; +import Anonymous from './anonymous'; -var JavaScript = function (string, escaped, index, currentFileInfo) { - this.escaped = escaped; - this.expression = string; - this._index = index; - this._fileInfo = currentFileInfo; -}; -JavaScript.prototype = new JsEvalNode(); -JavaScript.prototype.type = 'JavaScript'; -JavaScript.prototype.eval = function(context) { - var result = this.evaluateJavaScript(this.expression, context); - var type = typeof result; +class JavaScript extends JsEvalNode { + constructor(string, escaped, index, currentFileInfo) { + super(); - if (type === 'number' && !isNaN(result)) { - return new Dimension(result); - } else if (type === 'string') { - return new Quoted('"' + result + '"', result, this.escaped, this._index); - } else if (Array.isArray(result)) { - return new Anonymous(result.join(', ')); - } else { - return new Anonymous(result); + this.escaped = escaped; + this.expression = string; + this._index = index; + this._fileInfo = currentFileInfo; } -}; -module.exports = JavaScript; + eval(context) { + const result = this.evaluateJavaScript(this.expression, context); + const type = typeof result; + + if (type === 'number' && !isNaN(result)) { + return new Dimension(result); + } else if (type === 'string') { + return new Quoted(`"${result}"`, result, this.escaped, this._index); + } else if (Array.isArray(result)) { + return new Anonymous(result.join(', ')); + } else { + return new Anonymous(result); + } + } +} + +JavaScript.prototype.type = 'JavaScript'; +export default JavaScript; diff --git a/lib/less/tree/js-eval-node.js b/lib/less/tree/js-eval-node.js index f168fe9d7..5fbb018c1 100644 --- a/lib/less/tree/js-eval-node.js +++ b/lib/less/tree/js-eval-node.js @@ -1,61 +1,58 @@ -var Node = require('./node'), - Variable = require('./variable'); - -var JsEvalNode = function() { -}; -JsEvalNode.prototype = new Node(); - -JsEvalNode.prototype.evaluateJavaScript = function (expression, context) { - var result, - that = this, - evalContext = {}; - - if (!context.javascriptEnabled) { - throw { message: 'Inline JavaScript is not enabled. Is it set in your options?', - filename: this.fileInfo().filename, - index: this.getIndex() }; - } +import Node from './node'; +import Variable from './variable'; + +class JsEvalNode extends Node { + evaluateJavaScript(expression, context) { + let result; + const that = this; + const evalContext = {}; + + if (!context.javascriptEnabled) { + throw { message: 'Inline JavaScript is not enabled. Is it set in your options?', + filename: this.fileInfo().filename, + index: this.getIndex() }; + } - expression = expression.replace(/@\{([\w-]+)\}/g, function (_, name) { - return that.jsify(new Variable('@' + name, that.getIndex(), that.fileInfo()).eval(context)); - }); + expression = expression.replace(/@\{([\w-]+)\}/g, (_, name) => that.jsify(new Variable(`@${name}`, that.getIndex(), that.fileInfo()).eval(context))); - try { - expression = new Function('return (' + expression + ')'); - } catch (e) { - throw { message: 'JavaScript evaluation error: ' + e.message + ' from `' + expression + '`' , - filename: this.fileInfo().filename, - index: this.getIndex() }; - } + try { + expression = new Function(`return (${expression})`); + } catch (e) { + throw { message: `JavaScript evaluation error: ${e.message} from \`${expression}\`` , + filename: this.fileInfo().filename, + index: this.getIndex() }; + } - var variables = context.frames[0].variables(); - for (var k in variables) { - if (variables.hasOwnProperty(k)) { - /* jshint loopfunc:true */ - evalContext[k.slice(1)] = { - value: variables[k].value, - toJS: function () { - return this.value.eval(context).toCSS(); - } - }; + const variables = context.frames[0].variables(); + for (const k in variables) { + if (variables.hasOwnProperty(k)) { + /* jshint loopfunc:true */ + evalContext[k.slice(1)] = { + value: variables[k].value, + toJS: function () { + return this.value.eval(context).toCSS(); + } + }; + } } - } - try { - result = expression.call(evalContext); - } catch (e) { - throw { message: 'JavaScript evaluation error: \'' + e.name + ': ' + e.message.replace(/["]/g, '\'') + '\'' , - filename: this.fileInfo().filename, - index: this.getIndex() }; + try { + result = expression.call(evalContext); + } catch (e) { + throw { message: `JavaScript evaluation error: '${e.name}: ${e.message.replace(/["]/g, '\'')}'` , + filename: this.fileInfo().filename, + index: this.getIndex() }; + } + return result; } - return result; -}; -JsEvalNode.prototype.jsify = function (obj) { - if (Array.isArray(obj.value) && (obj.value.length > 1)) { - return '[' + obj.value.map(function (v) { return v.toCSS(); }).join(', ') + ']'; - } else { - return obj.toCSS(); + + jsify(obj) { + if (Array.isArray(obj.value) && (obj.value.length > 1)) { + return `[${obj.value.map(v => v.toCSS()).join(', ')}]`; + } else { + return obj.toCSS(); + } } -}; +} -module.exports = JsEvalNode; +export default JsEvalNode; diff --git a/lib/less/tree/keyword.js b/lib/less/tree/keyword.js index 16c0b8700..20199f587 100644 --- a/lib/less/tree/keyword.js +++ b/lib/less/tree/keyword.js @@ -1,14 +1,21 @@ -var Node = require('./node'); +import Node from './node'; + +class Keyword extends Node { + constructor(value) { + super(); + + this.value = value; + } + + genCSS(context, output) { + if (this.value === '%') { throw { type: 'Syntax', message: 'Invalid % without number' }; } + output.add(this.value); + } +} -var Keyword = function (value) { this.value = value; }; -Keyword.prototype = new Node(); Keyword.prototype.type = 'Keyword'; -Keyword.prototype.genCSS = function (context, output) { - if (this.value === '%') { throw { type: 'Syntax', message: 'Invalid % without number' }; } - output.add(this.value); -}; Keyword.True = new Keyword('true'); Keyword.False = new Keyword('false'); -module.exports = Keyword; +export default Keyword; diff --git a/lib/less/tree/media.js b/lib/less/tree/media.js index cda552668..684537208 100644 --- a/lib/less/tree/media.js +++ b/lib/less/tree/media.js @@ -1,141 +1,154 @@ -var Ruleset = require('./ruleset'), - Value = require('./value'), - Selector = require('./selector'), - Anonymous = require('./anonymous'), - Expression = require('./expression'), - AtRule = require('./atrule'), - utils = require('../utils'); - -var Media = function (value, features, index, currentFileInfo, visibilityInfo) { - this._index = index; - this._fileInfo = currentFileInfo; - - var selectors = (new Selector([], null, null, this._index, this._fileInfo)).createEmptySelectors(); - - this.features = new Value(features); - this.rules = [new Ruleset(selectors, value)]; - this.rules[0].allowImports = true; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; - this.setParent(selectors, this); - this.setParent(this.features, this); - this.setParent(this.rules, this); -}; -Media.prototype = new AtRule(); -Media.prototype.type = 'Media'; -Media.prototype.isRulesetLike = function() { return true; }; -Media.prototype.accept = function (visitor) { - if (this.features) { - this.features = visitor.visit(this.features); +import Ruleset from './ruleset'; +import Value from './value'; +import Selector from './selector'; +import Anonymous from './anonymous'; +import Expression from './expression'; +import AtRule from './atrule'; +import * as utils from '../utils'; + +class Media extends AtRule { + constructor(value, features, index, currentFileInfo, visibilityInfo) { + super(); + + this._index = index; + this._fileInfo = currentFileInfo; + + const selectors = (new Selector([], null, null, this._index, this._fileInfo)).createEmptySelectors(); + + this.features = new Value(features); + this.rules = [new Ruleset(selectors, value)]; + this.rules[0].allowImports = true; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + this.setParent(selectors, this); + this.setParent(this.features, this); + this.setParent(this.rules, this); } - if (this.rules) { - this.rules = visitor.visitArray(this.rules); + + isRulesetLike() { + return true; } -}; -Media.prototype.genCSS = function (context, output) { - output.add('@media ', this._fileInfo, this._index); - this.features.genCSS(context, output); - this.outputRuleset(context, output, this.rules); -}; -Media.prototype.eval = function (context) { - if (!context.mediaBlocks) { - context.mediaBlocks = []; - context.mediaPath = []; + + accept(visitor) { + if (this.features) { + this.features = visitor.visit(this.features); + } + if (this.rules) { + this.rules = visitor.visitArray(this.rules); + } } - var media = new Media(null, [], this._index, this._fileInfo, this.visibilityInfo()); - if (this.debugInfo) { - this.rules[0].debugInfo = this.debugInfo; - media.debugInfo = this.debugInfo; + genCSS(context, output) { + output.add('@media ', this._fileInfo, this._index); + this.features.genCSS(context, output); + this.outputRuleset(context, output, this.rules); } - - media.features = this.features.eval(context); - - context.mediaPath.push(media); - context.mediaBlocks.push(media); - - this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit(); - context.frames.unshift(this.rules[0]); - media.rules = [this.rules[0].eval(context)]; - context.frames.shift(); - - context.mediaPath.pop(); - - return context.mediaPath.length === 0 ? media.evalTop(context) : - media.evalNested(context); -}; -Media.prototype.evalTop = function (context) { - var result = this; - - // Render all dependent Media blocks. - if (context.mediaBlocks.length > 1) { - var selectors = (new Selector([], null, null, this.getIndex(), this.fileInfo())).createEmptySelectors(); - result = new Ruleset(selectors, context.mediaBlocks); - result.multiMedia = true; - result.copyVisibilityInfo(this.visibilityInfo()); - this.setParent(result, this); + + eval(context) { + if (!context.mediaBlocks) { + context.mediaBlocks = []; + context.mediaPath = []; + } + + const media = new Media(null, [], this._index, this._fileInfo, this.visibilityInfo()); + if (this.debugInfo) { + this.rules[0].debugInfo = this.debugInfo; + media.debugInfo = this.debugInfo; + } + + media.features = this.features.eval(context); + + context.mediaPath.push(media); + context.mediaBlocks.push(media); + + this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit(); + context.frames.unshift(this.rules[0]); + media.rules = [this.rules[0].eval(context)]; + context.frames.shift(); + + context.mediaPath.pop(); + + return context.mediaPath.length === 0 ? media.evalTop(context) : + media.evalNested(context); } - delete context.mediaBlocks; - delete context.mediaPath; + evalTop(context) { + let result = this; - return result; -}; -Media.prototype.evalNested = function (context) { - var i, value, - path = context.mediaPath.concat([this]); + // Render all dependent Media blocks. + if (context.mediaBlocks.length > 1) { + const selectors = (new Selector([], null, null, this.getIndex(), this.fileInfo())).createEmptySelectors(); + result = new Ruleset(selectors, context.mediaBlocks); + result.multiMedia = true; + result.copyVisibilityInfo(this.visibilityInfo()); + this.setParent(result, this); + } - // Extract the media-query conditions separated with `,` (OR). - for (i = 0; i < path.length; i++) { - value = path[i].features instanceof Value ? - path[i].features.value : path[i].features; - path[i] = Array.isArray(value) ? value : [value]; + delete context.mediaBlocks; + delete context.mediaPath; + + return result; } - // Trace all permutations to generate the resulting media-query. - // - // (a, b and c) with nested (d, e) -> - // a and d - // a and e - // b and c and d - // b and c and e - this.features = new Value(this.permute(path).map(function (path) { - path = path.map(function (fragment) { - return fragment.toCSS ? fragment : new Anonymous(fragment); - }); - - for (i = path.length - 1; i > 0; i--) { - path.splice(i, 0, new Anonymous('and')); + evalNested(context) { + let i; + let value; + const path = context.mediaPath.concat([this]); + + // Extract the media-query conditions separated with `,` (OR). + for (i = 0; i < path.length; i++) { + value = path[i].features instanceof Value ? + path[i].features.value : path[i].features; + path[i] = Array.isArray(value) ? value : [value]; } - return new Expression(path); - })); - this.setParent(this.features, this); - - // Fake a tree-node that doesn't output anything. - return new Ruleset([], []); -}; -Media.prototype.permute = function (arr) { - if (arr.length === 0) { - return []; - } else if (arr.length === 1) { - return arr[0]; - } else { - var result = []; - var rest = this.permute(arr.slice(1)); - for (var i = 0; i < rest.length; i++) { - for (var j = 0; j < arr[0].length; j++) { - result.push([arr[0][j]].concat(rest[i])); + // Trace all permutations to generate the resulting media-query. + // + // (a, b and c) with nested (d, e) -> + // a and d + // a and e + // b and c and d + // b and c and e + this.features = new Value(this.permute(path).map(path => { + path = path.map(fragment => fragment.toCSS ? fragment : new Anonymous(fragment)); + + for (i = path.length - 1; i > 0; i--) { + path.splice(i, 0, new Anonymous('and')); } + + return new Expression(path); + })); + this.setParent(this.features, this); + + // Fake a tree-node that doesn't output anything. + return new Ruleset([], []); + } + + permute(arr) { + if (arr.length === 0) { + return []; + } else if (arr.length === 1) { + return arr[0]; + } else { + const result = []; + const rest = this.permute(arr.slice(1)); + for (let i = 0; i < rest.length; i++) { + for (let j = 0; j < arr[0].length; j++) { + result.push([arr[0][j]].concat(rest[i])); + } + } + return result; } - return result; } -}; -Media.prototype.bubbleSelectors = function (selectors) { - if (!selectors) { - return; + + bubbleSelectors(selectors) { + if (!selectors) { + return; + } + this.rules = [new Ruleset(utils.copyArray(selectors), [this.rules[0]])]; + this.setParent(this.rules, this); } - this.rules = [new Ruleset(utils.copyArray(selectors), [this.rules[0]])]; - this.setParent(this.rules, this); -}; -module.exports = Media; +} + +Media.prototype.type = 'Media'; +export default Media; diff --git a/lib/less/tree/mixin-call.js b/lib/less/tree/mixin-call.js index 49784f02a..ec63968da 100644 --- a/lib/less/tree/mixin-call.js +++ b/lib/less/tree/mixin-call.js @@ -1,179 +1,205 @@ -var Node = require('./node'), - Selector = require('./selector'), - MixinDefinition = require('./mixin-definition'), - defaultFunc = require('../functions/default'); - -var MixinCall = function (elements, args, index, currentFileInfo, important) { - this.selector = new Selector(elements); - this.arguments = args || []; - this._index = index; - this._fileInfo = currentFileInfo; - this.important = important; - this.allowRoot = true; - this.setParent(this.selector, this); -}; -MixinCall.prototype = new Node(); -MixinCall.prototype.type = 'MixinCall'; -MixinCall.prototype.accept = function (visitor) { - if (this.selector) { - this.selector = visitor.visit(this.selector); +import Node from './node'; +import Selector from './selector'; +import MixinDefinition from './mixin-definition'; +import defaultFunc from '../functions/default'; + +class MixinCall extends Node { + constructor(elements, args, index, currentFileInfo, important) { + super(); + + this.selector = new Selector(elements); + this.arguments = args || []; + this._index = index; + this._fileInfo = currentFileInfo; + this.important = important; + this.allowRoot = true; + this.setParent(this.selector, this); } - if (this.arguments.length) { - this.arguments = visitor.visitArray(this.arguments); + + accept(visitor) { + if (this.selector) { + this.selector = visitor.visit(this.selector); + } + if (this.arguments.length) { + this.arguments = visitor.visitArray(this.arguments); + } } -}; -MixinCall.prototype.eval = function (context) { - var mixins, mixin, mixinPath, args = [], arg, argValue, - rules = [], match = false, i, m, f, isRecursive, isOneFound, - candidates = [], candidate, conditionResult = [], defaultResult, defFalseEitherCase = -1, - defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset, noArgumentsFilter; - - this.selector = this.selector.eval(context); - - function calcDefGroup(mixin, mixinPath) { - var f, p, namespace; - - for (f = 0; f < 2; f++) { - conditionResult[f] = true; - defaultFunc.value(f); - for (p = 0; p < mixinPath.length && conditionResult[f]; p++) { - namespace = mixinPath[p]; - if (namespace.matchCondition) { - conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, context); + + eval(context) { + let mixins; + let mixin; + let mixinPath; + const args = []; + let arg; + let argValue; + const rules = []; + let match = false; + let i; + let m; + let f; + let isRecursive; + let isOneFound; + const candidates = []; + let candidate; + const conditionResult = []; + let defaultResult; + const defFalseEitherCase = -1; + const defNone = 0; + const defTrue = 1; + const defFalse = 2; + let count; + let originalRuleset; + let noArgumentsFilter; + + this.selector = this.selector.eval(context); + + function calcDefGroup(mixin, mixinPath) { + let f; + let p; + let namespace; + + for (f = 0; f < 2; f++) { + conditionResult[f] = true; + defaultFunc.value(f); + for (p = 0; p < mixinPath.length && conditionResult[f]; p++) { + namespace = mixinPath[p]; + if (namespace.matchCondition) { + conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, context); + } + } + if (mixin.matchCondition) { + conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, context); } } - if (mixin.matchCondition) { - conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, context); - } - } - if (conditionResult[0] || conditionResult[1]) { - if (conditionResult[0] != conditionResult[1]) { - return conditionResult[1] ? - defTrue : defFalse; - } + if (conditionResult[0] || conditionResult[1]) { + if (conditionResult[0] != conditionResult[1]) { + return conditionResult[1] ? + defTrue : defFalse; + } - return defNone; + return defNone; + } + return defFalseEitherCase; } - return defFalseEitherCase; - } - for (i = 0; i < this.arguments.length; i++) { - arg = this.arguments[i]; - argValue = arg.value.eval(context); - if (arg.expand && Array.isArray(argValue.value)) { - argValue = argValue.value; - for (m = 0; m < argValue.length; m++) { - args.push({value: argValue[m]}); + for (i = 0; i < this.arguments.length; i++) { + arg = this.arguments[i]; + argValue = arg.value.eval(context); + if (arg.expand && Array.isArray(argValue.value)) { + argValue = argValue.value; + for (m = 0; m < argValue.length; m++) { + args.push({value: argValue[m]}); + } + } else { + args.push({name: arg.name, value: argValue}); } - } else { - args.push({name: arg.name, value: argValue}); } - } - noArgumentsFilter = function(rule) {return rule.matchArgs(null, context);}; - - for (i = 0; i < context.frames.length; i++) { - if ((mixins = context.frames[i].find(this.selector, null, noArgumentsFilter)).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].rule; - mixinPath = mixins[m].path; - isRecursive = false; - for (f = 0; f < context.frames.length; f++) { - if ((!(mixin instanceof MixinDefinition)) && mixin === (context.frames[f].originalRuleset || context.frames[f])) { - isRecursive = true; - break; + noArgumentsFilter = rule => rule.matchArgs(null, context); + + for (i = 0; i < context.frames.length; i++) { + if ((mixins = context.frames[i].find(this.selector, null, noArgumentsFilter)).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].rule; + mixinPath = mixins[m].path; + isRecursive = false; + for (f = 0; f < context.frames.length; f++) { + if ((!(mixin instanceof MixinDefinition)) && mixin === (context.frames[f].originalRuleset || context.frames[f])) { + isRecursive = true; + break; + } + } + if (isRecursive) { + continue; } - } - if (isRecursive) { - continue; - } - if (mixin.matchArgs(args, context)) { - candidate = {mixin: mixin, group: calcDefGroup(mixin, mixinPath)}; + if (mixin.matchArgs(args, context)) { + candidate = {mixin, group: calcDefGroup(mixin, mixinPath)}; - if (candidate.group !== defFalseEitherCase) { - candidates.push(candidate); - } + if (candidate.group !== defFalseEitherCase) { + candidates.push(candidate); + } - match = true; + match = true; + } } - } - defaultFunc.reset(); + defaultFunc.reset(); - count = [0, 0, 0]; - for (m = 0; m < candidates.length; m++) { - count[candidates[m].group]++; - } + 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.getIndex(), filename: this.fileInfo().filename }; + 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.getIndex(), filename: this.fileInfo().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 MixinDefinition)) { - originalRuleset = mixin.originalRuleset || mixin; - mixin = new MixinDefinition('', [], mixin.rules, null, false, null, originalRuleset.visibilityInfo()); - mixin.originalRuleset = originalRuleset; + for (m = 0; m < candidates.length; m++) { + candidate = candidates[m].group; + if ((candidate === defNone) || (candidate === defaultResult)) { + try { + mixin = candidates[m].mixin; + if (!(mixin instanceof MixinDefinition)) { + originalRuleset = mixin.originalRuleset || mixin; + mixin = new MixinDefinition('', [], mixin.rules, null, false, null, originalRuleset.visibilityInfo()); + mixin.originalRuleset = originalRuleset; + } + const newRules = mixin.evalCall(context, args, this.important).rules; + this._setVisibilityToReplacement(newRules); + Array.prototype.push.apply(rules, newRules); + } catch (e) { + throw { message: e.message, index: this.getIndex(), filename: this.fileInfo().filename, stack: e.stack }; } - var newRules = mixin.evalCall(context, args, this.important).rules; - this._setVisibilityToReplacement(newRules); - Array.prototype.push.apply(rules, newRules); - } catch (e) { - throw { message: e.message, index: this.getIndex(), filename: this.fileInfo().filename, stack: e.stack }; } } - } - if (match) { - return rules; + if (match) { + return rules; + } } } + if (isOneFound) { + throw { type: 'Runtime', + message: `No matching definition was found for \`${this.format(args)}\``, + index: this.getIndex(), filename: this.fileInfo().filename }; + } else { + throw { type: 'Name', + message: `${this.selector.toCSS().trim()} is undefined`, + index: this.getIndex(), filename: this.fileInfo().filename }; + } } - if (isOneFound) { - throw { type: 'Runtime', - message: 'No matching definition was found for `' + this.format(args) + '`', - index: this.getIndex(), filename: this.fileInfo().filename }; - } else { - throw { type: 'Name', - message: this.selector.toCSS().trim() + ' is undefined', - index: this.getIndex(), filename: this.fileInfo().filename }; - } -}; - -MixinCall.prototype._setVisibilityToReplacement = function (replacement) { - var i, rule; - if (this.blocksVisibility()) { - for (i = 0; i < replacement.length; i++) { - rule = replacement[i]; - rule.addVisibilityBlock(); + + _setVisibilityToReplacement(replacement) { + let i; + let rule; + if (this.blocksVisibility()) { + for (i = 0; i < replacement.length; i++) { + rule = replacement[i]; + rule.addVisibilityBlock(); + } } } -}; -MixinCall.prototype.format = function (args) { - return this.selector.toCSS().trim() + '(' + - (args ? args.map(function (a) { - var argValue = ''; + + format(args) { + return `${this.selector.toCSS().trim()}(${args ? args.map(a => { + let argValue = ''; if (a.name) { - argValue += a.name + ':'; + argValue += `${a.name}:`; } if (a.value.toCSS) { argValue += a.value.toCSS(); @@ -181,6 +207,9 @@ MixinCall.prototype.format = function (args) { argValue += '???'; } return argValue; - }).join(', ') : '') + ')'; -}; -module.exports = MixinCall; + }).join(', ') : ''})`; + } +} + +MixinCall.prototype.type = 'MixinCall'; +export default MixinCall; diff --git a/lib/less/tree/mixin-definition.js b/lib/less/tree/mixin-definition.js index 3d0cc6252..0feb8e577 100644 --- a/lib/less/tree/mixin-definition.js +++ b/lib/less/tree/mixin-definition.js @@ -1,209 +1,229 @@ -var Selector = require('./selector'), - Element = require('./element'), - Ruleset = require('./ruleset'), - Declaration = require('./declaration'), - DetachedRuleset = require('./detached-ruleset'), - Expression = require('./expression'), - contexts = require('../contexts'), - utils = require('../utils'); - -var Definition = function (name, params, rules, condition, variadic, frames, visibilityInfo) { - this.name = name || 'anonymous mixin'; - this.selectors = [new Selector([new Element(null, name, false, this._index, this._fileInfo)])]; - this.params = params; - this.condition = condition; - this.variadic = variadic; - this.arity = params.length; - this.rules = rules; - this._lookups = {}; - var optionalParameters = []; - this.required = params.reduce(function (count, p) { - if (!p.name || (p.name && !p.value)) { - return count + 1; +import Selector from './selector'; +import Element from './element'; +import Ruleset from './ruleset'; +import Declaration from './declaration'; +import DetachedRuleset from './detached-ruleset'; +import Expression from './expression'; +import contexts from '../contexts'; +import * as utils from '../utils'; + +class Definition extends Ruleset { + constructor(name, params, rules, condition, variadic, frames, visibilityInfo) { + super(); + + this.name = name || 'anonymous mixin'; + this.selectors = [new Selector([new Element(null, name, false, this._index, this._fileInfo)])]; + this.params = params; + this.condition = condition; + this.variadic = variadic; + this.arity = params.length; + this.rules = rules; + this._lookups = {}; + const optionalParameters = []; + this.required = params.reduce((count, p) => { + if (!p.name || (p.name && !p.value)) { + return count + 1; + } + else { + optionalParameters.push(p.name); + return count; + } + }, 0); + this.optionalParameters = optionalParameters; + this.frames = frames; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + } + + accept(visitor) { + if (this.params && this.params.length) { + this.params = visitor.visitArray(this.params); } - else { - optionalParameters.push(p.name); - return count; + this.rules = visitor.visitArray(this.rules); + if (this.condition) { + this.condition = visitor.visit(this.condition); } - }, 0); - this.optionalParameters = optionalParameters; - this.frames = frames; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; -}; -Definition.prototype = new Ruleset(); -Definition.prototype.type = 'MixinDefinition'; -Definition.prototype.evalFirst = true; -Definition.prototype.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); - } -}; -Definition.prototype.evalParams = function (context, mixinEnv, args, evaldArguments) { - /* jshint boss:true */ - var frame = new Ruleset(null, null), - varargs, arg, - params = utils.copyArray(this.params), - i, j, val, name, isNamedFound, argIndex, argsLength = 0; - - if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) { - frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit(); - } - mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames)); - - if (args) { - args = utils.copyArray(args); - 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(context); - frame.prependRule(new Declaration(name, arg.value.eval(context))); - isNamedFound = true; - break; + + evalParams(context, mixinEnv, args, evaldArguments) { + /* jshint boss:true */ + const frame = new Ruleset(null, null); + + let varargs; + let arg; + const params = utils.copyArray(this.params); + let i; + let j; + let val; + let name; + let isNamedFound; + let argIndex; + let argsLength = 0; + + if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) { + frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit(); + } + mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames)); + + if (args) { + args = utils.copyArray(args); + 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(context); + frame.prependRule(new Declaration(name, arg.value.eval(context))); + 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` }; } - } - 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; } + argIndex = 0; + for (i = 0; i < params.length; i++) { + if (evaldArguments[i]) { continue; } - arg = args && args[argIndex]; + 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(context)); - } - frame.prependRule(new Declaration(name, new Expression(varargs).eval(context))); - } else { - val = arg && arg.value; - if (val) { - // This was a mixin call, pass in a detached ruleset of it's eval'd rules - if (Array.isArray(val)) { - val = new DetachedRuleset(new Ruleset('', val)); - } - else { - val = val.eval(context); + if (name = params[i].name) { + if (params[i].variadic) { + varargs = []; + for (j = argIndex; j < argsLength; j++) { + varargs.push(args[j].value.eval(context)); } - } else if (params[i].value) { - val = params[i].value.eval(mixinEnv); - frame.resetCache(); + frame.prependRule(new Declaration(name, new Expression(varargs).eval(context))); } else { - throw { type: 'Runtime', message: 'wrong number of arguments for ' + this.name + - ' (' + argsLength + ' for ' + this.arity + ')' }; - } + val = arg && arg.value; + if (val) { + // This was a mixin call, pass in a detached ruleset of it's eval'd rules + if (Array.isArray(val)) { + val = new DetachedRuleset(new Ruleset('', val)); + } + else { + val = val.eval(context); + } + } 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 Declaration(name, val)); - evaldArguments[i] = val; + frame.prependRule(new Declaration(name, val)); + evaldArguments[i] = val; + } } - } - if (params[i].variadic && args) { - for (j = argIndex; j < argsLength; j++) { - evaldArguments[j] = args[j].value.eval(context); + if (params[i].variadic && args) { + for (j = argIndex; j < argsLength; j++) { + evaldArguments[j] = args[j].value.eval(context); + } } + argIndex++; } - argIndex++; + + return frame; } - return frame; -}; -Definition.prototype.makeImportant = function() { - var rules = !this.rules ? this.rules : this.rules.map(function (r) { - if (r.makeImportant) { - return r.makeImportant(true); - } else { - return r; - } - }); - var result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames); - return result; -}; -Definition.prototype.eval = function (context) { - return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || utils.copyArray(context.frames)); -}; -Definition.prototype.evalCall = function (context, args, important) { - var _arguments = [], - mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames, - frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments), - rules, ruleset; - - frame.prependRule(new Declaration('@arguments', new Expression(_arguments).eval(context))); - - rules = utils.copyArray(this.rules); - - ruleset = new Ruleset(null, rules); - ruleset.originalRuleset = this; - ruleset = ruleset.eval(new contexts.Eval(context, [this, frame].concat(mixinFrames))); - if (important) { - ruleset = ruleset.makeImportant(); + makeImportant() { + const rules = !this.rules ? this.rules : this.rules.map(r => { + if (r.makeImportant) { + return r.makeImportant(true); + } else { + return r; + } + }); + const result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames); + return result; } - return ruleset; -}; -Definition.prototype.matchCondition = function (args, context) { - if (this.condition && !this.condition.eval( - new contexts.Eval(context, - [this.evalParams(context, /* the parameter variables */ - new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])] - .concat(this.frames || []) // the parent namespace/mixin frames - .concat(context.frames)))) { // the current environment frames - return false; + + eval(context) { + return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || utils.copyArray(context.frames)); } - return true; -}; -Definition.prototype.matchArgs = function (args, context) { - var allArgsCnt = (args && args.length) || 0, len, optionalParameters = this.optionalParameters; - var requiredArgsCnt = !args ? 0 : args.reduce(function (count, p) { - if (optionalParameters.indexOf(p.name) < 0) { - return count + 1; - } else { - return count; - } - }, 0); - if (!this.variadic) { - if (requiredArgsCnt < this.required) { - return false; - } - if (allArgsCnt > this.params.length) { - return false; + evalCall(context, args, important) { + const _arguments = []; + const mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames; + const frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments); + let rules; + let ruleset; + + frame.prependRule(new Declaration('@arguments', new Expression(_arguments).eval(context))); + + rules = utils.copyArray(this.rules); + + ruleset = new Ruleset(null, rules); + ruleset.originalRuleset = this; + ruleset = ruleset.eval(new contexts.Eval(context, [this, frame].concat(mixinFrames))); + if (important) { + ruleset = ruleset.makeImportant(); } - } else { - if (requiredArgsCnt < (this.required - 1)) { + return ruleset; + } + + matchCondition(args, context) { + if (this.condition && !this.condition.eval( + new contexts.Eval(context, + [this.evalParams(context, /* the parameter variables */ + new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])] + .concat(this.frames || []) // the parent namespace/mixin frames + .concat(context.frames)))) { // the current environment frames return false; } + return true; } - // check patterns - len = Math.min(requiredArgsCnt, this.arity); + matchArgs(args, context) { + const allArgsCnt = (args && args.length) || 0; + let len; + const optionalParameters = this.optionalParameters; + const requiredArgsCnt = !args ? 0 : args.reduce((count, p) => { + if (optionalParameters.indexOf(p.name) < 0) { + return count + 1; + } else { + return count; + } + }, 0); - for (var i = 0; i < len; i++) { - if (!this.params[i].name && !this.params[i].variadic) { - if (args[i].value.eval(context).toCSS() != this.params[i].value.eval(context).toCSS()) { + if (!this.variadic) { + if (requiredArgsCnt < this.required) { + return false; + } + if (allArgsCnt > this.params.length) { + return false; + } + } else { + if (requiredArgsCnt < (this.required - 1)) { return false; } } + + // check patterns + len = Math.min(requiredArgsCnt, this.arity); + + for (let i = 0; i < len; i++) { + if (!this.params[i].name && !this.params[i].variadic) { + if (args[i].value.eval(context).toCSS() != this.params[i].value.eval(context).toCSS()) { + return false; + } + } + } + return true; } - return true; -}; -module.exports = Definition; +} + +Definition.prototype.type = 'MixinDefinition'; +Definition.prototype.evalFirst = true; +export default Definition; diff --git a/lib/less/tree/namespace-value.js b/lib/less/tree/namespace-value.js index 3ef109cc9..b1425e846 100644 --- a/lib/less/tree/namespace-value.js +++ b/lib/less/tree/namespace-value.js @@ -1,79 +1,87 @@ -var Node = require('./node'), - Variable = require('./variable'), - Ruleset = require('./ruleset'), - Selector = require('./selector'); +import Node from './node'; +import Variable from './variable'; +import Ruleset from './ruleset'; +import Selector from './selector'; -var NamespaceValue = function (ruleCall, lookups, important, index, fileInfo) { - this.value = ruleCall; - this.lookups = lookups; - this.important = important; - this._index = index; - this._fileInfo = fileInfo; -}; -NamespaceValue.prototype = new Node(); -NamespaceValue.prototype.type = 'NamespaceValue'; -NamespaceValue.prototype.eval = function (context) { - var i, j, name, rules = this.value.eval(context); - - for (i = 0; i < this.lookups.length; i++) { - name = this.lookups[i]; +class NamespaceValue extends Node { + constructor(ruleCall, lookups, important, index, fileInfo) { + super(); - /** - * Eval'd DRs return rulesets. - * Eval'd mixins return rules, so let's make a ruleset if we need it. - * We need to do this because of late parsing of values - */ - if (Array.isArray(rules)) { - rules = new Ruleset([new Selector()], rules); - } + this.value = ruleCall; + this.lookups = lookups; + this.important = important; + this._index = index; + this._fileInfo = fileInfo; + } - if (name === '') { - rules = rules.lastDeclaration(); - } - else if (name.charAt(0) === '@') { - if (name.charAt(1) === '@') { - name = '@' + new Variable(name.substr(1)).eval(context).value; + eval(context) { + let i; + let j; + let name; + let rules = this.value.eval(context); + + for (i = 0; i < this.lookups.length; i++) { + name = this.lookups[i]; + + /** + * Eval'd DRs return rulesets. + * Eval'd mixins return rules, so let's make a ruleset if we need it. + * We need to do this because of late parsing of values + */ + if (Array.isArray(rules)) { + rules = new Ruleset([new Selector()], rules); } - if (rules.variables) { - rules = rules.variable(name); + + if (name === '') { + rules = rules.lastDeclaration(); } - - if (!rules) { - throw { type: 'Name', - message: 'variable ' + name + ' not found', - filename: this.fileInfo().filename, - index: this.getIndex() }; - } - } - else { - if (name.substring(0, 2) === '$@') { - name = '$' + new Variable(name.substr(1)).eval(context).value; + else if (name.charAt(0) === '@') { + if (name.charAt(1) === '@') { + name = `@${new Variable(name.substr(1)).eval(context).value}`; + } + if (rules.variables) { + rules = rules.variable(name); + } + + if (!rules) { + throw { type: 'Name', + message: `variable ${name} not found`, + filename: this.fileInfo().filename, + index: this.getIndex() }; + } } else { - name = name.charAt(0) === '$' ? name : '$' + name; + if (name.substring(0, 2) === '$@') { + name = `$${new Variable(name.substr(1)).eval(context).value}`; + } + else { + name = name.charAt(0) === '$' ? name : `$${name}`; + } + if (rules.properties) { + rules = rules.property(name); + } + + if (!rules) { + throw { type: 'Name', + message: `property "${name.substr(1)}" not found`, + filename: this.fileInfo().filename, + index: this.getIndex() }; + } + // Properties are an array of values, since a ruleset can have multiple props. + // We pick the last one (the "cascaded" value) + rules = rules[rules.length - 1]; } - if (rules.properties) { - rules = rules.property(name); + + if (rules.value) { + rules = rules.eval(context).value; } - - if (!rules) { - throw { type: 'Name', - message: 'property "' + name.substr(1) + '" not found', - filename: this.fileInfo().filename, - index: this.getIndex() }; + if (rules.ruleset) { + rules = rules.ruleset.eval(context); } - // Properties are an array of values, since a ruleset can have multiple props. - // We pick the last one (the "cascaded" value) - rules = rules[rules.length - 1]; - } - - if (rules.value) { - rules = rules.eval(context).value; - } - if (rules.ruleset) { - rules = rules.ruleset.eval(context); } + return rules; } - return rules; -}; -module.exports = NamespaceValue; +} + +NamespaceValue.prototype.type = 'NamespaceValue'; +export default NamespaceValue; diff --git a/lib/less/tree/negative.js b/lib/less/tree/negative.js index 5052dddb1..2e24c0e48 100644 --- a/lib/less/tree/negative.js +++ b/lib/less/tree/negative.js @@ -1,20 +1,26 @@ -var Node = require('./node'), - Operation = require('./operation'), - Dimension = require('./dimension'); +import Node from './node'; +import Operation from './operation'; +import Dimension from './dimension'; -var Negative = function (node) { - this.value = node; -}; -Negative.prototype = new Node(); -Negative.prototype.type = 'Negative'; -Negative.prototype.genCSS = function (context, output) { - output.add('-'); - this.value.genCSS(context, output); -}; -Negative.prototype.eval = function (context) { - if (context.isMathOn()) { - return (new Operation('*', [new Dimension(-1), this.value])).eval(context); +class Negative extends Node { + constructor(node) { + super(); + + this.value = node; + } + + genCSS(context, output) { + output.add('-'); + this.value.genCSS(context, output); } - return new Negative(this.value.eval(context)); -}; -module.exports = Negative; + + eval(context) { + if (context.isMathOn()) { + return (new Operation('*', [new Dimension(-1), this.value])).eval(context); + } + return new Negative(this.value.eval(context)); + } +} + +Negative.prototype.type = 'Negative'; +export default Negative; diff --git a/lib/less/tree/node.js b/lib/less/tree/node.js index fe9e5231a..39d4ec018 100644 --- a/lib/less/tree/node.js +++ b/lib/less/tree/node.js @@ -1,72 +1,144 @@ -var Node = function() { - this.parent = null; - this.visibilityBlocks = undefined; - this.nodeVisible = undefined; - this.rootNode = null; - this.parsed = null; - - var self = this; - Object.defineProperty(this, 'currentFileInfo', { - get: function() { return self.fileInfo(); } - }); - Object.defineProperty(this, 'index', { - get: function() { return self.getIndex(); } - }); +class Node { + constructor() { + this.parent = null; + this.visibilityBlocks = undefined; + this.nodeVisible = undefined; + this.rootNode = null; + this.parsed = null; -}; -Node.prototype.setParent = function(nodes, parent) { - function set(node) { - if (node && node instanceof Node) { - node.parent = parent; + const self = this; + Object.defineProperty(this, 'currentFileInfo', { + get: function() { return self.fileInfo(); } + }); + Object.defineProperty(this, 'index', { + get: function() { return self.getIndex(); } + }); + + } + + setParent(nodes, parent) { + function set(node) { + if (node && node instanceof Node) { + node.parent = parent; + } } + if (Array.isArray(nodes)) { + nodes.forEach(set); + } + else { + set(nodes); + } + } + + getIndex() { + return this._index || (this.parent && this.parent.getIndex()) || 0; } - if (Array.isArray(nodes)) { - nodes.forEach(set); + + fileInfo() { + return this._fileInfo || (this.parent && this.parent.fileInfo()) || {}; } - else { - set(nodes); + + isRulesetLike() { + return false; } -}; -Node.prototype.getIndex = function() { - return this._index || (this.parent && this.parent.getIndex()) || 0; -}; -Node.prototype.fileInfo = function() { - return this._fileInfo || (this.parent && this.parent.fileInfo()) || {}; -}; -Node.prototype.isRulesetLike = function() { return false; }; -Node.prototype.toCSS = function (context) { - var strs = []; - this.genCSS(context, { - add: function(chunk, fileInfo, index) { - strs.push(chunk); - }, - isEmpty: function () { - return strs.length === 0; + + toCSS(context) { + const strs = []; + this.genCSS(context, { + add: function(chunk, fileInfo, index) { + strs.push(chunk); + }, + isEmpty: function () { + return strs.length === 0; + } + }); + return strs.join(''); + } + + genCSS(context, output) { + output.add(this.value); + } + + accept(visitor) { + this.value = visitor.visit(this.value); + } + + eval() { return this; } + + _operate(context, op, a, b) { + switch (op) { + case '+': return a + b; + case '-': return a - b; + case '*': return a * b; + case '/': return a / b; } - }); - return strs.join(''); -}; -Node.prototype.genCSS = function (context, output) { - output.add(this.value); -}; -Node.prototype.accept = function (visitor) { - this.value = visitor.visit(this.value); -}; -Node.prototype.eval = function () { return this; }; -Node.prototype._operate = function (context, op, a, b) { - switch (op) { - case '+': return a + b; - case '-': return a - b; - case '*': return a * b; - case '/': return a / b; } -}; -Node.prototype.fround = function(context, value) { - var precision = context && context.numPrecision; - // add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999...) are properly rounded: - return (precision) ? Number((value + 2e-16).toFixed(precision)) : value; -}; -Node.compare = function (a, b) { + + fround(context, value) { + const precision = context && context.numPrecision; + // add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999...) are properly rounded: + return (precision) ? Number((value + 2e-16).toFixed(precision)) : value; + } + + // Returns true if this node represents root of ast imported by reference + blocksVisibility() { + if (this.visibilityBlocks == null) { + this.visibilityBlocks = 0; + } + return this.visibilityBlocks !== 0; + } + + addVisibilityBlock() { + if (this.visibilityBlocks == null) { + this.visibilityBlocks = 0; + } + this.visibilityBlocks = this.visibilityBlocks + 1; + } + + removeVisibilityBlock() { + if (this.visibilityBlocks == null) { + this.visibilityBlocks = 0; + } + this.visibilityBlocks = this.visibilityBlocks - 1; + } + + // Turns on node visibility - if called node will be shown in output regardless + // of whether it comes from import by reference or not + ensureVisibility() { + this.nodeVisible = true; + } + + // Turns off node visibility - if called node will NOT be shown in output regardless + // of whether it comes from import by reference or not + ensureInvisibility() { + this.nodeVisible = false; + } + + // return values: + // false - the node must not be visible + // true - the node must be visible + // undefined or null - the node has the same visibility as its parent + isVisible() { + return this.nodeVisible; + } + + visibilityInfo() { + return { + visibilityBlocks: this.visibilityBlocks, + nodeVisible: this.nodeVisible + }; + } + + copyVisibilityInfo(info) { + if (!info) { + return; + } + this.visibilityBlocks = info.visibilityBlocks; + this.nodeVisible = info.nodeVisible; + } +} + +Node.compare = (a, b) => { /* returns: -1: a < b 0: a = b @@ -92,7 +164,7 @@ Node.compare = function (a, b) { if (a.length !== b.length) { return undefined; } - for (var i = 0; i < a.length; i++) { + for (let i = 0; i < a.length; i++) { if (Node.compare(a[i], b[i]) !== 0) { return undefined; } @@ -100,58 +172,7 @@ Node.compare = function (a, b) { return 0; }; -Node.numericCompare = function (a, b) { - return a < b ? -1 - : a === b ? 0 +Node.numericCompare = (a, b) => a < b ? -1 + : a === b ? 0 : a > b ? 1 : undefined; -}; -// Returns true if this node represents root of ast imported by reference -Node.prototype.blocksVisibility = function () { - if (this.visibilityBlocks == null) { - this.visibilityBlocks = 0; - } - return this.visibilityBlocks !== 0; -}; -Node.prototype.addVisibilityBlock = function () { - if (this.visibilityBlocks == null) { - this.visibilityBlocks = 0; - } - this.visibilityBlocks = this.visibilityBlocks + 1; -}; -Node.prototype.removeVisibilityBlock = function () { - if (this.visibilityBlocks == null) { - this.visibilityBlocks = 0; - } - this.visibilityBlocks = this.visibilityBlocks - 1; -}; -// Turns on node visibility - if called node will be shown in output regardless -// of whether it comes from import by reference or not -Node.prototype.ensureVisibility = function () { - this.nodeVisible = true; -}; -// Turns off node visibility - if called node will NOT be shown in output regardless -// of whether it comes from import by reference or not -Node.prototype.ensureInvisibility = function () { - this.nodeVisible = false; -}; -// return values: -// false - the node must not be visible -// true - the node must be visible -// undefined or null - the node has the same visibility as its parent -Node.prototype.isVisible = function () { - return this.nodeVisible; -}; -Node.prototype.visibilityInfo = function() { - return { - visibilityBlocks: this.visibilityBlocks, - nodeVisible: this.nodeVisible - }; -}; -Node.prototype.copyVisibilityInfo = function(info) { - if (!info) { - return; - } - this.visibilityBlocks = info.visibilityBlocks; - this.nodeVisible = info.nodeVisible; -}; -module.exports = Node; +export default Node; diff --git a/lib/less/tree/operation.js b/lib/less/tree/operation.js index c292ec231..46a8cf1de 100644 --- a/lib/less/tree/operation.js +++ b/lib/less/tree/operation.js @@ -1,54 +1,62 @@ -var Node = require('./node'), - Color = require('./color'), - Dimension = require('./dimension'), - MATH = require('../constants').Math; - -var Operation = function (op, operands, isSpaced) { - this.op = op.trim(); - this.operands = operands; - this.isSpaced = isSpaced; -}; -Operation.prototype = new Node(); -Operation.prototype.type = 'Operation'; -Operation.prototype.accept = function (visitor) { - this.operands = visitor.visitArray(this.operands); -}; -Operation.prototype.eval = function (context) { - var a = this.operands[0].eval(context), - b = this.operands[1].eval(context), - op; - - if (context.isMathOn(this.op)) { - op = this.op === './' ? '/' : this.op; - if (a instanceof Dimension && b instanceof Color) { - a = a.toColor(); - } - if (b instanceof Dimension && a instanceof Color) { - b = b.toColor(); - } - if (!a.operate) { - if (a instanceof Operation && a.op === '/' && context.math === MATH.PARENS_DIVISION) { - return new Operation(this.op, [a, b], this.isSpaced); - } - throw { type: 'Operation', - message: 'Operation on an invalid type' }; - } +import Node from './node'; +import Color from './color'; +import Dimension from './dimension'; +import * as Constants from '../constants'; +const MATH = Constants.Math; - return a.operate(context, op, b); - } else { - return new Operation(this.op, [a, b], this.isSpaced); + +class Operation extends Node { + constructor(op, operands, isSpaced) { + super(); + + this.op = op.trim(); + this.operands = operands; + this.isSpaced = isSpaced; } -}; -Operation.prototype.genCSS = function (context, output) { - this.operands[0].genCSS(context, output); - if (this.isSpaced) { - output.add(' '); + + accept(visitor) { + this.operands = visitor.visitArray(this.operands); + } + + eval(context) { + let a = this.operands[0].eval(context); + let b = this.operands[1].eval(context); + let op; + + if (context.isMathOn(this.op)) { + op = this.op === './' ? '/' : this.op; + if (a instanceof Dimension && b instanceof Color) { + a = a.toColor(); + } + if (b instanceof Dimension && a instanceof Color) { + b = b.toColor(); + } + if (!a.operate) { + if (a instanceof Operation && a.op === '/' && context.math === MATH.PARENS_DIVISION) { + return new Operation(this.op, [a, b], this.isSpaced); + } + throw { type: 'Operation', + message: 'Operation on an invalid type' }; + } + + return a.operate(context, op, b); + } else { + return new Operation(this.op, [a, b], this.isSpaced); + } } - output.add(this.op); - if (this.isSpaced) { - output.add(' '); + + genCSS(context, output) { + this.operands[0].genCSS(context, output); + if (this.isSpaced) { + output.add(' '); + } + output.add(this.op); + if (this.isSpaced) { + output.add(' '); + } + this.operands[1].genCSS(context, output); } - this.operands[1].genCSS(context, output); -}; +} -module.exports = Operation; +Operation.prototype.type = 'Operation'; +export default Operation; diff --git a/lib/less/tree/paren.js b/lib/less/tree/paren.js index d77956f16..9fd712477 100644 --- a/lib/less/tree/paren.js +++ b/lib/less/tree/paren.js @@ -1,16 +1,22 @@ -var Node = require('./node'); +import Node from './node'; + +class Paren extends Node { + constructor(node) { + super(); + + this.value = node; + } + + genCSS(context, output) { + output.add('('); + this.value.genCSS(context, output); + output.add(')'); + } + + eval(context) { + return new Paren(this.value.eval(context)); + } +} -var Paren = function (node) { - this.value = node; -}; -Paren.prototype = new Node(); Paren.prototype.type = 'Paren'; -Paren.prototype.genCSS = function (context, output) { - output.add('('); - this.value.genCSS(context, output); - output.add(')'); -}; -Paren.prototype.eval = function (context) { - return new Paren(this.value.eval(context)); -}; -module.exports = Paren; +export default Paren; diff --git a/lib/less/tree/property.js b/lib/less/tree/property.js index 34572197b..2deca3349 100644 --- a/lib/less/tree/property.js +++ b/lib/less/tree/property.js @@ -1,70 +1,77 @@ -var Node = require('./node'), - Declaration = require('./declaration'); +import Node from './node'; +import Declaration from './declaration'; -var Property = function (name, index, currentFileInfo) { - this.name = name; - this._index = index; - this._fileInfo = currentFileInfo; -}; -Property.prototype = new Node(); -Property.prototype.type = 'Property'; -Property.prototype.eval = function (context) { - var property, name = this.name; - // TODO: shorten this reference - var mergeRules = context.pluginManager.less.visitors.ToCSSVisitor.prototype._mergeRules; +class Property extends Node { + constructor(name, index, currentFileInfo) { + super(); - if (this.evaluating) { - throw { type: 'Name', - message: 'Recursive property reference for ' + name, - filename: this.fileInfo().filename, - index: this.getIndex() }; + this.name = name; + this._index = index; + this._fileInfo = currentFileInfo; } - this.evaluating = true; + eval(context) { + let property; + const name = this.name; + // TODO: shorten this reference + const mergeRules = context.pluginManager.less.visitors.ToCSSVisitor.prototype._mergeRules; + + if (this.evaluating) { + throw { type: 'Name', + message: `Recursive property reference for ${name}`, + filename: this.fileInfo().filename, + index: this.getIndex() }; + } - property = this.find(context.frames, function (frame) { + this.evaluating = true; - var v, vArr = frame.property(name); - if (vArr) { - for (var i = 0; i < vArr.length; i++) { - v = vArr[i]; + property = this.find(context.frames, frame => { + let v; + const vArr = frame.property(name); + if (vArr) { + for (let i = 0; i < vArr.length; i++) { + v = vArr[i]; - vArr[i] = new Declaration(v.name, - v.value, - v.important, - v.merge, - v.index, - v.currentFileInfo, - v.inline, - v.variable - ); - } - mergeRules(vArr); + vArr[i] = new Declaration(v.name, + v.value, + v.important, + v.merge, + v.index, + v.currentFileInfo, + v.inline, + v.variable + ); + } + mergeRules(vArr); - v = vArr[vArr.length - 1]; - if (v.important) { - var importantScope = context.importantScope[context.importantScope.length - 1]; - importantScope.important = v.important; + v = vArr[vArr.length - 1]; + if (v.important) { + const importantScope = context.importantScope[context.importantScope.length - 1]; + importantScope.important = v.important; + } + v = v.value.eval(context); + return v; } - v = v.value.eval(context); - return v; + }); + if (property) { + this.evaluating = false; + return property; + } else { + throw { type: 'Name', + message: `Property '${name}' is undefined`, + filename: this.currentFileInfo.filename, + index: this.index }; } - }); - if (property) { - this.evaluating = false; - return property; - } else { - throw { type: 'Name', - message: 'Property \'' + name + '\' is undefined', - filename: this.currentFileInfo.filename, - index: this.index }; } -}; -Property.prototype.find = function (obj, fun) { - for (var i = 0, r; i < obj.length; i++) { - r = fun.call(obj, obj[i]); - if (r) { return r; } + + find(obj, fun) { + for (let i = 0, r; i < obj.length; i++) { + r = fun.call(obj, obj[i]); + if (r) { return r; } + } + return null; } - return null; -}; -module.exports = Property; +} + +Property.prototype.type = 'Property'; +export default Property; diff --git a/lib/less/tree/quoted.js b/lib/less/tree/quoted.js index 080552ac7..f3b26e448 100644 --- a/lib/less/tree/quoted.js +++ b/lib/less/tree/quoted.js @@ -1,58 +1,67 @@ -var Node = require('./node'), - Variable = require('./variable'), - Property = require('./property'); +import Node from './node'; +import Variable from './variable'; +import Property from './property'; -var Quoted = function (str, content, escaped, index, currentFileInfo) { - this.escaped = (escaped == null) ? true : escaped; - this.value = content || ''; - this.quote = str.charAt(0); - this._index = index; - this._fileInfo = currentFileInfo; - this.variableRegex = /@\{([\w-]+)\}/g; - this.propRegex = /\$\{([\w-]+)\}/g; -}; -Quoted.prototype = new Node(); -Quoted.prototype.type = 'Quoted'; -Quoted.prototype.genCSS = function (context, output) { - if (!this.escaped) { - output.add(this.quote, this.fileInfo(), this.getIndex()); +class Quoted extends Node { + constructor(str, content, escaped, index, currentFileInfo) { + super(); + + this.escaped = (escaped == null) ? true : escaped; + this.value = content || ''; + this.quote = str.charAt(0); + this._index = index; + this._fileInfo = currentFileInfo; + this.variableRegex = /@\{([\w-]+)\}/g; + this.propRegex = /\$\{([\w-]+)\}/g; } - output.add(this.value); - if (!this.escaped) { - output.add(this.quote); + + genCSS(context, output) { + if (!this.escaped) { + output.add(this.quote, this.fileInfo(), this.getIndex()); + } + output.add(this.value); + if (!this.escaped) { + output.add(this.quote); + } } -}; -Quoted.prototype.containsVariables = function() { - return this.value.match(this.variableRegex); -}; -Quoted.prototype.eval = function (context) { - var that = this, value = this.value; - var variableReplacement = function (_, name) { - var v = new Variable('@' + name, that.getIndex(), that.fileInfo()).eval(context, true); - return (v instanceof Quoted) ? v.value : v.toCSS(); - }; - var propertyReplacement = function (_, name) { - var v = new Property('$' + name, that.getIndex(), that.fileInfo()).eval(context, true); - return (v instanceof Quoted) ? v.value : v.toCSS(); - }; - function iterativeReplace(value, regexp, replacementFnc) { - var evaluatedValue = value; - do { - value = evaluatedValue.toString(); - evaluatedValue = value.replace(regexp, replacementFnc); - } while (value !== evaluatedValue); - return evaluatedValue; + + containsVariables() { + return this.value.match(this.variableRegex); } - value = iterativeReplace(value, this.variableRegex, variableReplacement); - value = iterativeReplace(value, this.propRegex, propertyReplacement); - return new Quoted(this.quote + value + this.quote, value, this.escaped, this.getIndex(), this.fileInfo()); -}; -Quoted.prototype.compare = function (other) { - // when comparing quoted strings allow the quote to differ - if (other.type === 'Quoted' && !this.escaped && !other.escaped) { - return Node.numericCompare(this.value, other.value); - } else { - return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; + + eval(context) { + const that = this; + let value = this.value; + const variableReplacement = (_, name) => { + const v = new Variable(`@${name}`, that.getIndex(), that.fileInfo()).eval(context, true); + return (v instanceof Quoted) ? v.value : v.toCSS(); + }; + const propertyReplacement = (_, name) => { + const v = new Property(`$${name}`, that.getIndex(), that.fileInfo()).eval(context, true); + return (v instanceof Quoted) ? v.value : v.toCSS(); + }; + function iterativeReplace(value, regexp, replacementFnc) { + let evaluatedValue = value; + do { + value = evaluatedValue.toString(); + evaluatedValue = value.replace(regexp, replacementFnc); + } while (value !== evaluatedValue); + return evaluatedValue; + } + value = iterativeReplace(value, this.variableRegex, variableReplacement); + value = iterativeReplace(value, this.propRegex, propertyReplacement); + return new Quoted(this.quote + value + this.quote, value, this.escaped, this.getIndex(), this.fileInfo()); } -}; -module.exports = Quoted; + + compare(other) { + // when comparing quoted strings allow the quote to differ + if (other.type === 'Quoted' && !this.escaped && !other.escaped) { + return Node.numericCompare(this.value, other.value); + } else { + return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined; + } + } +} + +Quoted.prototype.type = 'Quoted'; +export default Quoted; diff --git a/lib/less/tree/ruleset.js b/lib/less/tree/ruleset.js index 89622afb6..a746dbc6e 100644 --- a/lib/less/tree/ruleset.js +++ b/lib/less/tree/ruleset.js @@ -1,808 +1,867 @@ -var Node = require('./node'), - Declaration = require('./declaration'), - Keyword = require('./keyword'), - Comment = require('./comment'), - Paren = require('./paren'), - Selector = require('./selector'), - Element = require('./element'), - Anonymous = require('./anonymous'), - contexts = require('../contexts'), - globalFunctionRegistry = require('../functions/function-registry'), - defaultFunc = require('../functions/default'), - getDebugInfo = require('./debug-info'), - utils = require('../utils'); - -var Ruleset = function (selectors, rules, strictImports, visibilityInfo) { - this.selectors = selectors; - this.rules = rules; - this._lookups = {}; - this._variables = null; - this._properties = null; - this.strictImports = strictImports; - this.copyVisibilityInfo(visibilityInfo); - this.allowRoot = true; - - this.setParent(this.selectors, this); - this.setParent(this.rules, this); - -}; -Ruleset.prototype = new Node(); -Ruleset.prototype.type = 'Ruleset'; -Ruleset.prototype.isRuleset = true; -Ruleset.prototype.isRulesetLike = function() { return true; }; -Ruleset.prototype.accept = function (visitor) { - if (this.paths) { - this.paths = visitor.visitArray(this.paths, true); - } else if (this.selectors) { - this.selectors = visitor.visitArray(this.selectors); - } - if (this.rules && this.rules.length) { - this.rules = visitor.visitArray(this.rules); - } -}; -Ruleset.prototype.eval = function (context) { - var that = this, selectors, selCnt, selector, i, hasVariable, hasOnePassingSelector = false; - - if (this.selectors && (selCnt = this.selectors.length)) { - selectors = new Array(selCnt); - defaultFunc.error({ - type: 'Syntax', - message: 'it is currently only allowed in parametric mixin guards,' - }); +import Node from './node'; +import Declaration from './declaration'; +import Keyword from './keyword'; +import Comment from './comment'; +import Paren from './paren'; +import Selector from './selector'; +import Element from './element'; +import Anonymous from './anonymous'; +import contexts from '../contexts'; +import globalFunctionRegistry from '../functions/function-registry'; +import defaultFunc from '../functions/default'; +import getDebugInfo from './debug-info'; +import * as utils from '../utils'; + +class Ruleset extends Node { + constructor(selectors, rules, strictImports, visibilityInfo) { + super(); + + this.selectors = selectors; + this.rules = rules; + this._lookups = {}; + this._variables = null; + this._properties = null; + this.strictImports = strictImports; + this.copyVisibilityInfo(visibilityInfo); + this.allowRoot = true; + + this.setParent(this.selectors, this); + this.setParent(this.rules, this); + + } + + isRulesetLike() { + return true; + } + + accept(visitor) { + if (this.paths) { + this.paths = visitor.visitArray(this.paths, true); + } else if (this.selectors) { + this.selectors = visitor.visitArray(this.selectors); + } + if (this.rules && this.rules.length) { + this.rules = visitor.visitArray(this.rules); + } + } + + eval(context) { + const that = this; + let selectors; + let selCnt; + let selector; + let i; + let hasVariable; + let hasOnePassingSelector = false; + + if (this.selectors && (selCnt = this.selectors.length)) { + selectors = new Array(selCnt); + defaultFunc.error({ + type: 'Syntax', + message: 'it is currently only allowed in parametric mixin guards,' + }); - for (i = 0; i < selCnt; i++) { - selector = this.selectors[i].eval(context); - for (var j = 0; j < selector.elements.length; j++) { - if (selector.elements[j].isVariable) { - hasVariable = true; - break; + for (i = 0; i < selCnt; i++) { + selector = this.selectors[i].eval(context); + for (var j = 0; j < selector.elements.length; j++) { + if (selector.elements[j].isVariable) { + hasVariable = true; + break; + } + } + selectors[i] = selector; + if (selector.evaldCondition) { + hasOnePassingSelector = true; } } - selectors[i] = selector; - if (selector.evaldCondition) { - hasOnePassingSelector = true; + + if (hasVariable) { + const toParseSelectors = new Array(selCnt); + for (i = 0; i < selCnt; i++) { + selector = selectors[i]; + toParseSelectors[i] = selector.toCSS(context); + } + this.parse.parseNode( + toParseSelectors.join(','), + ["selectors"], + selectors[0].getIndex(), + selectors[0].fileInfo(), + (err, result) => { + if (result) { + selectors = utils.flattenArray(result); + } + }); } - } - if (hasVariable) { - var toParseSelectors = new Array(selCnt); - for (i = 0; i < selCnt; i++) { - selector = selectors[i]; - toParseSelectors[i] = selector.toCSS(context); - } - this.parse.parseNode( - toParseSelectors.join(','), - ["selectors"], - selectors[0].getIndex(), - selectors[0].fileInfo(), - function(err, result) { - if (result) { - selectors = utils.flattenArray(result); - } - }); + defaultFunc.reset(); + } else { + hasOnePassingSelector = true; } - defaultFunc.reset(); - } else { - hasOnePassingSelector = true; - } + let rules = this.rules ? utils.copyArray(this.rules) : null; + const ruleset = new Ruleset(selectors, rules, this.strictImports, this.visibilityInfo()); + let rule; + let subRule; - var rules = this.rules ? utils.copyArray(this.rules) : null, - ruleset = new Ruleset(selectors, rules, this.strictImports, this.visibilityInfo()), - rule, subRule; + ruleset.originalRuleset = this; + ruleset.root = this.root; + ruleset.firstRoot = this.firstRoot; + ruleset.allowImports = this.allowImports; - ruleset.originalRuleset = this; - ruleset.root = this.root; - ruleset.firstRoot = this.firstRoot; - ruleset.allowImports = this.allowImports; + if (this.debugInfo) { + ruleset.debugInfo = this.debugInfo; + } - if (this.debugInfo) { - ruleset.debugInfo = this.debugInfo; - } + if (!hasOnePassingSelector) { + rules.length = 0; + } - if (!hasOnePassingSelector) { - rules.length = 0; - } + // inherit a function registry from the frames stack when possible; + // otherwise from the global registry + ruleset.functionRegistry = (frames => { + let i = 0; + const n = frames.length; + let found; + for ( ; i !== n ; ++i ) { + found = frames[ i ].functionRegistry; + if ( found ) { return found; } + } + return globalFunctionRegistry; + })(context.frames).inherit(); - // inherit a function registry from the frames stack when possible; - // otherwise from the global registry - ruleset.functionRegistry = (function (frames) { - var i = 0, - n = frames.length, - found; - for ( ; i !== n ; ++i ) { - found = frames[ i ].functionRegistry; - if ( found ) { return found; } - } - return globalFunctionRegistry; - }(context.frames)).inherit(); - - // push the current ruleset to the frames stack - var ctxFrames = context.frames; - ctxFrames.unshift(ruleset); - - // currrent selectors - var ctxSelectors = context.selectors; - if (!ctxSelectors) { - context.selectors = ctxSelectors = []; - } - ctxSelectors.unshift(this.selectors); + // push the current ruleset to the frames stack + const ctxFrames = context.frames; + ctxFrames.unshift(ruleset); - // Evaluate imports - if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { - ruleset.evalImports(context); - } + // currrent selectors + let ctxSelectors = context.selectors; + if (!ctxSelectors) { + context.selectors = ctxSelectors = []; + } + ctxSelectors.unshift(this.selectors); - // Store the frames around mixin definitions, - // so they can be evaluated like closures when the time comes. - var rsRules = ruleset.rules; - for (i = 0; (rule = rsRules[i]); i++) { - if (rule.evalFirst) { - rsRules[i] = rule.eval(context); + // Evaluate imports + if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { + ruleset.evalImports(context); } - } - var mediaBlockCount = (context.mediaBlocks && context.mediaBlocks.length) || 0; - - // Evaluate mixin calls. - for (i = 0; (rule = rsRules[i]); i++) { - if (rule.type === 'MixinCall') { - /* jshint loopfunc:true */ - rules = rule.eval(context).filter(function(r) { - if ((r instanceof Declaration) && r.variable) { - // do not pollute the scope if the variable is - // already there. consider returning false here - // but we need a way to "return" variable from mixins - return !(ruleset.variable(r.name)); - } - return true; - }); - rsRules.splice.apply(rsRules, [i, 1].concat(rules)); - i += rules.length - 1; - ruleset.resetCache(); - } else if (rule.type === 'VariableCall') { - /* jshint loopfunc:true */ - rules = rule.eval(context).rules.filter(function(r) { - if ((r instanceof Declaration) && r.variable) { - // do not pollute the scope at all - return false; - } - return true; - }); - rsRules.splice.apply(rsRules, [i, 1].concat(rules)); - i += rules.length - 1; - ruleset.resetCache(); + // Store the frames around mixin definitions, + // so they can be evaluated like closures when the time comes. + const rsRules = ruleset.rules; + for (i = 0; (rule = rsRules[i]); i++) { + if (rule.evalFirst) { + rsRules[i] = rule.eval(context); + } } - } - // Evaluate everything else - for (i = 0; (rule = rsRules[i]); i++) { - if (!rule.evalFirst) { - rsRules[i] = rule = rule.eval ? rule.eval(context) : rule; + const mediaBlockCount = (context.mediaBlocks && context.mediaBlocks.length) || 0; + + // Evaluate mixin calls. + for (i = 0; (rule = rsRules[i]); i++) { + if (rule.type === 'MixinCall') { + /* jshint loopfunc:true */ + rules = rule.eval(context).filter(r => { + if ((r instanceof Declaration) && r.variable) { + // do not pollute the scope if the variable is + // already there. consider returning false here + // but we need a way to "return" variable from mixins + return !(ruleset.variable(r.name)); + } + return true; + }); + rsRules.splice(...[i, 1].concat(rules)); + i += rules.length - 1; + ruleset.resetCache(); + } else if (rule.type === 'VariableCall') { + /* jshint loopfunc:true */ + rules = rule.eval(context).rules.filter(r => { + if ((r instanceof Declaration) && r.variable) { + // do not pollute the scope at all + return false; + } + return true; + }); + rsRules.splice(...[i, 1].concat(rules)); + i += rules.length - 1; + ruleset.resetCache(); + } } - } - // Evaluate everything else - for (i = 0; (rule = rsRules[i]); i++) { - // for rulesets, check if it is a css guard and can be removed - if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) { - // check if it can be folded in (e.g. & where) - if (rule.selectors[0] && rule.selectors[0].isJustParentSelector()) { - rsRules.splice(i--, 1); - - for (var j = 0; (subRule = rule.rules[j]); j++) { - if (subRule instanceof Node) { - subRule.copyVisibilityInfo(rule.visibilityInfo()); - if (!(subRule instanceof Declaration) || !subRule.variable) { - rsRules.splice(++i, 0, subRule); + // Evaluate everything else + for (i = 0; (rule = rsRules[i]); i++) { + if (!rule.evalFirst) { + rsRules[i] = rule = rule.eval ? rule.eval(context) : rule; + } + } + + // Evaluate everything else + for (i = 0; (rule = rsRules[i]); i++) { + // for rulesets, check if it is a css guard and can be removed + if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) { + // check if it can be folded in (e.g. & where) + if (rule.selectors[0] && rule.selectors[0].isJustParentSelector()) { + rsRules.splice(i--, 1); + + for (var j = 0; (subRule = rule.rules[j]); j++) { + if (subRule instanceof Node) { + subRule.copyVisibilityInfo(rule.visibilityInfo()); + if (!(subRule instanceof Declaration) || !subRule.variable) { + rsRules.splice(++i, 0, subRule); + } } } } } } + + // Pop the stack + ctxFrames.shift(); + ctxSelectors.shift(); + + if (context.mediaBlocks) { + for (i = mediaBlockCount; i < context.mediaBlocks.length; i++) { + context.mediaBlocks[i].bubbleSelectors(selectors); + } + } + + return ruleset; } - // Pop the stack - ctxFrames.shift(); - ctxSelectors.shift(); + evalImports(context) { + const rules = this.rules; + let i; + let importRules; + if (!rules) { return; } - if (context.mediaBlocks) { - for (i = mediaBlockCount; i < context.mediaBlocks.length; i++) { - context.mediaBlocks[i].bubbleSelectors(selectors); + for (i = 0; i < rules.length; i++) { + if (rules[i].type === 'Import') { + importRules = rules[i].eval(context); + if (importRules && (importRules.length || importRules.length === 0)) { + rules.splice(...[i, 1].concat(importRules)); + i += importRules.length - 1; + } else { + rules.splice(i, 1, importRules); + } + this.resetCache(); + } } } - return ruleset; -}; -Ruleset.prototype.evalImports = function(context) { - var rules = this.rules, i, importRules; - if (!rules) { return; } - - for (i = 0; i < rules.length; i++) { - if (rules[i].type === 'Import') { - importRules = rules[i].eval(context); - if (importRules && (importRules.length || importRules.length === 0)) { - rules.splice.apply(rules, [i, 1].concat(importRules)); - i += importRules.length - 1; + makeImportant() { + const result = new Ruleset(this.selectors, this.rules.map(r => { + if (r.makeImportant) { + return r.makeImportant(); } else { - rules.splice(i, 1, importRules); + return r; } - this.resetCache(); - } + }), this.strictImports, this.visibilityInfo()); + + return result; } -}; -Ruleset.prototype.makeImportant = function() { - var result = new Ruleset(this.selectors, this.rules.map(function (r) { - if (r.makeImportant) { - return r.makeImportant(); - } else { - return r; - } - }), this.strictImports, this.visibilityInfo()); - - return result; -}; -Ruleset.prototype.matchArgs = function (args) { - return !args || args.length === 0; -}; -// lets you call a css selector with a guard -Ruleset.prototype.matchCondition = function (args, context) { - var lastSelector = this.selectors[this.selectors.length - 1]; - if (!lastSelector.evaldCondition) { - return false; + + matchArgs(args) { + return !args || args.length === 0; } - if (lastSelector.condition && - !lastSelector.condition.eval( - new contexts.Eval(context, - context.frames))) { - return false; + + // lets you call a css selector with a guard + matchCondition(args, context) { + const lastSelector = this.selectors[this.selectors.length - 1]; + if (!lastSelector.evaldCondition) { + return false; + } + if (lastSelector.condition && + !lastSelector.condition.eval( + new contexts.Eval(context, + context.frames))) { + return false; + } + return true; } - return true; -}; -Ruleset.prototype.resetCache = function () { - this._rulesets = null; - this._variables = null; - this._properties = null; - this._lookups = {}; -}; -Ruleset.prototype.variables = function () { - if (!this._variables) { - this._variables = !this.rules ? {} : this.rules.reduce(function (hash, r) { - if (r instanceof Declaration && r.variable === true) { - hash[r.name] = r; - } - // when evaluating variables in an import statement, imports have not been eval'd - // so we need to go inside import statements. - // guard against root being a string (in the case of inlined less) - if (r.type === 'Import' && r.root && r.root.variables) { - var vars = r.root.variables(); - for (var name in vars) { - if (vars.hasOwnProperty(name)) { - hash[name] = r.root.variable(name); - } - } - } - return hash; - }, {}); + + resetCache() { + this._rulesets = null; + this._variables = null; + this._properties = null; + this._lookups = {}; } - return this._variables; -}; -Ruleset.prototype.properties = function () { - if (!this._properties) { - this._properties = !this.rules ? {} : this.rules.reduce(function (hash, r) { - if (r instanceof Declaration && r.variable !== true) { - var name = (r.name.length === 1) && (r.name[0] instanceof Keyword) ? - r.name[0].value : r.name; - // Properties don't overwrite as they can merge - if (!hash['$' + name]) { - hash['$' + name] = [ r ]; + + variables() { + if (!this._variables) { + this._variables = !this.rules ? {} : this.rules.reduce((hash, r) => { + if (r instanceof Declaration && r.variable === true) { + hash[r.name] = r; } - else { - hash['$' + name].push(r); + // when evaluating variables in an import statement, imports have not been eval'd + // so we need to go inside import statements. + // guard against root being a string (in the case of inlined less) + if (r.type === 'Import' && r.root && r.root.variables) { + const vars = r.root.variables(); + for (const name in vars) { + if (vars.hasOwnProperty(name)) { + hash[name] = r.root.variable(name); + } + } } - } - return hash; - }, {}); + return hash; + }, {}); + } + return this._variables; } - return this._properties; -}; -Ruleset.prototype.variable = function (name) { - var decl = this.variables()[name]; - if (decl) { - return this.parseValue(decl); + + properties() { + if (!this._properties) { + this._properties = !this.rules ? {} : this.rules.reduce((hash, r) => { + if (r instanceof Declaration && r.variable !== true) { + const name = (r.name.length === 1) && (r.name[0] instanceof Keyword) ? + r.name[0].value : r.name; + // Properties don't overwrite as they can merge + if (!hash[`$${name}`]) { + hash[`$${name}`] = [ r ]; + } + else { + hash[`$${name}`].push(r); + } + } + return hash; + }, {}); + } + return this._properties; } -}; -Ruleset.prototype.property = function (name) { - var decl = this.properties()[name]; - if (decl) { - return this.parseValue(decl); + + variable(name) { + const decl = this.variables()[name]; + if (decl) { + return this.parseValue(decl); + } } -}; -Ruleset.prototype.lastDeclaration = function () { - for (var i = this.rules.length; i > 0; i--) { - var decl = this.rules[i - 1]; - if (decl instanceof Declaration) { + + property(name) { + const decl = this.properties()[name]; + if (decl) { return this.parseValue(decl); } } -}; -Ruleset.prototype.parseValue = function(toParse) { - var self = this; - function transformDeclaration(decl) { - if (decl.value instanceof Anonymous && !decl.parsed) { - if (typeof decl.value.value === 'string') { - this.parse.parseNode( - decl.value.value, - ['value', 'important'], - decl.value.getIndex(), - decl.fileInfo(), - function(err, result) { - if (err) { - decl.parsed = true; - } - if (result) { - decl.value = result[0]; - decl.important = result[1] || ''; - decl.parsed = true; - } - }); - } else { - decl.parsed = true; + + lastDeclaration() { + for (let i = this.rules.length; i > 0; i--) { + const decl = this.rules[i - 1]; + if (decl instanceof Declaration) { + return this.parseValue(decl); } + } + } + + parseValue(toParse) { + const self = this; + function transformDeclaration(decl) { + if (decl.value instanceof Anonymous && !decl.parsed) { + if (typeof decl.value.value === 'string') { + this.parse.parseNode( + decl.value.value, + ['value', 'important'], + decl.value.getIndex(), + decl.fileInfo(), + (err, result) => { + if (err) { + decl.parsed = true; + } + if (result) { + decl.value = result[0]; + decl.important = result[1] || ''; + decl.parsed = true; + } + }); + } else { + decl.parsed = true; + } - return decl; + return decl; + } + else { + return decl; + } + } + if (!Array.isArray(toParse)) { + return transformDeclaration.call(self, toParse); } else { - return decl; + const nodes = []; + toParse.forEach(n => { + nodes.push(transformDeclaration.call(self, n)); + }); + return nodes; } } - if (!Array.isArray(toParse)) { - return transformDeclaration.call(self, toParse); - } - else { - var nodes = []; - toParse.forEach(function(n) { - nodes.push(transformDeclaration.call(self, n)); - }); - return nodes; - } -}; -Ruleset.prototype.rulesets = function () { - if (!this.rules) { return []; } - var filtRules = [], rules = this.rules, - i, rule; + rulesets() { + if (!this.rules) { return []; } + + const filtRules = []; + const rules = this.rules; + let i; + let rule; - for (i = 0; (rule = rules[i]); i++) { - if (rule.isRuleset) { - filtRules.push(rule); + for (i = 0; (rule = rules[i]); i++) { + if (rule.isRuleset) { + filtRules.push(rule); + } } - } - return filtRules; -}; -Ruleset.prototype.prependRule = function (rule) { - var rules = this.rules; - if (rules) { - rules.unshift(rule); - } else { - this.rules = [ rule ]; + return filtRules; } - this.setParent(rule, this); -}; -Ruleset.prototype.find = function (selector, self, filter) { - self = self || this; - var rules = [], match, foundMixins, - key = selector.toCSS(); - - if (key in this._lookups) { return this._lookups[key]; } - - this.rulesets().forEach(function (rule) { - if (rule !== self) { - for (var j = 0; j < rule.selectors.length; j++) { - match = selector.match(rule.selectors[j]); - if (match) { - if (selector.elements.length > match) { - if (!filter || filter(rule)) { - foundMixins = rule.find(new Selector(selector.elements.slice(match)), self, filter); - for (var i = 0; i < foundMixins.length; ++i) { - foundMixins[i].path.push(rule); + + prependRule(rule) { + const rules = this.rules; + if (rules) { + rules.unshift(rule); + } else { + this.rules = [ rule ]; + } + this.setParent(rule, this); + } + + find(selector, self = this, filter) { + const rules = []; + let match; + let foundMixins; + const key = selector.toCSS(); + + if (key in this._lookups) { return this._lookups[key]; } + + this.rulesets().forEach(rule => { + if (rule !== self) { + for (let j = 0; j < rule.selectors.length; j++) { + match = selector.match(rule.selectors[j]); + if (match) { + if (selector.elements.length > match) { + if (!filter || filter(rule)) { + foundMixins = rule.find(new Selector(selector.elements.slice(match)), self, filter); + for (let i = 0; i < foundMixins.length; ++i) { + foundMixins[i].path.push(rule); + } + Array.prototype.push.apply(rules, foundMixins); } - Array.prototype.push.apply(rules, foundMixins); + } else { + rules.push({ rule, path: []}); } - } else { - rules.push({ rule: rule, path: []}); + break; } - break; } } - } - }); - this._lookups[key] = rules; - return rules; -}; -Ruleset.prototype.genCSS = function (context, output) { - var i, j, - charsetRuleNodes = [], - ruleNodes = [], - debugInfo, // Line number debugging - rule, - path; + }); + this._lookups[key] = rules; + return rules; + } - context.tabLevel = (context.tabLevel || 0); + genCSS(context, output) { + let i; + let j; + const charsetRuleNodes = []; + let ruleNodes = []; - if (!this.root) { - context.tabLevel++; - } + let // Line number debugging + debugInfo; - var tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join(' '), - tabSetStr = context.compress ? '' : Array(context.tabLevel).join(' '), - sep; + let rule; + let path; - var charsetNodeIndex = 0; - var importNodeIndex = 0; - for (i = 0; (rule = this.rules[i]); i++) { - if (rule instanceof Comment) { - if (importNodeIndex === i) { + context.tabLevel = (context.tabLevel || 0); + + if (!this.root) { + context.tabLevel++; + } + + const tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join(' '); + const tabSetStr = context.compress ? '' : Array(context.tabLevel).join(' '); + let sep; + + let charsetNodeIndex = 0; + let importNodeIndex = 0; + for (i = 0; (rule = this.rules[i]); i++) { + if (rule instanceof Comment) { + if (importNodeIndex === i) { + importNodeIndex++; + } + ruleNodes.push(rule); + } else if (rule.isCharset && rule.isCharset()) { + ruleNodes.splice(charsetNodeIndex, 0, rule); + charsetNodeIndex++; importNodeIndex++; + } else if (rule.type === 'Import') { + ruleNodes.splice(importNodeIndex, 0, rule); + importNodeIndex++; + } else { + ruleNodes.push(rule); } - ruleNodes.push(rule); - } else if (rule.isCharset && rule.isCharset()) { - ruleNodes.splice(charsetNodeIndex, 0, rule); - charsetNodeIndex++; - importNodeIndex++; - } else if (rule.type === 'Import') { - ruleNodes.splice(importNodeIndex, 0, rule); - importNodeIndex++; - } else { - ruleNodes.push(rule); } - } - ruleNodes = charsetRuleNodes.concat(ruleNodes); + ruleNodes = charsetRuleNodes.concat(ruleNodes); - // If this is the root node, we don't render - // a selector, or {}. - if (!this.root) { - debugInfo = getDebugInfo(context, this, tabSetStr); + // If this is the root node, we don't render + // a selector, or {}. + if (!this.root) { + debugInfo = getDebugInfo(context, this, tabSetStr); - if (debugInfo) { - output.add(debugInfo); - output.add(tabSetStr); - } + if (debugInfo) { + output.add(debugInfo); + output.add(tabSetStr); + } - var paths = this.paths, pathCnt = paths.length, - pathSubCnt; + const paths = this.paths; + const pathCnt = paths.length; + let pathSubCnt; - sep = context.compress ? ',' : (',\n' + tabSetStr); + sep = context.compress ? ',' : (`,\n${tabSetStr}`); - for (i = 0; i < pathCnt; i++) { - path = paths[i]; - if (!(pathSubCnt = path.length)) { continue; } - if (i > 0) { output.add(sep); } + for (i = 0; i < pathCnt; i++) { + path = paths[i]; + if (!(pathSubCnt = path.length)) { continue; } + if (i > 0) { output.add(sep); } - context.firstSelector = true; - path[0].genCSS(context, output); + context.firstSelector = true; + path[0].genCSS(context, output); - context.firstSelector = false; - for (j = 1; j < pathSubCnt; j++) { - path[j].genCSS(context, output); + context.firstSelector = false; + for (j = 1; j < pathSubCnt; j++) { + path[j].genCSS(context, output); + } } - } - output.add((context.compress ? '{' : ' {\n') + tabRuleStr); - } + output.add((context.compress ? '{' : ' {\n') + tabRuleStr); + } - // Compile rules and rulesets - for (i = 0; (rule = ruleNodes[i]); i++) { + // Compile rules and rulesets + for (i = 0; (rule = ruleNodes[i]); i++) { - if (i + 1 === ruleNodes.length) { - context.lastRule = true; - } + if (i + 1 === ruleNodes.length) { + context.lastRule = true; + } - var currentLastRule = context.lastRule; - if (rule.isRulesetLike(rule)) { - context.lastRule = false; - } + const currentLastRule = context.lastRule; + if (rule.isRulesetLike(rule)) { + context.lastRule = false; + } - if (rule.genCSS) { - rule.genCSS(context, output); - } else if (rule.value) { - output.add(rule.value.toString()); - } + if (rule.genCSS) { + rule.genCSS(context, output); + } else if (rule.value) { + output.add(rule.value.toString()); + } - context.lastRule = currentLastRule; + context.lastRule = currentLastRule; - if (!context.lastRule && rule.isVisible()) { - output.add(context.compress ? '' : ('\n' + tabRuleStr)); - } else { - context.lastRule = false; + if (!context.lastRule && rule.isVisible()) { + output.add(context.compress ? '' : (`\n${tabRuleStr}`)); + } else { + context.lastRule = false; + } } - } - if (!this.root) { - output.add((context.compress ? '}' : '\n' + tabSetStr + '}')); - context.tabLevel--; - } + if (!this.root) { + output.add((context.compress ? '}' : `\n${tabSetStr}}`)); + context.tabLevel--; + } - if (!output.isEmpty() && !context.compress && this.firstRoot) { - output.add('\n'); + if (!output.isEmpty() && !context.compress && this.firstRoot) { + output.add('\n'); + } } -}; -Ruleset.prototype.joinSelectors = function (paths, context, selectors) { - for (var s = 0; s < selectors.length; s++) { - this.joinSelector(paths, context, selectors[s]); + joinSelectors(paths, context, selectors) { + for (let s = 0; s < selectors.length; s++) { + this.joinSelector(paths, context, selectors[s]); + } } -}; -Ruleset.prototype.joinSelector = function (paths, context, selector) { + joinSelector(paths, context, selector) { + function createParenthesis(elementsToPak, originalElement) { + let replacementParen; + let j; + if (elementsToPak.length === 0) { + replacementParen = new Paren(elementsToPak[0]); + } else { + const insideParent = new Array(elementsToPak.length); + for (j = 0; j < elementsToPak.length; j++) { + insideParent[j] = new Element( + null, + elementsToPak[j], + originalElement.isVariable, + originalElement._index, + originalElement._fileInfo + ); + } + replacementParen = new Paren(new Selector(insideParent)); + } + return replacementParen; + } + + function createSelector(containedElement, originalElement) { + let element; + let selector; + element = new Element(null, containedElement, originalElement.isVariable, originalElement._index, originalElement._fileInfo); + selector = new Selector([element]); + return selector; + } + + // joins selector path from `beginningPath` with selector path in `addPath` + // `replacedElement` contains element that is being replaced by `addPath` + // returns concatenated path + function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) { + let newSelectorPath; + let lastSelector; + let newJoinedSelector; + // our new selector path + newSelectorPath = []; + + // construct the joined selector - if & is the first thing this will be empty, + // if not newJoinedSelector will be the last set of elements in the selector + if (beginningPath.length > 0) { + newSelectorPath = utils.copyArray(beginningPath); + lastSelector = newSelectorPath.pop(); + newJoinedSelector = originalSelector.createDerived(utils.copyArray(lastSelector.elements)); + } + else { + newJoinedSelector = originalSelector.createDerived([]); + } - function createParenthesis(elementsToPak, originalElement) { - var replacementParen, j; - if (elementsToPak.length === 0) { - replacementParen = new Paren(elementsToPak[0]); - } else { - var insideParent = new Array(elementsToPak.length); - for (j = 0; j < elementsToPak.length; j++) { - insideParent[j] = new Element( - null, - elementsToPak[j], - originalElement.isVariable, - originalElement._index, - originalElement._fileInfo - ); - } - replacementParen = new Paren(new Selector(insideParent)); - } - return replacementParen; - } + if (addPath.length > 0) { + // /deep/ is a CSS4 selector - (removed, so should deprecate) + // that is valid without anything in front of it + // so if the & does not have a combinator that is "" or " " then + // and there is a combinator on the parent, then grab that. + // this also allows + a { & .b { .a & { ... though not sure why you would want to do that + let combinator = replacedElement.combinator; + + const parentEl = addPath[0].elements[0]; + if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) { + combinator = parentEl.combinator; + } + // join the elements so far with the first part of the parent + newJoinedSelector.elements.push(new Element( + combinator, + parentEl.value, + replacedElement.isVariable, + replacedElement._index, + replacedElement._fileInfo + )); + newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1)); + } - function createSelector(containedElement, originalElement) { - var element, selector; - element = new Element(null, containedElement, originalElement.isVariable, originalElement._index, originalElement._fileInfo); - selector = new Selector([element]); - return selector; - } + // now add the joined selector - but only if it is not empty + if (newJoinedSelector.elements.length !== 0) { + newSelectorPath.push(newJoinedSelector); + } - // joins selector path from `beginningPath` with selector path in `addPath` - // `replacedElement` contains element that is being replaced by `addPath` - // returns concatenated path - function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) { - var newSelectorPath, lastSelector, newJoinedSelector; - // our new selector path - newSelectorPath = []; - - // construct the joined selector - if & is the first thing this will be empty, - // if not newJoinedSelector will be the last set of elements in the selector - if (beginningPath.length > 0) { - newSelectorPath = utils.copyArray(beginningPath); - lastSelector = newSelectorPath.pop(); - newJoinedSelector = originalSelector.createDerived(utils.copyArray(lastSelector.elements)); - } - else { - newJoinedSelector = originalSelector.createDerived([]); - } - - if (addPath.length > 0) { - // /deep/ is a CSS4 selector - (removed, so should deprecate) - // that is valid without anything in front of it - // so if the & does not have a combinator that is "" or " " then - // and there is a combinator on the parent, then grab that. - // this also allows + a { & .b { .a & { ... though not sure why you would want to do that - var combinator = replacedElement.combinator, parentEl = addPath[0].elements[0]; - if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) { - combinator = parentEl.combinator; - } - // join the elements so far with the first part of the parent - newJoinedSelector.elements.push(new Element( - combinator, - parentEl.value, - replacedElement.isVariable, - replacedElement._index, - replacedElement._fileInfo - )); - newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1)); - } - - // now add the joined selector - but only if it is not empty - if (newJoinedSelector.elements.length !== 0) { - newSelectorPath.push(newJoinedSelector); - } - - // put together the parent selectors after the join (e.g. the rest of the parent) - if (addPath.length > 1) { - var restOfPath = addPath.slice(1); - restOfPath = restOfPath.map(function (selector) { - return selector.createDerived(selector.elements, []); - }); - newSelectorPath = newSelectorPath.concat(restOfPath); + // put together the parent selectors after the join (e.g. the rest of the parent) + if (addPath.length > 1) { + let restOfPath = addPath.slice(1); + restOfPath = restOfPath.map(selector => selector.createDerived(selector.elements, [])); + newSelectorPath = newSelectorPath.concat(restOfPath); + } + return newSelectorPath; } - return newSelectorPath; - } - // joins selector path from `beginningPath` with every selector path in `addPaths` array - // `replacedElement` contains element that is being replaced by `addPath` - // returns array with all concatenated paths - function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) { - var j; - for (j = 0; j < beginningPath.length; j++) { - var newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector); - result.push(newSelectorPath); + // joins selector path from `beginningPath` with every selector path in `addPaths` array + // `replacedElement` contains element that is being replaced by `addPath` + // returns array with all concatenated paths + function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) { + let j; + for (j = 0; j < beginningPath.length; j++) { + const newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector); + result.push(newSelectorPath); + } + return result; } - return result; - } - function mergeElementsOnToSelectors(elements, selectors) { - var i, sel; - - if (elements.length === 0) { - return ; - } - if (selectors.length === 0) { - selectors.push([ new Selector(elements) ]); - return; - } + function mergeElementsOnToSelectors(elements, selectors) { + let i; + let sel; - for (i = 0; (sel = selectors[i]); i++) { - // if the previous thing in sel is a parent this needs to join on to it - if (sel.length > 0) { - sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements)); + if (elements.length === 0) { + return ; } - else { - sel.push(new Selector(elements)); + if (selectors.length === 0) { + selectors.push([ new Selector(elements) ]); + return; + } + + for (i = 0; (sel = selectors[i]); i++) { + // if the previous thing in sel is a parent this needs to join on to it + if (sel.length > 0) { + sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements)); + } + else { + sel.push(new Selector(elements)); + } } } - } - // replace all parent selectors inside `inSelector` by content of `context` array - // resulting selectors are returned inside `paths` array - // returns true if `inSelector` contained at least one parent selector - function replaceParentSelector(paths, context, inSelector) { - // The paths are [[Selector]] - // The first list is a list of comma separated selectors - // The inner list is a list of inheritance separated selectors - // e.g. - // .a, .b { - // .c { - // } - // } - // == [[.a] [.c]] [[.b] [.c]] - // - var i, j, k, currentElements, newSelectors, selectorsMultiplied, sel, el, hadParentSelector = false, length, lastSelector; - function findNestedSelector(element) { - var maybeSelector; - if (!(element.value instanceof Paren)) { - return null; - } - - maybeSelector = element.value.value; - if (!(maybeSelector instanceof Selector)) { - return null; - } - - return maybeSelector; - } - - // the elements from the current selector so far - currentElements = []; - // the current list of new selectors to add to the path. - // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors - // by the parents - newSelectors = [ - [] - ]; - - for (i = 0; (el = inSelector.elements[i]); i++) { - // non parent reference elements just get added - if (el.value !== '&') { - var nestedSelector = findNestedSelector(el); - if (nestedSelector != null) { - // merge the current list of non parent selector elements - // on to the current list of selectors to add - mergeElementsOnToSelectors(currentElements, newSelectors); + // replace all parent selectors inside `inSelector` by content of `context` array + // resulting selectors are returned inside `paths` array + // returns true if `inSelector` contained at least one parent selector + function replaceParentSelector(paths, context, inSelector) { + // The paths are [[Selector]] + // The first list is a list of comma separated selectors + // The inner list is a list of inheritance separated selectors + // e.g. + // .a, .b { + // .c { + // } + // } + // == [[.a] [.c]] [[.b] [.c]] + // + let i; + + let j; + let k; + let currentElements; + let newSelectors; + let selectorsMultiplied; + let sel; + let el; + let hadParentSelector = false; + let length; + let lastSelector; + function findNestedSelector(element) { + let maybeSelector; + if (!(element.value instanceof Paren)) { + return null; + } - var nestedPaths = [], replaced, replacedNewSelectors = []; - replaced = replaceParentSelector(nestedPaths, context, nestedSelector); - hadParentSelector = hadParentSelector || replaced; - // the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors - for (k = 0; k < nestedPaths.length; k++) { - var replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el); - addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors); + maybeSelector = element.value.value; + if (!(maybeSelector instanceof Selector)) { + return null; + } + + return maybeSelector; + } + + // the elements from the current selector so far + currentElements = []; + // the current list of new selectors to add to the path. + // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors + // by the parents + newSelectors = [ + [] + ]; + + for (i = 0; (el = inSelector.elements[i]); i++) { + // non parent reference elements just get added + if (el.value !== '&') { + const nestedSelector = findNestedSelector(el); + if (nestedSelector != null) { + // merge the current list of non parent selector elements + // on to the current list of selectors to add + mergeElementsOnToSelectors(currentElements, newSelectors); + + const nestedPaths = []; + let replaced; + const replacedNewSelectors = []; + replaced = replaceParentSelector(nestedPaths, context, nestedSelector); + hadParentSelector = hadParentSelector || replaced; + // the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors + for (k = 0; k < nestedPaths.length; k++) { + const replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el); + addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors); + } + newSelectors = replacedNewSelectors; + currentElements = []; + } else { + currentElements.push(el); } - newSelectors = replacedNewSelectors; - currentElements = []; } else { - currentElements.push(el); - } + hadParentSelector = true; + // the new list of selectors to add + selectorsMultiplied = []; - } else { - hadParentSelector = true; - // the new list of selectors to add - selectorsMultiplied = []; - - // merge the current list of non parent selector elements - // on to the current list of selectors to add - mergeElementsOnToSelectors(currentElements, newSelectors); - - // loop through our current selectors - for (j = 0; j < newSelectors.length; j++) { - sel = newSelectors[j]; - // if we don't have any parent paths, the & might be in a mixin so that it can be used - // whether there are parents or not - if (context.length === 0) { - // the combinator used on el should now be applied to the next element instead so that - // it is not lost - if (sel.length > 0) { - sel[0].elements.push(new Element(el.combinator, '', el.isVariable, el._index, el._fileInfo)); + // merge the current list of non parent selector elements + // on to the current list of selectors to add + mergeElementsOnToSelectors(currentElements, newSelectors); + + // loop through our current selectors + for (j = 0; j < newSelectors.length; j++) { + sel = newSelectors[j]; + // if we don't have any parent paths, the & might be in a mixin so that it can be used + // whether there are parents or not + if (context.length === 0) { + // the combinator used on el should now be applied to the next element instead so that + // it is not lost + if (sel.length > 0) { + sel[0].elements.push(new Element(el.combinator, '', el.isVariable, el._index, el._fileInfo)); + } + selectorsMultiplied.push(sel); } - selectorsMultiplied.push(sel); - } - else { - // and the parent selectors - for (k = 0; k < context.length; k++) { - // We need to put the current selectors - // then join the last selector's elements on to the parents selectors - var newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector); - // add that to our new set of selectors - selectorsMultiplied.push(newSelectorPath); + else { + // and the parent selectors + for (k = 0; k < context.length; k++) { + // We need to put the current selectors + // then join the last selector's elements on to the parents selectors + const newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector); + // add that to our new set of selectors + selectorsMultiplied.push(newSelectorPath); + } } } - } - // our new selectors has been multiplied, so reset the state - newSelectors = selectorsMultiplied; - currentElements = []; + // our new selectors has been multiplied, so reset the state + newSelectors = selectorsMultiplied; + currentElements = []; + } } - } - // if we have any elements left over (e.g. .a& .b == .b) - // add them on to all the current selectors - mergeElementsOnToSelectors(currentElements, newSelectors); + // if we have any elements left over (e.g. .a& .b == .b) + // add them on to all the current selectors + mergeElementsOnToSelectors(currentElements, newSelectors); - for (i = 0; i < newSelectors.length; i++) { - length = newSelectors[i].length; - if (length > 0) { - paths.push(newSelectors[i]); - lastSelector = newSelectors[i][length - 1]; - newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList); + for (i = 0; i < newSelectors.length; i++) { + length = newSelectors[i].length; + if (length > 0) { + paths.push(newSelectors[i]); + lastSelector = newSelectors[i][length - 1]; + newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList); + } } + + return hadParentSelector; } - return hadParentSelector; - } + function deriveSelector(visibilityInfo, deriveFrom) { + const newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition); + newSelector.copyVisibilityInfo(visibilityInfo); + return newSelector; + } - function deriveSelector(visibilityInfo, deriveFrom) { - var newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition); - newSelector.copyVisibilityInfo(visibilityInfo); - return newSelector; - } + // joinSelector code follows + let i; - // joinSelector code follows - var i, newPaths, hadParentSelector; + let newPaths; + let hadParentSelector; - newPaths = []; - hadParentSelector = replaceParentSelector(newPaths, context, selector); + newPaths = []; + hadParentSelector = replaceParentSelector(newPaths, context, selector); - if (!hadParentSelector) { - if (context.length > 0) { - newPaths = []; - for (i = 0; i < context.length; i++) { + if (!hadParentSelector) { + if (context.length > 0) { + newPaths = []; + for (i = 0; i < context.length; i++) { - var concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo())); + const concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo())); - concatenated.push(selector); - newPaths.push(concatenated); + concatenated.push(selector); + newPaths.push(concatenated); + } + } + else { + newPaths = [[selector]]; } } - else { - newPaths = [[selector]]; - } - } - for (i = 0; i < newPaths.length; i++) { - paths.push(newPaths[i]); + for (i = 0; i < newPaths.length; i++) { + paths.push(newPaths[i]); + } } +} -}; -module.exports = Ruleset; +Ruleset.prototype.type = 'Ruleset'; +Ruleset.prototype.isRuleset = true; +export default Ruleset; diff --git a/lib/less/tree/selector.js b/lib/less/tree/selector.js index 16ac803c8..2d5be797c 100644 --- a/lib/less/tree/selector.js +++ b/lib/less/tree/selector.js @@ -1,131 +1,146 @@ -var Node = require('./node'), - Element = require('./element'), - LessError = require('../less-error'); - -var Selector = function (elements, extendList, condition, index, currentFileInfo, visibilityInfo) { - this.extendList = extendList; - this.condition = condition; - this.evaldCondition = !condition; - this._index = index; - this._fileInfo = currentFileInfo; - this.elements = this.getElements(elements); - this.mixinElements_ = undefined; - this.copyVisibilityInfo(visibilityInfo); - this.setParent(this.elements, this); -}; -Selector.prototype = new Node(); -Selector.prototype.type = 'Selector'; -Selector.prototype.accept = function (visitor) { - if (this.elements) { - this.elements = visitor.visitArray(this.elements); +import Node from './node'; +import Element from './element'; +import LessError from '../less-error'; + +class Selector extends Node { + constructor(elements, extendList, condition, index, currentFileInfo, visibilityInfo) { + super(); + + this.extendList = extendList; + this.condition = condition; + this.evaldCondition = !condition; + this._index = index; + this._fileInfo = currentFileInfo; + this.elements = this.getElements(elements); + this.mixinElements_ = undefined; + this.copyVisibilityInfo(visibilityInfo); + this.setParent(this.elements, this); } - if (this.extendList) { - this.extendList = visitor.visitArray(this.extendList); + + accept(visitor) { + if (this.elements) { + this.elements = visitor.visitArray(this.elements); + } + if (this.extendList) { + this.extendList = visitor.visitArray(this.extendList); + } + if (this.condition) { + this.condition = visitor.visit(this.condition); + } } - if (this.condition) { - this.condition = visitor.visit(this.condition); + + createDerived(elements, extendList, evaldCondition) { + elements = this.getElements(elements); + const newSelector = new Selector(elements, extendList || this.extendList, + null, this.getIndex(), this.fileInfo(), this.visibilityInfo()); + newSelector.evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition; + newSelector.mediaEmpty = this.mediaEmpty; + return newSelector; } -}; -Selector.prototype.createDerived = function(elements, extendList, evaldCondition) { - elements = this.getElements(elements); - var newSelector = new Selector(elements, extendList || this.extendList, - null, this.getIndex(), this.fileInfo(), this.visibilityInfo()); - newSelector.evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition; - newSelector.mediaEmpty = this.mediaEmpty; - return newSelector; -}; -Selector.prototype.getElements = function(els) { - if (!els) { - return [new Element('', '&', false, this._index, this._fileInfo)]; + + getElements(els) { + if (!els) { + return [new Element('', '&', false, this._index, this._fileInfo)]; + } + if (typeof els === 'string') { + this.parse.parseNode( + els, + ['selector'], + this._index, + this._fileInfo, + function(err, result) { + if (err) { + throw new LessError({ + index: err.index, + message: err.message + }, this.parse.imports, this._fileInfo.filename); + } + els = result[0].elements; + }); + } + return els; } - if (typeof els === 'string') { - this.parse.parseNode( - els, - ['selector'], - this._index, - this._fileInfo, - function(err, result) { - if (err) { - throw new LessError({ - index: err.index, - message: err.message - }, this.parse.imports, this._fileInfo.filename); + + createEmptySelectors() { + const el = new Element('', '&', false, this._index, this._fileInfo); + const sels = [new Selector([el], null, null, this._index, this._fileInfo)]; + sels[0].mediaEmpty = true; + return sels; + } + + match(other) { + const elements = this.elements; + const len = elements.length; + let olen; + let i; + + other = other.mixinElements(); + olen = other.length; + if (olen === 0 || len < olen) { + return 0; + } else { + for (i = 0; i < olen; i++) { + if (elements[i].value !== other[i]) { + return 0; } - els = result[0].elements; - }); + } + } + + return olen; // return number of matched elements } - return els; -}; -Selector.prototype.createEmptySelectors = function() { - var el = new Element('', '&', false, this._index, this._fileInfo), - sels = [new Selector([el], null, null, this._index, this._fileInfo)]; - sels[0].mediaEmpty = true; - return sels; -}; -Selector.prototype.match = function (other) { - var elements = this.elements, - len = elements.length, - olen, i; - - other = other.mixinElements(); - olen = other.length; - if (olen === 0 || len < olen) { - return 0; - } else { - for (i = 0; i < olen; i++) { - if (elements[i].value !== other[i]) { - return 0; + + mixinElements() { + if (this.mixinElements_) { + return this.mixinElements_; + } + + let elements = this.elements.map( v => v.combinator.value + (v.value.value || v.value)).join('').match(/[,&#\*\.\w-]([\w-]|(\\.))*/g); + + if (elements) { + if (elements[0] === '&') { + elements.shift(); } + } else { + elements = []; } + + return (this.mixinElements_ = elements); } - return olen; // return number of matched elements -}; -Selector.prototype.mixinElements = function() { - if (this.mixinElements_) { - return this.mixinElements_; + isJustParentSelector() { + return !this.mediaEmpty && + this.elements.length === 1 && + this.elements[0].value === '&' && + (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === ''); } - var elements = this.elements.map( function(v) { - return v.combinator.value + (v.value.value || v.value); - }).join('').match(/[,&#\*\.\w-]([\w-]|(\\.))*/g); + eval(context) { + const evaldCondition = this.condition && this.condition.eval(context); + let elements = this.elements; + let extendList = this.extendList; - if (elements) { - if (elements[0] === '&') { - elements.shift(); - } - } else { - elements = []; + elements = elements && elements.map(e => e.eval(context)); + extendList = extendList && extendList.map(extend => extend.eval(context)); + + return this.createDerived(elements, extendList, evaldCondition); } - return (this.mixinElements_ = elements); -}; -Selector.prototype.isJustParentSelector = function() { - return !this.mediaEmpty && - this.elements.length === 1 && - this.elements[0].value === '&' && - (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === ''); -}; -Selector.prototype.eval = function (context) { - var evaldCondition = this.condition && this.condition.eval(context), - elements = this.elements, extendList = this.extendList; - - elements = elements && elements.map(function (e) { return e.eval(context); }); - extendList = extendList && extendList.map(function(extend) { return extend.eval(context); }); - - return this.createDerived(elements, extendList, evaldCondition); -}; -Selector.prototype.genCSS = function (context, output) { - var i, element; - if ((!context || !context.firstSelector) && this.elements[0].combinator.value === '') { - output.add(' ', this.fileInfo(), this.getIndex()); + genCSS(context, output) { + let i; + let element; + if ((!context || !context.firstSelector) && this.elements[0].combinator.value === '') { + output.add(' ', this.fileInfo(), this.getIndex()); + } + for (i = 0; i < this.elements.length; i++) { + element = this.elements[i]; + element.genCSS(context, output); + } } - for (i = 0; i < this.elements.length; i++) { - element = this.elements[i]; - element.genCSS(context, output); + + getIsOutput() { + return this.evaldCondition; } -}; -Selector.prototype.getIsOutput = function() { - return this.evaldCondition; -}; -module.exports = Selector; +} + +Selector.prototype.type = 'Selector'; +export default Selector; diff --git a/lib/less/tree/unicode-descriptor.js b/lib/less/tree/unicode-descriptor.js index 5fd846b27..662dae574 100644 --- a/lib/less/tree/unicode-descriptor.js +++ b/lib/less/tree/unicode-descriptor.js @@ -1,9 +1,13 @@ -var Node = require('./node'); +import Node from './node'; + +class UnicodeDescriptor extends Node { + constructor(value) { + super(); + + this.value = value; + } +} -var UnicodeDescriptor = function (value) { - this.value = value; -}; -UnicodeDescriptor.prototype = new Node(); UnicodeDescriptor.prototype.type = 'UnicodeDescriptor'; -module.exports = UnicodeDescriptor; +export default UnicodeDescriptor; diff --git a/lib/less/tree/unit.js b/lib/less/tree/unit.js index 91c2e27a3..d76b47722 100644 --- a/lib/less/tree/unit.js +++ b/lib/less/tree/unit.js @@ -1,121 +1,141 @@ -var Node = require('./node'), - unitConversions = require('../data/unit-conversions'), - utils = require('../utils'); - -var Unit = function (numerator, denominator, backupUnit) { - this.numerator = numerator ? utils.copyArray(numerator).sort() : []; - this.denominator = denominator ? utils.copyArray(denominator).sort() : []; - if (backupUnit) { - this.backupUnit = backupUnit; - } else if (numerator && numerator.length) { - this.backupUnit = numerator[0]; +import Node from './node'; +import unitConversions from '../data/unit-conversions'; +import * as utils from '../utils'; + +class Unit extends Node { + constructor(numerator, denominator, backupUnit) { + super(); + + this.numerator = numerator ? utils.copyArray(numerator).sort() : []; + this.denominator = denominator ? utils.copyArray(denominator).sort() : []; + if (backupUnit) { + this.backupUnit = backupUnit; + } else if (numerator && numerator.length) { + this.backupUnit = numerator[0]; + } } -}; -Unit.prototype = new Node(); -Unit.prototype.type = 'Unit'; -Unit.prototype.clone = function () { - return new Unit(utils.copyArray(this.numerator), utils.copyArray(this.denominator), this.backupUnit); -}; -Unit.prototype.genCSS = function (context, output) { - // Dimension checks the unit is singular and throws an error if in strict math mode. - var strictUnits = context && context.strictUnits; - if (this.numerator.length === 1) { - output.add(this.numerator[0]); // the ideal situation - } else if (!strictUnits && this.backupUnit) { - output.add(this.backupUnit); - } else if (!strictUnits && this.denominator.length) { - output.add(this.denominator[0]); + clone() { + return new Unit(utils.copyArray(this.numerator), utils.copyArray(this.denominator), this.backupUnit); } -}; -Unit.prototype.toString = function () { - var i, returnStr = this.numerator.join('*'); - for (i = 0; i < this.denominator.length; i++) { - returnStr += '/' + this.denominator[i]; + + genCSS(context, output) { + // Dimension checks the unit is singular and throws an error if in strict math mode. + const strictUnits = context && context.strictUnits; + if (this.numerator.length === 1) { + output.add(this.numerator[0]); // the ideal situation + } else if (!strictUnits && this.backupUnit) { + output.add(this.backupUnit); + } else if (!strictUnits && this.denominator.length) { + output.add(this.denominator[0]); + } } - return returnStr; -}; -Unit.prototype.compare = function (other) { - return this.is(other.toString()) ? 0 : undefined; -}; -Unit.prototype.is = function (unitString) { - return this.toString().toUpperCase() === unitString.toUpperCase(); -}; -Unit.prototype.isLength = function () { - return RegExp('^(px|em|ex|ch|rem|in|cm|mm|pc|pt|ex|vw|vh|vmin|vmax)$', 'gi').test(this.toCSS()); -}; -Unit.prototype.isEmpty = function () { - return this.numerator.length === 0 && this.denominator.length === 0; -}; -Unit.prototype.isSingular = function() { - return this.numerator.length <= 1 && this.denominator.length === 0; -}; -Unit.prototype.map = function(callback) { - var i; - - for (i = 0; i < this.numerator.length; i++) { - this.numerator[i] = callback(this.numerator[i], false); + + toString() { + let i; + let returnStr = this.numerator.join('*'); + for (i = 0; i < this.denominator.length; i++) { + returnStr += `/${this.denominator[i]}`; + } + return returnStr; } - for (i = 0; i < this.denominator.length; i++) { - this.denominator[i] = callback(this.denominator[i], true); + compare(other) { + return this.is(other.toString()) ? 0 : undefined; } -}; -Unit.prototype.usedUnits = function() { - var group, result = {}, mapUnit, groupName; - - mapUnit = function (atomicUnit) { - /* jshint loopfunc:true */ - if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { - result[groupName] = atomicUnit; - } - return atomicUnit; - }; + is(unitString) { + return this.toString().toUpperCase() === unitString.toUpperCase(); + } - for (groupName in unitConversions) { - if (unitConversions.hasOwnProperty(groupName)) { - group = unitConversions[groupName]; + isLength() { + return RegExp('^(px|em|ex|ch|rem|in|cm|mm|pc|pt|ex|vw|vh|vmin|vmax)$', 'gi').test(this.toCSS()); + } - this.map(mapUnit); - } + isEmpty() { + return this.numerator.length === 0 && this.denominator.length === 0; + } + + isSingular() { + return this.numerator.length <= 1 && this.denominator.length === 0; } - return result; -}; -Unit.prototype.cancel = function () { - var counter = {}, atomicUnit, i; + map(callback) { + let i; + + for (i = 0; i < this.numerator.length; i++) { + this.numerator[i] = callback(this.numerator[i], false); + } - for (i = 0; i < this.numerator.length; i++) { - atomicUnit = this.numerator[i]; - counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; + for (i = 0; i < this.denominator.length; i++) { + this.denominator[i] = callback(this.denominator[i], true); + } } - for (i = 0; i < this.denominator.length; i++) { - atomicUnit = this.denominator[i]; - counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; + usedUnits() { + let group; + const result = {}; + let mapUnit; + let groupName; + + mapUnit = atomicUnit => { + /* jshint loopfunc:true */ + if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { + result[groupName] = atomicUnit; + } + + return atomicUnit; + }; + + for (groupName in unitConversions) { + if (unitConversions.hasOwnProperty(groupName)) { + group = unitConversions[groupName]; + + this.map(mapUnit); + } + } + + return result; } - this.numerator = []; - this.denominator = []; + cancel() { + const counter = {}; + let atomicUnit; + let i; - for (atomicUnit in counter) { - if (counter.hasOwnProperty(atomicUnit)) { - var count = counter[atomicUnit]; + for (i = 0; i < this.numerator.length; i++) { + atomicUnit = this.numerator[i]; + counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; + } - if (count > 0) { - for (i = 0; i < count; i++) { - this.numerator.push(atomicUnit); - } - } else if (count < 0) { - for (i = 0; i < -count; i++) { - this.denominator.push(atomicUnit); + for (i = 0; i < this.denominator.length; i++) { + atomicUnit = this.denominator[i]; + counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; + } + + this.numerator = []; + this.denominator = []; + + for (atomicUnit in counter) { + if (counter.hasOwnProperty(atomicUnit)) { + const count = counter[atomicUnit]; + + if (count > 0) { + for (i = 0; i < count; i++) { + this.numerator.push(atomicUnit); + } + } else if (count < 0) { + for (i = 0; i < -count; i++) { + this.denominator.push(atomicUnit); + } } } } + + this.numerator.sort(); + this.denominator.sort(); } +} - this.numerator.sort(); - this.denominator.sort(); -}; -module.exports = Unit; +Unit.prototype.type = 'Unit'; +export default Unit; diff --git a/lib/less/tree/url.js b/lib/less/tree/url.js index 234292e2d..4c1acdc16 100644 --- a/lib/less/tree/url.js +++ b/lib/less/tree/url.js @@ -1,58 +1,65 @@ -var Node = require('./node'); - -var URL = function (val, index, currentFileInfo, isEvald) { - this.value = val; - this._index = index; - this._fileInfo = currentFileInfo; - this.isEvald = isEvald; -}; -URL.prototype = new Node(); -URL.prototype.type = 'Url'; -URL.prototype.accept = function (visitor) { - this.value = visitor.visit(this.value); -}; -URL.prototype.genCSS = function (context, output) { - output.add('url('); - this.value.genCSS(context, output); - output.add(')'); -}; -URL.prototype.eval = function (context) { - var val = this.value.eval(context), - rootpath; - - if (!this.isEvald) { - // Add the rootpath if the URL requires a rewrite - rootpath = this.fileInfo() && this.fileInfo().rootpath; - if (typeof rootpath === 'string' && - typeof val.value === 'string' && - context.pathRequiresRewrite(val.value)) { - if (!val.quote) { - rootpath = escapePath(rootpath); +import Node from './node'; + +class URL extends Node { + constructor(val, index, currentFileInfo, isEvald) { + super(); + + this.value = val; + this._index = index; + this._fileInfo = currentFileInfo; + this.isEvald = isEvald; + } + + accept(visitor) { + this.value = visitor.visit(this.value); + } + + genCSS(context, output) { + output.add('url('); + this.value.genCSS(context, output); + output.add(')'); + } + + eval(context) { + const val = this.value.eval(context); + let rootpath; + + if (!this.isEvald) { + // Add the rootpath if the URL requires a rewrite + rootpath = this.fileInfo() && this.fileInfo().rootpath; + if (typeof rootpath === 'string' && + typeof val.value === 'string' && + context.pathRequiresRewrite(val.value)) { + if (!val.quote) { + rootpath = escapePath(rootpath); + } + val.value = context.rewritePath(val.value, rootpath); + } else { + val.value = context.normalizePath(val.value); } - val.value = context.rewritePath(val.value, rootpath); - } else { - val.value = context.normalizePath(val.value); - } - // Add url args if enabled - if (context.urlArgs) { - if (!val.value.match(/^\s*data:/)) { - var delimiter = val.value.indexOf('?') === -1 ? '?' : '&'; - var urlArgs = delimiter + context.urlArgs; - if (val.value.indexOf('#') !== -1) { - val.value = val.value.replace('#', urlArgs + '#'); - } else { - val.value += urlArgs; + // Add url args if enabled + if (context.urlArgs) { + if (!val.value.match(/^\s*data:/)) { + const delimiter = val.value.indexOf('?') === -1 ? '?' : '&'; + const urlArgs = delimiter + context.urlArgs; + if (val.value.indexOf('#') !== -1) { + val.value = val.value.replace('#', `${urlArgs}#`); + } else { + val.value += urlArgs; + } } } } + + return new URL(val, this.getIndex(), this.fileInfo(), true); } +} - return new URL(val, this.getIndex(), this.fileInfo(), true); -}; +URL.prototype.type = 'Url'; function escapePath(path) { - return path.replace(/[\(\)'"\s]/g, function(match) { return '\\' + match; }); + return path.replace(/[\(\)'"\s]/g, match => `\\${match}`); } -module.exports = URL; +export default URL; diff --git a/lib/less/tree/value.js b/lib/less/tree/value.js index cd3fa3904..c21d0b294 100644 --- a/lib/less/tree/value.js +++ b/lib/less/tree/value.js @@ -1,39 +1,44 @@ -var Node = require('./node'); +import Node from './node'; -var Value = function (value) { - if (!value) { - throw new Error('Value requires an array argument'); - } - if (!Array.isArray(value)) { - this.value = [ value ]; - } - else { - this.value = value; +class Value extends Node { + constructor(value) { + super(); + + if (!value) { + throw new Error('Value requires an array argument'); + } + if (!Array.isArray(value)) { + this.value = [ value ]; + } + else { + this.value = value; + } } -}; -Value.prototype = new Node(); -Value.prototype.type = 'Value'; -Value.prototype.accept = function (visitor) { - if (this.value) { - this.value = visitor.visitArray(this.value); + + accept(visitor) { + if (this.value) { + this.value = visitor.visitArray(this.value); + } } -}; -Value.prototype.eval = function (context) { - if (this.value.length === 1) { - return this.value[0].eval(context); - } else { - return new Value(this.value.map(function (v) { - return v.eval(context); - })); + + eval(context) { + if (this.value.length === 1) { + return this.value[0].eval(context); + } else { + return new Value(this.value.map(v => v.eval(context))); + } } -}; -Value.prototype.genCSS = function (context, output) { - var i; - for (i = 0; i < this.value.length; i++) { - this.value[i].genCSS(context, output); - if (i + 1 < this.value.length) { - output.add((context && context.compress) ? ',' : ', '); + + genCSS(context, output) { + let i; + for (i = 0; i < this.value.length; i++) { + this.value[i].genCSS(context, output); + if (i + 1 < this.value.length) { + output.add((context && context.compress) ? ',' : ', '); + } } } -}; -module.exports = Value; +} + +Value.prototype.type = 'Value'; +export default Value; diff --git a/lib/less/tree/variable-call.js b/lib/less/tree/variable-call.js index ab9b7c647..c246d7d13 100644 --- a/lib/less/tree/variable-call.js +++ b/lib/less/tree/variable-call.js @@ -1,39 +1,46 @@ -var Node = require('./node'), - Variable = require('./variable'), - Ruleset = require('./ruleset'), - DetachedRuleset = require('./detached-ruleset'), - LessError = require('../less-error'); +import Node from './node'; +import Variable from './variable'; +import Ruleset from './ruleset'; +import DetachedRuleset from './detached-ruleset'; +import LessError from '../less-error'; -var VariableCall = function (variable, index, currentFileInfo) { - this.variable = variable; - this._index = index; - this._fileInfo = currentFileInfo; - this.allowRoot = true; -}; -VariableCall.prototype = new Node(); -VariableCall.prototype.type = 'VariableCall'; -VariableCall.prototype.eval = function (context) { - var rules, detachedRuleset = new Variable(this.variable, this.getIndex(), this.fileInfo()).eval(context), - error = new LessError({message: 'Could not evaluate variable call ' + this.variable}); +class VariableCall extends Node { + constructor(variable, index, currentFileInfo) { + super(); - if (!detachedRuleset.ruleset) { - if (detachedRuleset.rules) { - rules = detachedRuleset; - } - else if (Array.isArray(detachedRuleset)) { - rules = new Ruleset('', detachedRuleset); - } - else if (Array.isArray(detachedRuleset.value)) { - rules = new Ruleset('', detachedRuleset.value); + this.variable = variable; + this._index = index; + this._fileInfo = currentFileInfo; + this.allowRoot = true; + } + + eval(context) { + let rules; + let detachedRuleset = new Variable(this.variable, this.getIndex(), this.fileInfo()).eval(context); + const error = new LessError({message: `Could not evaluate variable call ${this.variable}`}); + + if (!detachedRuleset.ruleset) { + if (detachedRuleset.rules) { + rules = detachedRuleset; + } + else if (Array.isArray(detachedRuleset)) { + rules = new Ruleset('', detachedRuleset); + } + else if (Array.isArray(detachedRuleset.value)) { + rules = new Ruleset('', detachedRuleset.value); + } + else { + throw error; + } + detachedRuleset = new DetachedRuleset(rules); } - else { - throw error; + + if (detachedRuleset.ruleset) { + return detachedRuleset.callEval(context); } - detachedRuleset = new DetachedRuleset(rules); - } - if (detachedRuleset.ruleset) { - return detachedRuleset.callEval(context); + throw error; } - throw error; -}; -module.exports = VariableCall; +} + +VariableCall.prototype.type = 'VariableCall'; +export default VariableCall; diff --git a/lib/less/tree/variable.js b/lib/less/tree/variable.js index 9ead289c4..1c7e5f0c7 100644 --- a/lib/less/tree/variable.js +++ b/lib/less/tree/variable.js @@ -1,60 +1,67 @@ -var Node = require('./node'), - Call = require('./call'); - -var Variable = function (name, index, currentFileInfo) { - this.name = name; - this._index = index; - this._fileInfo = currentFileInfo; -}; -Variable.prototype = new Node(); -Variable.prototype.type = 'Variable'; -Variable.prototype.eval = function (context) { - var variable, name = this.name; +import Node from './node'; +import Call from './call'; - if (name.indexOf('@@') === 0) { - name = '@' + new Variable(name.slice(1), this.getIndex(), this.fileInfo()).eval(context).value; - } +class Variable extends Node { + constructor(name, index, currentFileInfo) { + super(); - if (this.evaluating) { - throw { type: 'Name', - message: 'Recursive variable definition for ' + name, - filename: this.fileInfo().filename, - index: this.getIndex() }; + this.name = name; + this._index = index; + this._fileInfo = currentFileInfo; } - this.evaluating = true; + eval(context) { + let variable; + let name = this.name; - variable = this.find(context.frames, function (frame) { - var v = frame.variable(name); - if (v) { - if (v.important) { - var importantScope = context.importantScope[context.importantScope.length - 1]; - importantScope.important = v.important; - } - // If in calc, wrap vars in a function call to cascade evaluate args first - if (context.inCalc) { - return (new Call('_SELF', [v.value])).eval(context); - } - else { - return v.value.eval(context); + if (name.indexOf('@@') === 0) { + name = `@${new Variable(name.slice(1), this.getIndex(), this.fileInfo()).eval(context).value}`; + } + + if (this.evaluating) { + throw { type: 'Name', + message: `Recursive variable definition for ${name}`, + filename: this.fileInfo().filename, + index: this.getIndex() }; + } + + this.evaluating = true; + + variable = this.find(context.frames, frame => { + const v = frame.variable(name); + if (v) { + if (v.important) { + const importantScope = context.importantScope[context.importantScope.length - 1]; + importantScope.important = v.important; + } + // If in calc, wrap vars in a function call to cascade evaluate args first + if (context.inCalc) { + return (new Call('_SELF', [v.value])).eval(context); + } + else { + return v.value.eval(context); + } } + }); + if (variable) { + this.evaluating = false; + return variable; + } else { + throw { type: 'Name', + message: `variable ${name} is undefined`, + filename: this.fileInfo().filename, + index: this.getIndex() }; } - }); - if (variable) { - this.evaluating = false; - return variable; - } else { - throw { type: 'Name', - message: 'variable ' + name + ' is undefined', - filename: this.fileInfo().filename, - index: this.getIndex() }; } -}; -Variable.prototype.find = function (obj, fun) { - for (var i = 0, r; i < obj.length; i++) { - r = fun.call(obj, obj[i]); - if (r) { return r; } + + find(obj, fun) { + for (let i = 0, r; i < obj.length; i++) { + r = fun.call(obj, obj[i]); + if (r) { return r; } + } + return null; } - return null; -}; -module.exports = Variable; +} + +Variable.prototype.type = 'Variable'; +export default Variable; diff --git a/lib/less/utils.js b/lib/less/utils.js index ade25c832..54f776962 100644 --- a/lib/less/utils.js +++ b/lib/less/utils.js @@ -1,120 +1,122 @@ /* jshint proto: true */ -var Constants = require('./constants'); -var clone = require('clone'); +import * as Constants from './constants'; +import CloneHelper from 'clone'; -var utils = { - getLocation: function(index, inputStream) { - var n = index + 1, - line = null, - column = -1; +export function getLocation(index, inputStream) { + let n = index + 1; + let line = null; + let column = -1; - while (--n >= 0 && inputStream.charAt(n) !== '\n') { - column++; - } + while (--n >= 0 && inputStream.charAt(n) !== '\n') { + column++; + } - if (typeof index === 'number') { - line = (inputStream.slice(0, index).match(/\n/g) || '').length; - } + if (typeof index === 'number') { + line = (inputStream.slice(0, index).match(/\n/g) || '').length; + } - return { - line: line, - column: column - }; - }, - copyArray: function(arr) { - var i, length = arr.length, - copy = new Array(length); - - for (i = 0; i < length; i++) { - copy[i] = arr[i]; - } - return copy; - }, - clone: function (obj) { - var cloned = {}; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - cloned[prop] = obj[prop]; - } - } - return cloned; - }, - copyOptions: function(obj1, obj2) { - if (obj2 && obj2._defaults) { - return obj2; - } - var opts = utils.defaults(obj1, obj2); - if (opts.strictMath) { - opts.math = Constants.Math.STRICT_LEGACY; - } - // Back compat with changed relativeUrls option - if (opts.relativeUrls) { - opts.rewriteUrls = Constants.RewriteUrls.ALL; - } - if (typeof opts.math === 'string') { - switch (opts.math.toLowerCase()) { - case 'always': - opts.math = Constants.Math.ALWAYS; - break; - case 'parens-division': - opts.math = Constants.Math.PARENS_DIVISION; - break; - case 'strict': - case 'parens': - opts.math = Constants.Math.PARENS; - break; - case 'strict-legacy': - opts.math = Constants.Math.STRICT_LEGACY; - } + return { + line, + column + }; +} + +export function copyArray(arr) { + let i; + const length = arr.length; + const copy = new Array(length); + + for (i = 0; i < length; i++) { + copy[i] = arr[i]; + } + return copy; +} + +export function clone(obj) { + const cloned = {}; + for (const prop in obj) { + if (obj.hasOwnProperty(prop)) { + cloned[prop] = obj[prop]; } - if (typeof opts.rewriteUrls === 'string') { - switch (opts.rewriteUrls.toLowerCase()) { - case 'off': - opts.rewriteUrls = Constants.RewriteUrls.OFF; - break; - case 'local': - opts.rewriteUrls = Constants.RewriteUrls.LOCAL; - break; - case 'all': - opts.rewriteUrls = Constants.RewriteUrls.ALL; - break; - } + } + return cloned; +} + +export function defaults(obj1, obj2) { + let newObj = obj2 || {}; + if (!obj2._defaults) { + newObj = {}; + const defaults = CloneHelper(obj1); + newObj._defaults = defaults; + const cloned = obj2 ? CloneHelper(obj2) : {}; + Object.assign(newObj, defaults, cloned); + } + return newObj; +} + +export function copyOptions(obj1, obj2) { + if (obj2 && obj2._defaults) { + return obj2; + } + const opts = defaults(obj1, obj2); + if (opts.strictMath) { + opts.math = Constants.Math.STRICT_LEGACY; + } + // Back compat with changed relativeUrls option + if (opts.relativeUrls) { + opts.rewriteUrls = Constants.RewriteUrls.ALL; + } + if (typeof opts.math === 'string') { + switch (opts.math.toLowerCase()) { + case 'always': + opts.math = Constants.Math.ALWAYS; + break; + case 'parens-division': + opts.math = Constants.Math.PARENS_DIVISION; + break; + case 'strict': + case 'parens': + opts.math = Constants.Math.PARENS; + break; + case 'strict-legacy': + opts.math = Constants.Math.STRICT_LEGACY; } - return opts; - }, - defaults: function(obj1, obj2) { - var newObj = obj2 || {}; - if (!obj2._defaults) { - newObj = {}; - var defaults = clone(obj1); - newObj._defaults = defaults; - var cloned = obj2 ? clone(obj2) : {}; - Object.assign(newObj, defaults, cloned); + } + if (typeof opts.rewriteUrls === 'string') { + switch (opts.rewriteUrls.toLowerCase()) { + case 'off': + opts.rewriteUrls = Constants.RewriteUrls.OFF; + break; + case 'local': + opts.rewriteUrls = Constants.RewriteUrls.LOCAL; + break; + case 'all': + opts.rewriteUrls = Constants.RewriteUrls.ALL; + break; } - return newObj; - }, - merge: function(obj1, obj2) { - for (var prop in obj2) { - if (obj2.hasOwnProperty(prop)) { - obj1[prop] = obj2[prop]; - } + } + return opts; +} + +export function merge(obj1, obj2) { + for (const prop in obj2) { + if (obj2.hasOwnProperty(prop)) { + obj1[prop] = obj2[prop]; } - return obj1; - }, - flattenArray: function(arr, result) { - result = result || []; - for (var i = 0, length = arr.length; i < length; i++) { - var value = arr[i]; - if (Array.isArray(value)) { - utils.flattenArray(value, result); - } else { - if (value !== undefined) { - result.push(value); - } + } + return obj1; +} + +export function flattenArray(arr, result = []) { + for (let i = 0, length = arr.length; i < length; i++) { + const value = arr[i]; + if (Array.isArray(value)) { + flattenArray(value, result); + } else { + if (value !== undefined) { + result.push(value); } } - return result; } -}; - -module.exports = utils; \ No newline at end of file + return result; +} \ No newline at end of file diff --git a/lib/less/visitors/extend-visitor.js b/lib/less/visitors/extend-visitor.js index be13f8242..f9e5b40c0 100644 --- a/lib/less/visitors/extend-visitor.js +++ b/lib/less/visitors/extend-visitor.js @@ -1,37 +1,46 @@ -var tree = require('../tree'), - Visitor = require('./visitor'), - logger = require('../logger'), - utils = require('../utils'); +import tree from '../tree'; +import Visitor from './visitor'; +import logger from '../logger'; +import * as utils from '../utils'; /* jshint loopfunc:true */ -var ExtendFinderVisitor = function() { - this._visitor = new Visitor(this); - this.contexts = []; - this.allExtendsStack = [[]]; -}; +class ExtendFinderVisitor { + constructor() { + this._visitor = new Visitor(this); + this.contexts = []; + this.allExtendsStack = [[]]; + } -ExtendFinderVisitor.prototype = { - run: function (root) { + run(root) { root = this._visitor.visit(root); root.allExtends = this.allExtendsStack[0]; return root; - }, - visitDeclaration: function (declNode, visitArgs) { + } + + visitDeclaration(declNode, visitArgs) { visitArgs.visitDeeper = false; - }, - visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { + } + + visitMixinDefinition(mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; - }, - visitRuleset: function (rulesetNode, visitArgs) { + } + + visitRuleset(rulesetNode, visitArgs) { if (rulesetNode.root) { return; } - var i, j, extend, allSelectorsExtendList = [], extendList; + let i; + let j; + let extend; + const allSelectorsExtendList = []; + let extendList; // get &:extend(.a); rules which apply to all selectors in this ruleset - var rules = rulesetNode.rules, ruleCnt = rules ? rules.length : 0; + const rules = rulesetNode.rules; + + const ruleCnt = rules ? rules.length : 0; for (i = 0; i < ruleCnt; i++) { if (rulesetNode.rules[i] instanceof tree.Extend) { allSelectorsExtendList.push(rules[i]); @@ -41,19 +50,17 @@ ExtendFinderVisitor.prototype = { // now find every selector and apply the extends that apply to all extends // and the ones which apply to an individual extend - var paths = rulesetNode.paths; + const paths = rulesetNode.paths; for (i = 0; i < paths.length; i++) { - var selectorPath = paths[i], - selector = selectorPath[selectorPath.length - 1], - selExtendList = selector.extendList; + const selectorPath = paths[i]; + const selector = selectorPath[selectorPath.length - 1]; + const selExtendList = selector.extendList; extendList = selExtendList ? utils.copyArray(selExtendList).concat(allSelectorsExtendList) - : allSelectorsExtendList; + : allSelectorsExtendList; if (extendList) { - extendList = extendList.map(function(allSelectorsExtend) { - return allSelectorsExtend.clone(); - }); + extendList = extendList.map(allSelectorsExtend => allSelectorsExtend.clone()); } for (j = 0; j < extendList.length; j++) { @@ -67,62 +74,67 @@ ExtendFinderVisitor.prototype = { } this.contexts.push(rulesetNode.selectors); - }, - visitRulesetOut: function (rulesetNode) { + } + + visitRulesetOut(rulesetNode) { if (!rulesetNode.root) { this.contexts.length = this.contexts.length - 1; } - }, - visitMedia: function (mediaNode, visitArgs) { + } + + visitMedia(mediaNode, visitArgs) { mediaNode.allExtends = []; this.allExtendsStack.push(mediaNode.allExtends); - }, - visitMediaOut: function (mediaNode) { + } + + visitMediaOut(mediaNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; - }, - visitAtRule: function (atRuleNode, visitArgs) { + } + + visitAtRule(atRuleNode, visitArgs) { atRuleNode.allExtends = []; this.allExtendsStack.push(atRuleNode.allExtends); - }, - visitAtRuleOut: function (atRuleNode) { + } + + visitAtRuleOut(atRuleNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; } -}; +} -var ProcessExtendsVisitor = function() { - this._visitor = new Visitor(this); -}; +class ProcessExtendsVisitor { + constructor() { + this._visitor = new Visitor(this); + } -ProcessExtendsVisitor.prototype = { - run: function(root) { - var extendFinder = new ExtendFinderVisitor(); + run(root) { + const extendFinder = new ExtendFinderVisitor(); this.extendIndices = {}; extendFinder.run(root); if (!extendFinder.foundExtends) { return root; } root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends)); this.allExtendsStack = [root.allExtends]; - var newRoot = this._visitor.visit(root); + const newRoot = this._visitor.visit(root); this.checkExtendsForNonMatched(root.allExtends); return newRoot; - }, - checkExtendsForNonMatched: function(extendList) { - var indices = this.extendIndices; - extendList.filter(function(extend) { - return !extend.hasFoundMatches && extend.parent_ids.length == 1; - }).forEach(function(extend) { - var selector = '_unknown_'; + } + + checkExtendsForNonMatched(extendList) { + const indices = this.extendIndices; + extendList.filter(extend => !extend.hasFoundMatches && extend.parent_ids.length == 1).forEach(extend => { + let selector = '_unknown_'; try { selector = extend.selector.toCSS({}); } catch (_) {} - if (!indices[extend.index + ' ' + selector]) { - indices[extend.index + ' ' + selector] = true; - logger.warn('extend \'' + selector + '\' has no matches'); + if (!indices[`${extend.index} ${selector}`]) { + indices[`${extend.index} ${selector}`] = true; + logger.warn(`extend '${selector}' has no matches`); } }); - }, - doExtendChaining: function (extendsList, extendsListTarget, iterationCount) { + } + + doExtendChaining(extendsList, extendsListTarget, iterationCount) { // // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering // and pasting the selector we would do normally, but we are also adding an extend with the same target selector @@ -132,8 +144,17 @@ ProcessExtendsVisitor.prototype = { // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already // processed if we look at each selector at a time, as is done in visitRuleset - var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, - extend, targetExtend, newExtend; + let extendIndex; + + let targetExtendIndex; + let matches; + const extendsToAdd = []; + let newSelector; + const extendVisitor = this; + let selectorPath; + let extend; + let targetExtend; + let newExtend; iterationCount = iterationCount || 0; @@ -160,8 +181,8 @@ ProcessExtendsVisitor.prototype = { extend.hasFoundMatches = true; // we found a match, so for each self selector.. - extend.selfSelectors.forEach(function(selfSelector) { - var info = targetExtend.visibilityInfo(); + extend.selfSelectors.forEach(selfSelector => { + const info = targetExtend.visibilityInfo(); // process the extend as usual newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector, extend.isVisible()); @@ -197,15 +218,14 @@ ProcessExtendsVisitor.prototype = { // may no longer be needed. this.extendChainCount++; if (iterationCount > 100) { - var selectorOne = '{unable to calculate}'; - var selectorTwo = '{unable to calculate}'; + let selectorOne = '{unable to calculate}'; + let selectorTwo = '{unable to calculate}'; try { selectorOne = extendsToAdd[0].selfSelectors[0].toCSS(); selectorTwo = extendsToAdd[0].selector.toCSS(); } catch (e) {} - throw { message: 'extend circular reference detected. One of the circular extends is currently:' + - selectorOne + ':extend(' + selectorTwo + ')'}; + throw { message: `extend circular reference detected. One of the circular extends is currently:${selectorOne}:extend(${selectorTwo})`}; } // now process the new extends on the existing rules so that we can handle a extending b extending c extending @@ -214,22 +234,31 @@ ProcessExtendsVisitor.prototype = { } else { return extendsToAdd; } - }, - visitDeclaration: function (ruleNode, visitArgs) { + } + + visitDeclaration(ruleNode, visitArgs) { visitArgs.visitDeeper = false; - }, - visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { + } + + visitMixinDefinition(mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; - }, - visitSelector: function (selectorNode, visitArgs) { + } + + visitSelector(selectorNode, visitArgs) { visitArgs.visitDeeper = false; - }, - visitRuleset: function (rulesetNode, visitArgs) { + } + + visitRuleset(rulesetNode, visitArgs) { if (rulesetNode.root) { return; } - var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length - 1], - selectorsToAdd = [], extendVisitor = this, selectorPath; + let matches; + let pathIndex; + let extendIndex; + const allExtends = this.allExtendsStack[this.allExtendsStack.length - 1]; + const selectorsToAdd = []; + const extendVisitor = this; + let selectorPath; // look at each selector path in the ruleset, find any extend matches and then copy, find and replace @@ -239,7 +268,7 @@ ProcessExtendsVisitor.prototype = { // extending extends happens initially, before the main pass if (rulesetNode.extendOnEveryPath) { continue; } - var extendList = selectorPath[selectorPath.length - 1].extendList; + const extendList = selectorPath[selectorPath.length - 1].extendList; if (extendList && extendList.length) { continue; } matches = this.findMatch(allExtends[extendIndex], selectorPath); @@ -247,8 +276,8 @@ ProcessExtendsVisitor.prototype = { if (matches.length) { allExtends[extendIndex].hasFoundMatches = true; - allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) { - var extendedSelectors; + allExtends[extendIndex].selfSelectors.forEach(selfSelector => { + let extendedSelectors; extendedSelectors = extendVisitor.extendSelector(matches, selectorPath, selfSelector, allExtends[extendIndex].isVisible()); selectorsToAdd.push(extendedSelectors); }); @@ -256,17 +285,25 @@ ProcessExtendsVisitor.prototype = { } } rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd); - }, - findMatch: function (extend, haystackSelectorPath) { + } + + findMatch(extend, haystackSelectorPath) { // // look through the haystack selector path to try and find the needle - extend.selector // returns an array of selector matches that can then be replaced // - var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement, - targetCombinator, i, - extendVisitor = this, - needleElements = extend.selector.elements, - potentialMatches = [], potentialMatch, matches = []; + let haystackSelectorIndex; + + let hackstackSelector; + let hackstackElementIndex; + let haystackElement; + let targetCombinator; + let i; + const extendVisitor = this; + const needleElements = extend.selector.elements; + const potentialMatches = []; + let potentialMatch; + const matches = []; // loop through the haystack elements for (haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) { @@ -327,8 +364,9 @@ ProcessExtendsVisitor.prototype = { } } return matches; - }, - isElementValuesEqual: function(elementValue1, elementValue2) { + } + + isElementValuesEqual(elementValue1, elementValue2) { if (typeof elementValue1 === 'string' || typeof elementValue2 === 'string') { return elementValue1 === elementValue2; } @@ -352,7 +390,7 @@ ProcessExtendsVisitor.prototype = { if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) { return false; } - for (var i = 0; i < elementValue1.elements.length; i++) { + for (let i = 0; i < elementValue1.elements.length; i++) { if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) { if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) { return false; @@ -365,19 +403,20 @@ ProcessExtendsVisitor.prototype = { return true; } return false; - }, - extendSelector:function (matches, selectorPath, replacementSelector, isVisible) { + } + extendSelector(matches, selectorPath, replacementSelector, isVisible) { // for a set of matches, replace each match with the replacement selector - var currentSelectorPathIndex = 0, - currentSelectorPathElementIndex = 0, - path = [], - matchIndex, - selector, - firstElement, - match, - newElements; + let currentSelectorPathIndex = 0; + + let currentSelectorPathElementIndex = 0; + let path = []; + let matchIndex; + let selector; + let firstElement; + let match; + let newElements; for (matchIndex = 0; matchIndex < matches.length; matchIndex++) { match = matches[matchIndex]; @@ -427,9 +466,9 @@ ProcessExtendsVisitor.prototype = { } path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length)); - path = path.map(function (currentValue) { + path = path.map(currentValue => { // we can re-use elements here, because the visibility property matters only for selectors - var derived = currentValue.createDerived(currentValue.elements); + const derived = currentValue.createDerived(currentValue.elements); if (isVisible) { derived.ensureVisibility(); } else { @@ -438,25 +477,29 @@ ProcessExtendsVisitor.prototype = { return derived; }); return path; - }, - visitMedia: function (mediaNode, visitArgs) { - var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); + } + + visitMedia(mediaNode, visitArgs) { + let newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends)); this.allExtendsStack.push(newAllExtends); - }, - visitMediaOut: function (mediaNode) { - var lastIndex = this.allExtendsStack.length - 1; + } + + visitMediaOut(mediaNode) { + const lastIndex = this.allExtendsStack.length - 1; this.allExtendsStack.length = lastIndex; - }, - visitAtRule: function (atRuleNode, visitArgs) { - var newAllExtends = atRuleNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); + } + + visitAtRule(atRuleNode, visitArgs) { + let newAllExtends = atRuleNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, atRuleNode.allExtends)); this.allExtendsStack.push(newAllExtends); - }, - visitAtRuleOut: function (atRuleNode) { - var lastIndex = this.allExtendsStack.length - 1; + } + + visitAtRuleOut(atRuleNode) { + const lastIndex = this.allExtendsStack.length - 1; this.allExtendsStack.length = lastIndex; } -}; +} -module.exports = ProcessExtendsVisitor; +export default ProcessExtendsVisitor; diff --git a/lib/less/visitors/import-sequencer.js b/lib/less/visitors/import-sequencer.js index dcebf8e72..b21f628b4 100644 --- a/lib/less/visitors/import-sequencer.js +++ b/lib/less/visitors/import-sequencer.js @@ -1,54 +1,58 @@ -function ImportSequencer(onSequencerEmpty) { - this.imports = []; - this.variableImports = []; - this._onSequencerEmpty = onSequencerEmpty; - this._currentDepth = 0; -} +class ImportSequencer { + constructor(onSequencerEmpty) { + this.imports = []; + this.variableImports = []; + this._onSequencerEmpty = onSequencerEmpty; + this._currentDepth = 0; + } + + addImport(callback) { + const importSequencer = this; -ImportSequencer.prototype.addImport = function(callback) { - var importSequencer = this, - importItem = { - callback: callback, + const importItem = { + callback, args: null, isReady: false }; - this.imports.push(importItem); - return function() { - importItem.args = Array.prototype.slice.call(arguments, 0); - importItem.isReady = true; - importSequencer.tryRun(); - }; -}; -ImportSequencer.prototype.addVariableImport = function(callback) { - this.variableImports.push(callback); -}; + this.imports.push(importItem); + return function(...args) { + importItem.args = Array.prototype.slice.call(args, 0); + importItem.isReady = true; + importSequencer.tryRun(); + }; + } + + addVariableImport(callback) { + this.variableImports.push(callback); + } -ImportSequencer.prototype.tryRun = function() { - this._currentDepth++; - try { - while (true) { - while (this.imports.length > 0) { - var importItem = this.imports[0]; - if (!importItem.isReady) { - return; + tryRun() { + this._currentDepth++; + try { + while (true) { + while (this.imports.length > 0) { + const importItem = this.imports[0]; + if (!importItem.isReady) { + return; + } + this.imports = this.imports.slice(1); + importItem.callback.apply(null, importItem.args); } - this.imports = this.imports.slice(1); - importItem.callback.apply(null, importItem.args); - } - if (this.variableImports.length === 0) { - break; + if (this.variableImports.length === 0) { + break; + } + const variableImport = this.variableImports[0]; + this.variableImports = this.variableImports.slice(1); + variableImport(); } - var variableImport = this.variableImports[0]; - this.variableImports = this.variableImports.slice(1); - variableImport(); + } finally { + this._currentDepth--; + } + if (this._currentDepth === 0 && this._onSequencerEmpty) { + this._onSequencerEmpty(); } - } finally { - this._currentDepth--; - } - if (this._currentDepth === 0 && this._onSequencerEmpty) { - this._onSequencerEmpty(); } -}; +} -module.exports = ImportSequencer; +export default ImportSequencer; diff --git a/lib/less/visitors/import-visitor.js b/lib/less/visitors/import-visitor.js index 25cc68108..a83cd4331 100644 --- a/lib/less/visitors/import-visitor.js +++ b/lib/less/visitors/import-visitor.js @@ -1,9 +1,9 @@ -var contexts = require('../contexts'), - Visitor = require('./visitor'), - ImportSequencer = require('./import-sequencer'), - utils = require('../utils'); +import contexts from '../contexts'; +import Visitor from './visitor'; +import ImportSequencer from './import-sequencer'; +import * as utils from '../utils'; -var ImportVisitor = function(importer, finish) { +const ImportVisitor = function(importer, finish) { this._visitor = new Visitor(this); this._importer = importer; @@ -36,12 +36,12 @@ ImportVisitor.prototype = { this._finish(this.error); }, visitImport: function (importNode, visitArgs) { - var inlineCSS = importNode.options.inline; + const inlineCSS = importNode.options.inline; if (!importNode.css || inlineCSS) { - var context = new contexts.Eval(this.context, utils.copyArray(this.context.frames)); - var importParent = context.frames[0]; + const context = new contexts.Eval(this.context, utils.copyArray(this.context.frames)); + const importParent = context.frames[0]; this.importCount++; if (importNode.isVariableImport()) { @@ -53,8 +53,8 @@ ImportVisitor.prototype = { visitArgs.visitDeeper = false; }, processImportNode: function(importNode, context, importParent) { - var evaldImportNode, - inlineCSS = importNode.options.inline; + let evaldImportNode; + const inlineCSS = importNode.options.inline; try { evaldImportNode = importNode.evalForImport(context); @@ -67,23 +67,22 @@ ImportVisitor.prototype = { } if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) { - if (evaldImportNode.options.multiple) { context.importMultiple = true; } // try appending if we haven't determined if it is css or not - var tryAppendLessExtension = evaldImportNode.css === undefined; + const tryAppendLessExtension = evaldImportNode.css === undefined; - for (var i = 0; i < importParent.rules.length; i++) { + for (let i = 0; i < importParent.rules.length; i++) { if (importParent.rules[i] === importNode) { importParent.rules[i] = evaldImportNode; break; } } - var onImported = this.onImported.bind(this, evaldImportNode, context), - sequencedOnImported = this._sequencer.addImport(onImported); + const onImported = this.onImported.bind(this, evaldImportNode, context); + const sequencedOnImported = this._sequencer.addImport(onImported); this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.fileInfo(), evaldImportNode.options, sequencedOnImported); @@ -102,17 +101,17 @@ ImportVisitor.prototype = { this.error = e; } - var importVisitor = this, - inlineCSS = importNode.options.inline, - isPlugin = importNode.options.isPlugin, - isOptional = importNode.options.optional, - duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector; + const importVisitor = this; + const inlineCSS = importNode.options.inline; + const isPlugin = importNode.options.isPlugin; + const isOptional = importNode.options.optional; + const duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector; if (!context.importMultiple) { if (duplicateImport) { importNode.skip = true; } else { - importNode.skip = function() { + importNode.skip = () => { if (fullPath in importVisitor.onceFileDetectionMap) { return true; } @@ -133,7 +132,7 @@ ImportVisitor.prototype = { if (!inlineCSS && !isPlugin && (context.importMultiple || !duplicateImport)) { importVisitor.recursionDetector[fullPath] = true; - var oldContext = this.context; + const oldContext = this.context; this.context = context; try { this._visitor.visit(root); @@ -187,4 +186,4 @@ ImportVisitor.prototype = { this.context.frames.shift(); } }; -module.exports = ImportVisitor; +export default ImportVisitor; diff --git a/lib/less/visitors/index.js b/lib/less/visitors/index.js index 2176e49c5..96deb76c4 100644 --- a/lib/less/visitors/index.js +++ b/lib/less/visitors/index.js @@ -1,10 +1,15 @@ -var visitors = { - Visitor: require('./visitor'), - ImportVisitor: require('./import-visitor'), - MarkVisibleSelectorsVisitor: require('./set-tree-visibility-visitor'), - ExtendVisitor: require('./extend-visitor'), - JoinSelectorVisitor: require('./join-selector-visitor'), - ToCSSVisitor: require('./to-css-visitor') -}; +import Visitor from './visitor'; +import ImportVisitor from './import-visitor'; +import MarkVisibleSelectorsVisitor from './set-tree-visibility-visitor'; +import ExtendVisitor from './extend-visitor'; +import JoinSelectorVisitor from './join-selector-visitor'; +import ToCSSVisitor from './to-css-visitor'; -module.exports = visitors; +export default { + Visitor, + ImportVisitor, + MarkVisibleSelectorsVisitor, + ExtendVisitor, + JoinSelectorVisitor, + ToCSSVisitor +}; diff --git a/lib/less/visitors/join-selector-visitor.js b/lib/less/visitors/join-selector-visitor.js index 1ea830524..d042ee3d0 100644 --- a/lib/less/visitors/join-selector-visitor.js +++ b/lib/less/visitors/join-selector-visitor.js @@ -1,51 +1,57 @@ -var Visitor = require('./visitor'); +import Visitor from './visitor'; -var JoinSelectorVisitor = function() { - this.contexts = [[]]; - this._visitor = new Visitor(this); -}; +class JoinSelectorVisitor { + constructor() { + this.contexts = [[]]; + this._visitor = new Visitor(this); + } -JoinSelectorVisitor.prototype = { - run: function (root) { + run(root) { return this._visitor.visit(root); - }, - visitDeclaration: function (declNode, visitArgs) { + } + + visitDeclaration(declNode, visitArgs) { visitArgs.visitDeeper = false; - }, - visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { + } + + visitMixinDefinition(mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; - }, + } - visitRuleset: function (rulesetNode, visitArgs) { - var context = this.contexts[this.contexts.length - 1], - paths = [], selectors; + visitRuleset(rulesetNode, visitArgs) { + const context = this.contexts[this.contexts.length - 1]; + const paths = []; + let selectors; this.contexts.push(paths); if (!rulesetNode.root) { selectors = rulesetNode.selectors; if (selectors) { - selectors = selectors.filter(function(selector) { return selector.getIsOutput(); }); + selectors = selectors.filter(selector => selector.getIsOutput()); rulesetNode.selectors = selectors.length ? selectors : (selectors = null); if (selectors) { rulesetNode.joinSelectors(paths, context, selectors); } } if (!selectors) { rulesetNode.rules = null; } rulesetNode.paths = paths; } - }, - visitRulesetOut: function (rulesetNode) { + } + + visitRulesetOut(rulesetNode) { this.contexts.length = this.contexts.length - 1; - }, - visitMedia: function (mediaNode, visitArgs) { - var context = this.contexts[this.contexts.length - 1]; + } + + visitMedia(mediaNode, visitArgs) { + const context = this.contexts[this.contexts.length - 1]; mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia); - }, - visitAtRule: function (atRuleNode, visitArgs) { - var context = this.contexts[this.contexts.length - 1]; + } + + visitAtRule(atRuleNode, visitArgs) { + const context = this.contexts[this.contexts.length - 1]; if (atRuleNode.rules && atRuleNode.rules.length) { atRuleNode.rules[0].root = (atRuleNode.isRooted || context.length === 0 || null); } } -}; +} -module.exports = JoinSelectorVisitor; +export default JoinSelectorVisitor; diff --git a/lib/less/visitors/set-tree-visibility-visitor.js b/lib/less/visitors/set-tree-visibility-visitor.js index 0f9c9e736..3a713e0ae 100644 --- a/lib/less/visitors/set-tree-visibility-visitor.js +++ b/lib/less/visitors/set-tree-visibility-visitor.js @@ -1,38 +1,45 @@ -var SetTreeVisibilityVisitor = function(visible) { - this.visible = visible; -}; -SetTreeVisibilityVisitor.prototype.run = function(root) { - this.visit(root); -}; -SetTreeVisibilityVisitor.prototype.visitArray = function(nodes) { - if (!nodes) { - return nodes; +class SetTreeVisibilityVisitor { + constructor(visible) { + this.visible = visible; } - var cnt = nodes.length, i; - for (i = 0; i < cnt; i++) { - this.visit(nodes[i]); - } - return nodes; -}; -SetTreeVisibilityVisitor.prototype.visit = function(node) { - if (!node) { - return node; + run(root) { + this.visit(root); } - if (node.constructor === Array) { - return this.visitArray(node); + + visitArray(nodes) { + if (!nodes) { + return nodes; + } + + const cnt = nodes.length; + let i; + for (i = 0; i < cnt; i++) { + this.visit(nodes[i]); + } + return nodes; } - if (!node.blocksVisibility || node.blocksVisibility()) { + visit(node) { + if (!node) { + return node; + } + if (node.constructor === Array) { + return this.visitArray(node); + } + + if (!node.blocksVisibility || node.blocksVisibility()) { + return node; + } + if (this.visible) { + node.ensureVisibility(); + } else { + node.ensureInvisibility(); + } + + node.accept(this); return node; } - if (this.visible) { - node.ensureVisibility(); - } else { - node.ensureInvisibility(); - } +} - node.accept(this); - return node; -}; -module.exports = SetTreeVisibilityVisitor; \ No newline at end of file +export default SetTreeVisibilityVisitor; \ No newline at end of file diff --git a/lib/less/visitors/to-css-visitor.js b/lib/less/visitors/to-css-visitor.js index 6b6d3f1c9..0761b4675 100644 --- a/lib/less/visitors/to-css-visitor.js +++ b/lib/less/visitors/to-css-visitor.js @@ -1,18 +1,18 @@ -var tree = require('../tree'), - Visitor = require('./visitor'); +import tree from '../tree'; +import Visitor from './visitor'; -var CSSVisitorUtils = function(context) { - this._visitor = new Visitor(this); - this._context = context; -}; +class CSSVisitorUtils { + constructor(context) { + this._visitor = new Visitor(this); + this._context = context; + } -CSSVisitorUtils.prototype = { - containsSilentNonBlockedChild: function(bodyRules) { - var rule; + containsSilentNonBlockedChild(bodyRules) { + let rule; if (!bodyRules) { return false; } - for (var r = 0; r < bodyRules.length; r++) { + for (let r = 0; r < bodyRules.length; r++) { rule = bodyRules[r]; if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) { // the atrule contains something that was referenced (likely by extend) @@ -21,27 +21,25 @@ CSSVisitorUtils.prototype = { } } return false; - }, + } - keepOnlyVisibleChilds: function(owner) { + keepOnlyVisibleChilds(owner) { if (owner && owner.rules) { - owner.rules = owner.rules.filter(function(thing) { - return thing.isVisible(); - }); + owner.rules = owner.rules.filter(thing => thing.isVisible()); } - }, + } - isEmpty: function(owner) { + isEmpty(owner) { return (owner && owner.rules) ? (owner.rules.length === 0) : true; - }, + } - hasVisibleSelector: function(rulesetNode) { + hasVisibleSelector(rulesetNode) { return (rulesetNode && rulesetNode.paths) ? (rulesetNode.paths.length > 0) : false; - }, + } - resolveVisibility: function (node, originalRules) { + resolveVisibility(node, originalRules) { if (!node.blocksVisibility()) { if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) { return ; @@ -50,7 +48,7 @@ CSSVisitorUtils.prototype = { return node; } - var compiledRulesBody = node.rules[0]; + const compiledRulesBody = node.rules[0]; this.keepOnlyVisibleChilds(compiledRulesBody); if (this.isEmpty(compiledRulesBody)) { @@ -61,9 +59,9 @@ CSSVisitorUtils.prototype = { node.removeVisibilityBlock(); return node; - }, + } - isVisibleRuleset: function(rulesetNode) { + isVisibleRuleset(rulesetNode) { if (rulesetNode.firstRoot) { return true; } @@ -78,10 +76,9 @@ CSSVisitorUtils.prototype = { return true; } +} -}; - -var ToCSSVisitor = function(context) { +const ToCSSVisitor = function(context) { this._visitor = new Visitor(this); this._context = context; this.utils = new CSSVisitorUtils(context); @@ -117,7 +114,7 @@ ToCSSVisitor.prototype = { }, visitMedia: function(mediaNode, visitArgs) { - var originalRules = mediaNode.rules[0].rules; + const originalRules = mediaNode.rules[0].rules; mediaNode.accept(this._visitor); visitArgs.visitDeeper = false; @@ -150,11 +147,11 @@ ToCSSVisitor.prototype = { // if there is only one nested ruleset and that one has no path, then it is // just fake ruleset function hasFakeRuleset(atRuleNode) { - var bodyRules = atRuleNode.rules; + const bodyRules = atRuleNode.rules; return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0); } function getBodyRules(atRuleNode) { - var nodeRules = atRuleNode.rules; + const nodeRules = atRuleNode.rules; if (hasFakeRuleset(atRuleNode)) { return nodeRules[0].rules; } @@ -164,7 +161,7 @@ ToCSSVisitor.prototype = { // it is still true that it is only one ruleset in array // this is last such moment // process childs - var originalRules = getBodyRules(atRuleNode); + const originalRules = getBodyRules(atRuleNode); atRuleNode.accept(this._visitor); visitArgs.visitDeeper = false; @@ -186,7 +183,7 @@ ToCSSVisitor.prototype = { // be considered illegal css as it has to be on the first line if (this.charset) { if (atRuleNode.debugInfo) { - var comment = new tree.Comment('/* ' + atRuleNode.toCSS(this._context).replace(/\n/g, '') + ' */\n'); + const comment = new tree.Comment(`/* ${atRuleNode.toCSS(this._context).replace(/\n/g, '')} */\n`); comment.debugInfo = atRuleNode.debugInfo; return this._visitor.visit(comment); } @@ -203,18 +200,18 @@ ToCSSVisitor.prototype = { return; } - for (var i = 0; i < rules.length; i++) { - var ruleNode = rules[i]; + for (let i = 0; i < rules.length; i++) { + const ruleNode = rules[i]; if (isRoot && ruleNode instanceof tree.Declaration && !ruleNode.variable) { throw { message: 'Properties must be inside selector blocks. They cannot be in the root', index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename}; } if (ruleNode instanceof tree.Call) { - throw { message: 'Function \'' + ruleNode.name + '\' is undefined', + throw { message: `Function '${ruleNode.name}' is undefined`, index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename}; } if (ruleNode.type && !ruleNode.allowRoot) { - throw { message: ruleNode.type + ' node returned by a function is not valid here', + throw { message: `${ruleNode.type} node returned by a function is not valid here`, index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename}; } } @@ -222,7 +219,9 @@ ToCSSVisitor.prototype = { visitRuleset: function (rulesetNode, visitArgs) { // at this point rulesets are nested into each other - var rule, rulesets = []; + let rule; + + const rulesets = []; this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot); @@ -231,8 +230,10 @@ ToCSSVisitor.prototype = { this._compileRulesetPaths(rulesetNode); // remove rulesets from this ruleset body and compile them separately - var nodeRules = rulesetNode.rules, nodeRuleCnt = nodeRules ? nodeRules.length : 0; - for (var i = 0; i < nodeRuleCnt; ) { + const nodeRules = rulesetNode.rules; + + let nodeRuleCnt = nodeRules ? nodeRules.length : 0; + for (let i = 0; i < nodeRuleCnt; ) { rule = nodeRules[i]; if (rule && rule.rules) { // visit because we are moving them out from being a child @@ -252,7 +253,6 @@ ToCSSVisitor.prototype = { rulesetNode.rules = null; } visitArgs.visitDeeper = false; - } else { // if (! rulesetNode.root) { rulesetNode.accept(this._visitor); visitArgs.visitDeeper = false; @@ -278,8 +278,8 @@ ToCSSVisitor.prototype = { _compileRulesetPaths: function(rulesetNode) { if (rulesetNode.paths) { rulesetNode.paths = rulesetNode.paths - .filter(function(p) { - var i; + .filter(p => { + let i; if (p[0].elements[0].combinator.value === ' ') { p[0].elements[0].combinator = new(tree.Combinator)(''); } @@ -297,8 +297,11 @@ ToCSSVisitor.prototype = { if (!rules) { return; } // remove duplicates - var ruleCache = {}, - ruleList, rule, i; + const ruleCache = {}; + + let ruleList; + let rule; + let i; for (i = rules.length - 1; i >= 0 ; i--) { rule = rules[i]; @@ -310,7 +313,7 @@ ToCSSVisitor.prototype = { if (ruleList instanceof tree.Declaration) { ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._context)]; } - var ruleCSS = rule.toCSS(this._context); + const ruleCSS = rule.toCSS(this._context); if (ruleList.indexOf(ruleCSS) !== -1) { rules.splice(i, 1); } else { @@ -326,25 +329,25 @@ ToCSSVisitor.prototype = { return; } - var groups = {}, - groupsArr = []; - - for (var i = 0; i < rules.length; i++) { - var rule = rules[i]; + const groups = {}; + const groupsArr = []; + + for (let i = 0; i < rules.length; i++) { + const rule = rules[i]; if (rule.merge) { - var key = rule.name; + const key = rule.name; groups[key] ? rules.splice(i--, 1) : groupsArr.push(groups[key] = []); groups[key].push(rule); } } - groupsArr.forEach(function(group) { + groupsArr.forEach(group => { if (group.length > 0) { - var result = group[0], - space = [], - comma = [new tree.Expression(space)]; - group.forEach(function(rule) { + const result = group[0]; + let space = []; + const comma = [new tree.Expression(space)]; + group.forEach(rule => { if ((rule.merge === '+') && (space.length > 0)) { comma.push(new tree.Expression(space = [])); } @@ -357,4 +360,4 @@ ToCSSVisitor.prototype = { } }; -module.exports = ToCSSVisitor; +export default ToCSSVisitor; diff --git a/lib/less/visitors/visitor.js b/lib/less/visitors/visitor.js index e857eb283..235ce85e9 100644 --- a/lib/less/visitors/visitor.js +++ b/lib/less/visitors/visitor.js @@ -1,7 +1,6 @@ -var tree = require('../tree'); - -var _visitArgs = { visitDeeper: true }, - _hasIndexed = false; +import tree from '../tree'; +const _visitArgs = { visitDeeper: true }; +let _hasIndexed = false; function _noop(node) { return node; @@ -9,7 +8,9 @@ function _noop(node) { function indexNodeTypes(parent, ticker) { // add .typeIndex to tree node types for lookup table - var key, child; + let key; + + let child; for (key in parent) { /* eslint guard-for-in: 0 */ child = parent[key]; @@ -30,24 +31,24 @@ function indexNodeTypes(parent, ticker) { return ticker; } -var Visitor = function(implementation) { - this._implementation = implementation; - this._visitInCache = {}; - this._visitOutCache = {}; +class Visitor { + constructor(implementation) { + this._implementation = implementation; + this._visitInCache = {}; + this._visitOutCache = {}; - if (!_hasIndexed) { - indexNodeTypes(tree, 1); - _hasIndexed = true; + if (!_hasIndexed) { + indexNodeTypes(tree, 1); + _hasIndexed = true; + } } -}; -Visitor.prototype = { - visit: function(node) { + visit(node) { if (!node) { return node; } - var nodeTypeIndex = node.typeIndex; + const nodeTypeIndex = node.typeIndex; if (!nodeTypeIndex) { // MixinCall args aren't a node type? if (node.value && node.value.typeIndex) { @@ -56,24 +57,24 @@ Visitor.prototype = { return node; } - var impl = this._implementation, - func = this._visitInCache[nodeTypeIndex], - funcOut = this._visitOutCache[nodeTypeIndex], - visitArgs = _visitArgs, - fnName; + const impl = this._implementation; + let func = this._visitInCache[nodeTypeIndex]; + let funcOut = this._visitOutCache[nodeTypeIndex]; + const visitArgs = _visitArgs; + let fnName; visitArgs.visitDeeper = true; if (!func) { - fnName = 'visit' + node.type; + fnName = `visit${node.type}`; func = impl[fnName] || _noop; - funcOut = impl[fnName + 'Out'] || _noop; + funcOut = impl[`${fnName}Out`] || _noop; this._visitInCache[nodeTypeIndex] = func; this._visitOutCache[nodeTypeIndex] = funcOut; } if (func !== _noop) { - var newNode = func.call(impl, node, visitArgs); + const newNode = func.call(impl, node, visitArgs); if (node && impl.isReplacing) { node = newNode; } @@ -88,13 +89,15 @@ Visitor.prototype = { } return node; - }, - visitArray: function(nodes, nonReplacing) { + } + + visitArray(nodes, nonReplacing) { if (!nodes) { return nodes; } - var cnt = nodes.length, i; + const cnt = nodes.length; + let i; // Non-replacing if (nonReplacing || !this._implementation.isReplacing) { @@ -105,9 +108,9 @@ Visitor.prototype = { } // Replacing - var out = []; + const out = []; for (i = 0; i < cnt; i++) { - var evald = this.visit(nodes[i]); + const evald = this.visit(nodes[i]); if (evald === undefined) { continue; } if (!evald.splice) { out.push(evald); @@ -116,14 +119,19 @@ Visitor.prototype = { } } return out; - }, - flatten: function(arr, out) { + } + + flatten(arr, out) { if (!out) { out = []; } - var cnt, i, item, - nestedCnt, j, nestedItem; + let cnt; + let i; + let item; + let nestedCnt; + let j; + let nestedItem; for (i = 0, cnt = arr.length; i < cnt; i++) { item = arr[i]; @@ -150,5 +158,6 @@ Visitor.prototype = { return out; } -}; -module.exports = Visitor; +} + +export default Visitor; diff --git a/lib/lessc.js b/lib/lessc.js new file mode 100755 index 000000000..efa6cc93f --- /dev/null +++ b/lib/lessc.js @@ -0,0 +1,557 @@ +import path from 'path'; +import fs from './less-node/fs'; +import os from 'os'; +import * as utils from './less/utils'; +import * as Constants from './less/constants'; +let errno; +let mkdirp; + +try { + errno = require('errno'); +} catch (err) { + errno = null; +} + +import less from './less-node'; +const pluginManager = new less.PluginManager(less); +const fileManager = new less.FileManager(); +const plugins = []; +const queuePlugins = []; +let args = process.argv.slice(1); +let silent = false; +let verbose = false; +const options = less.options; + +options.plugins = plugins; +options.reUsePluginManager = true; + +const sourceMapOptions = {}; +let continueProcessing = true; + +// Calling process.exit does not flush stdout always. Instead of exiting the process, we set the process' exitCode, +// close all handles and wait for the event loop to exit the process. +// @see https://github.com/nodejs/node/issues/6409 +// Unfortunately, node 0.10.x does not support setting process.exitCode, so we need to call reallyExit() explicitly. +// @see https://nodejs.org/api/process.html#process_process_exitcode +// Additionally we also need to make sure that uncaughtExceptions are never swallowed. +// @see https://github.com/less/less.js/issues/2881 +// This code can safely be removed if node 0.10.x is not supported anymore. +process.on('exit', () => { process.reallyExit(process.exitCode); }); +process.on('uncaughtException', err => { + console.error(err); + process.exitCode = 1; +}); +// This code will still be required because otherwise rejected promises would not be reported to the user +process.on('unhandledRejection', err => { + console.error(err); + process.exitCode = 1; +}); + +const checkArgFunc = (arg, option) => { + if (!option) { + console.error(`${arg} option requires a parameter`); + continueProcessing = false; + process.exitCode = 1; + return false; + } + return true; +}; + +const checkBooleanArg = arg => { + const onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg); + if (!onOff) { + console.error(` unable to parse ${arg} as a boolean. use one of on/t/true/y/yes/off/f/false/n/no`); + continueProcessing = false; + process.exitCode = 1; + return false; + } + return Boolean(onOff[2]); +}; + +const parseVariableOption = (option, variables) => { + const parts = option.split('=', 2); + variables[parts[0]] = parts[1]; +}; + +let sourceMapFileInline = false; + +function printUsage() { + less.lesscHelper.printUsage(); + pluginManager.Loader.printUsage(plugins); + continueProcessing = false; +} +function render() { + + if (!continueProcessing) { + return; + } + + let input = args[1]; + if (input && input != '-') { + input = path.resolve(process.cwd(), input); + } + let output = args[2]; + const outputbase = args[2]; + if (output) { + output = path.resolve(process.cwd(), output); + } + + if (options.sourceMap) { + + sourceMapOptions.sourceMapInputFilename = input; + if (!sourceMapOptions.sourceMapFullFilename) { + if (!output && !sourceMapFileInline) { + console.error('the sourcemap option only has an optional filename if the css filename is given'); + console.error('consider adding --source-map-map-inline which embeds the sourcemap into the css'); + process.exitCode = 1; + return; + } + // its in the same directory, so always just the basename + if (output) { + sourceMapOptions.sourceMapOutputFilename = path.basename(output); + sourceMapOptions.sourceMapFullFilename = `${output}.map`; + } + // its in the same directory, so always just the basename + if ('sourceMapFullFilename' in sourceMapOptions) { + sourceMapOptions.sourceMapFilename = path.basename(sourceMapOptions.sourceMapFullFilename); + } + } else if (options.sourceMap && !sourceMapFileInline) { + const mapFilename = path.resolve(process.cwd(), sourceMapOptions.sourceMapFullFilename); + const mapDir = path.dirname(mapFilename); + const outputDir = path.dirname(output); + // find the path from the map to the output file + sourceMapOptions.sourceMapOutputFilename = path.join( + path.relative(mapDir, outputDir), path.basename(output)); + + // make the sourcemap filename point to the sourcemap relative to the css file output directory + sourceMapOptions.sourceMapFilename = path.join( + path.relative(outputDir, mapDir), path.basename(sourceMapOptions.sourceMapFullFilename)); + } + } + + if (sourceMapOptions.sourceMapBasepath === undefined) { + sourceMapOptions.sourceMapBasepath = input ? path.dirname(input) : process.cwd(); + } + + if (sourceMapOptions.sourceMapRootpath === undefined) { + const pathToMap = path.dirname((sourceMapFileInline ? output : sourceMapOptions.sourceMapFullFilename) || '.'); + const pathToInput = path.dirname(sourceMapOptions.sourceMapInputFilename || '.'); + sourceMapOptions.sourceMapRootpath = path.relative(pathToMap, pathToInput); + } + + + if (!input) { + console.error('lessc: no input files'); + console.error(''); + printUsage(); + process.exitCode = 1; + return; + } + + const ensureDirectory = filepath => { + const dir = path.dirname(filepath); + let cmd; + const existsSync = fs.existsSync || path.existsSync; + if (!existsSync(dir)) { + if (mkdirp === undefined) { + try {mkdirp = require('mkdirp');} + catch (e) { mkdirp = null; } + } + cmd = mkdirp && mkdirp.sync || fs.mkdirSync; + cmd(dir); + } + }; + + if (options.depends) { + if (!outputbase) { + console.error('option --depends requires an output path to be specified'); + process.exitCode = 1; + return; + } + process.stdout.write(`${outputbase}: `); + } + + if (!sourceMapFileInline) { + var writeSourceMap = (output = '', onDone) => { + const filename = sourceMapOptions.sourceMapFullFilename; + ensureDirectory(filename); + fs.writeFile(filename, output, 'utf8', err => { + if (err) { + let description = 'Error: '; + if (errno && errno.errno[err.errno]) { + description += errno.errno[err.errno].description; + } else { + description += `${err.code} ${err.message}`; + } + console.error(`lessc: failed to create file ${filename}`); + console.error(description); + process.exitCode = 1; + } else { + less.logger.info(`lessc: wrote ${filename}`); + } + onDone(); + }); + }; + } + + const writeSourceMapIfNeeded = (output, onDone) => { + if (options.sourceMap && !sourceMapFileInline) { + writeSourceMap(output, onDone); + } else { + onDone(); + } + }; + + const writeOutput = (output, result, onSuccess) => { + if (options.depends) { + onSuccess(); + } else if (output) { + ensureDirectory(output); + fs.writeFile(output, result.css, {encoding: 'utf8'}, err => { + if (err) { + let description = 'Error: '; + if (errno && errno.errno[err.errno]) { + description += errno.errno[err.errno].description; + } else { + description += `${err.code} ${err.message}`; + } + console.error(`lessc: failed to create file ${output}`); + console.error(description); + process.exitCode = 1; + } else { + less.logger.info(`lessc: wrote ${output}`); + onSuccess(); + } + }); + } else if (!options.depends) { + process.stdout.write(result.css); + onSuccess(); + } + }; + + const logDependencies = (options, result) => { + if (options.depends) { + let depends = ''; + for (let i = 0; i < result.imports.length; i++) { + depends += `${result.imports[i]} `; + } + console.log(depends); + } + }; + + const parseLessFile = (e, data) => { + if (e) { + console.error(`lessc: ${e.message}`); + process.exitCode = 1; + return; + } + + data = data.replace(/^\uFEFF/, ''); + + options.paths = [path.dirname(input)].concat(options.paths); + options.filename = input; + + if (options.lint) { + options.sourceMap = false; + } + sourceMapOptions.sourceMapFileInline = sourceMapFileInline; + + if (options.sourceMap) { + options.sourceMap = sourceMapOptions; + } + + less.logger.addListener({ + info: function(msg) { + if (verbose) { + console.log(msg); + } + }, + warn: function(msg) { + // do not show warning if the silent option is used + if (!silent) { + console.warn(msg); + } + }, + error: function(msg) { + console.error(msg); + } + }); + + less.render(data, options) + .then(result => { + if (!options.lint) { + writeOutput(output, result, () => { + writeSourceMapIfNeeded(result.map, () => { + logDependencies(options, result); + }); + }); + } + }, + err => { + if (!options.silent) { + console.error(err.toString({ + stylize: options.color && less.lesscHelper.stylize + })); + } + process.exitCode = 1; + }); + }; + + if (input != '-') { + fs.readFile(input, 'utf8', parseLessFile); + } else { + process.stdin.resume(); + process.stdin.setEncoding('utf8'); + + let buffer = ''; + process.stdin.on('data', data => { + buffer += data; + }); + + process.stdin.on('end', () => { + parseLessFile(false, buffer); + }); + } +} + +function processPluginQueue() { + let x = 0; + + function pluginError(name) { + console.error(`Unable to load plugin ${name} please make sure that it is installed under or at the same level as less`); + process.exitCode = 1; + } + function pluginFinished(plugin) { + x++; + plugins.push(plugin); + if (x === queuePlugins.length) { + render(); + } + } + queuePlugins.forEach(queue => { + const context = utils.clone(options); + pluginManager.Loader.loadPlugin(queue.name, process.cwd(), context, less.environment, fileManager) + .then(data => { + pluginFinished({ + fileContent: data.contents, + filename: data.filename, + options: queue.options + }); + }) + .catch(() => { + pluginError(queue.name); + }); + }); +} + +// self executing function so we can return +(() => { + args = args.filter(arg => { + let match; + + match = arg.match(/^-I(.+)$/); + if (match) { + options.paths.push(match[1]); + return false; + } + + match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i); + if (match) { + arg = match[1]; + } else { + return arg; + } + + switch (arg) { + case 'v': + case 'version': + console.log(`lessc ${less.version.join('.')} (Less Compiler) [JavaScript]`); + continueProcessing = false; + break; + case 'verbose': + verbose = true; + break; + case 's': + case 'silent': + silent = true; + break; + case 'l': + case 'lint': + options.lint = true; + break; + case 'strict-imports': + options.strictImports = true; + break; + case 'h': + case 'help': + printUsage(); + break; + case 'x': + case 'compress': + options.compress = true; + break; + case 'insecure': + options.insecure = true; + break; + case 'M': + case 'depends': + options.depends = true; + break; + case 'max-line-len': + if (checkArgFunc(arg, match[2])) { + options.maxLineLen = parseInt(match[2], 10); + if (options.maxLineLen <= 0) { + options.maxLineLen = -1; + } + } + break; + case 'no-color': + options.color = false; + break; + case 'js': + options.javascriptEnabled = true; + break; + case 'no-js': + console.error('The "--no-js" argument is deprecated, as inline JavaScript ' + + 'is disabled by default. Use "--js" to enable inline JavaScript (not recommended).'); + break; + case 'include-path': + if (checkArgFunc(arg, match[2])) { + // ; supported on windows. + // : supported on windows and linux, excluding a drive letter like C:\ so C:\file:D:\file parses to 2 + options.paths = match[2] + .split(os.type().match(/Windows/) ? /:(?!\\)|;/ : ':') + .map(p => { + if (p) { + return path.resolve(process.cwd(), p); + } + }); + } + break; + case 'line-numbers': + if (checkArgFunc(arg, match[2])) { + options.dumpLineNumbers = match[2]; + } + break; + case 'source-map': + options.sourceMap = true; + if (match[2]) { + sourceMapOptions.sourceMapFullFilename = match[2]; + } + break; + case 'source-map-rootpath': + if (checkArgFunc(arg, match[2])) { + sourceMapOptions.sourceMapRootpath = match[2]; + } + break; + case 'source-map-basepath': + if (checkArgFunc(arg, match[2])) { + sourceMapOptions.sourceMapBasepath = match[2]; + } + break; + case 'source-map-inline': + case 'source-map-map-inline': + sourceMapFileInline = true; + options.sourceMap = true; + break; + case 'source-map-include-source': + case 'source-map-less-inline': + sourceMapOptions.outputSourceFiles = true; + break; + case 'source-map-url': + if (checkArgFunc(arg, match[2])) { + sourceMapOptions.sourceMapURL = match[2]; + } + break; + case 'rp': + case 'rootpath': + if (checkArgFunc(arg, match[2])) { + options.rootpath = match[2].replace(/\\/g, '/'); + } + break; + case 'relative-urls': + console.warn('The --relative-urls option has been deprecated. Use --rewrite-urls=all.'); + options.rewriteUrls = Constants.RewriteUrls.ALL; + break; + case 'ru': + case 'rewrite-urls': + const m = match[2]; + if (m) { + if (m === 'local') { + options.rewriteUrls = Constants.RewriteUrls.LOCAL; + } else if (m === 'off') { + options.rewriteUrls = Constants.RewriteUrls.OFF; + } else if (m === 'all') { + options.rewriteUrls = Constants.RewriteUrls.ALL; + } else { + console.error(`Unknown rewrite-urls argument ${m}`); + continueProcessing = false; + process.exitCode = 1; + } + } else { + options.rewriteUrls = Constants.RewriteUrls.ALL; + } + break; + case 'sm': + case 'strict-math': + console.warn('The --strict-math option has been deprecated. Use --math=strict.'); + if (checkArgFunc(arg, match[2])) { + if (checkBooleanArg(match[2])) { + options.math = Constants.Math.STRICT_LEGACY; + } + } + break; + case 'm': + case 'math': + if (checkArgFunc(arg, match[2])) { + options.math = match[2]; + } + break; + case 'su': + case 'strict-units': + if (checkArgFunc(arg, match[2])) { + options.strictUnits = checkBooleanArg(match[2]); + } + break; + case 'global-var': + if (checkArgFunc(arg, match[2])) { + if (!options.globalVars) { + options.globalVars = {}; + } + parseVariableOption(match[2], options.globalVars); + } + break; + case 'modify-var': + if (checkArgFunc(arg, match[2])) { + if (!options.modifyVars) { + options.modifyVars = {}; + } + + parseVariableOption(match[2], options.modifyVars); + } + break; + case 'url-args': + if (checkArgFunc(arg, match[2])) { + options.urlArgs = match[2]; + } + break; + case 'plugin': + const splitupArg = match[2].match(/^([^=]+)(=(.*))?/); + const name = splitupArg[1]; + const pluginOptions = splitupArg[3]; + queuePlugins.push({ name, options: pluginOptions }); + break; + default: + queuePlugins.push({ name: arg, options: match[2], default: true }); + break; + } + }); + + if (queuePlugins.length > 0) { + processPluginQueue(); + } + else { + render(); + } + +})(); diff --git a/package.json b/package.json index 6ead4b22f..3dc3ee2b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "less", - "version": "3.9.0", + "version": "3.10.0", "description": "Leaner CSS", "homepage": "http://lesscss.org", "author": { @@ -26,15 +26,13 @@ "lessc": "./bin/lessc" }, "main": "index", + "module": "./lib/less-node/index", "directories": { "test": "./test" }, - "jam": { - "main": "./dist/less.js" - }, "browser": "./dist/less.js", "engines": { - "node": ">=4" + "node": ">=6" }, "scripts": { "test": "grunt test", @@ -51,30 +49,40 @@ "source-map": "~0.6.0" }, "devDependencies": { + "@babel/cli": "^7.5.5", + "@babel/core": "^7.5.5", + "@babel/preset-env": "^7.5.5", + "@typescript-eslint/eslint-plugin": "^1.13.0", + "@typescript-eslint/parser": "^1.13.0", "bootstrap-less-port": "0.3.0", "diff": "^3.2.0", "git-rev": "^0.2.1", - "grunt": "~0.4.5", - "grunt-browserify": "^5.0.0", - "grunt-cli": "^1.2.0", + "grunt": "^1.0.4", + "grunt-cli": "^1.3.2", "grunt-contrib-clean": "^1.0.0", - "grunt-contrib-concat": "^1.0.1", "grunt-contrib-connect": "^1.0.2", "grunt-contrib-jasmine": "^1.2.0", - "grunt-contrib-uglify": "^1.0.1", - "grunt-eslint": "^19.0.0", + "grunt-eslint": "^21.1.0", "grunt-saucelabs": "^9.0.0", "grunt-shell": "^1.3.0", "import-module": "file:test/import-module", "jit-grunt": "^0.10.0", "less-plugin-autoprefix": "^1.5.1", "less-plugin-clean-css": "^1.5.1", + "minimist": "^1.2.0", "performance-now": "^0.2.0", "phantomjs-polyfill-object-assign": "0.0.2", "phantomjs-prebuilt": "^2.1.16", "phin": "^2.2.3", "promise": "^7.1.1", + "read-glob": "^3.0.0", + "rollup": "^1.17.0", + "rollup-plugin-babel": "^4.3.3", + "rollup-plugin-commonjs": "^10.0.1", + "rollup-plugin-node-resolve": "^5.2.0", + "rollup-plugin-terser": "^5.1.1", "time-grunt": "^1.3.0", + "typescript": "^3.5.3", "uikit": "2.27.4" }, "keywords": [ diff --git a/test/browser/common.js b/test/browser/common.js index fe83fea2e..1b98fe577 100644 --- a/test/browser/common.js +++ b/test/browser/common.js @@ -143,6 +143,10 @@ testSheet = function (sheet) { expect(lessOutput).toEqual(text); done(); }); + }) + .catch(function(err) { + console.log(err); + done(); }); }); }; @@ -183,38 +187,38 @@ testErrorSheet = function (sheet) { return actualErrorElement !== null; }).then(function () { var innerText = (actualErrorElement.innerHTML - .replace(/

    |<\/?p>||<\/a>|