Skip to content

Commit

Permalink
feat(eslint-plugin): [explicit-function-return-type] add allowedNames (
Browse files Browse the repository at this point in the history
…#4440)

* feat(eslint-plugin): [explicit-function-return-type] add allowedNames option

* feat(eslint-plugin): [explicit-function-return-type] afix typecheck

* Update packages/eslint-plugin/src/rules/explicit-function-return-type.ts

Co-authored-by: Josh Goldberg <me@joshuakgoldberg.com>

* feat(eslint-plugin): [explicit-function-return-type] Change to allowedNames to work for object properties and class methods

* feat(eslint-plugin): [explicit-function-return-type] Change to allowedNames to work for object properties and class methods

* fix(eslint-plugin): [explicit-function-return-type] fix for codecov

* fix(eslint-plugin): [explicit-function-return-type] add test

* fix(eslint-plugin): [explicit-function-return-type] add test

* fix(eslint-plugin): [explicit-function-return-type] fix for codecov

* fix(eslint-plugin): [explicit-function-return-type] Change allowedName to not ignore computed property

Co-authored-by: Josh Goldberg <me@joshuakgoldberg.com>
Co-authored-by: Josh Goldberg <joshuakgoldberg@outlook.com>
  • Loading branch information
3 people committed Feb 2, 2022
1 parent a2bd048 commit 936e252
Show file tree
Hide file tree
Showing 3 changed files with 275 additions and 0 deletions.
20 changes: 20 additions & 0 deletions packages/eslint-plugin/docs/rules/explicit-function-return-type.md
Expand Up @@ -77,6 +77,10 @@ type Options = {
allowDirectConstAssertionInArrowFunctions?: boolean;
// if true, concise arrow functions that start with the void keyword will not be checked
allowConciseArrowFunctionExpressionsStartingWithVoid?: boolean;
/**
* An array of function/method names that will not have their arguments or their return values checked.
*/
allowedNames?: string[];
};

const defaults = {
Expand All @@ -85,6 +89,7 @@ const defaults = {
allowHigherOrderFunctions: true,
allowDirectConstAssertionInArrowFunctions: true,
allowConciseArrowFunctionExpressionsStartingWithVoid: false,
allowedNames: [],
};
```

Expand Down Expand Up @@ -262,6 +267,21 @@ const log = (message: string) => {
var log = (message: string) => void console.log(message);
```

### `allowedNames`

You may pass function/method names you would like this rule to ignore, like so:

```json
{
"@typescript-eslint/explicit-function-return-type": [
"error",
{
"allowedNames": ["ignoredFunctionName", "ignoredMethodName"]
}
]
}
```

## When Not To Use It

If you don't wish to prevent calling code from using function return values in unexpected ways, then
Expand Down
67 changes: 67 additions & 0 deletions packages/eslint-plugin/src/rules/explicit-function-return-type.ts
Expand Up @@ -13,6 +13,7 @@ type Options = [
allowHigherOrderFunctions?: boolean;
allowDirectConstAssertionInArrowFunctions?: boolean;
allowConciseArrowFunctionExpressionsStartingWithVoid?: boolean;
allowedNames?: string[];
},
];
type MessageIds = 'missingReturnType';
Expand Down Expand Up @@ -48,6 +49,12 @@ export default util.createRule<Options, MessageIds>({
allowConciseArrowFunctionExpressionsStartingWithVoid: {
type: 'boolean',
},
allowedNames: {
type: 'array',
items: {
type: 'string',
},
},
},
additionalProperties: false,
},
Expand All @@ -60,11 +67,64 @@ export default util.createRule<Options, MessageIds>({
allowHigherOrderFunctions: true,
allowDirectConstAssertionInArrowFunctions: true,
allowConciseArrowFunctionExpressionsStartingWithVoid: false,
allowedNames: [],
},
],
create(context, [options]) {
const sourceCode = context.getSourceCode();
function isAllowedName(
node:
| TSESTree.ArrowFunctionExpression
| TSESTree.FunctionExpression
| TSESTree.FunctionDeclaration,
): boolean {
if (!options.allowedNames || !options.allowedNames.length) {
return false;
}

if (
node.type === AST_NODE_TYPES.ArrowFunctionExpression ||
node.type === AST_NODE_TYPES.FunctionExpression
) {
const parent = node.parent;
let funcName;
if (node.id?.name) {
funcName = node.id.name;
} else if (parent) {
switch (parent.type) {
case AST_NODE_TYPES.VariableDeclarator: {
if (parent.id.type === AST_NODE_TYPES.Identifier) {
funcName = parent.id.name;
}
break;
}
case AST_NODE_TYPES.MethodDefinition:
case AST_NODE_TYPES.PropertyDefinition:
case AST_NODE_TYPES.Property: {
if (
parent.key.type === AST_NODE_TYPES.Identifier &&
parent.computed === false
) {
funcName = parent.key.name;
}
break;
}
}
}
if (!!funcName && !!options.allowedNames.includes(funcName)) {
return true;
}
}
if (
node.type === AST_NODE_TYPES.FunctionDeclaration &&
node.id &&
node.id.type === AST_NODE_TYPES.Identifier &&
!!options.allowedNames.includes(node.id.name)
) {
return true;
}
return false;
}
return {
'ArrowFunctionExpression, FunctionExpression'(
node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,
Expand All @@ -79,6 +139,10 @@ export default util.createRule<Options, MessageIds>({
return;
}

if (isAllowedName(node)) {
return;
}

if (
options.allowTypedFunctionExpressions &&
(isValidFunctionExpressionReturnType(node, options) ||
Expand All @@ -96,6 +160,9 @@ export default util.createRule<Options, MessageIds>({
);
},
FunctionDeclaration(node): void {
if (isAllowedName(node)) {
return;
}
if (options.allowTypedFunctionExpressions && node.returnType) {
return;
}
Expand Down
Expand Up @@ -400,6 +400,99 @@ new Foo(1, () => {});
code: 'const log = (message: string) => void console.log(message);',
options: [{ allowConciseArrowFunctionExpressionsStartingWithVoid: true }],
},
{
filename: 'test.ts',
options: [
{
allowedNames: ['test1', 'test2'],
},
],
code: `
function test1() {
return;
}
const foo = function test2() {
return;
};
`,
},
{
filename: 'test.ts',
options: [
{
allowedNames: ['test1', 'test2'],
},
],
code: `
const test1 = function () {
return;
};
const foo = function () {
return function test2() {};
};
`,
},
{
filename: 'test.ts',
options: [
{
allowedNames: ['test1', 'test2'],
},
],
code: `
const test1 = () => {
return;
};
export const foo = {
test2() {
return 0;
},
};
`,
},
{
filename: 'test.ts',
code: `
class Test {
constructor() {}
get prop() {
return 1;
}
set prop() {}
method() {
return;
}
arrow = () => 'arrow';
private method() {
return;
}
}
`,
options: [
{
allowedNames: ['prop', 'method', 'arrow'],
},
],
},
{
filename: 'test.ts',
code: `
const x = {
arrowFn: () => {
return;
},
fn: function () {
return;
},
};
`,
options: [
{
allowedNames: ['arrowFn', 'fn'],
},
],
},
{
filename: 'test.ts',
code: `
Expand Down Expand Up @@ -1226,5 +1319,100 @@ const func = (value: number) => ({ type: 'X', value } as const);
},
],
},
{
filename: 'test.ts',
options: [
{
allowedNames: ['test', '1'],
},
],
code: `
function hoge() {
return;
}
const foo = () => {
return;
};
const baz = function () {
return;
};
let [test, test] = function () {
return;
};
class X {
[test] = function () {
return;
};
}
const x = {
1: function () {
reutrn;
},
};
`,
errors: [
{
messageId: 'missingReturnType',
line: 2,
endLine: 2,
column: 1,
endColumn: 16,
},
{
messageId: 'missingReturnType',
line: 5,
endLine: 5,
column: 13,
endColumn: 18,
},
{
messageId: 'missingReturnType',
line: 8,
endLine: 8,
column: 13,
endColumn: 24,
},
{
messageId: 'missingReturnType',
line: 11,
endLine: 11,
column: 20,
endColumn: 31,
},
{
line: 15,
column: 12,
messageId: 'missingReturnType',
endLine: 15,
endColumn: 23,
},
{
messageId: 'missingReturnType',
line: 20,
endLine: 20,
column: 6,
endColumn: 17,
},
],
},
{
filename: 'test.ts',
code: `
const ignoredName = 'notIgnoredName';
class Foo {
[ignoredName]() {}
}
`,
options: [{ allowedNames: ['ignoredName'] }],
errors: [
{
messageId: 'missingReturnType',
line: 4,
endLine: 4,
column: 3,
endColumn: 18,
},
],
},
],
});

0 comments on commit 936e252

Please sign in to comment.