Skip to content

Commit 7ef4cf7

Browse files
authored
fix: remove unnecessary semicolon from fixes (#19857)
1 parent 7dabc38 commit 7ef4cf7

File tree

3 files changed

+138
-0
lines changed

3 files changed

+138
-0
lines changed

lib/rules/utils/ast-utils.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,35 @@ let needsPrecedingSemicolon;
11931193
"WithStatement",
11941194
]);
11951195

1196+
const TS_TYPE_NODE_TYPES = new Set([
1197+
"TSAsExpression",
1198+
"TSSatisfiesExpression",
1199+
"TSTypeAliasDeclaration",
1200+
"TSTypeAnnotation",
1201+
]);
1202+
1203+
/**
1204+
* Determines whether a specified node is inside a TypeScript type context.
1205+
* @param {ASTNode} node The node to check.
1206+
* @returns {boolean} Whether the node is inside a TypeScript type context.
1207+
*/
1208+
function isInType(node) {
1209+
for (let currNode = node; ; ) {
1210+
const { parent } = currNode;
1211+
if (!parent) {
1212+
break;
1213+
}
1214+
if (
1215+
TS_TYPE_NODE_TYPES.has(parent.type) &&
1216+
currNode === parent.typeAnnotation
1217+
) {
1218+
return true;
1219+
}
1220+
currNode = parent;
1221+
}
1222+
return false;
1223+
}
1224+
11961225
needsPrecedingSemicolon = function (sourceCode, node) {
11971226
const prevToken = sourceCode.getTokenBefore(node);
11981227

@@ -1206,6 +1235,16 @@ let needsPrecedingSemicolon;
12061235

12071236
const prevNode = sourceCode.getNodeByRangeIndex(prevToken.range[0]);
12081237

1238+
if (
1239+
prevNode.type === "TSDeclareFunction" ||
1240+
prevNode.parent.type === "TSImportEqualsDeclaration" ||
1241+
prevNode.parent.parent?.type === "TSImportEqualsDeclaration" ||
1242+
TS_TYPE_NODE_TYPES.has(prevNode.type) ||
1243+
isInType(prevNode)
1244+
) {
1245+
return false;
1246+
}
1247+
12091248
if (isClosingParenToken(prevToken)) {
12101249
return !STATEMENTS.has(prevNode.type);
12111250
}
@@ -1222,6 +1261,12 @@ let needsPrecedingSemicolon;
12221261
}
12231262

12241263
if (IDENTIFIER_OR_KEYWORD.has(prevToken.type)) {
1264+
if (
1265+
prevNode.parent.type === "VariableDeclarator" &&
1266+
!prevNode.parent.init
1267+
) {
1268+
return false;
1269+
}
12251270
if (BREAK_OR_CONTINUE.has(prevNode.parent.type)) {
12261271
return false;
12271272
}

tests/lib/rules/no-array-constructor.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,18 @@ ruleTester.run("no-array-constructor", rule, {
491491
break yield
492492
new Array();
493493
}
494+
`,
495+
},
496+
{
497+
code: `
498+
var foo
499+
Array()
500+
`,
501+
},
502+
{
503+
code: `
504+
let bar
505+
Array()
494506
`,
495507
},
496508
].map(props => ({
@@ -972,5 +984,74 @@ ruleTesterTypeScript.run("no-array-constructor", rule, {
972984
},
973985
],
974986
},
987+
988+
// No semicolon required after TypeScript syntax
989+
...[
990+
"type T = Foo",
991+
"type T = Foo<Bar>",
992+
"type T = (A | B)",
993+
"type T = -1",
994+
"type T = 'foo'",
995+
"const foo",
996+
"declare const foo",
997+
"function foo()",
998+
"declare function foo()",
999+
"function foo(): []",
1000+
"declare function foo(): []",
1001+
"function foo(): (Foo)",
1002+
"declare function foo(): (Foo)",
1003+
"let foo: bar",
1004+
"import Foo = require('foo')",
1005+
"import Foo = Bar",
1006+
"import Foo = Bar.Baz.Qux",
1007+
].map(code => ({
1008+
code: `${code}\nArray(0, 1)`,
1009+
output: `${code}\n[0, 1]`,
1010+
errors: [{ messageId: "preferLiteral" }],
1011+
})),
1012+
{
1013+
code: `
1014+
(function () {
1015+
Fn
1016+
Array() // ";" required
1017+
}) as Fn
1018+
Array() // ";" not required
1019+
`,
1020+
output: `
1021+
(function () {
1022+
Fn
1023+
;[] // ";" required
1024+
}) as Fn
1025+
[] // ";" not required
1026+
`,
1027+
errors: [
1028+
{ messageId: "preferLiteral" },
1029+
{ messageId: "preferLiteral" },
1030+
],
1031+
},
1032+
{
1033+
code: `
1034+
({
1035+
foo() {
1036+
Object
1037+
Array() // ";" required
1038+
}
1039+
}) as Object
1040+
Array() // ";" not required
1041+
`,
1042+
output: `
1043+
({
1044+
foo() {
1045+
Object
1046+
;[] // ";" required
1047+
}
1048+
}) as Object
1049+
[] // ";" not required
1050+
`,
1051+
errors: [
1052+
{ messageId: "preferLiteral" },
1053+
{ messageId: "preferLiteral" },
1054+
],
1055+
},
9751056
],
9761057
});

tests/lib/rules/no-object-constructor.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,18 @@ ruleTester.run("no-object-constructor", rule, {
377377
break yield
378378
new Object();
379379
}
380+
`,
381+
},
382+
{
383+
code: `
384+
var foo
385+
Object()
386+
`,
387+
},
388+
{
389+
code: `
390+
let bar
391+
Object()
380392
`,
381393
},
382394
].map(props => ({

0 commit comments

Comments
 (0)