@checkdigit/eslint-plugin 6.6.0-PR.75-e357 → 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 +171 -128
- package/dist-cjs/metafile.json +18 -23
- package/dist-mjs/agent/fix-function-call-arguments.mjs +77 -35
- 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 +89 -43
package/dist-cjs/metafile.json
CHANGED
|
@@ -12323,19 +12323,8 @@
|
|
|
12323
12323
|
],
|
|
12324
12324
|
"format": "esm"
|
|
12325
12325
|
},
|
|
12326
|
-
"src/library/ts-tree.ts": {
|
|
12327
|
-
"bytes": 2883,
|
|
12328
|
-
"imports": [
|
|
12329
|
-
{
|
|
12330
|
-
"path": "node_modules/@typescript-eslint/utils/dist/index.js",
|
|
12331
|
-
"kind": "import-statement",
|
|
12332
|
-
"original": "@typescript-eslint/utils"
|
|
12333
|
-
}
|
|
12334
|
-
],
|
|
12335
|
-
"format": "esm"
|
|
12336
|
-
},
|
|
12337
12326
|
"src/agent/fix-function-call-arguments.ts": {
|
|
12338
|
-
"bytes":
|
|
12327
|
+
"bytes": 6880,
|
|
12339
12328
|
"imports": [
|
|
12340
12329
|
{
|
|
12341
12330
|
"path": "node_modules/@typescript-eslint/utils/dist/index.js",
|
|
@@ -12356,11 +12345,6 @@
|
|
|
12356
12345
|
"path": "src/get-documentation-url.ts",
|
|
12357
12346
|
"kind": "import-statement",
|
|
12358
12347
|
"original": "../get-documentation-url"
|
|
12359
|
-
},
|
|
12360
|
-
{
|
|
12361
|
-
"path": "src/library/ts-tree.ts",
|
|
12362
|
-
"kind": "import-statement",
|
|
12363
|
-
"original": "../library/ts-tree"
|
|
12364
12348
|
}
|
|
12365
12349
|
],
|
|
12366
12350
|
"format": "esm"
|
|
@@ -12469,6 +12453,17 @@
|
|
|
12469
12453
|
],
|
|
12470
12454
|
"format": "esm"
|
|
12471
12455
|
},
|
|
12456
|
+
"src/library/ts-tree.ts": {
|
|
12457
|
+
"bytes": 2883,
|
|
12458
|
+
"imports": [
|
|
12459
|
+
{
|
|
12460
|
+
"path": "node_modules/@typescript-eslint/utils/dist/index.js",
|
|
12461
|
+
"kind": "import-statement",
|
|
12462
|
+
"original": "@typescript-eslint/utils"
|
|
12463
|
+
}
|
|
12464
|
+
],
|
|
12465
|
+
"format": "esm"
|
|
12466
|
+
},
|
|
12472
12467
|
"src/agent/no-full-response.ts": {
|
|
12473
12468
|
"bytes": 2331,
|
|
12474
12469
|
"imports": [
|
|
@@ -15747,14 +15742,11 @@
|
|
|
15747
15742
|
"src/agent/fetch-then.ts": {
|
|
15748
15743
|
"bytesInOutput": 12231
|
|
15749
15744
|
},
|
|
15750
|
-
"src/library/ts-tree.ts": {
|
|
15751
|
-
"bytesInOutput": 2095
|
|
15752
|
-
},
|
|
15753
15745
|
"src/agent/fix-function-call-arguments.ts": {
|
|
15754
|
-
"bytesInOutput":
|
|
15746
|
+
"bytesInOutput": 6098
|
|
15755
15747
|
},
|
|
15756
15748
|
"src/invalid-json-stringify.ts": {
|
|
15757
|
-
"bytesInOutput":
|
|
15749
|
+
"bytesInOutput": 2475
|
|
15758
15750
|
},
|
|
15759
15751
|
"src/no-duplicated-imports.ts": {
|
|
15760
15752
|
"bytesInOutput": 3736
|
|
@@ -15765,6 +15757,9 @@
|
|
|
15765
15757
|
"src/agent/no-fixture.ts": {
|
|
15766
15758
|
"bytesInOutput": 16455
|
|
15767
15759
|
},
|
|
15760
|
+
"src/library/ts-tree.ts": {
|
|
15761
|
+
"bytesInOutput": 2095
|
|
15762
|
+
},
|
|
15768
15763
|
"src/agent/no-full-response.ts": {
|
|
15769
15764
|
"bytesInOutput": 2006
|
|
15770
15765
|
},
|
|
@@ -15826,7 +15821,7 @@
|
|
|
15826
15821
|
"bytesInOutput": 3362
|
|
15827
15822
|
}
|
|
15828
15823
|
},
|
|
15829
|
-
"bytes":
|
|
15824
|
+
"bytes": 4373358
|
|
15830
15825
|
}
|
|
15831
15826
|
}
|
|
15832
15827
|
}
|
|
@@ -3,8 +3,10 @@ import { ESLintUtils, TSESTree } from "@typescript-eslint/utils";
|
|
|
3
3
|
import { strict as assert } from "node:assert";
|
|
4
4
|
import debug from "debug";
|
|
5
5
|
import getDocumentationUrl from "../get-documentation-url.mjs";
|
|
6
|
-
import { getParent } from "../library/ts-tree.mjs";
|
|
7
6
|
var ruleId = "fix-function-call-arguments";
|
|
7
|
+
var DEFAULT_OPTIONS = {
|
|
8
|
+
typesToCheck: ["Configuration<ResolvedServices>", "EMPTY_CONTEXT", "Fixture"]
|
|
9
|
+
};
|
|
8
10
|
var createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
|
|
9
11
|
var log = debug("eslint-plugin:fix-function-call-arguments");
|
|
10
12
|
var rule = createRule({
|
|
@@ -19,59 +21,99 @@ var rule = createRule({
|
|
|
19
21
|
unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.'
|
|
20
22
|
},
|
|
21
23
|
fixable: "code",
|
|
22
|
-
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
|
+
]
|
|
23
39
|
},
|
|
24
|
-
defaultOptions: [],
|
|
40
|
+
defaultOptions: [DEFAULT_OPTIONS],
|
|
25
41
|
create(context) {
|
|
42
|
+
const { typesToCheck } = context.options[0];
|
|
26
43
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
27
44
|
const typeChecker = parserServices.program.getTypeChecker();
|
|
28
45
|
const sourceCode = context.sourceCode;
|
|
29
46
|
return {
|
|
30
47
|
CallExpression(callExpression) {
|
|
31
|
-
if (
|
|
48
|
+
if (callExpression.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression) {
|
|
32
49
|
return;
|
|
33
50
|
}
|
|
34
|
-
log("
|
|
51
|
+
log("===== file name:", context.filename);
|
|
35
52
|
log("callExpression:", sourceCode.getText(callExpression));
|
|
36
53
|
try {
|
|
37
54
|
const calleeTsNode = parserServices.esTreeNodeToTSNodeMap.get(callExpression.callee);
|
|
38
55
|
const calleeType = typeChecker.getTypeAtLocation(calleeTsNode);
|
|
39
|
-
const
|
|
40
|
-
if (
|
|
41
|
-
signature.typeParameters !== void 0 && signature.typeParameters.length > 0) {
|
|
56
|
+
const signatures = calleeType.getCallSignatures();
|
|
57
|
+
if (signatures.length > 1) {
|
|
42
58
|
return;
|
|
43
59
|
}
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const providedArgsCount = providedArgs.length;
|
|
48
|
-
if (providedArgsCount === 0 || providedArgsCount === expectedArgsCount) {
|
|
60
|
+
const signature = signatures[0];
|
|
61
|
+
assert.ok(signature, "Signature not found.");
|
|
62
|
+
if (signature.typeParameters !== void 0 && signature.typeParameters.length > 0) {
|
|
49
63
|
return;
|
|
50
64
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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;
|
|
74
|
+
const actualParameters = callExpression.arguments;
|
|
75
|
+
const actualParametersCount = actualParameters.length;
|
|
76
|
+
if (actualParametersCount === 0 || actualParametersCount === expectedParametersCount) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const parametersToKeep = [];
|
|
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");
|
|
68
110
|
}
|
|
69
111
|
}
|
|
70
|
-
if (
|
|
112
|
+
if (parametersToKeep.length === actualParametersCount) {
|
|
71
113
|
return;
|
|
72
114
|
}
|
|
73
|
-
const firstParameter =
|
|
74
|
-
const lastParameter =
|
|
115
|
+
const firstParameter = actualParameters[0];
|
|
116
|
+
const lastParameter = actualParameters.at(-1);
|
|
75
117
|
assert.ok(firstParameter !== void 0 && lastParameter !== void 0);
|
|
76
118
|
const tokenAfterParameters = sourceCode.getTokenAfter(lastParameter);
|
|
77
119
|
context.report({
|
|
@@ -83,7 +125,7 @@ var rule = createRule({
|
|
|
83
125
|
firstParameter.range[0],
|
|
84
126
|
tokenAfterParameters?.value === "," ? tokenAfterParameters.range[1] : lastParameter.range[1]
|
|
85
127
|
],
|
|
86
|
-
|
|
128
|
+
parametersToKeep.map((arg) => sourceCode.getText(arg)).join(", ")
|
|
87
129
|
);
|
|
88
130
|
}
|
|
89
131
|
});
|
|
@@ -107,4 +149,4 @@ export {
|
|
|
107
149
|
fix_function_call_arguments_default as default,
|
|
108
150
|
ruleId
|
|
109
151
|
};
|
|
110
|
-
//# 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"}}
|
|
@@ -10,10 +10,16 @@ import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';
|
|
|
10
10
|
import { strict as assert } from 'node:assert';
|
|
11
11
|
import debug from 'debug';
|
|
12
12
|
import getDocumentationUrl from '../get-documentation-url';
|
|
13
|
-
import { getParent } from '../library/ts-tree';
|
|
14
13
|
|
|
15
14
|
export const ruleId = 'fix-function-call-arguments';
|
|
16
15
|
|
|
16
|
+
export interface FixFunctionCallArgumentsRuleOptions {
|
|
17
|
+
typesToCheck: string[];
|
|
18
|
+
}
|
|
19
|
+
const DEFAULT_OPTIONS = {
|
|
20
|
+
typesToCheck: ['Configuration<ResolvedServices>', 'EMPTY_CONTEXT', 'Fixture'],
|
|
21
|
+
};
|
|
22
|
+
|
|
17
23
|
const createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
|
|
18
24
|
const log = debug('eslint-plugin:fix-function-call-arguments');
|
|
19
25
|
|
|
@@ -29,10 +35,25 @@ const rule = createRule({
|
|
|
29
35
|
unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.',
|
|
30
36
|
},
|
|
31
37
|
fixable: 'code',
|
|
32
|
-
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
|
+
],
|
|
33
53
|
},
|
|
34
|
-
defaultOptions: [],
|
|
54
|
+
defaultOptions: [DEFAULT_OPTIONS],
|
|
35
55
|
create(context) {
|
|
56
|
+
const { typesToCheck } = context.options[0] as FixFunctionCallArgumentsRuleOptions;
|
|
36
57
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
37
58
|
const typeChecker = parserServices.program.getTypeChecker();
|
|
38
59
|
const sourceCode = context.sourceCode;
|
|
@@ -41,64 +62,89 @@ const rule = createRule({
|
|
|
41
62
|
CallExpression(callExpression) {
|
|
42
63
|
// ignore calls like `foo.bar()` which are likely to be 3rd party module calls
|
|
43
64
|
// we only focus on calls against local functions or functions imported from the same module
|
|
44
|
-
if (
|
|
65
|
+
if (callExpression.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression) {
|
|
45
66
|
return;
|
|
46
67
|
}
|
|
47
68
|
|
|
48
|
-
log('
|
|
69
|
+
log('===== file name:', context.filename);
|
|
49
70
|
log('callExpression:', sourceCode.getText(callExpression));
|
|
50
71
|
try {
|
|
51
72
|
const calleeTsNode = parserServices.esTreeNodeToTSNodeMap.get(callExpression.callee);
|
|
52
73
|
const calleeType = typeChecker.getTypeAtLocation(calleeTsNode);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
// ignore complex signatures
|
|
57
|
-
|
|
58
|
-
|
|
74
|
+
|
|
75
|
+
const signatures = calleeType.getCallSignatures();
|
|
76
|
+
if (signatures.length > 1) {
|
|
77
|
+
// ignore complex signatures with overloads
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const signature = signatures[0];
|
|
82
|
+
assert.ok(signature, 'Signature not found.');
|
|
83
|
+
if (signature.typeParameters !== undefined && signature.typeParameters.length > 0) {
|
|
84
|
+
// ignore complex signatures with type parameters
|
|
59
85
|
return;
|
|
60
86
|
}
|
|
61
87
|
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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;
|
|
97
|
+
const actualParameters = callExpression.arguments;
|
|
98
|
+
const actualParametersCount = actualParameters.length;
|
|
99
|
+
if (actualParametersCount === 0 || actualParametersCount === expectedParametersCount) {
|
|
67
100
|
return;
|
|
68
101
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
|
|
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
|
+
}
|
|
110
|
+
|
|
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
|
|
85
131
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
132
|
+
typeChecker.isTypeAssignableTo(actualType, expectedType) === true
|
|
133
|
+
) {
|
|
134
|
+
parametersToKeep.push(actualParameter);
|
|
135
|
+
log('matched');
|
|
136
|
+
expectedParameterIndex++;
|
|
137
|
+
} else {
|
|
138
|
+
log('not matched');
|
|
93
139
|
}
|
|
94
140
|
}
|
|
95
141
|
|
|
96
|
-
if (
|
|
142
|
+
if (parametersToKeep.length === actualParametersCount) {
|
|
97
143
|
return;
|
|
98
144
|
}
|
|
99
145
|
|
|
100
|
-
const firstParameter =
|
|
101
|
-
const lastParameter =
|
|
146
|
+
const firstParameter = actualParameters[0];
|
|
147
|
+
const lastParameter = actualParameters.at(-1);
|
|
102
148
|
assert.ok(firstParameter !== undefined && lastParameter !== undefined);
|
|
103
149
|
const tokenAfterParameters = sourceCode.getTokenAfter(lastParameter);
|
|
104
150
|
|
|
@@ -111,7 +157,7 @@ const rule = createRule({
|
|
|
111
157
|
firstParameter.range[0],
|
|
112
158
|
tokenAfterParameters?.value === ',' ? tokenAfterParameters.range[1] : lastParameter.range[1],
|
|
113
159
|
],
|
|
114
|
-
|
|
160
|
+
parametersToKeep.map((arg) => sourceCode.getText(arg)).join(', '),
|
|
115
161
|
);
|
|
116
162
|
},
|
|
117
163
|
});
|