Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(eslint-plugin): [method-signature-style] don't auto-fix interfaces within namespaces #2678

Merged
merged 8 commits into from Oct 19, 2020
119 changes: 76 additions & 43 deletions packages/eslint-plugin/src/rules/method-signature-style.ts
Expand Up @@ -97,6 +97,21 @@ export default util.createRule<Options, MessageIds>({
return '';
}

function isNodeParentModuleDeclaration(node: TSESTree.Node): boolean {
if (!node.parent) {
return false;
}

if (node.parent.type === AST_NODE_TYPES.TSModuleDeclaration) {
return true;
}

if (node.parent.type === AST_NODE_TYPES.Program) {
return false;
}
return isNodeParentModuleDeclaration(node.parent);
}

return {
TSMethodSignature(methodNode): void {
if (mode === 'method') {
Expand All @@ -112,61 +127,79 @@ export default util.createRule<Options, MessageIds>({
getMethodKey(element) === getMethodKey(methodNode),
)
: [];
const isParentModule = isNodeParentModuleDeclaration(methodNode);

if (duplicatedKeyMethodNodes.length > 0) {
if (isParentModule) {
context.report({
node: methodNode,
messageId: 'errorMethod',
});
} else {
context.report({
node: methodNode,
messageId: 'errorMethod',
*fix(fixer) {
const methodNodes = [
methodNode,
...duplicatedKeyMethodNodes,
].sort((a, b) => (a.range[0] < b.range[0] ? -1 : 1));
const typeString = methodNodes.reduce(
(str, node, idx, nodes) => {
const params = getMethodParams(node);
const returnType = getMethodReturnType(node);
return `${str}(${params} => ${returnType})${
idx !== nodes.length - 1 ? ' & ' : ''
}`;
},
'',
);
const key = getMethodKey(methodNode);
const delimiter = getDelimiter(methodNode);
yield fixer.replaceText(
methodNode,
`${key}: ${typeString}${delimiter}`,
);
for (const node of duplicatedKeyMethodNodes) {
const lastToken = sourceCode.getLastToken(node);
if (lastToken) {
const nextToken = sourceCode.getTokenAfter(lastToken);
if (nextToken) {
yield fixer.remove(node);
yield fixer.replaceTextRange(
[lastToken.range[1], nextToken.range[0]],
'',
);
}
}
}
},
});
}
return;
}

if (isParentModule) {
context.report({
node: methodNode,
messageId: 'errorMethod',
*fix(fixer) {
const methodNodes = [
methodNode,
...duplicatedKeyMethodNodes,
].sort((a, b) => (a.range[0] < b.range[0] ? -1 : 1));
const typeString = methodNodes.reduce((str, node, idx, nodes) => {
const params = getMethodParams(node);
const returnType = getMethodReturnType(node);
return `${str}(${params} => ${returnType})${
idx !== nodes.length - 1 ? ' & ' : ''
}`;
}, '');
});
} else {
context.report({
node: methodNode,
messageId: 'errorMethod',
fix: fixer => {
const key = getMethodKey(methodNode);
const params = getMethodParams(methodNode);
const returnType = getMethodReturnType(methodNode);
const delimiter = getDelimiter(methodNode);
yield fixer.replaceText(
return fixer.replaceText(
methodNode,
`${key}: ${typeString}${delimiter}`,
`${key}: ${params} => ${returnType}${delimiter}`,
);
for (const node of duplicatedKeyMethodNodes) {
const lastToken = sourceCode.getLastToken(node);
if (lastToken) {
const nextToken = sourceCode.getTokenAfter(lastToken);
if (nextToken) {
yield fixer.remove(node);
yield fixer.replaceTextRange(
[lastToken.range[1], nextToken.range[0]],
'',
);
}
}
}
},
});
return;
}

context.report({
node: methodNode,
messageId: 'errorMethod',
fix: fixer => {
const key = getMethodKey(methodNode);
const params = getMethodParams(methodNode);
const returnType = getMethodReturnType(methodNode);
const delimiter = getDelimiter(methodNode);
return fixer.replaceText(
methodNode,
`${key}: ${params} => ${returnType}${delimiter}`,
);
},
});
},
TSPropertySignature(propertyNode): void {
const typeNode = propertyNode.typeAnnotation?.typeAnnotation;
Expand Down
23 changes: 23 additions & 0 deletions packages/eslint-plugin/tests/rules/method-signature-style.test.ts
Expand Up @@ -348,5 +348,28 @@ interface Foo {
},
],
},
{
code: noFormat`
declare global {
namespace jest {
interface Matchers<R, T> {
// Add overloads specific to the DOM
toHaveProp<K extends keyof DomPropsOf<T>>(name: K, value?: DomPropsOf<T>[K]): R;
toHaveProps(props: Partial<DomPropsOf<T>>): R;
}
}
}
`,
errors: [
{
messageId: 'errorMethod',
line: 6,
},
{
messageId: 'errorMethod',
line: 7,
},
],
},
],
});