Skip to content

Commit 318f482

Browse files
pnevykgajus
authored andcommitted
chore: test docs check script (#368)
* chore: Add checking script for tests and docs * chore: Fix issues discovered by tests-docs-check * chore: Add tests-docs-checker to pre-commit hook * docs: generate docs * docs: Mention tests-docs-check in contributing guide
1 parent 633c5a3 commit 318f482

8 files changed

+289
-5
lines changed

.README/rules/no-flow-fix-me-comments.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ This rule takes an optional RegExp that comments a text RegExp that makes the su
1919
}
2020
```
2121

22-
<!-- assertions no-flow-fix-me-comments -->
22+
<!-- assertions noFlowFixMeComments -->

.README/rules/require-types-at-top.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ The rule has a string option:
1111

1212
The default value is `"always"`.
1313

14-
<!-- assertions require-types-at-top -->
14+
<!-- assertions requireTypesAtTop -->

.README/rules/valid-syntax.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
**Deprecated** Babylon (the Babel parser) v6.10.0 fixes parsing of the invalid syntax this plugin warned against.
44

55
Checks for simple Flow syntax errors.
6+
7+
<!-- assertions validSyntax -->

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
When making a commit, the following Pre-Commit hooks run:
88

9+
* tests and docs checks
910
* tests
1011
* lint
1112
* commit message validation (see "Commit Messages" below)

README.md

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,7 +1308,44 @@ This rule takes an optional RegExp that comments a text RegExp that makes the su
13081308
}
13091309
```
13101310
1311-
<!-- assertions no-flow-fix-me-comments -->
1311+
The following patterns are considered problems:
1312+
1313+
```js
1314+
// $FlowFixMe I am doing something evil here
1315+
const text = 'HELLO';
1316+
// Message: $FlowFixMe is treated as `any` and should be fixed.
1317+
1318+
// Options: ["TODO [0-9]+"]
1319+
// $FlowFixMe I am doing something evil here
1320+
const text = 'HELLO';
1321+
// Message: $FlowFixMe is treated as `any` and should be fixed. Fix it or match `/TODO [0-9]+/`.
1322+
1323+
// Options: ["TODO [0-9]+"]
1324+
// $FlowFixMe TODO abc 47 I am doing something evil here
1325+
const text = 'HELLO';
1326+
// Message: $FlowFixMe is treated as `any` and should be fixed. Fix it or match `/TODO [0-9]+/`.
1327+
1328+
// $$FlowFixMeProps I am doing something evil here
1329+
const text = 'HELLO';
1330+
// Message: $FlowFixMe is treated as `any` and should be fixed.
1331+
1332+
// Options: ["TODO [0-9]+"]
1333+
// $FlowFixMeProps I am doing something evil here
1334+
const text = 'HELLO';
1335+
// Message: $FlowFixMe is treated as `any` and should be fixed. Fix it or match `/TODO [0-9]+/`.
1336+
```
1337+
1338+
The following patterns are not considered problems:
1339+
1340+
```js
1341+
const text = 'HELLO';
1342+
1343+
// Options: ["TODO [0-9]+"]
1344+
// $FlowFixMe TODO 48
1345+
const text = 'HELLO';
1346+
```
1347+
1348+
13121349
13131350
<a name="eslint-plugin-flowtype-rules-no-mutable-array"></a>
13141351
### <code>no-mutable-array</code>
@@ -2494,7 +2531,65 @@ The rule has a string option:
24942531
24952532
The default value is `"always"`.
24962533
2497-
<!-- assertions require-types-at-top -->
2534+
The following patterns are considered problems:
2535+
2536+
```js
2537+
const foo = 3;
2538+
type Foo = number;
2539+
// Message: All type declaration should be at the top of the file, after any import declarations.
2540+
2541+
const foo = 3;
2542+
opaque type Foo = number;
2543+
// Message: All type declaration should be at the top of the file, after any import declarations.
2544+
2545+
const foo = 3;
2546+
export type Foo = number;
2547+
// Message: All type declaration should be at the top of the file, after any import declarations.
2548+
2549+
const foo = 3;
2550+
export opaque type Foo = number;
2551+
// Message: All type declaration should be at the top of the file, after any import declarations.
2552+
2553+
const foo = 3;
2554+
type Foo = number | string;
2555+
// Message: All type declaration should be at the top of the file, after any import declarations.
2556+
2557+
import bar from "./bar";
2558+
const foo = 3;
2559+
type Foo = number;
2560+
// Message: All type declaration should be at the top of the file, after any import declarations.
2561+
```
2562+
2563+
The following patterns are not considered problems:
2564+
2565+
```js
2566+
type Foo = number;
2567+
const foo = 3;
2568+
2569+
opaque type Foo = number;
2570+
const foo = 3;
2571+
2572+
export type Foo = number;
2573+
const foo = 3;
2574+
2575+
export opaque type Foo = number;
2576+
const foo = 3;
2577+
2578+
type Foo = number;
2579+
const foo = 3;
2580+
2581+
import bar from "./bar";
2582+
type Foo = number;
2583+
2584+
type Foo = number;
2585+
import bar from "./bar";
2586+
2587+
// Options: ["never"]
2588+
const foo = 3;
2589+
type Foo = number;
2590+
```
2591+
2592+
24982593
24992594
<a name="eslint-plugin-flowtype-rules-require-valid-file-annotation"></a>
25002595
### <code>require-valid-file-annotation</code>
@@ -4658,3 +4753,13 @@ declare var A: Y
46584753
46594754
Checks for simple Flow syntax errors.
46604755
4756+
The following patterns are not considered problems:
4757+
4758+
```js
4759+
function x(foo: string = "1") {}
4760+
4761+
function x(foo: Type = bar()) {}
4762+
```
4763+
4764+
4765+

