@checkdigit/eslint-plugin 6.6.0-PR.75-a513 → 6.6.0-PR.75-8f9f

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 (63) hide show
  1. package/dist-cjs/index.cjs +519 -428
  2. package/dist-cjs/metafile.json +169 -178
  3. package/dist-mjs/{fixture → agent}/add-url-domain.mjs +2 -2
  4. package/dist-mjs/{fixture → agent}/fetch-response-body-json.mjs +2 -2
  5. package/dist-mjs/agent/fetch-response-header-getter.mjs +117 -0
  6. package/dist-mjs/{fixture → agent}/fetch-then.mjs +6 -6
  7. package/dist-mjs/{fixture → agent}/fetch.mjs +3 -3
  8. package/dist-mjs/{fixture → agent}/no-fixture.mjs +6 -6
  9. package/dist-mjs/{fixture → agent}/no-full-response.mjs +4 -4
  10. package/dist-mjs/{fixture → agent}/no-service-wrapper.mjs +4 -4
  11. package/dist-mjs/{fixture → agent}/no-status-code.mjs +2 -2
  12. package/dist-mjs/{fixture → agent}/response-reference.mjs +3 -3
  13. package/dist-mjs/{fixture → agent}/url.mjs +2 -2
  14. package/dist-mjs/index.mjs +21 -18
  15. package/dist-mjs/library/format.mjs +14 -0
  16. package/dist-mjs/{ast → library}/tree.mjs +2 -2
  17. package/dist-mjs/library/ts-tree.mjs +72 -0
  18. package/dist-mjs/{fixture → library}/variable.mjs +2 -2
  19. package/dist-mjs/require-resolve-full-response.mjs +156 -0
  20. package/dist-types/index.d.ts +3 -2
  21. package/dist-types/{ast → library}/ts-tree.d.ts +1 -0
  22. package/dist-types/require-resolve-full-response.d.ts +4 -0
  23. package/package.json +1 -1
  24. package/src/{fixture → agent}/add-url-domain.ts +2 -2
  25. package/src/{fixture/fetch-response-header-getter-ts.ts → agent/fetch-response-header-getter.ts} +32 -21
  26. package/src/{fixture → agent}/fetch-then.ts +4 -5
  27. package/src/{fixture → agent}/fetch.ts +1 -1
  28. package/src/{fixture → agent}/no-fixture.ts +4 -5
  29. package/src/{fixture → agent}/no-full-response.ts +2 -2
  30. package/src/{fixture → agent}/no-service-wrapper.ts +2 -2
  31. package/src/{fixture → agent}/response-reference.ts +1 -1
  32. package/src/index.ts +18 -15
  33. package/src/{ast → library}/ts-tree.ts +11 -0
  34. package/src/require-resolve-full-response.ts +199 -0
  35. package/dist-mjs/ast/format.mjs +0 -14
  36. package/dist-mjs/ast/ts-tree.mjs +0 -65
  37. package/dist-mjs/fixture/fetch-header-getter.mjs +0 -71
  38. package/dist-mjs/fixture/fetch-response-header-getter-ts.mjs +0 -110
  39. package/dist-mjs/fixture/ts-tree.mjs +0 -12
  40. package/dist-types/fixture/fetch-header-getter.d.ts +0 -4
  41. package/dist-types/fixture/ts-tree.d.ts +0 -2
  42. package/src/fixture/fetch-header-getter.ts +0 -91
  43. package/src/fixture/ts-tree.ts +0 -14
  44. /package/dist-types/{fixture → agent}/add-url-domain.d.ts +0 -0
  45. /package/dist-types/{fixture → agent}/fetch-response-body-json.d.ts +0 -0
  46. /package/dist-types/{fixture/fetch-response-header-getter-ts.d.ts → agent/fetch-response-header-getter.d.ts} +0 -0
  47. /package/dist-types/{fixture → agent}/fetch-then.d.ts +0 -0
  48. /package/dist-types/{fixture → agent}/fetch.d.ts +0 -0
  49. /package/dist-types/{fixture → agent}/no-fixture.d.ts +0 -0
  50. /package/dist-types/{fixture → agent}/no-full-response.d.ts +0 -0
  51. /package/dist-types/{fixture → agent}/no-service-wrapper.d.ts +0 -0
  52. /package/dist-types/{fixture → agent}/no-status-code.d.ts +0 -0
  53. /package/dist-types/{fixture → agent}/response-reference.d.ts +0 -0
  54. /package/dist-types/{fixture → agent}/url.d.ts +0 -0
  55. /package/dist-types/{ast → library}/format.d.ts +0 -0
  56. /package/dist-types/{ast → library}/tree.d.ts +0 -0
  57. /package/dist-types/{fixture → library}/variable.d.ts +0 -0
  58. /package/src/{fixture → agent}/fetch-response-body-json.ts +0 -0
  59. /package/src/{fixture → agent}/no-status-code.ts +0 -0
  60. /package/src/{fixture → agent}/url.ts +0 -0
  61. /package/src/{ast → library}/format.ts +0 -0
  62. /package/src/{ast → library}/tree.ts +0 -0
  63. /package/src/{fixture → library}/variable.ts +0 -0
