@checkdigit/eslint-plugin 7.2.0 → 7.3.0-PR.75-aa6d

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.
Files changed (52) hide show
  1. package/dist-mjs/agent/add-url-domain.mjs +61 -0
  2. package/dist-mjs/agent/agent-test-wiring.mjs +170 -0
  3. package/dist-mjs/agent/fetch-response-body-json.mjs +63 -0
  4. package/dist-mjs/agent/fetch-response-header-getter.mjs +117 -0
  5. package/dist-mjs/agent/fetch-then.mjs +267 -0
  6. package/dist-mjs/agent/fetch.mjs +34 -0
  7. package/dist-mjs/agent/fix-function-call-arguments.mjs +153 -0
  8. package/dist-mjs/agent/no-fixture.mjs +326 -0
  9. package/dist-mjs/agent/no-mapped-response.mjs +75 -0
  10. package/dist-mjs/agent/no-service-wrapper.mjs +183 -0
  11. package/dist-mjs/agent/no-status-code.mjs +59 -0
  12. package/dist-mjs/agent/no-unused-function-argument.mjs +79 -0
  13. package/dist-mjs/agent/no-unused-imports.mjs +81 -0
  14. package/dist-mjs/agent/no-unused-service-variable.mjs +74 -0
  15. package/dist-mjs/agent/response-reference.mjs +56 -0
  16. package/dist-mjs/agent/url.mjs +26 -0
  17. package/dist-mjs/index.mjs +104 -7
  18. package/dist-types/agent/add-url-domain.d.ts +4 -0
  19. package/dist-types/agent/agent-test-wiring.d.ts +4 -0
  20. package/dist-types/agent/fetch-response-body-json.d.ts +4 -0
  21. package/dist-types/agent/fetch-response-header-getter.d.ts +4 -0
  22. package/dist-types/agent/fetch-then.d.ts +4 -0
  23. package/dist-types/agent/fetch.d.ts +4 -0
  24. package/dist-types/agent/fix-function-call-arguments.d.ts +9 -0
  25. package/dist-types/agent/no-fixture.d.ts +4 -0
  26. package/dist-types/agent/no-mapped-response.d.ts +4 -0
  27. package/dist-types/agent/no-service-wrapper.d.ts +4 -0
  28. package/dist-types/agent/no-status-code.d.ts +4 -0
  29. package/dist-types/agent/no-unused-function-argument.d.ts +4 -0
  30. package/dist-types/agent/no-unused-imports.d.ts +4 -0
  31. package/dist-types/agent/no-unused-service-variable.d.ts +4 -0
  32. package/dist-types/agent/response-reference.d.ts +16 -0
  33. package/dist-types/agent/url.d.ts +5 -0
  34. package/dist-types/index.d.ts +4 -2
  35. package/package.json +1 -96
  36. package/src/agent/add-url-domain.ts +76 -0
  37. package/src/agent/agent-test-wiring.ts +204 -0
  38. package/src/agent/fetch-response-body-json.ts +77 -0
  39. package/src/agent/fetch-response-header-getter.ts +148 -0
  40. package/src/agent/fetch-then.ts +355 -0
  41. package/src/agent/fetch.ts +53 -0
  42. package/src/agent/fix-function-call-arguments.ts +184 -0
  43. package/src/agent/no-fixture.ts +455 -0
  44. package/src/agent/no-mapped-response.ts +84 -0
  45. package/src/agent/no-service-wrapper.ts +239 -0
  46. package/src/agent/no-status-code.ts +72 -0
  47. package/src/agent/no-unused-function-argument.ts +98 -0
  48. package/src/agent/no-unused-imports.ts +103 -0
  49. package/src/agent/no-unused-service-variable.ts +93 -0
  50. package/src/agent/response-reference.ts +109 -0
  51. package/src/agent/url.ts +25 -0
  52. package/src/index.ts +105 -6
