From 94d1cfd8f8267af6c3736b75b42799e832bc1cd5 Mon Sep 17 00:00:00 2001 From: Klaus Meinhardt Date: Fri, 20 Oct 2017 06:10:57 +0200 Subject: [PATCH] semicolon: add "strict-bound-class-methods" option (#3294) [new-rule-option] `semicolon` adds `"strict-bound-class-methods"` Fixes: #3216 --- src/rules/semicolonRule.ts | 25 +++++++++++++---- .../strict-bound-class-methods/test.ts.fix | 22 +++++++++++++++ .../strict-bound-class-methods/test.ts.lint | 27 +++++++++++++++++++ .../strict-bound-class-methods/tslint.json | 5 ++++ 4 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 test/rules/semicolon/strict-bound-class-methods/test.ts.fix create mode 100644 test/rules/semicolon/strict-bound-class-methods/test.ts.lint create mode 100644 test/rules/semicolon/strict-bound-class-methods/tslint.json diff --git a/src/rules/semicolonRule.ts b/src/rules/semicolonRule.ts index baab2f17344..209ea714f08 100644 --- a/src/rules/semicolonRule.ts +++ b/src/rules/semicolonRule.ts @@ -23,10 +23,17 @@ import * as Lint from "../index"; const OPTION_ALWAYS = "always"; const OPTION_NEVER = "never"; const OPTION_IGNORE_BOUND_CLASS_METHODS = "ignore-bound-class-methods"; +const OPTION_STRICT_BOUND_CLASS_METHODS = "strict-bound-class-methods"; const OPTION_IGNORE_INTERFACES = "ignore-interfaces"; +const enum BoundClassMethodOption { + Default, + Ignore, + Strict, +} + interface Options { - boundClassMethods: boolean; + boundClassMethods: BoundClassMethodOption; interfaces: boolean; } @@ -45,7 +52,10 @@ export class Rule extends Lint.Rules.AbstractRule { The following arguments may be optionally provided: * \`"${OPTION_IGNORE_INTERFACES}"\` skips checking semicolons at the end of interface members. - * \`"${OPTION_IGNORE_BOUND_CLASS_METHODS}"\` skips checking semicolons at the end of bound class methods.`, + * \`"${OPTION_IGNORE_BOUND_CLASS_METHODS}"\` skips checking semicolons at the end of bound class methods. + * \`"${OPTION_STRICT_BOUND_CLASS_METHODS}"\` disables any special handling of bound class methods and treats them as any + other assignment. This option overrides \`"${OPTION_IGNORE_BOUND_CLASS_METHODS}"\`. + `, options: { type: "array", items: [ @@ -77,7 +87,11 @@ export class Rule extends Lint.Rules.AbstractRule { public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { const options: Options = { - boundClassMethods: this.ruleArguments.indexOf(OPTION_IGNORE_BOUND_CLASS_METHODS) === -1, + boundClassMethods: this.ruleArguments.indexOf(OPTION_STRICT_BOUND_CLASS_METHODS) !== -1 + ? BoundClassMethodOption.Strict + : this.ruleArguments.indexOf(OPTION_IGNORE_BOUND_CLASS_METHODS) !== -1 + ? BoundClassMethodOption.Ignore + : BoundClassMethodOption.Default, interfaces: this.ruleArguments.indexOf(OPTION_IGNORE_INTERFACES) === -1, }; const Walker = this.ruleArguments.indexOf(OPTION_NEVER) === -1 ? SemicolonAlwaysWalker : SemicolonNeverWalker; @@ -175,10 +189,11 @@ abstract class SemicolonWalker extends Lint.AbstractWalker { private visitPropertyDeclaration(node: ts.PropertyDeclaration) { // check if this is a multi-line arrow function - if (node.initializer !== undefined && + if (this.options.boundClassMethods !== BoundClassMethodOption.Strict && + node.initializer !== undefined && node.initializer.kind === ts.SyntaxKind.ArrowFunction && !utils.isSameLine(this.sourceFile, node.getStart(this.sourceFile), node.end)) { - if (this.options.boundClassMethods) { + if (this.options.boundClassMethods === BoundClassMethodOption.Default) { this.checkUnnecessary(node); } } else { diff --git a/test/rules/semicolon/strict-bound-class-methods/test.ts.fix b/test/rules/semicolon/strict-bound-class-methods/test.ts.fix new file mode 100644 index 00000000000..faeb16b4135 --- /dev/null +++ b/test/rules/semicolon/strict-bound-class-methods/test.ts.fix @@ -0,0 +1,22 @@ +class MyClass { + public name : string; + private index : number; + private email : string; + + public initializedProperty = 6; + public initializedMethodProperty = () => { + return "hi"; + }; + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + }; + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; }; + public realMethod() {} + public multilineRealMethod() { + return "foo"; + } +} diff --git a/test/rules/semicolon/strict-bound-class-methods/test.ts.lint b/test/rules/semicolon/strict-bound-class-methods/test.ts.lint new file mode 100644 index 00000000000..2cc42b71ad6 --- /dev/null +++ b/test/rules/semicolon/strict-bound-class-methods/test.ts.lint @@ -0,0 +1,27 @@ +class MyClass { + public name : string + ~nil [Missing semicolon] + private index : number + ~nil [Missing semicolon] + private email : string; + + public initializedProperty = 6 + ~nil [Missing semicolon] + public initializedMethodProperty = () => { + return "hi"; + }; + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + ~nil [Missing semicolon] + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~nil [Missing semicolon] + public realMethod() {} + public multilineRealMethod() { + return "foo"; + } +} diff --git a/test/rules/semicolon/strict-bound-class-methods/tslint.json b/test/rules/semicolon/strict-bound-class-methods/tslint.json new file mode 100644 index 00000000000..f29bda5b7c7 --- /dev/null +++ b/test/rules/semicolon/strict-bound-class-methods/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "semicolon": [true, "always", "strict-bound-class-methods"] + } +}