forked from avajs/eslint-plugin-ava
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcreate-ava-rule.js
More file actions
102 lines (89 loc) · 2.74 KB
/
Copy pathcreate-ava-rule.js
File metadata and controls
102 lines (89 loc) · 2.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import {getTestModifiers, unwrapTypeExpression} from './util.js';
export default context => {
let isTestFile = false;
const testIdentifiers = new Set();
function isTestFunctionCall(node) {
if (node.type === 'Identifier') {
return testIdentifiers.has(node.name);
}
if (node.type === 'MemberExpression') {
return isTestFunctionCall(node.object);
}
return false;
}
const getModifierNames = node => getTestModifiers(node).map(property => property.name);
const predefinedRules = {
ImportDeclaration(node) {
if (node.source.value !== 'ava' || node.importKind === 'type') {
return;
}
for (const specifier of node.specifiers) {
if (specifier.importKind === 'type') {
continue;
}
if (specifier.type === 'ImportDefaultSpecifier') {
isTestFile = true;
testIdentifiers.add(specifier.local.name);
} else if (specifier.type === 'ImportSpecifier' && specifier.imported.name === 'serial') {
isTestFile = true;
testIdentifiers.add(specifier.local.name);
}
}
},
VariableDeclarator(node) {
const init = unwrapTypeExpression(node.init);
// Track re-assignment from a test identifier (e.g., `const test = anyTest as TestFn<Context>`)
if (init?.type === 'Identifier' && testIdentifiers.has(init.name) && node.id.type === 'Identifier') {
testIdentifiers.add(node.id.name);
}
},
'Program:exit'() {
isTestFile = false;
testIdentifiers.clear();
},
};
return {
isInTestFile: () => isTestFile,
isTestNode: node => node.type === 'CallExpression' && isTestFunctionCall(node.callee),
isInTestNode(node) {
if (node.type === 'CallExpression' && isTestFunctionCall(node.callee)) {
return node;
}
const ancestors = context.sourceCode.getAncestors(node);
for (let index = ancestors.length - 1; index >= 0; index--) {
const ancestor = ancestors[index];
if (ancestor.type === 'CallExpression' && isTestFunctionCall(ancestor.callee)) {
return ancestor;
}
}
return undefined;
},
hasTestModifier: (node, modifier) => getModifierNames(node).includes(modifier),
hasNoUtilityModifier(node) {
const modifiers = getModifierNames(node);
return !modifiers.includes('before')
&& !modifiers.includes('beforeEach')
&& !modifiers.includes('after')
&& !modifiers.includes('afterEach')
&& !modifiers.includes('macro');
},
merge: customHandlers => ({
...predefinedRules,
...Object.fromEntries(Object.entries(customHandlers).map(([key, custom]) => {
const predefined = predefinedRules[key];
if (!predefined) {
return [key, custom];
}
return [key, key.endsWith(':exit')
? node => {
custom(node);
predefined(node);
}
: node => {
predefined(node);
custom(node);
}];
})),
}),
};
};