247 lines
11 KiB
JavaScript
247 lines
11 KiB
JavaScript
|
"use strict";
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2018 Palantir Technologies, Inc.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
exports.consoleTestResultHandler = exports.consoleTestResultsHandler = exports.runTest = exports.runTests = void 0;
|
||
|
var chalk_1 = require("chalk");
|
||
|
var diff = require("diff");
|
||
|
var fs = require("fs");
|
||
|
var glob = require("glob");
|
||
|
var path = require("path");
|
||
|
var semver = require("semver");
|
||
|
var ts = require("typescript");
|
||
|
var rule_1 = require("./language/rule/rule");
|
||
|
var linter_1 = require("./linter");
|
||
|
var utils_1 = require("./utils");
|
||
|
var parse = require("./verify/parse");
|
||
|
var MARKUP_FILE_EXTENSION = ".lint";
|
||
|
var FIXES_FILE_EXTENSION = ".fix";
|
||
|
function runTests(patterns, rulesDirectory) {
|
||
|
var files = [];
|
||
|
for (var _i = 0, patterns_1 = patterns; _i < patterns_1.length; _i++) {
|
||
|
var pattern = patterns_1[_i];
|
||
|
if (path.basename(pattern) !== "tslint.json") {
|
||
|
pattern = path.join(pattern, "tslint.json");
|
||
|
}
|
||
|
files.push.apply(files, glob.sync(pattern));
|
||
|
}
|
||
|
return files.map(function (directory) { return runTest(path.dirname(directory), rulesDirectory); });
|
||
|
}
|
||
|
exports.runTests = runTests;
|
||
|
function runTest(testDirectory, rulesDirectory) {
|
||
|
var filesToLint = glob.sync(path.join(testDirectory, "**/*" + MARKUP_FILE_EXTENSION));
|
||
|
var tslintConfig = linter_1.Linter.findConfiguration(path.join(testDirectory, "tslint.json"), "")
|
||
|
.results;
|
||
|
var tsConfig = path.join(testDirectory, "tsconfig.json");
|
||
|
var compilerOptions = { allowJs: true };
|
||
|
var hasConfig = fs.existsSync(tsConfig);
|
||
|
if (hasConfig) {
|
||
|
var _a = ts.readConfigFile(tsConfig, ts.sys.readFile), config = _a.config, error = _a.error;
|
||
|
if (error !== undefined) {
|
||
|
throw new Error(ts.formatDiagnostics([error], ts.createCompilerHost({})));
|
||
|
}
|
||
|
var parseConfigHost = {
|
||
|
fileExists: fs.existsSync,
|
||
|
readDirectory: ts.sys.readDirectory,
|
||
|
readFile: function (file) { return fs.readFileSync(file, "utf8"); },
|
||
|
useCaseSensitiveFileNames: true,
|
||
|
};
|
||
|
compilerOptions = ts.parseJsonConfigFileContent(config, parseConfigHost, testDirectory)
|
||
|
.options;
|
||
|
}
|
||
|
var results = { directory: testDirectory, results: {} };
|
||
|
var _loop_1 = function (fileToLint) {
|
||
|
var isEncodingRule = path.basename(testDirectory) === "encoding";
|
||
|
var fileCompileName = utils_1.denormalizeWinPath(path.resolve(fileToLint.replace(/\.lint$/, "")));
|
||
|
var fileText = isEncodingRule
|
||
|
? utils_1.readBufferWithDetectedEncoding(fs.readFileSync(fileToLint))
|
||
|
: fs.readFileSync(fileToLint, "utf-8");
|
||
|
var tsVersionRequirement = parse.getTypescriptVersionRequirement(fileText);
|
||
|
if (tsVersionRequirement !== undefined) {
|
||
|
// remove prerelease suffix when matching to allow testing with nightly builds
|
||
|
if (!semver.satisfies(parse.getNormalizedTypescriptVersion(), tsVersionRequirement)) {
|
||
|
results.results[fileToLint] = {
|
||
|
requirement: tsVersionRequirement,
|
||
|
skipped: true,
|
||
|
};
|
||
|
return "continue";
|
||
|
}
|
||
|
// remove the first line from the file before continuing
|
||
|
var lineBreak = fileText.search(/\n/);
|
||
|
fileText = lineBreak === -1 ? "" : fileText.substr(lineBreak + 1);
|
||
|
}
|
||
|
fileText = parse.preprocessDirectives(fileText);
|
||
|
var fileTextWithoutMarkup = parse.removeErrorMarkup(fileText);
|
||
|
var errorsFromMarkup = parse.parseErrorsFromMarkup(fileText);
|
||
|
var program = void 0;
|
||
|
if (hasConfig) {
|
||
|
var compilerHost = {
|
||
|
fileExists: function (file) { return file === fileCompileName || fs.existsSync(file); },
|
||
|
getCanonicalFileName: function (filename) { return filename; },
|
||
|
getCurrentDirectory: function () { return process.cwd(); },
|
||
|
getDefaultLibFileName: function () { return ts.getDefaultLibFileName(compilerOptions); },
|
||
|
getDirectories: function (dir) { return fs.readdirSync(dir); },
|
||
|
getNewLine: function () { return "\n"; },
|
||
|
getSourceFile: function (filenameToGet, target) {
|
||
|
if (utils_1.denormalizeWinPath(filenameToGet) === fileCompileName) {
|
||
|
return ts.createSourceFile(filenameToGet, fileTextWithoutMarkup, target, true);
|
||
|
}
|
||
|
if (path.basename(filenameToGet) === filenameToGet) {
|
||
|
// resolve path of lib.xxx.d.ts
|
||
|
filenameToGet = path.join(path.dirname(ts.getDefaultLibFilePath(compilerOptions)), filenameToGet);
|
||
|
}
|
||
|
var text = fs.readFileSync(filenameToGet, "utf8");
|
||
|
return ts.createSourceFile(filenameToGet, text, target, true);
|
||
|
},
|
||
|
readFile: function (x) { return x; },
|
||
|
useCaseSensitiveFileNames: function () { return true; },
|
||
|
writeFile: function () { return null; },
|
||
|
};
|
||
|
program = ts.createProgram([fileCompileName], compilerOptions, compilerHost);
|
||
|
}
|
||
|
var lintOptions = {
|
||
|
fix: false,
|
||
|
formatter: "prose",
|
||
|
formattersDirectory: "",
|
||
|
rulesDirectory: rulesDirectory,
|
||
|
};
|
||
|
var linter = new linter_1.Linter(lintOptions, program);
|
||
|
// Need to use the true path (ending in '.lint') for "encoding" rule so that it can read the file.
|
||
|
linter.lint(isEncodingRule ? fileToLint : fileCompileName, fileTextWithoutMarkup, tslintConfig);
|
||
|
var failures = linter.getResult().failures;
|
||
|
var errorsFromLinter = failures.map(function (failure) {
|
||
|
var startLineAndCharacter = failure.getStartPosition().getLineAndCharacter();
|
||
|
var endLineAndCharacter = failure.getEndPosition().getLineAndCharacter();
|
||
|
return {
|
||
|
endPos: {
|
||
|
col: endLineAndCharacter.character,
|
||
|
line: endLineAndCharacter.line,
|
||
|
},
|
||
|
message: failure.getFailure(),
|
||
|
startPos: {
|
||
|
col: startLineAndCharacter.character,
|
||
|
line: startLineAndCharacter.line,
|
||
|
},
|
||
|
};
|
||
|
});
|
||
|
// test against fixed files
|
||
|
var fixedFileText = "";
|
||
|
var newFileText = "";
|
||
|
try {
|
||
|
var fixedFile = fileToLint.replace(/\.lint$/, FIXES_FILE_EXTENSION);
|
||
|
var stat = fs.statSync(fixedFile);
|
||
|
if (stat.isFile()) {
|
||
|
fixedFileText = fs.readFileSync(fixedFile, "utf8");
|
||
|
var fixes = utils_1.mapDefined(failures, function (f) { return f.getFix(); });
|
||
|
newFileText = rule_1.Replacement.applyFixes(fileTextWithoutMarkup, fixes);
|
||
|
}
|
||
|
}
|
||
|
catch (e) {
|
||
|
fixedFileText = "";
|
||
|
newFileText = "";
|
||
|
}
|
||
|
results.results[fileToLint] = {
|
||
|
errorsFromLinter: errorsFromLinter,
|
||
|
errorsFromMarkup: errorsFromMarkup,
|
||
|
fixesFromLinter: newFileText,
|
||
|
fixesFromMarkup: fixedFileText,
|
||
|
markupFromLinter: parse.createMarkupFromErrors(fileToLint, fileTextWithoutMarkup, errorsFromMarkup),
|
||
|
markupFromMarkup: parse.createMarkupFromErrors(fileToLint, fileTextWithoutMarkup, errorsFromLinter),
|
||
|
skipped: false,
|
||
|
};
|
||
|
};
|
||
|
for (var _i = 0, filesToLint_1 = filesToLint; _i < filesToLint_1.length; _i++) {
|
||
|
var fileToLint = filesToLint_1[_i];
|
||
|
_loop_1(fileToLint);
|
||
|
}
|
||
|
return results;
|
||
|
}
|
||
|
exports.runTest = runTest;
|
||
|
function consoleTestResultsHandler(testResults, logger) {
|
||
|
var didAllTestsPass = true;
|
||
|
for (var _i = 0, testResults_1 = testResults; _i < testResults_1.length; _i++) {
|
||
|
var testResult = testResults_1[_i];
|
||
|
if (!consoleTestResultHandler(testResult, logger)) {
|
||
|
didAllTestsPass = false;
|
||
|
}
|
||
|
}
|
||
|
return didAllTestsPass;
|
||
|
}
|
||
|
exports.consoleTestResultsHandler = consoleTestResultsHandler;
|
||
|
function consoleTestResultHandler(testResult, logger) {
|
||
|
// needed to get colors to show up when passing through Grunt
|
||
|
chalk_1.default.enabled = true;
|
||
|
var didAllTestsPass = true;
|
||
|
for (var _i = 0, _a = Object.keys(testResult.results); _i < _a.length; _i++) {
|
||
|
var fileName = _a[_i];
|
||
|
var results = testResult.results[fileName];
|
||
|
logger.log(fileName + ":");
|
||
|
if (results.skipped) {
|
||
|
logger.log(chalk_1.default.yellow(" Skipped, requires typescript " + results.requirement + "\n"));
|
||
|
}
|
||
|
else {
|
||
|
var markupDiffResults = diff.diffLines(results.markupFromMarkup, results.markupFromLinter);
|
||
|
var fixesDiffResults = diff.diffLines(results.fixesFromLinter, results.fixesFromMarkup);
|
||
|
var didMarkupTestPass = !markupDiffResults.some(function (hunk) { return hunk.added === true || hunk.removed === true; });
|
||
|
var didFixesTestPass = !fixesDiffResults.some(function (hunk) { return hunk.added === true || hunk.removed === true; });
|
||
|
if (didMarkupTestPass && didFixesTestPass) {
|
||
|
logger.log(chalk_1.default.green(" Passed\n"));
|
||
|
}
|
||
|
else {
|
||
|
logger.log(chalk_1.default.red(" Failed!\n"));
|
||
|
didAllTestsPass = false;
|
||
|
if (!didMarkupTestPass) {
|
||
|
displayDiffResults(markupDiffResults, MARKUP_FILE_EXTENSION, logger);
|
||
|
}
|
||
|
if (!didFixesTestPass) {
|
||
|
displayDiffResults(fixesDiffResults, FIXES_FILE_EXTENSION, logger);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return didAllTestsPass;
|
||
|
}
|
||
|
exports.consoleTestResultHandler = consoleTestResultHandler;
|
||
|
function displayDiffResults(diffResults, extension, logger) {
|
||
|
logger.log(chalk_1.default.green("Expected (from " + extension + " file)\n"));
|
||
|
logger.log(chalk_1.default.red("Actual (from TSLint)\n"));
|
||
|
var _loop_2 = function (diffResult) {
|
||
|
var color = chalk_1.default.grey;
|
||
|
var prefix = " ";
|
||
|
if (diffResult.added) {
|
||
|
color = chalk_1.default.green.underline;
|
||
|
prefix = "+ ";
|
||
|
}
|
||
|
else if (diffResult.removed) {
|
||
|
color = chalk_1.default.red.underline;
|
||
|
prefix = "- ";
|
||
|
}
|
||
|
logger.log(color(diffResult.value
|
||
|
.split(/\r\n|\r|\n/)
|
||
|
// strings end on a newline which we do not want to include the prefix.
|
||
|
// tslint:disable-next-line:prefer-template
|
||
|
.map(function (line, index, array) {
|
||
|
return index === array.length - 1 ? line : "" + prefix + line + "\n";
|
||
|
})
|
||
|
.join("")));
|
||
|
};
|
||
|
for (var _i = 0, diffResults_1 = diffResults; _i < diffResults_1.length; _i++) {
|
||
|
var diffResult = diffResults_1[_i];
|
||
|
_loop_2(diffResult);
|
||
|
}
|
||
|
}
|