/
validate-table-rules.ts
123 lines (108 loc) · 3.19 KB
/
validate-table-rules.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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import { TSESLint } from '@typescript-eslint/experimental-utils';
import chalk from 'chalk';
import fs from 'fs';
import marked from 'marked';
import path from 'path';
import { logRule } from './log';
function validateTableRules<TMessageIds extends string>(
rules: Record<string, TSESLint.RuleModule<TMessageIds, any, any>>,
rulesTable: marked.Tokens.Table,
): boolean {
let hasErrors = false;
Object.entries(rules).forEach(([ruleName, rule]) => {
const row = rulesTable.cells.find(row =>
row[0].includes(`/${ruleName}.md`),
);
if (!row) {
if (!rule.meta.deprecated) {
hasErrors = true;
logRule(false, ruleName, 'Missing entry in table');
return;
}
// all is well, the rule shouldn't have a row as it's deprecated
return;
}
if (row && rule.meta.deprecated) {
hasErrors = true;
logRule(
false,
ruleName,
'Rule is marked as deprecated, should not have an entry in the table',
);
return;
}
const errors: string[] = [];
const [
rowLink,
rowDescription,
rowIsRecommended,
rowIsFixable,
rowNeedsTypeInfo,
] = row;
function validateTableBoolean(
value: boolean,
cell: string,
trueString: string,
columnLabel: string,
): void {
if (value && cell !== trueString) {
errors.push(
`Rule ${chalk.red(
'not',
)} marked as ${columnLabel} when it ${chalk.bold('should')} be`,
);
}
if (!value && cell !== '') {
errors.push(
`Rule ${chalk.red(
'was',
)} marked as ${columnLabel} when it ${chalk.bold('should not')} be`,
);
}
}
const expectedLink = `[\`@typescript-eslint/${ruleName}\`](./docs/rules/${ruleName}.md)`;
if (rowLink !== expectedLink) {
errors.push(
`Link is invalid.`,
` Expected: ${chalk.underline(expectedLink)}`,
` Received: ${chalk.underline(rowLink)}`,
);
}
const expectedDescription = rule.meta.docs.description;
if (rowDescription !== expectedDescription) {
errors.push(
'Description does not match the rule metadata.',
` Expected: ${chalk.underline(expectedDescription)}`,
` Received: ${chalk.underline(rowDescription)}`,
);
}
validateTableBoolean(
!!rule.meta.docs.recommended,
rowIsRecommended,
':heavy_check_mark:',
'recommended',
);
validateTableBoolean(
rule.meta.fixable !== undefined,
rowIsFixable,
':wrench:',
'fixable',
);
// quick-and-dirty check to see if it uses parserServices
// not perfect but should be good enough
const ruleFileContents = fs.readFileSync(
path.resolve(__dirname, `../../src/rules/${ruleName}.ts`),
);
const usesTypeInformation = ruleFileContents.includes('getParserServices');
validateTableBoolean(
usesTypeInformation,
rowNeedsTypeInfo,
':thought_balloon:',
'requiring type information',
);
hasErrors = hasErrors || errors.length > 0;
logRule(errors.length === 0, ruleName, ...errors);
});
return hasErrors;
}
export { validateTableRules };