diff --git a/docs/rules/number-literal-case.md b/docs/rules/number-literal-case.md index 6fa54905cb..0282d4adcc 100644 --- a/docs/rules/number-literal-case.md +++ b/docs/rules/number-literal-case.md @@ -1,26 +1,42 @@ -# Enforce lowercase identifier and uppercase value for number literals +# Enforce proper case for numeric literals -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. +Differentiating the casing of the identifier and value clearly separates them and makes your code more readable. -This rule is fixable. +- Lowercase identifier and uppercase value for [`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) and [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#BigInt_type). +- Lowercase `e` for exponential notation. +This rule is fixable. ## Fail +[Hexadecimal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Hexadecimal) + ```js const foo = 0XFF; const foo = 0xff; const foo = 0Xff; +const foo = 0Xffn; ``` +[Binary](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Binary) + ```js -const foo = 0B11; +const foo = 0B10; +const foo = 0B10n; ``` +[Octal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Octal) + ```js -const foo = 0O10; +const foo = 0O76; +const foo = 0O76n; ``` +Exponential notation + +```js +const foo = 2E-5; +``` ## Pass @@ -29,9 +45,17 @@ const foo = 0xFF; ``` ```js -const foo = 0b11; +const foo = 0b10; +``` + +```js +const foo = 0o76; +``` + +```js +const foo = 0xFFn; ``` ```js -const foo = 0o10; +const foo = 2e+5; ``` diff --git a/readme.md b/readme.md index 1d73a498a5..3f4eb2b39c 100644 --- a/readme.md +++ b/readme.md @@ -113,7 +113,7 @@ Configure it in `package.json`. - [no-unsafe-regex](docs/rules/no-unsafe-regex.md) - Disallow unsafe regular expressions. - [no-unused-properties](docs/rules/no-unused-properties.md) - Disallow unused object properties. - [no-zero-fractions](docs/rules/no-zero-fractions.md) - Disallow number literals with zero fractions or dangling dots. *(fixable)* -- [number-literal-case](docs/rules/number-literal-case.md) - Enforce lowercase identifier and uppercase value for number literals. *(fixable)* +- [number-literal-case](docs/rules/number-literal-case.md) - Enforce proper case for numeric literals. *(fixable)* - [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) - Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. *(partly fixable)* - [prefer-dataset](docs/rules/prefer-dataset.md) - Prefer using `.dataset` on DOM elements over `.setAttribute(…)`. *(fixable)* - [prefer-event-key](docs/rules/prefer-event-key.md) - Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. *(partly fixable)* diff --git a/rules/number-literal-case.js b/rules/number-literal-case.js index 6a5c044480..737b68129b 100644 --- a/rules/number-literal-case.js +++ b/rules/number-literal-case.js @@ -1,28 +1,32 @@ 'use strict'; const getDocumentationUrl = require('./utils/get-documentation-url'); -const fix = value => { - if (!/^0[A-Za-z]/.test(value)) { - return value; +const fix = (value, isBigInt) => { + value = value.toLowerCase(); + if (value.startsWith('0x')) { + value = '0x' + value.slice(2).toUpperCase(); } - const indicator = value[1].toLowerCase(); - const newValue = value.slice(2).toUpperCase(); - - return `0${indicator}${newValue}`; + return `${value}${isBigInt ? 'n' : ''}`; }; const create = context => { return { Literal: node => { - const value = node.raw; - const fixedValue = fix(value); + const {value, raw, bigint} = node; + const isBigInt = Boolean(bigint); + + if (typeof value !== 'number' && !isBigInt) { + return; + } + + const fixed = fix(isBigInt ? bigint : raw, isBigInt); - if (value !== fixedValue) { + if (raw !== fixed) { context.report({ node, message: 'Invalid number literal casing.', - fix: fixer => fixer.replaceText(node, fixedValue) + fix: fixer => fixer.replaceText(node, fixed) }); } } diff --git a/test/number-literal-case.js b/test/number-literal-case.js index 2bb077144f..c70abf55bb 100644 --- a/test/number-literal-case.js +++ b/test/number-literal-case.js @@ -8,7 +8,7 @@ const ruleTester = avaRuleTester(test, { es6: true }, parserOptions: { - sourceType: 'module' + ecmaVersion: 2020 } }); @@ -17,43 +17,87 @@ const error = { message: 'Invalid number literal casing.' }; +// TODO: Add numeric separator tests when ESLint supports it. ruleTester.run('number-literal-case', rule, { valid: [ - 'const foo = 0xFF', - 'const foo = 0b11', - 'const foo = 0o10', - 'const foo = \'0Xff\'' + // Number + 'const foo = 1234', + 'const foo = 0777', + 'const foo = 0888', + 'const foo = 0b10', + 'const foo = 0o1234567', + 'const foo = 0xABCDEF', + + // BigInt + 'const foo = 1234n', + 'const foo = 0b10n', + 'const foo = 0o1234567n', + 'const foo = 0xABCDEFn', + + // Symbolic value + 'const foo = NaN', + 'const foo = +Infinity', + 'const foo = -Infinity', + + // Exponential notation + 'const foo = 1.2e3', + 'const foo = 1.2e-3', + 'const foo = 1.2e+3', + + // Not number + 'const foo = \'0Xff\'', + 'const foo = \'0Xffn\'' ], invalid: [ + // Number { - code: 'const foo = 0XFF', + code: 'const foo = 0B10', errors: [error], - output: 'const foo = 0xFF' + output: 'const foo = 0b10' }, { - code: 'const foo = 0xff', + code: 'const foo = 0O1234567', errors: [error], - output: 'const foo = 0xFF' + output: 'const foo = 0o1234567' }, { - code: 'const foo = 0Xff', + code: 'const foo = 0XaBcDeF', + errors: [error], + output: 'const foo = 0xABCDEF' + }, + + // BigInt + { + code: 'const foo = 0B10n', errors: [error], - output: 'const foo = 0xFF' + output: 'const foo = 0b10n' }, { - code: 'const foo = 0Xff', + code: 'const foo = 0O1234567n', + errors: [error], + output: 'const foo = 0o1234567n' + }, + { + code: 'const foo = 0XaBcDeFn', + errors: [error], + output: 'const foo = 0xABCDEFn' + }, + + // Exponential notation + { + code: 'const foo = 1.2E3', errors: [error], - output: 'const foo = 0xFF' + output: 'const foo = 1.2e3' }, { - code: 'const foo = 0B11', + code: 'const foo = 1.2E-3', errors: [error], - output: 'const foo = 0b11' + output: 'const foo = 1.2e-3' }, { - code: 'const foo = 0O10', + code: 'const foo = 1.2E+3', errors: [error], - output: 'const foo = 0o10' + output: 'const foo = 1.2e+3' }, { code: outdent`