@checkdigit/eslint-plugin 6.6.0-PR.75-1f73 → 6.6.0-PR.77-5328

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 (45) hide show
  1. package/dist-cjs/index.cjs +755 -2126
  2. package/dist-cjs/metafile.json +82 -519
  3. package/dist-mjs/index.mjs +2 -60
  4. package/dist-mjs/require-resolve-full-response.mjs +5 -2
  5. package/dist-types/index.d.ts +1 -48
  6. package/dist-types/require-resolve-full-response.d.ts +3 -1
  7. package/package.json +1 -1
  8. package/src/index.ts +0 -58
  9. package/src/require-resolve-full-response.ts +2 -1
  10. package/dist-mjs/agent/add-url-domain.mjs +0 -61
  11. package/dist-mjs/agent/fetch-response-body-json.mjs +0 -63
  12. package/dist-mjs/agent/fetch-response-header-getter.mjs +0 -117
  13. package/dist-mjs/agent/fetch-then.mjs +0 -269
  14. package/dist-mjs/agent/fetch.mjs +0 -34
  15. package/dist-mjs/agent/no-fixture.mjs +0 -328
  16. package/dist-mjs/agent/no-full-response.mjs +0 -67
  17. package/dist-mjs/agent/no-mapped-response.mjs +0 -75
  18. package/dist-mjs/agent/no-service-wrapper.mjs +0 -184
  19. package/dist-mjs/agent/no-status-code.mjs +0 -59
  20. package/dist-mjs/agent/response-reference.mjs +0 -56
  21. package/dist-mjs/agent/url.mjs +0 -26
  22. package/dist-types/agent/add-url-domain.d.ts +0 -4
  23. package/dist-types/agent/fetch-response-body-json.d.ts +0 -4
  24. package/dist-types/agent/fetch-response-header-getter.d.ts +0 -4
  25. package/dist-types/agent/fetch-then.d.ts +0 -4
  26. package/dist-types/agent/fetch.d.ts +0 -4
  27. package/dist-types/agent/no-fixture.d.ts +0 -4
  28. package/dist-types/agent/no-full-response.d.ts +0 -4
  29. package/dist-types/agent/no-mapped-response.d.ts +0 -4
  30. package/dist-types/agent/no-service-wrapper.d.ts +0 -4
  31. package/dist-types/agent/no-status-code.d.ts +0 -4
  32. package/dist-types/agent/response-reference.d.ts +0 -16
  33. package/dist-types/agent/url.d.ts +0 -5
  34. package/src/agent/add-url-domain.ts +0 -75
  35. package/src/agent/fetch-response-body-json.ts +0 -76
  36. package/src/agent/fetch-response-header-getter.ts +0 -148
  37. package/src/agent/fetch-then.ts +0 -354
  38. package/src/agent/fetch.ts +0 -52
  39. package/src/agent/no-fixture.ts +0 -453
  40. package/src/agent/no-full-response.ts +0 -75
  41. package/src/agent/no-mapped-response.ts +0 -84
  42. package/src/agent/no-service-wrapper.ts +0 -238
  43. package/src/agent/no-status-code.ts +0 -71
  44. package/src/agent/response-reference.ts +0 -100
  45. package/src/agent/url.ts +0 -23
