diff --git a/src/language/walker/syntaxWalker.ts b/src/language/walker/syntaxWalker.ts index 5afdf2d1bfc..61470816f16 100644 --- a/src/language/walker/syntaxWalker.ts +++ b/src/language/walker/syntaxWalker.ts @@ -86,6 +86,10 @@ export class SyntaxWalker { this.walkChildren(node); } + protected visitConstructSignature(node: ts.ConstructSignatureDeclaration) { + this.walkChildren(node); + } + protected visitConstructorDeclaration(node: ts.ConstructorDeclaration) { this.walkChildren(node); } @@ -294,6 +298,10 @@ export class SyntaxWalker { this.walkChildren(node); } + protected visitTupleType(node: ts.TupleTypeNode) { + this.walkChildren(node); + } + protected visitTypeAliasDeclaration(node: ts.TypeAliasDeclaration) { this.walkChildren(node); } @@ -392,6 +400,10 @@ export class SyntaxWalker { this.visitConditionalExpression( node); break; + case ts.SyntaxKind.ConstructSignature: + this.visitConstructSignature( node); + break; + case ts.SyntaxKind.Constructor: this.visitConstructorDeclaration( node); break; @@ -604,6 +616,10 @@ export class SyntaxWalker { this.visitTryStatement( node); break; + case ts.SyntaxKind.TupleType: + this.visitTupleType( node); + break; + case ts.SyntaxKind.TypeAliasDeclaration: this.visitTypeAliasDeclaration( node); break; diff --git a/src/rules/trailingCommaRule.ts b/src/rules/trailingCommaRule.ts index 083922c592d..d5e18726c3f 100644 --- a/src/rules/trailingCommaRule.ts +++ b/src/rules/trailingCommaRule.ts @@ -23,7 +23,9 @@ export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ public static metadata: Lint.IRuleMetadata = { ruleName: "trailing-comma", - description: "Requires or disallows trailing commas in array and object literals, destructuring assignments and named imports.", + description: Lint.Utils.dedent` + Requires or disallows trailing commas in array and object literals, destructuring assignments, function and tuple typings, + named imports and function parameters.`, optionsDescription: Lint.Utils.dedent` One argument which is an object with the keys \`multiline\` and \`singleline\`. Both should be set to either \`"always"\` or \`"never"\`. @@ -33,7 +35,8 @@ export class Rule extends Lint.Rules.AbstractRule { A array is considered "multiline" if its closing bracket is on a line after the last array element. The same general logic is followed for - object literals and named import statements.`, + object literals, function and tuple typings, named import statements + and function parameters.`, options: { type: "object", properties: { @@ -62,40 +65,181 @@ export class Rule extends Lint.Rules.AbstractRule { } class TrailingCommaWalker extends Lint.RuleWalker { + private static SYNTAX_LIST_WRAPPER_TOKENS: [ts.SyntaxKind, ts.SyntaxKind][] = [ + [ts.SyntaxKind.OpenBraceToken, ts.SyntaxKind.CloseBraceToken], + [ts.SyntaxKind.OpenBracketToken, ts.SyntaxKind.CloseBracketToken], + [ts.SyntaxKind.OpenParenToken, ts.SyntaxKind.CloseParenToken], + [ts.SyntaxKind.LessThanToken, ts.SyntaxKind.GreaterThanToken], + ]; + public visitArrayLiteralExpression(node: ts.ArrayLiteralExpression) { - this.lintNode(node); + this.lintChildNodeWithIndex(node, 1); super.visitArrayLiteralExpression(node); } + public visitArrowFunction(node: ts.FunctionLikeDeclaration) { + this.lintChildNodeWithIndex(node, 1); + super.visitArrowFunction(node); + } + public visitBindingPattern(node: ts.BindingPattern) { if (node.kind === ts.SyntaxKind.ArrayBindingPattern || node.kind === ts.SyntaxKind.ObjectBindingPattern) { - this.lintNode(node); + this.lintChildNodeWithIndex(node, 1); } super.visitBindingPattern(node); } - public visitNamedImports(node: ts.NamedImports) { + public visitCallExpression(node: ts.CallExpression) { + this.lintNode(node); + super.visitCallExpression(node); + } + + public visitClassDeclaration(node: ts.ClassDeclaration) { + this.lintNode(node); + super.visitClassDeclaration(node); + } + + public visitConstructSignature(node: ts.ConstructSignatureDeclaration) { + this.lintNode(node); + super.visitConstructSignature(node); + } + + public visitConstructorDeclaration(node: ts.ConstructorDeclaration) { + this.lintNode(node); + super.visitConstructorDeclaration(node); + } + + public visitConstructorType(node: ts.FunctionOrConstructorTypeNode) { + this.lintNode(node); + super.visitConstructorType(node); + } + + public visitEnumDeclaration(node: ts.EnumDeclaration) { + this.lintNode(node, true); + super.visitEnumDeclaration(node); + } + + public visitFunctionType(node: ts.FunctionOrConstructorTypeNode) { + this.lintChildNodeWithIndex(node, 1); + super.visitFunctionType(node); + } + + public visitFunctionDeclaration(node: ts.FunctionDeclaration) { + this.lintNode(node); + super.visitFunctionDeclaration(node); + } + + public visitFunctionExpression(node: ts.FunctionExpression) { + this.lintNode(node); + super.visitFunctionExpression(node); + } + + public visitInterfaceDeclaration(node: ts.InterfaceDeclaration) { + this.lintNode(node); + super.visitInterfaceDeclaration(node); + } + + public visitMethodDeclaration(node: ts.MethodDeclaration) { + this.lintNode(node); + super.visitMethodDeclaration(node); + } + + public visitMethodSignature(node: ts.SignatureDeclaration) { this.lintNode(node); + super.visitMethodSignature(node); + } + + public visitNamedImports(node: ts.NamedImports) { + this.lintChildNodeWithIndex(node, 1); super.visitNamedImports(node); } - public visitObjectLiteralExpression(node: ts.ObjectLiteralExpression) { + public visitNewExpression(node: ts.NewExpression) { this.lintNode(node); + super.visitNewExpression(node); + } + + public visitObjectLiteralExpression(node: ts.ObjectLiteralExpression) { + this.lintChildNodeWithIndex(node, 1); super.visitObjectLiteralExpression(node); } - private lintNode(node: ts.Node) { - const child = node.getChildAt(1); - if (child != null && child.kind === ts.SyntaxKind.SyntaxList) { + public visitSetAccessor(node: ts.AccessorDeclaration) { + this.lintNode(node); + super.visitSetAccessor(node); + } + + public visitTupleType(node: ts.TupleTypeNode) { + this.lintChildNodeWithIndex(node, 1); + super.visitTupleType(node); + } + + public visitTypeLiteral(node: ts.TypeLiteralNode) { + this.lintNode(node); + // object type literals need to be inspected separately because they + // have a different syntax list wrapper token, and they can be semicolon delimited + const children = node.getChildren(); + for (let i = 0; i < children.length - 2; i++) { + if (children[i].kind === ts.SyntaxKind.OpenBraceToken && + children[i + 1].kind === ts.SyntaxKind.SyntaxList && + children[i + 2].kind === ts.SyntaxKind.CloseBraceToken) { + const grandChildren = children[i + 1].getChildren(); + // the AST is different from the grammar spec. The semicolons are included as tokens as part of *Signature, + // as opposed to optionals alongside it. So instead of children[i + 1] having + // [ PropertySignature, Semicolon, PropertySignature, Semicolon ], the AST is + // [ PropertySignature, PropertySignature], where the Semicolons are under PropertySignature + const hasSemicolon = grandChildren.some(grandChild => { + return grandChild.getChildren().some(ggc => ggc.kind === ts.SyntaxKind.SemicolonToken); + }); + + if (!hasSemicolon) { + const endLineOfClosingElement = this.getSourceFile().getLineAndCharacterOfPosition(children[i + 2].getEnd()).line; + this.lintChildNodeWithIndex(children[i + 1], grandChildren.length - 1, endLineOfClosingElement); + } + } + } + super.visitTypeLiteral(node); + } + + public visitTypeReference(node: ts.TypeReferenceNode) { + this.lintNode(node); + super.visitTypeReference(node); + } + + private lintNode(node: ts.Node, includeBraces?: boolean) { + const children = node.getChildren(); + const syntaxListWrapperTokens = (includeBraces === true) ? + TrailingCommaWalker.SYNTAX_LIST_WRAPPER_TOKENS : TrailingCommaWalker.SYNTAX_LIST_WRAPPER_TOKENS.slice(1); + + for (let i = 0; i < children.length - 2; i++) { + syntaxListWrapperTokens.forEach(([openToken, closeToken]) => { + if (children[i].kind === openToken && + children[i + 1].kind === ts.SyntaxKind.SyntaxList && + children[i + 2].kind === closeToken) { + this.lintChildNodeWithIndex(node, i + 1); + } + }); + } + } + + private lintChildNodeWithIndex(node: ts.Node, childNodeIndex: number, endLineOfClosingElement?: number) { + const child = node.getChildAt(childNodeIndex); + if (child != null) { const grandChildren = child.getChildren(); if (grandChildren.length > 0) { const lastGrandChild = grandChildren[grandChildren.length - 1]; const hasTrailingComma = lastGrandChild.kind === ts.SyntaxKind.CommaToken; - const endLineOfNode = this.getSourceFile().getLineAndCharacterOfPosition(node.getEnd()).line; const endLineOfLastElement = this.getSourceFile().getLineAndCharacterOfPosition(lastGrandChild.getEnd()).line; - const isMultiline = endLineOfNode !== endLineOfLastElement; + if (endLineOfClosingElement === undefined) { + let closingElementNode = node.getChildAt(childNodeIndex + 1); + if (closingElementNode == null) { + closingElementNode = node; + } + endLineOfClosingElement = this.getSourceFile().getLineAndCharacterOfPosition(closingElementNode.getEnd()).line; + } + const isMultiline = endLineOfClosingElement !== endLineOfLastElement; const option = this.getOption(isMultiline ? "multiline" : "singleline"); if (hasTrailingComma && option === "never") { diff --git a/test/rules/trailing-comma/multiline-always/test.ts.lint b/test/rules/trailing-comma/multiline-always/test.ts.lint index ce112b7c9a5..db9087ea76d 100644 --- a/test/rules/trailing-comma/multiline-always/test.ts.lint +++ b/test/rules/trailing-comma/multiline-always/test.ts.lint @@ -113,6 +113,21 @@ var [ccA, ccB,] = cc; var [ddOne, ddTwo] = dd; +var a: [string, number] = null; + +var a: [string, number,] = null; + +var a: [ + string, + number + ~ [Missing trailing comma] +] = null; + +var a: [ + string, + number, +] = null; + import { ClassS, } from "module"; @@ -136,3 +151,434 @@ import { import {ClassA, ClassB,} from "module"; import {ClassC, ClassD} from "module"; + +function foo(bar: string, baz: string); + +function foo(bar: string, baz: string,); + +function foo( + bar: string, + baz: string + ~ [Missing trailing comma] +); + +function foo( + bar: string, + baz: string, +); + +var foo = function(bar: string, baz: string) { return 42; }; + +var foo = function(bar: string, baz: string,) { return 42; }; + +var foo = function( + bar: string, + baz: string + ~ [Missing trailing comma] +) { + return 42; +}; + +var foo = function( + bar: string, + baz: string, +) { + return 42; +}; + +function foo(bar: string, baz: string) { return 42; } + +function foo(bar: string, baz: string,) { return 42; } + +function foo( + bar: string, + baz: string + ~ [Missing trailing comma] +) { + return 42; +} + +function foo( + bar: string, + baz: string, +) { + return 42; +} + +function foo(bar: string, baz: string, + ack: string + ~ [Missing trailing comma] +) { + return 42; +} + +function foo(bar: string, baz: string, + ack: string, +) { + return 42; +} + +var foo = (bar: string, baz: string) => 42; + +var foo = (bar: string, baz: string,) => 42; + +var foo = ( + bar: string, + baz: string + ~ [Missing trailing comma] +) => 42; + +var foo = ( + bar: string, + baz: string, +) => 42; + +var foo: (bar: string, baz: string) => number = null; + +var foo: (bar: string, baz: string,) => number = null; + +var foo: ( + bar: string, + baz: string + ~ [Missing trailing comma] +) => number = null; + +var foo: ( + bar: string, + baz: string, +) => number = null; + +var foo: (bar: string, baz: string) => number; + +var foo: (bar: string, baz: string,) => number; + +var foo: ( + bar: string, + baz: string + ~ [Missing trailing comma] +) => number; + +var foo: ( + bar: string, + baz: string, +) => number; + +var foo: new (bar: string, baz: string) => Test; + +var foo: new (bar: string, baz: string,) => Test; + +var foo: new ( + bar: string, + baz: string + ~ [Missing trailing comma] +) => Test; + +var foo: new ( + bar: string, + baz: string, +) => Test; + +var x = foo(42, 43); + +var x = foo(42, 43,); + +var x = foo( + 42, + 43 + ~ [Missing trailing comma] +); + +var x = foo( + 42, + 43, +); + +var x = new Test("foo"); + +var x = new Test("foo",); + +var x = new Test( + "foo" + ~ [Missing trailing comma] +); + +var x = new Test( + "foo", +); + +var x: { foo: string; bar: string }; + +var x: { foo: string; bar: string; }; + +var x: { + foo: string; + bar: string +}; + +var x: { + foo: string; + bar: string; +}; + +var x: { foo: string, bar: string }; + +var x: { foo: string, bar: string, }; + +var x: { + foo: string, + bar: string + ~ [Missing trailing comma] +}; + +var x: { + foo: string, + bar: string, +}; + +class Test { + + constructor(bar: string) { } + + constructor(bar: string, baz: string,) { } + + constructor( + bar: string, + baz: string, + ack: string + ~ [Missing trailing comma] + ) { } + + constructor( + bar: string, + baz: string, + ack: string, + foo: string, + ) { } + + public foo(bar: string, baz: string) { + return 42; + } + + private foo2(bar: string, baz: string,) { + return 42; + } + + public static foo3( + bar: string, + baz: string + ~ [Missing trailing comma] + ) { + return 42; + } + + private static foo4( + bar: string, + baz: string, + ) { + return 42; + } + + foo5< + T extends Test<[A, A], [A, A,], A>, + U extends Test, + V extends Test< + [ + C, + C + ~ [Missing trailing comma] + ], + [ + C, + C, + ] + C + ~ [Missing trailing comma] + > + ~ [Missing trailing comma] + >( + bar: A, + baz: T, + ) { + return 42; + } + + foo6< + T extends { foo: A; bar: B; }, + U extends { foo: A; bar: B; }, + V extends { + foo: A; + bar: B; + }, + W extends { + foo: [ + string, + string, + ]; + }, + >() { return 42; } + + set bar(foo: string) { } + + set bar2(foo: string,) { } + + set bar3( + foo: string + ~ [Missing trailing comma] + ) { } + + set bar4( + foo: string, + ) { } +} + +class Test2 { } + +class Test3< + A, + B, + C + ~ [Missing trailing comma] +> { } + +class Test4< + A, + B, + C, +> { } + +interface ITest { + + new (bar: U): ITest; + + new (bar: U, baz: V,): ITest; + + new < + U, + V + ~ [Missing trailing comma] + >( + bar: U, + baz: U, + ack: V + ~ [Missing trailing comma] + ): ITest< + U, + U, + V + ~ [Missing trailing comma] + >; + + new < + U, + V, + >( + bar: U, + baz: U, + ack: V, + foo: V, + ): ITest< + U, + U, + V, + >; + + foo(bar: string, baz: string); + + foo2(bar: string, baz: string,); + + foo3( + bar: string, + baz: string + ~ [Missing trailing comma] + ); + + foo4( + bar: string, + baz: string, + ); + + foo5< + T extends Test<[A, A], [A, A,], A>, + U extends Test, + V extends Test< + [ + C, + C + ~ [Missing trailing comma] + ], + [ + C, + C, + ] + C + ~ [Missing trailing comma] + > + ~ [Missing trailing comma] + >( + bar: A, + baz: T, + ); + + foo6< + T extends { foo: A; bar: B; }, + U extends { foo: A; bar: B; }, + V extends { + foo: A; + bar: B; + }, + W extends { + foo: [ + string, + string + ~ [Missing trailing comma] + ]; + } + ~ [Missing trailing comma] + >(); +} + +interface ITest2 { } + +interface ITest3< + A, + B, + C + ~ [Missing trailing comma] +> { } + +interface ITest4< + A, + B, + C, +> { } + +enum Foo { BAR, BAZ } + +enum Foo { BAR, BAZ, } + +enum Foo { + Bar, + Baz + ~ [Missing trailing comma] +} + +enum Foo { + Bar, + Baz, +} + +const enum Foo { BAR = 1, BAZ = 2 } + +const enum Foo { BAR = 1, BAZ = 2, } + +const enum Foo { + Bar = 1, + Baz = 2 + ~ [Missing trailing comma] +} + +const enum Foo { + Bar = 1, + Baz = 2, +} + diff --git a/test/rules/trailing-comma/multiline-never/test.ts.lint b/test/rules/trailing-comma/multiline-never/test.ts.lint index 594b93924f9..359d6063b36 100644 --- a/test/rules/trailing-comma/multiline-never/test.ts.lint +++ b/test/rules/trailing-comma/multiline-never/test.ts.lint @@ -113,6 +113,21 @@ var [ccA, ccB,] = cc; var [ddOne, ddTwo] = dd; +var a: [string, number] = null; + +var a: [string, number,] = null; + +var a: [ + string, + number +] = null; + +var a: [ + string, + number, + ~ [Unnecessary trailing comma] +] = null; + import { ClassS, ~ [Unnecessary trailing comma] @@ -136,3 +151,384 @@ import { import {ClassA, ClassB,} from "module"; import {ClassC, ClassD} from "module"; + +function foo(bar: string, baz: string); + +function foo(bar: string, baz: string,); + +function foo( + bar: string, + baz: string +); + +function foo( + bar: string, + baz: string, + ~ [Unnecessary trailing comma] +); + +var foo = function(bar: string, baz: string) { return 42; }; + +var foo = function(bar: string, baz: string,) { return 42; }; + +var foo = function( + bar: string, + baz: string +) { + return 42; +}; + +var foo = function( + bar: string, + baz: string, + ~ [Unnecessary trailing comma] +) { + return 42; +}; + +function foo(bar: string, baz: string) { return 42; } + +function foo(bar: string, baz: string,) { return 42; } + +function foo( + bar: string, + baz: string +) { + return 42; +} + +function foo( + bar: string, + baz: string, + ~ [Unnecessary trailing comma] +) { + return 42; +} + +function foo(bar: string, baz: string, + ack: string +) { + return 42; +} + +function foo(bar: string, baz: string, + ack: string, + ~ [Unnecessary trailing comma] +) { + return 42; +} + +var foo = (bar: string, baz: string) => 42; + +var foo = (bar: string, baz: string,) => 42; + +var foo = ( + bar: string, + baz: string +) => 42; + +var foo = ( + bar: string, + baz: string, + ~ [Unnecessary trailing comma] +) => 42; + +var foo: (bar: string, baz: string) => number = null; + +var foo: (bar: string, baz: string,) => number = null; + +var foo: ( + bar: string, + baz: string +) => number = null; + +var foo: ( + bar: string, + baz: string, + ~ [Unnecessary trailing comma] +) => number = null; + +var foo: (bar: string, baz: string) => number; + +var foo: (bar: string, baz: string,) => number; + +var foo: ( + bar: string, + baz: string +) => number; + +var foo: ( + bar: string, + baz: string, + ~ [Unnecessary trailing comma] +) => number; + +var foo: new (bar: string, baz: string) => Test; + +var foo: new (bar: string, baz: string,) => Test; + +var foo: new ( + bar: string, + baz: string +) => Test; + +var foo: new ( + bar: string, + baz: string, + ~ [Unnecessary trailing comma] +) => Test; + +var x = foo(42, 43); + +var x = foo(42, 43,); + +var x = foo( + 42, + 43 +); + +var x = foo( + 42, + 43, + ~ [Unnecessary trailing comma] +); + +var x = new Test("foo"); + +var x = new Test("foo",); + +var x = new Test( + "foo" +); + +var x = new Test( + "foo", + ~ [Unnecessary trailing comma] +); + +var x: { foo: string; bar: string }; + +var x: { foo: string; bar: string; }; + +var x: { + foo: string; + bar: string +}; + +var x: { + foo: string; + bar: string; +}; + +var x: { foo: string, bar: string }; + +var x: { foo: string, bar: string, }; + +var x: { + foo: string, + bar: string +}; + +var x: { + foo: string, + bar: string, + ~ [Unnecessary trailing comma] +}; + +class Test { + + constructor(bar: string) { } + + constructor(bar: string, baz: string,) { } + + constructor( + bar: string, + baz: string, + ack: string + ) { } + + constructor( + bar: string, + baz: string, + ack: string, + foo: string, + ~ [Unnecessary trailing comma] + ) { } + + public foo(bar: string, baz: string) { + return 42; + } + + private foo2(bar: string, baz: string,) { + return 42; + } + + public static foo3( + bar: string, + baz: string + ) { + return 42; + } + + private static foo4( + bar: string, + baz: string, + ~ [Unnecessary trailing comma] + ) { + return 42; + } + + foo5< + T extends Test<[A, A], [A, A,], A>, + U extends Test, + V extends Test< + [ + C, + C + ], + [ + C, + C, + ~ [Unnecessary trailing comma] + ] + C + > + >( + bar: A, + baz: T, + ~ [Unnecessary trailing comma] + ) { + return 42; + } + + foo6< + T extends { foo: A; bar: B; }, + U extends { foo: A; bar: B; }, + V extends { + foo: A; + bar: B; + }, + W extends { + foo: [ + string, + string, + ~ [Unnecessary trailing comma] + ]; + }, + ~ [Unnecessary trailing comma] + >() { return 42; } +} + +class Test2 { } + +class Test3< + A, + B, + C +> { } + +class Test4< + A, + B, + C, + ~ [Unnecessary trailing comma] +> { } + +interface ITest { + foo(bar: string, baz: string); + + foo2(bar: string, baz: string,); + + foo3( + bar: string, + baz: string + ); + + foo4( + bar: string, + baz: string, + ~ [Unnecessary trailing comma] + ); + + foo5< + T extends Test<[A, A], [A, A,], A>, + U extends Test, + V extends Test< + [ + C, + C + ], + [ + C, + C, + ~ [Unnecessary trailing comma] + ] + C + > + >( + bar: A, + baz: T, + ~ [Unnecessary trailing comma] + ); + + foo6< + T extends { foo: A; bar: B; }, + U extends { foo: A; bar: B; }, + V extends { + foo: A; + bar: B; + }, + W extends { + foo: [ + string, + string + ]; + } + >(); +} + +interface ITest2 { } + +interface ITest3< + A, + B, + C +> { } + +interface ITest4< + A, + B, + C, + ~ [Unnecessary trailing comma] +> { } + +enum Foo { BAR, BAZ } + +enum Foo { BAR, BAZ, } + +enum Foo { + Bar, + Baz +} + +enum Foo { + Bar, + Baz, + ~ [Unnecessary trailing comma] +} + +const enum Foo { BAR = 1, BAZ = 2 } + +const enum Foo { BAR = 1, BAZ = 2, } + +const enum Foo { + Bar = 1, + Baz = 2 +} + +const enum Foo { + Bar = 1, + Baz = 2, + ~ [Unnecessary trailing comma] +} + diff --git a/test/rules/trailing-comma/singleline-always/test.ts.lint b/test/rules/trailing-comma/singleline-always/test.ts.lint index aba942571dc..ee6f9c40de9 100644 --- a/test/rules/trailing-comma/singleline-always/test.ts.lint +++ b/test/rules/trailing-comma/singleline-always/test.ts.lint @@ -111,6 +111,21 @@ var [ccA, ccB,] = cc; var [ddOne, ddTwo] = dd; ~ [Missing trailing comma] +var a: [string, number] = null; + ~ [Missing trailing comma] + +var a: [string, number,] = null; + +var a: [ + string, + number +] = null; + +var a: [ + string, + number, +] = null; + import { ClassS, } from "module"; @@ -133,3 +148,428 @@ import {ClassA, ClassB,} from "module"; import {ClassC, ClassD} from "module"; ~ [Missing trailing comma] + +function foo(bar: string, baz: string); + ~ [Missing trailing comma] + +function foo(bar: string, baz: string,); + +function foo( + bar: string, + baz: string +); + +function foo( + bar: string, + baz: string, +); + +var foo = function(bar: string, baz: string) { return 42; }; + ~ [Missing trailing comma] + +var foo = function(bar: string, baz: string,) { return 42; }; + +var foo = function( + bar: string, + baz: string +) { + return 42; +}; + +var foo = function( + bar: string, + baz: string, +) { + return 42; +}; + +function foo(bar: string, baz: string) { return 42; } + ~ [Missing trailing comma] + +function foo(bar: string, baz: string,) { return 42; } + +function foo( + bar: string, + baz: string +) { + return 42; +} + +function foo( + bar: string, + baz: string, +) { + return 42; +} + +function foo(bar: string, baz: string, + ack: string +) { + return 42; +} + +function foo(bar: string, baz: string, + ack: string, +) { + return 42; +} + +var foo = (bar: string, baz: string) => 42; + ~ [Missing trailing comma] + +var foo = (bar: string, baz: string,) => 42; + +var foo = ( + bar: string, + baz: string +) => 42; + +var foo = ( + bar: string, + baz: string, +) => 42; + +var foo: (bar: string, baz: string) => number = null; + ~ [Missing trailing comma] + +var foo: (bar: string, baz: string,) => number = null; + +var foo: ( + bar: string, + baz: string +) => number = null; + +var foo: ( + bar: string, + baz: string, +) => number = null; + +var foo: (bar: string, baz: string) => number; + ~ [Missing trailing comma] + +var foo: (bar: string, baz: string,) => number; + +var foo: ( + bar: string, + baz: string +) => number; + +var foo: ( + bar: string, + baz: string, +) => number; + +var foo: new (bar: string, baz: string) => Test; + ~ [Missing trailing comma] + +var foo: new (bar: string, baz: string,) => Test; + +var foo: new ( + bar: string, + baz: string +) => Test; + +var foo: new ( + bar: string, + baz: string, +) => Test; + +var x = foo(42, 43); + ~ [Missing trailing comma] + +var x = foo(42, 43,); + +var x = foo( + 42, + 43 +); + +var x = foo( + 42, + 43, +); + +var x = new Test("foo"); + ~ [Missing trailing comma] + +var x = new Test("foo",); + +var x = new Test( + "foo" +); + +var x = new Test( + "foo", +); + +var x: { foo: string; bar: string }; + +var x: { foo: string; bar: string; }; + +var x: { + foo: string; + bar: string +}; + +var x: { + foo: string; + bar: string; +}; + +var x: { foo: string, bar: string }; + ~ [Missing trailing comma] + +var x: { foo: string, bar: string, }; + +var x: { + foo: string, + bar: string +}; + +var x: { + foo: string, + bar: string, +}; + +class Test { + ~ [Missing trailing comma] + + constructor(bar: string) { } + ~ [Missing trailing comma] + + constructor(bar: string, baz: string,) { } + + constructor( + bar: string, + baz: string, + ack: string + ) { } + + constructor( + bar: string, + baz: string, + ack: string, + foo: string, + ) { } + + public foo(bar: string, baz: string) { + ~ [Missing trailing comma] + return 42; + } + + private foo2(bar: string, baz: string,) { + return 42; + } + + public static foo3( + bar: string, + baz: string + ) { + return 42; + } + + private static foo4( + bar: string, + baz: string, + ) { + return 42; + } + + foo5< + T extends Test<[A, A], [A, A,], A>, + ~ [Missing trailing comma] + ~ [Missing trailing comma] + U extends Test, + V extends Test< + [ + C, + C + ], + [ + C, + C, + ] + C + > + >( + bar: A, + baz: T, + ) { + return 42; + } + + foo6< + T extends { foo: A; bar: B; }, + U extends { foo: A; bar: B; }, + V extends { + foo: A; + bar: B; + }, + W extends { + foo: [ + string, + string, + ]; + }, + >() { return 42; } + + set bar(foo: string) { } + ~ [Missing trailing comma] + + set bar2(foo: string,) { } + + set bar3( + foo: string + ) { } + + set bar4( + foo: string, + ) { } +} + +class Test2 { } + +class Test3< + A, + B, + C +> { } + +class Test4< + A, + B, + C, +> { } + +interface ITest { + ~ [Missing trailing comma] + + new (bar: U): ITest; + ~ [Missing trailing comma] + ~ [Missing trailing comma] + ~ [Missing trailing comma] + + new < + U, + V + >( + bar: U, + baz: U, + ack: V + ): ITest< + U, + U, + V + >; + + new < + U, + V, + >( + bar: U, + baz: U, + ack: V, + foo: V, + ): ITest< + U, + U, + V, + >; + + foo(bar: string, baz: string); + ~ [Missing trailing comma] + + foo2(bar: string, baz: string,); + + foo3( + bar: string, + baz: string + ); + + foo4( + bar: string, + baz: string, + ); + + foo5< + T extends Test<[A, A], [A, A,], A>, + ~ [Missing trailing comma] + ~ [Missing trailing comma] + U extends Test, + V extends Test< + [ + C, + C + ], + [ + C, + C, + ] + C + > + >( + bar: A, + baz: T, + ); + + foo6< + T extends { foo: A; bar: B; }, + U extends { foo: A; bar: B; }, + V extends { + foo: A; + bar: B; + }, + W extends { + foo: [ + string, + string + ]; + } + >(); +} + +interface ITest2 { } + ~ [Missing trailing comma] + +interface ITest3< + A, + B, + C +> { } + +interface ITest4< + A, + B, + C, +> { } + +enum Foo { BAR, BAZ } + ~ [Missing trailing comma] + +enum Foo { BAR, BAZ, } + +enum Foo { + Bar, + Baz +} + +enum Foo { + Bar, + Baz, +} + +const enum Foo { BAR = 1, BAZ = 2 } + ~ [Missing trailing comma] + +const enum Foo { BAR = 1, BAZ = 2, } + +const enum Foo { + Bar = 1, + Baz = 2 +} + +const enum Foo { + Bar = 1, + Baz = 2, +} + diff --git a/test/rules/trailing-comma/singleline-never/test.ts.lint b/test/rules/trailing-comma/singleline-never/test.ts.lint index 0ecc929bb2f..4c42d04a8d3 100644 --- a/test/rules/trailing-comma/singleline-never/test.ts.lint +++ b/test/rules/trailing-comma/singleline-never/test.ts.lint @@ -111,6 +111,22 @@ var [ccA, ccB,] = cc; var [ddOne, ddTwo] = dd; +var a: [string, number] = null; + +var a: [string, number,] = null; + ~ [Unnecessary trailing comma] + +var a: [ + string, + number +] = null; + +var a: [ + string, + number, +] = null; + + import { ClassS, } from "module"; @@ -133,3 +149,381 @@ import {ClassA, ClassB,} from "module"; ~ [Unnecessary trailing comma] import {ClassC, ClassD} from "module"; + +function foo(bar: string, baz: string); + +function foo(bar: string, baz: string,); + ~ [Unnecessary trailing comma] + +function foo( + bar: string, + baz: string +); + +function foo( + bar: string, + baz: string, +); + +var foo = function(bar: string, baz: string) { return 42; }; + +var foo = function(bar: string, baz: string,) { return 42; }; + ~ [Unnecessary trailing comma] + +var foo = function( + bar: string, + baz: string +) { + return 42; +}; + +var foo = function( + bar: string, + baz: string, +) { + return 42; +}; + +function foo(bar: string, baz: string) { return 42; } + +function foo(bar: string, baz: string,) { return 42; } + ~ [Unnecessary trailing comma] + +function foo( + bar: string, + baz: string +) { + return 42; +} + +function foo( + bar: string, + baz: string, +) { + return 42; +} + +function foo(bar: string, baz: string, + ack: string +) { + return 42; +} + +function foo(bar: string, baz: string, + ack: string, +) { + return 42; +} + +var foo = (bar: string, baz: string) => 42; + +var foo = (bar: string, baz: string,) => 42; + ~ [Unnecessary trailing comma] + +var foo = ( + bar: string, + baz: string +) => 42; + +var foo = ( + bar: string, + baz: string, +) => 42; + +var foo: (bar: string, baz: string) => number = null; + +var foo: (bar: string, baz: string,) => number = null; + ~ [Unnecessary trailing comma] + +var foo: ( + bar: string, + baz: string +) => number = null; + +var foo: ( + bar: string, + baz: string, +) => number = null; + +var foo: (bar: string, baz: string) => number; + +var foo: (bar: string, baz: string,) => number; + ~ [Unnecessary trailing comma] + +var foo: ( + bar: string, + baz: string +) => number; + +var foo: ( + bar: string, + baz: string, +) => number; + +var foo: new (bar: string, baz: string) => Test; + +var foo: new (bar: string, baz: string,) => Test; + ~ [Unnecessary trailing comma] + +var foo: new ( + bar: string, + baz: string +) => Test; + +var foo: new ( + bar: string, + baz: string, +) => Test; + +var x = foo(42, 43); + +var x = foo(42, 43,); + ~ [Unnecessary trailing comma] + +var x = foo( + 42, + 43 +); + +var x = foo( + 42, + 43, +); + +var x = new Test("foo"); + +var x = new Test("foo",); + ~ [Unnecessary trailing comma] + +var x = new Test( + "foo" +); + +var x = new Test( + "foo", +); + +var x: { foo: string; bar: string }; + +var x: { foo: string; bar: string; }; + +var x: { + foo: string; + bar: string +}; + +var x: { + foo: string; + bar: string; +}; + +var x: { foo: string, bar: string }; + +var x: { foo: string, bar: string, }; + ~ [Unnecessary trailing comma] + +var x: { + foo: string, + bar: string +}; + +var x: { + foo: string, + bar: string, +}; + +class Test { + + constructor(bar: string) { } + + constructor(bar: string, baz: string,) { } + ~ [Unnecessary trailing comma] + + constructor( + bar: string, + baz: string, + ack: string + ) { } + + constructor( + bar: string, + baz: string, + ack: string, + foo: string, + ) { } + + public foo(bar: string, baz: string) { + return 42; + } + + private foo2(bar: string, baz: string,) { + ~ [Unnecessary trailing comma] + return 42; + } + + public static foo3( + bar: string, + baz: string + ) { + return 42; + } + + private static foo4( + bar: string, + baz: string, + ) { + return 42; + } + + foo5< + T extends Test<[A, A], [A, A,], A>, + ~ [Unnecessary trailing comma] + U extends Test, + ~ [Unnecessary trailing comma] + V extends Test< + [ + C, + C + ], + [ + C, + C, + ] + C + > + >( + bar: A, + baz: T, + ) { + return 42; + } + + foo6< + T extends { foo: A, bar: B }, + U extends { foo: A, bar: B }, + V extends { + foo: A; + bar: B; + }, + W extends { + foo: [ + string, + string, + ]; + }, + >() { return 42; } +} + +class Test2 { } + ~ [Unnecessary trailing comma] + + +class Test3< + A, + B, + C +> { } + +class Test4< + A, + B, + C, +> { } + +interface ITest { + foo(bar: string, baz: string); + + foo2(bar: string, baz: string,); + ~ [Unnecessary trailing comma] + + foo3( + bar: string, + baz: string + ); + + foo4( + bar: string, + baz: string, + ); + + foo5< + T extends Test<[A, A], [A, A,], A>, + ~ [Unnecessary trailing comma] + U extends Test, + ~ [Unnecessary trailing comma] + V extends Test< + [ + C, + C + ], + [ + C, + C, + ] + C + > + >( + bar: A, + baz: T, + ); + + foo6< + T extends { foo: A, bar: B }, + U extends { foo: A, bar: B }, + V extends { + foo: A; + bar: B; + }, + W extends { + foo: [ + string, + string + ]; + } + >(); +} + +interface ITest2 { } + +interface ITest3< + A, + B, + C +> { } + +interface ITest4< + A, + B, + C, +> { } + +enum Foo { BAR, BAZ } + +enum Foo { BAR, BAZ, } + ~ [Unnecessary trailing comma] + +enum Foo { + Bar, + Baz +} + +enum Foo { + Bar, + Baz, +} + +const enum Foo { BAR = 1, BAZ = 2 } + +const enum Foo { BAR = 1, BAZ = 2, } + ~ [Unnecessary trailing comma] + +const enum Foo { + Bar = 1, + Baz = 2 +} + +const enum Foo { + Bar = 1, + Baz = 2, +} +