UNPKG

6.93 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright 2014 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 });
19exports.removeDisabledFailures = exports.ENABLE_DISABLE_REGEX = void 0;
20// tslint:disable object-literal-sort-keys
21var utils = require("tsutils");
22var ts = require("typescript");
23/**
24 * regex is: start of string followed by any amount of whitespace
25 * followed by tslint and colon
26 * followed by either "enable" or "disable"
27 * followed optionally by -line or -next-line
28 * followed by either colon, whitespace or end of string
29 */
30exports.ENABLE_DISABLE_REGEX = /^\s*tslint:(enable|disable)(?:-(line|next-line))?(:|\s|$)/;
31function removeDisabledFailures(sourceFile, failures) {
32 if (failures.length === 0) {
33 // Usually there won't be failures anyway, so no need to look for "tslint:disable".
34 return failures;
35 }
36 var failingRules = new Set(failures.map(function (f) { return f.getRuleName(); }));
37 var map = getDisableMap(sourceFile, failingRules);
38 return failures.filter(function (failure) {
39 var disabledIntervals = map.get(failure.getRuleName());
40 return (disabledIntervals === undefined ||
41 !disabledIntervals.some(function (_a) {
42 var pos = _a.pos, end = _a.end;
43 var failPos = failure.getStartPosition().getPosition();
44 var failEnd = failure.getEndPosition().getPosition();
45 return failEnd >= pos && (end === -1 || failPos < end);
46 }));
47 });
48}
49exports.removeDisabledFailures = removeDisabledFailures;
50/**
51 * The map will have an array of TextRange for each disable of a rule in a file.
52 * (It will have no entry if the rule is never disabled, meaning all arrays are non-empty.)
53 */
54function getDisableMap(sourceFile, failingRules) {
55 var map = new Map();
56 utils.forEachComment(sourceFile, function (fullText, comment) {
57 var commentText = comment.kind === ts.SyntaxKind.SingleLineCommentTrivia
58 ? fullText.substring(comment.pos + 2, comment.end)
59 : fullText.substring(comment.pos + 2, comment.end - 2);
60 var parsed = parseComment(commentText);
61 if (parsed !== undefined) {
62 var rulesList = parsed.rulesList, isEnabled = parsed.isEnabled, modifier = parsed.modifier;
63 var switchRange = getSwitchRange(modifier, comment, sourceFile);
64 if (switchRange !== undefined) {
65 var rulesToSwitch = rulesList === "all"
66 ? Array.from(failingRules)
67 : rulesList.filter(function (r) { return failingRules.has(r); });
68 for (var _i = 0, rulesToSwitch_1 = rulesToSwitch; _i < rulesToSwitch_1.length; _i++) {
69 var ruleToSwitch = rulesToSwitch_1[_i];
70 switchRuleState(ruleToSwitch, isEnabled, switchRange.pos, switchRange.end);
71 }
72 }
73 }
74 });
75 return map;
76 function switchRuleState(ruleName, isEnable, start, end) {
77 var disableRanges = map.get(ruleName);
78 if (isEnable) {
79 if (disableRanges !== undefined) {
80 var lastDisable = disableRanges[disableRanges.length - 1];
81 if (lastDisable.end === -1) {
82 lastDisable.end = start;
83 if (end !== -1) {
84 // Disable it again after the enable range is over.
85 disableRanges.push({ pos: end, end: -1 });
86 }
87 }
88 }
89 }
90 else {
91 // disable
92 if (disableRanges === undefined) {
93 map.set(ruleName, [{ pos: start, end: end }]);
94 }
95 else if (disableRanges[disableRanges.length - 1].end !== -1) {
96 disableRanges.push({ pos: start, end: end });
97 }
98 }
99 }
100}
101/** End will be -1 to indicate no end. */
102function getSwitchRange(modifier, range, sourceFile) {
103 var lineStarts = sourceFile.getLineStarts();
104 switch (modifier) {
105 case "line":
106 return {
107 // start at the beginning of the line where comment starts
108 pos: getStartOfLinePosition(range.pos),
109 // end at the beginning of the line following the comment
110 end: getStartOfLinePosition(range.end, 1),
111 };
112 case "next-line":
113 // start at the beginning of the line following the comment
114 var pos = getStartOfLinePosition(range.end, 1);
115 if (pos === -1) {
116 // no need to switch anything, there is no next line
117 return undefined;
118 }
119 // end at the beginning of the line following the next line
120 return { pos: pos, end: getStartOfLinePosition(range.end, 2) };
121 default:
122 // switch rule for the rest of the file
123 // start at the current position, but skip end position
124 return { pos: range.pos, end: -1 };
125 }
126 /** Returns -1 for last line. */
127 function getStartOfLinePosition(position, lineOffset) {
128 if (lineOffset === void 0) { lineOffset = 0; }
129 var line = ts.getLineAndCharacterOfPosition(sourceFile, position).line + lineOffset;
130 return line >= lineStarts.length ? -1 : lineStarts[line];
131 }
132}
133function parseComment(commentText) {
134 var match = exports.ENABLE_DISABLE_REGEX.exec(commentText);
135 if (match === null) {
136 return undefined;
137 }
138 // remove everything matched by the previous regex to get only the specified rules
139 // split at whitespaces
140 // filter empty items coming from whitespaces at start, at end or empty list
141 var rulesList = splitOnSpaces(commentText.substr(match[0].length));
142 if (rulesList.length === 0 && match[3] === ":") {
143 // nothing to do here: an explicit separator was specified but no rules to switch
144 return undefined;
145 }
146 if (rulesList.length === 0 || rulesList.indexOf("all") !== -1) {
147 // if list is empty we default to all enabled rules
148 // if `all` is specified we ignore the other rules and take all enabled rules
149 rulesList = "all";
150 }
151 return { rulesList: rulesList, isEnabled: match[1] === "enable", modifier: match[2] };
152}
153function splitOnSpaces(str) {
154 return str.split(/\s+/).filter(function (s) { return s !== ""; });
155}