@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.
@@ -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": 5206,
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": 4458
15746
+ "bytesInOutput": 6098
15755
15747
  },
15756
15748
  "src/invalid-json-stringify.ts": {
15757
- "bytesInOutput": 2473
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": 4370736
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 (getParent(callExpression)?.type === TSESTree.AST_NODE_TYPES.MemberExpression) {
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 signature = calleeType.getCallSignatures()[0];
40
- if (!signature || // ignore complex signatures
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 signatureParameters = signature.getParameters();
45
- const expectedArgsCount = signatureParameters.length;
46
- const providedArgs = callExpression.arguments;
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
- const argsToKeep = [];
52
- if (expectedArgsCount > 0) {
53
- let parameterIndex = 0;
54
- for (const arg of providedArgs) {
55
- const currentExpectedArg = signatureParameters[parameterIndex];
56
- assert.ok(currentExpectedArg, "Expected argument not found.");
57
- const expectedType = typeChecker.getTypeOfSymbol(currentExpectedArg);
58
- const actualType = typeChecker.getTypeAtLocation(parserServices.esTreeNodeToTSNodeMap.get(arg));
59
- log("expected type:", currentExpectedArg.escapedName, typeChecker.typeToString(expectedType));
60
- log("actual type:", sourceCode.getText(arg), typeChecker.typeToString(actualType));
61
- if (typeChecker.isTypeAssignableTo(actualType, expectedType) === true) {
62
- argsToKeep.push(arg);
63
- parameterIndex++;
64
- log("matched");
65
- } else {
66
- log("not matched");
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 (argsToKeep.length === providedArgsCount) {
112
+ if (parametersToKeep.length === actualParametersCount) {
71
113
  return;
72
114
  }
73
- const firstParameter = providedArgs[0];
74
- const lastParameter = providedArgs.at(-1);
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
- argsToKeep.map((arg) => sourceCode.getText(arg)).join(", ")
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,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FnZW50L2ZpeC1mdW5jdGlvbi1jYWxsLWFyZ3VtZW50cy50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFRQSxTQUFTLGFBQWEsZ0JBQWdCO0FBQ3RDLFNBQVMsVUFBVSxjQUFjO0FBQ2pDLE9BQU8sV0FBVztBQUNsQixPQUFPLHlCQUF5QjtBQUNoQyxTQUFTLGlCQUFpQjtBQUVuQixJQUFNLFNBQVM7QUFFdEIsSUFBTSxhQUFhLFlBQVksWUFBWSxDQUFDLFNBQVMsb0JBQW9CLElBQUksQ0FBQztBQUM5RSxJQUFNLE1BQU0sTUFBTSwyQ0FBMkM7QUFFN0QsSUFBTSxPQUFPLFdBQVc7QUFBQSxFQUN0QixNQUFNO0FBQUEsRUFDTixNQUFNO0FBQUEsSUFDSixNQUFNO0FBQUEsSUFDTixNQUFNO0FBQUEsTUFDSixhQUFhO0FBQUEsSUFDZjtBQUFBLElBQ0EsVUFBVTtBQUFBLE1BQ1IscUNBQXFDO0FBQUEsTUFDckMsY0FBYztBQUFBLElBQ2hCO0FBQUEsSUFDQSxTQUFTO0FBQUEsSUFDVCxRQUFRLENBQUM7QUFBQSxFQUNYO0FBQUEsRUFDQSxnQkFBZ0IsQ0FBQztBQUFBLEVBQ2pCLE9BQU8sU0FBUztBQUNkLFVBQU0saUJBQWlCLFlBQVksa0JBQWtCLE9BQU87QUFDNUQsVUFBTSxjQUFjLGVBQWUsUUFBUSxlQUFlO0FBQzFELFVBQU0sYUFBYSxRQUFRO0FBRTNCLFdBQU87QUFBQSxNQUNMLGVBQWUsZ0JBQWdCO0FBRzdCLFlBQUksVUFBVSxjQUFjLEdBQUcsU0FBUyxTQUFTLGVBQWUsa0JBQWtCO0FBQ2hGO0FBQUEsUUFDRjtBQUVBLFlBQUkscUNBQXFDO0FBQ3pDLFlBQUksbUJBQW1CLFdBQVcsUUFBUSxjQUFjLENBQUM7QUFDekQsWUFBSTtBQUNGLGdCQUFNLGVBQWUsZUFBZSxzQkFBc0IsSUFBSSxlQUFlLE1BQU07QUFDbkYsZ0JBQU0sYUFBYSxZQUFZLGtCQUFrQixZQUFZO0FBQzdELGdCQUFNLFlBQVksV0FBVyxrQkFBa0Is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
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
- declare const rule: ESLintUtils.RuleModule<"unknownError" | "removeIncompatibleFunctionArguments", never[], ESLintUtils.RuleListener>;
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;
@@ -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", never[], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
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-e357","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"}}
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 (getParent(callExpression)?.type === TSESTree.AST_NODE_TYPES.MemberExpression) {
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
- const signature = calleeType.getCallSignatures()[0];
54
- if (
55
- !signature ||
56
- // ignore complex signatures
57
- (signature.typeParameters !== undefined && signature.typeParameters.length > 0)
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
- const signatureParameters = signature.getParameters();
63
- const expectedArgsCount = signatureParameters.length; /*?*/
64
- const providedArgs = callExpression.arguments; /*?*/
65
- const providedArgsCount = providedArgs.length; /*?*/
66
- if (providedArgsCount === 0 || providedArgsCount === expectedArgsCount) {
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
- const argsToKeep: TSESTree.CallExpressionArgument[] = [];
70
-
71
- if (expectedArgsCount > 0) {
72
- let parameterIndex = 0;
73
- for (const arg of providedArgs) {
74
- const currentExpectedArg = signatureParameters[parameterIndex];
75
- assert.ok(currentExpectedArg, 'Expected argument not found.');
76
-
77
- const expectedType = typeChecker.getTypeOfSymbol(currentExpectedArg);
78
- const actualType = typeChecker.getTypeAtLocation(parserServices.esTreeNodeToTSNodeMap.get(arg));
79
-
80
- // eslint-disable-next-line no-console
81
- log('expected type:', currentExpectedArg.escapedName, typeChecker.typeToString(expectedType));
82
- // eslint-disable-next-line no-console
83
- log('actual type:', sourceCode.getText(arg), typeChecker.typeToString(actualType));
84
- // @ts-expect-error: internal API
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
- if (typeChecker.isTypeAssignableTo(actualType, expectedType) === true) {
87
- argsToKeep.push(arg);
88
- parameterIndex++;
89
- log('matched');
90
- } else {
91
- log('not matched');
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 (argsToKeep.length === providedArgsCount) {
142
+ if (parametersToKeep.length === actualParametersCount) {
97
143
  return;
98
144
  }
99
145
 
100
- const firstParameter = providedArgs[0];
101
- const lastParameter = providedArgs.at(-1);
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
- argsToKeep.map((arg) => sourceCode.getText(arg)).join(', '),
160
+ parametersToKeep.map((arg) => sourceCode.getText(arg)).join(', '),
115
161
  );
116
162
  },
117
163
  });