@flint.fyi/ts 0.14.3 → 0.14.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/lib/createTypeScriptFileFromProgram.js +1 -0
- package/lib/language.d.ts +1 -0
- package/lib/plugin.d.ts +44 -0
- package/lib/plugin.js +22 -0
- package/lib/rules/anyReturns.d.ts +6 -0
- package/lib/rules/anyReturns.js +187 -0
- package/lib/rules/anyReturns.test.d.ts +1 -0
- package/lib/rules/anyReturns.test.js +647 -0
- package/lib/rules/caseDuplicates.d.ts +6 -0
- package/lib/rules/caseDuplicates.js +49 -0
- package/lib/rules/caseDuplicates.test.d.ts +1 -0
- package/lib/rules/caseDuplicates.test.js +307 -0
- package/lib/rules/elseIfDuplicates.d.ts +6 -0
- package/lib/rules/elseIfDuplicates.js +53 -0
- package/lib/rules/elseIfDuplicates.test.d.ts +1 -0
- package/lib/rules/elseIfDuplicates.test.js +176 -0
- package/lib/rules/forDirections.d.ts +6 -0
- package/lib/rules/forDirections.js +124 -0
- package/lib/rules/forDirections.test.d.ts +1 -0
- package/lib/rules/forDirections.test.js +99 -0
- package/lib/rules/functionNewCalls.d.ts +6 -0
- package/lib/rules/functionNewCalls.js +60 -0
- package/lib/rules/functionNewCalls.test.d.ts +1 -0
- package/lib/rules/functionNewCalls.test.js +115 -0
- package/lib/rules/negativeZeroComparisons.js +4 -22
- package/lib/rules/nonOctalDecimalEscapes.d.ts +6 -0
- package/lib/rules/nonOctalDecimalEscapes.js +57 -0
- package/lib/rules/nonOctalDecimalEscapes.test.d.ts +1 -0
- package/lib/rules/nonOctalDecimalEscapes.test.js +69 -0
- package/lib/rules/numericLiteralParsing.d.ts +6 -0
- package/lib/rules/numericLiteralParsing.js +97 -0
- package/lib/rules/numericLiteralParsing.test.d.ts +1 -0
- package/lib/rules/numericLiteralParsing.test.js +99 -0
- package/lib/rules/selfAssignments.d.ts +6 -0
- package/lib/rules/selfAssignments.js +44 -0
- package/lib/rules/selfAssignments.test.d.ts +1 -0
- package/lib/rules/selfAssignments.test.js +66 -0
- package/lib/rules/selfComparisons.d.ts +6 -0
- package/lib/rules/selfComparisons.js +41 -0
- package/lib/rules/selfComparisons.test.d.ts +1 -0
- package/lib/rules/selfComparisons.test.js +297 -0
- package/lib/rules/sequences.d.ts +6 -0
- package/lib/rules/sequences.js +34 -0
- package/lib/rules/sequences.test.d.ts +1 -0
- package/lib/rules/sequences.test.js +48 -0
- package/lib/rules/typeofComparisons.d.ts +6 -0
- package/lib/rules/typeofComparisons.js +78 -0
- package/lib/rules/typeofComparisons.test.d.ts +1 -0
- package/lib/rules/typeofComparisons.test.js +85 -0
- package/lib/rules/utils/discriminateAnyType.d.ts +12 -0
- package/lib/rules/utils/discriminateAnyType.js +41 -0
- package/lib/rules/utils/getThisExpression.d.ts +2 -0
- package/lib/rules/utils/getThisExpression.js +23 -0
- package/lib/rules/utils/isUnsafeAssignment.d.ts +13 -0
- package/lib/rules/utils/isUnsafeAssignment.js +76 -0
- package/lib/rules/utils/operators.d.ts +4 -0
- package/lib/rules/utils/operators.js +36 -0
- package/lib/utils/declarationIncludesGlobal.d.ts +2 -0
- package/lib/utils/declarationIncludesGlobal.js +5 -0
- package/lib/utils/declarationsIncludeGlobal.js +2 -5
- package/lib/utils/hasSameTokens.d.ts +2 -0
- package/lib/utils/hasSameTokens.js +30 -0
- package/lib/utils/isGlobalDeclarationOfName.d.ts +5 -0
- package/lib/utils/isGlobalDeclarationOfName.js +31 -0
- package/package.json +1 -1
- package/src/createTypeScriptFileFromProgram.ts +1 -0
- package/src/language.ts +1 -0
- package/src/plugin.ts +22 -0
- package/src/rules/anyReturns.test.ts +649 -0
- package/src/rules/anyReturns.ts +263 -0
- package/src/rules/caseDuplicates.test.ts +308 -0
- package/src/rules/caseDuplicates.ts +57 -0
- package/src/rules/elseIfDuplicates.test.ts +177 -0
- package/src/rules/elseIfDuplicates.ts +69 -0
- package/src/rules/forDirections.test.ts +100 -0
- package/src/rules/forDirections.ts +163 -0
- package/src/rules/functionNewCalls.test.ts +116 -0
- package/src/rules/functionNewCalls.ts +75 -0
- package/src/rules/negativeZeroComparisons.ts +8 -27
- package/src/rules/nonOctalDecimalEscapes.test.ts +70 -0
- package/src/rules/nonOctalDecimalEscapes.ts +70 -0
- package/src/rules/numericLiteralParsing.test.ts +100 -0
- package/src/rules/numericLiteralParsing.ts +116 -0
- package/src/rules/selfAssignments.test.ts +67 -0
- package/src/rules/selfAssignments.ts +50 -0
- package/src/rules/selfComparisons.test.ts +298 -0
- package/src/rules/selfComparisons.ts +45 -0
- package/src/rules/sequences.test.ts +49 -0
- package/src/rules/sequences.ts +37 -0
- package/src/rules/typeofComparisons.test.ts +86 -0
- package/src/rules/typeofComparisons.ts +88 -0
- package/src/rules/utils/discriminateAnyType.ts +66 -0
- package/src/rules/utils/getThisExpression.ts +24 -0
- package/src/rules/utils/isUnsafeAssignment.ts +113 -0
- package/src/rules/utils/operators.ts +39 -0
- package/src/utils/declarationIncludesGlobal.ts +9 -0
- package/src/utils/declarationsIncludeGlobal.ts +3 -7
- package/src/utils/hasSameTokens.ts +45 -0
- package/src/utils/isGlobalDeclarationOfName.ts +51 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ruleTester } from "./ruleTester.js";
|
|
2
|
+
import rule from "./typeofComparisons.js";
|
|
3
|
+
ruleTester.describe(rule, {
|
|
4
|
+
invalid: [
|
|
5
|
+
{
|
|
6
|
+
code: `
|
|
7
|
+
if (typeof value === "") {
|
|
8
|
+
process();
|
|
9
|
+
}
|
|
10
|
+
`,
|
|
11
|
+
snapshot: `
|
|
12
|
+
if (typeof value === "") {
|
|
13
|
+
~~
|
|
14
|
+
This string literal is not one that the typeof operator will ever produce.
|
|
15
|
+
process();
|
|
16
|
+
}
|
|
17
|
+
`,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
code: `
|
|
21
|
+
if (typeof data != "invalid") {
|
|
22
|
+
reject();
|
|
23
|
+
}
|
|
24
|
+
`,
|
|
25
|
+
snapshot: `
|
|
26
|
+
if (typeof data != "invalid") {
|
|
27
|
+
~~~~~~~~~
|
|
28
|
+
This string literal is not one that the typeof operator will ever produce.
|
|
29
|
+
reject();
|
|
30
|
+
}
|
|
31
|
+
`,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
code: `
|
|
35
|
+
if ("invalid" === typeof flag) {
|
|
36
|
+
toggle();
|
|
37
|
+
}
|
|
38
|
+
`,
|
|
39
|
+
snapshot: `
|
|
40
|
+
if ("invalid" === typeof flag) {
|
|
41
|
+
~~~~~~~~~
|
|
42
|
+
This string literal is not one that the typeof operator will ever produce.
|
|
43
|
+
toggle();
|
|
44
|
+
}
|
|
45
|
+
`,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
code: `
|
|
49
|
+
if (typeof value === "String") {
|
|
50
|
+
process();
|
|
51
|
+
}
|
|
52
|
+
`,
|
|
53
|
+
snapshot: `
|
|
54
|
+
if (typeof value === "String") {
|
|
55
|
+
~~~~~~~~
|
|
56
|
+
This string literal is not one that the typeof operator will ever produce.
|
|
57
|
+
process();
|
|
58
|
+
}
|
|
59
|
+
`,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
code: `
|
|
63
|
+
const isValid = typeof input !== "array";
|
|
64
|
+
`,
|
|
65
|
+
snapshot: `
|
|
66
|
+
const isValid = typeof input !== "array";
|
|
67
|
+
~~~~~~~
|
|
68
|
+
This string literal is not one that the typeof operator will ever produce.
|
|
69
|
+
`,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
valid: [
|
|
73
|
+
`if (typeof value === "string") { process(); }`,
|
|
74
|
+
`if (typeof variable == "undefined") { handle(); }`,
|
|
75
|
+
`if (typeof data != "number") { reject(); }`,
|
|
76
|
+
`if (typeof callback !== "function") { throw new Error("Invalid callback"); }`,
|
|
77
|
+
`if (typeof flag === "boolean") { toggle(); }`,
|
|
78
|
+
`if (typeof value === "object") { parse(); }`,
|
|
79
|
+
`if (typeof value === "symbol") { handle(); }`,
|
|
80
|
+
`if (typeof value === "bigint") { compute(); }`,
|
|
81
|
+
`if (typeof value === other) { process(); }`,
|
|
82
|
+
`if (typeof value === typeof other) { compare(); }`,
|
|
83
|
+
`const type = typeof value;`,
|
|
84
|
+
],
|
|
85
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as ts from "typescript";
|
|
2
|
+
export declare enum AnyType {
|
|
3
|
+
Any = 0,
|
|
4
|
+
PromiseAny = 1,
|
|
5
|
+
AnyArray = 2,
|
|
6
|
+
Safe = 3
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* @returns `AnyType.Any` if the type is `any`, `AnyType.AnyArray` if the type is `any[]` or `readonly any[]`, `AnyType.PromiseAny` if the type is `Promise<any>`,
|
|
10
|
+
* otherwise it returns `AnyType.Safe`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function discriminateAnyType(type: ts.Type, checker: ts.TypeChecker, program: ts.Program, tsNode: ts.Node): AnyType;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as tsutils from "ts-api-utils";
|
|
2
|
+
import * as ts from "typescript";
|
|
3
|
+
export var AnyType;
|
|
4
|
+
(function (AnyType) {
|
|
5
|
+
AnyType[AnyType["Any"] = 0] = "Any";
|
|
6
|
+
AnyType[AnyType["PromiseAny"] = 1] = "PromiseAny";
|
|
7
|
+
AnyType[AnyType["AnyArray"] = 2] = "AnyArray";
|
|
8
|
+
AnyType[AnyType["Safe"] = 3] = "Safe";
|
|
9
|
+
})(AnyType || (AnyType = {}));
|
|
10
|
+
/**
|
|
11
|
+
* @returns `AnyType.Any` if the type is `any`, `AnyType.AnyArray` if the type is `any[]` or `readonly any[]`, `AnyType.PromiseAny` if the type is `Promise<any>`,
|
|
12
|
+
* otherwise it returns `AnyType.Safe`.
|
|
13
|
+
*/
|
|
14
|
+
export function discriminateAnyType(type, checker, program, tsNode) {
|
|
15
|
+
return discriminateAnyTypeWorker(type, checker, program, tsNode, new Set());
|
|
16
|
+
}
|
|
17
|
+
function discriminateAnyTypeWorker(type, checker, program, tsNode, visited) {
|
|
18
|
+
if (visited.has(type)) {
|
|
19
|
+
return AnyType.Safe;
|
|
20
|
+
}
|
|
21
|
+
visited.add(type);
|
|
22
|
+
if (tsutils.isTypeFlagSet(type, ts.TypeFlags.Any)) {
|
|
23
|
+
return AnyType.Any;
|
|
24
|
+
}
|
|
25
|
+
if (checker.isArrayType(type) &&
|
|
26
|
+
tsutils.isTypeFlagSet(checker.getTypeArguments(type)[0], ts.TypeFlags.Any)) {
|
|
27
|
+
return AnyType.AnyArray;
|
|
28
|
+
}
|
|
29
|
+
for (const part of tsutils.typeConstituents(type)) {
|
|
30
|
+
if (tsutils.isThenableType(checker, tsNode, part)) {
|
|
31
|
+
const awaitedType = checker.getAwaitedType(part);
|
|
32
|
+
if (awaitedType) {
|
|
33
|
+
const awaitedAnyType = discriminateAnyTypeWorker(awaitedType, checker, program, tsNode, visited);
|
|
34
|
+
if (awaitedAnyType === AnyType.Any) {
|
|
35
|
+
return AnyType.PromiseAny;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return AnyType.Safe;
|
|
41
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as tsutils from "ts-api-utils";
|
|
2
|
+
import * as ts from "typescript";
|
|
3
|
+
export function getThisExpression(node) {
|
|
4
|
+
while (true) {
|
|
5
|
+
node = skipParentheses(node);
|
|
6
|
+
if (ts.isCallExpression(node) || tsutils.isAccessExpression(node)) {
|
|
7
|
+
node = node.expression;
|
|
8
|
+
}
|
|
9
|
+
else if (tsutils.isThisExpression(node)) {
|
|
10
|
+
return node;
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
function skipParentheses(node) {
|
|
19
|
+
while (ts.isParenthesizedExpression(node)) {
|
|
20
|
+
node = node.expression;
|
|
21
|
+
}
|
|
22
|
+
return node;
|
|
23
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as ts from "typescript";
|
|
2
|
+
/**
|
|
3
|
+
* Does a simple check to see if there is an any being assigned to a non-any type.
|
|
4
|
+
*
|
|
5
|
+
* This also checks generic positions to ensure there's no unsafe sub-assignments.
|
|
6
|
+
* Note: in the case of generic positions, it makes the assumption that the two types are the same.
|
|
7
|
+
* @example See tests for examples
|
|
8
|
+
* @returns false if it's safe, or an object with the two types if it's unsafe
|
|
9
|
+
*/
|
|
10
|
+
export declare function isUnsafeAssignment(type: ts.Type, receiver: ts.Type, checker: ts.TypeChecker, senderNode: null | ts.Node): false | {
|
|
11
|
+
receiver: ts.Type;
|
|
12
|
+
sender: ts.Type;
|
|
13
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as tsutils from "ts-api-utils";
|
|
2
|
+
import * as ts from "typescript";
|
|
3
|
+
/**
|
|
4
|
+
* Does a simple check to see if there is an any being assigned to a non-any type.
|
|
5
|
+
*
|
|
6
|
+
* This also checks generic positions to ensure there's no unsafe sub-assignments.
|
|
7
|
+
* Note: in the case of generic positions, it makes the assumption that the two types are the same.
|
|
8
|
+
* @example See tests for examples
|
|
9
|
+
* @returns false if it's safe, or an object with the two types if it's unsafe
|
|
10
|
+
*/
|
|
11
|
+
export function isUnsafeAssignment(type, receiver, checker, senderNode) {
|
|
12
|
+
return isUnsafeAssignmentWorker(type, receiver, checker, senderNode, new Map());
|
|
13
|
+
}
|
|
14
|
+
function isUnsafeAssignmentWorker(type, receiver, checker, senderNode, visited) {
|
|
15
|
+
if (tsutils.isTypeFlagSet(type, ts.TypeFlags.Any)) {
|
|
16
|
+
// Allow assignment of any ==> unknown.
|
|
17
|
+
if (tsutils.isTypeFlagSet(receiver, ts.TypeFlags.Unknown)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
if (!tsutils.isTypeFlagSet(receiver, ts.TypeFlags.Any)) {
|
|
21
|
+
return { receiver, sender: type };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const typeAlreadyVisited = visited.get(type);
|
|
25
|
+
if (typeAlreadyVisited) {
|
|
26
|
+
if (typeAlreadyVisited.has(receiver)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
typeAlreadyVisited.add(receiver);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
visited.set(type, new Set([receiver]));
|
|
33
|
+
}
|
|
34
|
+
if (tsutils.isTypeReference(type) && tsutils.isTypeReference(receiver)) {
|
|
35
|
+
// TODO - figure out how to handle cases like this,
|
|
36
|
+
// where the types are assignable, but not the same type
|
|
37
|
+
/*
|
|
38
|
+
function foo(): ReadonlySet<number> { return new Set<any>(); }
|
|
39
|
+
|
|
40
|
+
// and
|
|
41
|
+
|
|
42
|
+
type Test<T> = { prop: T }
|
|
43
|
+
type Test2 = { prop: string }
|
|
44
|
+
declare const a: Test<any>;
|
|
45
|
+
const b: Test2 = a;
|
|
46
|
+
*/
|
|
47
|
+
if (type.target !== receiver.target) {
|
|
48
|
+
// if the type references are different, assume safe, as we won't know how to compare the two types
|
|
49
|
+
// the generic positions might not be equivalent for both types
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (senderNode != null &&
|
|
53
|
+
ts.isNewExpression(senderNode) &&
|
|
54
|
+
ts.isIdentifier(senderNode.expression) &&
|
|
55
|
+
senderNode.expression.text === "Map" &&
|
|
56
|
+
(senderNode.arguments == null || senderNode.arguments.length === 0) &&
|
|
57
|
+
senderNode.typeArguments == null) {
|
|
58
|
+
// special case to handle `new Map()`
|
|
59
|
+
// unfortunately Map's default empty constructor is typed to return `Map<any, any>` :(
|
|
60
|
+
// https://github.com/typescript-eslint/typescript-eslint/issues/2109#issuecomment-634144396
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
const typeArguments = type.typeArguments ?? [];
|
|
64
|
+
const receiverTypeArguments = receiver.typeArguments ?? [];
|
|
65
|
+
for (let i = 0; i < typeArguments.length; i += 1) {
|
|
66
|
+
const arg = typeArguments[i];
|
|
67
|
+
const receiverArg = receiverTypeArguments[i];
|
|
68
|
+
const unsafe = isUnsafeAssignmentWorker(arg, receiverArg, checker, senderNode, visited);
|
|
69
|
+
if (unsafe) {
|
|
70
|
+
return { receiver, sender: type };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as ts from "typescript";
|
|
2
|
+
export declare function isComparisonOperator(token: ts.BinaryOperatorToken): boolean;
|
|
3
|
+
export declare function isEqualityOperator(token: ts.BinaryOperatorToken): boolean;
|
|
4
|
+
export declare function isNegatedEqualityOperator(token: ts.BinaryOperatorToken): boolean;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as ts from "typescript";
|
|
2
|
+
export function isComparisonOperator(token) {
|
|
3
|
+
switch (token.kind) {
|
|
4
|
+
case ts.SyntaxKind.EqualsEqualsEqualsToken:
|
|
5
|
+
case ts.SyntaxKind.EqualsEqualsToken:
|
|
6
|
+
case ts.SyntaxKind.ExclamationEqualsEqualsToken:
|
|
7
|
+
case ts.SyntaxKind.ExclamationEqualsToken:
|
|
8
|
+
case ts.SyntaxKind.GreaterThanEqualsToken:
|
|
9
|
+
case ts.SyntaxKind.GreaterThanToken:
|
|
10
|
+
case ts.SyntaxKind.LessThanEqualsToken:
|
|
11
|
+
case ts.SyntaxKind.LessThanToken:
|
|
12
|
+
return true;
|
|
13
|
+
default:
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function isEqualityOperator(token) {
|
|
18
|
+
switch (token.kind) {
|
|
19
|
+
case ts.SyntaxKind.EqualsEqualsEqualsToken:
|
|
20
|
+
case ts.SyntaxKind.EqualsEqualsToken:
|
|
21
|
+
case ts.SyntaxKind.ExclamationEqualsEqualsToken:
|
|
22
|
+
case ts.SyntaxKind.ExclamationEqualsToken:
|
|
23
|
+
return true;
|
|
24
|
+
default:
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function isNegatedEqualityOperator(token) {
|
|
29
|
+
switch (token.kind) {
|
|
30
|
+
case ts.SyntaxKind.ExclamationEqualsEqualsToken:
|
|
31
|
+
case ts.SyntaxKind.ExclamationEqualsToken:
|
|
32
|
+
return true;
|
|
33
|
+
default:
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
+
import { declarationIncludesGlobal } from "./declarationIncludesGlobal.js";
|
|
1
2
|
export function declarationsIncludeGlobal(declarations) {
|
|
2
|
-
return declarations.some(
|
|
3
|
-
const sourceFile = declaration.getSourceFile();
|
|
4
|
-
return (sourceFile.hasNoDefaultLib ||
|
|
5
|
-
/\/lib\.[^/]*\.d\.ts$/.test(sourceFile.fileName));
|
|
6
|
-
});
|
|
3
|
+
return declarations.some(declarationIncludesGlobal);
|
|
7
4
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as ts from "typescript";
|
|
2
|
+
export function hasSameTokens(nodeA, nodeB, sourceFile) {
|
|
3
|
+
const queueA = [nodeA];
|
|
4
|
+
const queueB = [nodeB];
|
|
5
|
+
while (true) {
|
|
6
|
+
const currentA = queueA.shift();
|
|
7
|
+
const currentB = queueB.shift();
|
|
8
|
+
if (!currentA || !currentB) {
|
|
9
|
+
break;
|
|
10
|
+
}
|
|
11
|
+
if (currentA.kind !== currentB.kind) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (currentA.kind >= ts.SyntaxKind.FirstToken &&
|
|
15
|
+
currentA.kind <= ts.SyntaxKind.LastToken) {
|
|
16
|
+
if (currentA.getText(sourceFile) !== currentB.getText(sourceFile)) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const childrenA = currentA.getChildren(sourceFile);
|
|
22
|
+
const childrenB = currentB.getChildren(sourceFile);
|
|
23
|
+
if (childrenA.length !== childrenB.length) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
queueA.push(...childrenA);
|
|
27
|
+
queueB.push(...childrenB);
|
|
28
|
+
}
|
|
29
|
+
return queueA.length === queueB.length;
|
|
30
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as ts from "typescript";
|
|
2
|
+
import { declarationIncludesGlobal } from "./declarationIncludesGlobal.js";
|
|
3
|
+
/**
|
|
4
|
+
* TODO: Use a scope analyzer (#400).
|
|
5
|
+
*/
|
|
6
|
+
export function isGlobalDeclarationOfName(node, name, typeChecker) {
|
|
7
|
+
const declarations = typeChecker.getSymbolAtLocation(node)?.getDeclarations();
|
|
8
|
+
if (!declarations) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
return declarations.every((declaration) => {
|
|
12
|
+
// Special case: a variable set to a known identifier. E.g.:
|
|
13
|
+
// const CustomFunction = Function;
|
|
14
|
+
if (ts.isVariableDeclaration(declaration) &&
|
|
15
|
+
declaration.initializer &&
|
|
16
|
+
declaration.initializer.kind === ts.SyntaxKind.Identifier) {
|
|
17
|
+
return isGlobalDeclarationOfName(declaration.initializer, name, typeChecker);
|
|
18
|
+
}
|
|
19
|
+
return (isDeclarationOfName(declaration, name) &&
|
|
20
|
+
declarationIncludesGlobal(declaration));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function isDeclarationOfName(node, name) {
|
|
24
|
+
if (ts.isClassDeclaration(node) ||
|
|
25
|
+
ts.isFunctionDeclaration(node) ||
|
|
26
|
+
ts.isInterfaceDeclaration(node) ||
|
|
27
|
+
ts.isVariableDeclaration(node)) {
|
|
28
|
+
return node.name && ts.isIdentifier(node.name) && node.name.text === name;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
package/package.json
CHANGED
package/src/language.ts
CHANGED
package/src/plugin.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createPlugin } from "@flint.fyi/core";
|
|
2
2
|
|
|
3
|
+
import anyReturns from "./rules/anyReturns.js";
|
|
3
4
|
import asyncPromiseExecutors from "./rules/asyncPromiseExecutors.js";
|
|
4
5
|
import caseDeclarations from "./rules/caseDeclarations.js";
|
|
6
|
+
import caseDuplicates from "./rules/caseDuplicates.js";
|
|
5
7
|
import chainedAssignments from "./rules/chainedAssignments.js";
|
|
6
8
|
import classAssignments from "./rules/classAssignments.js";
|
|
7
9
|
import consecutiveNonNullAssertions from "./rules/consecutiveNonNullAssertions.js";
|
|
@@ -10,11 +12,14 @@ import constructorReturns from "./rules/constructorReturns.js";
|
|
|
10
12
|
import debuggerStatements from "./rules/debuggerStatements.js";
|
|
11
13
|
import defaultCaseLast from "./rules/defaultCaseLast.js";
|
|
12
14
|
import duplicateArguments from "./rules/duplicateArguments.js";
|
|
15
|
+
import elseIfDuplicates from "./rules/elseIfDuplicates.js";
|
|
13
16
|
import emptyDestructures from "./rules/emptyDestructures.js";
|
|
14
17
|
import emptyStaticBlocks from "./rules/emptyStaticBlocks.js";
|
|
15
18
|
import exceptionAssignments from "./rules/exceptionAssignments.js";
|
|
19
|
+
import forDirections from "./rules/forDirections.js";
|
|
16
20
|
import forInArrays from "./rules/forInArrays.js";
|
|
17
21
|
import functionAssignments from "./rules/functionAssignments.js";
|
|
22
|
+
import functionNewCalls from "./rules/functionNewCalls.js";
|
|
18
23
|
import generatorFunctionYields from "./rules/generatorFunctionYields.js";
|
|
19
24
|
import globalAssignments from "./rules/globalAssignments.js";
|
|
20
25
|
import globalObjectCalls from "./rules/globalObjectCalls.js";
|
|
@@ -22,12 +27,18 @@ import namespaceDeclarations from "./rules/namespaceDeclarations.js";
|
|
|
22
27
|
import negativeZeroComparisons from "./rules/negativeZeroComparisons.js";
|
|
23
28
|
import newExpressions from "./rules/newExpressions.js";
|
|
24
29
|
import newNativeNonConstructors from "./rules/newNativeNonConstructors.js";
|
|
30
|
+
import nonOctalDecimalEscapes from "./rules/nonOctalDecimalEscapes.js";
|
|
31
|
+
import numericLiteralParsing from "./rules/numericLiteralParsing.js";
|
|
25
32
|
import objectProto from "./rules/objectProto.js";
|
|
26
33
|
import octalEscapes from "./rules/octalEscapes.js";
|
|
27
34
|
import octalNumbers from "./rules/octalNumbers.js";
|
|
28
35
|
import returnAssignments from "./rules/returnAssignments.js";
|
|
36
|
+
import selfAssignments from "./rules/selfAssignments.js";
|
|
37
|
+
import selfComparisons from "./rules/selfComparisons.js";
|
|
38
|
+
import sequences from "./rules/sequences.js";
|
|
29
39
|
import sparseArrays from "./rules/sparseArrays.js";
|
|
30
40
|
import symbolDescriptions from "./rules/symbolDescriptions.js";
|
|
41
|
+
import typeofComparisons from "./rules/typeofComparisons.js";
|
|
31
42
|
import unassignedVariables from "./rules/unassignedVariables.js";
|
|
32
43
|
import undefinedVariables from "./rules/undefinedVariables.js";
|
|
33
44
|
import unicodeBOMs from "./rules/unicodeBOMs.js";
|
|
@@ -42,8 +53,10 @@ export const ts = createPlugin({
|
|
|
42
53
|
},
|
|
43
54
|
name: "ts",
|
|
44
55
|
rules: [
|
|
56
|
+
anyReturns,
|
|
45
57
|
asyncPromiseExecutors,
|
|
46
58
|
caseDeclarations,
|
|
59
|
+
caseDuplicates,
|
|
47
60
|
chainedAssignments,
|
|
48
61
|
classAssignments,
|
|
49
62
|
consecutiveNonNullAssertions,
|
|
@@ -52,11 +65,14 @@ export const ts = createPlugin({
|
|
|
52
65
|
debuggerStatements,
|
|
53
66
|
defaultCaseLast,
|
|
54
67
|
duplicateArguments,
|
|
68
|
+
elseIfDuplicates,
|
|
55
69
|
emptyDestructures,
|
|
56
70
|
emptyStaticBlocks,
|
|
57
71
|
exceptionAssignments,
|
|
72
|
+
forDirections,
|
|
58
73
|
forInArrays,
|
|
59
74
|
functionAssignments,
|
|
75
|
+
functionNewCalls,
|
|
60
76
|
generatorFunctionYields,
|
|
61
77
|
globalAssignments,
|
|
62
78
|
globalObjectCalls,
|
|
@@ -64,12 +80,18 @@ export const ts = createPlugin({
|
|
|
64
80
|
negativeZeroComparisons,
|
|
65
81
|
newExpressions,
|
|
66
82
|
newNativeNonConstructors,
|
|
83
|
+
nonOctalDecimalEscapes,
|
|
84
|
+
numericLiteralParsing,
|
|
67
85
|
objectProto,
|
|
68
86
|
octalEscapes,
|
|
69
87
|
octalNumbers,
|
|
70
88
|
returnAssignments,
|
|
89
|
+
selfAssignments,
|
|
90
|
+
selfComparisons,
|
|
91
|
+
sequences,
|
|
71
92
|
sparseArrays,
|
|
72
93
|
symbolDescriptions,
|
|
94
|
+
typeofComparisons,
|
|
73
95
|
unassignedVariables,
|
|
74
96
|
undefinedVariables,
|
|
75
97
|
unicodeBOMs,
|