'use strict'; /** * Command line implementation for CSSComb * * Usage example: * ./node_modules/.bin/csscomb [options] [file1 [dir1 [fileN [dirN]]]] */ var fs = require('fs'); var parseArgs = require('minimist'); var path = require('path'); var os = require('os'); var Comb = require('./csscomb'); var Errors = require('./errors'); var getInputData = new Promise(function(resolve) { var input = ''; process.stdin.resume(); process.stdin.setEncoding('utf8'); process.stdin.on('data', function(data) { input += data; }); process.stdin.on('end', function() { resolve(input); }); }); var comb = new Comb(); var options = getOptions(); if (options.help) { displayHelp(); process.exit(0); } if (options.detect) { const config = detectConfig(); process.stdout.write(config); process.exit(0); } var config = getConfig(); comb.configure(config); if (options['tty-mode'] || process.stdin.isTTY) { processFiles(options._); } else { processSTDIN(); } function getOptions() { var parserOptions = { boolean: ['help', 'lint', 'verbose', 'tty-mode'], alias: { config: 'c', detect: 'd', lint: 'l', help: 'h', verbose: 'v', 'tty-mode': 't' } }; return parseArgs(process.argv.slice(2), parserOptions); } function displayHelp() { var help = [ 'NAME', ' csscomb — Lint and fix style errors in css files', '', 'SYNOPSIS', ' csscomb [options] file.css', ' cat file.css | csscomb [options] -', '', 'OPTIONS', ' -c, --config [path]', ' Path to configuration file.', ' -d, --detect', ' Run the tool in detect mode, returning detected options.', ' -l, --lint', ' Run the tool in linter mode, without modifying files.', ' -h, --help', ' Display help message.', ' -v, --verbose', ' Whether to print logging info.', ' -t, --tty-mode', ' Run the tool in TTY mode using external app (e.g. IDE).', '' ]; process.stdout.write(help.join(os.EOL)); } function detectConfig() { const config = Comb.detectInFile(options.detect); return JSON.stringify(config, false, 4); } function getConfig() { var configPath = options.config && path.resolve(process.cwd(), options.config) || Comb.getCustomConfigPath(); var config; if (!fs.existsSync(configPath)) { config = require('../config/csscomb.json'); } else if (configPath.match(/\.css$/)) { config = Comb.detectInFile(configPath); } else { config = Comb.getCustomConfig(configPath); } if (!config) { const errorMessage = Errors.configParsingError(configPath); process.stderr.write(errorMessage); process.exit(1); } applyTemplate(config); if (options.verbose) config.verbose = options.verbose; if (options.lint) config.lint = options.lint; return config; } function applyTemplate(config) { if (!config.template) return; if (!fs.existsSync(config.template)) { const errorMessage = Errors.missingTemplateFile(config.template); process.stderr.write(errorMessage); process.exit(1); } var templateConfig = Comb.detectInFile(config.template); for (var attrname in templateConfig) { if (templateConfig.hasOwnProperty(attrname) && !config[attrname]) { config[attrname] = templateConfig[attrname]; } } } function processFiles(files) { const promises = files.map(file => { return comb.processPath(file); }); Promise.all(promises).catch(error => { process.stderr.write(error.stack); process.exit(1); }).then(c => { c = [].concat.apply([], c); var tbchanged = c.filter(isChanged => { return isChanged !== undefined; }).reduce((a, b) => { return a + b; }, 0); var changed = options.lint ? 0 : tbchanged; if (options.verbose) { let message = [ `${c.length} file${c.length === 1 ? '' : 's'} processed`, `${changed} file${changed === 1 ? '' : 's'} fixed`, '' ].join(os.EOL); process.stdout.write(message); } if (options.lint && tbchanged) { process.exit(1); } process.exit(0); }); } function processSTDIN() { getInputData.then(processInputData); } function processInputData(input) { comb.processString(input).catch(e => { process.stderr.write(e.message); process.exit(1); }).then(output => { process.stdout.write(output); process.exit(0); }); }