Skip to content

Commit

Permalink
fix(eslint-plugin): [method-signature-style] don't auto-fix interface…
Browse files Browse the repository at this point in the history
…s within namespaces (#2678)
  • Loading branch information
aggmoulik committed Oct 19, 2020
1 parent 5225a76 commit e012049
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 43 deletions.
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,
},
],
},
],
});

0 comments on commit e012049

Please sign in to comment.