Skip to content

Commit

Permalink
New: Add adjacent-overload-signatures (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
weirdpattern authored and JamesHenry committed Jan 17, 2019
1 parent 4667709 commit f5aa4b8
Show file tree
Hide file tree
Showing 4 changed files with 812 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/eslint-plugin-typescript/README.md
Expand Up @@ -61,3 +61,4 @@ Then configure the rules you want to use under the rules section.
* `typescript/no-type-literal` - disallows the use of type aliases.
* `typescript/member-ordering` - enforces a standard member declaration order.
* `typescript/no-unused-vars` - prevents TypeScript-specific constructs from being erroneously flagged as unused
* `typescript/adjacent-overload-signatures` - enforces member overloads to be consecutive.
@@ -0,0 +1,79 @@
# Enforces member overloads to be consecutive.

Grouping overloaded members (methods and functions) together can improve readability of the code.

## Rule Details

This rule aims to standardise the way overloaded members are organized.

The following patterns are considered warnings:

```ts
declare namespace Foo {
export function foo(s: string): void;
export function foo(n: number): void;
export function bar(): void;
export function foo(sn: string | number): void;
}

type Foo = {
foo(s: string): void;
foo(n: number): void;
bar(): void;
foo(sn: string | number): void;
}

interface Foo {
foo(s: string): void;
foo(n: number): void;
bar(): void;
foo(sn: string | number): void;
}

class Foo {
foo(s: string): void;
foo(n: number): void;
bar(): void {}
foo(sn: string | number): void {}
}
```

The following patterns are not warnings:

```ts
declare namespace Foo {
export function foo(s: string): void;
export function foo(n: number): void;
export function foo(sn: string | number): void;
export function bar(): void;
}

type Foo = {
foo(s: string): void;
foo(n: number): void;
foo(sn: string | number): void;
bar(): void;
}

interface Foo {
foo(s: string): void;
foo(n: number): void;
foo(sn: string | number): void;
bar(): void;
}

class Foo {
foo(s: string): void;
foo(n: number): void;
foo(sn: string | number): void {}
bar(): void {}
}
```

## When Not To Use It

If you don't care about the general structure of the code, then you will not need this rule.

## Compatibility

* TSLint: [adjacent-overload-signatures](https://palantir.github.io/tslint/rules/adjacent-overload-signatures/)
@@ -0,0 +1,99 @@
/**
* @fileoverview Enforces member overloads to be consecutive.
* @author Patricio Trevino
*/
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = {
meta: {
docs: {
description: "Enforces member overloads to be consecutive",
category: "TypeScript"
},
schema: []
},

create(context) {

//----------------------------------------------------------------------
// Helpers
//----------------------------------------------------------------------

/**
* Gets the name of the member being processed.
* @param {ASTNode} member the member being processed.
* @returns {string} the name of the member or null if it's a member not relevant to the rule.
* @private
*/
function getMemberName(member) {
switch (member.type) {
case "ExportNamedDeclaration": {
return member.declaration.id.name;
}
case "DeclareFunction":
case "FunctionDeclaration":
case "TSNamespaceFunctionDeclaration": {
return member.id.name;
}
case "TSMethodSignature": {
return member.key && (member.key.name || member.key.value) ||
member.name && (member.name.name || member.name.value);
}
case "TSCallSignature": {
return "call";
}
case "MethodDefinition": {
return member.key.name || member.key.value;
}
default: {
return null;
}
}
}

/**
* Check the body for overload methods.
* @param {ASTNode} node the body to be inspected.
* @returns {void}
* @private
*/
function checkBodyForOverloadMethods(node) {
const members = node.body || node.members;

if (members) {
const seen = [];
let index, name, lastName;

members.forEach(member => {
name = getMemberName(member);
index = seen.indexOf(name);
if (index > -1 && lastName !== name) {
context.report({
node: member,
message: `All '${name}' signatures should be adjacent`
});
} else if (index === -1) {
seen.push(name);
}

lastName = name;
});
}
}

//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------
return {
TSModuleBlock: checkBodyForOverloadMethods,
TSTypeLiteral: checkBodyForOverloadMethods,
TSInterfaceBody: checkBodyForOverloadMethods,
ClassBody: checkBodyForOverloadMethods,
Program: checkBodyForOverloadMethods
};
}
};

0 comments on commit f5aa4b8

Please sign in to comment.