@checkdigit/eslint-plugin 6.6.0-PR.75-f33d → 6.6.0-PR.75-20dc
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 +292 -324
- package/dist-cjs/metafile.json +105 -71
- package/dist-mjs/ast/tree.mjs +2 -2
- package/dist-mjs/fixture/fetch-header-getter.mjs +64 -0
- package/dist-mjs/{no-fixture.mjs → fixture/no-fixture.mjs} +8 -56
- package/dist-mjs/fixture/response-reference.mjs +56 -0
- package/dist-mjs/index.mjs +5 -5
- package/dist-types/fixture/fetch-header-getter.d.ts +4 -0
- package/dist-types/fixture/response-reference.d.ts +16 -0
- package/dist-types/index.d.ts +2 -2
- package/package.json +1 -1
- package/src/ast/tree.ts +1 -1
- package/src/fixture/fetch-header-getter.ts +90 -0
- package/src/{no-fixture.ts → fixture/no-fixture.ts} +7 -110
- package/src/fixture/response-reference.ts +108 -0
- package/src/index.ts +4 -4
- package/dist-mjs/no-fixture-headers.mjs +0 -98
- package/dist-types/no-fixture-headers.d.ts +0 -4
- package/src/no-fixture-headers.ts +0 -134
- /package/dist-types/{no-fixture.d.ts → fixture/no-fixture.d.ts} +0 -0
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
// 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, MemberExpression, VariableDeclarator } from 'estree';
|
|
10
|
-
import { getEnclosingScopeNode, getParent } from './ast/tree';
|
|
11
|
-
import { type Rule } from 'eslint';
|
|
12
|
-
import { strict as assert } from 'node:assert';
|
|
13
|
-
import getDocumentationUrl from './get-documentation-url';
|
|
14
|
-
|
|
15
|
-
export const ruleId = 'no-fixture-headers';
|
|
16
|
-
|
|
17
|
-
const rule: Rule.RuleModule = {
|
|
18
|
-
meta: {
|
|
19
|
-
type: 'suggestion',
|
|
20
|
-
docs: {
|
|
21
|
-
description: 'Prefer native fetch API over customized fixture API.',
|
|
22
|
-
url: getDocumentationUrl(ruleId),
|
|
23
|
-
},
|
|
24
|
-
messages: {
|
|
25
|
-
preferNativeFetch: 'Prefer native fetch API over customized fixture API.',
|
|
26
|
-
unknownError:
|
|
27
|
-
'Unknown error occurred in file "{{fileName}}": {{ error }}. Please manually convert the fixture API call to fetch API call.',
|
|
28
|
-
},
|
|
29
|
-
fixable: 'code',
|
|
30
|
-
schema: [],
|
|
31
|
-
},
|
|
32
|
-
// eslint-disable-next-line max-lines-per-function
|
|
33
|
-
create(context) {
|
|
34
|
-
const sourceCode = context.sourceCode;
|
|
35
|
-
const scopeManager = sourceCode.scopeManager;
|
|
36
|
-
|
|
37
|
-
return {
|
|
38
|
-
// eslint-disable-next-line max-lines-per-function
|
|
39
|
-
'VariableDeclarator[init.argument.callee.name="fetch"]': (fetchCall: VariableDeclarator) => {
|
|
40
|
-
try {
|
|
41
|
-
const enclosingScopeNode = getEnclosingScopeNode(fetchCall);
|
|
42
|
-
assert.ok(fetchCall.id.type === 'Identifier');
|
|
43
|
-
const fetchVariableName = fetchCall.id.name; /*?*/
|
|
44
|
-
assert.ok(enclosingScopeNode !== undefined, 'enclosing scope node should exist');
|
|
45
|
-
const scope = scopeManager.acquire(enclosingScopeNode);
|
|
46
|
-
const responseVariable = scope?.variables.find((variable) => {
|
|
47
|
-
const identifier = variable.identifiers[0];
|
|
48
|
-
return identifier?.type === 'Identifier' && identifier.name === fetchVariableName;
|
|
49
|
-
});
|
|
50
|
-
if (responseVariable === undefined) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const headersReferences = responseVariable.references
|
|
55
|
-
.map((reference) => getParent(reference.identifier))
|
|
56
|
-
.filter(
|
|
57
|
-
(parent): parent is MemberExpression =>
|
|
58
|
-
parent?.type === 'MemberExpression' &&
|
|
59
|
-
parent.property.type === 'Identifier' &&
|
|
60
|
-
parent.property.name === 'headers',
|
|
61
|
-
);
|
|
62
|
-
const directHeadersReferences = headersReferences
|
|
63
|
-
.map(getParent)
|
|
64
|
-
.filter(
|
|
65
|
-
(parent): parent is MemberExpression =>
|
|
66
|
-
parent?.type === 'MemberExpression' &&
|
|
67
|
-
!(parent.property.type === 'Identifier' && parent.property.name === 'get'),
|
|
68
|
-
);
|
|
69
|
-
directHeadersReferences.map((reference) => sourceCode.getText(reference)); /*?*/
|
|
70
|
-
|
|
71
|
-
const reDeclaredHeadersVariableNames = headersReferences
|
|
72
|
-
.map((reference) => getParent(reference))
|
|
73
|
-
.filter((parent): parent is VariableDeclarator => parent?.type === 'VariableDeclarator')
|
|
74
|
-
.map((declarator) => (declarator.id as Identifier).name);
|
|
75
|
-
|
|
76
|
-
const indirectHeadersReferences = reDeclaredHeadersVariableNames
|
|
77
|
-
.map((variableName) => {
|
|
78
|
-
const headersVariable = scope?.variables.find((variable) => {
|
|
79
|
-
const identifier = variable.identifiers[0];
|
|
80
|
-
return identifier?.type === 'Identifier' && identifier.name === variableName;
|
|
81
|
-
});
|
|
82
|
-
return (
|
|
83
|
-
headersVariable?.references
|
|
84
|
-
.map((reference) => getParent(reference.identifier))
|
|
85
|
-
.filter(
|
|
86
|
-
(parent): parent is MemberExpression =>
|
|
87
|
-
parent?.type === 'MemberExpression' &&
|
|
88
|
-
!(parent.property.type === 'Identifier' && parent.property.name === 'get'),
|
|
89
|
-
) ?? []
|
|
90
|
-
);
|
|
91
|
-
})
|
|
92
|
-
.flat();
|
|
93
|
-
indirectHeadersReferences.map((reference) => sourceCode.getText(reference)); /*?*/
|
|
94
|
-
|
|
95
|
-
const invalidHeadersReferences = [...directHeadersReferences, ...indirectHeadersReferences].map<
|
|
96
|
-
[MemberExpression, string]
|
|
97
|
-
>((reference) => {
|
|
98
|
-
sourceCode.getText(reference); /*?*/
|
|
99
|
-
const headerNameNode = reference.property; /*?*/
|
|
100
|
-
const headerName =
|
|
101
|
-
// eslint-disable-next-line no-nested-ternary, @typescript-eslint/restrict-template-expressions
|
|
102
|
-
reference.computed ? sourceCode.getText(headerNameNode) : `'${sourceCode.getText(headerNameNode)}'`; /*?*/
|
|
103
|
-
const replacementText = `${sourceCode.getText(reference.object)}.get(${headerName})`;
|
|
104
|
-
return [reference, replacementText];
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
context.report({
|
|
108
|
-
node: fetchCall,
|
|
109
|
-
messageId: 'preferNativeFetch',
|
|
110
|
-
*fix(fixer) {
|
|
111
|
-
// handle response headers references
|
|
112
|
-
for (const [node, replacementText] of invalidHeadersReferences) {
|
|
113
|
-
yield fixer.replaceText(node, replacementText);
|
|
114
|
-
}
|
|
115
|
-
},
|
|
116
|
-
});
|
|
117
|
-
} catch (error) {
|
|
118
|
-
// eslint-disable-next-line no-console
|
|
119
|
-
console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
|
|
120
|
-
context.report({
|
|
121
|
-
node: fetchCall,
|
|
122
|
-
messageId: 'unknownError',
|
|
123
|
-
data: {
|
|
124
|
-
fileName: context.filename,
|
|
125
|
-
error: error instanceof Error ? error.toString() : JSON.stringify(error),
|
|
126
|
-
},
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
};
|
|
131
|
-
},
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
export default rule;
|
|
File without changes
|