@@ -0,0 +1,199 @@
1
+ // require-resolve-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 { AST_NODE_TYPES, ESLintUtils, TSESTree } from '@typescript-eslint/utils';
10
+ import { DefinitionType, type Scope } from '@typescript-eslint/scope-manager';
11
+ import { PLAIN_URL_REGEXP, TOKENIZED_URL_REGEXP } from './agent/url';
12
+ import { strict as assert } from 'node:assert';
13
+ import getDocumentationUrl from './get-documentation-url';
14
+ import { getEnclosingScopeNode } from './library/ts-tree';
15
+
16
+ export const ruleId = 'require-resolve-full-response';
17
+
18
+ const createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
19
+
20
+ const rule = createRule({
21
+ name: ruleId,
22
+ meta: {
23
+ type: 'suggestion',
24
+ docs: {
25
+ description: 'Prefer native fetch over customized service wrapper.',
26
+ },
27
+ messages: {
28
+ invalidOptions:
29
+ '"options" argument should be provided with "resolveWithFullResponse" property set as "true". Otherwise, it indicates that the response body will be obtained without status code assertion which could result in unexpected issue.',
30
+ unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.',
31
+ },
32
+ schema: [],
33
+ },
34
+ defaultOptions: [],
35
+ create(context) {
36
+ const sourceCode = context.sourceCode;
37
+ const scopeManager = sourceCode.scopeManager;
38
+ const parserService = ESLintUtils.getParserServices(context);
39
+ const typeChecker = parserService.program.getTypeChecker();
40
+
41
+ function isUrlArgumentValid(urlArgument: TSESTree.Node | undefined, scope: Scope) {
42
+ if (
43
+ (urlArgument?.type === AST_NODE_TYPES.Literal && typeof urlArgument.value === 'string') ||
44
+ urlArgument?.type === AST_NODE_TYPES.TemplateLiteral
45
+ ) {
46
+ const urlText = sourceCode.getText(urlArgument);
47
+ return PLAIN_URL_REGEXP.test(urlText) || TOKENIZED_URL_REGEXP.test(urlText);
48
+ }
49
+
50
+ if (urlArgument?.type === AST_NODE_TYPES.Identifier) {
51
+ const foundVariable = scope.variables.find((variable) => variable.name === urlArgument.name);
52
+ if (foundVariable) {
53
+ const variableDefinition = foundVariable.defs.find((def) => def.type === DefinitionType.Variable);
54
+ assert.ok(variableDefinition, `Variable "${urlArgument.name}" not defined in scope`);
55
+ const variableDefinitionNode = variableDefinition.node;
56
+ assert.ok(variableDefinitionNode.type === AST_NODE_TYPES.VariableDeclarator);
57
+ assert.ok(variableDefinitionNode.init, 'Variable definition node has no init property');
58
+ return isUrlArgumentValid(variableDefinitionNode.init, scope);
59
+ }
60
+ }
61
+
62
+ return false;
63
+ }
64
+
65
+ function getType(identifier: TSESTree.Identifier) {
66
+ const variable = parserService.esTreeNodeToTSNodeMap.get(identifier);
67
+ const variableType = typeChecker.getTypeAtLocation(variable);
68
+ return typeChecker.typeToString(variableType);
69
+ }
70
+
71
+ function isServiceLikeName(name: string) {
72
+ return /.*[Ss]ervice$/u.test(name);
73
+ }
74
+
75
+ function isCalleeServiceWrapper(serviceCall: TSESTree.CallExpression) {
76
+ const callee = serviceCall.callee;
77
+ if (callee.type !== AST_NODE_TYPES.MemberExpression) {
78
+ return false;
79
+ }
80
+
81
+ const endpoint = callee.object;
82
+ if (endpoint.type === AST_NODE_TYPES.Identifier) {
83
+ return getType(endpoint) === 'Endpoint' || isServiceLikeName(endpoint.name);
84
+ }
85
+ if (endpoint.type !== AST_NODE_TYPES.CallExpression) {
86
+ return false;
87
+ }
88
+
89
+ const [contextArgument] = endpoint.arguments;
90
+ if (contextArgument?.type !== AST_NODE_TYPES.Identifier) {
91
+ return false;
92
+ }
93
+ if (contextArgument.name !== 'EMPTY_CONTEXT' && getType(contextArgument) !== 'InboundContext') {
94
+ return false;
95
+ }
96
+ const service = endpoint.callee;
97
+ if (service.type === AST_NODE_TYPES.Identifier) {
98
+ return getType(service) === 'ResolvedService';
99
+ }
100
+
101
+ if (service.type !== AST_NODE_TYPES.MemberExpression) {
102
+ return false;
103
+ }
104
+ const services = service.object;
105
+ if (services.type === AST_NODE_TYPES.Identifier) {
106
+ return getType(services) === 'ResolvedServices';
107
+ }
108
+
109
+ if (services.type !== AST_NODE_TYPES.MemberExpression) {
110
+ return false;
111
+ }
112
+ const configuration = services.object;
113
+ if (configuration.type === AST_NODE_TYPES.Identifier) {
114
+ return ['Configuration', 'Configuration<ResolvedServices>'].includes(getType(configuration));
115
+ }
116
+
117
+ // following applies only to test code (fixture)
118
+ if (configuration.type !== AST_NODE_TYPES.MemberExpression) {
119
+ return false;
120
+ }
121
+ const fixture = configuration.object;
122
+ if (fixture.type === AST_NODE_TYPES.Identifier) {
123
+ return fixture.name === 'fixture' || getType(fixture) === 'Fixture';
124
+ }
125
+
126
+ return false;
127
+ }
128
+
129
+ return {
130
+ 'CallExpression[callee.property.name=/^(head|get|put|post|del|patch)$/]': (
131
+ serviceCall: TSESTree.CallExpression,
132
+ ) => {
133
+ try {
134
+ if (!isCalleeServiceWrapper(serviceCall)) {
135
+ return;
136
+ }
137
+
138
+ const enclosingScopeNode = getEnclosingScopeNode(serviceCall);
139
+ assert.ok(enclosingScopeNode, 'enclosingScopeNode is undefined');
140
+ const scope = scopeManager?.acquire(enclosingScopeNode);
141
+ assert.ok(scope, 'scope is undefined');
142
+ const urlArgument = serviceCall.arguments[0];
143
+ if (!isUrlArgumentValid(urlArgument, scope)) {
144
+ return;
145
+ }
146
+
147
+ assert.ok(serviceCall.callee.type === AST_NODE_TYPES.MemberExpression);
148
+ assert.ok(serviceCall.callee.property.type === AST_NODE_TYPES.Identifier);
149
+
150
+ // method
151
+ const method = serviceCall.callee.property.name;
152
+
153
+ // options
154
+ const optionsArgument = ['get', 'head', 'del'].includes(method)
155
+ ? serviceCall.arguments[1]
156
+ : serviceCall.arguments[2];
157
+ if (optionsArgument === undefined || optionsArgument.type !== AST_NODE_TYPES.ObjectExpression) {
158
+ context.report({
159
+ node: serviceCall,
160
+ messageId: 'invalidOptions',
161
+ });
162
+ return;
163
+ }
164
+
165
+ const resolveWithFullResponseProperty = optionsArgument.properties.find(
166
+ (property) =>
167
+ property.type === AST_NODE_TYPES.Property &&
168
+ property.key.type === AST_NODE_TYPES.Identifier &&
169
+ property.key.name === 'resolveWithFullResponse',
170
+ );
171
+ if (
172
+ resolveWithFullResponseProperty?.type !== AST_NODE_TYPES.Property ||
173
+ resolveWithFullResponseProperty.value.type !== AST_NODE_TYPES.Literal ||
174
+ resolveWithFullResponseProperty.value.value !== true
175
+ ) {
176
+ context.report({
177
+ node: optionsArgument,
178
+ messageId: 'invalidOptions',
179
+ });
180
+ return;
181
+ }
182
+ } catch (error) {
183
+ // eslint-disable-next-line no-console
184
+ console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
185
+ context.report({
186
+ node: serviceCall,
187
+ messageId: 'unknownError',
188
+ data: {
189
+ fileName: context.filename,
190
+ error: error instanceof Error ? error.toString() : JSON.stringify(error),
191
+ },
192
+ });
193
+ }
194
+ },
195
+ };
196
+ },
197
+ });
198
+
199
+ export default rule;
@@ -1,14 +0,0 @@
1
- // src/ast/format.ts
2
- import "@typescript-eslint/utils";
3
- import { strict as assert } from "node:assert";
4
- function getIndentation(node, sourceCode) {
5
- assert.ok(node.loc);
6
- const line = sourceCode.lines[node.loc.start.line - 1];
7
- assert.ok(line !== void 0);
8
- const indentMatch = line.match(/^\s*/u);
9
- return indentMatch ? indentMatch[0] : "";
10
- }
11
- export {
12
- getIndentation
13
- };
14
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FzdC9mb3JtYXQudHMiXSwKICAibWFwcGluZ3MiOiAiO0FBUUEsT0FBbUM7QUFHbkMsU0FBUyxVQUFVLGNBQWM7QUFFMUIsU0FBUyxlQUFlLE1BQTRCLFlBQThDO0FBQ3ZHLFNBQU8sR0FBRyxLQUFLLEdBQUc7QUFDbEIsUUFBTSxPQUFPLFdBQVcsTUFBTSxLQUFLLElBQUksTUFBTSxPQUFPLENBQUM7QUFDckQsU0FBTyxHQUFHLFNBQVMsTUFBUztBQUM1QixRQUFNLGNBQWMsS0FBSyxNQUFNLE9BQU87QUFDdEMsU0FBTyxjQUFjLFlBQVksQ0FBQyxJQUFJO0FBQ3hDOyIsCiAgIm5hbWVzIjogW10KfQo=
@@ -1,65 +0,0 @@
1
- // src/ast/ts-tree.ts
2
- import { AST_NODE_TYPES } from "@typescript-eslint/utils";
3
- function getParent(node) {
4
- return node.parent;
5
- }
6
- function getAncestor(node, matcher, exitMatcher) {
7
- const parent = getParent(node);
8
- if (!parent) {
9
- return void 0;
10
- } else if (typeof matcher === "string" && parent.type === matcher) {
11
- return parent;
12
- } else if (typeof matcher === "function" && matcher(parent)) {
13
- return parent;
14
- } else if (typeof exitMatcher === "string" && parent.type === exitMatcher) {
15
- return void 0;
16
- } else if (typeof exitMatcher === "function" && exitMatcher(parent)) {
17
- return void 0;
18
- }
19
- return getAncestor(parent, matcher, exitMatcher);
20
- }
21
- function isBlockStatement(node) {
22
- return node.type.endsWith("Statement") || node.type.endsWith("Declaration");
23
- }
24
- function getEnclosingStatement(node) {
25
- return getAncestor(node, isBlockStatement);
26
- }
27
- function getEnclosingScopeNode(node) {
28
- return getAncestor(
29
- node,
30
- (parentNode) => ["FunctionExpression", "FunctionDeclaration", "ArrowFunctionExpression", "Program"].includes(parentNode.type)
31
- );
32
- }
33
- function isUsedInArrayOrAsArgument(node) {
34
- if (isBlockStatement(node)) {
35
- return false;
36
- }
37
- const parent = getParent(node);
38
- if (!parent) {
39
- return false;
40
- }
41
- if (parent.type === AST_NODE_TYPES.ArrayExpression || parent.type === AST_NODE_TYPES.CallExpression && parent.arguments.includes(node)) {
42
- return true;
43
- }
44
- return isUsedInArrayOrAsArgument(parent);
45
- }
46
- function getEnclosingFunction(node) {
47
- if (node.type === AST_NODE_TYPES.FunctionDeclaration || node.type === AST_NODE_TYPES.FunctionExpression || node.type === AST_NODE_TYPES.ArrowFunctionExpression) {
48
- return node;
49
- }
50
- const parent = getParent(node);
51
- if (!parent) {
52
- return;
53
- }
54
- return getEnclosingFunction(parent);
55
- }
56
- export {
57
- getAncestor,
58
- getEnclosingFunction,
59
- getEnclosingScopeNode,
60
- getEnclosingStatement,
61
- getParent,
62
- isBlockStatement,
63
- isUsedInArrayOrAsArgument
64
- };
65
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FzdC90cy10cmVlLnRzIl0sCiAgIm1hcHBpbmdzIjogIjtBQVFBLFNBQVMsc0JBQWdDO0FBUWxDLFNBQVMsVUFBVSxNQUF1RDtBQUMvRSxTQUFRLEtBQXdDO0FBQ2xEO0FBRU8sU0FBUyxZQUNkLE1BQ0EsU0FDQSxhQUMyQjtBQUMzQixRQUFNLFNBQVMsVUFBVSxJQUFJO0FBQzdCLE1BQUksQ0FBQyxRQUFRO0FBQ1gsV0FBTztBQUFBLEVBQ1QsV0FBVyxPQUFPLFlBQVksWUFBWSxPQUFPLFNBQVMsU0FBUztBQUNqRSxXQUFPO0FBQUEsRUFDVCxXQUFXLE9BQU8sWUFBWSxjQUFjLFFBQVEsTUFBTSxHQUFHO0FBQzNELFdBQU87QUFBQSxFQUNULFdBQVcsT0FBTyxnQkFBZ0IsWUFBWSxPQUFPLFNBQVMsYUFBYTtBQUN6RSxXQUFPO0FBQUEsRUFDVCxXQUFXLE9BQU8sZ0JBQWdCLGNBQWMsWUFBWSxNQUFNLEdBQUc7QUFDbkUsV0FBTztBQUFBLEVBQ1Q7QUFDQSxTQUFPLFlBQVksUUFBUSxTQUFTLFdBQVc7QUFDakQ7QUFFTyxTQUFTLGlCQUFpQixNQUFxQjtBQUNwRCxTQUFPLEtBQUssS0FBSyxTQUFTLFdBQVcsS0FBSyxLQUFLLEtBQUssU0FBUyxhQUFhO0FBQzVFO0FBRU8sU0FBUyxzQkFBc0IsTUFBcUI7QUFDekQsU0FBTyxZQUFZLE1BQU0sZ0JBQWdCO0FBQzNDO0FBRU8sU0FBUyxzQkFBc0IsTUFBcUI7QUFDekQsU0FBTztBQUFBLElBQVk7QUFBQSxJQUFNLENBQUMsZUFDeEIsQ0FBQyxzQkFBc0IsdUJBQXVCLDJCQUEyQixTQUFTLEVBQUUsU0FBUyxXQUFXLElBQUk7QUFBQSxFQUM5RztBQUNGO0FBRU8sU0FBUywwQkFBMEIsTUFBcUI7QUFDN0QsTUFBSSxpQkFBaUIsSUFBSSxHQUFHO0FBQzFCLFdBQU87QUFBQSxFQUNUO0FBRUEsUUFBTSxTQUFTLFVBQVUsSUFBSTtBQUM3QixNQUFJLENBQUMsUUFBUTtBQUNYLFdBQU87QUFBQSxFQUNUO0FBRUEsTUFDRSxPQUFPLFNBQVMsZUFBZSxtQkFDOUIsT0FBTyxTQUFTLGVBQWUsa0JBQWtCLE9BQU8sVUFBVSxTQUFTLElBQTJCLEdBQ3ZHO0FBQ0EsV0FBTztBQUFBLEVBQ1Q7QUFHQSxTQUFPLDBCQUEwQixNQUFNO0FBQ3pDO0FBRU8sU0FBUyxxQkFBcUIsTUFBcUI7QUFDeEQsTUFDRSxLQUFLLFNBQVMsZUFBZSx1QkFDN0IsS0FBSyxTQUFTLGVBQWUsc0JBQzdCLEtBQUssU0FBUyxlQUFlLHlCQUM3QjtBQUNBLFdBQU87QUFBQSxFQUNUO0FBRUEsUUFBTSxTQUFTLFVBQVUsSUFBSTtBQUM3QixNQUFJLENBQUMsUUFBUTtBQUNYO0FBQUEsRUFDRjtBQUNBLFNBQU8scUJBQXFCLE1BQU07QUFDcEM7IiwKICAibmFtZXMiOiBbXQp9Cg==
@@ -1,71 +0,0 @@
1
- // src/fixture/fetch-header-getter.ts
2
- import { analyzeResponseReferences } from "./response-reference.mjs";
3
- import { strict as assert } from "node:assert";
4
- import getDocumentationUrl from "../get-documentation-url.mjs";
5
- import { getParent } from "../ast/tree.mjs";
6
- import { isInvalidResponseHeadersAccess } from "./fetch.mjs";
7
- var ruleId = "fetch-header-getter";
8
- var rule = {
9
- meta: {
10
- type: "problem",
11
- docs: {
12
- description: "Make sure getter is used to access response headers.",
13
- url: getDocumentationUrl(ruleId)
14
- },
15
- messages: {
16
- shouldUseHeaderGetter: "Getter should be used to access response headers."
17
- },
18
- fixable: "code",
19
- schema: []
20
- },
21
- create(context) {
22
- const sourceCode = context.sourceCode;
23
- const scopeManager = sourceCode.scopeManager;
24
- return {
25
- 'VariableDeclarator[init.argument.callee.name="fetch"]': (fetchCall) => {
26
- const variableDeclaration = getParent(fetchCall);
27
- assert.ok(variableDeclaration?.type === "VariableDeclaration");
28
- const { variable: responseVariable, headersReferences: responseHeadersReferences } = analyzeResponseReferences(
29
- variableDeclaration,
30
- scopeManager
31
- );
32
- assert.ok(responseVariable);
33
- const directHeadersReferences = responseHeadersReferences.filter((headersReference) => {
34
- const headersAccess = getParent(headersReference);
35
- return headersAccess?.type !== "VariableDeclarator";
36
- });
37
- const indirectHeadersReferences = responseHeadersReferences.map(getParent).filter((parent) => parent?.type === "VariableDeclarator").map((declarator) => declarator.id.name).map((redefinedHeadersVariableName) => {
38
- const headersVariable = responseVariable.scope.variables.find((variable) => {
39
- const identifier = variable.identifiers[0];
40
- return identifier?.type === "Identifier" && identifier.name === redefinedHeadersVariableName;
41
- });
42
- return headersVariable?.references.map((reference) => reference.identifier) ?? [];
43
- }).flat();
44
- const invalidHeadersReferences = [...directHeadersReferences, ...indirectHeadersReferences].filter(
45
- isInvalidResponseHeadersAccess
46
- );
47
- invalidHeadersReferences.forEach((headersReference) => {
48
- const headerAccess = getParent(headersReference);
49
- if (headerAccess?.type === "MemberExpression") {
50
- const headerNameNode = headerAccess.property;
51
- const headerName = headerAccess.computed ? sourceCode.getText(headerNameNode) : `'${sourceCode.getText(headerNameNode)}'`;
52
- const replacementText = `${sourceCode.getText(headerAccess.object)}.get(${headerName})`;
53
- context.report({
54
- node: headerAccess,
55
- messageId: "shouldUseHeaderGetter",
56
- fix(fixer) {
57
- return fixer.replaceText(headerAccess, replacementText);
58
- }
59
- });
60
- }
61
- });
62
- }
63
- };
64
- }
65
- };
66
- var fetch_header_getter_default = rule;
67
- export {
68
- fetch_header_getter_default as default,
69
- ruleId
70
- };
71
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2ZpeHR1cmUvZmV0Y2gtaGVhZGVyLWdldHRlci50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFVQSxTQUFTLGlDQUFpQztBQUMxQyxTQUFTLFVBQVUsY0FBYztBQUNqQyxPQUFPLHlCQUF5QjtBQUNoQyxTQUFTLGlCQUFpQjtBQUMxQixTQUFTLHNDQUFzQztBQUV4QyxJQUFNLFNBQVM7QUFFdEIsSUFBTSxPQUF3QjtBQUFBLEVBQzVCLE1BQU07QUFBQSxJQUNKLE1BQU07QUFBQSxJQUNOLE1BQU07QUFBQSxNQUNKLGFBQWE7QUFBQSxNQUNiLEtBQUssb0JBQW9CLE1BQU07QUFBQSxJQUNqQztBQUFBLElBQ0EsVUFBVTtBQUFBLE1BQ1IsdUJBQXVCO0FBQUEsSUFDekI7QUFBQSxJQUNBLFNBQVM7QUFBQSxJQUNULFFBQVEsQ0FBQztBQUFBLEVBQ1g7QUFBQSxFQUNBLE9BQU8sU0FBUztBQUNkLFVBQU0sYUFBYSxRQUFRO0FBQzNCLFVBQU0sZUFBZSxXQUFXO0FBRWhDLFdBQU87QUFBQSxNQUNMLHlEQUF5RCxDQUFDLGNBQWtDO0FBQzFGLGNBQU0sc0JBQXNCLFVBQVUsU0FBUztBQUMvQyxlQUFPLEdBQUcscUJBQXFCLFNBQVMscUJBQXFCO0FBQzdELGNBQU0sRUFBRSxVQUFVLGtCQUFrQixtQkFBbUIsMEJBQTBCLElBQUk7QUFBQSxVQUNuRjtBQUFBLFVBQ0E7QUFBQSxRQUNGO0FBQ0EsZUFBTyxHQUFHLGdCQUFnQjtBQUUxQixjQUFNLDBCQUEwQiwwQkFBMEIsT0FBTyxDQUFDLHFCQUFxQjtBQUNyRixnQkFBTSxnQkFBZ0IsVUFBVSxnQkFBZ0I7QUFDaEQsaUJBQU8sZUFBZSxTQUFTO0FBQUEsUUFDakMsQ0FBQztBQUVELGNBQU0sNEJBQTRCLDBCQUMvQixJQUFJLFNBQVMsRUFDYixPQUFPLENBQUMsV0FBeUMsUUFBUSxTQUFTLG9CQUFvQixFQUN0RixJQUFJLENBQUMsZUFBZ0IsV0FBVyxHQUFrQixJQUFJLEVBQ3RELElBQUksQ0FBQyxpQ0FBaUM7QUFDckMsZ0JBQU0sa0JBQWtCLGlCQUFpQixNQUFNLFVBQVUsS0FBSyxDQUFDLGFBQWE7QUFDMUUsa0JBQU0sYUFBYSxTQUFTLFlBQVksQ0FBQztBQUN6QyxtQkFBTyxZQUFZLFNBQVMsZ0JBQWdCLFdBQVcsU0FBUztBQUFBLFVBQ2xFLENBQUM7QUFDRCxpQkFBTyxpQkFBaUIsV0FBVyxJQUFJLENBQUMsY0FBYyxVQUFVLFVBQVUsS0FBSyxDQUFDO0FBQUEsUUFDbEYsQ0FBQyxFQUNBLEtBQUs7QUFFUixjQUFNLDJCQUEyQixDQUFDLEdBQUcseUJBQXlCLEdBQUcseUJBQXlCLEVBQUU7QUFBQSxVQUMxRjtBQUFBLFFBQ0Y7QUFFQSxpQ0FBeUIsUUFBUSxDQUFDLHFCQUFxQjtBQUNyRCxnQkFBTSxlQUFlLFVBQVUsZ0JBQWdCO0FBQy9DLGNBQUksY0FBYyxTQUFTLG9CQUFvQjtBQUM3QyxrQkFBTSxpQkFBaUIsYUFBYTtBQUNwQyxrQkFBTSxhQUFhLGFBQWEsV0FDNUIsV0FBVyxRQUFRLGNBQWMsSUFDakMsSUFBSSxXQUFXLFFBQVEsY0FBYyxDQUFDO0FBQzFDLGtCQUFNLGtCQUFrQixHQUFHLFdBQVcsUUFBUSxhQUFhLE1BQU0sQ0FBQyxRQUFRLFVBQVU7QUFFcEYsb0JBQVEsT0FBTztBQUFBLGNBQ2IsTUFBTTtBQUFBLGNBQ04sV0FBVztBQUFBLGNBQ1gsSUFBSSxPQUFPO0FBQ1QsdUJBQU8sTUFBTSxZQUFZLGNBQWMsZUFBZTtBQUFBLGNBQ3hEO0FBQUEsWUFDRixDQUFDO0FBQUEsVUFDSDtBQUFBLFFBQ0YsQ0FBQztBQUFBLE1BQ0g7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUNGO0FBRUEsSUFBTyw4QkFBUTsiLAogICJuYW1lcyI6IFtdCn0K
@@ -1,110 +0,0 @@
1
- // src/fixture/fetch-response-header-getter-ts.ts
2
- import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
3
- import getDocumentationUrl from "../get-documentation-url.mjs";
4
- var ruleId = "fetch-response-header-getter-ts";
5
- var createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
6
- var rule = createRule({
7
- name: ruleId,
8
- meta: {
9
- type: "suggestion",
10
- docs: {
11
- description: 'Use "get()" method to get header value from the headers object of the fetch response.'
12
- },
13
- messages: {
14
- useGetter: 'Use "get()" method to get header value from the headers object of the fetch response.',
15
- unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.'
16
- },
17
- fixable: "code",
18
- schema: []
19
- },
20
- defaultOptions: [],
21
- create(context) {
22
- const parserServices = ESLintUtils.getParserServices(context);
23
- const typeChecker = parserServices.program.getTypeChecker();
24
- const sourceCode = context.sourceCode;
25
- return {
26
- 'MemberExpression[object.property.name="headers"]': (responseHeadersAccess) => {
27
- try {
28
- if (responseHeadersAccess.property.type === AST_NODE_TYPES.Identifier && responseHeadersAccess.property.name === "get") {
29
- return;
30
- }
31
- const responseHeadersTsNode = parserServices.esTreeNodeToTSNodeMap.get(responseHeadersAccess.object);
32
- const responseType = typeChecker.getTypeAtLocation(responseHeadersTsNode);
33
- const shouldReplace = responseType.getProperties().some((symbol) => symbol.name === "get");
34
- if (!shouldReplace) {
35
- return;
36
- }
37
- let replacementText;
38
- if (responseHeadersAccess.property.type === AST_NODE_TYPES.Identifier) {
39
- replacementText = `${sourceCode.getText(responseHeadersAccess.object)}.get(${sourceCode.getText(responseHeadersAccess.property)})`;
40
- } else if (responseHeadersAccess.property.type === AST_NODE_TYPES.TemplateLiteral) {
41
- replacementText = `${sourceCode.getText(responseHeadersAccess.object)}.get(${sourceCode.getText(responseHeadersAccess.property)})`;
42
- } else if (responseHeadersAccess.property.type === AST_NODE_TYPES.Literal) {
43
- replacementText = responseHeadersAccess.computed ? `${sourceCode.getText(responseHeadersAccess.object)}.get(${sourceCode.getText(responseHeadersAccess.property)})` : `${sourceCode.getText(responseHeadersAccess.object)}.get('${sourceCode.getText(responseHeadersAccess.property)}')`;
44
- } else {
45
- throw new Error(`Unexpected property type: ${responseHeadersAccess.property.type}`);
46
- }
47
- context.report({
48
- messageId: "useGetter",
49
- node: responseHeadersAccess.property,
50
- fix(fixer) {
51
- return fixer.replaceText(responseHeadersAccess, replacementText);
52
- }
53
- });
54
- } catch (error) {
55
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
56
- context.report({
57
- node: responseHeadersAccess,
58
- messageId: "unknownError",
59
- data: {
60
- fileName: context.filename,
61
- error: error instanceof Error ? error.toString() : JSON.stringify(error)
62
- }
63
- });
64
- }
65
- },
66
- 'CallExpression[callee.property.name="get"]:not([callee.object.name="request"])': (responseHeadersAccess) => {
67
- try {
68
- if (responseHeadersAccess.callee.type !== AST_NODE_TYPES.MemberExpression) {
69
- return;
70
- }
71
- const responseNode = responseHeadersAccess.callee.object;
72
- const responseHeadersTsNode = parserServices.esTreeNodeToTSNodeMap.get(responseNode);
73
- const responseType = typeChecker.getTypeAtLocation(responseHeadersTsNode);
74
- const typeName = typeChecker.typeToString(responseType);
75
- if (typeName === "InboundContext" || typeName.endsWith("RequestType")) {
76
- return;
77
- }
78
- const hasHeadersProperty = responseType.getProperties().some((symbol) => symbol.name === "headers");
79
- if (!hasHeadersProperty) {
80
- return;
81
- }
82
- const replacementText = `${sourceCode.getText(responseNode)}.headers`;
83
- context.report({
84
- messageId: "useGetter",
85
- node: responseHeadersAccess,
86
- fix(fixer) {
87
- return fixer.replaceText(responseNode, replacementText);
88
- }
89
- });
90
- } catch (error) {
91
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
92
- context.report({
93
- node: responseHeadersAccess,
94
- messageId: "unknownError",
95
- data: {
96
- fileName: context.filename,
97
- error: error instanceof Error ? error.toString() : JSON.stringify(error)
98
- }
99
- });
100
- }
101
- }
102
- };
103
- }
104
- });
105
- var fetch_response_header_getter_ts_default = rule;
106
- export {
107
- fetch_response_header_getter_ts_default as default,
108
- ruleId
109
- };
110
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2ZpeHR1cmUvZmV0Y2gtcmVzcG9uc2UtaGVhZGVyLWdldHRlci10cy50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFRQSxTQUFTLGdCQUFnQixtQkFBNkI7QUFDdEQsT0FBTyx5QkFBeUI7QUFFekIsSUFBTSxTQUFTO0FBRXRCLElBQU0sYUFBYSxZQUFZLFlBQVksQ0FBQyxTQUFTLG9CQUFvQixJQUFJLENBQUM7QUFFOUUsSUFBTSxPQUFPLFdBQVc7QUFBQSxFQUN0QixNQUFNO0FBQUEsRUFDTixNQUFNO0FBQUEsSUFDSixNQUFNO0FBQUEsSUFDTixNQUFNO0FBQUEsTUFDSixhQUFhO0FBQUEsSUFDZjtBQUFBLElBQ0EsVUFBVTtBQUFBLE1BQ1IsV0FBVztBQUFBLE1BQ1gsY0FBYztBQUFBLElBQ2hCO0FBQUEsSUFDQSxTQUFTO0FBQUEsSUFDVCxRQUFRLENBQUM7QUFBQSxFQUNYO0FBQUEsRUFDQSxnQkFBZ0IsQ0FBQztBQUFBLEVBQ2pCLE9BQU8sU0FBUztBQUNkLFVBQU0saUJBQWlCLFlBQVksa0JBQWtCLE9BQU87QUFDNUQsVUFBTSxjQUFjLGVBQWUsUUFBUSxlQUFlO0FBQzFELFVBQU0sYUFBYSxRQUFRO0FBRTNCLFdBQU87QUFBQSxNQUNMLG9EQUFvRCxDQUFDLDBCQUFxRDtBQUN4RyxZQUFJO0FBQ0YsY0FDRSxzQkFBc0IsU0FBUyxTQUFTLGVBQWUsY0FDdkQsc0JBQXNCLFNBQVMsU0FBUyxPQUN4QztBQUVBO0FBQUEsVUFDRjtBQUVBLGdCQUFNLHdCQUF3QixlQUFlLHNCQUFzQixJQUFJLHNCQUFzQixNQUFNO0FBQ25HLGdCQUFNLGVBQWUsWUFBWSxrQkFBa0IscUJBQXFCO0FBRXhFLGdCQUFNLGdCQUFnQixhQUFhLGNBQWMsRUFBRSxLQUFLLENBQUMsV0FBVyxPQUFPLFNBQVMsS0FBSztBQUN6RixjQUFJLENBQUMsZUFBZTtBQUNsQjtBQUFBLFVBQ0Y7QUFNQSxjQUFJO0FBQ0osY0FBSSxzQkFBc0IsU0FBUyxTQUFT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
@@ -1,12 +0,0 @@
1
- // src/fixture/ts-tree.ts
2
- import { AST_NODE_TYPES } from "@typescript-eslint/utils";
3
- function getTypeParentNode(node) {
4
- if (!node) {
5
- return void 0;
6
- }
7
- return node.type === AST_NODE_TYPES.TSTypeAnnotation || node.type === AST_NODE_TYPES.TSAsExpression ? node : getTypeParentNode(node.parent);
8
- }
9
- export {
10
- getTypeParentNode
11
- };
12
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2ZpeHR1cmUvdHMtdHJlZS50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFFQSxTQUFTLHNCQUFnQztBQUVsQyxTQUFTLGtCQUNkLE1BQ2lFO0FBQ2pFLE1BQUksQ0FBQyxNQUFNO0FBQ1QsV0FBTztBQUFBLEVBQ1Q7QUFDQSxTQUFPLEtBQUssU0FBUyxlQUFlLG9CQUFvQixLQUFLLFNBQVMsZUFBZSxpQkFDakYsT0FDQSxrQkFBa0IsS0FBSyxNQUFNO0FBQ25DOyIsCiAgIm5hbWVzIjogW10KfQo=
@@ -1,4 +0,0 @@
1
- import type { Rule } from 'eslint';
2
- export declare const ruleId = "fetch-header-getter";
3
- declare const rule: Rule.RuleModule;
4
- export default rule;
@@ -1,2 +0,0 @@
1
- import { TSESTree } from '@typescript-eslint/utils';
2
- export declare function getTypeParentNode(node: TSESTree.Node | undefined): TSESTree.TSTypeAnnotation | TSESTree.TSAsExpression | undefined;
@@ -1,91 +0,0 @@
1
- // fixture/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 { Identifier, VariableDeclarator } from 'estree';
10
- import type { Rule } from 'eslint';
11
- import { analyzeResponseReferences } from './response-reference';
12
- import { strict as assert } from 'node:assert';
13
- import getDocumentationUrl from '../get-documentation-url';
14
- import { getParent } from '../ast/tree';
15
- import { isInvalidResponseHeadersAccess } from './fetch';
16
-
17
- export const ruleId = 'fetch-header-getter';
18
-
19
- const rule: Rule.RuleModule = {
20
- meta: {
21
- type: 'problem',
22
- docs: {
23
- description: 'Make sure getter is used to access response headers.',
24
- url: getDocumentationUrl(ruleId),
25
- },
26
- messages: {
27
- shouldUseHeaderGetter: 'Getter should be used to access response headers.',
28
- },
29
- fixable: 'code',
30
- schema: [],
31
- },
32
- create(context) {
33
- const sourceCode = context.sourceCode;
34
- const scopeManager = sourceCode.scopeManager;
35
-
36
- return {
37
- 'VariableDeclarator[init.argument.callee.name="fetch"]': (fetchCall: VariableDeclarator) => {
38
- const variableDeclaration = getParent(fetchCall);
39
- assert.ok(variableDeclaration?.type === 'VariableDeclaration');
40
- const { variable: responseVariable, headersReferences: responseHeadersReferences } = analyzeResponseReferences(
41
- variableDeclaration,
42
- scopeManager,
43
- );
44
- assert.ok(responseVariable);
45
-
46
- const directHeadersReferences = responseHeadersReferences.filter((headersReference) => {
47
- const headersAccess = getParent(headersReference);
48
- return headersAccess?.type !== 'VariableDeclarator';
49
- });
50
-
51
- const indirectHeadersReferences = responseHeadersReferences
52
- .map(getParent)
53
- .filter((parent): parent is VariableDeclarator => parent?.type === 'VariableDeclarator')
54
- .map((declarator) => (declarator.id as Identifier).name)
55
- .map((redefinedHeadersVariableName) => {
56
- const headersVariable = responseVariable.scope.variables.find((variable) => {
57
- const identifier = variable.identifiers[0];
58
- return identifier?.type === 'Identifier' && identifier.name === redefinedHeadersVariableName;
59
- });
60
- return headersVariable?.references.map((reference) => reference.identifier) ?? [];
61
- })
62
- .flat();
63
-
64
- const invalidHeadersReferences = [...directHeadersReferences, ...indirectHeadersReferences].filter(
65
- isInvalidResponseHeadersAccess,
66
- );
67
-
68
- invalidHeadersReferences.forEach((headersReference) => {
69
- const headerAccess = getParent(headersReference);
70
- if (headerAccess?.type === 'MemberExpression') {
71
- const headerNameNode = headerAccess.property;
72
- const headerName = headerAccess.computed
73
- ? sourceCode.getText(headerNameNode)
74
- : `'${sourceCode.getText(headerNameNode)}'`;
75
- const replacementText = `${sourceCode.getText(headerAccess.object)}.get(${headerName})`;
76
-
77
- context.report({
78
- node: headerAccess,
79
- messageId: 'shouldUseHeaderGetter',
80
- fix(fixer) {
81
- return fixer.replaceText(headerAccess, replacementText);
82
- },
83
- });
84
- }
85
- });
86
- },
87
- };
88
- },
89
- };
90
-
91
- export default rule;
@@ -1,14 +0,0 @@
1
- // fixture/ts-tree.ts
2
-
3
- import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
4
-
5
- export function getTypeParentNode(
6
- node: TSESTree.Node | undefined,
7
- ): TSESTree.TSTypeAnnotation | TSESTree.TSAsExpression | undefined {
8
- if (!node) {
9
- return undefined;
10
- }
11
- return node.type === AST_NODE_TYPES.TSTypeAnnotation || node.type === AST_NODE_TYPES.TSAsExpression
12
- ? node
13
- : getTypeParentNode(node.parent);
14
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes