Skip to content

Commit 2b2f2d7

Browse files
a-tarasyukbradzacher
authored andcommitted
fix(eslint-plugin): crash fixing readonly arrays to generic (#1172)
1 parent 643d6d6 commit 2b2f2d7

File tree

2 files changed

+62
-13
lines changed

2 files changed

+62
-13
lines changed

packages/eslint-plugin/src/rules/array-type.ts

+32-13
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ export default util.createRule<Options, MessageIds>({
146146
return false;
147147
}
148148

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

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

172+
/**
173+
* @param node the node to be evaluated
174+
*/
175+
function getTypeOpNodeRange(
176+
node: TSESTree.Node | null,
177+
): [number, number] | undefined {
178+
if (!node) {
179+
return undefined;
180+
}
181+
182+
const firstToken = sourceCode.getFirstToken(node)!;
183+
const nextToken = sourceCode.getTokenAfter(firstToken)!;
184+
return [firstToken.range[0], nextToken.range[0]];
185+
}
186+
171187
return {
172188
TSArrayType(node): void {
173189
if (
@@ -208,24 +224,27 @@ export default util.createRule<Options, MessageIds>({
208224
type: getMessageType(node.elementType),
209225
},
210226
fix(fixer) {
211-
const startText = requireWhitespaceBefore(node);
212227
const toFix = [
213228
fixer.replaceTextRange([node.range[1] - 2, node.range[1]], '>'),
214-
fixer.insertTextBefore(
215-
node,
216-
`${startText ? ' ' : ''}${isReadonly ? 'Readonly' : ''}Array<`,
217-
),
218229
];
219-
if (typeOpNode) {
220-
// remove the readonly operator if it exists
221-
toFix.unshift(
222-
fixer.removeRange([
223-
typeOpNode.range[0],
224-
typeOpNode.range[0] + 'readonly '.length,
225-
]),
230+
const startText = requireWhitespaceBefore(node);
231+
const typeOpNodeRange = getTypeOpNodeRange(typeOpNode);
232+
233+
if (typeOpNodeRange) {
234+
toFix.unshift(fixer.removeRange(typeOpNodeRange));
235+
} else {
236+
toFix.push(
237+
fixer.insertTextBefore(node, `${startText ? ' ' : ''}`),
226238
);
227239
}
228240

241+
toFix.push(
242+
fixer.insertTextBefore(
243+
node,
244+
`${isReadonly ? 'Readonly' : ''}Array<`,
245+
),
246+
);
247+
229248
if (node.elementType.type === AST_NODE_TYPES.TSParenthesizedType) {
230249
const first = sourceCode.getFirstToken(node.elementType);
231250
const last = sourceCode.getLastToken(node.elementType);

packages/eslint-plugin/tests/rules/array-type.test.ts

+30
Original file line numberDiff line numberDiff line change
@@ -1071,5 +1071,35 @@ class Foo<T = Bar[][]> extends Bar<T, T[]> implements Baz<T[]> {
10711071
`let a: readonly Array<number>[] = []`,
10721072
'array',
10731073
);
1074+
testOutput(
1075+
'generic',
1076+
`type T = readonly(string)[]`,
1077+
`type T = ReadonlyArray<string>`,
1078+
'generic',
1079+
);
1080+
testOutput(
1081+
'generic',
1082+
`let a: readonly(readonly string[])[] = []`,
1083+
`let a: ReadonlyArray<ReadonlyArray<string>> = []`,
1084+
'generic',
1085+
);
1086+
testOutput(
1087+
'generic',
1088+
`type T = readonly(readonly string[])[]`,
1089+
`type T = ReadonlyArray<ReadonlyArray<string>>`,
1090+
'generic',
1091+
);
1092+
testOutput(
1093+
'generic',
1094+
`type T = readonly (readonly string[])[]`,
1095+
`type T = ReadonlyArray<ReadonlyArray<string>>`,
1096+
'generic',
1097+
);
1098+
testOutput(
1099+
'generic',
1100+
`type T = readonly (readonly string[])[]`,
1101+
`type T = ReadonlyArray<ReadonlyArray<string>>`,
1102+
'generic',
1103+
);
10741104
});
10751105
});

0 commit comments

Comments
 (0)