@checkdigit/eslint-plugin 6.6.0-PR.75-0dbb → 6.6.0-PR.75-3712
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.
- package/dist-cjs/index.cjs +9929 -394
- package/dist-cjs/metafile.json +4715 -10
- package/dist-mjs/ast/format.mjs +2 -1
- package/dist-mjs/ast/ts-tree.mjs +65 -0
- package/dist-mjs/fixture/no-service-wrapper.mjs +154 -0
- package/dist-mjs/index.mjs +6 -3
- package/dist-types/ast/format.d.ts +2 -1
- package/dist-types/ast/ts-tree.d.ts +8 -0
- package/dist-types/fixture/no-service-wrapper.d.ts +4 -0
- package/dist-types/index.d.ts +2 -0
- package/package.json +1 -1
- package/src/ast/format.ts +2 -1
- package/src/ast/ts-tree.ts +90 -0
- package/src/fixture/no-service-wrapper.ts +223 -0
- package/src/index.ts +3 -0
package/dist-mjs/ast/format.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/ast/format.ts
|
|
2
|
+
import "@typescript-eslint/utils";
|
|
2
3
|
import { strict as assert } from "node:assert";
|
|
3
4
|
function getIndentation(node, sourceCode) {
|
|
4
5
|
assert.ok(node.loc);
|
|
@@ -10,4 +11,4 @@ function getIndentation(node, sourceCode) {
|
|
|
10
11
|
export {
|
|
11
12
|
getIndentation
|
|
12
13
|
};
|
|
13
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FzdC9mb3JtYXQudHMiXSwKICAibWFwcGluZ3MiOiAiO0FBUUEsT0FBbUM7QUFHbkMsU0FBUyxVQUFVLGNBQWM7QUFFMUIsU0FBUyxlQUFlLE1BQTRCLFlBQThDO0FBQ3ZHLFNBQU8sR0FBRyxLQUFLLEdBQUc7QUFDbEIsUUFBTSxPQUFPLFdBQVcsTUFBTSxLQUFLLElBQUksTUFBTSxPQUFPLENBQUM7QUFDckQsU0FBTyxHQUFHLFNBQVMsTUFBUztBQUM1QixRQUFNLGNBQWMsS0FBSyxNQUFNLE9BQU87QUFDdEMsU0FBTyxjQUFjLFlBQVksQ0FBQyxJQUFJO0FBQ3hDOyIsCiAgIm5hbWVzIjogW10KfQo=
|
|
@@ -0,0 +1,65 @@
|
|
|
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==
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// src/fixture/no-service-wrapper.ts
|
|
2
|
+
import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
|
|
3
|
+
import "@typescript-eslint/scope-manager";
|
|
4
|
+
import { strict as assert } from "node:assert";
|
|
5
|
+
import getDocumentationUrl from "../get-documentation-url.mjs";
|
|
6
|
+
import { getEnclosingScopeNode } from "../ast/ts-tree.mjs";
|
|
7
|
+
import { getIndentation } from "../ast/format.mjs";
|
|
8
|
+
var ruleId = "no-service-wrapper";
|
|
9
|
+
var createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
|
|
10
|
+
var rule = createRule({
|
|
11
|
+
name: ruleId,
|
|
12
|
+
meta: {
|
|
13
|
+
type: "suggestion",
|
|
14
|
+
docs: {
|
|
15
|
+
description: "Prefer native fetch over customized service wrapper."
|
|
16
|
+
},
|
|
17
|
+
messages: {
|
|
18
|
+
preferNativeFetch: "Prefer native fetch over customized service wrapper.",
|
|
19
|
+
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.'
|
|
20
|
+
// unknownError:
|
|
21
|
+
// '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
|
+
// eslint-disable-next-line max-lines-per-function
|
|
28
|
+
create(context) {
|
|
29
|
+
const sourceCode = context.sourceCode;
|
|
30
|
+
const scopeManager = sourceCode.scopeManager;
|
|
31
|
+
const parserService = ESLintUtils.getParserServices(context);
|
|
32
|
+
const typeChecker = parserService.program.getTypeChecker();
|
|
33
|
+
function isUrlArgumentTemplateLiteral(urlArgument, scope) {
|
|
34
|
+
return urlArgument?.type === AST_NODE_TYPES.TemplateLiteral || urlArgument?.type === AST_NODE_TYPES.Identifier && scope.variables.some((variable) => variable.name === urlArgument.name);
|
|
35
|
+
}
|
|
36
|
+
function getType(identifier) {
|
|
37
|
+
const variable = parserService.esTreeNodeToTSNodeMap.get(identifier);
|
|
38
|
+
const variableType = typeChecker.getTypeAtLocation(variable);
|
|
39
|
+
return typeChecker.typeToString(variableType);
|
|
40
|
+
}
|
|
41
|
+
function isServiceLikeName(name) {
|
|
42
|
+
return /.*[Ss]ervice$/u.test(name);
|
|
43
|
+
}
|
|
44
|
+
function isCalleeServiceWrapper(serviceCall) {
|
|
45
|
+
const callee = serviceCall.callee;
|
|
46
|
+
if (callee.type !== AST_NODE_TYPES.MemberExpression) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const endpoint = callee.object;
|
|
50
|
+
if (endpoint.type === AST_NODE_TYPES.Identifier) {
|
|
51
|
+
return getType(endpoint) === "Endpoint" || isServiceLikeName(endpoint.name);
|
|
52
|
+
}
|
|
53
|
+
if (endpoint.type !== AST_NODE_TYPES.CallExpression) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const [contextArgument] = endpoint.arguments;
|
|
57
|
+
if (contextArgument?.type !== AST_NODE_TYPES.Identifier) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
if (contextArgument.name !== "EMPTY_CONTEXT" && getType(contextArgument) !== "InboundContext") {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
const service = endpoint.callee;
|
|
64
|
+
if (service.type === AST_NODE_TYPES.Identifier) {
|
|
65
|
+
return getType(service) === "ResolvedService";
|
|
66
|
+
}
|
|
67
|
+
if (service.type !== AST_NODE_TYPES.MemberExpression) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
const services = service.object;
|
|
71
|
+
if (services.type === AST_NODE_TYPES.Identifier) {
|
|
72
|
+
return getType(services) === "ResolvedServices";
|
|
73
|
+
}
|
|
74
|
+
if (services.type !== AST_NODE_TYPES.MemberExpression) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
const configuration = services.object;
|
|
78
|
+
if (configuration.type === AST_NODE_TYPES.Identifier) {
|
|
79
|
+
return getType(configuration) === "Configuration";
|
|
80
|
+
}
|
|
81
|
+
if (configuration.type !== AST_NODE_TYPES.MemberExpression) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
const fixture = configuration.object;
|
|
85
|
+
if (fixture.type === AST_NODE_TYPES.Identifier) {
|
|
86
|
+
return fixture.name === "fixture" || getType(fixture) === "Fixture";
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
"CallExpression[callee.property.name=/^(head|get|put|post|del|patch)$/]": (serviceCall) => {
|
|
92
|
+
const enclosingScopeNode = getEnclosingScopeNode(serviceCall);
|
|
93
|
+
assert.ok(enclosingScopeNode, "enclosingScopeNode is undefined");
|
|
94
|
+
const scope = scopeManager?.acquire(enclosingScopeNode);
|
|
95
|
+
assert.ok(scope, "scope is undefined");
|
|
96
|
+
const urlArgument = serviceCall.arguments[0];
|
|
97
|
+
if (!isUrlArgumentTemplateLiteral(urlArgument, scope)) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (!isCalleeServiceWrapper(serviceCall)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
assert.ok(serviceCall.callee.type === AST_NODE_TYPES.MemberExpression);
|
|
104
|
+
assert.ok(serviceCall.callee.property.type === AST_NODE_TYPES.Identifier);
|
|
105
|
+
const method = serviceCall.callee.property.name;
|
|
106
|
+
const requestBodyProperty = ["put", "post", "options"].includes(method) ? serviceCall.arguments[1] : void 0;
|
|
107
|
+
const optionsArgument = ["get", "head", "del"].includes(method) ? serviceCall.arguments[1] : serviceCall.arguments[2];
|
|
108
|
+
if (optionsArgument === void 0 || optionsArgument.type !== AST_NODE_TYPES.ObjectExpression) {
|
|
109
|
+
context.report({
|
|
110
|
+
node: serviceCall,
|
|
111
|
+
messageId: "invalidOptions"
|
|
112
|
+
});
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const resolveWithFullResponseProperty = optionsArgument.properties.find(
|
|
116
|
+
(property) => property.type === AST_NODE_TYPES.Property && property.key.type === AST_NODE_TYPES.Identifier && property.key.name === "resolveWithFullResponse"
|
|
117
|
+
);
|
|
118
|
+
if (resolveWithFullResponseProperty?.type !== AST_NODE_TYPES.Property || resolveWithFullResponseProperty.value.type !== AST_NODE_TYPES.Literal || resolveWithFullResponseProperty.value.value !== true) {
|
|
119
|
+
context.report({
|
|
120
|
+
node: optionsArgument,
|
|
121
|
+
messageId: "invalidOptions"
|
|
122
|
+
});
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const requestHeadersProperty = optionsArgument.properties.find(
|
|
126
|
+
(property) => property.type === AST_NODE_TYPES.Property && property.key.type === AST_NODE_TYPES.Identifier && property.key.name === "headers"
|
|
127
|
+
);
|
|
128
|
+
context.report({
|
|
129
|
+
messageId: "preferNativeFetch",
|
|
130
|
+
node: serviceCall,
|
|
131
|
+
fix(fixer) {
|
|
132
|
+
const url = sourceCode.getText(urlArgument);
|
|
133
|
+
const indentation = getIndentation(serviceCall, sourceCode);
|
|
134
|
+
const fetchText = [
|
|
135
|
+
`fetch(${url}, {`,
|
|
136
|
+
` method: '${method.toUpperCase()}',`,
|
|
137
|
+
...requestHeadersProperty ? [` ${sourceCode.getText(requestHeadersProperty)},`] : [],
|
|
138
|
+
...requestBodyProperty ? [` body: JSON.stringify(${sourceCode.getText(requestBodyProperty)}),`] : [],
|
|
139
|
+
"})"
|
|
140
|
+
].join(`
|
|
141
|
+
${indentation}`);
|
|
142
|
+
return fixer.replaceText(serviceCall, fetchText);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
var no_service_wrapper_default = rule;
|
|
150
|
+
export {
|
|
151
|
+
no_service_wrapper_default as default,
|
|
152
|
+
ruleId
|
|
153
|
+
};
|
|
154
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2ZpeHR1cmUvbm8tc2VydmljZS13cmFwcGVyLnRzIl0sCiAgIm1hcHBpbmdzIjogIjtBQVFBLFNBQVMsZ0JBQWdCLG1CQUE2QjtBQUN0RCxPQUEyQjtBQUMzQixTQUFTLFVBQVUsY0FBYztBQUNqQyxPQUFPLHlCQUF5QjtBQUNoQyxTQUFTLDZCQUE2QjtBQUN0QyxTQUFTLHNCQUFzQjtBQUV4QixJQUFNLFNBQVM7QUFjdEIsSUFBTSxhQUFhLFlBQVksWUFBWSxDQUFDLFNBQVMsb0JBQW9CLElBQUksQ0FBQztBQUU5RSxJQUFNLE9BQU8sV0FBVztBQUFBLEVBQ3RCLE1BQU07QUFBQSxFQUNOLE1BQU07QUFBQSxJQUNKLE1BQU07QUFBQSxJQUNOLE1BQU07QUFBQSxNQUNKLGFBQWE7QUFBQSxJQUNmO0FBQUEsSUFDQSxVQUFVO0FBQUEsTUFDUixtQkFBbUI7QUFBQSxNQUNuQixnQkFDRTtBQUFBO0FBQUE7QUFBQSxJQUdKO0FBQUEsSUFDQSxTQUFTO0FBQUEsSUFDVCxRQUFRLENBQUM7QUFBQSxFQUNYO0FBQUEsRUFDQSxnQkFBZ0IsQ0FBQztBQUFBO0FBQUEsRUFFakIsT0FBTyxTQUFTO0FBQ2QsVUFBTSxhQUFhLFFBQVE7QUFDM0IsVUFBTSxlQUFlLFdBQVc7QUFDaEMsVUFBTSxnQkFBZ0IsWUFBWSxrQkFBa0IsT0FBTztBQUMzRCxVQUFNLGNBQWMsY0FBYyxRQUFRLGVBQWU7QUFVekQsYUFBUyw2QkFBNkIsYUFBd0MsT0FBYztBQUMxRixhQUNFLGFBQWEsU0FBUyxlQUFlLG1CQUNwQyxhQUFhLFNBQVMsZUFBZSxjQUNwQyxNQUFNLFVBQVUsS0FBSyxDQUFDLGFBQWEsU0FBUyxTQUFTLFlBQVksSUFBSTtBQUFBLElBRTNFO0FBRUEsYUFBUyxRQUFRLFlBQWlDO0FBQ2hELFlBQU0sV0FBVyxjQUFjLHNCQUFzQixJQUFJLFVBQVU7QUFDbkUsWUFBTSxlQUFlLFlBQVksa0JBQWtCLFFBQVE7QUFDM0QsYUFBTyxZQUFZLGFBQWEs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
|
package/dist-mjs/index.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import fetchThen, { ruleId as fetchThenRuleId } from "./fixture/fetch-then.mjs";
|
|
|
4
4
|
import invalidJsonStringify, { ruleId as invalidJsonStringifyRuleId } from "./invalid-json-stringify.mjs";
|
|
5
5
|
import noFixture, { ruleId as noFixtureRuleId } from "./fixture/no-fixture.mjs";
|
|
6
6
|
import noPromiseInstanceMethod, { ruleId as noPromiseInstanceMethodRuleId } from "./no-promise-instance-method.mjs";
|
|
7
|
+
import noServiceWrapper, { ruleId as noServiceWrapperRuleId } from "./fixture/no-service-wrapper.mjs";
|
|
7
8
|
import filePathComment from "./file-path-comment.mjs";
|
|
8
9
|
import noCardNumbers from "./no-card-numbers.mjs";
|
|
9
10
|
import noTestImport from "./no-test-import.mjs";
|
|
@@ -28,7 +29,8 @@ var src_default = {
|
|
|
28
29
|
[noPromiseInstanceMethodRuleId]: noPromiseInstanceMethod,
|
|
29
30
|
[noFixtureRuleId]: noFixture,
|
|
30
31
|
[fetchHeaderGetterRuleId]: fetchHeaderGetter,
|
|
31
|
-
[fetchThenRuleId]: fetchThen
|
|
32
|
+
[fetchThenRuleId]: fetchThen,
|
|
33
|
+
[noServiceWrapperRuleId]: noServiceWrapper
|
|
32
34
|
},
|
|
33
35
|
configs: {
|
|
34
36
|
all: {
|
|
@@ -46,7 +48,8 @@ var src_default = {
|
|
|
46
48
|
[`@checkdigit/${noPromiseInstanceMethodRuleId}`]: "error",
|
|
47
49
|
[`@checkdigit/${noFixtureRuleId}`]: "error",
|
|
48
50
|
[`@checkdigit/${fetchHeaderGetterRuleId}`]: "error",
|
|
49
|
-
[`@checkdigit/${fetchThenRuleId}`]: "error"
|
|
51
|
+
[`@checkdigit/${fetchThenRuleId}`]: "error",
|
|
52
|
+
[`@checkdigit/${noServiceWrapperRuleId}`]: "error"
|
|
50
53
|
}
|
|
51
54
|
},
|
|
52
55
|
recommended: {
|
|
@@ -69,4 +72,4 @@ var src_default = {
|
|
|
69
72
|
export {
|
|
70
73
|
src_default as default
|
|
71
74
|
};
|
|
72
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
75
|
+
//# sourceMappingURL=data:application/json;base64,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
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TSESLint, TSESTree } from '@typescript-eslint/utils';
|
|
1
2
|
import type { Node } from 'estree';
|
|
2
3
|
import type { SourceCode } from 'eslint';
|
|
3
|
-
export declare function getIndentation(node: Node, sourceCode: SourceCode): string;
|
|
4
|
+
export declare function getIndentation(node: Node | TSESTree.Node, sourceCode: SourceCode | TSESLint.SourceCode): string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
export declare function getParent(node: TSESTree.Node): TSESTree.Node | undefined | null;
|
|
3
|
+
export declare function getAncestor(node: TSESTree.Node, matcher: AST_NODE_TYPES | ((testNode: TSESTree.Node) => boolean), exitMatcher?: AST_NODE_TYPES | ((testNode: TSESTree.Node) => boolean)): TSESTree.Node | undefined;
|
|
4
|
+
export declare function isBlockStatement(node: TSESTree.Node): boolean;
|
|
5
|
+
export declare function getEnclosingStatement(node: TSESTree.Node): TSESTree.Node | undefined;
|
|
6
|
+
export declare function getEnclosingScopeNode(node: TSESTree.Node): TSESTree.Node | undefined;
|
|
7
|
+
export declare function isUsedInArrayOrAsArgument(node: TSESTree.Node): boolean;
|
|
8
|
+
export declare function getEnclosingFunction(node: TSESTree.Node): TSESTree.ArrowFunctionExpression | TSESTree.FunctionDeclarationWithOptionalName | TSESTree.FunctionExpression | undefined;
|
package/dist-types/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ declare const _default: {
|
|
|
14
14
|
"no-fixture": import("eslint").Rule.RuleModule;
|
|
15
15
|
"fetch-header-getter": import("eslint").Rule.RuleModule;
|
|
16
16
|
"fetch-then": import("eslint").Rule.RuleModule;
|
|
17
|
+
"no-service-wrapper": import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferNativeFetch" | "invalidOptions", never[], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
17
18
|
};
|
|
18
19
|
configs: {
|
|
19
20
|
all: {
|
|
@@ -32,6 +33,7 @@ declare const _default: {
|
|
|
32
33
|
"@checkdigit/no-fixture": string;
|
|
33
34
|
"@checkdigit/fetch-header-getter": string;
|
|
34
35
|
"@checkdigit/fetch-then": string;
|
|
36
|
+
"@checkdigit/no-service-wrapper": string;
|
|
35
37
|
};
|
|
36
38
|
};
|
|
37
39
|
recommended: {
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@checkdigit/eslint-plugin","version":"6.6.0-PR.75-
|
|
1
|
+
{"name":"@checkdigit/eslint-plugin","version":"6.6.0-PR.75-3712","description":"Check Digit eslint plugins","keywords":["eslint","eslintplugin"],"homepage":"https://github.com/checkdigit/eslint-plugin#readme","bugs":{"url":"https://github.com/checkdigit/eslint-plugin/issues"},"repository":{"type":"git","url":"https://github.com/checkdigit/eslint-plugin"},"license":"MIT","author":"Check Digit, LLC","sideEffects":false,"type":"module","exports":{".":{"types":"./dist-types/index.d.ts","require":"./dist-cjs/index.cjs","import":"./dist-mjs/index.mjs","default":"./dist-mjs/index.mjs"}},"files":["src","dist-types","dist-cjs","dist-mjs","!src/**/*.test.ts","!src/**/*.spec.ts","!dist-types/**/*.test.d.ts","!dist-types/**/*.spec.d.ts","!dist-cjs/**/*.test.cjs","!dist-cjs/**/*.spec.cjs","!dist-mjs/**/*.test.mjs","!dist-mjs/**/*.spec.mjs","SECURITY.md"],"scripts":{"build:dist-cjs":"rimraf dist-cjs && npx builder --type=commonjs --sourceMap --entryPoint=index.ts --outDir=dist-cjs --outFile=index.cjs --external=espree && echo \"module.exports = module.exports.default;\" >> dist-cjs/index.cjs","build:dist-mjs":"rimraf dist-mjs && npx builder --type=module --sourceMap --outDir=dist-mjs && node dist-mjs/index.mjs","build:dist-types":"rimraf dist-types && npx builder --type=types --outDir=dist-types","ci:compile":"tsc --noEmit","ci:coverage":"NODE_OPTIONS=\"--disable-warning ExperimentalWarning --experimental-vm-modules\" jest --coverage=true","ci:lint":"npm run lint","ci:style":"npm run prettier","ci:test":"NODE_OPTIONS=\"--disable-warning ExperimentalWarning --experimental-vm-modules\" jest --coverage=false","lint":"eslint --max-warnings 0 --ignore-path .gitignore .","lint:fix":"eslint --ignore-path .gitignore . --fix","prepublishOnly":"npm run build:dist-types && npm run build:dist-cjs && npm run build:dist-mjs","prettier":"prettier --ignore-path .gitignore --list-different .","prettier:fix":"prettier --ignore-path .gitignore --write .","test":"npm run ci:compile && npm run ci:test && npm run ci:lint && npm run ci:style"},"prettier":"@checkdigit/prettier-config","jest":{"preset":"@checkdigit/jest-config"},"dependencies":{"@typescript-eslint/type-utils":"7.18.0","@typescript-eslint/utils":"7.18.0","ts-api-utils":"^1.3.0"},"devDependencies":{"@checkdigit/jest-config":"^6.0.2","@checkdigit/prettier-config":"^5.5.0","@checkdigit/typescript-config":"6.0.0","@types/eslint":"^8.56.10","@typescript-eslint/eslint-plugin":"^7.18.0","@typescript-eslint/parser":"^7.18.0","@typescript-eslint/rule-tester":"7.18.0","eslint-config-prettier":"^9.1.0","eslint-plugin-eslint-plugin":"^6.2.0","eslint-plugin-import":"^2.29.1","eslint-plugin-no-only-tests":"^3.1.0","eslint-plugin-no-secrets":"^1.0.2","eslint-plugin-node":"^11.1.0","eslint-plugin-sonarjs":"0.24.0"},"peerDependencies":{"eslint":">=8 <9"},"engines":{"node":">=20.14"}}
|
package/src/ast/format.ts
CHANGED
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
* This code is licensed under the MIT license (see LICENSE.txt for details).
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { TSESLint, TSESTree } from '@typescript-eslint/utils';
|
|
9
10
|
import type { Node } from 'estree';
|
|
10
11
|
import type { SourceCode } from 'eslint';
|
|
11
12
|
import { strict as assert } from 'node:assert';
|
|
12
13
|
|
|
13
|
-
export function getIndentation(node: Node, sourceCode: SourceCode) {
|
|
14
|
+
export function getIndentation(node: Node | TSESTree.Node, sourceCode: SourceCode | TSESLint.SourceCode) {
|
|
14
15
|
assert.ok(node.loc);
|
|
15
16
|
const line = sourceCode.lines[node.loc.start.line - 1];
|
|
16
17
|
assert.ok(line !== undefined);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// tree.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, TSESTree } from '@typescript-eslint/utils';
|
|
10
|
+
|
|
11
|
+
type NodeParent = TSESTree.Node | undefined | null;
|
|
12
|
+
|
|
13
|
+
interface NodeParentExtension {
|
|
14
|
+
parent: NodeParent;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getParent(node: TSESTree.Node): TSESTree.Node | undefined | null {
|
|
18
|
+
return (node as unknown as NodeParentExtension).parent;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function getAncestor(
|
|
22
|
+
node: TSESTree.Node,
|
|
23
|
+
matcher: AST_NODE_TYPES | ((testNode: TSESTree.Node) => boolean),
|
|
24
|
+
exitMatcher?: AST_NODE_TYPES | ((testNode: TSESTree.Node) => boolean),
|
|
25
|
+
): TSESTree.Node | undefined {
|
|
26
|
+
const parent = getParent(node);
|
|
27
|
+
if (!parent) {
|
|
28
|
+
return undefined;
|
|
29
|
+
} else if (typeof matcher === 'string' && parent.type === matcher) {
|
|
30
|
+
return parent;
|
|
31
|
+
} else if (typeof matcher === 'function' && matcher(parent)) {
|
|
32
|
+
return parent;
|
|
33
|
+
} else if (typeof exitMatcher === 'string' && parent.type === exitMatcher) {
|
|
34
|
+
return undefined;
|
|
35
|
+
} else if (typeof exitMatcher === 'function' && exitMatcher(parent)) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
return getAncestor(parent, matcher, exitMatcher);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function isBlockStatement(node: TSESTree.Node) {
|
|
42
|
+
return node.type.endsWith('Statement') || node.type.endsWith('Declaration');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getEnclosingStatement(node: TSESTree.Node) {
|
|
46
|
+
return getAncestor(node, isBlockStatement);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getEnclosingScopeNode(node: TSESTree.Node) {
|
|
50
|
+
return getAncestor(node, (parentNode) =>
|
|
51
|
+
['FunctionExpression', 'FunctionDeclaration', 'ArrowFunctionExpression', 'Program'].includes(parentNode.type),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function isUsedInArrayOrAsArgument(node: TSESTree.Node) {
|
|
56
|
+
if (isBlockStatement(node)) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const parent = getParent(node);
|
|
61
|
+
if (!parent) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (
|
|
66
|
+
parent.type === AST_NODE_TYPES.ArrayExpression ||
|
|
67
|
+
(parent.type === AST_NODE_TYPES.CallExpression && parent.arguments.includes(node as TSESTree.Expression))
|
|
68
|
+
) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// recurse up the tree until hitting a block statement
|
|
73
|
+
return isUsedInArrayOrAsArgument(parent);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function getEnclosingFunction(node: TSESTree.Node) {
|
|
77
|
+
if (
|
|
78
|
+
node.type === AST_NODE_TYPES.FunctionDeclaration ||
|
|
79
|
+
node.type === AST_NODE_TYPES.FunctionExpression ||
|
|
80
|
+
node.type === AST_NODE_TYPES.ArrowFunctionExpression
|
|
81
|
+
) {
|
|
82
|
+
return node;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const parent = getParent(node);
|
|
86
|
+
if (!parent) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
return getEnclosingFunction(parent);
|
|
90
|
+
}
|