@@ -2,6 +2,10 @@ import {
22 isCallExpression ,
33 isStringLiteral ,
44} from './ast/index.js' ;
5+ import {
6+ needsSemicolon ,
7+ isParenthesized ,
8+ } from './utils/index.js' ;
59
610const MESSAGE_ID_ERROR = 'prefer-bigint-literals/error' ;
711const MESSAGE_ID_SUGGESTION = 'prefer-bigint-literals/suggestion' ;
@@ -39,13 +43,33 @@ const canUseNumericLiteralRaw = numericLiteral => {
3943function getReplacement ( valueNode ) {
4044 if ( isStringLiteral ( valueNode ) ) {
4145 const raw = valueNode . raw . slice ( 1 , - 1 ) ;
46+ let bigint ;
4247 try {
43- BigInt ( raw ) ;
48+ bigint = BigInt ( raw ) ;
4449 } catch {
4550 return ;
4651 }
4752
48- return { shouldUseSuggestion : false , text : `${ raw . trimEnd ( ) } n` } ;
53+ let text = bigint === 0n ? '0' : raw . trim ( ) ;
54+ if ( text . startsWith ( '+' ) ) {
55+ text = text . slice ( 1 ) . trim ( ) ;
56+ }
57+
58+ return { shouldUseSuggestion : raw . includes ( '+' ) , text : `${ text } n` , bigint} ;
59+ }
60+
61+ let shouldUseSuggestion = false ;
62+ let isNegated = false ;
63+ while ( valueNode . type === 'UnaryExpression' && valueNode . prefix ) {
64+ if ( valueNode . operator === '+' ) {
65+ shouldUseSuggestion = true ;
66+ valueNode = valueNode . argument ;
67+ } else if ( valueNode . operator === '-' ) {
68+ isNegated = ! isNegated ;
69+ valueNode = valueNode . argument ;
70+ } else {
71+ return ;
72+ }
4973 }
5074
5175 const { value, raw} = valueNode ;
@@ -61,9 +85,20 @@ function getReplacement(valueNode) {
6185 return ;
6286 }
6387
64- const shouldUseSuggestion = ! canUseNumericLiteralRaw ( valueNode ) ;
65- const text = shouldUseSuggestion ? `${ bigint } n` : `${ raw } n` ;
66- return { shouldUseSuggestion, text} ;
88+ let text ;
89+ if ( canUseNumericLiteralRaw ( valueNode ) ) {
90+ text = `${ raw } n` ;
91+ } else {
92+ text = `${ bigint } n` ;
93+ shouldUseSuggestion = true ;
94+ }
95+
96+ if ( isNegated && bigint !== 0n ) {
97+ text = `-${ text } ` ;
98+ bigint = - bigint ;
99+ }
100+
101+ return { shouldUseSuggestion, text, bigint} ;
67102}
68103
69104/** @param {import('eslint').Rule.RuleContext } context */
@@ -88,10 +123,23 @@ const create = context => {
88123 messageId : MESSAGE_ID_ERROR ,
89124 } ;
90125
91- const { shouldUseSuggestion, text} = replacement ;
126+ const { shouldUseSuggestion, text, bigint } = replacement ;
92127
93128 /** @param {import('eslint').Rule.RuleFixer } fixer */
94- const fix = fixer => fixer . replaceText ( callExpression , text ) ;
129+ const fix = fixer => {
130+ let replacementText = text ;
131+ if ( ! isParenthesized ( callExpression , context ) && bigint < 0n ) {
132+ replacementText = `(${ replacementText } )` ;
133+
134+ const tokenBefore = context . sourceCode . getTokenBefore ( callExpression ) ;
135+
136+ if ( needsSemicolon ( tokenBefore , context , replacementText ) ) {
137+ replacementText = `;${ replacementText } ` ;
138+ }
139+ }
140+
141+ return fixer . replaceText ( callExpression , replacementText ) ;
142+ } ;
95143
96144 if ( shouldUseSuggestion || context . sourceCode . getCommentsInside ( callExpression ) . length > 0 ) {
97145 problem . suggest = [
0 commit comments