bin/testsAndDocsCheck.js

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/**
2+
* This script checks if there is test suite and documentation for every rule and if they are correctly included in corresponding "index" files.
3+
*
4+
* Performed checks:
5+
*
6+
* - tests
7+
* - file `/tests/rules/assertions/<rule>.js` exists
8+
* - rule is included in `reportingRules` variable in `/tests/rules/index.js`
9+
*
10+
* - docs
11+
* - file `/.README/rules/<rule>.md` exists
12+
* - file `/.README/rules/<rule>.md` contains correct assertions placeholder (`<!-- assertions ... -->`)
13+
* - rule is included in gitdown directive in `/.README/README.md`
14+
* - rules in `/.README/README.md` are alphabetically sorted
15+
*/
16+
17+
import path from 'path';
18+
import fs from 'fs';
19+
import glob from 'glob';
20+
import _ from 'lodash';
21+
22+
// returns Array<[camelCase, kebab-case]>
23+
const getRules = () => {
24+
const rulesFiles = glob.sync(path.resolve(__dirname, '../src/rules/*.js'));
25+
26+
const rulesNames = rulesFiles.map((file) => {
27+
return path.basename(file, '.js');
28+
}).map((name) => {
29+
return [name, _.kebabCase(name)];
30+
});
31+
32+
return rulesNames;
33+
};
34+
35+
const isFile = (filepath) => {
36+
try {
37+
return fs.statSync(filepath).isFile();
38+
} catch (error) {
39+
return false;
40+
}
41+
};
42+
43+
const windows = (array, size) => {
44+
const output = [];
45+
46+
for (let ii = 0; ii < array.length - size + 1; ii++) {
47+
output.push(array.slice(ii, ii + size));
48+
}
49+
50+
return output;
51+
};
52+
53+
const getTestIndexRules = () => {
54+
const content = fs.readFileSync(path.resolve(__dirname, '../tests/rules/index.js'), 'utf-8');
55+
56+
const result = content.split('\n').reduce((acc, line) => {
57+
if (acc.inRulesArray) {
58+
if (line === '];') {
59+
acc.inRulesArray = false;
60+
} else {
61+
acc.rules.push(line.replace(/^\s*'([^']+)',?$/, '$1'));
62+
}
63+
} else if (line === 'const reportingRules = [') {
64+
acc.inRulesArray = true;
65+
}
66+
67+
return acc;
68+
}, {
69+
inRulesArray: false,
70+
rules: []
71+
});
72+
73+
const rules = result.rules;
74+
75+
if (rules.length === 0) {
76+
throw new Error('Tests checker is broken - it could not extract rules from test index file.');
77+
}
78+
79+
return rules;
80+
};
81+
82+
const getDocIndexRules = () => {
83+
const content = fs.readFileSync(path.resolve(__dirname, '../.README/README.md'), 'utf-8');
84+
85+
const rules = content.split('\n').map((line) => {
86+
const match = /^{"gitdown": "include", "file": "([^"]+)"}$/.exec(line);
87+
88+
if (match === null) {
89+
return null;
90+
} else {
91+
return match[1].replace('./rules/', '').replace('.md', '');
92+
}
93+
}).filter((rule) => {
94+
return rule !== null;
95+
});
96+
97+
if (rules.length === 0) {
98+
throw new Error('Docs checker is broken - it could not extract rules from docs index file.');
99+
}
100+
101+
return rules;
102+
};
103+
104+
const hasCorrectAssertions = (docPath, name) => {
105+
const content = fs.readFileSync(docPath, 'utf-8');
106+
107+
const match = /<!-- assertions ([a-zA-Z]+) -->/.exec(content);
108+
109+
if (match === null) {
110+
return false;
111+
} else {
112+
return match[1] === name;
113+
}
114+
};
115+
116+
const checkTests = (rulesNames) => {
117+
const testIndexRules = getTestIndexRules();
118+
119+
const invalid = rulesNames.filter((names) => {
120+
const testExists = isFile(path.resolve(__dirname, '../tests/rules/assertions', names[0] + '.js'));
121+
const inIndex = testIndexRules.indexOf(names[1]) !== -1;
122+
123+
return !(testExists && inIndex);
124+
});
125+
126+
if (invalid.length > 0) {
127+
const invalidList = invalid.map((names) => {
128+
return names[0];
129+
}).join(', ');
130+
131+
throw new Error(
132+
'Tests checker encountered an error in: ' + invalidList + '. ' +
133+
'Make sure that for every rule you created test suite and included the rule name in `tests/rules/index.js` file.'
134+
);
135+
}
136+
};
137+
138+
const checkDocs = (rulesNames) => {
139+
const docIndexRules = getDocIndexRules();
140+
141+
const sorted = windows(docIndexRules, 2).every((chunk) => {
142+
return chunk[0] < chunk[1];
143+
});
144+
145+
if (!sorted) {
146+
throw new Error('Rules are not alphabetically sorted in `.README/README.md` file.');
147+
}
148+
149+
const invalid = rulesNames.filter((names) => {
150+
const docPath = path.resolve(__dirname, '../.README/rules', names[1] + '.md');
151+
const docExists = isFile(docPath);
152+
const inIndex = docIndexRules.indexOf(names[1]) !== -1;
153+
const hasAssertions = docExists ? hasCorrectAssertions(docPath, names[0]) : false;
154+
155+
return !(docExists && inIndex && hasAssertions);
156+
});
157+
158+
if (invalid.length > 0) {
159+
const invalidList = invalid.map((names) => {
160+
return names[0];
161+
}).join(', ');
162+
163+
throw new Error(
164+
'Docs checker encountered an error in: ' + invalidList + '. ' +
165+
'Make sure that for every rule you created documentation file with assertions placeholder in camelCase ' +
166+
'and included the file path in `.README/README.md` file.'
167+
);
168+
}
169+
};
170+
171+
const rulesList = getRules();
172+
173+
checkTests(rulesList);
174+
checkDocs(rulesList);

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"husky": {
4444
"hooks": {
4545
"post-commit": "npm run create-readme && git add README.md && git commit -m 'docs: generate docs' --no-verify",
46-
"pre-commit": "npm run lint && npm run test && npm run build && npm run format-json"
46+
"pre-commit": "npm run tests-docs-check && npm run lint && npm run test && npm run build && npm run format-json"
4747
}
4848
},
4949
"repository": {
@@ -55,6 +55,7 @@
5555
"create-readme": "gitdown ./.README/README.md --output-file ./README.md && npm run documentation-add-assertions",
5656
"documentation-add-assertions": "babel-node ./bin/readmeAssertions",
5757
"format-json": "jsonlint --sort-keys --in-place --indent ' ' ./src/configs/recommended.json && echo '' >> ./src/configs/recommended.json",
58+
"tests-docs-check": "babel-node ./bin/testsAndDocsCheck",
5859
"lint": "eslint ./src ./tests",
5960
"test": "mocha --compilers js:babel-register ./tests/rules/index.js"
6061
},

tests/rules/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const reportingRules = [
1919
'generic-spacing',
2020
'newline-after-flow-annotation',
2121
'no-dupe-keys',
22+
'no-existential-type',
2223
'no-flow-fix-me-comments',
2324
'no-mutable-array',
2425
'no-primitive-constructor-types',

0 commit comments

Comments
 (0)