123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- "use strict";
- /*
- * @license
- * Copyright 2016 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 });
- var semver = require("semver");
- var ts = require("typescript");
- var util_1 = require("util");
- var utils_1 = require("../utils");
- var lines_1 = require("./lines");
- var lintError_1 = require("./lintError");
- var scanner;
- function getTypescriptVersionRequirement(text) {
- var lines = text.split(/\r?\n/);
- var firstLine = lines_1.parseLine(lines[0]);
- if (firstLine instanceof lines_1.MessageSubstitutionLine && firstLine.key === "typescript") {
- return firstLine.message;
- }
- return undefined;
- }
- exports.getTypescriptVersionRequirement = getTypescriptVersionRequirement;
- function getNormalizedTypescriptVersion() {
- var tsVersion = new semver.SemVer(ts.version);
- // remove prerelease suffix when matching to allow testing with nightly builds
- return tsVersion.major + "." + tsVersion.minor + "." + tsVersion.patch;
- }
- exports.getNormalizedTypescriptVersion = getNormalizedTypescriptVersion;
- function preprocessDirectives(text) {
- if (!/^#(?:if|else|endif)\b/m.test(text)) {
- return text; // If there are no directives, just return the input unchanged
- }
- var tsVersion = getNormalizedTypescriptVersion();
- var lines = text.split(/\n/);
- var result = [];
- var collecting = true;
- var state = 0 /* Initial */;
- for (var _i = 0, lines_2 = lines; _i < lines_2.length; _i++) {
- var line = lines_2[_i];
- if (line.startsWith("#if typescript")) {
- if (state !== 0 /* Initial */) {
- throw lintError_1.lintSyntaxError("#if directives cannot be nested");
- }
- state = 1 /* If */;
- collecting = semver.satisfies(tsVersion, line.slice("#if typescript".length).trim());
- }
- else if (/^#else\s*$/.test(line)) {
- if (state !== 1 /* If */) {
- throw lintError_1.lintSyntaxError("unexpected #else");
- }
- state = 2 /* Else */;
- collecting = !collecting;
- }
- else if (/^#endif\s*$/.test(line)) {
- if (state === 0 /* Initial */) {
- throw lintError_1.lintSyntaxError("unexpected #endif");
- }
- state = 0 /* Initial */;
- collecting = true;
- }
- else if (collecting) {
- result.push(line);
- }
- }
- if (state !== 0 /* Initial */) {
- throw lintError_1.lintSyntaxError("expected #endif");
- }
- return result.join("\n");
- }
- exports.preprocessDirectives = preprocessDirectives;
- /**
- * Takes the full text of a .lint file and returns the contents of the file
- * with all error markup removed
- */
- function removeErrorMarkup(text) {
- var textWithMarkup = text.split("\n");
- var lines = textWithMarkup.map(lines_1.parseLine);
- var codeText = lines.filter(function (line) { return (line instanceof lines_1.CodeLine); }).map(function (line) { return line.contents; });
- return codeText.join("\n");
- }
- exports.removeErrorMarkup = removeErrorMarkup;
- /* tslint:disable:object-literal-sort-keys */
- /**
- * Takes the full text of a .lint file and returns an array of LintErrors
- * corresponding to the error markup in the file.
- */
- function parseErrorsFromMarkup(text) {
- var textWithMarkup = text.split("\n");
- var lines = textWithMarkup.map(lines_1.parseLine);
- if (lines.length > 0 && !(lines[0] instanceof lines_1.CodeLine)) {
- throw lintError_1.lintSyntaxError("text cannot start with an error mark line.");
- }
- var messageSubstitutionLines = lines.filter(function (l) { return l instanceof lines_1.MessageSubstitutionLine; });
- var messageSubstitutions = new Map();
- for (var _i = 0, messageSubstitutionLines_1 = messageSubstitutionLines; _i < messageSubstitutionLines_1.length; _i++) {
- var _a = messageSubstitutionLines_1[_i], key = _a.key, message = _a.message;
- messageSubstitutions.set(key, formatMessage(messageSubstitutions, message));
- }
- // errorLineForCodeLine[5] contains all the ErrorLine objects associated with the 5th line of code, for example
- var errorLinesForCodeLines = createCodeLineNoToErrorsMap(lines);
- var lintErrors = [];
- function addError(errorLine, errorStartPos, lineNo) {
- lintErrors.push({
- startPos: errorStartPos,
- endPos: { line: lineNo, col: errorLine.endCol },
- message: substituteMessage(messageSubstitutions, errorLine.message),
- });
- }
- // for each line of code...
- errorLinesForCodeLines.forEach(function (errorLinesForLineOfCode, lineNo) {
- // for each error marking on that line...
- while (errorLinesForLineOfCode.length > 0) {
- var errorLine = errorLinesForLineOfCode.shift();
- var errorStartPos = { line: lineNo, col: errorLine.startCol };
- // if the error starts and ends on this line, add it now to list of errors
- if (errorLine instanceof lines_1.EndErrorLine) {
- addError(errorLine, errorStartPos, lineNo);
- // if the error is the start of a multiline error
- }
- else if (errorLine instanceof lines_1.MultilineErrorLine) {
- // iterate through the MultilineErrorLines until we get to an EndErrorLine
- for (var nextLineNo = lineNo + 1;; ++nextLineNo) {
- if (!isValidErrorMarkupContinuation(errorLinesForCodeLines, nextLineNo)) {
- throw lintError_1.lintSyntaxError("Error mark starting at " + errorStartPos.line + ":" + errorStartPos.col + " does not end correctly.");
- }
- else {
- var nextErrorLine = errorLinesForCodeLines[nextLineNo].shift();
- // if end of multiline error, add it it list of errors
- if (nextErrorLine instanceof lines_1.EndErrorLine) {
- addError(nextErrorLine, errorStartPos, nextLineNo);
- break;
- }
- }
- }
- }
- }
- });
- lintErrors.sort(lintError_1.errorComparator);
- return lintErrors;
- }
- exports.parseErrorsFromMarkup = parseErrorsFromMarkup;
- /**
- * Process `message` as follows:
- * - search `substitutions` for an exact match and return the substitution
- * - try to format the message when it looks like: name % ('substitution1' [, "substitution2" [, ...]])
- * - or return it unchanged
- */
- function substituteMessage(templates, message) {
- var substitution = templates.get(message);
- if (substitution !== undefined) {
- return substitution;
- }
- return formatMessage(templates, message);
- }
- /**
- * Tries to format the message when it has the correct format or returns it unchanged: name % ('substitution1' [, "substitution2" [, ...]])
- * Where `name` is the name of a message substitution that is used as template.
- * If `name` is not found in `templates`, `message` is returned unchanged.
- */
- function formatMessage(templates, message) {
- var formatMatch = /^([-\w]+) % \((.+)\)$/.exec(message);
- if (formatMatch !== null) {
- var template = templates.get(formatMatch[1]);
- if (template !== undefined) {
- var formatArgs = parseFormatArguments(formatMatch[2]);
- if (formatArgs !== undefined) {
- message = util_1.format.apply(void 0, [template].concat(formatArgs));
- }
- }
- }
- return message;
- }
- /**
- * Parse a list of comma separated string literals.
- * This function bails out if it sees something unexpected.
- * Whitespace between tokens is ignored.
- * Trailing comma is allowed.
- */
- function parseFormatArguments(text) {
- if (scanner === undefined) {
- // once the scanner is created, it is cached for subsequent calls
- scanner = ts.createScanner(ts.ScriptTarget.Latest, false);
- }
- scanner.setText(text);
- var result = [];
- var expectValue = true;
- for (var token = scanner.scan(); token !== ts.SyntaxKind.EndOfFileToken; token = scanner.scan()) {
- if (token === ts.SyntaxKind.StringLiteral) {
- if (!expectValue) {
- return undefined;
- }
- result.push(scanner.getTokenValue());
- expectValue = false;
- }
- else if (token === ts.SyntaxKind.CommaToken) {
- if (expectValue) {
- return undefined;
- }
- expectValue = true;
- }
- else if (token !== ts.SyntaxKind.WhitespaceTrivia) {
- // only ignore whitespace, other trivia like comments makes this function bail out
- return undefined;
- }
- }
- return result.length === 0 ? undefined : result;
- }
- function createMarkupFromErrors(code, lintErrors) {
- lintErrors.sort(lintError_1.errorComparator);
- var codeText = code.split("\n");
- var errorLinesForCodeText = codeText.map(function () { return []; });
- for (var _i = 0, lintErrors_1 = lintErrors; _i < lintErrors_1.length; _i++) {
- var error = lintErrors_1[_i];
- var startPos = error.startPos, endPos = error.endPos, message = error.message;
- if (startPos.line === endPos.line) {
- // single line error
- errorLinesForCodeText[startPos.line].push(new lines_1.EndErrorLine(startPos.col, endPos.col, message));
- }
- else {
- // multiline error
- errorLinesForCodeText[startPos.line].push(new lines_1.MultilineErrorLine(startPos.col));
- for (var lineNo = startPos.line + 1; lineNo < endPos.line; ++lineNo) {
- errorLinesForCodeText[lineNo].push(new lines_1.MultilineErrorLine(0));
- }
- errorLinesForCodeText[endPos.line].push(new lines_1.EndErrorLine(0, endPos.col, message));
- }
- }
- return utils_1.flatMap(codeText, function (line, i) { return [line].concat(utils_1.mapDefined(errorLinesForCodeText[i], function (err) { return lines_1.printLine(err, line); })); }).join("\n");
- }
- exports.createMarkupFromErrors = createMarkupFromErrors;
- /* tslint:enable:object-literal-sort-keys */
- function createCodeLineNoToErrorsMap(lines) {
- var errorLinesForCodeLine = [];
- for (var _i = 0, lines_3 = lines; _i < lines_3.length; _i++) {
- var line = lines_3[_i];
- if (line instanceof lines_1.CodeLine) {
- errorLinesForCodeLine.push([]);
- }
- else if (line instanceof lines_1.ErrorLine) {
- errorLinesForCodeLine[errorLinesForCodeLine.length - 1].push(line);
- }
- }
- return errorLinesForCodeLine;
- }
- function isValidErrorMarkupContinuation(errorLinesForCodeLines, lineNo) {
- return lineNo < errorLinesForCodeLines.length
- && errorLinesForCodeLines[lineNo].length !== 0
- && errorLinesForCodeLines[lineNo][0].startCol === 0;
- }
|