@checkdigit/eslint-plugin 6.6.0-PR.75-0fc6 → 6.6.0-PR.77-885a

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 (64) hide show
  1. package/dist-cjs/index.cjs +779 -2464
  2. package/dist-cjs/metafile.json +203 -795
  3. package/dist-mjs/index.mjs +3 -77
  4. package/dist-mjs/require-resolve-full-response.mjs +5 -2
  5. package/dist-types/index.d.ts +1 -51
  6. package/dist-types/require-resolve-full-response.d.ts +3 -1
  7. package/package.json +1 -1
  8. package/src/index.ts +0 -74
  9. package/src/library/format.ts +1 -1
  10. package/src/library/tree.ts +1 -1
  11. package/src/library/ts-tree.ts +1 -1
  12. package/src/library/variable.ts +1 -1
  13. package/src/require-resolve-full-response.ts +2 -1
  14. package/dist-mjs/agent/add-url-domain.mjs +0 -61
  15. package/dist-mjs/agent/fetch-response-body-json.mjs +0 -63
  16. package/dist-mjs/agent/fetch-response-header-getter.mjs +0 -117
  17. package/dist-mjs/agent/fetch-then.mjs +0 -269
  18. package/dist-mjs/agent/fetch.mjs +0 -34
  19. package/dist-mjs/agent/no-fixture.mjs +0 -328
  20. package/dist-mjs/agent/no-full-response.mjs +0 -67
  21. package/dist-mjs/agent/no-mapped-response.mjs +0 -75
  22. package/dist-mjs/agent/no-service-wrapper.mjs +0 -184
  23. package/dist-mjs/agent/no-status-code.mjs +0 -59
  24. package/dist-mjs/agent/no-unused-function-argument.mjs +0 -79
  25. package/dist-mjs/agent/no-unused-service-variable.mjs +0 -75
  26. package/dist-mjs/agent/response-reference.mjs +0 -56
  27. package/dist-mjs/agent/url.mjs +0 -26
  28. package/dist-mjs/no-duplicated-imports.mjs +0 -87
  29. package/dist-mjs/require-fixed-services-import.mjs +0 -46
  30. package/dist-mjs/require-type-out-of-type-only-imports.mjs +0 -48
  31. package/dist-types/agent/add-url-domain.d.ts +0 -4
  32. package/dist-types/agent/fetch-response-body-json.d.ts +0 -4
  33. package/dist-types/agent/fetch-response-header-getter.d.ts +0 -4
  34. package/dist-types/agent/fetch-then.d.ts +0 -4
  35. package/dist-types/agent/fetch.d.ts +0 -4
  36. package/dist-types/agent/no-fixture.d.ts +0 -4
  37. package/dist-types/agent/no-full-response.d.ts +0 -4
  38. package/dist-types/agent/no-mapped-response.d.ts +0 -4
  39. package/dist-types/agent/no-service-wrapper.d.ts +0 -4
  40. package/dist-types/agent/no-status-code.d.ts +0 -4
  41. package/dist-types/agent/no-unused-function-argument.d.ts +0 -4
  42. package/dist-types/agent/no-unused-service-variable.d.ts +0 -4
  43. package/dist-types/agent/response-reference.d.ts +0 -16
  44. package/dist-types/agent/url.d.ts +0 -5
  45. package/dist-types/no-duplicated-imports.d.ts +0 -4
  46. package/dist-types/require-fixed-services-import.d.ts +0 -4
  47. package/dist-types/require-type-out-of-type-only-imports.d.ts +0 -4
  48. package/src/agent/add-url-domain.ts +0 -75
  49. package/src/agent/fetch-response-body-json.ts +0 -76
  50. package/src/agent/fetch-response-header-getter.ts +0 -148
  51. package/src/agent/fetch-then.ts +0 -354
  52. package/src/agent/fetch.ts +0 -52
  53. package/src/agent/no-fixture.ts +0 -453
  54. package/src/agent/no-full-response.ts +0 -75
  55. package/src/agent/no-mapped-response.ts +0 -84
  56. package/src/agent/no-service-wrapper.ts +0 -238
  57. package/src/agent/no-status-code.ts +0 -71
  58. package/src/agent/no-unused-function-argument.ts +0 -96
  59. package/src/agent/no-unused-service-variable.ts +0 -92
  60. package/src/agent/response-reference.ts +0 -100
  61. package/src/agent/url.ts +0 -23
  62. package/src/no-duplicated-imports.ts +0 -116
  63. package/src/require-fixed-services-import.ts +0 -52
  64. package/src/require-type-out-of-type-only-imports.ts +0 -63
