diff --git a/rules/prefer-bigint-literals.js b/rules/prefer-bigint-literals.js index aaca442415..34adca3c41 100644 --- a/rules/prefer-bigint-literals.js +++ b/rules/prefer-bigint-literals.js @@ -10,15 +10,13 @@ const messages = { [MESSAGE_ID_SUGGESTION]: 'Replace with {{replacement}}.', }; -const canUseNumericLiteralRaw = numericLiteral => { - const raw = numericLiteral.raw.replaceAll('_', '').toLowerCase(); +const canUseNumericLiteralRaw = (value, nodeRaw) => { + const raw = nodeRaw.replaceAll('_', '').toLowerCase(); if (raw.includes('.')) { return false; } - const {value} = numericLiteral; - for (const {prefix, base} of [ {prefix: '0b', base: 2}, {prefix: '0o', base: 8}, @@ -36,19 +34,38 @@ const canUseNumericLiteralRaw = numericLiteral => { return raw === String(value); }; +function getValueOfNode(valueNode) { + // -BigInt(1) + if (valueNode.type === 'UnaryExpression' && (valueNode.operator === '+' || valueNode.operator === '-')) { + return valueNode.operator === '+' + ? {value: valueNode.argument.value, raw: valueNode.argument.raw, isPlusSignUnary: true} + : {value: -valueNode.argument.value, raw: `-${valueNode.argument.raw}`, isPlusSignUnary: false}; + } + + return {value: valueNode.value, raw: valueNode.raw, isPlusSignUnary: false}; +} + function getReplacement(valueNode) { if (isStringLiteral(valueNode)) { - const raw = valueNode.raw.slice(1, -1); + let raw = valueNode.raw.slice(1, -1); try { BigInt(raw); } catch { return; } + // BigInt("+1") -> 1n + const plusSignIndex = raw.indexOf('+'); + + if (plusSignIndex !== -1) { + raw = raw.slice(0, plusSignIndex) + raw.slice(plusSignIndex + 1); + return {shouldUseSuggestion: true, text: `${raw.trimEnd()}n`}; + } + return {shouldUseSuggestion: false, text: `${raw.trimEnd()}n`}; } - const {value, raw} = valueNode; + const {value, raw, isPlusSignUnary} = getValueOfNode(valueNode); if (!Number.isInteger(value)) { return; @@ -61,7 +78,7 @@ function getReplacement(valueNode) { return; } - const shouldUseSuggestion = !canUseNumericLiteralRaw(valueNode); + const shouldUseSuggestion = isPlusSignUnary ? true : !canUseNumericLiteralRaw(value, raw); const text = shouldUseSuggestion ? `${bigint}n` : `${raw}n`; return {shouldUseSuggestion, text}; } @@ -83,17 +100,30 @@ const create = context => ({ return; } + let {shouldUseSuggestion, text} = replacement; + let nodeToReplace = callExpression; + + const {parent} = callExpression; + + // -BigInt(-1) -> 1n + if ( + parent.type === 'UnaryExpression' + && parent.operator === '-' + && text.startsWith('-') + ) { + nodeToReplace = parent; + text = text.slice(1); + } + const problem = { - node: callExpression, + node: nodeToReplace, messageId: MESSAGE_ID_ERROR, }; - const {shouldUseSuggestion, text} = replacement; - /** @param {import('eslint').Rule.RuleFixer} fixer */ - const fix = fixer => fixer.replaceText(callExpression, text); + const fix = fixer => fixer.replaceText(nodeToReplace, text); - if (shouldUseSuggestion || context.sourceCode.getCommentsInside(callExpression).length > 0) { + if (shouldUseSuggestion || context.sourceCode.getCommentsInside(nodeToReplace).length > 0) { problem.suggest = [ { messageId: MESSAGE_ID_SUGGESTION, diff --git a/test/prefer-bigint-literals.js b/test/prefer-bigint-literals.js index 2fe1faedbb..dc18b1a246 100644 --- a/test/prefer-bigint-literals.js +++ b/test/prefer-bigint-literals.js @@ -25,6 +25,10 @@ test.snapshot({ 'BigInt("1_2")', 'BigInt("1\\\n2")', String.raw`BigInt("\u{31}")`, + 'BigInt(!1)', + 'BigInt(~1)', + 'BigInt("++1")', + 'BigInt("+ 1")', ], invalid: [ 'BigInt("0")', @@ -52,5 +56,22 @@ test.snapshot({ 'BigInt(1e2)', 'BigInt(/* comment */1)', `BigInt(${'9'.repeat(100)})`, + 'BigInt("-1")', + 'BigInt("+1")', + 'BigInt(-1)', + 'BigInt(+1)', + '-BigInt(-1)', + '-BigInt("-1")', + '-BigInt(1)', + '-BigInt("1")', + 'BigInt(" +1 ")', + 'BigInt(" -1 ")', + ` + foo + BigInt("-1") + `, + '-BigInt("+1")', + '-BigInt(/* comment */-1)', + '-(BigInt(-1))', ], }); diff --git a/test/snapshots/prefer-bigint-literals.js.md b/test/snapshots/prefer-bigint-literals.js.md index 347d367c98..27029a0b19 100644 --- a/test/snapshots/prefer-bigint-literals.js.md +++ b/test/snapshots/prefer-bigint-literals.js.md @@ -424,3 +424,296 @@ Generated by [AVA](https://avajs.dev). Suggestion 1/1: Replace with a bigint literal.␊ 1 | 10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104n␊ ` + +## invalid(22): BigInt("-1") + +> Input + + `␊ + 1 | BigInt("-1")␊ + ` + +> Output + + `␊ + 1 | -1n␊ + ` + +> Error 1/1 + + `␊ + > 1 | BigInt("-1")␊ + | ^^^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ` + +## invalid(23): BigInt("+1") + +> Input + + `␊ + 1 | BigInt("+1")␊ + ` + +> Error 1/1 + + `␊ + > 1 | BigInt("+1")␊ + | ^^^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Replace with \`1n\`.␊ + 1 | 1n␊ + ` + +## invalid(24): BigInt(-1) + +> Input + + `␊ + 1 | BigInt(-1)␊ + ` + +> Output + + `␊ + 1 | -1n␊ + ` + +> Error 1/1 + + `␊ + > 1 | BigInt(-1)␊ + | ^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ` + +## invalid(25): BigInt(+1) + +> Input + + `␊ + 1 | BigInt(+1)␊ + ` + +> Error 1/1 + + `␊ + > 1 | BigInt(+1)␊ + | ^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Replace with \`1n\`.␊ + 1 | 1n␊ + ` + +## invalid(26): -BigInt(-1) + +> Input + + `␊ + 1 | -BigInt(-1)␊ + ` + +> Output + + `␊ + 1 | 1n␊ + ` + +> Error 1/1 + + `␊ + > 1 | -BigInt(-1)␊ + | ^^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ` + +## invalid(27): -BigInt("-1") + +> Input + + `␊ + 1 | -BigInt("-1")␊ + ` + +> Output + + `␊ + 1 | 1n␊ + ` + +> Error 1/1 + + `␊ + > 1 | -BigInt("-1")␊ + | ^^^^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ` + +## invalid(28): -BigInt(1) + +> Input + + `␊ + 1 | -BigInt(1)␊ + ` + +> Output + + `␊ + 1 | -1n␊ + ` + +> Error 1/1 + + `␊ + > 1 | -BigInt(1)␊ + | ^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ` + +## invalid(29): -BigInt("1") + +> Input + + `␊ + 1 | -BigInt("1")␊ + ` + +> Output + + `␊ + 1 | -1n␊ + ` + +> Error 1/1 + + `␊ + > 1 | -BigInt("1")␊ + | ^^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ` + +## invalid(30): BigInt(" +1 ") + +> Input + + `␊ + 1 | BigInt(" +1 ")␊ + ` + +> Error 1/1 + + `␊ + > 1 | BigInt(" +1 ")␊ + | ^^^^^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Replace with \` 1n\`.␊ + 1 | 1n␊ + ` + +## invalid(31): BigInt(" -1 ") + +> Input + + `␊ + 1 | BigInt(" -1 ")␊ + ` + +> Output + + `␊ + 1 | -1n␊ + ` + +> Error 1/1 + + `␊ + > 1 | BigInt(" -1 ")␊ + | ^^^^^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ` + +## invalid(32): foo BigInt("-1") + +> Input + + `␊ + 1 |␊ + 2 | foo␊ + 3 | BigInt("-1")␊ + 4 | ␊ + ` + +> Output + + `␊ + 1 |␊ + 2 | foo␊ + 3 | -1n␊ + 4 | ␊ + ` + +> Error 1/1 + + `␊ + 1 |␊ + 2 | foo␊ + > 3 | BigInt("-1")␊ + | ^^^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + 4 | ␊ + ` + +## invalid(33): -BigInt("+1") + +> Input + + `␊ + 1 | -BigInt("+1")␊ + ` + +> Error 1/1 + + `␊ + > 1 | -BigInt("+1")␊ + | ^^^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Replace with \`1n\`.␊ + 1 | -1n␊ + ` + +## invalid(34): -BigInt(/* comment */-1) + +> Input + + `␊ + 1 | -BigInt(/* comment */-1)␊ + ` + +> Error 1/1 + + `␊ + > 1 | -BigInt(/* comment */-1)␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Replace with \`1n\`.␊ + 1 | 1n␊ + ` + +## invalid(35): -(BigInt(-1)) + +> Input + + `␊ + 1 | -(BigInt(-1))␊ + ` + +> Output + + `␊ + 1 | 1n␊ + ` + +> Error 1/1 + + `␊ + > 1 | -(BigInt(-1))␊ + | ^^^^^^^^^^^^^ Prefer using bigint literal over \`BigInt(…)\`.␊ + ` diff --git a/test/snapshots/prefer-bigint-literals.js.snap b/test/snapshots/prefer-bigint-literals.js.snap index acf4a24eb2..0870a6c1e7 100644 Binary files a/test/snapshots/prefer-bigint-literals.js.snap and b/test/snapshots/prefer-bigint-literals.js.snap differ