@flint.fyi/ts 0.14.2 → 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 +17 -0
- package/lib/createTypeScriptFileFromProgram.js +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/language.d.ts +1 -0
- package/lib/nodes.d.ts +1 -0
- package/lib/plugin.d.ts +165 -1
- package/lib/plugin.js +82 -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/asyncPromiseExecutors.d.ts +6 -0
- package/lib/rules/asyncPromiseExecutors.js +51 -0
- package/lib/rules/asyncPromiseExecutors.test.d.ts +1 -0
- package/lib/rules/asyncPromiseExecutors.test.js +71 -0
- package/lib/rules/caseDeclarations.d.ts +6 -0
- package/lib/rules/caseDeclarations.js +53 -0
- package/lib/rules/caseDeclarations.test.d.ts +1 -0
- package/lib/rules/caseDeclarations.test.js +227 -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/chainedAssignments.d.ts +6 -0
- package/lib/rules/chainedAssignments.js +48 -0
- package/lib/rules/chainedAssignments.test.d.ts +1 -0
- package/lib/rules/chainedAssignments.test.js +238 -0
- package/lib/rules/classAssignments.d.ts +6 -0
- package/lib/rules/classAssignments.js +42 -0
- package/lib/rules/classAssignments.test.d.ts +1 -0
- package/lib/rules/classAssignments.test.js +156 -0
- package/lib/rules/constantAssignments.d.ts +6 -0
- package/lib/rules/constantAssignments.js +61 -0
- package/lib/rules/constantAssignments.test.d.ts +1 -0
- package/lib/rules/constantAssignments.test.js +221 -0
- package/lib/rules/constructorReturns.d.ts +6 -0
- package/lib/rules/constructorReturns.js +52 -0
- package/lib/rules/constructorReturns.test.d.ts +1 -0
- package/lib/rules/constructorReturns.test.js +96 -0
- package/lib/rules/defaultCaseLast.d.ts +6 -0
- package/lib/rules/defaultCaseLast.js +43 -0
- package/lib/rules/defaultCaseLast.test.d.ts +1 -0
- package/lib/rules/defaultCaseLast.test.js +195 -0
- package/lib/rules/duplicateArguments.d.ts +6 -0
- package/lib/rules/duplicateArguments.js +51 -0
- package/lib/rules/duplicateArguments.test.d.ts +1 -0
- package/lib/rules/duplicateArguments.test.js +139 -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/emptyDestructures.d.ts +6 -0
- package/lib/rules/emptyDestructures.js +40 -0
- package/lib/rules/emptyDestructures.test.d.ts +1 -0
- package/lib/rules/emptyDestructures.test.js +186 -0
- package/lib/rules/emptyStaticBlocks.d.ts +6 -0
- package/lib/rules/emptyStaticBlocks.js +54 -0
- package/lib/rules/emptyStaticBlocks.test.d.ts +1 -0
- package/lib/rules/emptyStaticBlocks.test.js +167 -0
- package/lib/rules/exceptionAssignments.d.ts +6 -0
- package/lib/rules/exceptionAssignments.js +61 -0
- package/lib/rules/exceptionAssignments.test.d.ts +1 -0
- package/lib/rules/exceptionAssignments.test.js +264 -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/functionAssignments.d.ts +6 -0
- package/lib/rules/functionAssignments.js +42 -0
- package/lib/rules/functionAssignments.test.d.ts +1 -0
- package/lib/rules/functionAssignments.test.js +209 -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/generatorFunctionYields.d.ts +6 -0
- package/lib/rules/generatorFunctionYields.js +57 -0
- package/lib/rules/generatorFunctionYields.test.d.ts +1 -0
- package/lib/rules/generatorFunctionYields.test.js +151 -0
- package/lib/rules/globalAssignments.d.ts +6 -0
- package/lib/rules/globalAssignments.js +59 -0
- package/lib/rules/globalAssignments.test.d.ts +1 -0
- package/lib/rules/globalAssignments.test.js +215 -0
- package/lib/rules/globalObjectCalls.d.ts +6 -0
- package/lib/rules/globalObjectCalls.js +43 -0
- package/lib/rules/globalObjectCalls.test.d.ts +1 -0
- package/lib/rules/globalObjectCalls.test.js +93 -0
- package/lib/rules/negativeZeroComparisons.d.ts +6 -0
- package/lib/rules/negativeZeroComparisons.js +65 -0
- package/lib/rules/negativeZeroComparisons.test.d.ts +1 -0
- package/lib/rules/negativeZeroComparisons.test.js +209 -0
- package/lib/rules/newExpressions.d.ts +6 -0
- package/lib/rules/newExpressions.js +54 -0
- package/lib/rules/newExpressions.test.d.ts +1 -0
- package/lib/rules/newExpressions.test.js +79 -0
- package/lib/rules/newNativeNonConstructors.d.ts +6 -0
- package/lib/rules/newNativeNonConstructors.js +49 -0
- package/lib/rules/newNativeNonConstructors.test.d.ts +1 -0
- package/lib/rules/newNativeNonConstructors.test.js +94 -0
- 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/objectProto.d.ts +6 -0
- package/lib/rules/objectProto.js +54 -0
- package/lib/rules/objectProto.test.d.ts +1 -0
- package/lib/rules/objectProto.test.js +96 -0
- package/lib/rules/octalNumbers.d.ts +6 -0
- package/lib/rules/octalNumbers.js +68 -0
- package/lib/rules/octalNumbers.test.d.ts +1 -0
- package/lib/rules/octalNumbers.test.js +245 -0
- package/lib/rules/returnAssignments.d.ts +6 -0
- package/lib/rules/returnAssignments.js +50 -0
- package/lib/rules/returnAssignments.test.d.ts +1 -0
- package/lib/rules/returnAssignments.test.js +185 -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/sparseArrays.d.ts +6 -0
- package/lib/rules/sparseArrays.js +54 -0
- package/lib/rules/sparseArrays.test.d.ts +1 -0
- package/lib/rules/sparseArrays.test.js +110 -0
- package/lib/rules/symbolDescriptions.d.ts +6 -0
- package/lib/rules/symbolDescriptions.js +41 -0
- package/lib/rules/symbolDescriptions.test.d.ts +1 -0
- package/lib/rules/symbolDescriptions.test.js +89 -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/unassignedVariables.d.ts +6 -0
- package/lib/rules/unassignedVariables.js +55 -0
- package/lib/rules/unassignedVariables.test.d.ts +1 -0
- package/lib/rules/unassignedVariables.test.js +72 -0
- package/lib/rules/undefinedVariables.d.ts +6 -0
- package/lib/rules/undefinedVariables.js +76 -0
- package/lib/rules/undefinedVariables.test.d.ts +1 -0
- package/lib/rules/undefinedVariables.test.js +80 -0
- package/lib/rules/unicodeBOMs.d.ts +6 -0
- package/lib/rules/unicodeBOMs.js +41 -0
- package/lib/rules/unicodeBOMs.test.d.ts +1 -0
- package/lib/rules/unicodeBOMs.test.js +65 -0
- package/lib/rules/unnecessaryCatches.d.ts +6 -0
- package/lib/rules/unnecessaryCatches.js +68 -0
- package/lib/rules/unnecessaryCatches.test.d.ts +1 -0
- package/lib/rules/unnecessaryCatches.test.js +210 -0
- package/lib/rules/unsafeNegations.d.ts +6 -0
- package/lib/rules/unsafeNegations.js +50 -0
- package/lib/rules/unsafeNegations.test.d.ts +1 -0
- package/lib/rules/unsafeNegations.test.js +63 -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/rules/variableDeletions.d.ts +6 -0
- package/lib/rules/variableDeletions.js +39 -0
- package/lib/rules/variableDeletions.test.d.ts +1 -0
- package/lib/rules/variableDeletions.test.js +75 -0
- package/lib/rules/voidOperator.d.ts +6 -0
- package/lib/rules/voidOperator.js +36 -0
- package/lib/rules/voidOperator.test.d.ts +1 -0
- package/lib/rules/voidOperator.test.js +98 -0
- package/lib/utils/declarationIncludesGlobal.d.ts +2 -0
- package/lib/utils/declarationIncludesGlobal.js +5 -0
- package/lib/utils/declarationsIncludeGlobal.d.ts +2 -0
- package/lib/utils/declarationsIncludeGlobal.js +4 -0
- package/lib/utils/getModifyingReferences.d.ts +8 -0
- package/lib/utils/getModifyingReferences.js +42 -0
- package/lib/utils/hasSameTokens.d.ts +2 -0
- package/lib/utils/hasSameTokens.js +30 -0
- package/lib/utils/isGlobalDeclaration.d.ts +2 -0
- package/lib/utils/isGlobalDeclaration.js +5 -0
- package/lib/utils/isGlobalDeclarationOfName.d.ts +5 -0
- package/lib/utils/isGlobalDeclarationOfName.js +31 -0
- package/lib/utils/isGlobalVariable.d.ts +8 -0
- package/lib/utils/isGlobalVariable.js +21 -0
- package/lib/utils/unwrapParentParenthesizedExpressions.d.ts +2 -0
- package/lib/utils/unwrapParentParenthesizedExpressions.js +6 -0
- package/lib/utils/unwrapParenthesizedExpression.d.ts +2 -0
- package/lib/utils/unwrapParenthesizedExpression.js +6 -0
- package/package.json +1 -1
- package/src/createTypeScriptFileFromProgram.ts +1 -0
- package/src/index.ts +1 -0
- package/src/language.ts +1 -0
- package/src/nodes.ts +1 -0
- package/src/plugin.ts +82 -0
- package/src/rules/anyReturns.test.ts +649 -0
- package/src/rules/anyReturns.ts +263 -0
- package/src/rules/asyncPromiseExecutors.test.ts +72 -0
- package/src/rules/asyncPromiseExecutors.ts +61 -0
- package/src/rules/caseDeclarations.test.ts +228 -0
- package/src/rules/caseDeclarations.ts +70 -0
- package/src/rules/caseDuplicates.test.ts +308 -0
- package/src/rules/caseDuplicates.ts +57 -0
- package/src/rules/chainedAssignments.test.ts +239 -0
- package/src/rules/chainedAssignments.ts +55 -0
- package/src/rules/classAssignments.test.ts +157 -0
- package/src/rules/classAssignments.ts +50 -0
- package/src/rules/constantAssignments.test.ts +222 -0
- package/src/rules/constantAssignments.ts +78 -0
- package/src/rules/constructorReturns.test.ts +97 -0
- package/src/rules/constructorReturns.ts +59 -0
- package/src/rules/defaultCaseLast.test.ts +196 -0
- package/src/rules/defaultCaseLast.ts +54 -0
- package/src/rules/duplicateArguments.test.ts +140 -0
- package/src/rules/duplicateArguments.ts +58 -0
- package/src/rules/elseIfDuplicates.test.ts +177 -0
- package/src/rules/elseIfDuplicates.ts +69 -0
- package/src/rules/emptyDestructures.test.ts +187 -0
- package/src/rules/emptyDestructures.ts +48 -0
- package/src/rules/emptyStaticBlocks.test.ts +168 -0
- package/src/rules/emptyStaticBlocks.ts +60 -0
- package/src/rules/exceptionAssignments.test.ts +265 -0
- package/src/rules/exceptionAssignments.ts +77 -0
- package/src/rules/forDirections.test.ts +100 -0
- package/src/rules/forDirections.ts +163 -0
- package/src/rules/functionAssignments.test.ts +210 -0
- package/src/rules/functionAssignments.ts +51 -0
- package/src/rules/functionNewCalls.test.ts +116 -0
- package/src/rules/functionNewCalls.ts +75 -0
- package/src/rules/generatorFunctionYields.test.ts +152 -0
- package/src/rules/generatorFunctionYields.ts +71 -0
- package/src/rules/globalAssignments.test.ts +216 -0
- package/src/rules/globalAssignments.ts +67 -0
- package/src/rules/globalObjectCalls.test.ts +94 -0
- package/src/rules/globalObjectCalls.ts +52 -0
- package/src/rules/negativeZeroComparisons.test.ts +210 -0
- package/src/rules/negativeZeroComparisons.ts +87 -0
- package/src/rules/newExpressions.test.ts +80 -0
- package/src/rules/newExpressions.ts +67 -0
- package/src/rules/newNativeNonConstructors.test.ts +95 -0
- package/src/rules/newNativeNonConstructors.ts +59 -0
- 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/objectProto.test.ts +97 -0
- package/src/rules/objectProto.ts +62 -0
- package/src/rules/octalNumbers.test.ts +246 -0
- package/src/rules/octalNumbers.ts +75 -0
- package/src/rules/returnAssignments.test.ts +186 -0
- package/src/rules/returnAssignments.ts +57 -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/sparseArrays.test.ts +111 -0
- package/src/rules/sparseArrays.ts +61 -0
- package/src/rules/symbolDescriptions.test.ts +90 -0
- package/src/rules/symbolDescriptions.ts +47 -0
- package/src/rules/typeofComparisons.test.ts +86 -0
- package/src/rules/typeofComparisons.ts +88 -0
- package/src/rules/unassignedVariables.test.ts +73 -0
- package/src/rules/unassignedVariables.ts +69 -0
- package/src/rules/undefinedVariables.test.ts +81 -0
- package/src/rules/undefinedVariables.ts +97 -0
- package/src/rules/unicodeBOMs.test.ts +66 -0
- package/src/rules/unicodeBOMs.ts +44 -0
- package/src/rules/unnecessaryCatches.test.ts +211 -0
- package/src/rules/unnecessaryCatches.ts +84 -0
- package/src/rules/unsafeNegations.test.ts +64 -0
- package/src/rules/unsafeNegations.ts +59 -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/rules/variableDeletions.test.ts +76 -0
- package/src/rules/variableDeletions.ts +43 -0
- package/src/rules/voidOperator.test.ts +99 -0
- package/src/rules/voidOperator.ts +38 -0
- package/src/utils/declarationIncludesGlobal.ts +9 -0
- package/src/utils/declarationsIncludeGlobal.ts +7 -0
- package/src/utils/getModifyingReferences.ts +58 -0
- package/src/utils/hasSameTokens.ts +45 -0
- package/src/utils/isGlobalDeclaration.ts +12 -0
- package/src/utils/isGlobalDeclarationOfName.ts +51 -0
- package/src/utils/isGlobalVariable.ts +30 -0
- package/src/utils/unwrapParentParenthesizedExpressions.ts +7 -0
- package/src/utils/unwrapParenthesizedExpression.ts +9 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import * as tsutils from "ts-api-utils";
|
|
2
|
+
import * as ts from "typescript";
|
|
3
|
+
|
|
4
|
+
import { typescriptLanguage } from "../language.js";
|
|
5
|
+
import { AnyType, discriminateAnyType } from "./utils/discriminateAnyType.js";
|
|
6
|
+
import { getConstrainedTypeAtLocation } from "./utils/getConstrainedType.js";
|
|
7
|
+
import { getThisExpression } from "./utils/getThisExpression.js";
|
|
8
|
+
import { isUnsafeAssignment } from "./utils/isUnsafeAssignment.js";
|
|
9
|
+
|
|
10
|
+
export default typescriptLanguage.createRule({
|
|
11
|
+
about: {
|
|
12
|
+
description: "Reports returning a value with type `any` from a function.",
|
|
13
|
+
id: "anyReturns",
|
|
14
|
+
preset: "logical",
|
|
15
|
+
},
|
|
16
|
+
messages: {
|
|
17
|
+
unsafeReturn: {
|
|
18
|
+
primary: "Unsafe return of a value of type {{ type }}.",
|
|
19
|
+
secondary: [
|
|
20
|
+
"Returning a value of type `any` or a similar unsafe type defeats TypeScript's type safety guarantees.",
|
|
21
|
+
"This can allow unexpected types to propagate through your codebase, potentially causing runtime errors.",
|
|
22
|
+
],
|
|
23
|
+
suggestions: [
|
|
24
|
+
"Ensure the returned value has a well-defined, specific type.",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
unsafeReturnAssignment: {
|
|
28
|
+
primary:
|
|
29
|
+
"Unsafe return of type `{{ sender }}` from function with return type `{{ receiver }}`.",
|
|
30
|
+
secondary: [
|
|
31
|
+
"The function's declared return type does not safely accept the value being returned.",
|
|
32
|
+
"This can allow unexpected types to propagate through your codebase, potentially causing runtime errors.",
|
|
33
|
+
],
|
|
34
|
+
suggestions: [
|
|
35
|
+
"Adjust the return type of the function to match the returned value, if appropriate.",
|
|
36
|
+
"Otherwise, refine the returned value to ensure it matches the expected return type.",
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
unsafeReturnThis: {
|
|
40
|
+
primary:
|
|
41
|
+
"Unsafe return of a value of type `{{ type }}`. `this` is typed as `any`.",
|
|
42
|
+
secondary: [
|
|
43
|
+
"Returning `this` when it is implicitly typed as `any` introduces type-unsafe behavior.",
|
|
44
|
+
"This can allow unexpected types to propagate through your codebase, potentially causing runtime errors.",
|
|
45
|
+
],
|
|
46
|
+
suggestions: [
|
|
47
|
+
"Enable the `noImplicitThis` compiler option to enforce explicit `this` types.",
|
|
48
|
+
"Add an explicit `this` parameter to the function to clarify its type.",
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
setup(context) {
|
|
53
|
+
const isNoImplicitThis = tsutils.isStrictCompilerOptionEnabled(
|
|
54
|
+
context.program.getCompilerOptions(),
|
|
55
|
+
"noImplicitThis",
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
function checkReturn(returnNode: ts.Node, reportingNode: ts.Node): void {
|
|
59
|
+
const type = context.typeChecker.getTypeAtLocation(returnNode);
|
|
60
|
+
|
|
61
|
+
const anyType = discriminateAnyType(
|
|
62
|
+
type,
|
|
63
|
+
context.typeChecker,
|
|
64
|
+
context.program,
|
|
65
|
+
returnNode,
|
|
66
|
+
);
|
|
67
|
+
const functionNode = ts.findAncestor(
|
|
68
|
+
returnNode,
|
|
69
|
+
// TODO: I believe isFunctionLikeDeclaration was incorrectly marked
|
|
70
|
+
// as deprecated in https://github.com/JoshuaKGoldberg/ts-api-utils/pull/124
|
|
71
|
+
// It says "With TypeScript v5, in favor of typescript's `isFunctionLike`."
|
|
72
|
+
// However, isFunctionLike also checks for signature-like nodes,
|
|
73
|
+
// whereas isFunctionLikeDeclaration checks only for function-like nodes.
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
75
|
+
tsutils.isFunctionLikeDeclaration,
|
|
76
|
+
);
|
|
77
|
+
if (!functionNode) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// function has an explicit return type, so ensure it's a safe return
|
|
82
|
+
const returnNodeType = getConstrainedTypeAtLocation(
|
|
83
|
+
returnNode,
|
|
84
|
+
context.typeChecker,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// function expressions will not have their return type modified based on receiver typing
|
|
88
|
+
// so we have to use the contextual typing in these cases, i.e.
|
|
89
|
+
// const foo1: () => Set<string> = () => new Set<any>();
|
|
90
|
+
// the return type of the arrow function is Set<any> even though the variable is typed as Set<string>
|
|
91
|
+
let functionType =
|
|
92
|
+
ts.isFunctionExpression(functionNode) ||
|
|
93
|
+
ts.isArrowFunction(functionNode)
|
|
94
|
+
? context.typeChecker.getContextualType(functionNode)
|
|
95
|
+
: context.typeChecker.getTypeAtLocation(functionNode);
|
|
96
|
+
functionType ??= context.typeChecker.getTypeAtLocation(functionNode);
|
|
97
|
+
const callSignatures = tsutils.getCallSignaturesOfType(functionType);
|
|
98
|
+
// If there is an explicit type annotation *and* that type matches the actual
|
|
99
|
+
// function return type, we shouldn't complain (it's intentional, even if unsafe)
|
|
100
|
+
if (functionNode.type) {
|
|
101
|
+
for (const signature of callSignatures) {
|
|
102
|
+
const signatureReturnType = signature.getReturnType();
|
|
103
|
+
|
|
104
|
+
if (
|
|
105
|
+
returnNodeType === signatureReturnType ||
|
|
106
|
+
tsutils.isTypeFlagSet(
|
|
107
|
+
signatureReturnType,
|
|
108
|
+
ts.TypeFlags.Any | ts.TypeFlags.Unknown,
|
|
109
|
+
)
|
|
110
|
+
) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (
|
|
114
|
+
tsutils.includesModifier(
|
|
115
|
+
functionNode.modifiers,
|
|
116
|
+
ts.SyntaxKind.AsyncKeyword,
|
|
117
|
+
)
|
|
118
|
+
) {
|
|
119
|
+
const awaitedSignatureReturnType =
|
|
120
|
+
context.typeChecker.getAwaitedType(signatureReturnType);
|
|
121
|
+
|
|
122
|
+
const awaitedReturnNodeType =
|
|
123
|
+
context.typeChecker.getAwaitedType(returnNodeType);
|
|
124
|
+
if (
|
|
125
|
+
awaitedReturnNodeType === awaitedSignatureReturnType ||
|
|
126
|
+
(awaitedSignatureReturnType &&
|
|
127
|
+
tsutils.isTypeFlagSet(
|
|
128
|
+
awaitedSignatureReturnType,
|
|
129
|
+
ts.TypeFlags.Any | ts.TypeFlags.Unknown,
|
|
130
|
+
))
|
|
131
|
+
) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (anyType !== AnyType.Safe) {
|
|
139
|
+
// Allow cases when the declared return type of the function is either unknown or unknown[]
|
|
140
|
+
// and the function is returning any or any[].
|
|
141
|
+
for (const signature of callSignatures) {
|
|
142
|
+
const functionReturnType = signature.getReturnType();
|
|
143
|
+
if (
|
|
144
|
+
anyType === AnyType.Any &&
|
|
145
|
+
tsutils.isTypeFlagSet(functionReturnType, ts.TypeFlags.Unknown)
|
|
146
|
+
) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (
|
|
150
|
+
anyType === AnyType.AnyArray &&
|
|
151
|
+
context.typeChecker.isArrayType(functionReturnType) &&
|
|
152
|
+
tsutils.isTypeFlagSet(
|
|
153
|
+
context.typeChecker.getTypeArguments(
|
|
154
|
+
functionReturnType as ts.TypeReference,
|
|
155
|
+
)[0],
|
|
156
|
+
ts.TypeFlags.Unknown,
|
|
157
|
+
)
|
|
158
|
+
) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const awaitedType =
|
|
162
|
+
context.typeChecker.getAwaitedType(functionReturnType);
|
|
163
|
+
if (
|
|
164
|
+
awaitedType &&
|
|
165
|
+
anyType === AnyType.PromiseAny &&
|
|
166
|
+
tsutils.isTypeFlagSet(awaitedType, ts.TypeFlags.Unknown)
|
|
167
|
+
) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (
|
|
173
|
+
anyType === AnyType.PromiseAny &&
|
|
174
|
+
!tsutils.includesModifier(
|
|
175
|
+
functionNode.modifiers,
|
|
176
|
+
ts.SyntaxKind.AsyncKeyword,
|
|
177
|
+
)
|
|
178
|
+
) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
let message: "unsafeReturn" | "unsafeReturnThis" = "unsafeReturn";
|
|
183
|
+
const isErrorType = tsutils.isIntrinsicErrorType(returnNodeType);
|
|
184
|
+
|
|
185
|
+
if (!isNoImplicitThis) {
|
|
186
|
+
// `return this`
|
|
187
|
+
const thisExpression = getThisExpression(returnNode);
|
|
188
|
+
if (
|
|
189
|
+
thisExpression &&
|
|
190
|
+
tsutils.isTypeFlagSet(
|
|
191
|
+
getConstrainedTypeAtLocation(thisExpression, context.typeChecker),
|
|
192
|
+
ts.TypeFlags.Any,
|
|
193
|
+
)
|
|
194
|
+
) {
|
|
195
|
+
message = "unsafeReturnThis";
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// If the function return type was not unknown/unknown[], mark usage as unsafeReturn.
|
|
200
|
+
context.report({
|
|
201
|
+
data: {
|
|
202
|
+
type: isErrorType
|
|
203
|
+
? "error"
|
|
204
|
+
: anyType === AnyType.Any
|
|
205
|
+
? "`any`"
|
|
206
|
+
: anyType === AnyType.PromiseAny
|
|
207
|
+
? "`Promise<any>`"
|
|
208
|
+
: "`any[]`",
|
|
209
|
+
},
|
|
210
|
+
message,
|
|
211
|
+
range: {
|
|
212
|
+
begin: reportingNode.getStart(),
|
|
213
|
+
end: reportingNode.getEnd(),
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const signature = functionType.getCallSignatures().at(0);
|
|
220
|
+
if (signature) {
|
|
221
|
+
const functionReturnType = signature.getReturnType();
|
|
222
|
+
const result = isUnsafeAssignment(
|
|
223
|
+
returnNodeType,
|
|
224
|
+
functionReturnType,
|
|
225
|
+
context.typeChecker,
|
|
226
|
+
returnNode,
|
|
227
|
+
);
|
|
228
|
+
if (!result) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const { receiver, sender } = result;
|
|
233
|
+
context.report({
|
|
234
|
+
data: {
|
|
235
|
+
receiver: context.typeChecker.typeToString(receiver),
|
|
236
|
+
sender: context.typeChecker.typeToString(sender),
|
|
237
|
+
},
|
|
238
|
+
message: "unsafeReturnAssignment",
|
|
239
|
+
range: {
|
|
240
|
+
begin: reportingNode.getStart(),
|
|
241
|
+
end: reportingNode.getEnd(),
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
visitors: {
|
|
250
|
+
ArrowFunction: (node) => {
|
|
251
|
+
if (!ts.isBlock(node.body)) {
|
|
252
|
+
checkReturn(node.body, node.body);
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
ReturnStatement: (node) => {
|
|
256
|
+
if (node.expression != null) {
|
|
257
|
+
checkReturn(node.expression, node);
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
},
|
|
263
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import rule from "./asyncPromiseExecutors.js";
|
|
2
|
+
import { ruleTester } from "./ruleTester.js";
|
|
3
|
+
|
|
4
|
+
ruleTester.describe(rule, {
|
|
5
|
+
invalid: [
|
|
6
|
+
{
|
|
7
|
+
code: `
|
|
8
|
+
new Promise(async (resolve, reject) => {
|
|
9
|
+
resolve(42);
|
|
10
|
+
});
|
|
11
|
+
`,
|
|
12
|
+
snapshot: `
|
|
13
|
+
new Promise(async (resolve, reject) => {
|
|
14
|
+
~~~~~
|
|
15
|
+
Async Promise executor functions are not able to properly catch thrown errors and often indicate unnecessarily complex logic.
|
|
16
|
+
resolve(42);
|
|
17
|
+
});
|
|
18
|
+
`,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
code: `
|
|
22
|
+
new Promise(async function(resolve, reject) {
|
|
23
|
+
resolve(42);
|
|
24
|
+
});
|
|
25
|
+
`,
|
|
26
|
+
snapshot: `
|
|
27
|
+
new Promise(async function(resolve, reject) {
|
|
28
|
+
~~~~~
|
|
29
|
+
Async Promise executor functions are not able to properly catch thrown errors and often indicate unnecessarily complex logic.
|
|
30
|
+
resolve(42);
|
|
31
|
+
});
|
|
32
|
+
`,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
code: `
|
|
36
|
+
const p = new Promise(async (resolve) => {
|
|
37
|
+
resolve();
|
|
38
|
+
});
|
|
39
|
+
`,
|
|
40
|
+
snapshot: `
|
|
41
|
+
const p = new Promise(async (resolve) => {
|
|
42
|
+
~~~~~
|
|
43
|
+
Async Promise executor functions are not able to properly catch thrown errors and often indicate unnecessarily complex logic.
|
|
44
|
+
resolve();
|
|
45
|
+
});
|
|
46
|
+
`,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
valid: [
|
|
50
|
+
`
|
|
51
|
+
new Promise((resolve, reject) => {
|
|
52
|
+
resolve(42);
|
|
53
|
+
});
|
|
54
|
+
`,
|
|
55
|
+
`
|
|
56
|
+
new Promise(function(resolve, reject) {
|
|
57
|
+
resolve(42);
|
|
58
|
+
});
|
|
59
|
+
`,
|
|
60
|
+
`
|
|
61
|
+
const p = new Promise((resolve) => {
|
|
62
|
+
doSomething().then(resolve);
|
|
63
|
+
});
|
|
64
|
+
`,
|
|
65
|
+
`
|
|
66
|
+
// Not a Promise constructor
|
|
67
|
+
new SomethingElse(async (resolve) => {
|
|
68
|
+
resolve();
|
|
69
|
+
});
|
|
70
|
+
`,
|
|
71
|
+
],
|
|
72
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as ts from "typescript";
|
|
2
|
+
|
|
3
|
+
import { typescriptLanguage } from "../language.js";
|
|
4
|
+
import { isGlobalDeclaration } from "../utils/isGlobalDeclaration.js";
|
|
5
|
+
|
|
6
|
+
export default typescriptLanguage.createRule({
|
|
7
|
+
about: {
|
|
8
|
+
description: "Reports using async functions as Promise executor functions.",
|
|
9
|
+
id: "asyncPromiseExecutors",
|
|
10
|
+
preset: "logical",
|
|
11
|
+
},
|
|
12
|
+
messages: {
|
|
13
|
+
asyncPromiseExecutor: {
|
|
14
|
+
primary:
|
|
15
|
+
"Async Promise executor functions are not able to properly catch thrown errors and often indicate unnecessarily complex logic.",
|
|
16
|
+
secondary: [
|
|
17
|
+
"The Promise executor function is called synchronously by the Promise constructor.",
|
|
18
|
+
"If an async function is used as a Promise executor, thrown errors will not be caught by the Promise and will instead result in unhandled rejections.",
|
|
19
|
+
"Additionally, if a Promise executor function is using `await`, there's probably no need to use the `new Promise` constructor.",
|
|
20
|
+
],
|
|
21
|
+
suggestions: [
|
|
22
|
+
"Remove the `async` keyword from the executor function.",
|
|
23
|
+
"If you need to use `await` inside the Promise, consider restructuring your code to avoid the Promise constructor.",
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
setup(context) {
|
|
28
|
+
return {
|
|
29
|
+
visitors: {
|
|
30
|
+
NewExpression: (node) => {
|
|
31
|
+
if (
|
|
32
|
+
!isGlobalDeclaration(node.expression, context.typeChecker) ||
|
|
33
|
+
!node.arguments?.length
|
|
34
|
+
) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const executor = node.arguments[0];
|
|
39
|
+
if (!ts.isFunctionLike(executor)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const asyncModifier = executor.modifiers?.find(
|
|
44
|
+
(mod) => mod.kind === ts.SyntaxKind.AsyncKeyword,
|
|
45
|
+
);
|
|
46
|
+
if (!asyncModifier) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
context.report({
|
|
51
|
+
message: "asyncPromiseExecutor",
|
|
52
|
+
range: {
|
|
53
|
+
begin: asyncModifier.getStart(context.sourceFile),
|
|
54
|
+
end: asyncModifier.getEnd(),
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
});
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import rule from "./caseDeclarations.js";
|
|
2
|
+
import { ruleTester } from "./ruleTester.js";
|
|
3
|
+
|
|
4
|
+
ruleTester.describe(rule, {
|
|
5
|
+
invalid: [
|
|
6
|
+
{
|
|
7
|
+
code: `
|
|
8
|
+
switch (value) {
|
|
9
|
+
case 1:
|
|
10
|
+
let x = 1;
|
|
11
|
+
break;
|
|
12
|
+
}
|
|
13
|
+
`,
|
|
14
|
+
snapshot: `
|
|
15
|
+
switch (value) {
|
|
16
|
+
case 1:
|
|
17
|
+
let x = 1;
|
|
18
|
+
~~~
|
|
19
|
+
Variables declared in case clauses without braces leak into the surrounding scope.
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
`,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
code: `
|
|
26
|
+
switch (value) {
|
|
27
|
+
case 1:
|
|
28
|
+
const x = 1;
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
`,
|
|
32
|
+
snapshot: `
|
|
33
|
+
switch (value) {
|
|
34
|
+
case 1:
|
|
35
|
+
const x = 1;
|
|
36
|
+
~~~~~
|
|
37
|
+
Variables declared in case clauses without braces leak into the surrounding scope.
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
`,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
code: `
|
|
44
|
+
switch (value) {
|
|
45
|
+
case 1:
|
|
46
|
+
function foo() {}
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
`,
|
|
50
|
+
snapshot: `
|
|
51
|
+
switch (value) {
|
|
52
|
+
case 1:
|
|
53
|
+
function foo() {}
|
|
54
|
+
~~~~~~~~
|
|
55
|
+
Variables declared in case clauses without braces leak into the surrounding scope.
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
`,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
code: `
|
|
62
|
+
switch (value) {
|
|
63
|
+
case 1:
|
|
64
|
+
class Foo {}
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
`,
|
|
68
|
+
snapshot: `
|
|
69
|
+
switch (value) {
|
|
70
|
+
case 1:
|
|
71
|
+
class Foo {}
|
|
72
|
+
~~~~~
|
|
73
|
+
Variables declared in case clauses without braces leak into the surrounding scope.
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
`,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
code: `
|
|
80
|
+
switch (value) {
|
|
81
|
+
default:
|
|
82
|
+
let x = 1;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
`,
|
|
86
|
+
snapshot: `
|
|
87
|
+
switch (value) {
|
|
88
|
+
default:
|
|
89
|
+
let x = 1;
|
|
90
|
+
~~~
|
|
91
|
+
Variables declared in case clauses without braces leak into the surrounding scope.
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
`,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
code: `
|
|
98
|
+
switch (value) {
|
|
99
|
+
default:
|
|
100
|
+
const x = 1;
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
`,
|
|
104
|
+
snapshot: `
|
|
105
|
+
switch (value) {
|
|
106
|
+
default:
|
|
107
|
+
const x = 1;
|
|
108
|
+
~~~~~
|
|
109
|
+
Variables declared in case clauses without braces leak into the surrounding scope.
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
`,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
code: `
|
|
116
|
+
switch (value) {
|
|
117
|
+
case 1:
|
|
118
|
+
let x = 1;
|
|
119
|
+
case 2:
|
|
120
|
+
let y = 2;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
`,
|
|
124
|
+
snapshot: `
|
|
125
|
+
switch (value) {
|
|
126
|
+
case 1:
|
|
127
|
+
let x = 1;
|
|
128
|
+
~~~
|
|
129
|
+
Variables declared in case clauses without braces leak into the surrounding scope.
|
|
130
|
+
case 2:
|
|
131
|
+
let y = 2;
|
|
132
|
+
~~~
|
|
133
|
+
Variables declared in case clauses without braces leak into the surrounding scope.
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
`,
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
code: `
|
|
140
|
+
switch (value) {
|
|
141
|
+
case 1:
|
|
142
|
+
const x = 1;
|
|
143
|
+
console.log(x);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
`,
|
|
147
|
+
snapshot: `
|
|
148
|
+
switch (value) {
|
|
149
|
+
case 1:
|
|
150
|
+
const x = 1;
|
|
151
|
+
~~~~~
|
|
152
|
+
Variables declared in case clauses without braces leak into the surrounding scope.
|
|
153
|
+
console.log(x);
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
`,
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
valid: [
|
|
160
|
+
`switch (value) { case 1: { let x = 1; break; } }`,
|
|
161
|
+
`switch (value) { case 1: { const x = 1; break; } }`,
|
|
162
|
+
`switch (value) { case 1: { function foo() {} break; } }`,
|
|
163
|
+
`switch (value) { case 1: { class Foo {} break; } }`,
|
|
164
|
+
`switch (value) { default: { let x = 1; break; } }`,
|
|
165
|
+
`switch (value) { default: { const x = 1; break; } }`,
|
|
166
|
+
`switch (value) { case 1: var x = 1; break; }`,
|
|
167
|
+
`switch (value) { case 1: break; }`,
|
|
168
|
+
`switch (value) { case 1: console.log("test"); break; }`,
|
|
169
|
+
`
|
|
170
|
+
switch (value) {
|
|
171
|
+
case 1: {
|
|
172
|
+
let x = 1;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
`,
|
|
177
|
+
`
|
|
178
|
+
switch (value) {
|
|
179
|
+
case 1: {
|
|
180
|
+
const x = 1;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
`,
|
|
185
|
+
`
|
|
186
|
+
switch (value) {
|
|
187
|
+
case 1: {
|
|
188
|
+
function foo() {}
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
`,
|
|
193
|
+
`
|
|
194
|
+
switch (value) {
|
|
195
|
+
case 1: {
|
|
196
|
+
class Foo {}
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
`,
|
|
201
|
+
`
|
|
202
|
+
switch (value) {
|
|
203
|
+
case 1:
|
|
204
|
+
var x = 1;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
`,
|
|
208
|
+
`
|
|
209
|
+
switch (value) {
|
|
210
|
+
case 1: {
|
|
211
|
+
let x = 1;
|
|
212
|
+
}
|
|
213
|
+
case 2: {
|
|
214
|
+
let y = 2;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
`,
|
|
219
|
+
`
|
|
220
|
+
switch (value) {
|
|
221
|
+
default: {
|
|
222
|
+
let x = 1;
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
`,
|
|
227
|
+
],
|
|
228
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as tsutils from "ts-api-utils";
|
|
2
|
+
import * as ts from "typescript";
|
|
3
|
+
|
|
4
|
+
import { getTSNodeRange } from "../getTSNodeRange.js";
|
|
5
|
+
import { typescriptLanguage } from "../language.js";
|
|
6
|
+
|
|
7
|
+
export default typescriptLanguage.createRule({
|
|
8
|
+
about: {
|
|
9
|
+
description:
|
|
10
|
+
"Reports lexical declarations in case clauses without wrapping them in blocks.",
|
|
11
|
+
id: "caseDeclarations",
|
|
12
|
+
preset: "untyped",
|
|
13
|
+
},
|
|
14
|
+
messages: {
|
|
15
|
+
unexpectedLexicalDeclaration: {
|
|
16
|
+
primary:
|
|
17
|
+
"Variables declared in case clauses without braces leak into the surrounding scope.",
|
|
18
|
+
secondary: [
|
|
19
|
+
"Lexical declarations (let, const, function, class) are scoped to the entire switch statement, not just the case clause where they are declared.",
|
|
20
|
+
"This can lead to unexpected behavior when the same variable name is used in multiple case clauses, as they will conflict in the same scope.",
|
|
21
|
+
],
|
|
22
|
+
suggestions: [
|
|
23
|
+
"Wrap the case clause contents in curly braces {} to create a block scope.",
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
setup(context) {
|
|
28
|
+
function getLexicalDeclaration(
|
|
29
|
+
statements: ts.NodeArray<ts.Statement>,
|
|
30
|
+
): ts.Node | undefined {
|
|
31
|
+
for (const statement of statements) {
|
|
32
|
+
if (
|
|
33
|
+
ts.isVariableStatement(statement) &&
|
|
34
|
+
tsutils.isNodeFlagSet(
|
|
35
|
+
statement.declarationList,
|
|
36
|
+
ts.NodeFlags.Let | ts.NodeFlags.Const,
|
|
37
|
+
)
|
|
38
|
+
) {
|
|
39
|
+
return statement.declarationList.getChildAt(0, context.sourceFile);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (
|
|
43
|
+
ts.isClassDeclaration(statement) ||
|
|
44
|
+
ts.isFunctionDeclaration(statement)
|
|
45
|
+
) {
|
|
46
|
+
return statement.getChildAt(0, context.sourceFile);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function checkClause(node: ts.CaseClause | ts.DefaultClause): void {
|
|
54
|
+
const declarationNode = getLexicalDeclaration(node.statements);
|
|
55
|
+
if (declarationNode) {
|
|
56
|
+
context.report({
|
|
57
|
+
message: "unexpectedLexicalDeclaration",
|
|
58
|
+
range: getTSNodeRange(declarationNode, context.sourceFile),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
visitors: {
|
|
65
|
+
CaseClause: checkClause,
|
|
66
|
+
DefaultClause: checkClause,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
});
|