/
RuleTester.ts
84 lines (72 loc) · 2.52 KB
/
RuleTester.ts
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
import { TSESLint, ESLintUtils } from '@typescript-eslint/experimental-utils';
import { clearCaches } from '@typescript-eslint/parser';
import * as path from 'path';
const parser = '@typescript-eslint/parser';
type RuleTesterConfig = Omit<TSESLint.RuleTesterConfig, 'parser'> & {
parser: typeof parser;
};
class RuleTester extends TSESLint.RuleTester {
private filename: string | undefined = undefined;
// as of eslint 6 you have to provide an absolute path to the parser
// but that's not as clean to type, this saves us trying to manually enforce
// that contributors require.resolve everything
constructor(options: RuleTesterConfig) {
super({
...options,
parser: require.resolve(options.parser),
});
if (options.parserOptions && options.parserOptions.project) {
this.filename = path.join(getFixturesRootDir(), 'file.ts');
}
}
// as of eslint 6 you have to provide an absolute path to the parser
// If you don't do that at the test level, the test will fail somewhat cryptically...
// This is a lot more explicit
run<TMessageIds extends string, TOptions extends Readonly<unknown[]>>(
name: string,
rule: TSESLint.RuleModule<TMessageIds, TOptions>,
tests: TSESLint.RunTests<TMessageIds, TOptions>,
): void {
const errorMessage = `Do not set the parser at the test level unless you want to use a parser other than ${parser}`;
if (this.filename) {
tests.valid = tests.valid.map(test => {
if (typeof test === 'string') {
return {
code: test,
filename: this.filename,
};
}
return test;
});
}
tests.valid.forEach(test => {
if (typeof test !== 'string') {
if (test.parser === parser) {
throw new Error(errorMessage);
}
if (!test.filename) {
test.filename = this.filename;
}
}
});
tests.invalid.forEach(test => {
if (test.parser === parser) {
throw new Error(errorMessage);
}
if (!test.filename) {
test.filename = this.filename;
}
});
super.run(name, rule, tests);
}
}
function getFixturesRootDir(): string {
return path.join(process.cwd(), 'tests/fixtures/');
}
const { batchedSingleLineTests } = ESLintUtils;
// make sure that the parser doesn't hold onto file handles between tests
// on linux (i.e. our CI env), there can be very a limited number of watch handles available
afterAll(() => {
clearCaches();
});
export { RuleTester, getFixturesRootDir, batchedSingleLineTests };