/* jshint rhino:true, unused: false */ /* jscs:disable validateIndentation */ /*global name:true, less, loadStyleSheet, os */ function formatError(ctx, options) { options = options || {}; var message = ""; var extract = ctx.extract; var error = []; // var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str; }; var stylize = function (str) { return str; }; // only output a stack if it isn't a less error if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red'); } if (!ctx.hasOwnProperty('index') || !extract) { return ctx.stack || ctx.message; } if (typeof extract[0] === 'string') { error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey')); } if (typeof extract[1] === 'string') { var errorTxt = ctx.line + ' '; if (extract[1]) { errorTxt += extract[1].slice(0, ctx.column) + stylize(stylize(stylize(extract[1][ctx.column], 'bold') + extract[1].slice(ctx.column + 1), 'red'), 'inverse'); } error.push(errorTxt); } if (typeof extract[2] === 'string') { error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey')); } error = error.join('\n') + stylize('', 'reset') + '\n'; message += stylize(ctx.type + 'Error: ' + ctx.message, 'red'); if (ctx.filename) { message += stylize(' in ', 'red') + ctx.filename + stylize(' on line ' + ctx.line + ', column ' + (ctx.column + 1) + ':', 'grey'); } message += '\n' + error; if (ctx.callLine) { message += stylize('from ', 'red') + (ctx.filename || '') + '/n'; message += stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract + '/n'; } return message; } function writeError(ctx, options) { options = options || {}; if (options.silent) { return; } var message = formatError(ctx, options); throw new Error(message); } function loadStyleSheet(sheet, callback, reload, remaining) { var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')), sheetName = name.slice(0, endOfPath + 1) + sheet.href, contents = sheet.contents || {}, input = readFile(sheetName); input = input.replace(/^\xEF\xBB\xBF/, ''); contents[sheetName] = input; var parser = new less.Parser({ paths: [sheet.href.replace(/[\w\.-]+$/, '')], contents: contents }); parser.parse(input, function (e, root) { if (e) { return writeError(e); } try { callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName); } catch(e) { writeError(e); } }); } less.Parser.fileLoader = function (file, currentFileInfo, callback, env) { var href = file; if (currentFileInfo && currentFileInfo.currentDirectory && !/^\//.test(file)) { href = less.modules.path.join(currentFileInfo.currentDirectory, file); } var path = less.modules.path.dirname(href); var newFileInfo = { currentDirectory: path + '/', filename: href }; if (currentFileInfo) { newFileInfo.entryPath = currentFileInfo.entryPath; newFileInfo.rootpath = currentFileInfo.rootpath; newFileInfo.rootFilename = currentFileInfo.rootFilename; newFileInfo.relativeUrls = currentFileInfo.relativeUrls; } else { newFileInfo.entryPath = path; newFileInfo.rootpath = less.rootpath || path; newFileInfo.rootFilename = href; newFileInfo.relativeUrls = env.relativeUrls; } var j = file.lastIndexOf('/'); if (newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) { var relativeSubDirectory = file.slice(0, j + 1); newFileInfo.rootpath = newFileInfo.rootpath + relativeSubDirectory; // append (sub|sup) directory path of imported file } newFileInfo.currentDirectory = path; newFileInfo.filename = href; var data = null; try { data = readFile(href); } catch (e) { callback({ type: 'File', message: "'" + less.modules.path.basename(href) + "' wasn't found" }); return; } try { callback(null, data, href, newFileInfo, { lastModified: 0 }); } catch (e) { callback(e, null, href); } }; function writeFile(filename, content) { var fstream = new java.io.FileWriter(filename); var out = new java.io.BufferedWriter(fstream); out.write(content); out.close(); } // Command line integration via Rhino (function (args) { var options = { depends: false, compress: false, cleancss: false, max_line_len: -1, silent: false, verbose: false, lint: false, paths: [], color: true, strictImports: false, rootpath: '', relativeUrls: false, ieCompat: true, strictMath: false, strictUnits: false }; var continueProcessing = true, currentErrorcode; var checkArgFunc = function(arg, option) { if (!option) { print(arg + " option requires a parameter"); continueProcessing = false; 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) { print(" unable to parse " + arg + " as a boolean. use one of on/t/true/y/yes/off/f/false/n/no"); continueProcessing = false; return false; } return Boolean(onOff[2]); }; var warningMessages = ""; var sourceMapFileInline = false; args = args.filter(function (arg) { var 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': options.verbose = true; break; case 's': case 'silent': options.silent = true; break; case 'l': case 'lint': options.lint = true; break; case 'strict-imports': options.strictImports = true; break; case 'h': case 'help': //TODO // require('../lib/less/lessc_helper').printUsage(); continueProcessing = false; break; case 'x': case 'compress': options.compress = true; break; case 'M': case 'depends': options.depends = true; break; case 'yui-compress': warningMessages += "yui-compress option has been removed. assuming clean-css."; options.cleancss = true; break; case 'clean-css': options.cleancss = 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])) { // support for both ; and : path separators // even on windows when using absolute paths with drive letters (eg C:\path:D:\path) options.paths = match[2] .split(os.type().match(/Windows/) ? /:(?!\\)|;/ : ':') .map(function(p) { if (p) { // return path.resolve(process.cwd(), p); return p; } }); } break; case 'line-numbers': if (checkArgFunc(arg, match[2])) { options.dumpLineNumbers = match[2]; } break; case 'source-map': if (!match[2]) { options.sourceMap = true; } else { options.sourceMap = match[2]; } break; case 'source-map-rootpath': if (checkArgFunc(arg, match[2])) { options.sourceMapRootpath = match[2]; } break; case 'source-map-basepath': if (checkArgFunc(arg, match[2])) { options.sourceMapBasepath = match[2]; } break; case 'source-map-map-inline': sourceMapFileInline = true; options.sourceMap = true; break; case 'source-map-less-inline': options.outputSourceFiles = true; break; case 'source-map-url': if (checkArgFunc(arg, match[2])) { options.sourceMapURL = match[2]; } break; case 'source-map-output-map-file': if (checkArgFunc(arg, match[2])) { options.writeSourceMap = function(sourceMapContent) { writeFile(match[2], sourceMapContent); }; } 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; default: console.log('invalid option ' + arg); continueProcessing = false; } }); if (!continueProcessing) { return; } var name = args[0]; if (name && name != '-') { // name = path.resolve(process.cwd(), name); } var output = args[1]; var outputbase = args[1]; if (output) { options.sourceMapOutputFilename = output; // output = path.resolve(process.cwd(), output); if (warningMessages) { console.log(warningMessages); } } // options.sourceMapBasepath = process.cwd(); // options.sourceMapBasepath = ''; if (options.sourceMap === true) { console.log("output: " + output); if (!output && !sourceMapFileInline) { console.log("the sourcemap option only has an optional filename if the css filename is given"); return; } options.sourceMapFullFilename = options.sourceMapOutputFilename + ".map"; options.sourceMap = less.modules.path.basename(options.sourceMapFullFilename); } else if (options.sourceMap) { options.sourceMapOutputFilename = options.sourceMap; } if (!name) { console.log("lessc: no inout files"); console.log(""); // TODO // require('../lib/less/lessc_helper').printUsage(); currentErrorcode = 1; return; } // 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 (options.depends) { if (!outputbase) { console.log("option --depends requires an output path to be specified"); return; } console.log(outputbase + ": "); } if (!name) { console.log('No files present in the fileset'); quit(1); } var input = null; try { input = readFile(name, 'utf-8'); } catch (e) { console.log('lesscss: couldn\'t open file ' + name); quit(1); } options.filename = name; var result; try { var parser = new less.Parser(options); parser.parse(input, function (e, root) { if (e) { writeError(e, options); quit(1); } else { result = root.toCSS(options); if (output) { writeFile(output, result); console.log("Written to " + output); } else { print(result); } quit(0); } }); } catch(e) { writeError(e, options); quit(1); } }(arguments));