Files

Return to Package Diff Home.
Brought to you by Intrinsic.

Package Diff: tslint @ 5.15.0 .. 5.16.0

CHANGELOG.md

@@ -1,5 +1,37 @@
# Change Log
+## v5.16.0
+
+- [bugfix] Excuse more [`quotemark`](https://palantir.github.io/tslint/rules/quotemark/) backtick edge cases and fix behavior for TS < 2.7.1 (#4642)
+- [bugfix] Fix regression in [`interface-name`](https://palantir.github.io/tslint/rules/interface-name/) rule related to numeric characters in interface names (#4655, #4626)
+- [enhancement] Update `nyc` from v10.2.0 to v13.3.0 (#4633)
+- [enhancement] Migrate from deprecated [babel-code-frame](https://www.npmjs.com/package/babel-code-frame) package to new [@babel/code-frame](https://www.npmjs.com/package/@babel/code-frame) package (#4632)
+- [enhancement] Improve error message for [`restrict-plus-operands`](https://palantir.github.io/tslint/rules/restrict-plus-operands/) rule. (#4635)
+- [enhancement] [`comment-format`](https://palantir.github.io/tslint/rules/comment-format/) rule now whitelists `//region` comments generated by JetBrains IDE (#4609)
+- [enhancement] Relax [`no-null-undefined-union`](https://palantir.github.io/tslint/rules/no-null-undefined-union/) rule. (#4625)
+- [new-rule-option] `allow-else-if` option for [`unnecessary-else`](https://palantir.github.io/tslint/rules/unnecessary-else/) rule (#4599)
+- [documentation] Fix "identifer" typo in custom rules docs (#4657)
+- [documentation] Fix code example for [`switch-default`](https://palantir.github.io/tslint/rules/switch-default/) rule (#4650)
+- [documentation] Fix documentation example for prose formatter (#4656)
+- [documentation] [`no-parameter-properties`](https://palantir.github.io/tslint/rules/no-parameter-properties/): fix unclear rule description (#4629)
+- [documentation] Fix typo in rule docs generation (#4638)
+
+Thanks to our contributors!
+
+- Oleg Artene
+- William Neely
+- Bjorn Stromberg
+- Matthew Barry
+- Neha Rathi
+- Vincent Langlet
+- rarenal
+- Greg Jednaszewski
+- Adam Postma
+- Eric Ferreira
+- Evgeniy Timokhov
+- Martin Probst
+
+
## v5.15.0
- [api] `WalkContext` and `AbstractWalker` type parameter defaults to `void` (#2600)

lib/configuration.js

@@ -315,9 +315,7 @@
*
* @param ruleConfigValue The raw option setting of a rule
*/
-function parseRuleOptions(
-// tslint:disable-next-line no-null-undefined-union
-ruleConfigValue, rawDefaultRuleSeverity) {
+function parseRuleOptions(ruleConfigValue, rawDefaultRuleSeverity) {
var ruleArguments;
var defaultRuleSeverity = "error";
if (rawDefaultRuleSeverity !== undefined) {

lib/formatters/codeFrameFormatter.js

@@ -17,7 +17,7 @@
*/
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
-var codeFrame = require("babel-code-frame");
+var code_frame_1 = require("@babel/code-frame");
var chalk_1 = require("chalk");
var abstractFormatter_1 = require("../language/formatter/abstractFormatter");
var Utils = require("../utils");
@@ -52,9 +52,9 @@
var ruleName = failure.getRuleName();
ruleName = chalk_1.default.gray("(" + ruleName + ")");
// Frame
- var lineAndCharacter = failure.getStartPosition().getLineAndCharacter();
- var frame = codeFrame(failure.getRawLines(), lineAndCharacter.line + 1, // babel-code-frame is 1 index
- lineAndCharacter.character, {
+ var _a = failure.getStartPosition().getLineAndCharacter(), column = _a.character, line = _a.line;
+ var frame = code_frame_1.codeFrameColumns(failure.getRawLines(), { start: { line: line + 1, column: column } }, // babel-code-frame is 1 index
+ {
forceColor: chalk_1.default.enabled,
highlightCode: true,
});

lib/formatters/proseFormatter.js

@@ -57,7 +57,7 @@
Formatter.metadata = {
formatterName: "prose",
description: "The default formatter which outputs simple human-readable messages.",
- sample: "ERROR: myFile.ts[1, 14]: Missing semicolon",
+ sample: "ERROR: myFile.ts:1:14 - Missing semicolon",
consumer: "human",
};
return Formatter;

lib/linter.js

@@ -243,7 +243,7 @@
return utils.getSourceFile(fileName, source);
}
};
- Linter.VERSION = "5.15.0";
+ Linter.VERSION = "5.16.0";
Linter.findConfiguration = configuration_1.findConfiguration;
Linter.findConfigurationPath = configuration_1.findConfigurationPath;
Linter.getRulesDirectories = configuration_1.getRulesDirectories;

lib/rules/code-examples/switchDefault.examples.js

@@ -23,8 +23,8 @@
{
description: "Requires a `default` case in `switch` statements.",
config: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n \"rules\": { \"switch-default\": true }\n "], ["\n \"rules\": { \"switch-default\": true }\n "]))),
- pass: Lint.Utils.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n let foo: number = 1;\n switch (foo) {\n case 1:\n doSomething();\n break;\n case 2:\n doSomething2();\n break;\n default:\n console.log('default');\n break;\n }\n "], ["\n let foo: number = 1;\n switch (foo) {\n case 1:\n doSomething();\n break;\n case 2:\n doSomething2();\n break;\n default:\n console.log('default');\n break;\n }\n "]))),
- fail: Lint.Utils.dedent(templateObject_3 || (templateObject_3 = tslib_1.__makeTemplateObject(["\n let foo: number = 1;\n switch (foo) {\n case 1:\n doSomething();\n break;\n case 2:\n doSomething2();\n break;\n }\n "], ["\n let foo: number = 1;\n switch (foo) {\n case 1:\n doSomething();\n break;\n case 2:\n doSomething2();\n break;\n }\n "]))),
+ pass: Lint.Utils.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n let foo: number = 1;\n switch (foo) {\n case 1:\n doSomething();\n break;\n case 2:\n doSomething2();\n break;\n default:\n console.log('default');\n }\n "], ["\n let foo: number = 1;\n switch (foo) {\n case 1:\n doSomething();\n break;\n case 2:\n doSomething2();\n break;\n default:\n console.log('default');\n }\n "]))),
+ fail: Lint.Utils.dedent(templateObject_3 || (templateObject_3 = tslib_1.__makeTemplateObject(["\n let foo: number = 1;\n switch (foo) {\n case 1:\n doSomething();\n break;\n case 2:\n doSomething2();\n }\n "], ["\n let foo: number = 1;\n switch (foo) {\n case 1:\n doSomething();\n break;\n case 2:\n doSomething2();\n }\n "]))),
},
];
var templateObject_1, templateObject_2, templateObject_3;

lib/rules/commentFormatRule.js

@@ -137,8 +137,8 @@
return;
}
var commentText = fullText.slice(start, end);
- // whitelist //#region and //#endregion and JetBrains IDEs' "//noinspection ..."
- if (/^(?:#(?:end)?region|noinspection\s)/.test(commentText)) {
+ // whitelist //#region and //#endregion and JetBrains IDEs' "//noinspection ...", "//region", "//endregion"
+ if (/^(?:#?(?:end)?region|noinspection\s)/.test(commentText)) {
return;
}
if (ctx.options.space && commentText[0] !== " ") {

lib/rules/interfaceNameRule.js

@@ -20,7 +20,6 @@
var utils = require("tsutils");
var ts = require("typescript");
var Lint = require("../index");
-var utils_1 = require("../utils");
var OPTION_ALWAYS = "always-prefix";
var OPTION_NEVER = "never-prefix";
var Rule = /** @class */ (function (_super) {
@@ -73,10 +72,16 @@
});
}
function hasPrefixI(name) {
- return name.length >= 3 && name[0] === "I" && !utils_1.isLowerCase(name[1]) && !utils_1.isUpperCase(name[2]);
+ return name.length >= 3 && name[0] === "I" && /^[A-Z]*$/.test(name[1]);
}
function cantDecide(name) {
- return ((name.length === 2 && name[0] === "I" && !utils_1.isLowerCase(name[1])) ||
- (name.length >= 2 && name[0] === "I" && !utils_1.isLowerCase(name[1]) && !utils_1.isLowerCase(name[2])));
+ return (
+ // Case ID
+ (name.length === 2 && name[0] === "I" && /^[A-Z]*$/.test(name[1])) ||
+ // Case IDB or ID42
+ (name.length >= 2 &&
+ name[0] === "I" &&
+ /^[A-Z]*$/.test(name[1]) &&
+ !/^[a-z]*$/.test(name[2])));
}
var templateObject_1;

lib/rules/noInferredEmptyObjectTypeRule.js

@@ -35,7 +35,7 @@
optionsDescription: "Not configurable.",
options: null,
optionExamples: [true],
- rationale: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n When function or constructor may be called with a type parameter but one isn't supplied or inferrable,\n TypeScript defaults to `{}`.\n This is often undesirable as the call is meant to be of a more specific type.\n "], ["\n When function or constructor may be called with a type parameter but one isn't supplied or inferrable,\n TypeScript defaults to \\`{}\\`.\n This is often undesirable as the call is meant to be of a more specific type.\n "]))),
+ rationale: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n Prior to TypeScript 3.4, generic type parameters for functions and constructors are inferred as\n `{}` (the empty object type) by default when no type parameter is explicitly supplied or when\n the compiler cannot infer a more specific type.\n This is often undesirable as the call is meant to be of a more specific type.\n "], ["\n Prior to TypeScript 3.4, generic type parameters for functions and constructors are inferred as\n \\`{}\\` (the empty object type) by default when no type parameter is explicitly supplied or when\n the compiler cannot infer a more specific type.\n This is often undesirable as the call is meant to be of a more specific type.\n "]))),
type: "functionality",
typescriptOnly: true,
requiresTypeInfo: true,

lib/rules/noNullUndefinedUnionRule.js

@@ -31,8 +31,8 @@
/* tslint:disable:object-literal-sort-keys */
Rule.metadata = {
ruleName: "no-null-undefined-union",
- description: "Disallows union types with both `null` and `undefined` as members.",
- rationale: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n A union type that includes both `null` and `undefined` is either redundant or fragile.\n Enforcing the choice between the two allows the `triple-equals` rule to exist without\n exceptions, and is essentially a more flexible version of the `no-null-keyword` rule.\n "], ["\n A union type that includes both \\`null\\` and \\`undefined\\` is either redundant or fragile.\n Enforcing the choice between the two allows the \\`triple-equals\\` rule to exist without\n exceptions, and is essentially a more flexible version of the \\`no-null-keyword\\` rule.\n "]))),
+ description: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n Disallows explicitly declared or implicitly returned union types with both `null` and\n `undefined` as members.\n "], ["\n Disallows explicitly declared or implicitly returned union types with both \\`null\\` and\n \\`undefined\\` as members.\n "]))),
+ rationale: Lint.Utils.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n A union type that includes both `null` and `undefined` is either redundant or fragile.\n Enforcing the choice between the two allows the `triple-equals` rule to exist without\n exceptions, and is essentially a more flexible version of the `no-null-keyword` rule.\n Optional parameters are not considered to have the type `undefined`.\n "], ["\n A union type that includes both \\`null\\` and \\`undefined\\` is either redundant or fragile.\n Enforcing the choice between the two allows the \\`triple-equals\\` rule to exist without\n exceptions, and is essentially a more flexible version of the \\`no-null-keyword\\` rule.\n Optional parameters are not considered to have the type \\`undefined\\`.\n "]))),
optionsDescription: "Not configurable.",
options: null,
optionExamples: [true],
@@ -55,17 +55,11 @@
});
}
function getType(node, tc) {
- // This is a comprehensive intersection between `HasType` and has property `name`.
- // The node name kind must be identifier, or else this rule will throw errors while descending.
- if ((tsutils_1.isVariableDeclaration(node) ||
- tsutils_1.isParameterDeclaration(node) ||
- tsutils_1.isPropertySignature(node) ||
- tsutils_1.isPropertyDeclaration(node) ||
- tsutils_1.isTypeAliasDeclaration(node)) &&
- node.name.kind === ts.SyntaxKind.Identifier) {
+ if (tsutils_1.isUnionTypeNode(node)) {
return tc.getTypeAtLocation(node);
}
- else if (tsutils_1.isSignatureDeclaration(node)) {
+ else if (tsutils_1.isSignatureDeclaration(node) && node.type === undefined) {
+ // Explicit types should be handled by the first case.
var signature = tc.getSignatureFromDeclaration(node);
return signature === undefined ? undefined : signature.getReturnType();
}
@@ -91,4 +85,4 @@
}
return false;
}
-var templateObject_1;
+var templateObject_1, templateObject_2;

lib/rules/noParameterPropertiesRule.js

@@ -36,7 +36,7 @@
Rule.metadata = {
ruleName: "no-parameter-properties",
description: "Disallows parameter properties in class constructors.",
- rationale: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n Parameter properties can be confusing to those new to TS as they are less explicit\n than other ways of declaring and initializing class members.\n\n It can be cleaner to keep member variable declarations in one list directly only the class\n (instead of mixed between direct class members and constructor parameter properties).\n "], ["\n Parameter properties can be confusing to those new to TS as they are less explicit\n than other ways of declaring and initializing class members.\n\n It can be cleaner to keep member variable declarations in one list directly only the class\n (instead of mixed between direct class members and constructor parameter properties).\n "]))),
+ rationale: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n Parameter properties can be confusing to those new to TS as they are less explicit\n than other ways of declaring and initializing class members.\n\n It can be cleaner to keep member variable declarations in one list directly above the class constructor\n (instead of mixed between direct class members and constructor parameter properties).\n "], ["\n Parameter properties can be confusing to those new to TS as they are less explicit\n than other ways of declaring and initializing class members.\n\n It can be cleaner to keep member variable declarations in one list directly above the class constructor\n (instead of mixed between direct class members and constructor parameter properties).\n "]))),
optionsDescription: "Not configurable.",
options: null,
optionExamples: [true],

lib/rules/quotemarkRule.d.ts

@@ -1,3 +1,19 @@
+/**
+ * @license
+ * Copyright 2013 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.
+ */
import * as ts from "typescript";
import * as Lint from "../index";
export declare class Rule extends Lint.Rules.AbstractRule {

lib/rules/quotemarkRule.js

@@ -1,6 +1,4 @@
"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var tslib_1 = require("tslib");
/**
* @license
* Copyright 2013 Palantir Technologies, Inc.
@@ -17,9 +15,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = require("tslib");
+var semver_1 = require("semver");
var tsutils_1 = require("tsutils");
var ts = require("typescript");
var Lint = require("../index");
+var parse_1 = require("../verify/parse");
var OPTION_SINGLE = "single";
var OPTION_DOUBLE = "double";
var OPTION_BACKTICK = "backtick";
@@ -101,13 +103,14 @@
(tsutils_1.isExportDeclaration(node.parent) ||
// This captures `import blah from "package"`
tsutils_1.isImportDeclaration(node.parent) ||
- // This captures kebab-case property names in object literals (only when the node is not at the end of the parent node)
- (node.parent.kind === ts.SyntaxKind.PropertyAssignment &&
- node.end !== node.parent.end) ||
- // This captures the kebab-case property names in type definitions
- node.parent.kind === ts.SyntaxKind.PropertySignature ||
+ // This captures quoted names in object literal keys
+ isNameInAssignment(node) ||
+ // This captures quoted signatures (property or method)
+ isSignature(node) ||
// This captures literal types in generic type constraints
- node.parent.parent.kind === ts.SyntaxKind.TypeReference)) {
+ isTypeConstraint(node) ||
+ // Whether this is the type in a typeof check with older tsc
+ isTypeCheckWithOldTsc(node))) {
return;
}
// We already have the expected quotemark. Done.
@@ -191,4 +194,76 @@
// If the regular pref is backtick, use double quotes instead.
return regularQuotemarkPreference !== "`" ? regularQuotemarkPreference : '"';
}
+/**
+ * Whether this node is a type constraint in a generic type.
+ * @param node The node to check
+ * @return Whether this node is a type constraint
+ */
+function isTypeConstraint(node) {
+ var parent = node.parent.parent;
+ // If this node doesn't have a grandparent, it's not a type constraint
+ if (parent == undefined) {
+ return false;
+ }
+ // Iterate through all levels of union, intersection, or parethesized types
+ while (parent.kind === ts.SyntaxKind.UnionType ||
+ parent.kind === ts.SyntaxKind.IntersectionType ||
+ parent.kind === ts.SyntaxKind.ParenthesizedType) {
+ parent = parent.parent;
+ }
+ return (
+ // If the next level is a type reference, the node is a type constraint
+ parent.kind === ts.SyntaxKind.TypeReference ||
+ // If the next level is a type parameter, the node is a type constraint
+ parent.kind === ts.SyntaxKind.TypeParameter);
+}
+/**
+ * Whether this node is the signature of a property or method in a type.
+ * @param node The node to check
+ * @return Whether this node is a property/method signature.
+ */
+function isSignature(node) {
+ var parent = node.parent;
+ if (hasOldTscBacktickBehavior() && node.parent.kind === ts.SyntaxKind.LastTypeNode) {
+ // In older versions, there's a "LastTypeNode" here
+ parent = parent.parent;
+ }
+ return (
+ // This captures the kebab-case property names in type definitions
+ parent.kind === ts.SyntaxKind.PropertySignature ||
+ // This captures the kebab-case method names in type definitions
+ parent.kind === ts.SyntaxKind.MethodSignature);
+}
+/**
+ * Whether this node is the method or property name in an assignment/declaration.
+ * @param node The node to check
+ * @return Whether this node is the name in an assignment/decleration.
+ */
+function isNameInAssignment(node) {
+ if (node.parent.kind !== ts.SyntaxKind.PropertyAssignment &&
+ node.parent.kind !== ts.SyntaxKind.MethodDeclaration) {
+ // If the node is neither a property assignment or method declaration, it's not a name in an assignment
+ return false;
+ }
+ return (
+ // In old typescript versions, don't change values either
+ hasOldTscBacktickBehavior() ||
+ // If this node is not at the end of the parent
+ node.end !== node.parent.end);
+}
+function isTypeCheckWithOldTsc(node) {
+ if (!hasOldTscBacktickBehavior()) {
+ // This one only affects older typescript versions
+ return false;
+ }
+ if (node.parent.kind !== ts.SyntaxKind.BinaryExpression) {
+ // If this isn't in a binary expression
+ return false;
+ }
+ // If this node has a sibling that is a TypeOf
+ return node.parent.getChildren().some(function (n) { return n.kind === ts.SyntaxKind.TypeOfExpression; });
+}
+function hasOldTscBacktickBehavior() {
+ return semver_1.lt(parse_1.getNormalizedTypescriptVersion(), "2.7.1");
+}
var templateObject_1;

lib/rules/radixRule.js

@@ -52,16 +52,16 @@
function isPropertyAccessParseInt(expression) {
return tsutils_1.isPropertyAccessExpression(expression) && expression.name.text === "parseInt";
}
-function isPropertyAccessOfIdentifier(expression, identifers) {
+function isPropertyAccessOfIdentifier(expression, identifiers) {
return (tsutils_1.isPropertyAccessExpression(expression) &&
tsutils_1.isIdentifier(expression.expression) &&
- identifers.some(function (identifer) { return expression.expression.text === identifer; }));
+ identifiers.some(function (identifier) { return expression.expression.text === identifier; }));
}
-function isPropertyAccessOfProperty(expression, identifers) {
+function isPropertyAccessOfProperty(expression, identifiers) {
return (tsutils_1.isPropertyAccessExpression(expression) &&
tsutils_1.isPropertyAccessExpression(expression.expression) &&
- identifers.some(function (identifer) {
- return expression.expression.name.text === identifer;
+ identifiers.some(function (identifier) {
+ return expression.expression.name.text === identifier;
}));
}
function walk(ctx) {

lib/rules/restrictPlusOperandsRule.js

@@ -41,27 +41,41 @@
};
/* tslint:enable:object-literal-sort-keys */
Rule.INVALID_TYPES_ERROR = "Operands of '+' operation must either be both strings or both numbers";
- Rule.SUGGEST_TEMPLATE_LITERALS = ", consider using template literals";
+ Rule.SUGGEST_TEMPLATE_LITERALS = ". Consider using template literals.";
return Rule;
}(Lint.Rules.TypedRule));
exports.Rule = Rule;
function walk(ctx, tc) {
return ts.forEachChild(ctx.sourceFile, function cb(node) {
if (tsutils_1.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {
- var leftType = getBaseTypeOfLiteralType(tc.getTypeAtLocation(node.left));
- var rightType = getBaseTypeOfLiteralType(tc.getTypeAtLocation(node.right));
- if (leftType === "invalid" || rightType === "invalid" || leftType !== rightType) {
- if (leftType === "string" || rightType === "string") {
- return ctx.addFailureAtNode(node, Rule.INVALID_TYPES_ERROR + Rule.SUGGEST_TEMPLATE_LITERALS);
- }
- else {
- return ctx.addFailureAtNode(node, Rule.INVALID_TYPES_ERROR);
+ var leftType = tc.getTypeAtLocation(node.left);
+ var leftTypeStr = getBaseTypeOfLiteralType(leftType);
+ var rightType = tc.getTypeAtLocation(node.right);
+ var rightTypeStr = getBaseTypeOfLiteralType(rightType);
+ if (leftTypeStr === "invalid" ||
+ rightTypeStr === "invalid" ||
+ leftTypeStr !== rightTypeStr) {
+ var actualTypes = ", but found " + getTypeString(tc, node.left, leftType) + " + " + getTypeString(tc, node.right, rightType);
+ var message = Rule.INVALID_TYPES_ERROR + actualTypes;
+ if (leftTypeStr === "string" || rightTypeStr === "string") {
+ message += Rule.SUGGEST_TEMPLATE_LITERALS;
}
+ return ctx.addFailureAtNode(node, message);
}
}
return ts.forEachChild(node, cb);
});
}
+function getTypeString(tc, node, type) {
+ var typeString = tc.typeToString(type, node);
+ if (typeString === "undefined[]" &&
+ ts.isArrayLiteralExpression(node) &&
+ node.elements.length === 0) {
+ // Special case literal "[]" arrays that would otherwise be emitted as undefined[].
+ return "[]";
+ }
+ return typeString;
+}
function getBaseTypeOfLiteralType(type) {
if (tsutils_1.isTypeFlagSet(type, ts.TypeFlags.StringLiteral) ||
tsutils_1.isTypeFlagSet(type, ts.TypeFlags.String)) {

lib/rules/unnecessaryElseRule.js

@@ -1,6 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
+var _a, _b;
/**
* @license
* Copyright 2019 Palantir Technologies, Inc.
@@ -21,6 +22,7 @@
var ts = require("typescript");
var Lint = require("../index");
var unnecessaryElse_examples_1 = require("./code-examples/unnecessaryElse.examples");
+var OPTION_ALLOW_ELSE_IF = "allow-else-if";
var Rule = /** @class */ (function (_super) {
tslib_1.__extends(Rule, _super);
function Rule() {
@@ -31,16 +33,21 @@
return "The preceding `if` block ends with a `" + name + "` statement. This `else` is unnecessary.";
};
Rule.prototype.apply = function (sourceFile) {
- return this.applyWithFunction(sourceFile, walk);
+ return this.applyWithFunction(sourceFile, walk, parseOptions(this.ruleArguments[0]));
};
/* tslint:disable:object-literal-sort-keys */
Rule.metadata = {
description: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n Disallows `else` blocks following `if` blocks ending with a `break`, `continue`, `return`, or `throw` statement."], ["\n Disallows \\`else\\` blocks following \\`if\\` blocks ending with a \\`break\\`, \\`continue\\`, \\`return\\`, or \\`throw\\` statement."]))),
descriptionDetails: "",
- optionExamples: [true],
- options: null,
- optionsDescription: "Not configurable.",
- rationale: Lint.Utils.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n When an `if` block is guaranteed to exit control flow when entered,\n it is unnecessary to add an `else` statement.\n The contents that would be in the `else` block can be placed after the end of the `if` block."], ["\n When an \\`if\\` block is guaranteed to exit control flow when entered,\n it is unnecessary to add an \\`else\\` statement.\n The contents that would be in the \\`else\\` block can be placed after the end of the \\`if\\` block."]))),
+ optionExamples: [true, [true, (_a = {}, _a[OPTION_ALLOW_ELSE_IF] = true, _a)]],
+ options: {
+ type: "object",
+ properties: (_b = {},
+ _b[OPTION_ALLOW_ELSE_IF] = { type: "boolean" },
+ _b),
+ },
+ optionsDescription: Lint.Utils.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n You can optionally specify the option `\"", "\"` to allow \"else if\" statements.\n "], ["\n You can optionally specify the option \\`\"", "\"\\` to allow \"else if\" statements.\n "])), OPTION_ALLOW_ELSE_IF),
+ rationale: Lint.Utils.dedent(templateObject_3 || (templateObject_3 = tslib_1.__makeTemplateObject(["\n When an `if` block is guaranteed to exit control flow when entered,\n it is unnecessary to add an `else` statement.\n The contents that would be in the `else` block can be placed after the end of the `if` block."], ["\n When an \\`if\\` block is guaranteed to exit control flow when entered,\n it is unnecessary to add an \\`else\\` statement.\n The contents that would be in the \\`else\\` block can be placed after the end of the \\`if\\` block."]))),
ruleName: "unnecessary-else",
type: "style",
typescriptOnly: false,
@@ -49,6 +56,10 @@
return Rule;
}(Lint.Rules.AbstractRule));
exports.Rule = Rule;
+function parseOptions(option) {
+ var _a;
+ return tslib_1.__assign((_a = {}, _a[OPTION_ALLOW_ELSE_IF] = false, _a), option);
+}
function walk(ctx) {
var ifStatementStack = [];
function visitIfStatement(node) {
@@ -58,7 +69,8 @@
ifStatementStack.push({ node: node, jumpStatement: jumpStatement });
if (jumpStatement !== undefined &&
node.elseStatement !== undefined &&
- !recentStackParentMissingJumpStatement()) {
+ !recentStackParentMissingJumpStatement() &&
+ (!utils.isIfStatement(node.elseStatement) || !ctx.options[OPTION_ALLOW_ELSE_IF])) {
var elseKeyword = getPositionOfElseKeyword(node, ts.SyntaxKind.ElseKeyword);
ctx.addFailureAtNode(elseKeyword, Rule.FAILURE_STRING(jumpStatement));
}
@@ -120,4 +132,4 @@
function last(arr) {
return arr[arr.length - 1];
}
-var templateObject_1, templateObject_2;
+var templateObject_1, templateObject_2, templateObject_3;

package.json

@@ -1,6 +1,6 @@
{
"name": "tslint",
- "version": "5.15.0",
+ "version": "5.16.0",
"description": "An extensible static analysis linter for the TypeScript language",
"bin": {
"tslint": "./bin/tslint"
@@ -29,7 +29,7 @@
"coverage": "rimraf coverage .nyc_output && nyc npm test"
},
"dependencies": {
- "babel-code-frame": "^6.22.0",
+ "@babel/code-frame": "^7.0.0",
"builtin-modules": "^1.1.1",
"chalk": "^2.3.0",
"commander": "^2.12.1",
@@ -47,7 +47,7 @@
"typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev"
},
"devDependencies": {
- "@types/babel-code-frame": "^6.20.0",
+ "@types/babel__code-frame": "^7.0.1",
"@types/chai": "^3.5.0",
"@types/diff": "^3.2.0",
"@types/glob": "^5.0.30",
@@ -65,7 +65,7 @@
"json-stringify-pretty-compact": "^1.2.0",
"mocha": "^3.2.0",
"npm-run-all": "^4.0.2",
- "nyc": "^10.2.0",
+ "nyc": "^13.3.0",
"prettier": "~1.16.4",
"rimraf": "^2.5.4",
"ts-node": "^3.3.0",
@@ -73,7 +73,8 @@
"tslint-config-prettier": "^1.18.0",
"tslint-plugin-prettier": "^2.0.1",
"tslint-test-config-non-relative": "file:test/external/tslint-test-config-non-relative",
- "typescript": "~3.1.6"
+ "typescript": "~3.1.6",
+ "yarn-deduplicate": "^1.1.1"
},
"engines": {
"node": ">=4.8.0"

.prettierrc

@@ -0,0 +1,5 @@
+{
+ "printWidth": 100,
+ "tabWidth": 4,
+ "trailingComma": "all"
+}

README.md

@@ -9,7 +9,9 @@
TSLint is an extensible static analysis tool that checks [TypeScript](https://github.com/Microsoft/TypeScript) code for readability, maintainability, and functionality errors. It is widely supported across modern editors & build systems and can be customized with your own lint rules, configurations, and formatters.
-TSLint supports:
+:warning: __TSLint will be deprecated some time in 2019__. See this issue for more details: [Roadmap: TSLint &rarr; ESLint](https://github.com/palantir/tslint/issues/4534).
+
+TSLint currently supports:
- an extensive set of core rules
- custom lint rules
@@ -29,7 +31,7 @@
- [customization of TSLint](https://palantir.github.io/tslint/develop/custom-rules/).
- [inline disabling and enabling of rules with comment flags](https://palantir.github.io/tslint/usage/rule-flags/)
-## Custom Rules & Plugins
+## Custom rules & plugins
#### Custom rule sets from Palantir
@@ -57,7 +59,7 @@
- `node` v7+
- `yarn` v1.0+
-#### Quick Start
+#### Quick start
```bash
git clone git@github.com:palantir/tslint.git --config core.autocrlf=input --config core.eol=lf
@@ -65,15 +67,3 @@
yarn compile
yarn test
```
-
-## Creating a new release
-
-1. Bump the version number in `package.json` and `src/linter.ts`
-2. Add release notes in `CHANGELOG.md`
- - Use `./scripts/generate-changelog.js` (after building it with `tsc -p scripts`) to generate the changelog diff. This script expects a [Github.com personal access token](https://github.com/settings/tokens) to exist at `~/github_token.txt` with "repo" permissions.
-3. Commit with message `Prepare release <version>`
-4. Push your branch to GitHub and make a PR
-5. Once your PR is merged, wait for the tests to pass on CircleCI for develop
-6. Create a "Release" on GitHub with the proper tag version and notes from the changelog.
- - The tag should be identical to the version in `package.json`
-7. Run `yarn run publish:local`