Skip to content

Commit 718578a

Browse files
SamVerschuerenjfmengels
authored andcommitted
Add number-literal-case rule (fixes #55) (#57)
* add number-literal-case rule - fixes #55 * process feedback * remove meta * fix description
1 parent 7fdff88 commit 718578a

File tree

5 files changed

+150
-2
lines changed

5 files changed

+150
-2
lines changed

docs/rules/number-literal-case.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Enforce lowercase identifier and uppercase value for number literals
2+
3+
Enforces a convention of defining number literals where the literal identifier is written in lowercase and the value in uppercase. Differentiating the casing of the identifier and value clearly separates them and makes your code more readable.
4+
5+
6+
## Fail
7+
8+
```js
9+
const foo = 0XFF;
10+
const foo = 0xff;
11+
const foo = 0Xff;
12+
```
13+
14+
```js
15+
const foo = 0B11;
16+
```
17+
18+
```js
19+
const foo = 0O10;
20+
```
21+
22+
23+
## Pass
24+
25+
```js
26+
const foo = 0xFF;
27+
```
28+
29+
```js
30+
const foo = 0b11;
31+
```
32+
33+
```js
34+
const foo = 0o10;
35+
```

index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ module.exports = {
1818
'unicorn/filename-case': ['error', {case: 'kebabCase'}],
1919
'unicorn/no-abusive-eslint-disable': 'error',
2020
'unicorn/no-process-exit': 'error',
21-
'unicorn/throw-new-error': 'error'
21+
'unicorn/throw-new-error': 'error',
22+
'unicorn/number-literal-case': 'error'
2223
}
2324
}
2425
}

readme.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ Configure it in `package.json`.
3838
"unicorn/filename-case": ["error", {"case": "kebabCase"}],
3939
"unicorn/no-abusive-eslint-disable": "error",
4040
"unicorn/no-process-exit": "error",
41-
"unicorn/throw-new-error": "error"
41+
"unicorn/throw-new-error": "error",
42+
"unicorn/number-literal-case": "error"
4243
}
4344
}
4445
}
@@ -53,6 +54,7 @@ Configure it in `package.json`.
5354
- [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) - Enforce specifying rules to disable in `eslint-disable` comments.
5455
- [no-process-exit](docs/rules/no-process-exit.md) - Disallow `process.exit()`.
5556
- [throw-new-error](docs/rules/throw-new-error.md) - Require `new` when throwing an error. *(fixable)*
57+
- [number-literal-case](docs/rules/number-literal-case.md) - Enforce lowercase identifier and uppercase value for number literals. *(fixable)*
5658

5759

5860
## Recommended config

rules/number-literal-case.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict';
2+
const fix = value => {
3+
if (!/^0[a-zA-Z]/.test(value)) {
4+
return value;
5+
}
6+
7+
const indicator = value[1].toLowerCase();
8+
const val = value.slice(2).toUpperCase();
9+
10+
return `0${indicator}${val}`;
11+
};
12+
13+
const create = context => {
14+
return {
15+
Literal: node => {
16+
const value = node.raw;
17+
const fixedValue = fix(value);
18+
19+
if (value !== fixedValue) {
20+
context.report({
21+
node,
22+
message: 'Invalid number literal casing',
23+
fix: fixer => fixer.replaceText(node, fixedValue)
24+
});
25+
}
26+
}
27+
};
28+
};
29+
30+
module.exports = {
31+
meta: {
32+
fixable: 'code'
33+
},
34+
create
35+
};

test/number-literal-case.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import test from 'ava';
2+
import avaRuleTester from 'eslint-ava-rule-tester';
3+
import rule from '../rules/number-literal-case';
4+
5+
const ruleTester = avaRuleTester(test, {
6+
env: {
7+
es6: true
8+
},
9+
parserOptions: {
10+
sourceType: 'module'
11+
}
12+
});
13+
14+
const error = {
15+
ruleId: 'number-literal-case',
16+
message: 'Invalid number literal casing'
17+
};
18+
19+
ruleTester.run('number-literal-case', rule, {
20+
valid: [
21+
'const foo = 0xFF',
22+
'const foo = 0b11',
23+
'const foo = 0o10',
24+
`const foo = '0Xff'`
25+
],
26+
invalid: [
27+
{
28+
code: 'const foo = 0XFF',
29+
errors: [error],
30+
output: 'const foo = 0xFF'
31+
},
32+
{
33+
code: 'const foo = 0xff',
34+
errors: [error],
35+
output: 'const foo = 0xFF'
36+
},
37+
{
38+
code: 'const foo = 0Xff',
39+
errors: [error],
40+
output: 'const foo = 0xFF'
41+
},
42+
{
43+
code: 'const foo = 0Xff',
44+
errors: [error],
45+
output: 'const foo = 0xFF'
46+
},
47+
{
48+
code: 'const foo = 0B11',
49+
errors: [error],
50+
output: 'const foo = 0b11'
51+
},
52+
{
53+
code: 'const foo = 0O10',
54+
errors: [error],
55+
output: 'const foo = 0o10'
56+
},
57+
{
58+
code: `
59+
const foo = 255;
60+
61+
if (foo === 0xff) {
62+
console.log('invalid');
63+
}
64+
`,
65+
errors: [error],
66+
output: `
67+
const foo = 255;
68+
69+
if (foo === 0xFF) {
70+
console.log('invalid');
71+
}
72+
`
73+
}
74+
]
75+
});

0 commit comments

Comments
 (0)