@checkdigit/eslint-plugin 6.6.0-PR.75-7c7f → 6.6.0-PR.75-487e
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/dist-cjs/index.cjs +86 -66
- package/dist-cjs/metafile.json +4 -4
- package/dist-mjs/agent/fix-function-call-arguments.mjs +63 -43
- package/dist-types/agent/fix-function-call-arguments.d.ts +6 -1
- package/dist-types/index.d.ts +3 -1
- package/package.json +1 -1
- package/src/agent/fix-function-call-arguments.ts +71 -50
package/dist-cjs/metafile.json
CHANGED
|
@@ -12324,7 +12324,7 @@
|
|
|
12324
12324
|
"format": "esm"
|
|
12325
12325
|
},
|
|
12326
12326
|
"src/agent/fix-function-call-arguments.ts": {
|
|
12327
|
-
"bytes":
|
|
12327
|
+
"bytes": 6880,
|
|
12328
12328
|
"imports": [
|
|
12329
12329
|
{
|
|
12330
12330
|
"path": "node_modules/@typescript-eslint/utils/dist/index.js",
|
|
@@ -15743,10 +15743,10 @@
|
|
|
15743
15743
|
"bytesInOutput": 12231
|
|
15744
15744
|
},
|
|
15745
15745
|
"src/agent/fix-function-call-arguments.ts": {
|
|
15746
|
-
"bytesInOutput":
|
|
15746
|
+
"bytesInOutput": 6098
|
|
15747
15747
|
},
|
|
15748
15748
|
"src/invalid-json-stringify.ts": {
|
|
15749
|
-
"bytesInOutput":
|
|
15749
|
+
"bytesInOutput": 2475
|
|
15750
15750
|
},
|
|
15751
15751
|
"src/no-duplicated-imports.ts": {
|
|
15752
15752
|
"bytesInOutput": 3736
|
|
@@ -15821,7 +15821,7 @@
|
|
|
15821
15821
|
"bytesInOutput": 3362
|
|
15822
15822
|
}
|
|
15823
15823
|
},
|
|
15824
|
-
"bytes":
|
|
15824
|
+
"bytes": 4373358
|
|
15825
15825
|
}
|
|
15826
15826
|
}
|
|
15827
15827
|
}
|
|
@@ -4,6 +4,9 @@ import { strict as assert } from "node:assert";
|
|
|
4
4
|
import debug from "debug";
|
|
5
5
|
import getDocumentationUrl from "../get-documentation-url.mjs";
|
|
6
6
|
var ruleId = "fix-function-call-arguments";
|
|
7
|
+
var DEFAULT_OPTIONS = {
|
|
8
|
+
typesToCheck: ["Configuration<ResolvedServices>", "EMPTY_CONTEXT", "Fixture"]
|
|
9
|
+
};
|
|
7
10
|
var createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
|
|
8
11
|
var log = debug("eslint-plugin:fix-function-call-arguments");
|
|
9
12
|
var rule = createRule({
|
|
@@ -18,10 +21,25 @@ var rule = createRule({
|
|
|
18
21
|
unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.'
|
|
19
22
|
},
|
|
20
23
|
fixable: "code",
|
|
21
|
-
schema: [
|
|
24
|
+
schema: [
|
|
25
|
+
{
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
typesToCheck: {
|
|
29
|
+
description: "Text representation of the types of which the function call parameters will be examine",
|
|
30
|
+
type: "array",
|
|
31
|
+
items: {
|
|
32
|
+
type: "string"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
additionalProperties: false
|
|
37
|
+
}
|
|
38
|
+
]
|
|
22
39
|
},
|
|
23
|
-
defaultOptions: [],
|
|
40
|
+
defaultOptions: [DEFAULT_OPTIONS],
|
|
24
41
|
create(context) {
|
|
42
|
+
const { typesToCheck } = context.options[0];
|
|
25
43
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
26
44
|
const typeChecker = parserServices.program.getTypeChecker();
|
|
27
45
|
const sourceCode = context.sourceCode;
|
|
@@ -36,57 +54,59 @@ var rule = createRule({
|
|
|
36
54
|
const calleeTsNode = parserServices.esTreeNodeToTSNodeMap.get(callExpression.callee);
|
|
37
55
|
const calleeType = typeChecker.getTypeAtLocation(calleeTsNode);
|
|
38
56
|
const signatures = calleeType.getCallSignatures();
|
|
39
|
-
if (
|
|
40
|
-
// ignore complex signatures with overloads
|
|
41
|
-
signatures.length > 1
|
|
42
|
-
) {
|
|
57
|
+
if (signatures.length > 1) {
|
|
43
58
|
return;
|
|
44
59
|
}
|
|
45
60
|
const signature = signatures[0];
|
|
46
|
-
|
|
47
|
-
signature.typeParameters !== void 0 && signature.typeParameters.length > 0) {
|
|
61
|
+
assert.ok(signature, "Signature not found.");
|
|
62
|
+
if (signature.typeParameters !== void 0 && signature.typeParameters.length > 0) {
|
|
48
63
|
return;
|
|
49
64
|
}
|
|
50
|
-
|
|
51
|
-
const
|
|
65
|
+
log("signature:", signature.getDeclaration().getText());
|
|
66
|
+
const expectedParameters = signature.getParameters();
|
|
67
|
+
log(
|
|
68
|
+
"expected parameters:",
|
|
69
|
+
expectedParameters.map(
|
|
70
|
+
(expectedParameter) => typeChecker.typeToString(typeChecker.getTypeOfSymbol(expectedParameter))
|
|
71
|
+
)
|
|
72
|
+
);
|
|
73
|
+
const expectedParametersCount = expectedParameters.length;
|
|
52
74
|
const actualParameters = callExpression.arguments;
|
|
53
75
|
const actualParametersCount = actualParameters.length;
|
|
54
76
|
if (actualParametersCount === 0 || actualParametersCount === expectedParametersCount) {
|
|
55
77
|
return;
|
|
56
78
|
}
|
|
57
79
|
const parametersToKeep = [];
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
);
|
|
77
|
-
log(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
log("not matched");
|
|
89
|
-
}
|
|
80
|
+
let expectedParameterIndex = 0;
|
|
81
|
+
for (const [actualParameterIndex, actualParameter] of actualParameters.entries()) {
|
|
82
|
+
if (expectedParameterIndex >= expectedParametersCount) {
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
const expectedParameter = expectedParameters[expectedParameterIndex];
|
|
86
|
+
assert.ok(expectedParameter, "Expected parameter not found.");
|
|
87
|
+
const expectedType = typeChecker.getTypeOfSymbol(expectedParameter);
|
|
88
|
+
const actualType = typeChecker.getTypeAtLocation(parserServices.esTreeNodeToTSNodeMap.get(actualParameter));
|
|
89
|
+
const actualTypeString = typeChecker.typeToString(actualType);
|
|
90
|
+
log(
|
|
91
|
+
"expected type: #",
|
|
92
|
+
expectedParameterIndex,
|
|
93
|
+
expectedParameter.escapedName,
|
|
94
|
+
typeChecker.typeToString(expectedType)
|
|
95
|
+
);
|
|
96
|
+
log("actual type: #", actualParameterIndex, sourceCode.getText(actualParameter), actualTypeString);
|
|
97
|
+
if (!typesToCheck.includes(actualTypeString)) {
|
|
98
|
+
parametersToKeep.push(actualParameter);
|
|
99
|
+
log("skipped");
|
|
100
|
+
} else if (
|
|
101
|
+
// @ts-expect-error: this is typescript's internal API
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
103
|
+
typeChecker.isTypeAssignableTo(actualType, expectedType) === true
|
|
104
|
+
) {
|
|
105
|
+
parametersToKeep.push(actualParameter);
|
|
106
|
+
log("matched");
|
|
107
|
+
expectedParameterIndex++;
|
|
108
|
+
} else {
|
|
109
|
+
log("not matched");
|
|
90
110
|
}
|
|
91
111
|
}
|
|
92
112
|
if (parametersToKeep.length === actualParametersCount) {
|
|
@@ -129,4 +149,4 @@ export {
|
|
|
129
149
|
fix_function_call_arguments_default as default,
|
|
130
150
|
ruleId
|
|
131
151
|
};
|
|
132
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
152
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FnZW50L2ZpeC1mdW5jdGlvbi1jYWxsLWFyZ3VtZW50cy50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFRQSxTQUFTLGFBQWEsZ0JBQWdCO0FBQ3RDLFNBQVMsVUFBVSxjQUFjO0FBQ2pDLE9BQU8sV0FBVztBQUNsQixPQUFPLHlCQUF5QjtBQUV6QixJQUFNLFNBQVM7QUFLdEIsSUFBTSxrQkFBa0I7QUFBQSxFQUN0QixjQUFjLENBQUMsbUNBQW1DLGlCQUFpQixTQUFTO0FBQzlFO0FBRUEsSUFBTSxhQUFhLFlBQVksWUFBWSxDQUFDLFNBQVMsb0JBQW9CLElBQUksQ0FBQztBQUM5RSxJQUFNLE1BQU0sTUFBTSwyQ0FBMkM7QUFFN0QsSUFBTSxPQUFPLFdBQVc7QUFBQSxFQUN0QixNQUFNO0FBQUEsRUFDTixNQUFNO0FBQUEsSUFDSixNQUFNO0FBQUEsSUFDTixNQUFNO0FBQUEsTUFDSixhQUFhO0FBQUEsSUFDZjtBQUFBLElBQ0EsVUFBVTtBQUFBLE1BQ1IscUNBQXFDO0FBQUEsTUFDckMsY0FBYztBQUFBLElBQ2hCO0FBQUEsSUFDQSxTQUFTO0FBQUEsSUFDVCxRQUFRO0FBQUEsTUFDTjtBQUFBLFFBQ0UsTUFBTTtBQUFBLFFBQ04sWUFBWTtBQUFBLFVBQ1YsY0FBYztBQUFBLFlBQ1osYUFBYTtBQUFBLFlBQ2IsTUFBTTtBQUFBLFlBQ04sT0FBTztBQUFBLGNBQ0wsTUFBTTtBQUFBLFlBQ1I7QUFBQSxVQUNGO0FBQUEsUUFDRjtBQUFBLFFBQ0Esc0JBQXNCO0FBQUEsTUFDeEI7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUFBLEVBQ0EsZ0JBQWdCLENBQUMsZUFBZTtBQUFBLEVBQ2hDLE9BQU8sU0FBUztBQUNkLFVBQU0sRUFBRSxhQUFhLElBQUksUUFBUSxRQUFRLENBQUM7QUFDMUMsVUFBTSxpQkFBaUIsWUFBWSxrQkFBa0IsT0FBTztBQUM1RCxVQUFNLGNBQWMsZUFBZSxRQUFRLGVBQWU7QUFDMUQsVUFBTSxhQUFhLFFBQVE7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
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
2
|
export declare const ruleId = "fix-function-call-arguments";
|
|
3
|
-
|
|
3
|
+
export interface FixFunctionCallArgumentsRuleOptions {
|
|
4
|
+
typesToCheck: string[];
|
|
5
|
+
}
|
|
6
|
+
declare const rule: ESLintUtils.RuleModule<"unknownError" | "removeIncompatibleFunctionArguments", {
|
|
7
|
+
typesToCheck: string[];
|
|
8
|
+
}[], ESLintUtils.RuleListener>;
|
|
4
9
|
export default rule;
|
package/dist-types/index.d.ts
CHANGED
|
@@ -27,7 +27,9 @@ declare const _default: {
|
|
|
27
27
|
"no-unused-function-argument": import("@typescript-eslint/utils/ts-eslint").RuleModule<"unknownError" | "removeUnusedFunctionArguments", never[], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
28
28
|
"no-unused-service-variable": import("@typescript-eslint/utils/ts-eslint").RuleModule<"unknownError" | "removeUnusedServiceVariables", never[], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
29
29
|
"no-unused-imports": import("@typescript-eslint/utils/ts-eslint").RuleModule<"unknownError" | "removeUnusedImports", never[], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
30
|
-
"fix-function-call-arguments": import("@typescript-eslint/utils/ts-eslint").RuleModule<"unknownError" | "removeIncompatibleFunctionArguments",
|
|
30
|
+
"fix-function-call-arguments": import("@typescript-eslint/utils/ts-eslint").RuleModule<"unknownError" | "removeIncompatibleFunctionArguments", {
|
|
31
|
+
typesToCheck: string[];
|
|
32
|
+
}[], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
31
33
|
};
|
|
32
34
|
configs: {
|
|
33
35
|
all: {
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@checkdigit/eslint-plugin","version":"6.6.0-PR.75-
|
|
1
|
+
{"name":"@checkdigit/eslint-plugin","version":"6.6.0-PR.75-487e","description":"Check Digit eslint plugins","keywords":["eslint","eslintplugin"],"homepage":"https://github.com/checkdigit/eslint-plugin#readme","bugs":{"url":"https://github.com/checkdigit/eslint-plugin/issues"},"repository":{"type":"git","url":"https://github.com/checkdigit/eslint-plugin"},"license":"MIT","author":"Check Digit, LLC","sideEffects":false,"type":"module","exports":{".":{"types":"./dist-types/index.d.ts","require":"./dist-cjs/index.cjs","import":"./dist-mjs/index.mjs","default":"./dist-mjs/index.mjs"}},"files":["src","dist-types","dist-cjs","dist-mjs","!src/**/*.test.ts","!src/**/*.spec.ts","!dist-types/**/*.test.d.ts","!dist-types/**/*.spec.d.ts","!dist-cjs/**/*.test.cjs","!dist-cjs/**/*.spec.cjs","!dist-mjs/**/*.test.mjs","!dist-mjs/**/*.spec.mjs","SECURITY.md"],"scripts":{"build:dist-cjs":"rimraf dist-cjs && npx builder --type=commonjs --sourceMap --entryPoint=index.ts --outDir=dist-cjs --outFile=index.cjs --external=espree && echo \"module.exports = module.exports.default;\" >> dist-cjs/index.cjs","build:dist-mjs":"rimraf dist-mjs && npx builder --type=module --sourceMap --outDir=dist-mjs && node dist-mjs/index.mjs","build:dist-types":"rimraf dist-types && npx builder --type=types --outDir=dist-types","ci:compile":"tsc --noEmit","ci:coverage":"NODE_OPTIONS=\"--disable-warning ExperimentalWarning --experimental-vm-modules\" jest --coverage=true","ci:lint":"npm run lint","ci:style":"npm run prettier","ci:test":"NODE_OPTIONS=\"--disable-warning ExperimentalWarning --experimental-vm-modules\" jest --coverage=false","lint":"eslint --max-warnings 0 --ignore-path .gitignore .","lint:fix":"eslint --ignore-path .gitignore . --fix","prepublishOnly":"npm run build:dist-types && npm run build:dist-cjs && npm run build:dist-mjs","prettier":"prettier --ignore-path .gitignore --list-different .","prettier:fix":"prettier --ignore-path .gitignore --write .","test":"npm run ci:compile && npm run ci:test && npm run ci:lint && npm run ci:style"},"prettier":"@checkdigit/prettier-config","jest":{"preset":"@checkdigit/jest-config"},"dependencies":{"@typescript-eslint/type-utils":"7.18.0","@typescript-eslint/utils":"7.18.0","debug":"^4.3.7","ts-api-utils":"^1.3.0"},"devDependencies":{"@checkdigit/jest-config":"^6.0.2","@checkdigit/prettier-config":"^5.5.0","@checkdigit/typescript-config":"6.0.0","@types/debug":"^4.1.12","@types/eslint":"8.56.10","@typescript-eslint/eslint-plugin":"7.18.0","@typescript-eslint/parser":"7.18.0","@typescript-eslint/rule-tester":"7.18.0","eslint-config-prettier":"^9.1.0","eslint-plugin-eslint-plugin":"^6.2.0","eslint-plugin-import":"^2.29.1","eslint-plugin-no-only-tests":"^3.1.0","eslint-plugin-no-secrets":"^1.0.2","eslint-plugin-node":"^11.1.0","eslint-plugin-sonarjs":"0.24.0","http-status-codes":"^2.3.0"},"peerDependencies":{"eslint":">=8 <9"},"engines":{"node":">=20.14"}}
|
|
@@ -13,6 +13,13 @@ import getDocumentationUrl from '../get-documentation-url';
|
|
|
13
13
|
|
|
14
14
|
export const ruleId = 'fix-function-call-arguments';
|
|
15
15
|
|
|
16
|
+
export interface FixFunctionCallArgumentsRuleOptions {
|
|
17
|
+
typesToCheck: string[];
|
|
18
|
+
}
|
|
19
|
+
const DEFAULT_OPTIONS = {
|
|
20
|
+
typesToCheck: ['Configuration<ResolvedServices>', 'EMPTY_CONTEXT', 'Fixture'],
|
|
21
|
+
};
|
|
22
|
+
|
|
16
23
|
const createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
|
|
17
24
|
const log = debug('eslint-plugin:fix-function-call-arguments');
|
|
18
25
|
|
|
@@ -28,10 +35,25 @@ const rule = createRule({
|
|
|
28
35
|
unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.',
|
|
29
36
|
},
|
|
30
37
|
fixable: 'code',
|
|
31
|
-
schema: [
|
|
38
|
+
schema: [
|
|
39
|
+
{
|
|
40
|
+
type: 'object',
|
|
41
|
+
properties: {
|
|
42
|
+
typesToCheck: {
|
|
43
|
+
description: 'Text representation of the types of which the function call parameters will be examine',
|
|
44
|
+
type: 'array',
|
|
45
|
+
items: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
additionalProperties: false,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
32
53
|
},
|
|
33
|
-
defaultOptions: [],
|
|
54
|
+
defaultOptions: [DEFAULT_OPTIONS],
|
|
34
55
|
create(context) {
|
|
56
|
+
const { typesToCheck } = context.options[0] as FixFunctionCallArgumentsRuleOptions;
|
|
35
57
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
36
58
|
const typeChecker = parserServices.program.getTypeChecker();
|
|
37
59
|
const sourceCode = context.sourceCode;
|
|
@@ -51,70 +73,69 @@ const rule = createRule({
|
|
|
51
73
|
const calleeType = typeChecker.getTypeAtLocation(calleeTsNode);
|
|
52
74
|
|
|
53
75
|
const signatures = calleeType.getCallSignatures();
|
|
54
|
-
if (
|
|
76
|
+
if (signatures.length > 1) {
|
|
55
77
|
// ignore complex signatures with overloads
|
|
56
|
-
signatures.length > 1
|
|
57
|
-
) {
|
|
58
78
|
return;
|
|
59
79
|
}
|
|
60
80
|
|
|
61
81
|
const signature = signatures[0];
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// ignore complex signatures
|
|
65
|
-
(signature.typeParameters !== undefined && signature.typeParameters.length > 0)
|
|
66
|
-
) {
|
|
82
|
+
assert.ok(signature, 'Signature not found.');
|
|
83
|
+
if (signature.typeParameters !== undefined && signature.typeParameters.length > 0) {
|
|
84
|
+
// ignore complex signatures with type parameters
|
|
67
85
|
return;
|
|
68
86
|
}
|
|
69
87
|
|
|
70
|
-
|
|
71
|
-
const
|
|
88
|
+
log('signature:', signature.getDeclaration().getText());
|
|
89
|
+
const expectedParameters = signature.getParameters();
|
|
90
|
+
log(
|
|
91
|
+
'expected parameters:',
|
|
92
|
+
expectedParameters.map((expectedParameter) =>
|
|
93
|
+
typeChecker.typeToString(typeChecker.getTypeOfSymbol(expectedParameter)),
|
|
94
|
+
),
|
|
95
|
+
);
|
|
96
|
+
const expectedParametersCount = expectedParameters.length;
|
|
72
97
|
const actualParameters = callExpression.arguments;
|
|
73
98
|
const actualParametersCount = actualParameters.length;
|
|
74
99
|
if (actualParametersCount === 0 || actualParametersCount === expectedParametersCount) {
|
|
75
100
|
return;
|
|
76
101
|
}
|
|
77
|
-
const parametersToKeep: TSESTree.CallExpressionArgument[] = [];
|
|
78
|
-
|
|
79
|
-
if (expectedParametersCount > 0) {
|
|
80
|
-
let expectedParameterIndex = 0;
|
|
81
|
-
for (const [actualParameterIndex, actualParameter] of actualParameters.entries()) {
|
|
82
|
-
if (expectedParameterIndex >= expectedParametersCount) {
|
|
83
|
-
parametersToKeep.push(actualParameter);
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const expectedParameter = signatureParameters[expectedParameterIndex];
|
|
88
|
-
assert.ok(expectedParameter, 'Expected parameter not found.');
|
|
89
102
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
103
|
+
const parametersToKeep: TSESTree.CallExpressionArgument[] = [];
|
|
104
|
+
let expectedParameterIndex = 0;
|
|
105
|
+
for (const [actualParameterIndex, actualParameter] of actualParameters.entries()) {
|
|
106
|
+
// eslint-disable-next-line max-depth
|
|
107
|
+
if (expectedParameterIndex >= expectedParametersCount) {
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
94
110
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
const expectedParameter = expectedParameters[expectedParameterIndex];
|
|
112
|
+
assert.ok(expectedParameter, 'Expected parameter not found.');
|
|
113
|
+
|
|
114
|
+
const expectedType = typeChecker.getTypeOfSymbol(expectedParameter);
|
|
115
|
+
const actualType = typeChecker.getTypeAtLocation(parserServices.esTreeNodeToTSNodeMap.get(actualParameter));
|
|
116
|
+
const actualTypeString = typeChecker.typeToString(actualType);
|
|
117
|
+
log(
|
|
118
|
+
'expected type: #',
|
|
119
|
+
expectedParameterIndex,
|
|
120
|
+
expectedParameter.escapedName,
|
|
121
|
+
typeChecker.typeToString(expectedType),
|
|
122
|
+
);
|
|
123
|
+
log('actual type: #', actualParameterIndex, sourceCode.getText(actualParameter), actualTypeString);
|
|
124
|
+
|
|
125
|
+
if (!typesToCheck.includes(actualTypeString)) {
|
|
126
|
+
// skip the parameter type checking if it's not in the candidate types
|
|
127
|
+
parametersToKeep.push(actualParameter);
|
|
128
|
+
log('skipped');
|
|
129
|
+
} else if (
|
|
130
|
+
// @ts-expect-error: this is typescript's internal API
|
|
110
131
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
132
|
+
typeChecker.isTypeAssignableTo(actualType, expectedType) === true
|
|
133
|
+
) {
|
|
134
|
+
parametersToKeep.push(actualParameter);
|
|
135
|
+
log('matched');
|
|
136
|
+
expectedParameterIndex++;
|
|
137
|
+
} else {
|
|
138
|
+
log('not matched');
|
|
118
139
|
}
|
|
119
140
|
}
|
|
120
141
|
|