diff --git a/docs/rules/no-magic-numbers.md b/docs/rules/no-magic-numbers.md index ee6d3de7ee7..d0d6cdff96d 100644 --- a/docs/rules/no-magic-numbers.md +++ b/docs/rules/no-magic-numbers.md @@ -128,6 +128,20 @@ a = data[4294967295]; // above the max array index a = data[1e500]; // same as data["Infinity"] ``` +### ignoreDefaultValues + +A boolean to specify if numbers used in default value assignments are considered okay. `false` by default. + +Examples of **correct** code for the `{ "ignoreDefaultValues": true }` option: + +```js +/*eslint no-magic-numbers: ["error", { "ignoreDefaultValues": true }]*/ + +const { tax = 0.25 } = accountancy; + +function mapParallel(concurrency = 3) { /***/ } +``` + ### enforceConst A boolean to specify if we should check for the const keyword in variable declaration of numbers. `false` by default. diff --git a/lib/rules/no-magic-numbers.js b/lib/rules/no-magic-numbers.js index cd07f5c3bda..68153506a71 100644 --- a/lib/rules/no-magic-numbers.js +++ b/lib/rules/no-magic-numbers.js @@ -61,6 +61,10 @@ module.exports = { ignoreArrayIndexes: { type: "boolean", default: false + }, + ignoreDefaultValues: { + type: "boolean", + default: false } }, additionalProperties: false @@ -77,7 +81,8 @@ module.exports = { detectObjects = !!config.detectObjects, enforceConst = !!config.enforceConst, ignore = (config.ignore || []).map(normalizeIgnoreValue), - ignoreArrayIndexes = !!config.ignoreArrayIndexes; + ignoreArrayIndexes = !!config.ignoreArrayIndexes, + ignoreDefaultValues = !!config.ignoreDefaultValues; const okTypes = detectObjects ? [] : ["ObjectExpression", "Property", "AssignmentExpression"]; @@ -90,6 +95,16 @@ module.exports = { return ignore.indexOf(value) !== -1; } + /** + * Returns whether the number should be ignore when used as a default + * value assignment. + * @param {ASTNode} parent the non-"UnaryExpression" parent. + * @returns {boolean} true if the number should be ignored + */ + function isIgnoredDefaultValue(parent) { + return parent.type === "AssignmentPattern" && ignoreDefaultValues; + } + /** * Returns whether the given node is used as a radix within parseInt() or Number.parseInt() * @param {ASTNode} fullNumberNode `Literal` or `UnaryExpression` full number node @@ -176,9 +191,12 @@ module.exports = { raw = node.raw; } + const parent = fullNumberNode.parent; + // Always allow radix arguments and JSX props if ( isIgnoredValue(value) || + isIgnoredDefaultValue(parent) || isParseIntRadix(fullNumberNode) || isJSXNumber(fullNumberNode) || (ignoreArrayIndexes && isArrayIndex(fullNumberNode, value)) @@ -186,8 +204,6 @@ module.exports = { return; } - const parent = fullNumberNode.parent; - if (parent.type === "VariableDeclarator") { if (enforceConst && parent.parent.kind !== "const") { context.report({ diff --git a/tests/lib/rules/no-magic-numbers.js b/tests/lib/rules/no-magic-numbers.js index da75571ec28..4e706db9506 100644 --- a/tests/lib/rules/no-magic-numbers.js +++ b/tests/lib/rules/no-magic-numbers.js @@ -213,6 +213,16 @@ ruleTester.run("no-magic-numbers", rule, { code: "f(-100n)", options: [{ ignore: ["-100n"] }], parserOptions: { ecmaVersion: 2020 } + }, + { + code: "const { param = 123 } = sourceObject;", + options: [{ ignoreDefaultValues: true }], + env: { es6: true } + }, + { + code: "const func = ({ param = 123 }) => {}", + options: [{ ignoreDefaultValues: true }], + env: { es6: true } } ], invalid: [ @@ -719,6 +729,14 @@ ruleTester.run("no-magic-numbers", rule, { errors: [ { messageId: "noMagic", data: { raw: "100" }, line: 1 } ] + }, + { + code: "const { param = 123 } = sourceObject;", + options: [{ ignoreDefaultValues: false }], + env: { es6: true }, + errors: [ + { messageId: "noMagic", data: { raw: "123" }, line: 1 } + ] } ] });