diff options
Diffstat (limited to 'node_modules/tslint/lib/rules/strictBooleanExpressionsRule.js')
-rw-r--r-- | node_modules/tslint/lib/rules/strictBooleanExpressionsRule.js | 99 |
1 files changed, 69 insertions, 30 deletions
diff --git a/node_modules/tslint/lib/rules/strictBooleanExpressionsRule.js b/node_modules/tslint/lib/rules/strictBooleanExpressionsRule.js index a202e2c49..0d1851179 100644 --- a/node_modules/tslint/lib/rules/strictBooleanExpressionsRule.js +++ b/node_modules/tslint/lib/rules/strictBooleanExpressionsRule.js @@ -24,6 +24,7 @@ var OPTION_ALLOW_UNDEFINED_UNION = "allow-undefined-union"; var OPTION_ALLOW_STRING = "allow-string"; var OPTION_ALLOW_NUMBER = "allow-number"; var OPTION_ALLOW_MIX = "allow-mix"; +var OPTION_ALLOW_BOOLEAN_OR_UNDEFINED = "allow-boolean-or-undefined"; // tslint:disable object-literal-sort-keys switch-default var Rule = (function (_super) { tslib_1.__extends(Rule, _super); @@ -31,32 +32,39 @@ var Rule = (function (_super) { return _super !== null && _super.apply(this, arguments) || this; } Rule.prototype.applyWithProgram = function (sourceFile, program) { - var options = parseOptions(this.ruleArguments, program.getCompilerOptions().strictNullChecks === true); + var options = parseOptions(this.ruleArguments, Lint.isStrictNullChecksEnabled(program.getCompilerOptions())); return this.applyWithFunction(sourceFile, function (ctx) { return walk(ctx, program.getTypeChecker()); }, options); }; + Rule.metadata = { + ruleName: "strict-boolean-expressions", + description: (_a = ["\n Restricts the types allowed in boolean expressions. By default only booleans are allowed.\n\n The following nodes are checked:\n\n * Arguments to the `!`, `&&`, and `||` operators\n * The condition in a conditional expression (`cond ? x : y`)\n * Conditions for `if`, `for`, `while`, and `do-while` statements."], _a.raw = ["\n Restricts the types allowed in boolean expressions. By default only booleans are allowed.\n\n The following nodes are checked:\n\n * Arguments to the \\`!\\`, \\`&&\\`, and \\`||\\` operators\n * The condition in a conditional expression (\\`cond ? x : y\\`)\n * Conditions for \\`if\\`, \\`for\\`, \\`while\\`, and \\`do-while\\` statements."], Lint.Utils.dedent(_a)), + optionsDescription: (_b = ["\n These options may be provided:\n\n * `", "` allows union types containing `null`.\n - It does *not* allow `null` itself.\n - Without the '--strictNullChecks' compiler option, this will allow anything other than a string, number, or enum.\n * `", "` allows union types containing `undefined`.\n - It does *not* allow `undefined` itself.\n - Without the '--strictNullChecks' compiler option, this will allow anything other than a string, number, or enum.\n * `", "` allows strings.\n - It does *not* allow unions containing `string`.\n - It does *not* allow string literal types.\n * `", "` allows numbers.\n - It does *not* allow unions containing `number`.\n - It does *not* allow enums or number literal types.\n * `", "` allows multiple of the above to appear together.\n - For example, `string | number` or `RegExp | null | undefined` would normally not be allowed.\n - A type like `\"foo\" | \"bar\" | undefined` is always allowed, because it has only one way to be false.\n * `", "` allows `boolean | undefined`.\n - Also allows `true | false | undefined`.\n - Does not allow `false | undefined`.\n - This option is a subset of `", "`, so you don't need to enable both options at the same time.\n "], _b.raw = ["\n These options may be provided:\n\n * \\`", "\\` allows union types containing \\`null\\`.\n - It does *not* allow \\`null\\` itself.\n - Without the '--strictNullChecks' compiler option, this will allow anything other than a string, number, or enum.\n * \\`", "\\` allows union types containing \\`undefined\\`.\n - It does *not* allow \\`undefined\\` itself.\n - Without the '--strictNullChecks' compiler option, this will allow anything other than a string, number, or enum.\n * \\`", "\\` allows strings.\n - It does *not* allow unions containing \\`string\\`.\n - It does *not* allow string literal types.\n * \\`", "\\` allows numbers.\n - It does *not* allow unions containing \\`number\\`.\n - It does *not* allow enums or number literal types.\n * \\`", "\\` allows multiple of the above to appear together.\n - For example, \\`string | number\\` or \\`RegExp | null | undefined\\` would normally not be allowed.\n - A type like \\`\"foo\" | \"bar\" | undefined\\` is always allowed, because it has only one way to be false.\n * \\`", "\\` allows \\`boolean | undefined\\`.\n - Also allows \\`true | false | undefined\\`.\n - Does not allow \\`false | undefined\\`.\n - This option is a subset of \\`", "\\`, so you don't need to enable both options at the same time.\n "], Lint.Utils.dedent(_b, OPTION_ALLOW_NULL_UNION, OPTION_ALLOW_UNDEFINED_UNION, OPTION_ALLOW_STRING, OPTION_ALLOW_NUMBER, OPTION_ALLOW_MIX, OPTION_ALLOW_BOOLEAN_OR_UNDEFINED, OPTION_ALLOW_UNDEFINED_UNION)), + options: { + type: "array", + items: { + type: "string", + enum: [ + OPTION_ALLOW_NULL_UNION, + OPTION_ALLOW_UNDEFINED_UNION, + OPTION_ALLOW_STRING, + OPTION_ALLOW_NUMBER, + OPTION_ALLOW_BOOLEAN_OR_UNDEFINED, + ], + }, + minLength: 0, + maxLength: 5, + }, + optionExamples: [ + true, + [true, OPTION_ALLOW_NULL_UNION, OPTION_ALLOW_UNDEFINED_UNION, OPTION_ALLOW_STRING, OPTION_ALLOW_NUMBER], + [true, OPTION_ALLOW_BOOLEAN_OR_UNDEFINED], + ], + type: "functionality", + typescriptOnly: true, + requiresTypeInfo: true, + }; return Rule; }(Lint.Rules.TypedRule)); -Rule.metadata = { - ruleName: "strict-boolean-expressions", - description: (_a = ["\n Restricts the types allowed in boolean expressions. By default only booleans are allowed.\n\n The following nodes are checked:\n\n * Arguments to the `!`, `&&`, and `||` operators\n * The condition in a conditional expression (`cond ? x : y`)\n * Conditions for `if`, `for`, `while`, and `do-while` statements."], _a.raw = ["\n Restricts the types allowed in boolean expressions. By default only booleans are allowed.\n\n The following nodes are checked:\n\n * Arguments to the \\`!\\`, \\`&&\\`, and \\`||\\` operators\n * The condition in a conditional expression (\\`cond ? x : y\\`)\n * Conditions for \\`if\\`, \\`for\\`, \\`while\\`, and \\`do-while\\` statements."], Lint.Utils.dedent(_a)), - optionsDescription: (_b = ["\n These options may be provided:\n\n * `", "` allows union types containing `null`.\n - It does *not* allow `null` itself.\n - Without the '--strictNullChecks' compiler option, this will allow anything other than a string, number, or enum.\n * `", "` allows union types containing `undefined`.\n - It does *not* allow `undefined` itself.\n - Without the '--strictNullChecks' compiler option, this will allow anything other than a string, number, or enum.\n * `", "` allows strings.\n - It does *not* allow unions containing `string`.\n - It does *not* allow string literal types.\n * `", "` allows numbers.\n - It does *not* allow unions containing `number`.\n - It does *not* allow enums or number literal types.\n * `", "` allow multiple of the above to appear together.\n - For example, `string | number` or `RegExp | null | undefined` would normally not be allowed.\n - A type like `\"foo\" | \"bar\" | undefined` is always allowed, because it has only one way to be false."], _b.raw = ["\n These options may be provided:\n\n * \\`", "\\` allows union types containing \\`null\\`.\n - It does *not* allow \\`null\\` itself.\n - Without the '--strictNullChecks' compiler option, this will allow anything other than a string, number, or enum.\n * \\`", "\\` allows union types containing \\`undefined\\`.\n - It does *not* allow \\`undefined\\` itself.\n - Without the '--strictNullChecks' compiler option, this will allow anything other than a string, number, or enum.\n * \\`", "\\` allows strings.\n - It does *not* allow unions containing \\`string\\`.\n - It does *not* allow string literal types.\n * \\`", "\\` allows numbers.\n - It does *not* allow unions containing \\`number\\`.\n - It does *not* allow enums or number literal types.\n * \\`", "\\` allow multiple of the above to appear together.\n - For example, \\`string | number\\` or \\`RegExp | null | undefined\\` would normally not be allowed.\n - A type like \\`\"foo\" | \"bar\" | undefined\\` is always allowed, because it has only one way to be false."], Lint.Utils.dedent(_b, OPTION_ALLOW_NULL_UNION, OPTION_ALLOW_UNDEFINED_UNION, OPTION_ALLOW_STRING, OPTION_ALLOW_NUMBER, OPTION_ALLOW_MIX)), - options: { - type: "array", - items: { - type: "string", - enum: [OPTION_ALLOW_NULL_UNION, OPTION_ALLOW_UNDEFINED_UNION, OPTION_ALLOW_STRING, OPTION_ALLOW_NUMBER], - }, - minLength: 0, - maxLength: 5, - }, - optionExamples: [ - true, - [true, OPTION_ALLOW_NULL_UNION, OPTION_ALLOW_UNDEFINED_UNION, OPTION_ALLOW_STRING, OPTION_ALLOW_NUMBER], - ], - type: "functionality", - typescriptOnly: true, - requiresTypeInfo: true, -}; exports.Rule = Rule; function parseOptions(ruleArguments, strictNullChecks) { return { @@ -66,6 +74,7 @@ function parseOptions(ruleArguments, strictNullChecks) { allowString: has(OPTION_ALLOW_STRING), allowNumber: has(OPTION_ALLOW_NUMBER), allowMix: has(OPTION_ALLOW_MIX), + allowBooleanOrUndefined: has(OPTION_ALLOW_BOOLEAN_OR_UNDEFINED), }; function has(name) { return ruleArguments.indexOf(name) !== -1; @@ -115,7 +124,6 @@ function walk(ctx, checker) { if (condition !== undefined) { checkExpression(condition, node); } - break; } } return ts.forEachChild(node, cb); @@ -145,14 +153,41 @@ function getTypeFailure(type, options) { } switch (triState(kind)) { case true: - return 0 /* AlwaysTruthy */; + // Allow 'any'. Allow 'true' itself, but not any other always-truthy type. + // tslint:disable-next-line no-bitwise + return Lint.isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.BooleanLiteral) ? undefined : 0 /* AlwaysTruthy */; case false: - return 1 /* AlwaysFalsy */; + // Allow 'false' itself, but not any other always-falsy type + return Lint.isTypeFlagSet(type, ts.TypeFlags.BooleanLiteral) ? undefined : 1 /* AlwaysFalsy */; case undefined: return undefined; } } +function isBooleanUndefined(type) { + var isTruthy = false; + for (var _i = 0, _a = type.types; _i < _a.length; _i++) { + var ty = _a[_i]; + if (Lint.isTypeFlagSet(ty, ts.TypeFlags.Boolean)) { + isTruthy = true; + } + else if (Lint.isTypeFlagSet(ty, ts.TypeFlags.BooleanLiteral)) { + isTruthy = isTruthy || ty.intrinsicName === "true"; + } + else if (!Lint.isTypeFlagSet(ty, ts.TypeFlags.Void | ts.TypeFlags.Undefined)) { + return undefined; + } + } + return isTruthy; +} function handleUnion(type, options) { + if (options.allowBooleanOrUndefined) { + switch (isBooleanUndefined(type)) { + case true: + return undefined; + case false: + return 1 /* AlwaysFalsy */; + } + } // Tracks whether it's possibly truthy. var anyTruthy = false; // Counts falsy kinds to see if there's a mix. Also tracks whether it's possibly falsy. @@ -236,10 +271,11 @@ function getKind(type) { } } function numberLiteralIsZero(type) { - // Uses 'value' in TypeScript>=2.4. + // for compatibility with typescript@<2.4.0 return type.value !== undefined ? type.value === 0 : type.text === "0"; } function stringLiteralIsEmpty(type) { + // for compatibility with typescript@<2.4.0 return (type.value !== undefined ? type.value : type.text) === ""; } /** Matches `&&` and `||` operators. */ @@ -291,12 +327,12 @@ function showLocation(n) { return "operand for the '" + binaryBooleanExpressionKind(n) + "' operator"; } } -function showFailure(location, ty, isUnionType, options) { +function showFailure(location, ty, unionType, options) { var expectedTypes = showExpectedTypes(options); var expected = expectedTypes.length === 1 ? "Only " + expectedTypes[0] + "s are allowed" : "Allowed types are " + stringOr(expectedTypes); - var tyFail = showTypeFailure(ty, isUnionType, options.strictNullChecks); + var tyFail = showTypeFailure(ty, unionType, options.strictNullChecks); return "This type is not allowed in the " + showLocation(location) + " because it " + tyFail + ". " + expected + "."; } function showExpectedTypes(options) { @@ -313,10 +349,13 @@ function showExpectedTypes(options) { if (options.allowNumber) { parts.push("number"); } + if (options.allowBooleanOrUndefined) { + parts.push("boolean-or-undefined"); + } return parts; } -function showTypeFailure(ty, isUnionType, strictNullChecks) { - var is = isUnionType ? "could be" : "is"; +function showTypeFailure(ty, unionType, strictNullChecks) { + var is = unionType ? "could be" : "is"; switch (ty) { case 0 /* AlwaysTruthy */: return strictNullChecks |