Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

Add option to ignore accessors in adjacent-overload-signatures #3718

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
96a0c36
add noAsyncWithoutAwait rule
eranshabi Jun 6, 2018
5b4e3c3
fix lint
eranshabi Jun 8, 2018
7f6d5c7
code review updates
eranshabi Jun 17, 2018
5abe892
Merge remote-tracking branch 'upstream/master'
eranshabi Jun 17, 2018
e5a7c29
Add option to ignore accessors in adjacent-overload-signatures
saberduck Feb 14, 2018
9962297
Fix options schema
saberduck May 3, 2018
f4680ef
allow return as well as await
eranshabi Jul 6, 2018
d28b2d3
remove unneeded lint ignore
eranshabi Jul 6, 2018
337cd30
Merge remote-tracking branch 'upstream/master'
eranshabi Jul 6, 2018
7e11840
Merge remote-tracking branch 'upstream/master'
eranshabi Aug 2, 2018
57d08c7
Merge remote-tracking branch 'upstream/master' into ignore_accessors_…
saberduck Nov 14, 2018
4f51780
Merge remote-tracking branch 'upstream/master'
eranshabi Nov 19, 2018
bfa4c91
improve rationale & fix performance issue
eranshabi Nov 19, 2018
37aa7b5
fixes according to review
eranshabi Dec 26, 2018
0d58f68
finish fixing according to review
eranshabi Dec 27, 2018
7292df5
Merge branch 'master'
Jun 16, 2019
96f39ed
Initial feedback cleanups
Jun 16, 2019
7a782a5
Merge remote-tracking branch 'upstream/master'
Jun 16, 2019
65e10f5
Refactored to walk function
Jun 16, 2019
6d31f6a
Merge branch 'master' into ignore_accessors_in_adjacent_overload
Jun 16, 2019
201e4f2
Merge branch 'master' of https://github.com/palantir/tslint
Jun 16, 2019
9711521
Merge branch 'master' into ignore_accessors_in_adjacent_overload
Jun 16, 2019
7316e8a
Reset tslint.json to master
Jun 16, 2019
1c20797
Converted options to object form
Jun 16, 2019
21e9815
Disabled no-object-literal-type-assertion complaint
Jun 16, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 36 additions & 10 deletions src/rules/adjacentOverloadSignaturesRule.ts
Expand Up @@ -20,14 +20,30 @@ import * as ts from "typescript";

import * as Lint from "../index";

const IGNORE_ACCESSORS = "ignore-accessors";

interface Options {
ignoreAccessors: boolean;
}

export class Rule extends Lint.Rules.AbstractRule {
/* tslint:disable:object-literal-sort-keys */
public static metadata: Lint.IRuleMetadata = {
ruleName: "adjacent-overload-signatures",
description: "Enforces function overloads to be consecutive.",
optionsDescription: "Not configurable.",
options: null,
optionExamples: [true],
optionsDescription: Lint.Utils.dedent`
If \`${IGNORE_ACCESSORS}\` is specified, then getters and setters are not considered to be overloads
of function with the same signature.`,
options: {
type: "array",
items: {
type: "string",
enum: [IGNORE_ACCESSORS],
},
minLength: 0,
maxLength: 1,
},
optionExamples: [true, [true, IGNORE_ACCESSORS]],
rationale: "Improves readability and organization by grouping naturally related items together.",
type: "typescript",
typescriptOnly: true,
Expand All @@ -39,11 +55,13 @@ export class Rule extends Lint.Rules.AbstractRule {
}

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
return this.applyWithFunction(sourceFile, walk, {
ignoreAccessors: this.ruleArguments.indexOf(IGNORE_ACCESSORS) !== -1,
});
}
}

function walk(ctx: Lint.WalkContext<void>): void {
function walk(ctx: Lint.WalkContext<Options>): void {
const { sourceFile } = ctx;
visitStatements(sourceFile.statements);
return ts.forEachChild(sourceFile, function cb(node: ts.Node): void {
Expand All @@ -56,8 +74,10 @@ function walk(ctx: Lint.WalkContext<void>): void {
case ts.SyntaxKind.ClassDeclaration:
case ts.SyntaxKind.TypeLiteral: {
const { members } = node as ts.InterfaceDeclaration | ts.ClassDeclaration | ts.TypeLiteralNode;
addFailures(getMisplacedOverloads<ts.TypeElement | ts.ClassElement>(members, (member) =>
utils.isSignatureDeclaration(member) ? getOverloadKey(member) : undefined));
addFailures(getMisplacedOverloads<ts.TypeElement | ts.ClassElement>(
members,
(member) => utils.isSignatureDeclaration(member) ? getOverloadKey(member) : undefined,
ctx.options.ignoreAccessors));
}
}

Expand All @@ -66,7 +86,8 @@ function walk(ctx: Lint.WalkContext<void>): void {

function visitStatements(statements: ReadonlyArray<ts.Statement>): void {
addFailures(getMisplacedOverloads(statements, (statement) =>
utils.isFunctionDeclaration(statement) && statement.name !== undefined ? statement.name.text : undefined));
utils.isFunctionDeclaration(statement) && statement.name !== undefined ? statement.name.text : undefined,
ctx.options.ignoreAccessors));
}

function addFailures(misplacedOverloads: ReadonlyArray<ts.SignatureDeclaration>): void {
Expand All @@ -79,12 +100,13 @@ function walk(ctx: Lint.WalkContext<void>): void {
/** 'getOverloadName' may return undefined for nodes that cannot be overloads, e.g. a `const` declaration. */
function getMisplacedOverloads<T extends ts.Node>(
overloads: ReadonlyArray<T>,
getKey: (node: T) => string | undefined): ts.SignatureDeclaration[] {
getKey: (node: T) => string | undefined,
ignoreAccessors: boolean): ts.SignatureDeclaration[] {
const result: ts.SignatureDeclaration[] = [];
let lastKey: string | undefined;
const seen = new Set<string>();
for (const node of overloads) {
if (node.kind === ts.SyntaxKind.SemicolonClassElement) {
if (node.kind === ts.SyntaxKind.SemicolonClassElement || (ignoreAccessors && isAccessor(node))) {
continue;
}

Expand All @@ -102,6 +124,10 @@ function getMisplacedOverloads<T extends ts.Node>(
return result;
}

function isAccessor(member: ts.Node): boolean {
return member.kind === ts.SyntaxKind.GetAccessor || member.kind === ts.SyntaxKind.SetAccessor;
}

function printOverload(node: ts.SignatureDeclaration): string {
const info = getOverloadInfo(node);
return typeof info === "string" ? info : info === undefined ? "<unknown>" : info.name;
Expand Down
Expand Up @@ -153,3 +153,14 @@ interface I {
[Symbol.iterator](): void;
~~~~~~~~~~~~~~~~~~~~~~~~~~ [All 'Symbol.iterator' signatures should be adjacent]
}

class Accessors {
private x: number;
private y: number;
get x() {return this.x;}
get y() {return this.y;}
set x(newX: number) {this.x = newX;}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [All 'x' signatures should be adjacent]
set y(newY: number) {this.y = newY;}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [All 'y' signatures should be adjacent]
}
@@ -0,0 +1,11 @@
// good

class Accessors {
private x: number;
private y: number;
get x() {return this.x;}
get y() {return this.y;}
// setter is not considered as an overload of getter
set x(newX: number) {this.x = newX;}
set y(newY: number) {this.y = newY;}
}
@@ -0,0 +1,5 @@
{
"rules": {
"adjacent-overload-signatures": [true, "ignore-accessors"]
}
}