From 270fd097c99d9e3d4d7bcd090dd7a61197a29e40 Mon Sep 17 00:00:00 2001 From: Matthew Dean Date: Wed, 6 Jul 2016 13:26:25 -0700 Subject: [PATCH 1/2] Plugin loader set up for lessc, node, and browser --- .jscsrc | 4 +- bin/lessc | 462 ++++++++++-------- lib/less-browser/index.js | 12 +- lib/less-browser/plugin-loader.js | 57 ++- lib/less-node/index.js | 3 + lib/less-node/lessc-helper.js | 2 +- lib/less-node/plugin-loader.js | 105 ++-- .../environment/abstract-plugin-loader.js | 73 +-- lib/less/import-manager.js | 21 +- lib/less/parse.js | 27 +- lib/less/plugin-manager.js | 11 +- lib/less/transform-tree.js | 6 +- lib/less/tree/import.js | 2 +- lib/less/tree/js-eval-node.js | 2 +- test/less/errors/functions-1.less | 2 +- test/less/errors/functions-1.txt | 2 +- test/less/errors/functions-10-keyword.less | 2 +- test/less/errors/functions-10-keyword.txt | 2 +- test/less/errors/functions-11-operation.less | 2 +- test/less/errors/functions-11-operation.txt | 2 +- test/less/errors/functions-12-quoted.less | 2 +- test/less/errors/functions-12-quoted.txt | 2 +- test/less/errors/functions-13-selector.less | 2 +- test/less/errors/functions-13-selector.txt | 2 +- test/less/errors/functions-14-url.less | 2 +- test/less/errors/functions-14-url.txt | 2 +- test/less/errors/functions-15-value.less | 2 +- test/less/errors/functions-15-value.txt | 2 +- test/less/errors/functions-16-old-syntax.less | 1 - test/less/errors/functions-16-old-syntax.txt | 2 - test/less/errors/functions-2-alpha.less | 2 +- test/less/errors/functions-2-alpha.txt | 2 +- test/less/errors/functions-3-assignment.less | 2 +- test/less/errors/functions-3-assignment.txt | 2 +- test/less/errors/functions-4-call.less | 2 +- test/less/errors/functions-4-call.txt | 2 +- test/less/errors/functions-5-color.less | 2 +- test/less/errors/functions-5-color.txt | 2 +- test/less/errors/functions-6-condition.less | 2 +- test/less/errors/functions-6-condition.txt | 2 +- test/less/errors/functions-7-dimension.less | 2 +- test/less/errors/functions-7-dimension.txt | 2 +- test/less/errors/functions-8-element.less | 2 +- test/less/errors/functions-8-element.txt | 2 +- test/less/errors/functions-9-expression.less | 2 +- test/less/errors/functions-9-expression.txt | 2 +- test/less/errors/root-func-undefined-2.less | 2 +- test/less/errors/root-func-undefined-2.txt | 2 +- test/less/plugin.less | 16 +- .../plugin-global.js} | 0 .../plugin-local.js} | 0 .../plugin-transitive.js} | 0 .../plugin-transitive.less} | 2 +- .../plugin-tree-nodes.js} | 0 54 files changed, 499 insertions(+), 373 deletions(-) delete mode 100644 test/less/errors/functions-16-old-syntax.less delete mode 100644 test/less/errors/functions-16-old-syntax.txt rename test/less/{extension/extension-global.js => plugin/plugin-global.js} (100%) rename test/less/{extension/extension-local.js => plugin/plugin-local.js} (100%) rename test/less/{extension/extension-transitive.js => plugin/plugin-transitive.js} (100%) rename test/less/{extension/extension-transitive.less => plugin/plugin-transitive.less} (55%) rename test/less/{extension/extension-tree-nodes.js => plugin/plugin-tree-nodes.js} (100%) diff --git a/.jscsrc b/.jscsrc index a576705f..d0231574 100644 --- a/.jscsrc +++ b/.jscsrc @@ -1,5 +1,5 @@ { - "disallowImplicitTypeConversion": ["numeric", "boolean", "binary", "string"], + "disallowImplicitTypeConversion": ["numeric", "binary", "string"], "disallowKeywords": ["with"], "disallowMixedSpacesAndTabs": true, "disallowMultipleLineBreaks": true, @@ -14,7 +14,7 @@ "disallowSpacesInNamedFunctionExpression": { "beforeOpeningRoundBrace": true}, "disallowTrailingComma": true, - "disallowTrailingWhitespace": true, + "disallowTrailingWhitespace": false, "maximumLineLength": 160, "requireCommaBeforeLineBreak": true, "requireCurlyBraces": [ "if", diff --git a/bin/lessc b/bin/lessc index d733323c..e109ce08 100755 --- a/bin/lessc +++ b/bin/lessc @@ -14,31 +14,43 @@ try { var less = require('../lib/less-node'), pluginLoader = new less.PluginLoader(less), - plugin, - plugins = []; - -var args = process.argv.slice(1); -var silent = false, + plugins = [], + queuePlugins = [], + args = process.argv.slice(1), + silent = false, verbose = false, options = { - depends: false, - compress: false, - max_line_len: -1, - lint: false, - paths: [], - color: true, - strictImports: false, - insecure: false, - rootpath: '', - relativeUrls: false, - ieCompat: true, - strictMath: false, - strictUnits: false, - globalVars: null, - modifyVars: null, - urlArgs: '', - plugins: plugins -}; + depends: false, + compress: false, + max_line_len: -1, + lint: false, + paths: [], + color: true, + strictImports: false, + insecure: false, + rootpath: '', + relativeUrls: false, + ieCompat: true, + strictMath: false, + strictUnits: false, + globalVars: null, + modifyVars: null, + urlArgs: '', + plugins: plugins + }; + +if (less.options) { + for (var i = 0, keys = Object.keys(options); i < keys.length; i++) { + if (!less.options[keys[i]]) { + less.options[keys[i]] = options[keys[i]]; + } + } + options = less.options; +} +else { + less.options = options; +} + var sourceMapOptions = {}; var continueProcessing = true; @@ -94,194 +106,7 @@ function printUsage() { pluginLoader.printUsage(plugins); continueProcessing = false; } - -// self executing function so we can return -(function() { - args = args.filter(function (arg) { - var 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 'no-ie-compat': - options.ieCompat = false; - break; - case 'no-js': - options.javascriptEnabled = false; - 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-map-inline': - sourceMapFileInline = true; - options.sourceMap = true; - break; - 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 "ru": - case "relative-urls": - options.relativeUrls = true; - break; - case "sm": - case "strict-math": - if (checkArgFunc(arg, match[2])) { - options.strictMath = checkBooleanArg(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': - var splitupArg = match[2].match(/^([^=]+)(=(.*))?/), - name = splitupArg[1], - pluginOptions = splitupArg[3]; - - plugin = pluginLoader.tryLoadPlugin(name, pluginOptions); - if (plugin) { - plugins.push(plugin); - } else { - 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; - } - break; - default: - plugin = pluginLoader.tryLoadPlugin("less-plugin-" + arg, match[2]); - if (plugin) { - plugins.push(plugin); - } else { - console.error("Unable to interpret argument " + arg + - " - if it is a plugin (less-plugin-" + arg + "), make sure that it is installed under or at" + - " the same level as less"); - process.exitCode = 1; - } - break; - } - }); +function render() { if (!continueProcessing) { return; @@ -505,4 +330,219 @@ function printUsage() { parseLessFile(false, buffer); }); } +} + +function processPluginQueue() { + var 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(function(queue) { + pluginLoader.tryLoadPlugin(queue.name, function(err, data) { + if (err) { + pluginError(queue.name); + } + else { + pluginFinished({ + fileContent: data.contents, + filename: data.filename, + options: queue.options + }); + } + }); + }); +} + +// self executing function so we can return +(function() { + args = args.filter(function (arg) { + var 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 'no-ie-compat': + options.ieCompat = false; + break; + case 'inline-js': + options.javascriptEnabled = true; + break; + case 'no-js': + console.error('The "--no-js" argument is deprecated. Use "--inline-js" to enable inline JavaScript.'); + 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-map-inline': + sourceMapFileInline = true; + options.sourceMap = true; + break; + 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 "ru": + case "relative-urls": + options.relativeUrls = true; + break; + case "sm": + case "strict-math": + if (checkArgFunc(arg, match[2])) { + options.strictMath = checkBooleanArg(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': + 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; + } + }); + + if (queuePlugins.length > 0) { + processPluginQueue(); + } + else { + render(); + } + })(); diff --git a/lib/less-browser/index.js b/lib/less-browser/index.js index 6a1fbf49..c8967125 100644 --- a/lib/less-browser/index.js +++ b/lib/less-browser/index.js @@ -9,7 +9,7 @@ module.exports = function(window, options) { var document = window.document; var less = require('../less')(); - //module.exports = less; + options.javascriptEnabled = !!(options.javascriptEnabled || options.inlineJavaScript); less.options = options; var environment = less.environment, FileManager = require("./file-manager")(options, less.logger), @@ -23,20 +23,13 @@ module.exports = function(window, options) { var cache = less.cache = options.cache || require("./cache")(window, options, less.logger); require('./image-size')(less.environment); - //Setup user functions + //Setup user functions - Deprecate? if (options.functions) { less.functions.functionRegistry.addMultiple(options.functions); } var typePattern = /^text\/(x-)?less$/; - function postProcessCSS(styles) { // deprecated, use a plugin for postprocesstasks - if (options.postProcessor && typeof options.postProcessor === 'function') { - styles = options.postProcessor.call(styles, styles) || styles; - } - return styles; - } - function clone(obj) { var cloned = {}; for (var prop in obj) { @@ -133,7 +126,6 @@ module.exports = function(window, options) { e.href = path; callback(e); } else { - result.css = postProcessCSS(result.css); cache.setCSS(sheet.href, webInfo.lastModified, instanceOptions.modifyVars, result.css); callback(null, result.css, data, sheet, webInfo, path); } diff --git a/lib/less-browser/plugin-loader.js b/lib/less-browser/plugin-loader.js index e80828de..9331f088 100644 --- a/lib/less-browser/plugin-loader.js +++ b/lib/less-browser/plugin-loader.js @@ -11,24 +11,49 @@ var PluginLoader = function(less) { PluginLoader.prototype = new AbstractPluginLoader(); -PluginLoader.prototype.tryLoadFromEnvironment = function(filename, basePath, callback) { - - if(basePath && !filename) { - filename = path.join(basePath, name); - } - if(filename) { - var fileManager = new this.less.FileManager(); - - filename = fileManager.tryAppendExtension(filename,'.js'); - fileManager.loadFile(filename).then( - function(data) { +PluginLoader.prototype.tryLoadPlugin = function(name, argument, basePath, callback) { + var self = this; + var prefix = name.slice(0, 1); + var explicit = prefix === "." || prefix === "/" || name.slice(-3).toLowerCase() === ".js"; + this.tryLoadFromEnvironment(name, basePath, explicit, function(err, data) { + if (explicit) { + callback(err, data); + } + else { + if (!err) { callback(null, data); - }, - - function(err) { - callback(err); } - ); + else { + self.tryLoadFromEnvironment('less-plugin-' + name, basePath, explicit, function(err2, data) { + callback(err, data); + }); + } + } + }); + +}; + +PluginLoader.prototype.tryLoadFromEnvironment = function(filename, basePath, explicit, callback) { + var fileManager; + + if (basePath) { + filename = path.join(basePath, filename); + } + + if (filename) { + fileManager = new this.less.FileManager(); + + filename = fileManager.tryAppendExtension(filename, '.js'); + + var done = function(err, data) { + if (err) { + callback(err); + } else { + callback(null, data); + } + }; + fileManager.loadFile(filename, null, null, null, done); + } else { callback({ message: 'Plugin could not be found.'}); diff --git a/lib/less-node/index.js b/lib/less-node/index.js index 9baaf824..55da4b22 100644 --- a/lib/less-node/index.js +++ b/lib/less-node/index.js @@ -12,6 +12,9 @@ less.PluginLoader = require("./plugin-loader"); less.fs = require("./fs"); less.FileManager = FileManager; less.UrlFileManager = UrlFileManager; +less.options = less.options || {}; +less.options.javascriptEnabled = false; + less.formatError = function(ctx, options) { options = options || {}; diff --git a/lib/less-node/lessc-helper.js b/lib/less-node/lessc-helper.js index 7b57ce29..3aa84c99 100644 --- a/lib/less-node/lessc-helper.js +++ b/lib/less-node/lessc-helper.js @@ -31,7 +31,7 @@ var lessc_helper = { console.log(" -M, --depends Outputs a makefile import dependency list to stdout."); console.log(" --no-color Disables colorized output."); console.log(" --no-ie-compat Disables IE compatibility checks."); - console.log(" --no-js Disables JavaScript in less files"); + console.log(" --inline-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."); diff --git a/lib/less-node/plugin-loader.js b/lib/less-node/plugin-loader.js index 90dd17ba..8eaa19ae 100644 --- a/lib/less-node/plugin-loader.js +++ b/lib/less-node/plugin-loader.js @@ -11,54 +11,49 @@ var PluginLoader = function(less) { prefix = path.dirname(prefix); return function(id) { var str = id.substr(0, 2); - if(str === '..' || str === './') { + if (str === '..' || str === './') { return require(path.join(prefix, id)); } else { return require(id); } - } + }; }; }; PluginLoader.prototype = new AbstractPluginLoader(); -PluginLoader.prototype.tryLoadFromEnvironment = function(name, basePath, callback) { +PluginLoader.prototype.tryLoadPlugin = function(name, basePath, callback) { + var self = this; + var prefix = name.slice(0, 1); + var explicit = prefix === "." || prefix === "/" || name.slice(-3).toLowerCase() === ".js"; + if (explicit) { + this.tryLoadFromEnvironment(name, basePath, explicit, callback); + } + else { + this.tryLoadFromEnvironment('less-plugin-' + name, basePath, explicit, function(err, data) { + if (!err) { + callback(null, data); + } + else { + self.tryLoadFromEnvironment(name, basePath, explicit, function(err2, data2) { + callback(err2, data2); + }); + } + }); + } + +}; + +PluginLoader.prototype.tryLoadFromEnvironment = function(name, basePath, explicit, callback) { var filename; var self = this; - try { - filename = require.resolve(path.join("../../../", name)); - } - catch(e) { - } - // is installed as a sub dependency of the current folder - try { - filename = require.resolve(path.join(process.cwd(), "node_modules", name)); - } - catch(e) { - } - // is referenced relative to the current directory - try { - filename = require.resolve(path.join(process.cwd(), name)); - } - catch(e) { - } - // unlikely - would have to be a dependency of where this code was running (less.js)... - if (name[0] !== '.') { - try { - filename = require.resolve(name); - } - catch(e) { - } - } - if(basePath && !filename) { - filename = path.join(basePath, name); - } - if(filename) { - var fileManager = new this.less.FileManager(); + function getFile(filename) { - filename = fileManager.tryAppendExtension(filename,'.js'); + var fileManager = new self.less.FileManager(); + + filename = fileManager.tryAppendExtension(filename, '.js'); fileManager.loadFile(filename).then( function(data) { try { @@ -75,8 +70,48 @@ PluginLoader.prototype.tryLoadFromEnvironment = function(name, basePath, callbac } ); } + if (explicit) { + if (basePath) { + filename = path.join(basePath, name); + } + getFile(filename); + } else { - callback({ message: 'Plugin could not be found.'}); + // Search node_modules for a possible plugin name match + try { + filename = require.resolve(path.join("../../../", name)); + } + catch(e) { + } + // is installed as a sub dependency of the current folder + try { + filename = require.resolve(path.join(process.cwd(), "node_modules", name)); + } + catch(e) { + } + // is referenced relative to the current directory + try { + filename = require.resolve(path.join(process.cwd(), name)); + } + catch(e) { + } + // unlikely - would have to be a dependency of where this code was running (less.js)... + if (name[0] !== '.') { + try { + filename = require.resolve(name); + } + catch(e) { + } + } + if (basePath && !filename) { + filename = path.join(basePath, name); + } + if (filename) { + getFile(filename); + } + else { + callback({ message: 'Plugin could not be found.'}); + } } }; diff --git a/lib/less/environment/abstract-plugin-loader.js b/lib/less/environment/abstract-plugin-loader.js index 55858cb5..3f14be18 100644 --- a/lib/less/environment/abstract-plugin-loader.js +++ b/lib/less/environment/abstract-plugin-loader.js @@ -1,4 +1,6 @@ -var functionRegistry = require("../functions/function-registry"); +var functionRegistry = require("../functions/function-registry"), + LessError = require('../less-error'); + var AbstractPluginLoader = function() { }; @@ -10,26 +12,39 @@ function error(msg, type) { } ); } -AbstractPluginLoader.prototype.evalPlugin = function(contents, context, fileInfo, callback) { +AbstractPluginLoader.prototype.evalPlugin = function(contents, context, pluginOptions, fileInfo) { var loader, registry, pluginObj, localModule, - localExports; + localExports, + pluginManager, + filename; + pluginManager = context.pluginManager; - pluginObj = context.pluginManager.get(fileInfo.filename); - - if(pluginObj) { - if(pluginObj.use) { - pluginObj.use(this.less); + if (fileInfo) { + if (typeof fileInfo === "string") { + filename = fileInfo; + } + else { + filename = fileInfo.filename; } - return callback(null, pluginObj); } - localModule = { + if (filename) { + pluginObj = pluginManager.get(filename); + + if (pluginObj) { + if (pluginObj.use) { + pluginObj.use(this.less); + } + return pluginObj; + } + } + localModule = { exports: {}, - pluginManager: context.pluginManager, + pluginManager: pluginManager, fileInfo: fileInfo }; localExports = localModule.exports; @@ -39,18 +54,18 @@ AbstractPluginLoader.prototype.evalPlugin = function(contents, context, fileInfo loader = new Function("module", "require", "functions", "tree", "fileInfo", "less", contents); pluginObj = loader(localModule, this.require, registry, this.less.tree, fileInfo, this.less); - if(!pluginObj) { + if (!pluginObj) { pluginObj = localModule.exports; } - pluginObj = this.validatePlugin(pluginObj); - if(pluginObj) { + pluginObj = this.validatePlugin(pluginObj, filename, pluginOptions); + if (pluginObj) { // Run on first load - context.pluginManager.addPlugin(pluginObj, fileInfo.filename); + pluginManager.addPlugin(pluginObj, fileInfo.filename); pluginObj.functions = registry.getLocalFunctions(); // Run every @plugin call - if(pluginObj.use) { + if (pluginObj.use) { pluginObj.use(this.less); } } @@ -61,49 +76,39 @@ AbstractPluginLoader.prototype.evalPlugin = function(contents, context, fileInfo } catch(e) { // TODO pass the error console.log(e.stack.toString()); - callback(new this.less.LessError({ + return new this.less.LessError({ message: "Plugin evaluation error: '" + e.name + ': ' + e.message.replace(/["]/g, "'") + "'" , - filename: this.fileInfo.filename, + filename: filename, line: this.line, col: this.column - }), null ); + }); } - callback(null, pluginObj); + return pluginObj; }; -AbstractPluginLoader.prototype.tryLoadPlugin = function(name, argument, basePath, callback) { - var self = this; - this.tryLoadFromEnvironment(name, basePath, function(err, data) { - if(!err) { - callback(null, data); - } - else { - self.tryLoadFromEnvironment('less-plugin-' + name, basePath, callback); - } - }); -}; -AbstractPluginLoader.prototype.validatePlugin = function(plugin, argument) { +AbstractPluginLoader.prototype.validatePlugin = function(plugin, filename, options) { if (plugin) { // support plugins being a function // so that the plugin can be more usable programmatically if (typeof plugin === "function") { plugin = new plugin(); } + var name = require('path').basename(filename); if (plugin.minVersion) { if (this.compareVersion(plugin.minVersion, this.less.version) < 0) { error("plugin " + name + " requires version " + this.versionToString(plugin.minVersion)); return null; } } - if (argument) { + if (options) { if (!plugin.setOptions) { error("options have been provided but the plugin " + name + "does not support any options"); return null; } try { - plugin.setOptions(argument); + plugin.setOptions(options); } catch(e) { error("Error setting options on plugin " + name + '\n' + e.message); diff --git a/lib/less/import-manager.js b/lib/less/import-manager.js index 05ad8f00..7ef6171c 100644 --- a/lib/less/import-manager.js +++ b/lib/less/import-manager.js @@ -1,5 +1,6 @@ var contexts = require("./contexts"), - Parser = require('./parser/parser'); + Parser = require('./parser/parser'), + LessError = require('./less-error'); module.exports = function(environment) { @@ -35,7 +36,7 @@ module.exports = function(environment) { */ ImportManager.prototype.push = function (path, tryAppendExtension, currentFileInfo, importOptions, callback) { var importManager = this, - pluginLoader = new this.less.PluginLoader(this.less); + pluginLoader = this.context.pluginManager.Loader; this.queue.push(path); @@ -72,7 +73,8 @@ module.exports = function(environment) { } var loadFileCallback = function(loadedFile) { - var resolvedFilename = loadedFile.filename, + var plugin, + resolvedFilename = loadedFile.filename, contents = loadedFile.contents.replace(/^\uFEFF/, ''); // Pass on an updated rootpath if path of imported file is relative and file @@ -105,9 +107,14 @@ module.exports = function(environment) { } if (importOptions.isPlugin) { - pluginLoader.evalPlugin(contents, newEnv, newFileInfo, function (e, root) { - fileParsedFunc(e, root, resolvedFilename); - }); + + plugin = pluginLoader.evalPlugin(contents, newEnv, importOptions, newFileInfo); + if (plugin instanceof LessError) { + fileParsedFunc(plugin, null, resolvedFilename); + } + else { + fileParsedFunc(null, plugin, resolvedFilename); + } } else if (importOptions.inline) { fileParsedFunc(null, contents, resolvedFilename); } else { @@ -124,7 +131,7 @@ module.exports = function(environment) { loadFileCallback(loadedFile); } }; - if(importOptions.isPlugin) { + if (importOptions.isPlugin) { // TODO: implement options for plugins try { pluginLoader.tryLoadPlugin(path, null, currentFileInfo.currentDirectory, done); diff --git a/lib/less/parse.js b/lib/less/parse.js index a6048aa0..5dbad10e 100644 --- a/lib/less/parse.js +++ b/lib/less/parse.js @@ -1,7 +1,8 @@ var PromiseConstructor, contexts = require("./contexts"), Parser = require('./parser/parser'), - PluginManager = require('./plugin-manager'); + PluginManager = require('./plugin-manager'), + LessError = require('./less-error'); module.exports = function(environment, ParseTree, ImportManager) { var parse = function (input, options, callback) { @@ -29,10 +30,8 @@ module.exports = function(environment, ParseTree, ImportManager) { } else { var context, rootFileInfo, - less = this, pluginManager = new PluginManager(this, true); - pluginManager.addPlugins(options.plugins); options.pluginManager = pluginManager; context = new contexts.Parse(options); @@ -57,7 +56,27 @@ module.exports = function(environment, ParseTree, ImportManager) { } var imports = new ImportManager(this, context, rootFileInfo); - + + 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, plugin.options, plugin.filename); + if (!(evalResult instanceof LessError)) { + pluginManager.addPlugin(plugin); + } + else { + return callback(evalResult); + } + + } + else { + pluginManager.addPlugin(plugin); + } + }); + } + new Parser(context, imports, rootFileInfo) .parse(input, function (e, root) { if (e) { return callback(e); } diff --git a/lib/less/plugin-manager.js b/lib/less/plugin-manager.js index 54e65654..736930fc 100644 --- a/lib/less/plugin-manager.js +++ b/lib/less/plugin-manager.js @@ -10,6 +10,7 @@ var PluginManager = function(less) { this.fileManagers = []; this.iterator = -1; this.pluginCache = {}; + this.Loader = new less.PluginLoader(less); }; var pm, PluginManagerFactory = function(less, newFactory) { @@ -37,8 +38,10 @@ PluginManager.prototype.addPlugins = function(plugins) { */ PluginManager.prototype.addPlugin = function(plugin, filename) { this.installedPlugins.push(plugin); - this.pluginCache[filename] = plugin; - if(plugin.install) { + if (filename) { + this.pluginCache[filename] = plugin; + } + if (plugin.install) { plugin.install(this.less, this); } }; @@ -133,10 +136,10 @@ PluginManager.prototype.visitor = function() { return self.visitors[self.iterator]; }, get: function() { - self.iterator+=1; + self.iterator += 1; return self.visitors[self.iterator]; } - } + }; }; /** * diff --git a/lib/less/transform-tree.js b/lib/less/transform-tree.js index 94110274..f1fc37c2 100644 --- a/lib/less/transform-tree.js +++ b/lib/less/transform-tree.js @@ -47,8 +47,8 @@ module.exports = function(root, options) { if (options.pluginManager) { visitorIterator = options.pluginManager.visitor(); visitorIterator.first(); - while(v = visitorIterator.get()) { - if(v.isPreEvalVisitor) { + while ((v = visitorIterator.get())) { + if (v.isPreEvalVisitor) { v.run(root); } } @@ -62,7 +62,7 @@ module.exports = function(root, options) { if (options.pluginManager) { visitorIterator.first(); - while(v = visitorIterator.get()) { + while ((v = visitorIterator.get())) { v.run(root); } } diff --git a/lib/less/tree/import.js b/lib/less/tree/import.js index 10385141..eeb280e1 100644 --- a/lib/less/tree/import.js +++ b/lib/less/tree/import.js @@ -127,7 +127,7 @@ Import.prototype.doEval = function (context) { features = this.features && this.features.eval(context); if (this.options.isPlugin) { - if(this.root && this.root.setContext) { + if (this.root && this.root.setContext) { this.root.setContext(context); } registry = context.frames[0] && context.frames[0].functionRegistry; diff --git a/lib/less/tree/js-eval-node.js b/lib/less/tree/js-eval-node.js index 30fbbfae..3b37378e 100644 --- a/lib/less/tree/js-eval-node.js +++ b/lib/less/tree/js-eval-node.js @@ -11,7 +11,7 @@ JsEvalNode.prototype.evaluateJavaScript = function (expression, context) { evalContext = {}; if (context.javascriptEnabled !== undefined && !context.javascriptEnabled) { - throw { message: "You are using JavaScript, which has been disabled.", + throw { message: "Inline JavaScript is not enabled. Is it set in your options?", filename: this.currentFileInfo.filename, index: this.index }; } diff --git a/test/less/errors/functions-1.less b/test/less/errors/functions-1.less index 942be1d0..f502aa27 100644 --- a/test/less/errors/functions-1.less +++ b/test/less/errors/functions-1.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-undefined(); \ No newline at end of file diff --git a/test/less/errors/functions-1.txt b/test/less/errors/functions-1.txt index 61227a2b..abeb4bda 100644 --- a/test/less/errors/functions-1.txt +++ b/test/less/errors/functions-1.txt @@ -1,3 +1,3 @@ SyntaxError: Function 'test-undefined' is undefined in {path}functions-1.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-undefined(); diff --git a/test/less/errors/functions-10-keyword.less b/test/less/errors/functions-10-keyword.less index e85a35e1..16d0b985 100644 --- a/test/less/errors/functions-10-keyword.less +++ b/test/less/errors/functions-10-keyword.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-keyword(); \ No newline at end of file diff --git a/test/less/errors/functions-10-keyword.txt b/test/less/errors/functions-10-keyword.txt index efadbeb0..dabe839d 100644 --- a/test/less/errors/functions-10-keyword.txt +++ b/test/less/errors/functions-10-keyword.txt @@ -1,3 +1,3 @@ SyntaxError: Keyword node returned by a function is not valid here in {path}functions-10-keyword.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-keyword(); diff --git a/test/less/errors/functions-11-operation.less b/test/less/errors/functions-11-operation.less index e370c54a..5695bdb9 100644 --- a/test/less/errors/functions-11-operation.less +++ b/test/less/errors/functions-11-operation.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-operation(); \ No newline at end of file diff --git a/test/less/errors/functions-11-operation.txt b/test/less/errors/functions-11-operation.txt index c8cba0cb..27287179 100644 --- a/test/less/errors/functions-11-operation.txt +++ b/test/less/errors/functions-11-operation.txt @@ -1,3 +1,3 @@ SyntaxError: Operation node returned by a function is not valid here in {path}functions-11-operation.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-operation(); diff --git a/test/less/errors/functions-12-quoted.less b/test/less/errors/functions-12-quoted.less index 8ea74bb3..d35be871 100644 --- a/test/less/errors/functions-12-quoted.less +++ b/test/less/errors/functions-12-quoted.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-quoted(); \ No newline at end of file diff --git a/test/less/errors/functions-12-quoted.txt b/test/less/errors/functions-12-quoted.txt index 6be7951a..45c62ea6 100644 --- a/test/less/errors/functions-12-quoted.txt +++ b/test/less/errors/functions-12-quoted.txt @@ -1,3 +1,3 @@ SyntaxError: Quoted node returned by a function is not valid here in {path}functions-12-quoted.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-quoted(); diff --git a/test/less/errors/functions-13-selector.less b/test/less/errors/functions-13-selector.less index b830054b..2fd879c6 100644 --- a/test/less/errors/functions-13-selector.less +++ b/test/less/errors/functions-13-selector.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-selector(); \ No newline at end of file diff --git a/test/less/errors/functions-13-selector.txt b/test/less/errors/functions-13-selector.txt index 987868b6..2f4b097f 100644 --- a/test/less/errors/functions-13-selector.txt +++ b/test/less/errors/functions-13-selector.txt @@ -1,3 +1,3 @@ SyntaxError: Selector node returned by a function is not valid here in {path}functions-13-selector.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-selector(); diff --git a/test/less/errors/functions-14-url.less b/test/less/errors/functions-14-url.less index b40af7dd..bed6dabf 100644 --- a/test/less/errors/functions-14-url.less +++ b/test/less/errors/functions-14-url.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-url(); \ No newline at end of file diff --git a/test/less/errors/functions-14-url.txt b/test/less/errors/functions-14-url.txt index 11283de0..aeb275ca 100644 --- a/test/less/errors/functions-14-url.txt +++ b/test/less/errors/functions-14-url.txt @@ -1,3 +1,3 @@ SyntaxError: Url node returned by a function is not valid here in {path}functions-14-url.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-url(); diff --git a/test/less/errors/functions-15-value.less b/test/less/errors/functions-15-value.less index 6ec4a1ec..189ce196 100644 --- a/test/less/errors/functions-15-value.less +++ b/test/less/errors/functions-15-value.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-value(); \ No newline at end of file diff --git a/test/less/errors/functions-15-value.txt b/test/less/errors/functions-15-value.txt index 8dee3692..41f6e6a1 100644 --- a/test/less/errors/functions-15-value.txt +++ b/test/less/errors/functions-15-value.txt @@ -1,3 +1,3 @@ SyntaxError: Value node returned by a function is not valid here in {path}functions-15-value.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-value(); diff --git a/test/less/errors/functions-16-old-syntax.less b/test/less/errors/functions-16-old-syntax.less deleted file mode 100644 index 2d05b37e..00000000 --- a/test/less/errors/functions-16-old-syntax.less +++ /dev/null @@ -1 +0,0 @@ -@plugin "../extension/extension-tree-nodes"; \ No newline at end of file diff --git a/test/less/errors/functions-16-old-syntax.txt b/test/less/errors/functions-16-old-syntax.txt deleted file mode 100644 index d548c82b..00000000 --- a/test/less/errors/functions-16-old-syntax.txt +++ /dev/null @@ -1,2 +0,0 @@ -SyntaxError: @plugin is deprecated. Use @use in {path}functions-16-old-syntax.less on line 1, column 1: -1 @plugin "../extension/extension-tree-nodes"; diff --git a/test/less/errors/functions-2-alpha.less b/test/less/errors/functions-2-alpha.less index 5f4271da..f00da078 100644 --- a/test/less/errors/functions-2-alpha.less +++ b/test/less/errors/functions-2-alpha.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-alpha(); \ No newline at end of file diff --git a/test/less/errors/functions-2-alpha.txt b/test/less/errors/functions-2-alpha.txt index 3e093511..38a17273 100644 --- a/test/less/errors/functions-2-alpha.txt +++ b/test/less/errors/functions-2-alpha.txt @@ -1,3 +1,3 @@ SyntaxError: Alpha node returned by a function is not valid here in {path}functions-2-alpha.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-alpha(); diff --git a/test/less/errors/functions-3-assignment.less b/test/less/errors/functions-3-assignment.less index b65dfc48..fe7f5ade 100644 --- a/test/less/errors/functions-3-assignment.less +++ b/test/less/errors/functions-3-assignment.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-assignment(); \ No newline at end of file diff --git a/test/less/errors/functions-3-assignment.txt b/test/less/errors/functions-3-assignment.txt index eb1c6591..35c19926 100644 --- a/test/less/errors/functions-3-assignment.txt +++ b/test/less/errors/functions-3-assignment.txt @@ -1,3 +1,3 @@ SyntaxError: Assignment node returned by a function is not valid here in {path}functions-3-assignment.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-assignment(); diff --git a/test/less/errors/functions-4-call.less b/test/less/errors/functions-4-call.less index 071b8e6e..6b55c88a 100644 --- a/test/less/errors/functions-4-call.less +++ b/test/less/errors/functions-4-call.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-call(); \ No newline at end of file diff --git a/test/less/errors/functions-4-call.txt b/test/less/errors/functions-4-call.txt index 56157ba9..338582d7 100644 --- a/test/less/errors/functions-4-call.txt +++ b/test/less/errors/functions-4-call.txt @@ -1,3 +1,3 @@ SyntaxError: Function 'foo' is undefined in {path}functions-4-call.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-call(); diff --git a/test/less/errors/functions-5-color.less b/test/less/errors/functions-5-color.less index 16789a42..700ec5b9 100644 --- a/test/less/errors/functions-5-color.less +++ b/test/less/errors/functions-5-color.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-color(); \ No newline at end of file diff --git a/test/less/errors/functions-5-color.txt b/test/less/errors/functions-5-color.txt index 74beb776..fdcd1a08 100644 --- a/test/less/errors/functions-5-color.txt +++ b/test/less/errors/functions-5-color.txt @@ -1,3 +1,3 @@ SyntaxError: Color node returned by a function is not valid here in {path}functions-5-color.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-color(); diff --git a/test/less/errors/functions-6-condition.less b/test/less/errors/functions-6-condition.less index 660eba1c..db1000b8 100644 --- a/test/less/errors/functions-6-condition.less +++ b/test/less/errors/functions-6-condition.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-condition(); \ No newline at end of file diff --git a/test/less/errors/functions-6-condition.txt b/test/less/errors/functions-6-condition.txt index b169714a..421bba5f 100644 --- a/test/less/errors/functions-6-condition.txt +++ b/test/less/errors/functions-6-condition.txt @@ -1,3 +1,3 @@ SyntaxError: Condition node returned by a function is not valid here in {path}functions-6-condition.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-condition(); diff --git a/test/less/errors/functions-7-dimension.less b/test/less/errors/functions-7-dimension.less index f788151d..c399d33e 100644 --- a/test/less/errors/functions-7-dimension.less +++ b/test/less/errors/functions-7-dimension.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-dimension(); \ No newline at end of file diff --git a/test/less/errors/functions-7-dimension.txt b/test/less/errors/functions-7-dimension.txt index 6e7c584f..3b1b7026 100644 --- a/test/less/errors/functions-7-dimension.txt +++ b/test/less/errors/functions-7-dimension.txt @@ -1,3 +1,3 @@ SyntaxError: Dimension node returned by a function is not valid here in {path}functions-7-dimension.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-dimension(); diff --git a/test/less/errors/functions-8-element.less b/test/less/errors/functions-8-element.less index 16c9d393..c762aad8 100644 --- a/test/less/errors/functions-8-element.less +++ b/test/less/errors/functions-8-element.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-element(); \ No newline at end of file diff --git a/test/less/errors/functions-8-element.txt b/test/less/errors/functions-8-element.txt index c38a2bf8..b505d954 100644 --- a/test/less/errors/functions-8-element.txt +++ b/test/less/errors/functions-8-element.txt @@ -1,3 +1,3 @@ SyntaxError: Element node returned by a function is not valid here in {path}functions-8-element.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-element(); diff --git a/test/less/errors/functions-9-expression.less b/test/less/errors/functions-9-expression.less index da66c89e..5f0bf46c 100644 --- a/test/less/errors/functions-9-expression.less +++ b/test/less/errors/functions-9-expression.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes"; +@plugin "../plugin/plugin-tree-nodes"; test-expression(); \ No newline at end of file diff --git a/test/less/errors/functions-9-expression.txt b/test/less/errors/functions-9-expression.txt index d7d7d2c4..224db785 100644 --- a/test/less/errors/functions-9-expression.txt +++ b/test/less/errors/functions-9-expression.txt @@ -1,3 +1,3 @@ SyntaxError: Expression node returned by a function is not valid here in {path}functions-9-expression.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes"; +1 @plugin "../plugin/plugin-tree-nodes"; 2 test-expression(); diff --git a/test/less/errors/root-func-undefined-2.less b/test/less/errors/root-func-undefined-2.less index eb934f7c..ee34616e 100644 --- a/test/less/errors/root-func-undefined-2.less +++ b/test/less/errors/root-func-undefined-2.less @@ -1,2 +1,2 @@ -@use "../extension/extension-tree-nodes.js"; +@plugin "../plugin/plugin-tree-nodes.js"; test-undefined(); \ No newline at end of file diff --git a/test/less/errors/root-func-undefined-2.txt b/test/less/errors/root-func-undefined-2.txt index fb7a39f6..031385d0 100644 --- a/test/less/errors/root-func-undefined-2.txt +++ b/test/less/errors/root-func-undefined-2.txt @@ -1,3 +1,3 @@ SyntaxError: Function 'test-undefined' is undefined in {path}root-func-undefined-2.less on line 2, column 1: -1 @use "../extension/extension-tree-nodes.js"; +1 @plugin "../plugin/plugin-tree-nodes.js"; 2 test-undefined(); diff --git a/test/less/plugin.less b/test/less/plugin.less index b7caa99e..66775ea9 100644 --- a/test/less/plugin.less +++ b/test/less/plugin.less @@ -1,8 +1,8 @@ // importing plugin globally -@use "./extension/extension-global"; +@plugin "./plugin/plugin-global"; // transitively include plugins from importing another sheet -@import "./extension/extension-transitive"; +@import "./plugin/plugin-transitive"; // `test-global` function should be reachable @@ -18,7 +18,7 @@ // `test-local` function should be reachable // `test-shadow` function should return local version, shadowing global version .local { - @use "./extension/extension-local"; + @plugin "./plugin/plugin-local"; global : test-global(); local : test-local(); shadow : test-shadow(); @@ -28,19 +28,19 @@ // calling a mixin or detached ruleset should not bubble local plugins // imported inside either into the parent scope. .mixin() { - @use "./extension/extension-local"; + @plugin "./plugin/plugin-local"; mixin-local : test-local(); mixin-global : test-global(); mixin-shadow : test-shadow(); } @ruleset : { - @use "./extension/extension-local"; + @plugin "./plugin/plugin-local"; ruleset-local : test-local(); ruleset-global : test-global(); ruleset-shadow : test-shadow(); }; #ns { - @use "./extension/extension-local"; + @plugin "./plugin/plugin-local"; .mixin() { ns-mixin-global : test-global(); ns-mixin-local : test-local(); @@ -76,12 +76,12 @@ .test { @media screen { - @use "./extension/extension-local"; + @plugin "./plugin/plugin-local"; result : test-local(); } } -@use "./extension/extension-tree-nodes"; +@plugin "./plugin/plugin-tree-nodes"; @ruleset2: test-detached-ruleset(); .root { @ruleset2(); diff --git a/test/less/extension/extension-global.js b/test/less/plugin/plugin-global.js similarity index 100% rename from test/less/extension/extension-global.js rename to test/less/plugin/plugin-global.js diff --git a/test/less/extension/extension-local.js b/test/less/plugin/plugin-local.js similarity index 100% rename from test/less/extension/extension-local.js rename to test/less/plugin/plugin-local.js diff --git a/test/less/extension/extension-transitive.js b/test/less/plugin/plugin-transitive.js similarity index 100% rename from test/less/extension/extension-transitive.js rename to test/less/plugin/plugin-transitive.js diff --git a/test/less/extension/extension-transitive.less b/test/less/plugin/plugin-transitive.less similarity index 55% rename from test/less/extension/extension-transitive.less rename to test/less/plugin/plugin-transitive.less index e3268f82..a0c20283 100644 --- a/test/less/extension/extension-transitive.less +++ b/test/less/plugin/plugin-transitive.less @@ -1,4 +1,4 @@ -@use "extension-transitive"; +@plugin "extension-transitive"; .other { trans : test-transitive(); diff --git a/test/less/extension/extension-tree-nodes.js b/test/less/plugin/plugin-tree-nodes.js similarity index 100% rename from test/less/extension/extension-tree-nodes.js rename to test/less/plugin/plugin-tree-nodes.js From ad57737ce0c7192ac734541294620679629038be Mon Sep 17 00:00:00 2001 From: Matthew Dean Date: Tue, 12 Jul 2016 22:26:39 -0700 Subject: [PATCH 2/2] All tests passing for @plugin - Inline JavaScript disabled by default - Deprecated "preprocessor" option removed (preprocessor plugins still valid) --- Gruntfile.js | 10 +-- lib/less-browser/add-default-options.js | 2 + lib/less-browser/index.js | 3 +- lib/less-browser/plugin-loader.js | 12 ++- lib/less-node/index.js | 1 - lib/less-node/plugin-loader.js | 11 +-- lib/less/contexts.js | 2 +- lib/less/environment/abstract-file-manager.js | 3 +- .../environment/abstract-plugin-loader.js | 44 ++++++----- lib/less/import-manager.js | 6 +- lib/less/parser/parser.js | 42 +++++++--- lib/less/transform-tree.js | 4 +- lib/less/tree/import.js | 4 +- lib/less/tree/js-eval-node.js | 2 +- test/browser/common.js | 1 + test/browser/runner-browser-options.js | 2 +- test/browser/runner-errors-options.js | 4 +- test/browser/runner-postProcessor-options.js | 5 -- test/browser/runner-postProcessor.js | 3 - test/browser/test-runner-template.tmpl | 1 - test/index.js | 7 +- test/less-test.js | 78 ++++++++++--------- test/less/mixins-guards.less | 2 +- test/less/no-js-errors/no-js-errors.txt | 2 +- test/less/plugin.less | 2 +- test/less/plugin/plugin-local.js | 6 ++ test/less/plugin/plugin-transitive.less | 2 +- 27 files changed, 141 insertions(+), 120 deletions(-) delete mode 100644 test/browser/runner-postProcessor-options.js delete mode 100644 test/browser/runner-postProcessor.js diff --git a/Gruntfile.js b/Gruntfile.js index 5c2d00ad..92fea041 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -31,7 +31,7 @@ module.exports = function (grunt) { shell: { options: {stdout: true, failOnError: true}, test: { - command: 'node test' + command: 'node test/index.js' }, benchmark: { command: 'node benchmark/index.js' @@ -241,14 +241,6 @@ module.exports = function (grunt) { outfile: 'tmp/browser/test-runner-global-vars.html' } }, - postProcessor: { - src: ['test/browser/less/postProcessor/*.less'], - options: { - helpers: 'test/browser/runner-postProcessor-options.js', - specs: 'test/browser/runner-postProcessor.js', - outfile: 'tmp/browser/test-runner-post-processor.html' - } - }, postProcessorPlugin: { src: ['test/less/postProcessorPlugin/*.less'], options: { diff --git a/lib/less-browser/add-default-options.js b/lib/less-browser/add-default-options.js index b06c58f1..27fcb9e2 100644 --- a/lib/less-browser/add-default-options.js +++ b/lib/less-browser/add-default-options.js @@ -43,4 +43,6 @@ module.exports = function(window, options) { options.onReady = true; } + options.javascriptEnabled = (options.javascriptEnabled || options.inlineJavaScript) ? true : false; + }; diff --git a/lib/less-browser/index.js b/lib/less-browser/index.js index c8967125..5fc2a2b4 100644 --- a/lib/less-browser/index.js +++ b/lib/less-browser/index.js @@ -8,8 +8,7 @@ var addDataAttr = require("./utils").addDataAttr, module.exports = function(window, options) { var document = window.document; var less = require('../less')(); - - options.javascriptEnabled = !!(options.javascriptEnabled || options.inlineJavaScript); + less.options = options; var environment = less.environment, FileManager = require("./file-manager")(options, less.logger), diff --git a/lib/less-browser/plugin-loader.js b/lib/less-browser/plugin-loader.js index 9331f088..52bf6eb8 100644 --- a/lib/less-browser/plugin-loader.js +++ b/lib/less-browser/plugin-loader.js @@ -1,5 +1,4 @@ -var path = require("path"), - AbstractPluginLoader = require("../less/environment/abstract-plugin-loader.js"); +var AbstractPluginLoader = require("../less/environment/abstract-plugin-loader.js"); /** * Browser Plugin Loader @@ -11,7 +10,7 @@ var PluginLoader = function(less) { PluginLoader.prototype = new AbstractPluginLoader(); -PluginLoader.prototype.tryLoadPlugin = function(name, argument, basePath, callback) { +PluginLoader.prototype.tryLoadPlugin = function(name, basePath, callback) { var self = this; var prefix = name.slice(0, 1); var explicit = prefix === "." || prefix === "/" || name.slice(-3).toLowerCase() === ".js"; @@ -34,14 +33,13 @@ PluginLoader.prototype.tryLoadPlugin = function(name, argument, basePath, callba }; PluginLoader.prototype.tryLoadFromEnvironment = function(filename, basePath, explicit, callback) { - var fileManager; - + var fileManager = new this.less.FileManager(); + if (basePath) { - filename = path.join(basePath, filename); + filename = (fileManager.extractUrlParts(filename, basePath)).url; } if (filename) { - fileManager = new this.less.FileManager(); filename = fileManager.tryAppendExtension(filename, '.js'); diff --git a/lib/less-node/index.js b/lib/less-node/index.js index 55da4b22..ab278336 100644 --- a/lib/less-node/index.js +++ b/lib/less-node/index.js @@ -13,7 +13,6 @@ less.fs = require("./fs"); less.FileManager = FileManager; less.UrlFileManager = UrlFileManager; less.options = less.options || {}; -less.options.javascriptEnabled = false; less.formatError = function(ctx, options) { options = options || {}; diff --git a/lib/less-node/plugin-loader.js b/lib/less-node/plugin-loader.js index 8eaa19ae..d65880c9 100644 --- a/lib/less-node/plugin-loader.js +++ b/lib/less-node/plugin-loader.js @@ -36,9 +36,7 @@ PluginLoader.prototype.tryLoadPlugin = function(name, basePath, callback) { callback(null, data); } else { - self.tryLoadFromEnvironment(name, basePath, explicit, function(err2, data2) { - callback(err2, data2); - }); + self.tryLoadFromEnvironment(name, basePath, explicit, callback); } }); } @@ -46,11 +44,10 @@ PluginLoader.prototype.tryLoadPlugin = function(name, basePath, callback) { }; PluginLoader.prototype.tryLoadFromEnvironment = function(name, basePath, explicit, callback) { - var filename; + var filename = name; var self = this; function getFile(filename) { - var fileManager = new self.less.FileManager(); filename = fileManager.tryAppendExtension(filename, '.js'); @@ -60,7 +57,7 @@ PluginLoader.prototype.tryLoadFromEnvironment = function(name, basePath, explici self.require = self.requireRelative(filename); } catch(e) { - console.log(e.stack.toString()); + callback(e); } callback(null, data); }, @@ -103,7 +100,7 @@ PluginLoader.prototype.tryLoadFromEnvironment = function(name, basePath, explici catch(e) { } } - if (basePath && !filename) { + if (basePath) { filename = path.join(basePath, name); } if (filename) { diff --git a/lib/less/contexts.js b/lib/less/contexts.js index 545280b3..c7f6bc0f 100644 --- a/lib/less/contexts.js +++ b/lib/less/contexts.js @@ -48,7 +48,7 @@ var evalCopyProperties = [ '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 JavaScript is enabled. if undefined, defaults to true + '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 ]; diff --git a/lib/less/environment/abstract-file-manager.js b/lib/less/environment/abstract-file-manager.js index d9a2f90b..7c0e2063 100644 --- a/lib/less/environment/abstract-file-manager.js +++ b/lib/less/environment/abstract-file-manager.js @@ -35,13 +35,14 @@ abstractFileManager.prototype.alwaysMakePathsAbsolute = function() { abstractFileManager.prototype.isPathAbsolute = function(filename) { return (/^(?:[a-z-]+:|\/|\\|#)/i).test(filename); }; - +// TODO: pull out - this is part of Node & Browserify 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 diff --git a/lib/less/environment/abstract-plugin-loader.js b/lib/less/environment/abstract-plugin-loader.js index 3f14be18..9d86fcf2 100644 --- a/lib/less/environment/abstract-plugin-loader.js +++ b/lib/less/environment/abstract-plugin-loader.js @@ -36,6 +36,7 @@ AbstractPluginLoader.prototype.evalPlugin = function(contents, context, pluginOp pluginObj = pluginManager.get(filename); if (pluginObj) { + this.trySetOptions(pluginObj, filename, pluginOptions); if (pluginObj.use) { pluginObj.use(this.less); } @@ -58,24 +59,27 @@ AbstractPluginLoader.prototype.evalPlugin = function(contents, context, pluginOp pluginObj = localModule.exports; } - pluginObj = this.validatePlugin(pluginObj, filename, pluginOptions); + pluginObj = this.validatePlugin(pluginObj, filename); + if (pluginObj) { // Run on first load pluginManager.addPlugin(pluginObj, fileInfo.filename); pluginObj.functions = registry.getLocalFunctions(); + this.trySetOptions(pluginObj, filename, pluginOptions); + // Run every @plugin call if (pluginObj.use) { pluginObj.use(this.less); } } else { - throw new Error(); + throw new SyntaxError("Not a valid plugin"); } } catch(e) { // TODO pass the error - console.log(e.stack.toString()); + console.log(e); return new this.less.LessError({ message: "Plugin evaluation error: '" + e.name + ': ' + e.message.replace(/["]/g, "'") + "'" , filename: filename, @@ -88,7 +92,24 @@ AbstractPluginLoader.prototype.evalPlugin = function(contents, context, pluginOp }; -AbstractPluginLoader.prototype.validatePlugin = function(plugin, filename, options) { +AbstractPluginLoader.prototype.trySetOptions = function(plugin, filename, options) { + var name = require('path').basename(filename); + if (options) { + if (!plugin.setOptions) { + error("Options have been provided but the plugin " + name + " does not support any options."); + return null; + } + try { + plugin.setOptions(options); + } + catch(e) { + error("Error setting options on plugin " + name + '\n' + e.message); + return null; + } + } +}; + +AbstractPluginLoader.prototype.validatePlugin = function(plugin, filename) { if (plugin) { // support plugins being a function // so that the plugin can be more usable programmatically @@ -98,20 +119,7 @@ AbstractPluginLoader.prototype.validatePlugin = function(plugin, filename, optio var name = require('path').basename(filename); if (plugin.minVersion) { if (this.compareVersion(plugin.minVersion, this.less.version) < 0) { - error("plugin " + name + " requires version " + this.versionToString(plugin.minVersion)); - return null; - } - } - if (options) { - if (!plugin.setOptions) { - error("options have been provided but the plugin " + name + "does not support any options"); - return null; - } - try { - plugin.setOptions(options); - } - catch(e) { - error("Error setting options on plugin " + name + '\n' + e.message); + error("Plugin " + name + " requires version " + this.versionToString(plugin.minVersion)); return null; } } diff --git a/lib/less/import-manager.js b/lib/less/import-manager.js index 7ef6171c..3cbc4e21 100644 --- a/lib/less/import-manager.js +++ b/lib/less/import-manager.js @@ -107,8 +107,7 @@ module.exports = function(environment) { } if (importOptions.isPlugin) { - - plugin = pluginLoader.evalPlugin(contents, newEnv, importOptions, newFileInfo); + plugin = pluginLoader.evalPlugin(contents, newEnv, importOptions.pluginArgs, newFileInfo); if (plugin instanceof LessError) { fileParsedFunc(plugin, null, resolvedFilename); } @@ -132,9 +131,8 @@ module.exports = function(environment) { } }; if (importOptions.isPlugin) { - // TODO: implement options for plugins try { - pluginLoader.tryLoadPlugin(path, null, currentFileInfo.currentDirectory, done); + pluginLoader.tryLoadPlugin(path, currentFileInfo.currentDirectory, done); } catch(e) { callback(e); diff --git a/lib/less/parser/parser.js b/lib/less/parser/parser.js index 761ee6f3..11231e83 100644 --- a/lib/less/parser/parser.js +++ b/lib/less/parser/parser.js @@ -1384,22 +1384,27 @@ var Parser = function Parser(context, imports, fileInfo) { }, // - // A @plugin directive, used to import scoped extensions dynamically. + // A @plugin directive, used to import plugins dynamically. // - // @plugin "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. + // @plugin (args) "lib"; // plugin: function () { - var path, + var path, args, options, index = parserInput.i, dir = parserInput.$re(/^@plugin?\s+/); if (dir) { - var options = { isPlugin : true }; + args = this.pluginArgs(); + + if (args) { + options = { + pluginArgs: args, + isPlugin: true + }; + } + else { + options = { isPlugin: true }; + } if ((path = this.entities.quoted() || this.entities.url())) { @@ -1407,7 +1412,6 @@ var Parser = function Parser(context, imports, fileInfo) { parserInput.i = index; error("missing semi-colon on @plugin"); } - return new(tree.Import)(path, null, options, index, fileInfo); } else { @@ -1417,6 +1421,24 @@ var Parser = function Parser(context, imports, fileInfo) { } }, + 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; + } + }, + // // A CSS Directive // diff --git a/lib/less/transform-tree.js b/lib/less/transform-tree.js index f1fc37c2..1835462a 100644 --- a/lib/less/transform-tree.js +++ b/lib/less/transform-tree.js @@ -63,7 +63,9 @@ module.exports = function(root, options) { if (options.pluginManager) { visitorIterator.first(); while ((v = visitorIterator.get())) { - v.run(root); + if (!v.isPreEvalVisitor) { + v.run(evaldRoot); + } } } diff --git a/lib/less/tree/import.js b/lib/less/tree/import.js index eeb280e1..ef9636a9 100644 --- a/lib/less/tree/import.js +++ b/lib/less/tree/import.js @@ -127,8 +127,8 @@ Import.prototype.doEval = function (context) { features = this.features && this.features.eval(context); if (this.options.isPlugin) { - if (this.root && this.root.setContext) { - this.root.setContext(context); + if (this.root && this.root.eval) { + this.root.eval(context); } registry = context.frames[0] && context.frames[0].functionRegistry; if ( registry && this.root && this.root.functions ) { diff --git a/lib/less/tree/js-eval-node.js b/lib/less/tree/js-eval-node.js index 3b37378e..a4410b23 100644 --- a/lib/less/tree/js-eval-node.js +++ b/lib/less/tree/js-eval-node.js @@ -10,7 +10,7 @@ JsEvalNode.prototype.evaluateJavaScript = function (expression, context) { that = this, evalContext = {}; - if (context.javascriptEnabled !== undefined && !context.javascriptEnabled) { + if (!context.javascriptEnabled) { throw { message: "Inline JavaScript is not enabled. Is it set in your options?", filename: this.currentFileInfo.filename, index: this.index }; diff --git a/test/browser/common.js b/test/browser/common.js index 887e9cc6..58ef5060 100644 --- a/test/browser/common.js +++ b/test/browser/common.js @@ -1,6 +1,7 @@ /* Add js reporter for sauce */ jasmine.getEnv().addReporter(new jasmine.JSReporter2()); +jasmine.getEnv().defaultTimeoutInterval = 3000; /* record log messages for testing */ diff --git a/test/browser/runner-browser-options.js b/test/browser/runner-browser-options.js index 64037bbb..b90ec3b0 100644 --- a/test/browser/runner-browser-options.js +++ b/test/browser/runner-browser-options.js @@ -1,4 +1,4 @@ -var less = {logLevel: 4, errorReporting: "console"}; +var less = {logLevel: 4, errorReporting: "console", javascriptEnabled: true}; // There originally run inside describe method. However, since they have not // been inside it, they run at jasmine compile time (not runtime). It all diff --git a/test/browser/runner-errors-options.js b/test/browser/runner-errors-options.js index 8ba00e27..97b211d9 100644 --- a/test/browser/runner-errors-options.js +++ b/test/browser/runner-errors-options.js @@ -1,4 +1,6 @@ var less = { strictUnits: true, strictMath: true, - logLevel: 4 }; + logLevel: 4, + javascriptEnabled: true +}; diff --git a/test/browser/runner-postProcessor-options.js b/test/browser/runner-postProcessor-options.js deleted file mode 100644 index fe7111b6..00000000 --- a/test/browser/runner-postProcessor-options.js +++ /dev/null @@ -1,5 +0,0 @@ -var less = {logLevel: 4, - errorReporting: "console"}; -less.postProcessor = function(styles) { - return 'hr {height:50px;}\n' + styles; -}; diff --git a/test/browser/runner-postProcessor.js b/test/browser/runner-postProcessor.js deleted file mode 100644 index 64937669..00000000 --- a/test/browser/runner-postProcessor.js +++ /dev/null @@ -1,3 +0,0 @@ -describe("less.js postProcessor (deprecated)", function() { - testLessEqualsInDocument(); -}); diff --git a/test/browser/test-runner-template.tmpl b/test/browser/test-runner-template.tmpl index c02c38f3..9fef5680 100644 --- a/test/browser/test-runner-template.tmpl +++ b/test/browser/test-runner-template.tmpl @@ -3,7 +3,6 @@ Jasmine Spec Runner - <% var generateScriptTags = function(allScripts) { allScripts.forEach(function(script){ %> diff --git a/test/index.js b/test/index.js index a7aab0eb..c239e2fe 100644 --- a/test/index.js +++ b/test/index.js @@ -16,10 +16,11 @@ function getErrorPathReplacementFunction(dir) { } console.log("\n" + stylize("Less", 'underline') + "\n"); + lessTester.prepBomTest(); -lessTester.runTestSet({strictMath: true, relativeUrls: true, silent: true}); -lessTester.runTestSet({strictMath: true, strictUnits: true}, "errors/", - lessTester.testErrors, null, getErrorPathReplacementFunction("errors")); +lessTester.runTestSet({strictMath: true, relativeUrls: true, silent: true, javascriptEnabled: true}); +lessTester.runTestSet({strictMath: true, strictUnits: true, javascriptEnabled: true}, "errors/", + lessTester.testErrors, null, getErrorPathReplacementFunction("errors")); lessTester.runTestSet({strictMath: true, strictUnits: true, javascriptEnabled: false}, "no-js-errors/", lessTester.testErrors, null, getErrorPathReplacementFunction("no-js-errors")); lessTester.runTestSet({strictMath: true, dumpLineNumbers: 'comments'}, "debug/", null, diff --git a/test/less-test.js b/test/less-test.js index 7623a076..0d71a37c 100644 --- a/test/less-test.js +++ b/test/less-test.js @@ -58,7 +58,8 @@ module.exports = function() { var totalTests = 0, failedTests = 0, - passedTests = 0; + passedTests = 0, + finishTimer = setInterval(endTest, 500); less.functions.functionRegistry.addMultiple({ add: function (a, b) { @@ -221,48 +222,49 @@ module.exports = function() { var doubleCallCheck = false; queue(function() { toCSS(options, path.join(baseFolder, foldername + file), function (err, result) { - if (doubleCallCheck) { - totalTests++; - fail("less is calling back twice"); - process.stdout.write(doubleCallCheck + "\n"); - process.stdout.write((new Error()).stack + "\n"); - return; - } - doubleCallCheck = (new Error()).stack; + + if (doubleCallCheck) { + totalTests++; + fail("less is calling back twice"); + process.stdout.write(doubleCallCheck + "\n"); + process.stdout.write((new Error()).stack + "\n"); + return; + } + doubleCallCheck = (new Error()).stack; - if (verifyFunction) { - var verificationResult = verifyFunction(name, err, result && result.css, doReplacements, result && result.map, baseFolder); - release(); - return verificationResult; - } - if (err) { - fail("ERROR: " + (err && err.message)); - if (isVerbose) { - process.stdout.write("\n"); - if (err.stack) { - process.stdout.write(err.stack + "\n"); - } else { - //this sometimes happen - show the whole error object - console.log(err); + if (verifyFunction) { + var verificationResult = verifyFunction(name, err, result && result.css, doReplacements, result && result.map, baseFolder); + release(); + return verificationResult; + } + if (err) { + fail("ERROR: " + (err && err.message)); + if (isVerbose) { + process.stdout.write("\n"); + if (err.stack) { + process.stdout.write(err.stack + "\n"); + } else { + //this sometimes happen - show the whole error object + console.log(err); + } } + release(); + return; } - release(); - return; - } - var css_name = name; - if (nameModifier) { css_name = nameModifier(name); } - fs.readFile(path.join('test/css', css_name) + '.css', 'utf8', function (e, css) { - process.stdout.write("- " + path.join(baseFolder, css_name) + ": "); + var css_name = name; + if (nameModifier) { css_name = nameModifier(name); } + fs.readFile(path.join('test/css', css_name) + '.css', 'utf8', function (e, css) { + process.stdout.write("- " + path.join(baseFolder, css_name) + ": "); - css = css && doReplacements(css, path.join(baseFolder, foldername)); - if (result.css === css) { ok('OK'); } - else { - difference("FAIL", css, result.css); - } - release(); + css = css && doReplacements(css, path.join(baseFolder, foldername)); + if (result.css === css) { ok('OK'); } + else { + difference("FAIL", css, result.css); + } + release(); + }); }); }); - }); }); } @@ -305,8 +307,8 @@ module.exports = function() { function endTest() { if (isFinished && ((failedTests + passedTests) >= totalTests)) { + clearInterval(finishTimer); var leaked = checkGlobalLeaks(); - process.stdout.write("\n"); if (failedTests > 0) { process.stdout.write(failedTests + stylize(" Failed", "red") + ", " + passedTests + " passed\n"); diff --git a/test/less/mixins-guards.less b/test/less/mixins-guards.less index 883bb57a..31ad088e 100644 --- a/test/less/mixins-guards.less +++ b/test/less/mixins-guards.less @@ -150,7 +150,7 @@ .generic(abc, "abc"); .generic('abc', "abd"); .generic(6, e("6")); - .generic(`9`, 8); + .generic(9, 8); .generic(a, b); .generic(1 2, 3); } diff --git a/test/less/no-js-errors/no-js-errors.txt b/test/less/no-js-errors/no-js-errors.txt index d81dd2bd..10b3cd15 100644 --- a/test/less/no-js-errors/no-js-errors.txt +++ b/test/less/no-js-errors/no-js-errors.txt @@ -1,4 +1,4 @@ -SyntaxError: You are using JavaScript, which has been disabled. in {path}no-js-errors.less on line 2, column 6: +SyntaxError: Inline JavaScript is not enabled. Is it set in your options? in {path}no-js-errors.less on line 2, column 6: 1 .a { 2 a: `1 + 1`; 3 } diff --git a/test/less/plugin.less b/test/less/plugin.less index 66775ea9..d4dc0105 100644 --- a/test/less/plugin.less +++ b/test/less/plugin.less @@ -40,7 +40,7 @@ ruleset-shadow : test-shadow(); }; #ns { - @plugin "./plugin/plugin-local"; + @plugin (test=test) "./plugin/plugin-local"; .mixin() { ns-mixin-global : test-global(); ns-mixin-local : test-local(); diff --git a/test/less/plugin/plugin-local.js b/test/less/plugin/plugin-local.js index b54ca97a..d074b56c 100644 --- a/test/less/plugin/plugin-local.js +++ b/test/less/plugin/plugin-local.js @@ -6,3 +6,9 @@ functions.addMultiple({ return new tree.Anonymous( "local" ); } }); + +return { + setOptions: function(raw) { + // do nothing + } +} \ No newline at end of file diff --git a/test/less/plugin/plugin-transitive.less b/test/less/plugin/plugin-transitive.less index a0c20283..8e4ca00b 100644 --- a/test/less/plugin/plugin-transitive.less +++ b/test/less/plugin/plugin-transitive.less @@ -1,4 +1,4 @@ -@plugin "extension-transitive"; +@plugin "plugin-transitive"; .other { trans : test-transitive();