UNPKG

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
"use strict"; 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); } };