UNPKG

11.4 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright 2018 Palantir Technologies, Inc.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18Object.defineProperty(exports, "__esModule", { value: true });
19var chalk_1 = require("chalk");
20var diff = require("diff");
21var fs = require("fs");
22var glob = require("glob");
23var path = require("path");
24var semver = require("semver");
25var ts = require("typescript");
26var rule_1 = require("./language/rule/rule");
27var linter_1 = require("./linter");
28var utils_1 = require("./utils");
29var parse = require("./verify/parse");
30var MARKUP_FILE_EXTENSION = ".lint";
31var FIXES_FILE_EXTENSION = ".fix";
32function runTests(patterns, rulesDirectory) {
33 var files = [];
34 for (var _i = 0, patterns_1 = patterns; _i < patterns_1.length; _i++) {
35 var pattern = patterns_1[_i];
36 if (path.basename(pattern) !== "tslint.json") {
37 pattern = path.join(pattern, "tslint.json");
38 }
39 files.push.apply(files, glob.sync(pattern));
40 }
41 return files.map(function (directory) { return runTest(path.dirname(directory), rulesDirectory); });
42}
43exports.runTests = runTests;
44function runTest(testDirectory, rulesDirectory) {
45 var filesToLint = glob.sync(path.join(testDirectory, "**/*" + MARKUP_FILE_EXTENSION));
46 var tslintConfig = linter_1.Linter.findConfiguration(path.join(testDirectory, "tslint.json"), "")
47 .results;
48 var tsConfig = path.join(testDirectory, "tsconfig.json");
49 var compilerOptions = { allowJs: true };
50 var hasConfig = fs.existsSync(tsConfig);
51 if (hasConfig) {
52 var _a = ts.readConfigFile(tsConfig, ts.sys.readFile), config = _a.config, error = _a.error;
53 if (error !== undefined) {
54 throw new Error(ts.formatDiagnostics([error], ts.createCompilerHost({})));
55 }
56 var parseConfigHost = {
57 fileExists: fs.existsSync,
58 readDirectory: ts.sys.readDirectory,
59 readFile: function (file) { return fs.readFileSync(file, "utf8"); },
60 useCaseSensitiveFileNames: true,
61 };
62 compilerOptions = ts.parseJsonConfigFileContent(config, parseConfigHost, testDirectory)
63 .options;
64 }
65 var results = { directory: testDirectory, results: {} };
66 var _loop_1 = function (fileToLint) {
67 var isEncodingRule = path.basename(testDirectory) === "encoding";
68 var fileCompileName = utils_1.denormalizeWinPath(path.resolve(fileToLint.replace(/\.lint$/, "")));
69 var fileText = isEncodingRule
70 ? utils_1.readBufferWithDetectedEncoding(fs.readFileSync(fileToLint))
71 : fs.readFileSync(fileToLint, "utf-8");
72 var tsVersionRequirement = parse.getTypescriptVersionRequirement(fileText);
73 if (tsVersionRequirement !== undefined) {
74 // remove prerelease suffix when matching to allow testing with nightly builds
75 if (!semver.satisfies(parse.getNormalizedTypescriptVersion(), tsVersionRequirement)) {
76 results.results[fileToLint] = {
77 requirement: tsVersionRequirement,
78 skipped: true,
79 };
80 return "continue";
81 }
82 // remove the first line from the file before continuing
83 var lineBreak = fileText.search(/\n/);
84 fileText = lineBreak === -1 ? "" : fileText.substr(lineBreak + 1);
85 }
86 fileText = parse.preprocessDirectives(fileText);
87 var fileTextWithoutMarkup = parse.removeErrorMarkup(fileText);
88 var errorsFromMarkup = parse.parseErrorsFromMarkup(fileText);
89 var program = void 0;
90 if (hasConfig) {
91 var compilerHost = {
92 fileExists: function (file) { return file === fileCompileName || fs.existsSync(file); },
93 getCanonicalFileName: function (filename) { return filename; },
94 getCurrentDirectory: function () { return process.cwd(); },
95 getDefaultLibFileName: function () { return ts.getDefaultLibFileName(compilerOptions); },
96 getDirectories: function (dir) { return fs.readdirSync(dir); },
97 getNewLine: function () { return "\n"; },
98 getSourceFile: function (filenameToGet, target) {
99 if (utils_1.denormalizeWinPath(filenameToGet) === fileCompileName) {
100 return ts.createSourceFile(filenameToGet, fileTextWithoutMarkup, target, true);
101 }
102 if (path.basename(filenameToGet) === filenameToGet) {
103 // resolve path of lib.xxx.d.ts
104 filenameToGet = path.join(path.dirname(ts.getDefaultLibFilePath(compilerOptions)), filenameToGet);
105 }
106 var text = fs.readFileSync(filenameToGet, "utf8");
107 return ts.createSourceFile(filenameToGet, text, target, true);
108 },
109 readFile: function (x) { return x; },
110 useCaseSensitiveFileNames: function () { return true; },
111 writeFile: function () { return null; },
112 };
113 program = ts.createProgram([fileCompileName], compilerOptions, compilerHost);
114 }
115 var lintOptions = {
116 fix: false,
117 formatter: "prose",
118 formattersDirectory: "",
119 rulesDirectory: rulesDirectory,
120 };
121 var linter = new linter_1.Linter(lintOptions, program);
122 // Need to use the true path (ending in '.lint') for "encoding" rule so that it can read the file.
123 linter.lint(isEncodingRule ? fileToLint : fileCompileName, fileTextWithoutMarkup, tslintConfig);
124 var failures = linter.getResult().failures;
125 var errorsFromLinter = failures.map(function (failure) {
126 var startLineAndCharacter = failure.getStartPosition().getLineAndCharacter();
127 var endLineAndCharacter = failure.getEndPosition().getLineAndCharacter();
128 return {
129 endPos: {
130 col: endLineAndCharacter.character,
131 line: endLineAndCharacter.line,
132 },
133 message: failure.getFailure(),
134 startPos: {
135 col: startLineAndCharacter.character,
136 line: startLineAndCharacter.line,
137 },
138 };
139 });
140 // test against fixed files
141 var fixedFileText = "";
142 var newFileText = "";
143 try {
144 var fixedFile = fileToLint.replace(/\.lint$/, FIXES_FILE_EXTENSION);
145 var stat = fs.statSync(fixedFile);
146 if (stat.isFile()) {
147 fixedFileText = fs.readFileSync(fixedFile, "utf8");
148 var fixes = utils_1.mapDefined(failures, function (f) { return f.getFix(); });
149 newFileText = rule_1.Replacement.applyFixes(fileTextWithoutMarkup, fixes);
150 }
151 }
152 catch (e) {
153 fixedFileText = "";
154 newFileText = "";
155 }
156 results.results[fileToLint] = {
157 errorsFromLinter: errorsFromLinter,
158 errorsFromMarkup: errorsFromMarkup,
159 fixesFromLinter: newFileText,
160 fixesFromMarkup: fixedFileText,
161 markupFromLinter: parse.createMarkupFromErrors(fileTextWithoutMarkup, errorsFromMarkup),
162 markupFromMarkup: parse.createMarkupFromErrors(fileTextWithoutMarkup, errorsFromLinter),
163 skipped: false,
164 };
165 };
166 for (var _i = 0, filesToLint_1 = filesToLint; _i < filesToLint_1.length; _i++) {
167 var fileToLint = filesToLint_1[_i];
168 _loop_1(fileToLint);
169 }
170 return results;
171}
172exports.runTest = runTest;
173function consoleTestResultsHandler(testResults, logger) {
174 var didAllTestsPass = true;
175 for (var _i = 0, testResults_1 = testResults; _i < testResults_1.length; _i++) {
176 var testResult = testResults_1[_i];
177 if (!consoleTestResultHandler(testResult, logger)) {
178 didAllTestsPass = false;
179 }
180 }
181 return didAllTestsPass;
182}
183exports.consoleTestResultsHandler = consoleTestResultsHandler;
184function consoleTestResultHandler(testResult, logger) {
185 // needed to get colors to show up when passing through Grunt
186 chalk_1.default.enabled = true;
187 var didAllTestsPass = true;
188 for (var _i = 0, _a = Object.keys(testResult.results); _i < _a.length; _i++) {
189 var fileName = _a[_i];
190 var results = testResult.results[fileName];
191 logger.log(fileName + ":");
192 if (results.skipped) {
193 logger.log(chalk_1.default.yellow(" Skipped, requires typescript " + results.requirement + "\n"));
194 }
195 else {
196 var markupDiffResults = diff.diffLines(results.markupFromMarkup, results.markupFromLinter);
197 var fixesDiffResults = diff.diffLines(results.fixesFromLinter, results.fixesFromMarkup);
198 var didMarkupTestPass = !markupDiffResults.some(function (hunk) { return hunk.added === true || hunk.removed === true; });
199 var didFixesTestPass = !fixesDiffResults.some(function (hunk) { return hunk.added === true || hunk.removed === true; });
200 if (didMarkupTestPass && didFixesTestPass) {
201 logger.log(chalk_1.default.green(" Passed\n"));
202 }
203 else {
204 logger.log(chalk_1.default.red(" Failed!\n"));
205 didAllTestsPass = false;
206 if (!didMarkupTestPass) {
207 displayDiffResults(markupDiffResults, MARKUP_FILE_EXTENSION, logger);
208 }
209 if (!didFixesTestPass) {
210 displayDiffResults(fixesDiffResults, FIXES_FILE_EXTENSION, logger);
211 }
212 }
213 }
214 }
215 return didAllTestsPass;
216}
217exports.consoleTestResultHandler = consoleTestResultHandler;
218function displayDiffResults(diffResults, extension, logger) {
219 logger.log(chalk_1.default.green("Expected (from " + extension + " file)\n"));
220 logger.log(chalk_1.default.red("Actual (from TSLint)\n"));
221 var _loop_2 = function (diffResult) {
222 var color = chalk_1.default.grey;
223 var prefix = " ";
224 if (diffResult.added) {
225 color = chalk_1.default.green.underline;
226 prefix = "+ ";
227 }
228 else if (diffResult.removed) {
229 color = chalk_1.default.red.underline;
230 prefix = "- ";
231 }
232 logger.log(color(diffResult.value
233 .split(/\r\n|\r|\n/)
234 // strings end on a newline which we do not want to include the prefix.
235 // tslint:disable-next-line:prefer-template
236 .map(function (line, index, array) {
237 return index === array.length - 1 ? line : "" + prefix + line + "\n";
238 })
239 .join("")));
240 };
241 for (var _i = 0, diffResults_1 = diffResults; _i < diffResults_1.length; _i++) {
242 var diffResult = diffResults_1[_i];
243 _loop_2(diffResult);
244 }
245}