@@ -1,148 +0,0 @@
1
- // fixture/fetch-response-header-getter-ts.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 { AST_NODE_TYPES, ESLintUtils, TSESTree } from '@typescript-eslint/utils';
10
- import getDocumentationUrl from '../get-documentation-url';
11
-
12
- export const ruleId = 'fetch-response-header-getter-ts';
13
- const HEADER_BUILTIN_FUNCTIONS = Object.keys(Headers.prototype);
14
-
15
- const createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
16
-
17
- const rule = createRule({
18
- name: ruleId,
19
- meta: {
20
- type: 'suggestion',
21
- docs: {
22
- description: 'Use "get()" method to get header value from the headers object of the fetch response.',
23
- },
24
- messages: {
25
- useGetter: 'Use "get()" method to get header value from the headers object of the fetch response.',
26
- unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.',
27
- },
28
- fixable: 'code',
29
- schema: [],
30
- },
31
- defaultOptions: [],
32
- create(context) {
33
- const parserServices = ESLintUtils.getParserServices(context);
34
- const typeChecker = parserServices.program.getTypeChecker();
35
- const sourceCode = context.sourceCode;
36
-
37
- return {
38
- MemberExpression: (responseHeadersAccess: TSESTree.MemberExpression) => {
39
- try {
40
- if (
41
- responseHeadersAccess.property.type === AST_NODE_TYPES.Identifier &&
42
- HEADER_BUILTIN_FUNCTIONS.includes(responseHeadersAccess.property.name)
43
- ) {
44
- // skip Headers's built-in function calls
45
- return;
46
- }
47
-
48
- const responseHeadersTsNode = parserServices.esTreeNodeToTSNodeMap.get(responseHeadersAccess.object);
49
- let responseHeadersType = typeChecker.getTypeAtLocation(responseHeadersTsNode);
50
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
51
- responseHeadersType = responseHeadersType.isUnion() ? responseHeadersType.types[0]! : responseHeadersType;
52
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
53
- const responseHeadersTypeName = // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
54
- (responseHeadersType.symbol ?? responseHeadersType.aliasSymbol)?.escapedName;
55
- // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
56
- if (responseHeadersTypeName !== 'Headers' && responseHeadersTypeName !== 'HeaderGetter') {
57
- return;
58
- }
59
-
60
- let replacementText: string;
61
- if (!responseHeadersAccess.computed) {
62
- // e.g. headers.etag
63
- replacementText = `${sourceCode.getText(responseHeadersAccess.object)}.get('${sourceCode.getText(responseHeadersAccess.property)}')`;
64
- } else if (
65
- responseHeadersAccess.property.type === AST_NODE_TYPES.Identifier ||
66
- responseHeadersAccess.property.type === AST_NODE_TYPES.Literal ||
67
- responseHeadersAccess.property.type === AST_NODE_TYPES.TemplateLiteral
68
- ) {
69
- replacementText = `${sourceCode.getText(responseHeadersAccess.object)}.get(${sourceCode.getText(responseHeadersAccess.property)})`;
70
- } else {
71
- throw new Error(`Unexpected property type: ${responseHeadersAccess.property.type}`);
72
- }
73
-
74
- context.report({
75
- messageId: 'useGetter',
76
- node: responseHeadersAccess.property,
77
- fix(fixer) {
78
- return fixer.replaceText(responseHeadersAccess, replacementText);
79
- },
80
- });
81
- } catch (error) {
82
- // eslint-disable-next-line no-console
83
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
84
- context.report({
85
- node: responseHeadersAccess,
86
- messageId: 'unknownError',
87
- data: {
88
- fileName: context.filename,
89
- error: error instanceof Error ? error.toString() : JSON.stringify(error),
90
- },
91
- });
92
- }
93
- },
94
-
95
- // convert response.get() to response.headers.get()
96
- 'CallExpression[callee.property.name="get"]': (responseHeadersAccess: TSESTree.CallExpression) => {
97
- try {
98
- if (responseHeadersAccess.callee.type !== AST_NODE_TYPES.MemberExpression) {
99
- return;
100
- }
101
-
102
- // skip request-like calls
103
- if (
104
- responseHeadersAccess.callee.object.type !== AST_NODE_TYPES.Identifier ||
105
- responseHeadersAccess.callee.object.name === 'request'
106
- ) {
107
- return;
108
- }
109
- const responseNode = responseHeadersAccess.callee.object;
110
- const responseHeadersTsNode = parserServices.esTreeNodeToTSNodeMap.get(responseNode);
111
- const responseType = typeChecker.getTypeAtLocation(responseHeadersTsNode);
112
- const typeName = typeChecker.typeToString(responseType);
113
- if (typeName === 'InboundContext' || typeName.endsWith('RequestType')) {
114
- return;
115
- }
116
-
117
- // make sure the response type has "headers" property
118
- const hasHeadersProperty = responseType.getProperties().some((symbol) => symbol.name === 'headers');
119
- if (!hasHeadersProperty) {
120
- return;
121
- }
122
-
123
- const replacementText = `${sourceCode.getText(responseNode)}.headers`;
124
- context.report({
125
- messageId: 'useGetter',
126
- node: responseHeadersAccess,
127
- fix(fixer) {
128
- return fixer.replaceText(responseNode, replacementText);
129
- },
130
- });
131
- } catch (error) {
132
- // eslint-disable-next-line no-console
133
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
134
- context.report({
135
- node: responseHeadersAccess,
136
- messageId: 'unknownError',
137
- data: {
138
- fileName: context.filename,
139
- error: error instanceof Error ? error.toString() : JSON.stringify(error),
140
- },
141
- });
142
- }
143
- },
144
- };
145
- },
146
- });
147
-
148
- export default rule;
@@ -1,354 +0,0 @@
1
- // fixture/fetch-then.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 { CallExpression, Expression, MemberExpression, SimpleCallExpression } from 'estree';
10
- import { type Rule, type Scope, SourceCode } from 'eslint';
11
- import { getEnclosingFunction, getEnclosingStatement, getParent, isUsedInArrayOrAsArgument } from '../library/tree';
12
- import { hasAssertions, isInvalidResponseHeadersAccess } from './fetch';
13
- import { strict as assert } from 'node:assert';
14
- import getDocumentationUrl from '../get-documentation-url';
15
- import { getIndentation } from '../library/format';
16
- import { isValidPropertyName } from '../library/variable';
17
- import { replaceEndpointUrlPrefixWithBasePath } from './url';
18
-
19
- export const ruleId = 'fetch-then';
20
-
21
- interface FixtureCallInformation {
22
- fixtureNode: SimpleCallExpression;
23
- requestBody?: Expression;
24
- requestHeaders?: { name: Expression; value: Expression }[];
25
- assertions?: Expression[][];
26
- }
27
-
28
- // recursively analyze the fixture/supertest call chain to collect information of request/response
29
- function analyzeFixtureCall(call: SimpleCallExpression, results: FixtureCallInformation, sourceCode: SourceCode) {
30
- const parent = getParent(call);
31
- if (!parent) {
32
- return;
33
- }
34
-
35
- let nextCall;
36
- if (parent.type !== 'MemberExpression') {
37
- results.fixtureNode = call;
38
- return;
39
- }
40
-
41
- if (parent.property.type === 'Identifier') {
42
- if (parent.property.name === 'expect') {
43
- // supertest assertions
44
- const assertionCall = getParent(parent);
45
- assert.ok(assertionCall && assertionCall.type === 'CallExpression');
46
- results.assertions = [...(results.assertions ?? []), assertionCall.arguments as Expression[]];
47
- nextCall = assertionCall;
48
- } else if (parent.property.name === 'send') {
49
- // request body
50
- const sendRequestBodyCall = getParent(parent);
51
- assert.ok(sendRequestBodyCall && sendRequestBodyCall.type === 'CallExpression');
52
- results.requestBody = sendRequestBodyCall.arguments[0] as Expression;
53
- nextCall = sendRequestBodyCall;
54
- } else if (parent.property.name === 'set') {
55
- // request headers
56
- const setRequestHeaderCall = getParent(parent);
57
- assert.ok(setRequestHeaderCall && setRequestHeaderCall.type === 'CallExpression');
58
- const [name, value] = setRequestHeaderCall.arguments as [Expression, Expression];
59
- results.requestHeaders = [...(results.requestHeaders ?? []), { name, value }];
60
- nextCall = setRequestHeaderCall;
61
- }
62
- } else {
63
- throw new Error(`Unexpected expression in fixture/supertest call ${sourceCode.getText(parent)}.`);
64
- }
65
- if (nextCall) {
66
- analyzeFixtureCall(nextCall, results, sourceCode);
67
- }
68
- }
69
-
70
- // eslint-disable-next-line sonarjs/cognitive-complexity
71
- function createResponseAssertions(
72
- fixtureCallInformation: FixtureCallInformation,
73
- sourceCode: SourceCode,
74
- responseVariableName: string,
75
- ) {
76
- let statusAssertion: string | undefined;
77
- const nonStatusAssertions: string[] = [];
78
- for (const expectArguments of fixtureCallInformation.assertions ?? []) {
79
- if (expectArguments.length === 1) {
80
- const [assertionArgument] = expectArguments;
81
- assert.ok(assertionArgument);
82
- if (
83
- (assertionArgument.type === 'MemberExpression' &&
84
- assertionArgument.object.type === 'Identifier' &&
85
- assertionArgument.object.name === 'StatusCodes') ||
86
- assertionArgument.type === 'Literal' ||
87
- sourceCode.getText(assertionArgument).includes('StatusCodes.')
88
- ) {
89
- // status code assertion
90
- statusAssertion = `assert.equal(${responseVariableName}.status, ${sourceCode.getText(assertionArgument)})`;
91
- } else if (assertionArgument.type === 'ArrowFunctionExpression') {
92
- // callback assertion using arrow function
93
- let functionBody = sourceCode.getText(assertionArgument.body);
94
-
95
- const [originalResponseArgument] = assertionArgument.params;
96
- assert.ok(originalResponseArgument?.type === 'Identifier');
97
- const originalResponseArgumentName = originalResponseArgument.name;
98
- if (originalResponseArgumentName !== responseVariableName) {
99
- functionBody = functionBody.replace(
100
- new RegExp(`\\b${originalResponseArgumentName}\\b`, 'ug'),
101
- responseVariableName,
102
- );
103
- }
104
- nonStatusAssertions.push(`assert.ok(${functionBody})`);
105
- } else if (assertionArgument.type === 'Identifier') {
106
- // callback assertion using function reference
107
- nonStatusAssertions.push(`assert.ok(${sourceCode.getText(assertionArgument)}(${responseVariableName}))`);
108
- } else if (assertionArgument.type === 'ObjectExpression' || assertionArgument.type === 'CallExpression') {
109
- // body deep equal assertion
110
- nonStatusAssertions.push(
111
- `assert.deepEqual(await ${responseVariableName}.json(), ${sourceCode.getText(assertionArgument)})`,
112
- );
113
- } else {
114
- throw new Error(`Unexpected Supertest assertion argument: ".expect(${sourceCode.getText(assertionArgument)})`);
115
- }
116
- } else if (expectArguments.length === 2) {
117
- // header assertion
118
- const [headerName, headerValue] = expectArguments;
119
- assert.ok(headerName && headerValue);
120
- const headersReference = `${responseVariableName}.headers`;
121
- if (headerValue.type === 'Literal' && headerValue.value instanceof RegExp) {
122
- nonStatusAssertions.push(
123
- `assert.ok(${headersReference}.get(${sourceCode.getText(headerName)}).match(${sourceCode.getText(headerValue)}))`,
124
- );
125
- } else {
126
- nonStatusAssertions.push(
127
- `assert.equal(${headersReference}.get(${sourceCode.getText(headerName)}), ${sourceCode.getText(headerValue)})`,
128
- );
129
- }
130
- }
131
- }
132
- return {
133
- statusAssertion,
134
- nonStatusAssertions,
135
- };
136
- }
137
-
138
- function getResponseHeadersAccesses(
139
- responseVariables: Scope.Variable[],
140
- scopeManager: Scope.ScopeManager,
141
- sourceCode: SourceCode,
142
- ) {
143
- const responseHeadersAccesses: MemberExpression[] = [];
144
- for (const responseVariable of responseVariables) {
145
- for (const responseReference of responseVariable.references) {
146
- const responseAccess = getParent(responseReference.identifier);
147
- if (!responseAccess || responseAccess.type !== 'MemberExpression') {
148
- continue;
149
- }
150
-
151
- const responseAccessParent = getParent(responseAccess);
152
- if (!responseAccessParent) {
153
- continue;
154
- }
155
-
156
- if (
157
- responseAccessParent.type === 'CallExpression' &&
158
- responseAccessParent.arguments[0]?.type === 'ArrowFunctionExpression'
159
- ) {
160
- // map-like operation against responses, e.g. responses.map((response) => response.headers.etag)
161
- responseHeadersAccesses.push(
162
- ...getResponseHeadersAccesses(
163
- scopeManager.getDeclaredVariables(responseAccessParent.arguments[0]),
164
- scopeManager,
165
- sourceCode,
166
- ),
167
- );
168
- continue;
169
- }
170
-
171
- if (
172
- responseAccess.computed &&
173
- responseAccess.property.type === 'Literal' &&
174
- responseAccessParent.type === 'MemberExpression'
175
- ) {
176
- // header access through indexed responses array, e.g. responses[0].headers, responses[1].get(...), etc.
177
- responseHeadersAccesses.push(responseAccessParent);
178
- } else {
179
- responseHeadersAccesses.push(responseAccess);
180
- }
181
- }
182
- }
183
- return responseHeadersAccesses;
184
- }
185
-
186
- const rule: Rule.RuleModule = {
187
- meta: {
188
- type: 'suggestion',
189
- docs: {
190
- description: 'Prefer native fetch API over customized fixture API.',
191
- url: getDocumentationUrl(ruleId),
192
- },
193
- messages: {
194
- preferNativeFetch: 'Prefer native fetch API over customized fixture API.',
195
- shouldUseHeaderGetter: 'Getter should be used to access response headers.',
196
- unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.',
197
- },
198
- fixable: 'code',
199
- schema: [],
200
- },
201
- // eslint-disable-next-line max-lines-per-function
202
- create(context) {
203
- const sourceCode = context.sourceCode;
204
- const scopeManager = sourceCode.scopeManager;
205
-
206
- return {
207
- // eslint-disable-next-line max-lines-per-function
208
- 'CallExpression[callee.object.object.name="fixture"][callee.object.property.name="api"]': (
209
- fixtureCall: CallExpression,
210
- // eslint-disable-next-line sonarjs/cognitive-complexity
211
- ) => {
212
- try {
213
- if (!hasAssertions(fixtureCall)) {
214
- // skip if there are no assertions, let "no-fixture" rule to handle the conversion
215
- return;
216
- }
217
-
218
- if (!(isUsedInArrayOrAsArgument(fixtureCall) || getEnclosingFunction(fixtureCall)?.async === false)) {
219
- return;
220
- }
221
-
222
- assert.ok(fixtureCall.type === 'CallExpression');
223
- const fixtureFunction = fixtureCall.callee; // e.g. fixture.api.get
224
- assert.ok(fixtureFunction.type === 'MemberExpression');
225
- const indentation = getIndentation(fixtureCall, sourceCode);
226
-
227
- const [urlArgumentNode] = fixtureCall.arguments; // e.g. `/sample-service/v1/ping`
228
- assert.ok(urlArgumentNode !== undefined);
229
-
230
- const fixtureCallInformation = {} as FixtureCallInformation;
231
- analyzeFixtureCall(fixtureCall, fixtureCallInformation, sourceCode);
232
-
233
- // convert url from `/sample-service/v1/ping` to `${BASE_PATH}/ping`
234
- const originalUrlArgumentText = sourceCode.getText(urlArgumentNode);
235
- const fetchUrlArgumentText = replaceEndpointUrlPrefixWithBasePath(originalUrlArgumentText);
236
-
237
- // fetch request argument
238
- const methodNode = fixtureFunction.property; // get/put/etc.
239
- assert.ok(methodNode.type === 'Identifier');
240
- const fetchRequestArgumentLines = [
241
- '{',
242
- ` method: '${methodNode.name.toUpperCase()}',`,
243
- ...(fixtureCallInformation.requestBody
244
- ? [` body: JSON.stringify(${sourceCode.getText(fixtureCallInformation.requestBody)}),`]
245
- : []),
246
- ...(fixtureCallInformation.requestHeaders
247
- ? [
248
- ` headers: {`,
249
- ...fixtureCallInformation.requestHeaders.map(
250
- ({ name, value }) =>
251
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, no-nested-ternary, sonarjs/no-nested-template-literals
252
- ` ${name.type === 'Literal' ? (isValidPropertyName(name.value) ? name.value : `'${name.value}'`) : `[${sourceCode.getText(name)}]`}: ${sourceCode.getText(value)},`,
253
- ),
254
- ` },`,
255
- ]
256
- : []),
257
- '}',
258
- ].join(`\n${indentation}`);
259
-
260
- const responseVariableNameToUse = 'res';
261
- const { statusAssertion, nonStatusAssertions } = createResponseAssertions(
262
- fixtureCallInformation,
263
- sourceCode,
264
- responseVariableNameToUse,
265
- );
266
-
267
- // add variable declaration if needed
268
- const disableLintComment = '// eslint-disable-next-line @checkdigit/no-promise-instance-method';
269
- const fetchCallText = `fetch(${fetchUrlArgumentText}, ${fetchRequestArgumentLines})`;
270
- const appendingAssignmentAndAssertionText = [
271
- ...(statusAssertion !== undefined ? [statusAssertion] : []),
272
- ...nonStatusAssertions,
273
- ].join(`;\n${indentation}`);
274
- const replacementText = fixtureCallInformation.assertions
275
- ? [
276
- disableLintComment,
277
- `${fetchCallText}.then((${responseVariableNameToUse}) => {`,
278
- appendingAssignmentAndAssertionText === '' ? '' : ` ${appendingAssignmentAndAssertionText};`,
279
- ` return ${responseVariableNameToUse};`,
280
- `})`,
281
- ].join(`\n${indentation}`)
282
- : fetchCallText;
283
-
284
- context.report({
285
- node: fixtureCall,
286
- messageId: 'preferNativeFetch',
287
- fix(fixer) {
288
- return fixer.replaceText(fixtureCallInformation.fixtureNode, replacementText);
289
- },
290
- });
291
-
292
- const responsesVariable = getEnclosingStatement(fixtureCallInformation.fixtureNode);
293
- if (!responsesVariable) {
294
- return;
295
- }
296
-
297
- const responseVariableReferences = scopeManager.getDeclaredVariables(responsesVariable);
298
- const responseHeadersAccesses = getResponseHeadersAccesses(
299
- responseVariableReferences,
300
- scopeManager,
301
- sourceCode,
302
- );
303
- for (const responseHeadersAccess of responseHeadersAccesses) {
304
- if (isInvalidResponseHeadersAccess(responseHeadersAccess)) {
305
- const headerAccess = getParent(responseHeadersAccess);
306
- if (headerAccess?.type === 'MemberExpression') {
307
- const headerNameNode = headerAccess.property;
308
- const headerName = headerAccess.computed
309
- ? sourceCode.getText(headerNameNode)
310
- : `'${sourceCode.getText(headerNameNode)}'`;
311
- const headerAccessReplacementText = `${sourceCode.getText(headerAccess.object)}.get(${headerName})`;
312
-
313
- context.report({
314
- node: headerAccess,
315
- messageId: 'shouldUseHeaderGetter',
316
- fix(fixer) {
317
- return fixer.replaceText(headerAccess, headerAccessReplacementText);
318
- },
319
- });
320
- } else if (
321
- headerAccess?.type === 'CallExpression' &&
322
- responseHeadersAccess.property.type === 'Identifier' &&
323
- responseHeadersAccess.property.name === 'get'
324
- ) {
325
- const headerAccessReplacementText = `${sourceCode.getText(responseHeadersAccess.object)}.headers.get(${sourceCode.getText(headerAccess.arguments[0])})`;
326
-
327
- context.report({
328
- node: headerAccess,
329
- messageId: 'shouldUseHeaderGetter',
330
- fix(fixer) {
331
- return fixer.replaceText(headerAccess, headerAccessReplacementText);
332
- },
333
- });
334
- }
335
- }
336
- }
337
- } catch (error) {
338
- // eslint-disable-next-line no-console
339
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
340
- context.report({
341
- node: fixtureCall,
342
- messageId: 'unknownError',
343
- data: {
344
- fileName: context.filename,
345
- error: error instanceof Error ? error.toString() : JSON.stringify(error),
346
- },
347
- });
348
- }
349
- },
350
- };
351
- },
352
- };
353
-
354
- export default rule;
@@ -1,52 +0,0 @@
1
- // fixture/fetch.ts
2
-
3
- import { getParent, isBlockStatement } from '../library/tree';
4
- import type { Node } from 'estree';
5
-
6
- export function getResponseBodyRetrievalText(responseVariableName: string) {
7
- return `await ${responseVariableName}.json()`;
8
- }
9
-
10
- export function isInvalidResponseHeadersAccess(responseHeadersAccess: Node) {
11
- const responseHeaderAccessParent = getParent(responseHeadersAccess);
12
- if (responseHeaderAccessParent?.type === 'VariableDeclarator') {
13
- return false;
14
- }
15
-
16
- if (
17
- responseHeaderAccessParent?.type === 'CallExpression' &&
18
- responseHeaderAccessParent.callee.type === 'MemberExpression' &&
19
- responseHeaderAccessParent.callee.property.type === 'Identifier' &&
20
- responseHeaderAccessParent.callee.property.name === 'get'
21
- ) {
22
- return true;
23
- }
24
-
25
- return !(
26
- responseHeaderAccessParent?.type === 'MemberExpression' &&
27
- responseHeaderAccessParent.property.type === 'Identifier' &&
28
- responseHeaderAccessParent.property.name === 'get'
29
- );
30
- }
31
-
32
- export function hasAssertions(fixtureCall: Node) {
33
- if (isBlockStatement(fixtureCall)) {
34
- return false;
35
- }
36
-
37
- const parent = getParent(fixtureCall);
38
- if (!parent) {
39
- return false;
40
- }
41
-
42
- if (
43
- parent.type === 'MemberExpression' &&
44
- parent.property.type === 'Identifier' &&
45
- parent.property.name === 'expect' &&
46
- getParent(parent)?.type === 'CallExpression'
47
- ) {
48
- return true;
49
- }
50
-
51
- return hasAssertions(parent);
52
- }