@@ -0,0 +1,267 @@
1
+ // src/agent/fetch-then.ts
2
+ import { strict as assert } from "node:assert";
3
+ import "eslint";
4
+ import { getEnclosingFunction, getEnclosingStatement, getParent, isUsedInArrayOrAsArgument } from "../library/tree.mjs";
5
+ import getDocumentationUrl from "../get-documentation-url.mjs";
6
+ import { getIndentation } from "../library/format.mjs";
7
+ import { isValidPropertyName } from "../library/variable.mjs";
8
+ import { hasAssertions, isInvalidResponseHeadersAccess } from "./fetch.mjs";
9
+ import { replaceEndpointUrlPrefixWithBasePath } from "./url.mjs";
10
+ var ruleId = "fetch-then";
11
+ function analyzeFixtureCall(call, results, sourceCode) {
12
+ const parent = getParent(call);
13
+ if (!parent) {
14
+ return;
15
+ }
16
+ let nextCall;
17
+ if (parent.type !== "MemberExpression") {
18
+ results.fixtureNode = call;
19
+ return;
20
+ }
21
+ if (parent.property.type === "Identifier") {
22
+ if (parent.property.name === "expect") {
23
+ const assertionCall = getParent(parent);
24
+ assert.ok(assertionCall && assertionCall.type === "CallExpression");
25
+ results.assertions = [...results.assertions ?? [], assertionCall.arguments];
26
+ nextCall = assertionCall;
27
+ } else if (parent.property.name === "send") {
28
+ const sendRequestBodyCall = getParent(parent);
29
+ assert.ok(sendRequestBodyCall && sendRequestBodyCall.type === "CallExpression");
30
+ results.requestBody = sendRequestBodyCall.arguments[0];
31
+ nextCall = sendRequestBodyCall;
32
+ } else if (parent.property.name === "set") {
33
+ const setRequestHeaderCall = getParent(parent);
34
+ assert.ok(setRequestHeaderCall && setRequestHeaderCall.type === "CallExpression");
35
+ const [name, value] = setRequestHeaderCall.arguments;
36
+ results.requestHeaders = [...results.requestHeaders ?? [], { name, value }];
37
+ nextCall = setRequestHeaderCall;
38
+ }
39
+ } else {
40
+ throw new Error(`Unexpected expression in fixture/supertest call ${sourceCode.getText(parent)}.`);
41
+ }
42
+ if (nextCall) {
43
+ analyzeFixtureCall(nextCall, results, sourceCode);
44
+ }
45
+ }
46
+ function createResponseAssertions(fixtureCallInformation, sourceCode, responseVariableName) {
47
+ let statusAssertion;
48
+ const nonStatusAssertions = [];
49
+ for (const expectArguments of fixtureCallInformation.assertions ?? []) {
50
+ if (expectArguments.length === 1) {
51
+ const [assertionArgument] = expectArguments;
52
+ assert.ok(assertionArgument);
53
+ if (assertionArgument.type === "MemberExpression" && assertionArgument.object.type === "Identifier" && assertionArgument.object.name === "StatusCodes" || assertionArgument.type === "Literal" || sourceCode.getText(assertionArgument).includes("StatusCodes.")) {
54
+ statusAssertion = `assert.equal(${responseVariableName}.status, ${sourceCode.getText(assertionArgument)})`;
55
+ } else if (assertionArgument.type === "ArrowFunctionExpression") {
56
+ let functionBody = sourceCode.getText(assertionArgument.body);
57
+ const [originalResponseArgument] = assertionArgument.params;
58
+ assert.ok(originalResponseArgument?.type === "Identifier");
59
+ const originalResponseArgumentName = originalResponseArgument.name;
60
+ if (originalResponseArgumentName !== responseVariableName) {
61
+ functionBody = functionBody.replace(
62
+ new RegExp(`\\b${originalResponseArgumentName}\\b`, "ug"),
63
+ responseVariableName
64
+ );
65
+ }
66
+ nonStatusAssertions.push(`assert.ok(${functionBody})`);
67
+ } else if (assertionArgument.type === "Identifier") {
68
+ nonStatusAssertions.push(`assert.ok(${sourceCode.getText(assertionArgument)}(${responseVariableName}))`);
69
+ } else if (assertionArgument.type === "ObjectExpression" || assertionArgument.type === "CallExpression") {
70
+ nonStatusAssertions.push(
71
+ `assert.deepEqual(await ${responseVariableName}.json(), ${sourceCode.getText(assertionArgument)})`
72
+ );
73
+ } else {
74
+ throw new Error(`Unexpected Supertest assertion argument: ".expect(${sourceCode.getText(assertionArgument)})`);
75
+ }
76
+ } else if (expectArguments.length === 2) {
77
+ const [headerName, headerValue] = expectArguments;
78
+ assert.ok(headerName && headerValue);
79
+ const headersReference = `${responseVariableName}.headers`;
80
+ if (headerValue.type === "Literal" && headerValue.value instanceof RegExp) {
81
+ nonStatusAssertions.push(
82
+ `assert.ok(${headersReference}.get(${sourceCode.getText(headerName)}).match(${sourceCode.getText(headerValue)}))`
83
+ );
84
+ } else {
85
+ nonStatusAssertions.push(
86
+ `assert.equal(${headersReference}.get(${sourceCode.getText(headerName)}), ${sourceCode.getText(headerValue)})`
87
+ );
88
+ }
89
+ }
90
+ }
91
+ return {
92
+ statusAssertion,
93
+ nonStatusAssertions
94
+ };
95
+ }
96
+ function getResponseHeadersAccesses(responseVariables, scopeManager, sourceCode) {
97
+ const responseHeadersAccesses = [];
98
+ for (const responseVariable of responseVariables) {
99
+ for (const responseReference of responseVariable.references) {
100
+ const responseAccess = getParent(responseReference.identifier);
101
+ if (!responseAccess || responseAccess.type !== "MemberExpression") {
102
+ continue;
103
+ }
104
+ const responseAccessParent = getParent(responseAccess);
105
+ if (!responseAccessParent) {
106
+ continue;
107
+ }
108
+ if (responseAccessParent.type === "CallExpression" && responseAccessParent.arguments[0]?.type === "ArrowFunctionExpression") {
109
+ responseHeadersAccesses.push(
110
+ ...getResponseHeadersAccesses(
111
+ scopeManager.getDeclaredVariables(responseAccessParent.arguments[0]),
112
+ scopeManager,
113
+ sourceCode
114
+ )
115
+ );
116
+ continue;
117
+ }
118
+ if (responseAccess.computed && responseAccess.property.type === "Literal" && responseAccessParent.type === "MemberExpression") {
119
+ responseHeadersAccesses.push(responseAccessParent);
120
+ } else {
121
+ responseHeadersAccesses.push(responseAccess);
122
+ }
123
+ }
124
+ }
125
+ return responseHeadersAccesses;
126
+ }
127
+ var rule = {
128
+ meta: {
129
+ type: "suggestion",
130
+ docs: {
131
+ description: "Prefer native fetch API over customized fixture API.",
132
+ url: getDocumentationUrl(ruleId)
133
+ },
134
+ messages: {
135
+ preferNativeFetch: "Prefer native fetch API over customized fixture API.",
136
+ shouldUseHeaderGetter: "Getter should be used to access response headers.",
137
+ unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.'
138
+ },
139
+ fixable: "code",
140
+ schema: []
141
+ },
142
+ create(context) {
143
+ const sourceCode = context.sourceCode;
144
+ const scopeManager = sourceCode.scopeManager;
145
+ return {
146
+ 'CallExpression[callee.object.object.name="fixture"][callee.object.property.name="api"]': (fixtureCall) => {
147
+ try {
148
+ if (!hasAssertions(fixtureCall)) {
149
+ return;
150
+ }
151
+ if (!(isUsedInArrayOrAsArgument(fixtureCall) || getEnclosingFunction(fixtureCall)?.async === false)) {
152
+ return;
153
+ }
154
+ assert.ok(fixtureCall.type === "CallExpression");
155
+ const fixtureFunction = fixtureCall.callee;
156
+ assert.ok(fixtureFunction.type === "MemberExpression");
157
+ const indentation = getIndentation(fixtureCall, sourceCode);
158
+ const [urlArgumentNode] = fixtureCall.arguments;
159
+ assert.ok(urlArgumentNode !== void 0);
160
+ const fixtureCallInformation = {};
161
+ analyzeFixtureCall(fixtureCall, fixtureCallInformation, sourceCode);
162
+ const originalUrlArgumentText = sourceCode.getText(urlArgumentNode);
163
+ const fetchUrlArgumentText = replaceEndpointUrlPrefixWithBasePath(originalUrlArgumentText);
164
+ const methodNode = fixtureFunction.property;
165
+ assert.ok(methodNode.type === "Identifier");
166
+ const fetchRequestArgumentLines = [
167
+ "{",
168
+ ` method: '${methodNode.name.toUpperCase()}',`,
169
+ ...fixtureCallInformation.requestBody ? [` body: JSON.stringify(${sourceCode.getText(fixtureCallInformation.requestBody)}),`] : [],
170
+ ...fixtureCallInformation.requestHeaders ? [
171
+ ` headers: {`,
172
+ ...fixtureCallInformation.requestHeaders.map(
173
+ ({ name, value }) => (
174
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, no-nested-ternary, sonarjs/no-nested-template-literals
175
+ ` ${name.type === "Literal" ? isValidPropertyName(name.value) ? name.value : `'${name.value}'` : `[${sourceCode.getText(name)}]`}: ${sourceCode.getText(value)},`
176
+ )
177
+ ),
178
+ ` },`
179
+ ] : [],
180
+ "}"
181
+ ].join(`
182
+ ${indentation}`);
183
+ const responseVariableNameToUse = "res";
184
+ const { statusAssertion, nonStatusAssertions } = createResponseAssertions(
185
+ fixtureCallInformation,
186
+ sourceCode,
187
+ responseVariableNameToUse
188
+ );
189
+ const disableLintComment = "// eslint-disable-next-line @checkdigit/no-promise-instance-method";
190
+ const fetchCallText = `fetch(${fetchUrlArgumentText}, ${fetchRequestArgumentLines})`;
191
+ const appendingAssignmentAndAssertionText = [
192
+ ...statusAssertion !== void 0 ? [statusAssertion] : [],
193
+ ...nonStatusAssertions
194
+ ].join(`;
195
+ ${indentation}`);
196
+ const replacementText = fixtureCallInformation.assertions ? [
197
+ disableLintComment,
198
+ `${fetchCallText}.then((${responseVariableNameToUse}) => {`,
199
+ appendingAssignmentAndAssertionText === "" ? "" : ` ${appendingAssignmentAndAssertionText};`,
200
+ ` return ${responseVariableNameToUse};`,
201
+ `})`
202
+ ].join(`
203
+ ${indentation}`) : fetchCallText;
204
+ context.report({
205
+ node: fixtureCall,
206
+ messageId: "preferNativeFetch",
207
+ fix(fixer) {
208
+ return fixer.replaceText(fixtureCallInformation.fixtureNode, replacementText);
209
+ }
210
+ });
211
+ const responsesVariable = getEnclosingStatement(fixtureCallInformation.fixtureNode);
212
+ if (!responsesVariable) {
213
+ return;
214
+ }
215
+ const responseVariableReferences = scopeManager.getDeclaredVariables(responsesVariable);
216
+ const responseHeadersAccesses = getResponseHeadersAccesses(
217
+ responseVariableReferences,
218
+ scopeManager,
219
+ sourceCode
220
+ );
221
+ for (const responseHeadersAccess of responseHeadersAccesses) {
222
+ if (isInvalidResponseHeadersAccess(responseHeadersAccess)) {
223
+ const headerAccess = getParent(responseHeadersAccess);
224
+ if (headerAccess?.type === "MemberExpression") {
225
+ const headerNameNode = headerAccess.property;
226
+ const headerName = headerAccess.computed ? sourceCode.getText(headerNameNode) : `'${sourceCode.getText(headerNameNode)}'`;
227
+ const headerAccessReplacementText = `${sourceCode.getText(headerAccess.object)}.get(${headerName})`;
228
+ context.report({
229
+ node: headerAccess,
230
+ messageId: "shouldUseHeaderGetter",
231
+ fix(fixer) {
232
+ return fixer.replaceText(headerAccess, headerAccessReplacementText);
233
+ }
234
+ });
235
+ } else if (headerAccess?.type === "CallExpression" && responseHeadersAccess.property.type === "Identifier" && responseHeadersAccess.property.name === "get") {
236
+ const headerAccessReplacementText = `${sourceCode.getText(responseHeadersAccess.object)}.headers.get(${sourceCode.getText(headerAccess.arguments[0])})`;
237
+ context.report({
238
+ node: headerAccess,
239
+ messageId: "shouldUseHeaderGetter",
240
+ fix(fixer) {
241
+ return fixer.replaceText(headerAccess, headerAccessReplacementText);
242
+ }
243
+ });
244
+ }
245
+ }
246
+ }
247
+ } catch (error) {
248
+ console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
249
+ context.report({
250
+ node: fixtureCall,
251
+ messageId: "unknownError",
252
+ data: {
253
+ fileName: context.filename,
254
+ error: error instanceof Error ? error.toString() : JSON.stringify(error)
255
+ }
256
+ });
257
+ }
258
+ }
259
+ };
260
+ }
261
+ };
262
+ var fetch_then_default = rule;
263
+ export {
264
+ fetch_then_default as default,
265
+ ruleId
266
+ };
267
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FnZW50L2ZldGNoLXRoZW4udHMiXSwKICAibWFwcGluZ3MiOiAiO0FBUUEsU0FBUyxVQUFVLGNBQWM7QUFHakMsT0FBa0Q7QUFFbEQsU0FBUyxzQkFBc0IsdUJBQXVCLFdBQVcsaUNBQWlDO0FBQ2xHLE9BQU8seUJBQXlCO0FBQ2hDLFNBQVMsc0JBQXNCO0FBQy9CLFNBQVMsMkJBQTJCO0FBQ3BDLFNBQVMsZUFBZSxzQ0FBc0M7QUFDOUQsU0FBUyw0Q0FBNEM7QUFFOUMsSUFBTSxTQUFTO0FBVXRCLFNBQVMsbUJBQW1CLE1BQTRCLFNBQWlDLFlBQXdCO0FBQy9HLFFBQU0sU0FBUyxVQUFVLElBQUk7QUFDN0IsTUFBSSxDQUFDLFFBQVE7QUFDWDtBQUFBLEVBQ0Y7QUFFQSxNQUFJO0FBQ0osTUFBSSxPQUFPLFNBQVMsb0JBQW9CO0FBQ3RDLFlBQVEsY0FBYztBQUN0QjtBQUFBLEVBQ0Y7QUFFQSxNQUFJLE9BQU8sU0FBUyxTQUFTLGNBQWM7QUFDekMsUUFBSSxPQUFPLFNBQVMsU0FBUyxVQUFVO0FBRXJDLFlBQU0sZ0JBQWdCLFVBQVUsTUFBTTtBQUN0QyxhQUFPLEdBQUcsaUJBQWlCLGNBQWMsU0FBUyxnQkFBZ0I7QUFDbEUsY0FBUSxhQUFhLENBQUMsR0FBSSxRQUFRLGNBQWMsQ0FBQyxHQUFJLGNBQWMsU0FBeUI7QUFDNUYsaUJBQVc7QUFBQSxJQUNiLFdBQVcsT0FBTyxTQUFTLFNBQVMsUUFBUTtBQUUxQyxZQUFNLHNCQUFzQixVQUFVLE1BQU07QUFDNUMsYUFBTyxHQUFHLHVCQUF1QixvQkFBb0IsU0FBUyxnQkFBZ0I7QUFDOUUsY0FBUSxjQUFjLG9CQUFvQixVQUFVLENBQUM7QUFDckQsaUJBQVc7QUFBQSxJQUNiLFdBQVcsT0FBTyxTQUFTLFNBQVMsT0FBTztBQUV6QyxZQUFNLHVCQUF1QixVQUFVLE1BQU07QUFDN0MsYUFBTyxHQUFHLHdCQUF3QixxQkFBcUIsU0FBUyxnQkFBZ0I7QUFDaEYsWUFBTSxDQUFDLE1B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
@@ -0,0 +1,34 @@
1
+ // src/agent/fetch.ts
2
+ import { getParent, isBlockStatement } from "../library/tree.mjs";
3
+ function getResponseBodyRetrievalText(responseVariableName) {
4
+ return `await ${responseVariableName}.json()`;
5
+ }
6
+ function isInvalidResponseHeadersAccess(responseHeadersAccess) {
7
+ const responseHeaderAccessParent = getParent(responseHeadersAccess);
8
+ if (responseHeaderAccessParent?.type === "VariableDeclarator") {
9
+ return false;
10
+ }
11
+ if (responseHeaderAccessParent?.type === "CallExpression" && responseHeaderAccessParent.callee.type === "MemberExpression" && responseHeaderAccessParent.callee.property.type === "Identifier" && responseHeaderAccessParent.callee.property.name === "get") {
12
+ return true;
13
+ }
14
+ return !(responseHeaderAccessParent?.type === "MemberExpression" && responseHeaderAccessParent.property.type === "Identifier" && responseHeaderAccessParent.property.name === "get");
15
+ }
16
+ function hasAssertions(fixtureCall) {
17
+ if (isBlockStatement(fixtureCall)) {
18
+ return false;
19
+ }
20
+ const parent = getParent(fixtureCall);
21
+ if (!parent) {
22
+ return false;
23
+ }
24
+ if (parent.type === "MemberExpression" && parent.property.type === "Identifier" && parent.property.name === "expect" && getParent(parent)?.type === "CallExpression") {
25
+ return true;
26
+ }
27
+ return hasAssertions(parent);
28
+ }
29
+ export {
30
+ getResponseBodyRetrievalText,
31
+ hasAssertions,
32
+ isInvalidResponseHeadersAccess
33
+ };
34
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FnZW50L2ZldGNoLnRzIl0sCiAgIm1hcHBpbmdzIjogIjtBQUlBLFNBQVMsV0FBVyx3QkFBd0I7QUFFckMsU0FBUyw2QkFBNkIsc0JBQThCO0FBQ3pFLFNBQU8sU0FBUyxvQkFBb0I7QUFDdEM7QUFFTyxTQUFTLCtCQUErQix1QkFBc0M7QUFDbkYsUUFBTSw2QkFBNkIsVUFBVSxxQkFBcUI7QUFDbEUsTUFBSSw0QkFBNEIsU0FBUyxzQkFBc0I7QUFDN0QsV0FBTztBQUFBLEVBQ1Q7QUFFQSxNQUNFLDRCQUE0QixTQUFTLG9CQUNyQywyQkFBMkIsT0FBTyxTQUFTLHNCQUMzQywyQkFBMkIsT0FBTyxTQUFTLFNBQVMsZ0JBQ3BELDJCQUEyQixPQUFPLFNBQVMsU0FBUyxPQUNwRDtBQUNBLFdBQU87QUFBQSxFQUNUO0FBRUEsU0FBTyxFQUNMLDRCQUE0QixTQUFTLHNCQUNyQywyQkFBMkIsU0FBUyxTQUFTLGdCQUM3QywyQkFBMkIsU0FBUyxTQUFTO0FBRWpEO0FBRU8sU0FBUyxjQUFjLGFBQTRCO0FBQ3hELE1BQUksaUJBQWlCLFdBQVcsR0FBRztBQUNqQyxXQUFPO0FBQUEsRUFDVDtBQUVBLFFBQU0sU0FBUyxVQUFVLFdBQVc7QUFDcEMsTUFBSSxDQUFDLFFBQVE7QUFDWCxXQUFPO0FBQUEsRUFDVDtBQUVBLE1BQ0UsT0FBTyxTQUFTLHNCQUNoQixPQUFPLFNBQVMsU0FBUyxnQkFDekIsT0FBTyxTQUFTLFNBQVMsWUFDekIsVUFBVSxNQUFNLEdBQUcsU0FBUyxrQkFDNUI7QUFDQSxXQUFPO0FBQUEsRUFDVDtBQUVBLFNBQU8sY0FBYyxNQUFNO0FBQzdCOyIsCiAgIm5hbWVzIjogW10KfQo=
@@ -0,0 +1,153 @@
1
+ // src/agent/fix-function-call-arguments.ts
2
+ import { strict as assert } from "node:assert";
3
+ import { ESLintUtils, TSESTree } from "@typescript-eslint/utils";
4
+ import debug from "debug";
5
+ import getDocumentationUrl from "../get-documentation-url.mjs";
6
+ var ruleId = "fix-function-call-arguments";
7
+ var DEFAULT_OPTIONS = {
8
+ typesToCheck: [
9
+ "Configuration<ResolvedServices>",
10
+ "Fixture<ResolvedServices>",
11
+ "InboundContext",
12
+ "{ get: () => string; }"
13
+ ]
14
+ };
15
+ var createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
16
+ var log = debug("eslint-plugin:fix-function-call-arguments");
17
+ var rule = createRule({
18
+ name: ruleId,
19
+ meta: {
20
+ type: "suggestion",
21
+ docs: {
22
+ description: "Remove incompatible function arguments."
23
+ },
24
+ messages: {
25
+ removeIncompatibleFunctionArguments: "Removing incompatible function arguments.",
26
+ unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.'
27
+ },
28
+ fixable: "code",
29
+ schema: [
30
+ {
31
+ type: "object",
32
+ properties: {
33
+ typesToCheck: {
34
+ description: "Text representation of the types of which the function call parameters will be examine",
35
+ type: "array",
36
+ items: {
37
+ type: "string"
38
+ }
39
+ }
40
+ },
41
+ additionalProperties: false
42
+ }
43
+ ]
44
+ },
45
+ defaultOptions: [DEFAULT_OPTIONS],
46
+ create(context) {
47
+ const { typesToCheck } = context.options[0];
48
+ const parserServices = ESLintUtils.getParserServices(context);
49
+ const typeChecker = parserServices.program.getTypeChecker();
50
+ const sourceCode = context.sourceCode;
51
+ return {
52
+ CallExpression(callExpression) {
53
+ if (callExpression.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression) {
54
+ return;
55
+ }
56
+ log("===== file name:", context.filename);
57
+ log("callExpression:", sourceCode.getText(callExpression));
58
+ try {
59
+ const calleeTsNode = parserServices.esTreeNodeToTSNodeMap.get(callExpression.callee);
60
+ const calleeType = typeChecker.getTypeAtLocation(calleeTsNode);
61
+ const signatures = calleeType.getCallSignatures();
62
+ if (signatures.length > 1) {
63
+ return;
64
+ }
65
+ const signature = signatures[0];
66
+ assert.ok(signature, "Signature not found.");
67
+ if (signature.typeParameters !== void 0 && signature.typeParameters.length > 0) {
68
+ return;
69
+ }
70
+ log("signature:", signature.getDeclaration().getText());
71
+ const expectedParameters = signature.getParameters();
72
+ log(
73
+ "expected parameters:",
74
+ expectedParameters.map(
75
+ (expectedParameter) => typeChecker.typeToString(typeChecker.getTypeOfSymbol(expectedParameter))
76
+ )
77
+ );
78
+ const expectedParametersCount = expectedParameters.length;
79
+ const actualParameters = callExpression.arguments;
80
+ const actualParametersCount = actualParameters.length;
81
+ if (actualParametersCount === 0 || actualParametersCount === expectedParametersCount) {
82
+ return;
83
+ }
84
+ const parametersToKeep = [];
85
+ let expectedParameterIndex = 0;
86
+ for (const [actualParameterIndex, actualParameter] of actualParameters.entries()) {
87
+ if (expectedParameterIndex >= expectedParametersCount) {
88
+ break;
89
+ }
90
+ const expectedParameter = expectedParameters[expectedParameterIndex];
91
+ assert.ok(expectedParameter, "Expected parameter not found.");
92
+ const expectedType = typeChecker.getTypeOfSymbol(expectedParameter);
93
+ const actualType = typeChecker.getTypeAtLocation(parserServices.esTreeNodeToTSNodeMap.get(actualParameter));
94
+ const actualTypeString = typeChecker.typeToString(actualType);
95
+ log(
96
+ "expected type: #",
97
+ expectedParameterIndex,
98
+ expectedParameter.escapedName,
99
+ typeChecker.typeToString(expectedType)
100
+ );
101
+ log("actual type: #", actualParameterIndex, sourceCode.getText(actualParameter), actualTypeString);
102
+ if (!typesToCheck.includes(actualTypeString) && !actualTypeString.endsWith("RequestType")) {
103
+ parametersToKeep.push(actualParameter);
104
+ log("skipped");
105
+ } else if (typeChecker.isTypeAssignableTo(actualType, expectedType)) {
106
+ parametersToKeep.push(actualParameter);
107
+ log("matched");
108
+ expectedParameterIndex++;
109
+ } else {
110
+ log("not matched");
111
+ }
112
+ }
113
+ if (parametersToKeep.length === actualParametersCount) {
114
+ return;
115
+ }
116
+ const firstParameter = actualParameters[0];
117
+ const lastParameter = actualParameters.at(-1);
118
+ assert.ok(firstParameter !== void 0 && lastParameter !== void 0);
119
+ const tokenAfterParameters = sourceCode.getTokenAfter(lastParameter);
120
+ context.report({
121
+ node: callExpression,
122
+ messageId: "removeIncompatibleFunctionArguments",
123
+ fix(fixer) {
124
+ return fixer.replaceTextRange(
125
+ [
126
+ firstParameter.range[0],
127
+ tokenAfterParameters?.value === "," ? tokenAfterParameters.range[1] : lastParameter.range[1]
128
+ ],
129
+ parametersToKeep.map((arg) => sourceCode.getText(arg)).join(", ")
130
+ );
131
+ }
132
+ });
133
+ } catch (error) {
134
+ console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
135
+ context.report({
136
+ node: callExpression,
137
+ messageId: "unknownError",
138
+ data: {
139
+ fileName: context.filename,
140
+ error: error instanceof Error ? error.toString() : JSON.stringify(error)
141
+ }
142
+ });
143
+ }
144
+ }
145
+ };
146
+ }
147
+ });
148
+ var fix_function_call_arguments_default = rule;
149
+ export {
150
+ fix_function_call_arguments_default as default,
151
+ ruleId
152
+ };
153
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FnZW50L2ZpeC1mdW5jdGlvbi1jYWxsLWFyZ3VtZW50cy50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFRQSxTQUFTLFVBQVUsY0FBYztBQUNqQyxTQUFTLGFBQWEsZ0JBQWdCO0FBQ3RDLE9BQU8sV0FBVztBQUNsQixPQUFPLHlCQUF5QjtBQUV6QixJQUFNLFNBQVM7QUFLdEIsSUFBTSxrQkFBa0I7QUFBQSxFQUN0QixjQUFjO0FBQUEsSUFDWjtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLEVBQ0Y7QUFDRjtBQUVBLElBQU0sYUFBYSxZQUFZLFlBQVksQ0FBQyxTQUFTLG9CQUFvQixJQUFJLENBQUM7QUFDOUUsSUFBTSxNQUFNLE1BQU0sMkNBQTJDO0FBRTdELElBQU0sT0FHRixXQUFXO0FBQUEsRUFDYixNQUFNO0FBQUEsRUFDTixNQUFNO0FBQUEsSUFDSixNQUFNO0FBQUEsSUFDTixNQUFNO0FBQUEsTUFDSixhQUFhO0FBQUEsSUFDZjtBQUFBLElBQ0EsVUFBVTtBQUFBLE1BQ1IscUNBQXFDO0FBQUEsTUFDckMsY0FBYztBQUFBLElBQ2hCO0FBQUEsSUFDQSxTQUFTO0FBQUEsSUFDVCxRQUFRO0FBQUEsTUFDTjtBQUFBLFFBQ0UsTUFBTTtBQUFBLFFBQ04sWUFBWTtBQUFBLFVBQ1YsY0FBYztBQUFBLFlBQ1osYUFBYTtBQUFBLFlBQ2IsTUFBTTtBQUFBLFlBQ04sT0FBTztBQUFBLGNBQ0wsTUFBTTtBQUFBLFlBQ1I7QUFBQSxVQUNGO0FBQUEsUUFDRjtBQUFBLFFBQ0Esc0JBQXNCO0FBQUEsTUFDeEI7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUFBLEVBQ0EsZ0JBQWdCLENBQUMsZUFBZTtBQUFBLEVBQ2hDLE9BQU8sU0FBUztBQUNkLFVBQU0sRUFBRSxhQUFhLElBQUksUUFBUSxRQUFRLENBQUM7QUFDMUMsVUFBTSxpQkFBaUIsWUFBWSxrQkFBa0IsT0FBTztBQUM1RCxVQUFNLGNBQWMsZUFBZSxRQUFRLGVB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