htmllint-cli
Version:
A simple cli for htmllint.
165 lines (135 loc) • 4.87 kB
JavaScript
var chalk = require('chalk'),
cjson = require('cjson'),
Liftoff = require('liftoff'),
fs = require('fs'),
glob = require('glob'),
path = require('path'),
Promise = require('bluebird');
var readFilePromise = Promise.promisify(fs.readFile),
globPromise = Promise.promisify(glob);
var app = new Liftoff({
processTitle: 'htmllint',
moduleName: 'htmllint',
configName: '.htmllint',
extensions: {
'rc': null
}
});
var argv = require('yargs')
.usage([
'Lints html files with htmllint.',
'Usage: $0 [OPTIONS] [ARGS]'
].join('\n'))
.example('$0', 'lints all html files in the cwd and all child directories')
.example('$0 init', 'creates a default .htmllintrc in the cwd')
.example('$0 *.html', 'lints all html files in the cwd')
.example('$0 public/*.html', 'lints all html files in the public directory')
.default('rc', null)
.describe('rc', 'path to a htmllintrc file to use (json)')
.default('cwd', null)
.describe('cwd', 'path to use for the current working directory')
.argv;
var args = argv._;
app.launch({
cwd: argv.cwd,
configPath: argv.rc
}, function (env) {
var cwd = argv.cwd || process.cwd();
var htmllintPath = 'htmllint';
if (env.modulePath) {
var cliPackage = require('../package.json'),
semver = require('semver');
var acceptedRange = cliPackage.dependencies.htmllint,
localVersion = env.modulePackage.version;
if (semver.satisfies(localVersion, acceptedRange)) {
htmllintPath = env.modulePath;
} else {
console.log(
chalk.red('local htmllint version is not supported:'),
chalk.magenta(localVersion, '!=', acceptedRange)
);
console.log('using builtin version of htmllint');
}
}
var htmllint = require(htmllintPath);
if (args[0] === 'init') {
// copy .htmllintrc file
var srcPath = path.join(__dirname, '../lib/default_cfg.json'),
outputPath = path.join(env.cwd, '.htmllintrc');
var opts = htmllint.Linter.getOptions('default'),
config = JSON.stringify(opts, null, 4);
config = '{\n "plugins": [], // npm modules to load\n'
+ config.slice(1);
fs.writeFile(outputPath, config, function (err) {
if (err) {
console.error('error writing config file: ', err);
}
});
return;
}
if (!env.configPath) {
console.log(
chalk.red('local .htmllintrc file not found'),
'(you can create one using "htmllint init")'
);
process.exit(1);
}
var cfg = cjson.load(env.configPath);
htmllint.use(cfg.plugins || []);
delete cfg.plugins;
if (!args.length) {
args = ['**/*.html'];
}
function lintFile(filename) {
var filepath = path.resolve(cwd, filename);
return readFilePromise(filepath, 'utf8')
.then(function (src) {
return htmllint(src, cfg);
})
.then(function (issues) {
issues.forEach(function (issue) {
var msg = [
chalk.magenta(filename), ': ',
'line ', issue.line, ', ',
'col ', issue.column, ', ',
chalk.red(htmllint.messages.renderIssue(issue))
].join('');
console.log(msg);
});
return { errorCount: issues.length };
})
.catch(function (err) {
// MC: muahahahahah :D
throw ('[htmllint error in ' + filename + ' ] ' + err);
});
}
Promise.all(
args.map(function (pattern) {
return globPromise(pattern, { cwd: cwd });
})
).then(function (filesArr) {
var files = Array.prototype.concat.apply([], filesArr);
return Promise.settle(
files.map(lintFile)
);
}, function (err) {
console.error(chalk.red.bold('error during glob expansion:'), err);
}).done(function (results) {
var errorCount = 0;
console.log('');
results.forEach(function (result) {
if (result.isFulfilled()) {
var resultValue = result.value();
errorCount += resultValue.errorCount;
} else {
console.error(chalk.bold.red(result.reason()));
}
});
console.log(chalk.yellow('[htmllint] found %d errors out of %d files'),
errorCount, results.length);
if (errorCount > 0) {
process.exit(1);
}
});
});