/**
 * Shared AST traversal helpers.
 *
 * Provides a single recursive walk implementation that is reused across
 * validators and analysis passes, eliminating the repetition of the same
 * structural recursion in each consumer.
 */

/**
 * Visits every statement in a tree depth-first, calling visitor(stmt) for each node.
 * Recurses into all standard nested statement lists:
 *   body, consequent, alternate, branches[*].body, otherwise
 *
 * The visitor receives (stmt, index, siblings) and may return false to prevent
 * recursion into that node's children. All other return values allow recursion.
 *
 * Example — collect all ReturnStatements without crossing function boundaries:
 *
 *   const returns = [];
 *   walkStatements(body, stmt => {
 *       if (stmt.type === NodeType.ReturnStatement) returns.push(stmt);
 *       if (stmt.type === NodeType.FunctionDeclaration) return false;
 *   });
 *
 * @param {object[]} statements
 * @param {function(stmt: object, index: number, siblings: object[]): boolean|void} visitor
 */
function walkStatements(statements, visitor) {
    for (let i = 0; i < statements.length; i++) {
        const stmt = statements[i];
        const descend = visitor(stmt, i, statements);
        if (descend === false) continue;
        if (Array.isArray(stmt.body))       walkStatements(stmt.body,       visitor);
        if (Array.isArray(stmt.consequent)) walkStatements(stmt.consequent, visitor);
        if (Array.isArray(stmt.alternate))  walkStatements(stmt.alternate,  visitor);
        if (stmt.branches) {
            for (const b of stmt.branches) {
                if (Array.isArray(b.body)) walkStatements(b.body, visitor);
            }
        }
        if (Array.isArray(stmt.otherwise))  walkStatements(stmt.otherwise,  visitor);
    }
}

export { walkStatements };
