From 3960617bece1f23c7ba5560f3f9df5eda835cd59 Mon Sep 17 00:00:00 2001 From: Annie Zhang Date: Sun, 4 Sep 2016 19:15:33 -0400 Subject: [PATCH] New: `prefer-numeric-literals` rule (fixes #6068) (#7029) --- conf/eslint.json | 1 + docs/rules/prefer-numeric-literals.md | 49 +++++++++++++++++ lib/rules/prefer-numeric-literals.js | 62 ++++++++++++++++++++++ tests/lib/rules/prefer-numeric-literals.js | 47 ++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 docs/rules/prefer-numeric-literals.md create mode 100644 lib/rules/prefer-numeric-literals.js create mode 100644 tests/lib/rules/prefer-numeric-literals.js diff --git a/conf/eslint.json b/conf/eslint.json index 3be9be258be..4850d3dc465 100755 --- a/conf/eslint.json +++ b/conf/eslint.json @@ -199,6 +199,7 @@ "padded-blocks": "off", "prefer-arrow-callback": "off", "prefer-const": "off", + "prefer-numeric-literals": "off", "prefer-reflect": "off", "prefer-rest-params": "off", "prefer-spread": "off", diff --git a/docs/rules/prefer-numeric-literals.md b/docs/rules/prefer-numeric-literals.md new file mode 100644 index 00000000000..f4c70b6d3c4 --- /dev/null +++ b/docs/rules/prefer-numeric-literals.md @@ -0,0 +1,49 @@ +# disallow `parseInt()` in favor of binary, octal, and hexadecimal literals (prefer-numeric-literals) + +The `parseInt()` function can be used to turn binary, octal, and hexadecimal strings into integers. As binary, octal, and hexadecimal literals are supported in ES6, this rule encourages use of those numeric literals instead of `parseInt()`. + +```js +0b111110111 === 503; +0o767 === 503; +``` + +## Rule Details + +This rule disallows `parseInt()` if it is called with two arguments: a string and a radix option of 2 (binary), 8 (octal), or 16 (hexadecimal). + +Examples of **incorrect** code for this rule: + +```js +/*eslint prefer-numeric-literals: "error"*/ + +parseInt("111110111", 2) === 503; +parseInt("767", 8) === 503; +parseInt("1F7", 16) === 255; +``` + +Examples of **correct** code for this rule: + +```js +/*eslint prefer-numeric-literals: "error"*/ +/*eslint-env es6*/ + +parseInt(1); +parseInt(1, 3); + +0b111110111 === 503; +0o767 === 503; +0x1F7 === 503; + +a[parseInt](1,2); + +parseInt(foo); +parseInt(foo, 2); +``` + +## When Not To Use It + +If you want to allow use of `parseInt()` for binary, octal, or hexadecimal integers. If you are not using ES6 (because binary and octal literals are not supported in ES5 and below). + +## Compatibility + +* **JSCS**: [requireNumericLiterals](http://jscs.info/rule/requireNumericLiterals) diff --git a/lib/rules/prefer-numeric-literals.js b/lib/rules/prefer-numeric-literals.js new file mode 100644 index 00000000000..1e3bed59158 --- /dev/null +++ b/lib/rules/prefer-numeric-literals.js @@ -0,0 +1,62 @@ +/** + * @fileoverview Rule to disallow `parseInt()` in favor of binary, octal, and hexadecimal literals + * @author Annie Zhang, Henry Zhu + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: "disallow `parseInt()` in favor of binary, octal, and hexadecimal literals", + category: "ECMAScript 6", + recommended: false + }, + + schema: [] + }, + + create(context) { + const radixMap = { + 2: "binary", + 8: "octal", + 16: "hexadecimal" + }; + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + return { + + CallExpression(node) { + + // doesn't check parseInt() if it doesn't have a radix argument + if (node.arguments.length !== 2) { + return; + } + + // only error if the radix is 2, 8, or 16 + const radixName = radixMap[node.arguments[1].value]; + + if (node.callee.type === "Identifier" && + node.callee.name === "parseInt" && + radixName && + node.arguments[0].type === "Literal" + ) { + context.report({ + node, + message: "Use {{radixName}} literals instead of parseInt().", + data: { + radixName + } + }); + } + } + }; + } +}; diff --git a/tests/lib/rules/prefer-numeric-literals.js b/tests/lib/rules/prefer-numeric-literals.js new file mode 100644 index 00000000000..a63295ad5bb --- /dev/null +++ b/tests/lib/rules/prefer-numeric-literals.js @@ -0,0 +1,47 @@ +/** + * @fileoverview Tests for prefer-numeric-literals rule. + * @author Annie Zhang + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const rule = require("../../../lib/rules/prefer-numeric-literals"), + RuleTester = require("../../../lib/testers/rule-tester"); + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester(); + +ruleTester.run("prefer-numeric-literals", rule, { + valid: [ + "parseInt(1);", + "parseInt(1, 3);", + { code: "0b111110111 === 503;", parserOptions: { ecmaVersion: 6 } }, + { code: "0o767 === 503;", parserOptions: { ecmaVersion: 6 } }, + "0x1F7 === 503;", + "a[parseInt](1,2);", + "parseInt(foo);", + "parseInt(foo, 2);" + ], + invalid: [ + { + code: "parseInt(\"111110111\", 2) === 503;", + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Use binary literals instead of parseInt()." }] + }, { + code: "parseInt(\"767\", 8) === 503;", + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Use octal literals instead of parseInt()." }] + }, { + code: "parseInt(\"1F7\", 16) === 255;", + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Use hexadecimal literals instead of parseInt()." }] + } + ] +});