|                                                                                                                                                    |  | /** * @fileoverview Rule to disallow `parseInt()` in favor of binary, octal, and hexadecimal literals * @author Annie Zhang, Henry Zhu */
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
const radixMap = new Map([    [2, { system: "binary", literalPrefix: "0b" }],    [8, { system: "octal", literalPrefix: "0o" }],    [16, { system: "hexadecimal", literalPrefix: "0x" }]]);
/** * Checks to see if a CallExpression's callee node is `parseInt` or * `Number.parseInt`. * @param {ASTNode} calleeNode The callee node to evaluate. * @returns {boolean} True if the callee is `parseInt` or `Number.parseInt`, * false otherwise. */function isParseInt(calleeNode) {    return (        astUtils.isSpecificId(calleeNode, "parseInt") ||        astUtils.isSpecificMemberAccess(calleeNode, "Number", "parseInt")    );}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../shared/types').Rule} */module.exports = {    meta: {        type: "suggestion",
        docs: {            description: "Disallow `parseInt()` and `Number.parseInt()` in favor of binary, octal, and hexadecimal literals",            recommended: false,            url: "https://eslint.org/docs/latest/rules/prefer-numeric-literals"        },
        schema: [],
        messages: {            useLiteral: "Use {{system}} literals instead of {{functionName}}()."        },
        fixable: "code"    },
    create(context) {        const sourceCode = context.sourceCode;
        //----------------------------------------------------------------------
        // Public
        //----------------------------------------------------------------------
        return {
            "CallExpression[arguments.length=2]"(node) {                const [strNode, radixNode] = node.arguments,                    str = astUtils.getStaticStringValue(strNode),                    radix = radixNode.value;
                if (                    str !== null &&                    astUtils.isStringLiteral(strNode) &&                    radixNode.type === "Literal" &&                    typeof radix === "number" &&                    radixMap.has(radix) &&                    isParseInt(node.callee)                ) {
                    const { system, literalPrefix } = radixMap.get(radix);
                    context.report({                        node,                        messageId: "useLiteral",                        data: {                            system,                            functionName: sourceCode.getText(node.callee)                        },                        fix(fixer) {                            if (sourceCode.getCommentsInside(node).length) {                                return null;                            }
                            const replacement = `${literalPrefix}${str}`;
                            if (+replacement !== parseInt(str, radix)) {
                                /*                                 * If the newly-produced literal would be invalid, (e.g. 0b1234),                                 * or it would yield an incorrect parseInt result for some other reason, don't make a fix.                                 *                                 * If `str` had numeric separators, `+replacement` will evaluate to `NaN` because unary `+`                                 * per the specification doesn't support numeric separators. Thus, the above condition will be `true`                                 * (`NaN !== anything` is always `true`) regardless of the `parseInt(str, radix)` value.                                 * Consequently, no autofixes will be made. This is correct behavior because `parseInt` also                                 * doesn't support numeric separators, but it does parse part of the string before the first `_`,                                 * so the autofix would be invalid:                                 *                                 *   parseInt("1_1", 2) // === 1
                                 *   0b1_1 // === 3
                                 */                                return null;                            }
                            const tokenBefore = sourceCode.getTokenBefore(node),                                tokenAfter = sourceCode.getTokenAfter(node);                            let prefix = "",                                suffix = "";
                            if (                                tokenBefore &&                                tokenBefore.range[1] === node.range[0] &&                                !astUtils.canTokensBeAdjacent(tokenBefore, replacement)                            ) {                                prefix = " ";                            }
                            if (                                tokenAfter &&                                node.range[1] === tokenAfter.range[0] &&                                !astUtils.canTokensBeAdjacent(replacement, tokenAfter)                            ) {                                suffix = " ";                            }
                            return fixer.replaceText(node, `${prefix}${replacement}${suffix}`);                        }                    });                }            }        };    }};
 |