@@ -1,453 +0,0 @@
1
- // agent/no-fixture.ts
2
-
3
- /*
4
- * Copyright (c) 2021-2024 Check Digit, LLC
5
- *
6
- * This code is licensed under the MIT license (see LICENSE.txt for details).
7
- */
8
-
9
- import type {
10
- AwaitExpression,
11
- CallExpression,
12
- Expression,
13
- MemberExpression,
14
- Node,
15
- ReturnStatement,
16
- SimpleCallExpression,
17
- VariableDeclaration,
18
- } from 'estree';
19
- import { type Rule, type Scope, SourceCode } from 'eslint';
20
- import {
21
- getEnclosingFunction,
22
- getEnclosingScopeNode,
23
- getEnclosingStatement,
24
- getParent,
25
- isUsedInArrayOrAsArgument,
26
- } from '../library/tree';
27
- import { getResponseBodyRetrievalText, hasAssertions } from './fetch';
28
- import { analyzeResponseReferences } from './response-reference';
29
- import { strict as assert } from 'node:assert';
30
- import getDocumentationUrl from '../get-documentation-url';
31
- import { getIndentation } from '../library/format';
32
- import { isValidPropertyName } from '../library/variable';
33
- import { replaceEndpointUrlPrefixWithBasePath } from './url';
34
-
35
- export const ruleId = 'no-fixture';
36
-
37
- interface FixtureCallInformation {
38
- rootNode: AwaitExpression | ReturnStatement | VariableDeclaration | SimpleCallExpression;
39
- fixtureNode: AwaitExpression | SimpleCallExpression;
40
- variableDeclaration?: VariableDeclaration;
41
- requestBody?: Expression;
42
- requestHeaders?: { name: Expression; value: Expression }[];
43
- assertions?: Expression[][];
44
- inlineStatementNode?: Node;
45
- inlineBodyReference?: MemberExpression;
46
- }
47
-
48
- // recursively analyze the fixture/supertest call chain to collect information of request/response
49
- // eslint-disable-next-line sonarjs/cognitive-complexity
50
- function analyzeFixtureCall(call: SimpleCallExpression, results: FixtureCallInformation, sourceCode: SourceCode) {
51
- const parent = getParent(call);
52
- assert.ok(parent, 'parent should exist for fixture/supertest call node');
53
-
54
- let nextCall;
55
- if (parent.type === 'ReturnStatement') {
56
- // direct return, no variable declaration or await
57
- results.fixtureNode = call;
58
- results.rootNode = parent;
59
- } else if (parent.type === 'ArrayExpression' || parent.type === 'CallExpression') {
60
- // direct return, no variable declaration or await
61
- results.fixtureNode = call;
62
- results.rootNode = call;
63
- } else if (parent.type === 'AwaitExpression') {
64
- results.fixtureNode = call;
65
- const enclosingStatement = getEnclosingStatement(parent);
66
- assert.ok(enclosingStatement);
67
- const awaitParent = getParent(parent);
68
- if (awaitParent?.type === 'MemberExpression') {
69
- results.rootNode = parent;
70
- results.inlineStatementNode = enclosingStatement;
71
- if (awaitParent.property.type === 'Identifier' && awaitParent.property.name === 'body') {
72
- results.inlineBodyReference = awaitParent;
73
- }
74
- } else if (enclosingStatement.type === 'VariableDeclaration') {
75
- results.variableDeclaration = enclosingStatement;
76
- results.rootNode = enclosingStatement;
77
- } else {
78
- results.rootNode = parent;
79
- }
80
- } else if (parent.type === 'MemberExpression' && parent.property.type === 'Identifier') {
81
- if (parent.property.name === 'expect') {
82
- // supertest assertions
83
- const assertionCall = getParent(parent);
84
- assert.ok(assertionCall && assertionCall.type === 'CallExpression');
85
- results.assertions = [...(results.assertions ?? []), assertionCall.arguments as Expression[]];
86
- nextCall = assertionCall;
87
- } else if (parent.property.name === 'send') {
88
- // request body
89
- const sendRequestBodyCall = getParent(parent);
90
- assert.ok(sendRequestBodyCall && sendRequestBodyCall.type === 'CallExpression');
91
- results.requestBody = sendRequestBodyCall.arguments[0] as Expression;
92
- nextCall = sendRequestBodyCall;
93
- } else if (parent.property.name === 'set') {
94
- // request headers
95
- const setRequestHeaderCall = getParent(parent);
96
- assert.ok(setRequestHeaderCall && setRequestHeaderCall.type === 'CallExpression');
97
- const [name, value] = setRequestHeaderCall.arguments as [Expression, Expression];
98
- results.requestHeaders = [...(results.requestHeaders ?? []), { name, value }];
99
- nextCall = setRequestHeaderCall;
100
- }
101
- } else {
102
- throw new Error(`Unexpected expression in fixture/supertest call ${sourceCode.getText(parent)}.`);
103
- }
104
- if (nextCall) {
105
- analyzeFixtureCall(nextCall, results, sourceCode);
106
- }
107
- }
108
-
109
- // eslint-disable-next-line sonarjs/cognitive-complexity
110
- function createResponseAssertions(
111
- fixtureCallInformation: FixtureCallInformation,
112
- sourceCode: SourceCode,
113
- responseVariableName: string,
114
- destructuringResponseHeadersVariable: Scope.Variable | undefined,
115
- ) {
116
- let statusAssertion: string | undefined;
117
- const nonStatusAssertions: string[] = [];
118
- for (const expectArguments of fixtureCallInformation.assertions ?? []) {
119
- if (expectArguments.length === 1) {
120
- const [assertionArgument] = expectArguments;
121
- assert.ok(assertionArgument);
122
- if (
123
- (assertionArgument.type === 'MemberExpression' &&
124
- assertionArgument.object.type === 'Identifier' &&
125
- assertionArgument.object.name === 'StatusCodes') ||
126
- assertionArgument.type === 'Literal' ||
127
- sourceCode.getText(assertionArgument).includes('StatusCodes.')
128
- ) {
129
- // status code assertion
130
- statusAssertion = `assert.equal(${responseVariableName}.status, ${sourceCode.getText(assertionArgument)})`;
131
- } else if (assertionArgument.type === 'ArrowFunctionExpression') {
132
- // callback assertion using arrow function
133
- let functionBody = sourceCode.getText(assertionArgument.body);
134
-
135
- const [originalResponseArgument] = assertionArgument.params;
136
- assert.ok(originalResponseArgument?.type === 'Identifier');
137
- const originalResponseArgumentName = originalResponseArgument.name;
138
- if (originalResponseArgumentName !== responseVariableName) {
139
- functionBody = functionBody.replace(
140
- new RegExp(`\\b${originalResponseArgumentName}\\b`, 'ug'),
141
- responseVariableName,
142
- );
143
- }
144
- nonStatusAssertions.push(`assert.ok(${functionBody})`);
145
- } else if (assertionArgument.type === 'Identifier') {
146
- // callback assertion using function reference
147
- nonStatusAssertions.push(`assert.ok(${sourceCode.getText(assertionArgument)}(${responseVariableName}))`);
148
- } else if (assertionArgument.type === 'ObjectExpression' || assertionArgument.type === 'CallExpression') {
149
- // body deep equal assertion
150
- nonStatusAssertions.push(
151
- `assert.deepEqual(await ${responseVariableName}.json(), ${sourceCode.getText(assertionArgument)})`,
152
- );
153
- } else {
154
- throw new Error(`Unexpected Supertest assertion argument: ".expect(${sourceCode.getText(assertionArgument)})`);
155
- }
156
- } else if (expectArguments.length === 2) {
157
- // header assertion
158
- const [headerName, headerValue] = expectArguments;
159
- assert.ok(headerName && headerValue);
160
- const headersReference =
161
- destructuringResponseHeadersVariable !== undefined
162
- ? destructuringResponseHeadersVariable.name
163
- : `${responseVariableName}.headers`;
164
- if (headerValue.type === 'Literal' && headerValue.value instanceof RegExp) {
165
- nonStatusAssertions.push(
166
- `assert.ok(${headersReference}.get(${sourceCode.getText(headerName)}).match(${sourceCode.getText(headerValue)}))`,
167
- );
168
- } else {
169
- nonStatusAssertions.push(
170
- `assert.equal(${headersReference}.get(${sourceCode.getText(headerName)}), ${sourceCode.getText(headerValue)})`,
171
- );
172
- }
173
- }
174
- }
175
- return {
176
- statusAssertion,
177
- nonStatusAssertions,
178
- };
179
- }
180
-
181
- function getResponseVariableNameToUse(
182
- scopeManager: Scope.ScopeManager,
183
- fixtureCallInformation: FixtureCallInformation,
184
- scopeVariablesMap: Map<Scope.Scope, string[]>,
185
- ) {
186
- if (fixtureCallInformation.variableDeclaration) {
187
- const firstDeclaration = fixtureCallInformation.variableDeclaration.declarations[0];
188
- if (firstDeclaration && firstDeclaration.id.type === 'Identifier') {
189
- return firstDeclaration.id.name;
190
- }
191
- }
192
-
193
- const enclosingScopeNode = getEnclosingScopeNode(fixtureCallInformation.rootNode);
194
- scopeManager.getDeclaredVariables(fixtureCallInformation.rootNode);
195
- assert.ok(enclosingScopeNode);
196
- const scope = scopeManager.acquire(enclosingScopeNode);
197
- assert.ok(scope !== null);
198
- let scopeVariables = scopeVariablesMap.get(scope);
199
- if (!scopeVariables) {
200
- scopeVariables = [...scope.set.keys()];
201
- scopeVariablesMap.set(scope, scopeVariables);
202
- }
203
-
204
- let responseVariableCounter = 0;
205
- let responseVariableNameToUse;
206
- while (responseVariableNameToUse === undefined) {
207
- responseVariableCounter++;
208
- responseVariableNameToUse = `response${responseVariableCounter === 1 ? '' : responseVariableCounter.toString()}`;
209
- if (scopeVariables.includes(responseVariableNameToUse)) {
210
- responseVariableNameToUse = undefined;
211
- }
212
- }
213
- scopeVariables.push(responseVariableNameToUse);
214
- return responseVariableNameToUse;
215
- }
216
-
217
- function isResponseBodyRedefinition(responseBodyReference: MemberExpression): boolean {
218
- const parent = getParent(responseBodyReference);
219
- return parent?.type === 'VariableDeclarator' && parent.id.type === 'Identifier';
220
- }
221
-
222
- const rule: Rule.RuleModule = {
223
- meta: {
224
- type: 'suggestion',
225
- docs: {
226
- description: 'Prefer native fetch API over customized fixture API.',
227
- url: getDocumentationUrl(ruleId),
228
- },
229
- messages: {
230
- preferNativeFetch: 'Prefer native fetch API over customized fixture API.',
231
- unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.',
232
- },
233
- fixable: 'code',
234
- schema: [],
235
- },
236
- // eslint-disable-next-line max-lines-per-function
237
- create(context) {
238
- const sourceCode = context.sourceCode;
239
- const scopeManager = sourceCode.scopeManager;
240
- const scopeVariablesMap = new Map<Scope.Scope, string[]>();
241
-
242
- return {
243
- // eslint-disable-next-line max-lines-per-function
244
- 'CallExpression[callee.object.object.name="fixture"][callee.object.property.name="api"]': (
245
- fixtureCall: CallExpression,
246
- ) => {
247
- try {
248
- if (
249
- hasAssertions(fixtureCall) &&
250
- (isUsedInArrayOrAsArgument(fixtureCall) || getEnclosingFunction(fixtureCall)?.async === false)
251
- ) {
252
- // skip and leave it to "fetch-then" rule to handle it because no "await" can be used here
253
- return;
254
- }
255
-
256
- assert.ok(fixtureCall.type === 'CallExpression');
257
- const fixtureFunction = fixtureCall.callee; // e.g. fixture.api.get
258
- assert.ok(fixtureFunction.type === 'MemberExpression');
259
- const indentation = getIndentation(fixtureCall, sourceCode);
260
-
261
- const [urlArgumentNode] = fixtureCall.arguments; // e.g. `/sample-service/v1/ping`
262
- assert.ok(urlArgumentNode !== undefined);
263
-
264
- const fixtureCallInformation = {} as FixtureCallInformation;
265
- analyzeFixtureCall(fixtureCall, fixtureCallInformation, sourceCode);
266
-
267
- const {
268
- variable: responseVariable,
269
- bodyReferences: responseBodyReferences,
270
- headersReferences: responseHeadersReferences,
271
- statusReferences: responseStatusReferences,
272
- destructuringBodyVariable: destructuringResponseBodyVariable,
273
- destructuringHeadersVariable: destructuringResponseHeadersVariable,
274
- } = analyzeResponseReferences(fixtureCallInformation.variableDeclaration, scopeManager);
275
-
276
- // convert url from `/sample-service/v1/ping` to `${BASE_PATH}/ping`
277
- const originalUrlArgumentText = sourceCode.getText(urlArgumentNode);
278
- const fetchUrlArgumentText = replaceEndpointUrlPrefixWithBasePath(originalUrlArgumentText);
279
-
280
- // fetch request argument
281
- const methodNode = fixtureFunction.property; // get/put/etc.
282
- assert.ok(methodNode.type === 'Identifier');
283
- const methodName = methodNode.name.toUpperCase();
284
-
285
- const fetchRequestArgumentLines = [
286
- '{',
287
- ` method: '${methodName === 'DEL' ? 'DELETE' : methodName}',`,
288
- ...(fixtureCallInformation.requestBody
289
- ? [` body: JSON.stringify(${sourceCode.getText(fixtureCallInformation.requestBody)}),`]
290
- : []),
291
- ...(fixtureCallInformation.requestHeaders
292
- ? [
293
- ` headers: {`,
294
- ...fixtureCallInformation.requestHeaders.map(
295
- ({ name, value }) =>
296
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, no-nested-ternary, sonarjs/no-nested-template-literals
297
- ` ${name.type === 'Literal' ? (isValidPropertyName(name.value) ? name.value : `'${name.value}'`) : `[${sourceCode.getText(name)}]`}: ${sourceCode.getText(value)},`,
298
- ),
299
- ` },`,
300
- ]
301
- : []),
302
- '}',
303
- ].join(`\n${indentation}`);
304
-
305
- const responseVariableNameToUse = getResponseVariableNameToUse(
306
- scopeManager,
307
- fixtureCallInformation,
308
- scopeVariablesMap,
309
- );
310
-
311
- const isResponseBodyVariableRedefinitionNeeded =
312
- destructuringResponseBodyVariable !== undefined ||
313
- fixtureCallInformation.inlineBodyReference !== undefined ||
314
- (responseBodyReferences.length > 0 && !responseBodyReferences.some(isResponseBodyRedefinition));
315
- const redefineResponseBodyVariableName = `${responseVariableNameToUse}Body`;
316
-
317
- const isResponseVariableRedefinitionNeeded =
318
- (responseVariable === undefined && fixtureCallInformation.assertions !== undefined) ||
319
- isResponseBodyVariableRedefinitionNeeded;
320
-
321
- const responseBodyHeadersVariableRedefineLines = isResponseVariableRedefinitionNeeded
322
- ? [
323
- // eslint-disable-next-line no-nested-ternary
324
- ...(destructuringResponseBodyVariable
325
- ? [
326
- `const ${destructuringResponseBodyVariable.name} = ${getResponseBodyRetrievalText(responseVariableNameToUse)}`,
327
- ]
328
- : isResponseBodyVariableRedefinitionNeeded
329
- ? [
330
- `const ${redefineResponseBodyVariableName} = ${getResponseBodyRetrievalText(responseVariableNameToUse)}`,
331
- ]
332
- : []),
333
- ...(destructuringResponseHeadersVariable
334
- ? [`const ${destructuringResponseHeadersVariable.name} = ${responseVariableNameToUse}.headers`]
335
- : []),
336
- ]
337
- : [];
338
-
339
- const { statusAssertion, nonStatusAssertions } = createResponseAssertions(
340
- fixtureCallInformation,
341
- sourceCode,
342
- responseVariableNameToUse,
343
- destructuringResponseHeadersVariable,
344
- );
345
-
346
- // add variable declaration if needed
347
- const fetchCallText = `fetch(${fetchUrlArgumentText}, ${fetchRequestArgumentLines})`;
348
- const fetchStatementText = !isResponseVariableRedefinitionNeeded
349
- ? fetchCallText
350
- : `const ${responseVariableNameToUse} = await ${fetchCallText}`;
351
-
352
- const nodeToReplace = isResponseVariableRedefinitionNeeded
353
- ? fixtureCallInformation.rootNode
354
- : fixtureCallInformation.fixtureNode;
355
- const appendingAssignmentAndAssertionText = [
356
- '',
357
- ...(statusAssertion !== undefined ? [statusAssertion] : []),
358
- ...responseBodyHeadersVariableRedefineLines,
359
- ...nonStatusAssertions,
360
- ].join(`;\n${indentation}`);
361
-
362
- context.report({
363
- node: fixtureCall,
364
- messageId: 'preferNativeFetch',
365
- // eslint-disable-next-line sonarjs/cognitive-complexity
366
- *fix(fixer) {
367
- if (fixtureCallInformation.inlineStatementNode) {
368
- const preInlineDeclaration = [
369
- fetchStatementText,
370
- `${appendingAssignmentAndAssertionText};\n${indentation}`,
371
- ].join(``);
372
- yield fixer.insertTextBefore(fixtureCallInformation.inlineStatementNode, preInlineDeclaration);
373
- } else {
374
- yield fixer.replaceText(nodeToReplace, fetchStatementText);
375
-
376
- const needEndingSemiColon = sourceCode.getText(nodeToReplace).endsWith(';');
377
- yield fixer.insertTextAfter(
378
- nodeToReplace,
379
- needEndingSemiColon ? `${appendingAssignmentAndAssertionText};` : appendingAssignmentAndAssertionText,
380
- );
381
- }
382
-
383
- // handle response body references
384
- for (const responseBodyReference of responseBodyReferences) {
385
- yield fixer.replaceText(
386
- responseBodyReference,
387
- isResponseBodyVariableRedefinitionNeeded || !isResponseBodyRedefinition(responseBodyReference)
388
- ? redefineResponseBodyVariableName
389
- : getResponseBodyRetrievalText(responseVariableNameToUse),
390
- );
391
- }
392
- if (fixtureCallInformation.inlineBodyReference) {
393
- yield fixer.replaceText(fixtureCallInformation.inlineBodyReference, redefineResponseBodyVariableName);
394
- }
395
-
396
- // handle response headers references
397
- for (const responseHeadersReference of responseHeadersReferences) {
398
- const parent = getParent(responseHeadersReference);
399
- assert.ok(parent);
400
- let headerName;
401
- if (parent.type === 'MemberExpression') {
402
- const headerNameNode = parent.property;
403
- headerName =
404
- // eslint-disable-next-line no-nested-ternary, @typescript-eslint/restrict-template-expressions
405
- parent.computed ? sourceCode.getText(headerNameNode) : `'${sourceCode.getText(headerNameNode)}'`;
406
- } else if (parent.type === 'CallExpression') {
407
- const headerNameNode = parent.arguments[0];
408
- headerName = sourceCode.getText(headerNameNode);
409
- }
410
- assert.ok(headerName !== undefined);
411
- yield fixer.replaceText(parent, `${responseVariableNameToUse}.headers.get(${headerName})`);
412
- }
413
-
414
- // convert response.statusCode to response.status
415
- for (const responseStatusReference of responseStatusReferences) {
416
- if (
417
- responseStatusReference.property.type === 'Identifier' &&
418
- responseStatusReference.property.name === 'statusCode'
419
- ) {
420
- yield fixer.replaceText(responseStatusReference.property, `status`);
421
- }
422
- }
423
-
424
- // handle direct return statement without await, e.g. "return fixture.api.get(...);"
425
- if (
426
- fixtureCallInformation.rootNode.type === 'ReturnStatement' &&
427
- fixtureCallInformation.assertions !== undefined
428
- ) {
429
- yield fixer.insertTextAfter(
430
- fixtureCallInformation.rootNode,
431
- `\n${indentation}return ${responseVariableNameToUse};`,
432
- );
433
- }
434
- },
435
- });
436
- } catch (error) {
437
- // eslint-disable-next-line no-console
438
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
439
- context.report({
440
- node: fixtureCall,
441
- messageId: 'unknownError',
442
- data: {
443
- fileName: context.filename,
444
- error: error instanceof Error ? error.toString() : JSON.stringify(error),
445
- },
446
- });
447
- }
448
- },
449
- };
450
- },
451
- };
452
-
453
- export default rule;
@@ -1,75 +0,0 @@
1
- // agent/no-full-response.ts
2
-
3
- /*
4
- * Copyright (c) 2021-2024 Check Digit, LLC
5
- *
6
- * This code is licensed under the MIT license (see LICENSE.txt for details).
7
- */
8
-
9
- import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';
10
- import { strict as assert } from 'node:assert';
11
- import getDocumentationUrl from '../get-documentation-url';
12
- import { getTypeParentNode } from '../library/ts-tree';
13
-
14
- export const ruleId = 'no-full-response';
15
-
16
- const createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
17
-
18
- const rule = createRule({
19
- name: ruleId,
20
- meta: {
21
- type: 'suggestion',
22
- docs: {
23
- description: 'Remove the usage of FullResponse type.',
24
- },
25
- messages: {
26
- removeFullResponse: 'Removing the usage of FullResponse type.',
27
- unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.',
28
- },
29
- fixable: 'code',
30
- schema: [],
31
- },
32
- defaultOptions: [],
33
- create(context) {
34
- const sourceCode = context.sourceCode;
35
-
36
- return {
37
- 'TSTypeReference[typeName.name="FullResponse"]': (typeReference: TSESTree.TSTypeReference) => {
38
- try {
39
- const typeParentNode = getTypeParentNode(typeReference);
40
- assert.ok(typeParentNode);
41
- if (typeParentNode.type === TSESTree.AST_NODE_TYPES.TSAsExpression) {
42
- context.report({
43
- messageId: 'removeFullResponse',
44
- node: typeReference,
45
- fix(fixer) {
46
- return fixer.replaceText(typeParentNode, sourceCode.getText(typeParentNode.expression));
47
- },
48
- });
49
- } else {
50
- context.report({
51
- messageId: 'removeFullResponse',
52
- node: typeReference,
53
- fix(fixer) {
54
- return fixer.remove(typeParentNode);
55
- },
56
- });
57
- }
58
- } catch (error) {
59
- // eslint-disable-next-line no-console
60
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
61
- context.report({
62
- node: typeReference,
63
- messageId: 'unknownError',
64
- data: {
65
- fileName: context.filename,
66
- error: error instanceof Error ? error.toString() : JSON.stringify(error),
67
- },
68
- });
69
- }
70
- },
71
- };
72
- },
73
- });
74
-
75
- export default rule;
@@ -1,84 +0,0 @@
1
- // agent/no-mapped-response-type.ts
2
-
3
- /*
4
- * Copyright (c) 2021-2024 Check Digit, LLC
5
- *
6
- * This code is licensed under the MIT license (see LICENSE.txt for details).
7
- */
8
-
9
- import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';
10
- import getDocumentationUrl from '../get-documentation-url';
11
-
12
- export const ruleId = 'no-mapped-response';
13
-
14
- const createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
15
-
16
- const rule = createRule({
17
- name: ruleId,
18
- meta: {
19
- type: 'suggestion',
20
- docs: {
21
- description: 'Replace the usage of MappedResponse type with FetchResponse.',
22
- },
23
- messages: {
24
- replaceFullResponseWithFetchResponse: 'Replace the usage of FullResponse type with FetchResponse.',
25
- unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.',
26
- },
27
- fixable: 'code',
28
- schema: [],
29
- },
30
- defaultOptions: [],
31
- create(context) {
32
- const sourceCode = context.sourceCode;
33
-
34
- return {
35
- 'TSTypeReference[typeName.name="MappedResponse"]': (typeReference: TSESTree.TSTypeReference) => {
36
- try {
37
- context.report({
38
- messageId: 'replaceFullResponseWithFetchResponse',
39
- node: typeReference,
40
- fix(fixer) {
41
- const typeParams = sourceCode.getText(typeReference.typeArguments);
42
- return fixer.replaceText(typeReference, `FetchResponse${typeParams || ''}`);
43
- },
44
- });
45
- } catch (error) {
46
- // eslint-disable-next-line no-console
47
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
48
- context.report({
49
- node: typeReference,
50
- messageId: 'unknownError',
51
- data: {
52
- fileName: context.filename,
53
- error: error instanceof Error ? error.toString() : JSON.stringify(error),
54
- },
55
- });
56
- }
57
- },
58
- 'ImportSpecifier[imported.name="MappedResponse"]': (importSpecifier: TSESTree.ImportSpecifier) => {
59
- try {
60
- context.report({
61
- messageId: 'replaceFullResponseWithFetchResponse',
62
- node: importSpecifier.imported,
63
- fix(fixer) {
64
- return fixer.replaceText(importSpecifier.imported, 'FetchResponse');
65
- },
66
- });
67
- } catch (error) {
68
- // eslint-disable-next-line no-console
69
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
70
- context.report({
71
- node: importSpecifier.imported,
72
- messageId: 'unknownError',
73
- data: {
74
- fileName: context.filename,
75
- error: error instanceof Error ? error.toString() : JSON.stringify(error),
76
- },
77
- });
78
- }
79
- },
80
- };
81
- },
82
- });
83
-
84
- export default rule;