Skip to content

Commit

Permalink
feat(eslint-plugin): [unified-signatures] support ignoring overload s…
Browse files Browse the repository at this point in the history
…ignatures with different JSDoc comments (#10781)

* initial implementation

* add a test for interfaces

* remove some redundant 'export function ...' tests

* check for block comments instead of a heuristic to check jsdoc comments
  • Loading branch information
ronami authored Mar 3, 2025
1 parent 84af50e commit 02d9d73
Show file tree
Hide file tree
Showing 5 changed files with 439 additions and 3 deletions.
44 changes: 44 additions & 0 deletions packages/eslint-plugin/docs/rules/unified-signatures.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,50 @@ function f(b: string): void;
</TabItem>
</Tabs>

### `ignoreOverloadsWithDifferentJSDoc`

{/* insert option description */}

Examples of code for this rule with `ignoreOverloadsWithDifferentJSDoc`:

<Tabs>
<TabItem value="❌ Incorrect">

```ts option='{ "ignoreOverloadsWithDifferentJSDoc": true }'
declare function f(x: string): void;
declare function f(x: boolean): void;
/**
* @deprecate
*/
declare function f(x: number): void;
/**
* @deprecate
*/
declare function f(x: null): void;
```

</TabItem>
<TabItem value="✅ Correct">

```ts option='{ "ignoreOverloadsWithDifferentJSDoc": true }'
declare function f(x: string): void;
/**
* This signature does something else.
*/
declare function f(x: boolean): void;
/**
* @async
*/
declare function f(x: number): void;
/**
* @deprecate
*/
declare function f(x: null): void;
```

</TabItem>
</Tabs>

## When Not To Use It

This is purely a stylistic rule to help with readability of function signature overloads.
Expand Down
37 changes: 34 additions & 3 deletions packages/eslint-plugin/src/rules/unified-signatures.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { TSESTree } from '@typescript-eslint/utils';

import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils';

import type { Equal } from '../util';

Expand Down Expand Up @@ -61,6 +61,7 @@ export type MessageIds =
export type Options = [
{
ignoreDifferentlyNamedParameters?: boolean;
ignoreOverloadsWithDifferentJSDoc?: boolean;
},
];

Expand Down Expand Up @@ -91,16 +92,25 @@ export default createRule<Options, MessageIds>({
description:
'Whether two parameters with different names at the same index should be considered different even if their types are the same.',
},
ignoreOverloadsWithDifferentJSDoc: {
type: 'boolean',
description:
'Whether two overloads with different JSDoc comments should be considered different even if their parameter and return types are the same.',
},
},
},
],
},
defaultOptions: [
{
ignoreDifferentlyNamedParameters: false,
ignoreOverloadsWithDifferentJSDoc: false,
},
],
create(context, [{ ignoreDifferentlyNamedParameters }]) {
create(
context,
[{ ignoreDifferentlyNamedParameters, ignoreOverloadsWithDifferentJSDoc }],
) {
//----------------------------------------------------------------------
// Helpers
//----------------------------------------------------------------------
Expand Down Expand Up @@ -230,6 +240,15 @@ export default createRule<Options, MessageIds>({
}
}

if (ignoreOverloadsWithDifferentJSDoc) {
const aComment = getBlockCommentForNode(getExportingNode(a) ?? a);
const bComment = getBlockCommentForNode(getExportingNode(b) ?? b);

if (aComment?.value !== bComment?.value) {
return false;
}
}

return (
typesAreEqual(a.returnType, b.returnType) &&
// Must take the same type parameters.
Expand Down Expand Up @@ -522,6 +541,18 @@ export default createRule<Options, MessageIds>({
currentScope = scopes.pop();
}

/**
* @returns the first valid JSDoc comment annotating `node`
*/
function getBlockCommentForNode(
node: TSESTree.Node,
): TSESTree.Comment | undefined {
return context.sourceCode
.getCommentsBefore(node)
.reverse()
.find(comment => comment.type === AST_TOKEN_TYPES.Block);
}

function addOverload(
signature: OverloadNode,
key?: string,
Expand Down Expand Up @@ -590,7 +621,7 @@ export default createRule<Options, MessageIds>({
});

function getExportingNode(
node: TSESTree.TSDeclareFunction,
node: SignatureDefinition,
):
| TSESTree.ExportDefaultDeclaration
| TSESTree.ExportNamedDeclaration
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 02d9d73

Please sign in to comment.