@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,184 +0,0 @@
1
- // src/agent/no-service-wrapper.ts
2
- import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
3
- import { DefinitionType } from "@typescript-eslint/scope-manager";
4
- import { PLAIN_URL_REGEXP, TOKENIZED_URL_REGEXP, replaceEndpointUrlPrefixWithDomain } from "./url.mjs";
5
- import { strict as assert } from "node:assert";
6
- import getDocumentationUrl from "../get-documentation-url.mjs";
7
- import { getEnclosingScopeNode } from "../library/ts-tree.mjs";
8
- import { getIndentation } from "../library/format.mjs";
9
- var ruleId = "no-service-wrapper";
10
- var createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
11
- var rule = createRule({
12
- name: ruleId,
13
- meta: {
14
- type: "suggestion",
15
- docs: {
16
- description: "Prefer native fetch over customized service wrapper."
17
- },
18
- messages: {
19
- preferNativeFetch: "Prefer native fetch over customized service wrapper.",
20
- invalidOptions: '"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. Please manually convert the usage of customized service wrapper call to native fetch.',
21
- unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}. Please manually convert the usage of customized service wrapper call to native fetch.'
22
- },
23
- fixable: "code",
24
- schema: []
25
- },
26
- defaultOptions: [],
27
- create(context) {
28
- const sourceCode = context.sourceCode;
29
- const scopeManager = sourceCode.scopeManager;
30
- const parserService = ESLintUtils.getParserServices(context);
31
- const typeChecker = parserService.program.getTypeChecker();
32
- function isUrlArgumentValid(urlArgument, scope) {
33
- if (urlArgument?.type === AST_NODE_TYPES.Literal && typeof urlArgument.value === "string" || urlArgument?.type === AST_NODE_TYPES.TemplateLiteral) {
34
- const urlText = sourceCode.getText(urlArgument);
35
- return PLAIN_URL_REGEXP.test(urlText) || TOKENIZED_URL_REGEXP.test(urlText);
36
- }
37
- if (urlArgument?.type === AST_NODE_TYPES.Identifier) {
38
- const foundVariable = scope.variables.find((variable) => variable.name === urlArgument.name);
39
- if (foundVariable) {
40
- const variableDefinition = foundVariable.defs.find((def) => def.type === DefinitionType.Variable);
41
- assert.ok(variableDefinition, `Variable "${urlArgument.name}" not defined in scope`);
42
- const variableDefinitionNode = variableDefinition.node;
43
- assert.ok(variableDefinitionNode.type === AST_NODE_TYPES.VariableDeclarator);
44
- assert.ok(variableDefinitionNode.init, "Variable definition node has no init property");
45
- return isUrlArgumentValid(variableDefinitionNode.init, scope);
46
- }
47
- }
48
- return false;
49
- }
50
- function getType(identifier) {
51
- const variable = parserService.esTreeNodeToTSNodeMap.get(identifier);
52
- const variableType = typeChecker.getTypeAtLocation(variable);
53
- return typeChecker.typeToString(variableType);
54
- }
55
- function isServiceLikeName(name) {
56
- return /.*[Ss]ervice$/u.test(name);
57
- }
58
- function isCalleeServiceWrapper(serviceCall) {
59
- const callee = serviceCall.callee;
60
- if (callee.type !== AST_NODE_TYPES.MemberExpression) {
61
- return false;
62
- }
63
- const endpoint = callee.object;
64
- if (endpoint.type === AST_NODE_TYPES.Identifier) {
65
- return getType(endpoint) === "Endpoint" || isServiceLikeName(endpoint.name);
66
- }
67
- if (endpoint.type !== AST_NODE_TYPES.CallExpression) {
68
- return false;
69
- }
70
- const [contextArgument] = endpoint.arguments;
71
- if (contextArgument?.type !== AST_NODE_TYPES.Identifier) {
72
- return false;
73
- }
74
- if (contextArgument.name !== "EMPTY_CONTEXT" && getType(contextArgument) !== "InboundContext") {
75
- return false;
76
- }
77
- const service = endpoint.callee;
78
- if (service.type === AST_NODE_TYPES.Identifier) {
79
- return getType(service) === "ResolvedService";
80
- }
81
- if (service.type !== AST_NODE_TYPES.MemberExpression) {
82
- return false;
83
- }
84
- const services = service.object;
85
- if (services.type === AST_NODE_TYPES.Identifier) {
86
- return getType(services) === "ResolvedServices";
87
- }
88
- if (services.type !== AST_NODE_TYPES.MemberExpression) {
89
- return false;
90
- }
91
- const configuration = services.object;
92
- if (configuration.type === AST_NODE_TYPES.Identifier) {
93
- return ["Configuration", "Configuration<ResolvedServices>"].includes(getType(configuration));
94
- }
95
- if (configuration.type !== AST_NODE_TYPES.MemberExpression) {
96
- return false;
97
- }
98
- const fixture = configuration.object;
99
- if (fixture.type === AST_NODE_TYPES.Identifier) {
100
- return fixture.name === "fixture" || getType(fixture) === "Fixture";
101
- }
102
- return false;
103
- }
104
- return {
105
- "CallExpression[callee.property.name=/^(head|get|put|post|del|patch)$/]": (serviceCall) => {
106
- try {
107
- if (!isCalleeServiceWrapper(serviceCall)) {
108
- return;
109
- }
110
- const enclosingScopeNode = getEnclosingScopeNode(serviceCall);
111
- assert.ok(enclosingScopeNode, "enclosingScopeNode is undefined");
112
- const scope = scopeManager?.acquire(enclosingScopeNode);
113
- assert.ok(scope, "scope is undefined");
114
- const urlArgument = serviceCall.arguments[0];
115
- if (!isUrlArgumentValid(urlArgument, scope)) {
116
- return;
117
- }
118
- assert.ok(serviceCall.callee.type === AST_NODE_TYPES.MemberExpression);
119
- assert.ok(serviceCall.callee.property.type === AST_NODE_TYPES.Identifier);
120
- const method = serviceCall.callee.property.name;
121
- let requestBodyProperty = ["put", "post", "options"].includes(method) ? serviceCall.arguments[1] : void 0;
122
- if (requestBodyProperty !== void 0 && requestBodyProperty.type === AST_NODE_TYPES.Identifier && requestBodyProperty.name === "undefined") {
123
- requestBodyProperty = void 0;
124
- }
125
- const optionsArgument = ["get", "head", "del"].includes(method) ? serviceCall.arguments[1] : serviceCall.arguments[2];
126
- if (optionsArgument === void 0 || optionsArgument.type !== AST_NODE_TYPES.ObjectExpression) {
127
- context.report({
128
- node: serviceCall,
129
- messageId: "invalidOptions"
130
- });
131
- return;
132
- }
133
- const resolveWithFullResponseProperty = optionsArgument.properties.find(
134
- (property) => property.type === AST_NODE_TYPES.Property && property.key.type === AST_NODE_TYPES.Identifier && property.key.name === "resolveWithFullResponse"
135
- );
136
- if (resolveWithFullResponseProperty?.type !== AST_NODE_TYPES.Property || resolveWithFullResponseProperty.value.type !== AST_NODE_TYPES.Literal || resolveWithFullResponseProperty.value.value !== true) {
137
- context.report({
138
- node: optionsArgument,
139
- messageId: "invalidOptions"
140
- });
141
- return;
142
- }
143
- const requestHeadersProperty = optionsArgument.properties.find(
144
- (property) => property.type === AST_NODE_TYPES.Property && property.key.type === AST_NODE_TYPES.Identifier && property.key.name === "headers"
145
- );
146
- context.report({
147
- messageId: "preferNativeFetch",
148
- node: serviceCall,
149
- fix(fixer) {
150
- const url = sourceCode.getText(urlArgument);
151
- const replacedUrl = replaceEndpointUrlPrefixWithDomain(url);
152
- const indentation = getIndentation(serviceCall, sourceCode);
153
- const fetchText = [
154
- `fetch(${replacedUrl}, {`,
155
- ` method: '${method.toLowerCase() === "del" ? "DELETE" : method.toUpperCase()}',`,
156
- ...requestHeadersProperty ? [` ${sourceCode.getText(requestHeadersProperty)},`] : [],
157
- ...requestBodyProperty ? [` body: JSON.stringify(${sourceCode.getText(requestBodyProperty)}),`] : [],
158
- "})"
159
- ].join(`
160
- ${indentation}`);
161
- return fixer.replaceText(serviceCall, fetchText);
162
- }
163
- });
164
- } catch (error) {
165
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
166
- context.report({
167
- node: serviceCall,
168
- messageId: "unknownError",
169
- data: {
170
- fileName: context.filename,
171
- error: error instanceof Error ? error.toString() : JSON.stringify(error)
172
- }
173
- });
174
- }
175
- }
176
- };
177
- }
178
- });
179
- var no_service_wrapper_default = rule;
180
- export {
181
- no_service_wrapper_default as default,
182
- ruleId
183
- };
184
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FnZW50L25vLXNlcnZpY2Utd3JhcHBlci50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFRQSxTQUFTLGdCQUFnQixtQkFBNkI7QUFDdEQsU0FBUyxzQkFBa0M7QUFDM0MsU0FBUyxrQkFBa0Isc0JBQXNCLDBDQUEwQztBQUMzRixTQUFTLFVBQVUsY0FBYztBQUNqQyxPQUFPLHlCQUF5QjtBQUNoQyxTQUFTLDZCQUE2QjtBQUN0QyxTQUFTLHNCQUFzQjtBQUV4QixJQUFNLFNBQVM7QUFFdEIsSUFBTSxhQUFhLFlBQVksWUFBWSxDQUFDLFNBQVMsb0JBQW9CLElBQUksQ0FBQztBQUU5RSxJQUFNLE9BQU8sV0FBVztBQUFBLEVBQ3RCLE1BQU07QUFBQSxFQUNOLE1BQU07QUFBQSxJQUNKLE1BQU07QUFBQSxJQUNOLE1BQU07QUFBQSxNQUNKLGFBQWE7QUFBQSxJQUNmO0FBQUEsSUFDQSxVQUFVO0FBQUEsTUFDUixtQkFBbUI7QUFBQSxNQUNuQixnQkFDRTtBQUFBLE1BQ0YsY0FDRTtBQUFBLElBQ0o7QUFBQSxJQUNBLFNBQVM7QUFBQSxJQUNULFFBQVEsQ0FBQztBQUFBLEVBQ1g7QUFBQSxFQUNBLGdCQUFnQixDQUFDO0FBQUEsRUFDakIsT0FBTyxTQUFTO0FBQ2QsVUFBTSxhQUFhLFFBQVE7QUFDM0IsVUFBTSxlQUFlLFdBQVc7QUFDaEMsVUFBTSxnQkFBZ0IsWUFBWSxrQkFBa0IsT0FBTztBQUMzRCxVQUFNLGNBQWMsY0FBYyxRQUFRLGVBQWU7QUFFekQsYUFBUyxtQkFBbUIsYUFBd0MsT0FBYztBQUNoRixVQUNHLGFBQWEsU0FBUyxlQUFlLFdBQVcsT0FBTyxZQUFZLFVBQVUsWUFDOUUsYUFBYSxTQUFTLGVBQWUsaUJBQ3JDO0FBQ0EsY0FBTSxVQUFVLFdBQVcsUUFBUSxXQUFXO0FBQzlDLGVBQU8saUJBQWlCLEtBQUssT0FBTyxLQUFLLHFCQUFxQixLQUFLLE9BQU87QUFBQSxNQUM1RTtBQUVBLFVBQUksYUFBYSxTQUFTLGVB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
@@ -1,59 +0,0 @@
1
- // src/agent/no-status-code.ts
2
- import { ESLintUtils } from "@typescript-eslint/utils";
3
- import getDocumentationUrl from "../get-documentation-url.mjs";
4
- var ruleId = "no-status-code";
5
- var createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
6
- var rule = createRule({
7
- name: ruleId,
8
- meta: {
9
- type: "suggestion",
10
- docs: {
11
- description: 'Access the status code property of the fetch Response using "status" instead of "statusCode".'
12
- },
13
- messages: {
14
- replaceStatusCode: 'Replace "statusCode" with "status".',
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
- return {
25
- 'MemberExpression[property.name="statusCode"]': (responseStatusCode) => {
26
- try {
27
- const responseNode = parserServices.esTreeNodeToTSNodeMap.get(responseStatusCode.object);
28
- const responseType = typeChecker.getTypeAtLocation(responseNode);
29
- const shouldReplace = responseType.getProperties().some((symbol) => symbol.name === "status") && !responseType.getProperties().some((symbol) => symbol.name === "statusCode");
30
- if (shouldReplace) {
31
- context.report({
32
- messageId: "replaceStatusCode",
33
- node: responseStatusCode.property,
34
- fix(fixer) {
35
- return fixer.replaceText(responseStatusCode.property, "status");
36
- }
37
- });
38
- }
39
- } catch (error) {
40
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
41
- context.report({
42
- node: responseStatusCode,
43
- messageId: "unknownError",
44
- data: {
45
- fileName: context.filename,
46
- error: error instanceof Error ? error.toString() : JSON.stringify(error)
47
- }
48
- });
49
- }
50
- }
51
- };
52
- }
53
- });
54
- var no_status_code_default = rule;
55
- export {
56
- no_status_code_default as default,
57
- ruleId
58
- };
59
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FnZW50L25vLXN0YXR1cy1jb2RlLnRzIl0sCiAgIm1hcHBpbmdzIjogIjtBQVFBLFNBQVMsbUJBQTZCO0FBQ3RDLE9BQU8seUJBQXlCO0FBRXpCLElBQU0sU0FBUztBQUV0QixJQUFNLGFBQWEsWUFBWSxZQUFZLENBQUMsU0FBUyxvQkFBb0IsSUFBSSxDQUFDO0FBRTlFLElBQU0sT0FBTyxXQUFXO0FBQUEsRUFDdEIsTUFBTTtBQUFBLEVBQ04sTUFBTTtBQUFBLElBQ0osTUFBTTtBQUFBLElBQ04sTUFBTTtBQUFBLE1BQ0osYUFBYTtBQUFBLElBQ2Y7QUFBQSxJQUNBLFVBQVU7QUFBQSxNQUNSLG1CQUFtQjtBQUFBLE1BQ25CLGNBQWM7QUFBQSxJQUNoQjtBQUFBLElBQ0EsU0FBUztBQUFBLElBQ1QsUUFBUSxDQUFDO0FBQUEsRUFDWDtBQUFBLEVBQ0EsZ0JBQWdCLENBQUM7QUFBQSxFQUNqQixPQUFPLFNBQVM7QUFDZCxVQUFNLGlCQUFpQixZQUFZLGtCQUFrQixPQUFPO0FBQzVELFVBQU0sY0FBYyxlQUFlLFFBQVEsZUFBZTtBQUUxRCxXQUFPO0FBQUEsTUFDTCxnREFBZ0QsQ0FBQyx1QkFBa0Q7QUFDakcsWUFBSTtBQUNGLGdCQUFNLGVBQWUsZUFBZSxzQkFBc0IsSUFBSSxtQkFBbUIsTUFBTTtBQUN2RixnQkFBTSxlQUFlLFlBQVksa0JBQWtCLFlBQVk7QUFFL0QsZ0JBQU0sZ0JBQ0osYUFBYSxjQUFjLEVBQUUsS0FBSyxDQUFDLFdBQVcsT0FBTyxTQUFTLFFBQVEsS0FDdEUsQ0FBQyxhQUFhLGNBQWMsRUFBRSxLQUFLLENBQUMsV0FBVyxPQUFPLFNBQVMsWUFBWTtBQUU3RSxjQUFJLGVBQWU7QUFDakIsb0JBQVEsT0FBTztBQUFBLGNBQ2IsV0FBVztBQUFBLGNBQ1gsTUFBTSxtQkFBbUI7QUFBQSxjQUN6QixJQUFJLE9BQU87QUFDVCx1QkFBTyxNQUFNLFlBQVksbUJBQW1CLFVBQVUsUUFBUTtBQUFBLGNBQ2hFO0FBQUEsWUFDRixDQUFDO0FBQUEsVUFDSDtBQUFBLFFBQ0YsU0FBUyxPQUFPO0FBRWQsa0JBQVEsTUFBTSxtQkFBbUIsTUFBTSxtQkFBbUIsUUFBUSxRQUFRLE1BQU0sS0FBSztBQUNyRixrQkFBUSxPQUFPO0FBQUEsWUFDYixNQUFNO0FBQUEsWUFDTixXQUFXO0FBQUEsWUFDWCxNQUFNO0FBQUEsY0FDSixVQUFVLFFBQVE7QUFBQSxjQUNsQixPQUFPLGlCQUFpQixRQUFRLE1BQU0sU0FBUyxJQUFJLEtBQUssVUFBVSxLQUFLO0FBQUEsWUFDekU7QUFBQSxVQUNGLENBQUM7QUFBQSxRQUNIO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFBQSxFQUNGO0FBQ0YsQ0FBQztBQUVELElBQU8seUJBQVE7IiwKICAibmFtZXMiOiBbXQp9Cg==
@@ -1,56 +0,0 @@
1
- // src/agent/response-reference.ts
2
- import "eslint";
3
- import { strict as assert } from "node:assert";
4
- import { getParent } from "../library/tree.mjs";
5
- function analyzeResponseReferences(variableDeclaration, scopeManager) {
6
- const results = {
7
- bodyReferences: [],
8
- headersReferences: [],
9
- statusReferences: []
10
- };
11
- if (!variableDeclaration) {
12
- return results;
13
- }
14
- const responseVariables = scopeManager.getDeclaredVariables(variableDeclaration);
15
- for (const responseVariable of responseVariables) {
16
- const identifier = responseVariable.identifiers[0];
17
- assert.ok(identifier);
18
- const identifierParent = getParent(identifier);
19
- assert.ok(identifierParent);
20
- if (identifierParent.type === "VariableDeclarator") {
21
- results.variable = responseVariable;
22
- const responseReferences = responseVariable.references.map(
23
- (responseReference) => getParent(responseReference.identifier)
24
- );
25
- results.bodyReferences = responseReferences.filter(
26
- (node) => node?.type === "MemberExpression" && node.property.type === "Identifier" && node.property.name === "body"
27
- );
28
- results.headersReferences = responseReferences.filter(
29
- (node) => node?.type === "MemberExpression" && node.property.type === "Identifier" && (node.property.name === "header" || node.property.name === "headers" || node.property.name === "get")
30
- );
31
- results.statusReferences = responseReferences.filter(
32
- (node) => node?.type === "MemberExpression" && node.property.type === "Identifier" && (node.property.name === "status" || node.property.name === "statusCode")
33
- );
34
- } else if (
35
- // body reference through destruction/renaming, e.g. "const { body } = ..."
36
- identifierParent.type === "Property" && identifierParent.key.type === "Identifier" && identifierParent.key.name === "body"
37
- ) {
38
- results.destructuringBodyVariable = responseVariable;
39
- } else if (
40
- // header reference through destruction/renaming, e.g. "const { headers } = ..."
41
- identifierParent.type === "Property" && identifierParent.key.type === "Identifier" && identifierParent.key.name === "headers"
42
- ) {
43
- results.destructuringHeadersVariable = responseVariable;
44
- results.destructuringHeadersReferences = responseVariable.references.map((reference) => reference.identifier).map(getParent).filter(
45
- (parent) => parent?.type === "MemberExpression" && parent.property.type === "Identifier" && parent.property.name !== "get" && getParent(parent)?.type !== "CallExpression"
46
- );
47
- } else {
48
- throw new Error(`Unknown response variable reference: ${responseVariable.name}`);
49
- }
50
- }
51
- return results;
52
- }
53
- export {
54
- analyzeResponseReferences
55
- };
56
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FnZW50L3Jlc3BvbnNlLXJlZmVyZW5jZS50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFTQSxPQUEyQjtBQUMzQixTQUFTLFVBQVUsY0FBYztBQUNqQyxTQUFTLGlCQUFpQjtBQU9uQixTQUFTLDBCQUNkLHFCQUNBLGNBQ0E7QUFDQSxRQUFNLFVBUUY7QUFBQSxJQUNGLGdCQUFnQixDQUFDO0FBQUEsSUFDakIsbUJBQW1CLENBQUM7QUFBQSxJQUNwQixrQkFBa0IsQ0FBQztBQUFBLEVBQ3JCO0FBQ0EsTUFBSSxDQUFDLHFCQUFxQjtBQUN4QixXQUFPO0FBQUEsRUFDVDtBQUVBLFFBQU0sb0JBQW9CLGFBQWEscUJBQXFCLG1CQUFtQjtBQUMvRSxhQUFXLG9CQUFvQixtQkFBbUI7QUFDaEQsVUFBTSxhQUFhLGlCQUFpQixZQUFZLENBQUM7QUFDakQsV0FBTyxHQUFHLFVBQVU7QUFDcEIsVUFBTSxtQkFBbUIsVUFBVSxVQUFVO0FBQzdDLFdBQU8sR0FBRyxnQkFBZ0I7QUFDMUIsUUFBSSxpQkFBaUIsU0FBUyxzQkFBc0I7QUFFbEQsY0FBUSxXQUFXO0FBQ25CLFlBQU0scUJBQXFCLGlCQUFpQixXQUFXO0FBQUEsUUFBSSxDQUFDLHNCQUMxRCxVQUFVLGtCQUFrQixVQUFVO0FBQUEsTUFDeEM7QUFFQSxjQUFRLGlCQUFpQixtQkFBbUI7QUFBQSxRQUMxQyxDQUFDLFNBQ0MsTUFBTSxTQUFTLHNCQUFzQixLQUFLLFNBQVMsU0FBUyxnQkFBZ0IsS0FBSyxTQUFTLFNBQVM7QUFBQSxNQUN2RztBQUVBLGNBQVEsb0JBQW9CLG1CQUFtQjtBQUFBLFFBQzdDLENBQUMsU0FDQyxNQUFNLFNBQVMsc0JBQ2YsS0FBSyxTQUFTLFNBQVMsaUJBQ3RCLEtBQUssU0FBUyxTQUFTLFlBQVksS0FBSyxTQUFTLFNBQVMsYUFBYSxLQUFLLFNBQVMsU0FBUztBQUFBLE1BQ25HO0FBRUEsY0FBUSxtQkFBbUIsbUJBQW1CO0FBQUEsUUFDNUMsQ0FBQyxTQUNDLE1BQU0sU0FBUyxzQkFDZixLQUFLLFNBQVMsU0FBUyxpQkFDdEIsS0FBSyxTQUFTLFNBQVMsWUFBWSxLQUFLLFNBQVMsU0FBUztBQUFBLE1BQy9EO0FBQUEsSUFDRjtBQUFBO0FBQUEsTUFFRSxpQkFBaUIsU0FBUyxjQUMxQixpQkFBaUIsSUFBSSxTQUFTLGdCQUM5QixpQkFBaUIsSUFBSSxTQUFTO0FBQUEsTUFDOUI7QUFDQSxjQUFRLDRCQUE0QjtBQUFBLElBQ3RDO0FBQUE7QUFBQSxNQUVFLGlCQUFpQixTQUFTLGNBQzFCLGlCQUFpQixJQUFJLFNBQVMsZ0JBQzlCLGlCQUFpQixJQUFJLFNBQVM7QUFBQSxNQUM5QjtBQUNBLGNBQVEsK0JBQStCO0FBQ3ZDLGNBQVEsaUNBQWlDLGlCQUFpQixXQUN2RCxJQUFJLENBQUMsY0FBYyxVQUFVLFVBQVUsRUFDdkMsSUFBSSxTQUFTLEVBQ2I7QUFBQSxRQUNDLENBQUMsV0FDQyxRQUFRLFNBQVMsc0JBQ2pCLE9BQU8sU0FBUyxTQUFTLGdCQUN6QixPQUFPLFNBQVMsU0FBUyxTQUN6QixVQUFVLE1BQU0sR0FBRyxTQUFTO0FBQUEsTUFDaEM7QUFBQSxJQUNKLE9BQU87QUFDTCxZQUFNLElBQUksTUFBTSx3Q0FBd0MsaUJBQWlCLElBQUksRUFBRTtBQUFBLElBQ2pGO0FBQUEsRUFDRjtBQUNBLFNBQU87QUFDVDsiLAogICJuYW1lcyI6IFtdCn0K
@@ -1,26 +0,0 @@
1
- // src/agent/url.ts
2
- var PLAIN_URL_REGEXP = /^[`']\/\w+(?<serviceNamePart>-\w+)*\/v\d+\/(?<any>.|\r|\n)+[`']$/u;
3
- var TOKENIZED_URL_REGEXP = /^`\$\{(?<serviceNamePart>[A-Z]+_)*BASE_PATH\}\/(?<any>.|\r|\n)+`$/u;
4
- function replaceEndpointUrlPrefixWithBasePath(url) {
5
- return url.replace(/^`\/\w+(?<parts>-\w+)*\/v\d+\//u, "`${BASE_PATH}/");
6
- }
7
- function replaceEndpointUrlPrefixWithDomain(url) {
8
- return url.replace(
9
- /^(?<quotStart>[`'])\/(?<servicename>\w+(?<parts>-\w+)*)(?<path>\/v\d+\/(?<any>.|\r|\n)+(?<quotEnd>[`'])$)/u,
10
- "$1https://$2.checkdigit/$2$4"
11
- );
12
- }
13
- function addBasePathUrlDomain(url) {
14
- return url.replace(
15
- /^(?<quotStart>[`'])\/(?<servicename>\w+(?<parts>-\w+)*)(?<path>\/v\d+(?<quotEnd>[`'])$)/u,
16
- "$1https://$2.checkdigit/$2$4"
17
- );
18
- }
19
- export {
20
- PLAIN_URL_REGEXP,
21
- TOKENIZED_URL_REGEXP,
22
- addBasePathUrlDomain,
23
- replaceEndpointUrlPrefixWithBasePath,
24
- replaceEndpointUrlPrefixWithDomain
25
- };
26
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FnZW50L3VybC50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFFTyxJQUFNLG1CQUFtQjtBQUN6QixJQUFNLHVCQUF1QjtBQUU3QixTQUFTLHFDQUFxQyxLQUFhO0FBRWhFLFNBQU8sSUFBSSxRQUFRLG1DQUFtQyxnQkFBZ0I7QUFDeEU7QUFFTyxTQUFTLG1DQUFtQyxLQUFhO0FBQzlELFNBQU8sSUFBSTtBQUFBLElBQ1Q7QUFBQSxJQUNBO0FBQUEsRUFDRjtBQUNGO0FBRU8sU0FBUyxxQkFBcUIsS0FBYTtBQUNoRCxTQUFPLElBQUk7QUFBQSxJQUNUO0FBQUEsSUFDQTtBQUFBLEVBQ0Y7QUFDRjsiLAogICJuYW1lcyI6IFtdCn0K
@@ -1,4 +0,0 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- export declare const ruleId = "add-url-domain";
3
- declare const rule: ESLintUtils.RuleModule<"addDomain" | "unknownError", never[], ESLintUtils.RuleListener>;
4
- export default rule;
@@ -1,4 +0,0 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- export declare const ruleId = "fetch-response-body-json";
3
- declare const rule: ESLintUtils.RuleModule<"unknownError" | "replaceBodyWithJson", never[], ESLintUtils.RuleListener>;
4
- export default rule;
@@ -1,4 +0,0 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- export declare const ruleId = "fetch-response-header-getter-ts";
3
- declare const rule: ESLintUtils.RuleModule<"unknownError" | "useGetter", never[], ESLintUtils.RuleListener>;
4
- export default rule;
@@ -1,4 +0,0 @@
1
- import { type Rule } from 'eslint';
2
- export declare const ruleId = "fetch-then";
3
- declare const rule: Rule.RuleModule;
4
- export default rule;
@@ -1,4 +0,0 @@
1
- import type { Node } from 'estree';
2
- export declare function getResponseBodyRetrievalText(responseVariableName: string): string;
3
- export declare function isInvalidResponseHeadersAccess(responseHeadersAccess: Node): boolean;
4
- export declare function hasAssertions(fixtureCall: Node): boolean;
@@ -1,4 +0,0 @@
1
- import { type Rule } from 'eslint';
2
- export declare const ruleId = "no-fixture";
3
- declare const rule: Rule.RuleModule;
4
- export default rule;
@@ -1,4 +0,0 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- export declare const ruleId = "no-full-response";
3
- declare const rule: ESLintUtils.RuleModule<"unknownError" | "removeFullResponse", never[], ESLintUtils.RuleListener>;
4
- export default rule;
@@ -1,4 +0,0 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- export declare const ruleId = "no-mapped-response";
3
- declare const rule: ESLintUtils.RuleModule<"unknownError" | "replaceFullResponseWithFetchResponse", never[], ESLintUtils.RuleListener>;
4
- export default rule;
@@ -1,4 +0,0 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- export declare const ruleId = "no-service-wrapper";
3
- declare const rule: ESLintUtils.RuleModule<"unknownError" | "preferNativeFetch" | "invalidOptions", never[], ESLintUtils.RuleListener>;
4
- export default rule;
@@ -1,4 +0,0 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- export declare const ruleId = "no-status-code";
3
- declare const rule: ESLintUtils.RuleModule<"unknownError" | "replaceStatusCode", never[], ESLintUtils.RuleListener>;
4
- export default rule;
@@ -1,16 +0,0 @@
1
- import type { MemberExpression, VariableDeclaration } from 'estree';
2
- import { type Scope } from 'eslint';
3
- /**
4
- * analyze response related variables and their references
5
- * the implementation is for fixture API, but it can be used for fetch API as well since the tree structure is similar
6
- * @param variableDeclaration - variable declaration node
7
- */
8
- export declare function analyzeResponseReferences(variableDeclaration: VariableDeclaration | undefined, scopeManager: Scope.ScopeManager): {
9
- variable?: Scope.Variable;
10
- bodyReferences: MemberExpression[];
11
- headersReferences: MemberExpression[];
12
- statusReferences: MemberExpression[];
13
- destructuringBodyVariable?: Scope.Variable;
14
- destructuringHeadersVariable?: Scope.Variable;
15
- destructuringHeadersReferences?: MemberExpression[] | undefined;
16
- };
@@ -1,5 +0,0 @@
1
- export declare const PLAIN_URL_REGEXP: RegExp;
2
- export declare const TOKENIZED_URL_REGEXP: RegExp;
3
- export declare function replaceEndpointUrlPrefixWithBasePath(url: string): string;
4
- export declare function replaceEndpointUrlPrefixWithDomain(url: string): string;
5
- export declare function addBasePathUrlDomain(url: string): string;
@@ -1,75 +0,0 @@
1
- // fixture/add-url-domain.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 { addBasePathUrlDomain } from './url';
11
- import getDocumentationUrl from '../get-documentation-url';
12
-
13
- export const ruleId = 'add-url-domain';
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: 'Add HTTP domain to the BASE_PATH like url constant variable.',
23
- },
24
- messages: {
25
- addDomain: 'Add HTTP domain to the BASE_PATH like url constant variable.',
26
- unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.',
27
- },
28
- fixable: 'code',
29
- schema: [],
30
- },
31
- defaultOptions: [],
32
- create(context) {
33
- const sourceCode = context.sourceCode;
34
-
35
- return {
36
- 'VariableDeclarator[id.name=/^([A-Z]+_)*BASE_PATH$/]': (basePathDeclarator: TSESTree.VariableDeclarator) => {
37
- try {
38
- if (
39
- basePathDeclarator.init === null ||
40
- (basePathDeclarator.init.type !== AST_NODE_TYPES.Literal &&
41
- basePathDeclarator.init.type !== AST_NODE_TYPES.TemplateLiteral)
42
- ) {
43
- return;
44
- }
45
-
46
- const urlText = sourceCode.getText(basePathDeclarator.init);
47
- const replacement = addBasePathUrlDomain(urlText);
48
-
49
- if (replacement !== urlText) {
50
- context.report({
51
- messageId: 'addDomain',
52
- node: basePathDeclarator.init,
53
- fix(fixer) {
54
- return fixer.replaceText(basePathDeclarator.init as TSESTree.Node, replacement);
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: basePathDeclarator,
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,76 +0,0 @@
1
- // fixture/fetch-response-body-json.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-body-json';
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 "response.body" with "await response.json()".',
22
- },
23
- messages: {
24
- replaceBodyWithJson: 'Replace "response.body" with "await response.json()".',
25
- unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.',
26
- },
27
- fixable: 'code',
28
- schema: [],
29
- },
30
- defaultOptions: [],
31
- create(context) {
32
- const parserServices = ESLintUtils.getParserServices(context);
33
- const typeChecker = parserServices.program.getTypeChecker();
34
- const sourceCode = context.sourceCode;
35
-
36
- return {
37
- 'MemberExpression[property.name="body"]': (responseBody: TSESTree.MemberExpression) => {
38
- try {
39
- const responseNode = parserServices.esTreeNodeToTSNodeMap.get(responseBody.object);
40
- const responseType = typeChecker.getTypeAtLocation(responseNode);
41
-
42
- const shouldReplace =
43
- responseType.getProperties().some((symbol) => symbol.name === 'body') &&
44
- responseType.getProperties().some((symbol) => symbol.name === 'json');
45
-
46
- if (shouldReplace) {
47
- const responseText = sourceCode.getText(responseBody.object);
48
- const needAwait = responseBody.parent.type !== AST_NODE_TYPES.ReturnStatement;
49
- const replacementText = needAwait ? `(await ${responseText}.json())` : `${responseText}.json()`;
50
-
51
- context.report({
52
- messageId: 'replaceBodyWithJson',
53
- node: responseBody,
54
- fix(fixer) {
55
- return fixer.replaceText(responseBody, replacementText);
56
- },
57
- });
58
- }
59
- } catch (error) {
60
- // eslint-disable-next-line no-console
61
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
62
- context.report({
63
- node: responseBody,
64
- messageId: 'unknownError',
65
- data: {
66
- fileName: context.filename,
67
- error: error instanceof Error ? error.toString() : JSON.stringify(error),
68
- },
69
- });
70
- }
71
- },
72
- };
73
- },
74
- });
75
-
76
- export default rule;