tsconfig-lint
Version:
A tsconfig tool for running tslint on files found in the tsconfig. Integrates with tsconfig-glob to allow for `filesGlob` in the tsconfig.json.
196 lines (195 loc) • 6.52 kB
JavaScript
;
var fs = require('fs');
var path = require('path');
var glob = require('glob');
var util = require('util');
var os_1 = require('os');
var utils_1 = require('./utils');
var stable = require('stable');
var defaultRules = require('./tsconfig.json').lintOptions;
var Linter = require('tslint');
function log(color, lighten) {
if (lighten === void 0) { lighten = 0; }
var strColor;
if (Array.isArray(color)) {
strColor = ['\x1B[' + (color[0] + lighten) + 'm', '\x1B[' + color[1] + 'm'];
}
else {
strColor = ['', ''];
}
return function (message) {
console.log(strColor[0] + message + strColor[1]);
};
}
var colors = util.inspect.colors, red = log(colors.red, 60), green = log(colors.green), cyan = log(colors.cyan), normal = log();
function unique(arr) {
var keys = {}, out = [];
for (var i = 0, l = arr.length; i < l; ++i) {
if (keys.hasOwnProperty(arr[i])) {
continue;
}
out.push(arr[i]);
keys[arr[i]] = true;
}
return out;
}
function sort(a, b) {
var aTsd = a.indexOf('tsd.d.ts') > -1, bTsd = b.indexOf('tsd.d.ts') > -1, aD = a.indexOf('.d.ts') > -1, bD = b.indexOf('.d.ts') > -1;
if (aTsd) {
return -1;
}
if (bTsd) {
return 1;
}
if (aD && bD) {
return 0;
}
if (aD) {
return -1;
}
if (bD) {
return 1;
}
return 0;
}
function getFiles(options, configFile) {
var root = options.cwd || process.cwd(), configDir = path.resolve(root, options.configPath || '.'), exclude = configFile.exclude || [], files = configFile.files || [];
if (options.useGlob) {
files = configFile.include || configFile.filesGlob || [];
}
if (files.length === 0) {
exclude = exclude.map(function (file) {
if (file.slice(file.length - 3) !== '.ts') {
file = file + '/**/*.ts';
}
return '!' + file;
});
files = ['**/*.ts'].concat(exclude);
}
files = unique(files.concat(['!typings/**/*.ts']));
var include = files.filter(function (file) {
return file[0] !== '!';
}), ignore = files.filter(function (file) {
return file[0] === '!';
}), sortedFiles = [];
for (var _i = 0, include_1 = include; _i < include_1.length; _i++) {
var pattern = include_1[_i];
sortedFiles.push(glob.sync(pattern, {
cwd: configDir,
ignore: ignore.map(function (file) { return file.slice(1); })
}));
}
sortedFiles = sortedFiles.map(function (files) {
return stable(files);
});
files = unique(sortedFiles.reduce(function (files, current) {
return files.concat(current);
}, []));
return stable(files, sort);
}
function findRules(config) {
if (config.hasOwnProperty('rules')) {
return config;
}
return config.lintOptions;
}
var es6 = false;
function lintFile(file, config) {
try {
return [(new Linter(file, fs.readFileSync(file, 'utf8'), config)).lint(), file];
}
catch (e) {
if (!es6 && e.message.indexOf('Cannot read property \'text\' of undefined') > -1) {
es6 = true;
delete config.configuration.rules.whitespace;
delete config.configuration.rules['no-use-before-declare'];
delete config.configuration.rules['no-unused-variable'];
cyan("You are using the ES6 destructuring syntax (i.e. \"import {isString} from 'lodash';\")\nWe will remove the following rules allow linting files temporarily to lint these files:\n noUnusedVariableRule\n noUseBeforeDeclareRule\n whitespaceRule");
return lintFile(file, config);
}
else if (e.code === 'ENOENT') {
red("File " + file + " not found.");
}
return [{
failureCount: 0
}, file];
}
}
function lintFiles(files, config) {
var failed = 0;
cyan('Linting ' + files.length + ' file' + (files.length === 1 ? '' : 's'));
files.map(function (file) {
return lintFile(file, config);
})
.sort(function (resultA, resultB) {
var a = resultA[0], b = resultB[0];
if (a.failureCount > b.failureCount) {
return 1;
}
if (b.failureCount > a.failureCount) {
return -1;
}
return 0;
})
.map(function (results) {
var result = results[0];
if (result.failureCount <= 0) {
return '';
}
failed += result.failureCount;
return result.output
.split(/\r\n|\n/)
.map(function (line) {
if (line === '') {
return;
}
return line;
}).join(os_1.EOL);
}).forEach(function (value) {
if (!value) {
return;
}
normal(value);
});
return failed;
}
module.exports = function (options, done) {
var root = options.cwd || process.cwd();
var configDir = path.resolve(root, options.configPath || '.');
var tsLintConfigFilePath = path.resolve(configDir, options.tsLintConfigFilePath || 'tslint.json');
var filePath;
if (configDir.indexOf('.json') === -1) {
filePath = path.resolve(configDir, 'tsconfig.json');
}
else {
filePath = configDir;
}
var configFile = require(filePath);
lint();
function lint() {
var files = getFiles(options, configFile).map(function (file) {
return path.resolve(filePath, '..', file);
});
var configuration = null;
try {
fs.accessSync(tsLintConfigFilePath, fs.F_OK);
var tsLintConfigFile = require(tsLintConfigFilePath);
configuration = utils_1.extend(true, undefined, {}, findRules(tsLintConfigFile));
}
catch (e) {
configuration = utils_1.extend(true, undefined, defaultRules, findRules(configFile));
}
var failed = lintFiles(files, {
formatter: 'prose',
configuration: configuration
});
var message = 'Done with ' + failed + ' failures.';
if (failed > 0) {
red(message);
}
else {
green(message);
}
done(undefined, failed);
}
};