Advertisement
AmourSpirit

lessc default

Dec 21st, 2015
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env node
  2.  
  3. var path = require('path'),
  4.     fs = require('../lib/less-node/fs'),
  5.     os = require("os"),
  6.     errno,
  7.     mkdirp;
  8.  
  9. try {
  10.     errno = require('errno');
  11. } catch (err) {
  12.     errno = null;
  13. }
  14.  
  15. var less = require('../lib/less-node'),
  16.     pluginLoader = new less.PluginLoader(less),
  17.     plugin,
  18.     plugins = [];
  19.  
  20. var args = process.argv.slice(1);
  21. var silent = false,
  22.     verbose = false,
  23.     options = {
  24.     depends: false,
  25.     compress: false,
  26.     max_line_len: -1,
  27.     lint: false,
  28.     paths: [],
  29.     color: true,
  30.     strictImports: false,
  31.     insecure: false,
  32.     rootpath: '',
  33.     relativeUrls: false,
  34.     ieCompat: true,
  35.     strictMath: false,
  36.     strictUnits: false,
  37.     globalVars: null,
  38.     modifyVars: null,
  39.     urlArgs: '',
  40.     plugins: plugins
  41. };
  42. var sourceMapOptions = {};
  43. var continueProcessing = true,
  44.     currentErrorcode;
  45.  
  46. // calling process.exit does not flush stdout always
  47. // so use this to set the exit code
  48. process.on('exit', function() { process.reallyExit(currentErrorcode); });
  49.  
  50. var checkArgFunc = function(arg, option) {
  51.     if (!option) {
  52.         console.error(arg + " option requires a parameter");
  53.         continueProcessing = false;
  54.         currentErrorcode = 1;
  55.         return false;
  56.     }
  57.     return true;
  58. };
  59.  
  60. var checkBooleanArg = function(arg) {
  61.     var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
  62.     if (!onOff) {
  63.         console.error(" unable to parse " + arg + " as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
  64.         continueProcessing = false;
  65.         currentErrorcode = 1;
  66.         return false;
  67.     }
  68.     return Boolean(onOff[2]);
  69. };
  70.  
  71. var parseVariableOption = function(option, variables) {
  72.     var parts = option.split('=', 2);
  73.     variables[parts[0]] = parts[1];
  74. };
  75.  
  76. var sourceMapFileInline = false;
  77.  
  78. function printUsage() {
  79.     less.lesscHelper.printUsage();
  80.     pluginLoader.printUsage(plugins);
  81.     continueProcessing = false;
  82. }
  83.  
  84. // self executing function so we can return
  85. (function() {
  86.     args = args.filter(function (arg) {
  87.         var match;
  88.  
  89.         match = arg.match(/^-I(.+)$/);
  90.         if (match) {
  91.             options.paths.push(match[1]);
  92.             return false;
  93.         }
  94.  
  95.         match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
  96.         if (match) {
  97.             arg = match[1];
  98.         } else {
  99.             return arg;
  100.         }
  101.  
  102.         switch (arg) {
  103.             case 'v':
  104.             case 'version':
  105.                 console.log("lessc " + less.version.join('.') + " (Less Compiler) [JavaScript]");
  106.                 continueProcessing = false;
  107.                 break;
  108.             case 'verbose':
  109.                 verbose = true;
  110.                 break;
  111.             case 's':
  112.             case 'silent':
  113.                 silent = true;
  114.                 break;
  115.             case 'l':
  116.             case 'lint':
  117.                 options.lint = true;
  118.                 break;
  119.             case 'strict-imports':
  120.                 options.strictImports = true;
  121.                 break;
  122.             case 'h':
  123.             case 'help':
  124.                 printUsage();
  125.                 break;
  126.             case 'x':
  127.             case 'compress':
  128.                 options.compress = true;
  129.                 break;
  130.             case 'insecure':
  131.                 options.insecure = true;
  132.                 break;
  133.             case 'M':
  134.             case 'depends':
  135.                 options.depends = true;
  136.                 break;
  137.             case 'max-line-len':
  138.                 if (checkArgFunc(arg, match[2])) {
  139.                     options.maxLineLen = parseInt(match[2], 10);
  140.                     if (options.maxLineLen <= 0) {
  141.                         options.maxLineLen = -1;
  142.                     }
  143.                 }
  144.                 break;
  145.             case 'no-color':
  146.                 options.color = false;
  147.                 break;
  148.             case 'no-ie-compat':
  149.                 options.ieCompat = false;
  150.                 break;
  151.             case 'no-js':
  152.                 options.javascriptEnabled = false;
  153.                 break;
  154.             case 'include-path':
  155.                 if (checkArgFunc(arg, match[2])) {
  156.                     // ; supported on windows.
  157.                     // : supported on windows and linux, excluding a drive letter like C:\ so C:\file:D:\file parses to 2
  158.                     options.paths = match[2]
  159.                         .split(os.type().match(/Windows/) ? /:(?!\\)|;/ : ':')
  160.                         .map(function(p) {
  161.                             if (p) {
  162.                                 return path.resolve(process.cwd(), p);
  163.                             }
  164.                         });
  165.                 }
  166.                 break;
  167.             case 'line-numbers':
  168.                 if (checkArgFunc(arg, match[2])) {
  169.                     options.dumpLineNumbers = match[2];
  170.                 }
  171.                 break;
  172.             case 'source-map':
  173.                 options.sourceMap = true;
  174.                 if (match[2]) {
  175.                     sourceMapOptions.sourceMapFullFilename = match[2];
  176.                 }
  177.                 break;
  178.             case 'source-map-rootpath':
  179.                 if (checkArgFunc(arg, match[2])) {
  180.                     sourceMapOptions.sourceMapRootpath = match[2];
  181.                 }
  182.                 break;
  183.             case 'source-map-basepath':
  184.                 if (checkArgFunc(arg, match[2])) {
  185.                     sourceMapOptions.sourceMapBasepath = match[2];
  186.                 }
  187.                 break;
  188.             case 'source-map-map-inline':
  189.                 sourceMapFileInline = true;
  190.                 options.sourceMap = true;
  191.                 break;
  192.             case 'source-map-less-inline':
  193.                 sourceMapOptions.outputSourceFiles = true;
  194.                 break;
  195.             case 'source-map-url':
  196.                 if (checkArgFunc(arg, match[2])) {
  197.                     sourceMapOptions.sourceMapURL = match[2];
  198.                 }
  199.                 break;
  200.             case 'rp':
  201.             case 'rootpath':
  202.                 if (checkArgFunc(arg, match[2])) {
  203.                     options.rootpath = match[2].replace(/\\/g, '/');
  204.                 }
  205.                 break;
  206.             case "ru":
  207.             case "relative-urls":
  208.                 options.relativeUrls = true;
  209.                 break;
  210.             case "sm":
  211.             case "strict-math":
  212.                 if (checkArgFunc(arg, match[2])) {
  213.                     options.strictMath = checkBooleanArg(match[2]);
  214.                 }
  215.                 break;
  216.             case "su":
  217.             case "strict-units":
  218.                 if (checkArgFunc(arg, match[2])) {
  219.                     options.strictUnits = checkBooleanArg(match[2]);
  220.                 }
  221.                 break;
  222.             case "global-var":
  223.                 if (checkArgFunc(arg, match[2])) {
  224.                     if (!options.globalVars) {
  225.                         options.globalVars = {};
  226.                     }
  227.                     parseVariableOption(match[2], options.globalVars);
  228.                 }
  229.                 break;
  230.             case "modify-var":
  231.                 if (checkArgFunc(arg, match[2])) {
  232.                     if (!options.modifyVars) {
  233.                         options.modifyVars = {};
  234.                     }
  235.  
  236.                     parseVariableOption(match[2], options.modifyVars);
  237.                 }
  238.                 break;
  239.             case 'url-args':
  240.                 if (checkArgFunc(arg, match[2])) {
  241.                     options.urlArgs = match[2];
  242.                 }
  243.                 break;
  244.             case 'plugin':
  245.                 var splitupArg = match[2].match(/^([^=]+)(=(.*))?/),
  246.                     name = splitupArg[1],
  247.                     pluginOptions = splitupArg[3];
  248.  
  249.                 plugin = pluginLoader.tryLoadPlugin(name, pluginOptions);
  250.                 if (plugin) {
  251.                     plugins.push(plugin);
  252.                 } else {
  253.                     console.error("Unable to load plugin " + name +
  254.                         " please make sure that it is installed under or at the same level as less");
  255.                     currentErrorcode = 1;
  256.                 }
  257.                 break;
  258.             default:
  259.                 plugin = pluginLoader.tryLoadPlugin("less-plugin-" + arg, match[2]);
  260.                 if (plugin) {
  261.                     plugins.push(plugin);
  262.                 } else {
  263.                     console.error("Unable to interpret argument " + arg +
  264.                         " - if it is a plugin (less-plugin-" + arg + "), make sure that it is installed under or at" +
  265.                         " the same level as less");
  266.                     currentErrorcode = 1;
  267.                 }
  268.                 break;
  269.         }
  270.     });
  271.  
  272.     if (!continueProcessing) {
  273.         return;
  274.     }
  275.  
  276.     var input = args[1];
  277.     if (input && input != '-') {
  278.         input = path.resolve(process.cwd(), input);
  279.     }
  280.     var output = args[2];
  281.     var outputbase = args[2];
  282.     if (output) {
  283.         output = path.resolve(process.cwd(), output);
  284.     }
  285.  
  286.     if (options.sourceMap) {
  287.  
  288.         sourceMapOptions.sourceMapInputFilename = input;
  289.         if (!sourceMapOptions.sourceMapFullFilename) {
  290.             if (!output && !sourceMapFileInline) {
  291.                 console.log("the sourcemap option only has an optional filename if the css filename is given");
  292.                 console.log("consider adding --source-map-map-inline which embeds the sourcemap into the css");
  293.                 return;
  294.             }
  295.             // its in the same directory, so always just the basename
  296.             sourceMapOptions.sourceMapOutputFilename = path.basename(output);
  297.             sourceMapOptions.sourceMapFullFilename = output + ".map";
  298.             // its in the same directory, so always just the basename
  299.             sourceMapOptions.sourceMapFilename = path.basename(sourceMapOptions.sourceMapFullFilename);
  300.         } else if (options.sourceMap && !sourceMapFileInline) {
  301.             var mapFilename = path.resolve(process.cwd(), sourceMapOptions.sourceMapFullFilename),
  302.                 mapDir = path.dirname(mapFilename),
  303.                 outputDir = path.dirname(output);
  304.             // find the path from the map to the output file
  305.             sourceMapOptions.sourceMapOutputFilename = path.join(
  306.                 path.relative(mapDir, outputDir), path.basename(output));
  307.  
  308.             // make the sourcemap filename point to the sourcemap relative to the css file output directory
  309.             sourceMapOptions.sourceMapFilename = path.join(
  310.                 path.relative(outputDir, mapDir), path.basename(sourceMapOptions.sourceMapFullFilename));
  311.         }
  312.     }
  313.  
  314.     if (sourceMapOptions.sourceMapBasepath === undefined) {
  315.         sourceMapOptions.sourceMapBasepath = input ? path.dirname(input) : process.cwd();
  316.     }
  317.  
  318.     if (sourceMapOptions.sourceMapRootpath === undefined) {
  319.         var pathToMap = path.dirname(sourceMapFileInline ? output : sourceMapOptions.sourceMapFullFilename),
  320.             pathToInput = path.dirname(sourceMapOptions.sourceMapInputFilename);
  321.         sourceMapOptions.sourceMapRootpath = path.relative(pathToMap, pathToInput);
  322.     }
  323.  
  324.     if (! input) {
  325.         console.error("lessc: no input files");
  326.         console.error("");
  327.         printUsage();
  328.         currentErrorcode = 1;
  329.         return;
  330.     }
  331.  
  332.     var ensureDirectory = function (filepath) {
  333.         var dir = path.dirname(filepath),
  334.             cmd,
  335.             existsSync = fs.existsSync || path.existsSync;
  336.         if (!existsSync(dir)) {
  337.             if (mkdirp === undefined) {
  338.                 try {mkdirp = require('mkdirp');}
  339.                 catch(e) { mkdirp = null; }
  340.             }
  341.             cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
  342.             cmd(dir);
  343.         }
  344.     };
  345.  
  346.     if (options.depends) {
  347.         if (!outputbase) {
  348.             console.log("option --depends requires an output path to be specified");
  349.             return;
  350.         }
  351.         process.stdout.write(outputbase + ": ");
  352.     }
  353.  
  354.     if (!sourceMapFileInline) {
  355.         var writeSourceMap = function(output, onDone) {
  356.             output = output || "";
  357.             var filename = sourceMapOptions.sourceMapFullFilename;
  358.             ensureDirectory(filename);
  359.             fs.writeFile(filename, output, 'utf8', function (err) {
  360.                 if (err) {
  361.                     var description = "Error: ";
  362.                     if (errno && errno.errno[err.errno]) {
  363.                         description += errno.errno[err.errno].description;
  364.                     } else {
  365.                         description += err.code + " " + err.message;
  366.                     }
  367.                     console.error('lessc: failed to create file ' + filename);
  368.                     console.error(description);
  369.                 } else {
  370.                     less.logger.info('lessc: wrote ' + filename);
  371.                 }
  372.                 onDone();
  373.             });
  374.         };
  375.     }
  376.  
  377.     var writeSourceMapIfNeeded = function(output, onDone) {
  378.         if (options.sourceMap && !sourceMapFileInline) {
  379.             writeSourceMap(output, onDone);
  380.         } else {
  381.             onDone();
  382.         }
  383.     };
  384.  
  385.     var writeOutput = function(output, result, onSuccess) {
  386.         if (output) {
  387.             ensureDirectory(output);
  388.             fs.writeFile(output, result.css, {encoding: 'utf8'}, function (err) {
  389.                 if (err) {
  390.                     var description = "Error: ";
  391.                     if (errno && errno.errno[err.errno]) {
  392.                         description += errno.errno[err.errno].description;
  393.                     } else {
  394.                         description += err.code + " " + err.message;
  395.                     }
  396.                     console.error('lessc: failed to create file ' + output);
  397.                     console.error(description);
  398.                 } else {
  399.                     less.logger.info('lessc: wrote ' + output);
  400.                     onSuccess();
  401.                 }
  402.             });
  403.         } else if (!options.depends) {
  404.             process.stdout.write(result.css);
  405.             onSuccess();
  406.         }
  407.     };
  408.  
  409.     var logDependencies = function(options, result) {
  410.         if (options.depends) {
  411.             var depends = "";
  412.             for (var i = 0; i < result.imports.length; i++) {
  413.                 depends += result.imports[i] + " ";
  414.             }
  415.             console.log(depends);
  416.         }
  417.     };
  418.  
  419.     var parseLessFile = function (e, data) {
  420.         if (e) {
  421.             console.error("lessc: " + e.message);
  422.             currentErrorcode = 1;
  423.             return;
  424.         }
  425.  
  426.         data = data.replace(/^\uFEFF/, '');
  427.  
  428.         options.paths = [path.dirname(input)].concat(options.paths);
  429.         options.filename = input;
  430.  
  431.         if (options.lint) {
  432.             options.sourceMap = false;
  433.         }
  434.         sourceMapOptions.sourceMapFileInline = sourceMapFileInline;
  435.  
  436.         if (options.sourceMap) {
  437.             options.sourceMap = sourceMapOptions;
  438.         }
  439.  
  440.         less.logger.addListener({
  441.             info: function(msg) {
  442.                 if (verbose) {
  443.                     console.log(msg);
  444.                 }
  445.             },
  446.             warn: function(msg) {
  447.                 // do not show warning if the silent option is used
  448.                 if (!silent) {
  449.                     console.warn(msg);
  450.                 }
  451.             },
  452.             error: function(msg) {
  453.                 console.error(msg);
  454.             }
  455.         });
  456.  
  457.         less.render(data, options)
  458.             .then(function(result) {
  459.                 if (!options.lint) {
  460.                     writeOutput(output, result, function() {
  461.                         writeSourceMapIfNeeded(result.map, function() {
  462.                             logDependencies(options, result);
  463.                         });
  464.                     });
  465.                 }
  466.             },
  467.             function(err) {
  468.                 less.writeError(err, options);
  469.                 currentErrorcode = 1;
  470.             });
  471.     };
  472.  
  473.     if (input != '-') {
  474.         fs.readFile(input, 'utf8', parseLessFile);
  475.     } else {
  476.         process.stdin.resume();
  477.         process.stdin.setEncoding('utf8');
  478.  
  479.         var buffer = '';
  480.         process.stdin.on('data', function(data) {
  481.             buffer += data;
  482.         });
  483.  
  484.         process.stdin.on('end', function() {
  485.             parseLessFile(false, buffer);
  486.         });
  487.     }
  488. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement