Skip to content

Commit

Permalink
fix(eslint-plugin): crash fixing readonly arrays to generic (#1172)
Browse files Browse the repository at this point in the history
  • Loading branch information
a-tarasyuk authored and bradzacher committed Nov 5, 2019
1 parent 643d6d6 commit 2b2f2d7
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 13 deletions.
45 changes: 32 additions & 13 deletions packages/eslint-plugin/src/rules/array-type.ts
Expand Up @@ -146,7 +146,8 @@ export default util.createRule<Options, MessageIds>({
return false;
}

if (node.range[0] - prevToken.range[1] > 0) {
const nextToken = sourceCode.getTokenAfter(prevToken);
if (nextToken && sourceCode.isSpaceBetweenTokens(prevToken, nextToken)) {
return false;
}

Expand All @@ -168,6 +169,21 @@ export default util.createRule<Options, MessageIds>({
return 'T';
}

/**
* @param node the node to be evaluated
*/
function getTypeOpNodeRange(
node: TSESTree.Node | null,
): [number, number] | undefined {
if (!node) {
return undefined;
}

const firstToken = sourceCode.getFirstToken(node)!;
const nextToken = sourceCode.getTokenAfter(firstToken)!;
return [firstToken.range[0], nextToken.range[0]];
}

return {
TSArrayType(node): void {
if (
Expand Down Expand Up @@ -208,24 +224,27 @@ export default util.createRule<Options, MessageIds>({
type: getMessageType(node.elementType),
},
fix(fixer) {
const startText = requireWhitespaceBefore(node);
const toFix = [
fixer.replaceTextRange([node.range[1] - 2, node.range[1]], '>'),
fixer.insertTextBefore(
node,
`${startText ? ' ' : ''}${isReadonly ? 'Readonly' : ''}Array<`,
),
];
if (typeOpNode) {
// remove the readonly operator if it exists
toFix.unshift(
fixer.removeRange([
typeOpNode.range[0],
typeOpNode.range[0] + 'readonly '.length,
]),
const startText = requireWhitespaceBefore(node);
const typeOpNodeRange = getTypeOpNodeRange(typeOpNode);

if (typeOpNodeRange) {
toFix.unshift(fixer.removeRange(typeOpNodeRange));
} else {
toFix.push(
fixer.insertTextBefore(node, `${startText ? ' ' : ''}`),
);
}

toFix.push(
fixer.insertTextBefore(
node,
`${isReadonly ? 'Readonly' : ''}Array<`,
),
);

if (node.elementType.type === AST_NODE_TYPES.TSParenthesizedType) {
const first = sourceCode.getFirstToken(node.elementType);
const last = sourceCode.getLastToken(node.elementType);
Expand Down
30 changes: 30 additions & 0 deletions packages/eslint-plugin/tests/rules/array-type.test.ts
Expand Up @@ -1071,5 +1071,35 @@ class Foo<T = Bar[][]> extends Bar<T, T[]> implements Baz<T[]> {
`let a: readonly Array<number>[] = []`,
'array',
);
testOutput(
'generic',
`type T = readonly(string)[]`,
`type T = ReadonlyArray<string>`,
'generic',
);
testOutput(
'generic',
`let a: readonly(readonly string[])[] = []`,
`let a: ReadonlyArray<ReadonlyArray<string>> = []`,
'generic',
);
testOutput(
'generic',
`type T = readonly(readonly string[])[]`,
`type T = ReadonlyArray<ReadonlyArray<string>>`,
'generic',
);
testOutput(
'generic',
`type T = readonly (readonly string[])[]`,
`type T = ReadonlyArray<ReadonlyArray<string>>`,
'generic',
);
testOutput(
'generic',
`type T = readonly (readonly string[])[]`,
`type T = ReadonlyArray<ReadonlyArray<string>>`,
'generic',
);
});
});

0 comments on commit 2b2f2d7

Please sign in to comment.