Skip to content

Commit a2ba25e

Browse files
manovotnyfiskersindresorhus
authored
Add no-empty-file rule (#1506)
Co-authored-by: fisker Cheung <lionkay@gmail.com> Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
1 parent 46f8638 commit a2ba25e

File tree

7 files changed

+603
-0
lines changed

7 files changed

+603
-0
lines changed

configs/recommended.js

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module.exports = {
2424
'unicorn/no-array-reduce': 'error',
2525
'unicorn/no-console-spaces': 'error',
2626
'unicorn/no-document-cookie': 'error',
27+
'unicorn/no-empty-file': 'error',
2728
'unicorn/no-for-loop': 'error',
2829
'unicorn/no-hex-escape': 'error',
2930
'unicorn/no-instanceof-array': 'error',

docs/rules/no-empty-file.md

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Disallow empty files
2+
3+
Meaningless files clutter a codebase.
4+
5+
Disallow any files only containing the following:
6+
7+
- Whitespace
8+
- Comments
9+
- Directives
10+
- Empty statements
11+
- Empty block statements
12+
- Hashbang
13+
14+
## Fail
15+
16+
```js
17+
18+
```
19+
20+
```js
21+
// Comment
22+
```
23+
24+
```js
25+
/* Comment */
26+
```
27+
28+
```js
29+
'use strict';
30+
```
31+
32+
```js
33+
;
34+
```
35+
36+
```js
37+
{
38+
}
39+
```
40+
41+
```js
42+
#!/usr/bin/env node
43+
```
44+
45+
## Pass
46+
47+
```js
48+
const x = 0;
49+
```
50+
51+
```js
52+
'use strict';
53+
const x = 0;
54+
```
55+
56+
```js
57+
;;
58+
const x = 0;
59+
```
60+
61+
```js
62+
{
63+
const x = 0;
64+
}
65+
```

readme.md

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Configure it in `package.json`.
5757
"unicorn/no-array-reduce": "error",
5858
"unicorn/no-console-spaces": "error",
5959
"unicorn/no-document-cookie": "error",
60+
"unicorn/no-empty-file": "error",
6061
"unicorn/no-for-loop": "error",
6162
"unicorn/no-hex-escape": "error",
6263
"unicorn/no-instanceof-array": "error",
@@ -180,6 +181,7 @@ Each rule has emojis denoting:
180181
| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. || | |
181182
| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. || 🔧 | |
182183
| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. || | |
184+
| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. || | |
183185
| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. || 🔧 | |
184186
| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. || 🔧 | |
185187
| [no-instanceof-array](docs/rules/no-instanceof-array.md) | Require `Array.isArray()` instead of `instanceof Array`. || 🔧 | |

rules/no-empty-file.js

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
3+
const MESSAGE_ID = 'no-empty-file';
4+
const messages = {
5+
[MESSAGE_ID]: 'Empty files are not allowed.',
6+
};
7+
8+
const isEmpty = node =>
9+
(
10+
(node.type === 'Program' || node.type === 'BlockStatement')
11+
&& node.body.every(currentNode => isEmpty(currentNode))
12+
)
13+
|| node.type === 'EmptyStatement'
14+
|| (node.type === 'ExpressionStatement' && 'directive' in node);
15+
16+
const create = context => {
17+
const filename = context.getPhysicalFilename().toLowerCase();
18+
19+
if (!/\.(?:js|mjs|cjs|ts|mts|cts)$/.test(filename)) {
20+
return {};
21+
}
22+
23+
return {
24+
Program(node) {
25+
if (!isEmpty(node)) {
26+
return;
27+
}
28+
29+
return {
30+
node,
31+
messageId: MESSAGE_ID,
32+
};
33+
},
34+
};
35+
};
36+
37+
module.exports = {
38+
create,
39+
meta: {
40+
type: 'suggestion',
41+
docs: {
42+
description: 'Disallow empty files.',
43+
},
44+
schema: [],
45+
messages,
46+
},
47+
};

test/no-empty-file.mjs

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import outdent from 'outdent';
2+
import {getTester} from './utils/test.mjs';
3+
4+
const {test} = getTester(import.meta);
5+
6+
test.snapshot({
7+
valid: [
8+
...[
9+
'const x = 0;',
10+
';; const x = 0;',
11+
'{{{;;const x = 0;}}}',
12+
outdent`
13+
'use strict';
14+
const x = 0;
15+
`,
16+
';;\'use strict\';',
17+
'{\'use strict\';}',
18+
'("use strict")',
19+
'`use strict`',
20+
'({})',
21+
outdent`
22+
#!/usr/bin/env node
23+
console.log('done');
24+
`,
25+
'false',
26+
'("")',
27+
'NaN',
28+
'undefined',
29+
'null',
30+
'[]',
31+
'(() => {})()',
32+
].map(code => ({code, filename: 'example.js'})),
33+
'',
34+
...[
35+
'md',
36+
'vue',
37+
'svelte',
38+
'tsx',
39+
].map(extension => ({code: '', filename: `example.${extension}`})),
40+
],
41+
invalid: [
42+
...[
43+
'',
44+
'\uFEFF',
45+
' ',
46+
'\t',
47+
'\n',
48+
'\r',
49+
'\r\n',
50+
outdent`
51+
52+
`,
53+
'// comment',
54+
'/* comment */',
55+
'#!/usr/bin/env node',
56+
'\'use asm\';',
57+
'\'use strict\';',
58+
'"use strict"',
59+
'""',
60+
';',
61+
';;',
62+
'{}',
63+
'{;;}',
64+
'{{}}',
65+
].map(code => ({code, filename: 'example.js'})),
66+
...[
67+
'mjs',
68+
'cjs',
69+
'ts',
70+
'mts',
71+
'cts',
72+
].map(extension => ({code: '{}', filename: `example.${extension}`})),
73+
],
74+
});

0 commit comments

Comments
 (0)