1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | Object.defineProperty(exports, "__esModule", { value: true });
|
19 | var tslib_1 = require("tslib");
|
20 | var fs = require("fs");
|
21 | var path = require("path");
|
22 | var ts = require("typescript");
|
23 | var configuration_1 = require("./configuration");
|
24 | var enableDisableRules_1 = require("./enableDisableRules");
|
25 | var error_1 = require("./error");
|
26 | var formatterLoader_1 = require("./formatterLoader");
|
27 | var rule_1 = require("./language/rule/rule");
|
28 | var utils = require("./language/utils");
|
29 | var ruleLoader_1 = require("./ruleLoader");
|
30 | var utils_1 = require("./utils");
|
31 |
|
32 |
|
33 |
|
34 | var Linter = (function () {
|
35 | function Linter(options, program) {
|
36 | this.options = options;
|
37 | this.program = program;
|
38 | this.failures = [];
|
39 | this.fixes = [];
|
40 | if (typeof options !== "object") {
|
41 | throw new Error("Unknown Linter options type: " + typeof options);
|
42 | }
|
43 | if (options.configuration != undefined) {
|
44 | throw new Error("ILinterOptions does not contain the property `configuration` as of version 4. " +
|
45 | "Did you mean to pass the `IConfigurationFile` object to lint() ? ");
|
46 | }
|
47 | }
|
48 | |
49 |
|
50 |
|
51 | Linter.createProgram = function (configFile, projectDirectory) {
|
52 | if (projectDirectory === void 0) { projectDirectory = path.dirname(configFile); }
|
53 | var config = ts.readConfigFile(configFile, ts.sys.readFile);
|
54 | if (config.error !== undefined) {
|
55 | throw new error_1.FatalError(ts.formatDiagnostics([config.error], {
|
56 | getCanonicalFileName: function (f) { return f; },
|
57 | getCurrentDirectory: process.cwd,
|
58 | getNewLine: function () { return "\n"; },
|
59 | }));
|
60 | }
|
61 | var parseConfigHost = {
|
62 | fileExists: fs.existsSync,
|
63 | readDirectory: ts.sys.readDirectory,
|
64 | readFile: function (file) { return fs.readFileSync(file, "utf8"); },
|
65 | useCaseSensitiveFileNames: true,
|
66 | };
|
67 | var parsed = ts.parseJsonConfigFileContent(config.config, parseConfigHost, path.resolve(projectDirectory), { noEmit: true });
|
68 | if (parsed.errors !== undefined) {
|
69 |
|
70 | var errors = parsed.errors.filter(function (d) { return d.category === ts.DiagnosticCategory.Error && d.code !== 18003; });
|
71 | if (errors.length !== 0) {
|
72 | throw new error_1.FatalError(ts.formatDiagnostics(errors, {
|
73 | getCanonicalFileName: function (f) { return f; },
|
74 | getCurrentDirectory: process.cwd,
|
75 | getNewLine: function () { return "\n"; },
|
76 | }));
|
77 | }
|
78 | }
|
79 | var host = ts.createCompilerHost(parsed.options, true);
|
80 | var program = ts.createProgram(parsed.fileNames, parsed.options, host);
|
81 | return program;
|
82 | };
|
83 | |
84 |
|
85 |
|
86 |
|
87 | Linter.getFileNames = function (program) {
|
88 | return utils_1.mapDefined(program.getSourceFiles(), function (file) {
|
89 | return file.fileName.endsWith(".d.ts") || program.isSourceFileFromExternalLibrary(file)
|
90 | ? undefined
|
91 | : file.fileName;
|
92 | });
|
93 | };
|
94 | Linter.prototype.lint = function (fileName, source, configuration) {
|
95 | if (configuration === void 0) { configuration = configuration_1.DEFAULT_CONFIG; }
|
96 | var sourceFile = this.getSourceFile(fileName, source);
|
97 | var isJs = /\.jsx?$/i.test(fileName);
|
98 | var enabledRules = this.getEnabledRules(configuration, isJs);
|
99 | var fileFailures = this.getAllFailures(sourceFile, enabledRules);
|
100 | if (fileFailures.length === 0) {
|
101 |
|
102 | return;
|
103 | }
|
104 | if (this.options.fix && fileFailures.some(function (f) { return f.hasFix(); })) {
|
105 | fileFailures = this.applyAllFixes(enabledRules, fileFailures, sourceFile, fileName);
|
106 | }
|
107 |
|
108 | var ruleSeverityMap = new Map(enabledRules.map(function (rule) { return [rule.getOptions().ruleName, rule.getOptions().ruleSeverity]; }));
|
109 | for (var _i = 0, fileFailures_1 = fileFailures; _i < fileFailures_1.length; _i++) {
|
110 | var failure = fileFailures_1[_i];
|
111 | var severity = ruleSeverityMap.get(failure.getRuleName());
|
112 | if (severity === undefined) {
|
113 | throw new Error("Severity for rule '" + failure.getRuleName() + "' not found");
|
114 | }
|
115 | failure.setRuleSeverity(severity);
|
116 | }
|
117 | this.failures = this.failures.concat(fileFailures);
|
118 | };
|
119 | Linter.prototype.getResult = function () {
|
120 | var formatterName = this.options.formatter !== undefined ? this.options.formatter : "prose";
|
121 | var Formatter = formatterLoader_1.findFormatter(formatterName, this.options.formattersDirectory);
|
122 | if (Formatter === undefined) {
|
123 | throw new Error("formatter '" + formatterName + "' not found");
|
124 | }
|
125 | var formatter = new Formatter();
|
126 | var output = formatter.format(this.failures, this.fixes);
|
127 | var errorCount = this.failures.filter(function (failure) { return failure.getRuleSeverity() === "error"; }).length;
|
128 | return {
|
129 | errorCount: errorCount,
|
130 | failures: this.failures,
|
131 | fixes: this.fixes,
|
132 | format: formatterName,
|
133 | output: output,
|
134 | warningCount: this.failures.length - errorCount,
|
135 | };
|
136 | };
|
137 | Linter.prototype.getAllFailures = function (sourceFile, enabledRules) {
|
138 | var _this = this;
|
139 | var failures = utils_1.flatMap(enabledRules, function (rule) { return _this.applyRule(rule, sourceFile); });
|
140 | return enableDisableRules_1.removeDisabledFailures(sourceFile, failures);
|
141 | };
|
142 | Linter.prototype.applyAllFixes = function (enabledRules, fileFailures, sourceFile, sourceFileName) {
|
143 |
|
144 |
|
145 | var source = sourceFile.text;
|
146 | var _loop_1 = function (rule) {
|
147 | var hasFixes = fileFailures.some(function (f) { return f.hasFix() && f.getRuleName() === rule.getOptions().ruleName; });
|
148 | if (hasFixes) {
|
149 |
|
150 | var updatedFailures = enableDisableRules_1.removeDisabledFailures(sourceFile, this_1.applyRule(rule, sourceFile));
|
151 | var fixableFailures = updatedFailures.filter(function (f) { return f.hasFix(); });
|
152 | this_1.fixes = this_1.fixes.concat(fixableFailures);
|
153 | source = this_1.applyFixes(sourceFileName, source, fixableFailures);
|
154 | sourceFile = this_1.getSourceFile(sourceFileName, source);
|
155 | }
|
156 | };
|
157 | var this_1 = this;
|
158 | for (var _i = 0, enabledRules_1 = enabledRules; _i < enabledRules_1.length; _i++) {
|
159 | var rule = enabledRules_1[_i];
|
160 | _loop_1(rule);
|
161 | }
|
162 |
|
163 | return this.getAllFailures(sourceFile, enabledRules);
|
164 | };
|
165 |
|
166 |
|
167 | Linter.prototype.applyFixes = function (sourceFilePath, source, fixableFailures) {
|
168 | var _this = this;
|
169 | var fixesByFile = createMultiMap(fixableFailures, function (f) { return [f.getFileName(), f.getFix()]; });
|
170 | fixesByFile.forEach(function (fileFixes, filePath) {
|
171 | var fileNewSource;
|
172 | if (path.resolve(filePath) === path.resolve(sourceFilePath)) {
|
173 | source = rule_1.Replacement.applyFixes(source, fileFixes);
|
174 | fileNewSource = source;
|
175 | }
|
176 | else {
|
177 | var oldSource = fs.readFileSync(filePath, "utf-8");
|
178 | fileNewSource = rule_1.Replacement.applyFixes(oldSource, fileFixes);
|
179 | }
|
180 | fs.writeFileSync(filePath, fileNewSource);
|
181 | _this.updateProgram(filePath);
|
182 | });
|
183 | return source;
|
184 | };
|
185 | Linter.prototype.updateProgram = function (sourceFilePath) {
|
186 | if (this.program !== undefined && this.program.getSourceFile(sourceFilePath) !== undefined) {
|
187 | var options = this.program.getCompilerOptions();
|
188 | this.program = ts.createProgram(this.program.getRootFileNames(), options, ts.createCompilerHost(options, true), this.program);
|
189 | }
|
190 | };
|
191 | Linter.prototype.applyRule = function (rule, sourceFile) {
|
192 | try {
|
193 | if (this.program !== undefined && rule_1.isTypedRule(rule)) {
|
194 | return rule.applyWithProgram(sourceFile, this.program);
|
195 | }
|
196 | else {
|
197 | return rule.apply(sourceFile);
|
198 | }
|
199 | }
|
200 | catch (error) {
|
201 | if (error_1.isError(error) && error.stack !== undefined) {
|
202 | error_1.showRuleCrashWarning(error.stack, rule.getOptions().ruleName, sourceFile.fileName);
|
203 | }
|
204 | else {
|
205 | error_1.showRuleCrashWarning(String(error), rule.getOptions().ruleName, sourceFile.fileName);
|
206 | }
|
207 | return [];
|
208 | }
|
209 | };
|
210 | Linter.prototype.getEnabledRules = function (configuration, isJs) {
|
211 | if (configuration === void 0) { configuration = configuration_1.DEFAULT_CONFIG; }
|
212 | var ruleOptionsList = configuration_1.convertRuleOptions(isJs ? configuration.jsRules : configuration.rules);
|
213 | var rulesDirectories = utils_1.arrayify(this.options.rulesDirectory)
|
214 | .concat(utils_1.arrayify(configuration.rulesDirectory));
|
215 | return ruleLoader_1.loadRules(ruleOptionsList, rulesDirectories, isJs);
|
216 | };
|
217 | Linter.prototype.getSourceFile = function (fileName, source) {
|
218 | if (this.program !== undefined) {
|
219 | var sourceFile = this.program.getSourceFile(fileName);
|
220 | if (sourceFile === undefined) {
|
221 | var INVALID_SOURCE_ERROR = utils_1.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n Invalid source file: ", ". Ensure that the files supplied to lint have a .ts, .tsx, .d.ts, .js or .jsx extension.\n "], ["\n Invalid source file: ", ". Ensure that the files supplied to lint have a .ts, .tsx, .d.ts, .js or .jsx extension.\n "])), fileName);
|
222 | throw new error_1.FatalError(INVALID_SOURCE_ERROR);
|
223 | }
|
224 | return sourceFile;
|
225 | }
|
226 | else {
|
227 | return utils.getSourceFile(fileName, source);
|
228 | }
|
229 | };
|
230 | Linter.VERSION = "5.10.0";
|
231 | Linter.findConfiguration = configuration_1.findConfiguration;
|
232 | Linter.findConfigurationPath = configuration_1.findConfigurationPath;
|
233 | Linter.getRulesDirectories = configuration_1.getRulesDirectories;
|
234 | Linter.loadConfigurationFromPath = configuration_1.loadConfigurationFromPath;
|
235 | return Linter;
|
236 | }());
|
237 | exports.Linter = Linter;
|
238 | function createMultiMap(inputs, getPair) {
|
239 | var map = new Map();
|
240 | for (var _i = 0, inputs_1 = inputs; _i < inputs_1.length; _i++) {
|
241 | var input = inputs_1[_i];
|
242 | var pair = getPair(input);
|
243 | if (pair !== undefined) {
|
244 | var k = pair[0], v = pair[1];
|
245 | var vs = map.get(k);
|
246 | if (vs !== undefined) {
|
247 | vs.push(v);
|
248 | }
|
249 | else {
|
250 | map.set(k, [v]);
|
251 | }
|
252 | }
|
253 | }
|
254 | return map;
|
255 | }
|
256 | var templateObject_1;
|