lib/rules/prefer-const.js
function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) {
    if (variable.eslintUsed && variable.scope.type === "global") {
        return null;
    }

    // Finds the unique WriteReference.
    let writer = null;
    let isReadBeforeInit = false;
    const references = variable.references;

    for (let i = 0; i < references.length; ++i) {
        const reference = references[i];

        if (reference.isWrite()) {
            const isReassigned = (
                writer !== null &&
                writer.identifier !== reference.identifier
            );

            if (isReassigned) {
                return null;
            }

            const destructuringHost = getDestructuringHost(reference);

            if (destructuringHost !== null && destructuringHost.left !== void 0) {
                const leftNode = destructuringHost.left;
                let hasOuterVariables = false,
                    hasNonIdentifiers = false;

                if (leftNode.type === "ObjectPattern") {
                    const properties = leftNode.properties;

                    hasOuterVariables = properties
                        .filter(prop => prop.value)
                        .map(prop => prop.value.name)
                        .some(name => isOuterVariableInDestructing(name, variable.scope));

                    hasNonIdentifiers = hasMemberExpressionAssignment(leftNode);

                } else if (leftNode.type === "ArrayPattern") {
                    const elements = leftNode.elements;

                    hasOuterVariables = elements
                        .map(element => element && element.name)
                        .some(name => isOuterVariableInDestructing(name, variable.scope));

                    hasNonIdentifiers = hasMemberExpressionAssignment(leftNode);
                }

                if (hasOuterVariables || hasNonIdentifiers) {
                    return null;
                }

            }

            writer = reference;

        } else if (reference.isRead() && writer === null) {
            if (ignoreReadBeforeAssign) {
                return null;
            }
            isReadBeforeInit = true;
        }
    }

    /*
     * If the assignment is from a different scope, ignore it.
     * If the assignment cannot change to a declaration, ignore it.
     */
    const shouldBeConst = (
        writer !== null &&
        writer.from === variable.scope &&
        canBecomeVariableDeclaration(writer.identifier)
    );

    if (!shouldBeConst) {
        return null;
    }

    if (isReadBeforeInit) {
        return variable.defs[0].name;
    }

    return writer.identifier;
}
function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) {
    if (variable.eslintUsed && variable.scope.type === "global") {
        return null;
    }

    // Finds the unique WriteReference.
    let writer = null;
    let isReadBeforeInit = false;
    const references = variable.references;

    for (let i = 0; i < references.length; ++i) {
        const reference = references[i];

        if (reference.isWrite()) {
            const isReassigned = (
                writer !== null &&
                writer.identifier !== reference.identifier
            );

            if (isReassigned) {
                return null;
            }

            const destructuringHost = getDestructuringHost(reference);

            if (destructuringHost !== null && destructuringHost.left !== void 0) {
                const leftNode = destructuringHost.left;
                let hasOuterVariables = false,
                    hasNonIdentifiers = false;

                if (leftNode.type === "ObjectPattern") {
                    const properties = leftNode.properties;

                    hasOuterVariables = properties
                        .filter(prop => prop.value)
                        .map(prop => prop.value.name)
                        .some(name => isOuterVariableInDestructing(name, variable.scope));

                    hasNonIdentifiers = hasMemberExpressionAssignment(leftNode);

                } else if (leftNode.type === "ArrayPattern") {
                    const elements = leftNode.elements;

                    hasOuterVariables = elements
                        .map(element => element && element.name)
                        .some(name => isOuterVariableInDestructing(name, variable.scope));

                    hasNonIdentifiers = hasMemberExpressionAssignment(leftNode);
                }

                if (hasOuterVariables || hasNonIdentifiers) {
                    return null;
                }

            }

            writer = reference;

        } else if (reference.isRead() && writer === null) {
            if (ignoreReadBeforeAssign) {
                return null;
            }
            isReadBeforeInit = true;
        }
    }

    /*
     * If the assignment is from a different scope, ignore it.
     * If the assignment cannot change to a declaration, ignore it.
     */
    const shouldBeConst = (
        writer !== null &&
        writer.from === variable.scope &&
        canBecomeVariableDeclaration(writer.identifier)
    );

    if (!shouldBeConst) {
        return null;
    }

    if (isReadBeforeInit) {
        return variable.defs[0].name;
    }

    return writer.identifier;
}
function getIdentifierIfShouldBeConst ( variable , ignoreReadBeforeAssign ) { if ( variable . eslintUsed && variable . scope . type === "global" ) { return null ; } // Finds the unique WriteReference. let writer = null ; let isReadBeforeInit = false ; const references = variable . references ; for ( let i = 0 ; i < references . length ; ++ i ) { const reference = references [ i ] ; if ( reference . isWrite ( ) ) { const isReassigned = ( writer !== null && writer . identifier !== reference . identifier ) ; if ( isReassigned ) { return null ; } const destructuringHost = getDestructuringHost ( reference ) ; if ( destructuringHost !== null && destructuringHost . left !== void 0 ) { const leftNode = destructuringHost . left ; let hasOuterVariables = false , hasNonIdentifiers = false ; if ( leftNode . type === "ObjectPattern" ) { const properties = leftNode . properties ; hasOuterVariables = properties . filter ( prop => prop . value ) . map ( prop => prop . value . name ) . some ( name => isOuterVariableInDestructing ( name , variable . scope ) ) ; hasNonIdentifiers = hasMemberExpressionAssignment ( leftNode ) ; } else if ( leftNode . type === "ArrayPattern" ) { const elements = leftNode . elements ; hasOuterVariables = elements . map ( element => element && element . name ) . some ( name => isOuterVariableInDestructing ( name , variable . scope ) ) ; hasNonIdentifiers = hasMemberExpressionAssignment ( leftNode ) ; } if ( hasOuterVariables || hasNonIdentifiers ) { return null ; } } writer = reference ; } else if ( reference . isRead ( ) && writer === null ) { if ( ignoreReadBeforeAssign ) { return null ; } isReadBeforeInit = true ; } } /*
     * If the assignment is from a different scope, ignore it.
     * If the assignment cannot change to a declaration, ignore it.
     */ const shouldBeConst = ( writer !== null && writer . from === variable . scope && canBecomeVariableDeclaration ( writer . identifier ) ) ; if ( ! shouldBeConst ) { return null ; } if ( isReadBeforeInit ) { return variable . defs [ 0 ] . name ; } return writer . identifier ; }
Gets an identifier node of a given variable.

If the initialization exists or one or more reading references exist before
the first assignment, the identifier node is the node of the declaration.
Otherwise, the identifier node is the node of the first assignment.

If the variable should not change to const, this function returns null.
- If the variable is reassigned.
- If the variable is never initialized nor assigned.
- If the variable is initialized in a different scope from the declaration.
- If the unique assignment of the variable cannot change to a declaration.
e.g. `if (a) b = 1` / `return (b = 1)`
- If the variable is declared in the global scope and `eslintUsed` is `true`.
`/*exported foo` directive comment makes such variables. This rule does not
warn such variables because this rule cannot distinguish whether the
exported variables are reassigned or not.

@param {eslint-scope.Variable} variable - A variable to get.
@param {boolean} ignoreReadBeforeAssign -
The value of `ignoreReadBeforeAssign` option.
@returns {ASTNode|null}
An Identifier node if the variable should change to const.
Otherwise, null.
Gets an identifier node of a given variable .