/**
 * Maximum recursion depth for tree-sitter AST walkers.
 * Shared across all language extractors to prevent stack overflow on deeply nested ASTs.
 */
export const MAX_WALK_DEPTH = 200;
export function nodeEndLine(node) {
    return node.endPosition.row + 1;
}
export function findChild(node, type) {
    for (let i = 0; i < node.childCount; i++) {
        const child = node.child(i);
        if (child && child.type === type)
            return child;
    }
    return null;
}
/**
 * Merge a type-map entry, keeping the higher-confidence one.
 * Shared across all language extractors that build type maps for call resolution.
 */
export function setTypeMapEntry(typeMap, name, type, confidence) {
    const existing = typeMap.get(name);
    if (!existing || confidence > existing.confidence) {
        typeMap.set(name, { type, confidence });
    }
}
/**
 * Extract visibility from a node by scanning its children for modifier keywords.
 * Works for Java, C#, PHP, and similar languages where modifiers are child nodes.
 * @param {object} node - tree-sitter node
 * @param {Set<string>} [modifierTypes] - node types that indicate modifiers
 * @returns {'public'|'private'|'protected'|undefined}
 */
const DEFAULT_MODIFIER_TYPES = new Set([
    'modifiers',
    'modifier',
    'visibility_modifier',
    'accessibility_modifier',
]);
const VISIBILITY_KEYWORDS = new Set(['public', 'private', 'protected']);
/**
 * Python convention: __name → private, _name → protected, else undefined.
 */
export function pythonVisibility(name) {
    if (name.startsWith('__') && name.endsWith('__'))
        return undefined; // dunder — public
    if (name.startsWith('__'))
        return 'private';
    if (name.startsWith('_'))
        return 'protected';
    return undefined;
}
/**
 * Go convention: uppercase first letter → public, lowercase → private.
 */
export function goVisibility(name) {
    if (!name)
        return undefined;
    // Strip receiver prefix (e.g., "Receiver.Method" → check "Method")
    const bare = name.includes('.') ? (name.split('.').pop() ?? name) : name;
    if (!bare)
        return undefined;
    const first = bare[0];
    if (!first)
        return undefined;
    return first === first.toUpperCase() && first !== first.toLowerCase() ? 'public' : 'private';
}
/**
 * Rust: check for `visibility_modifier` child (pub, pub(crate), etc.).
 */
export function rustVisibility(node) {
    for (let i = 0; i < node.childCount; i++) {
        const child = node.child(i);
        if (!child)
            continue;
        if (child.type === 'visibility_modifier') {
            return 'public'; // pub, pub(crate), pub(super) all mean "visible"
        }
    }
    return 'private';
}
// ── Parser abstraction helpers ─────────────────────────────────────────────
/**
 * Walk up the parent chain to find an enclosing node whose type is in `typeNames`.
 * Returns the text of `nameField` (default `'name'`) on the matching ancestor, or null.
 *
 * Replaces per-language `findParentClass` / `findParentType` / `findCurrentImpl` helpers.
 */
export function findParentNode(node, typeNames, nameField = 'name') {
    let current = node.parent;
    while (current) {
        if (typeNames.includes(current.type)) {
            const nameNode = current.childForFieldName(nameField);
            return nameNode ? nameNode.text : null;
        }
        current = current.parent;
    }
    return null;
}
/**
 * Resolve a container's body node by trying each field name in order.
 */
function resolveBodyNode(containerNode, bodyFields) {
    for (const field of bodyFields) {
        const body = containerNode.childForFieldName(field) || findChild(containerNode, field);
        if (body)
            return body;
    }
    return null;
}
/**
 * Extract child declarations from a container node's body.
 * Finds the body via `bodyFields` (tries childForFieldName then findChild for each),
 * iterates its children, filters by `memberType`, extracts `nameField`, and returns SubDeclarations.
 *
 * Replaces per-language extractStructFields / extractEnumVariants / extractEnumConstants helpers
 * for the common case where each member has a direct name field.
 */
export function extractBodyMembers(containerNode, bodyFields, memberType, kind, nameField = 'name', visibility) {
    const body = resolveBodyNode(containerNode, bodyFields);
    if (!body)
        return [];
    const members = [];
    for (let i = 0; i < body.childCount; i++) {
        const member = body.child(i);
        if (!member || member.type !== memberType)
            continue;
        const nn = member.childForFieldName(nameField);
        if (!nn)
            continue;
        const entry = { name: nn.text, kind, line: member.startPosition.row + 1 };
        if (visibility)
            entry.visibility = visibility(member);
        members.push(entry);
    }
    return members;
}
/**
 * Strip leading/trailing quotes (single, double, or backtick) from a string.
 * Strips only the leading/trailing delimiter; interior quotes are untouched.
 */
export function stripQuotes(text) {
    return text.replace(/^['"`]|['"`]$/g, '');
}
/**
 * Extract the last segment of a delimited path.
 * e.g. `lastPathSegment('java.util.List', '.')` → `'List'`
 */
export function lastPathSegment(path, separator = '/') {
    return path.split(separator).pop() ?? path;
}
/**
 * Parse visibility from a modifier node's text content.
 */
function parseModifierText(text) {
    if (VISIBILITY_KEYWORDS.has(text))
        return text;
    // C# 'private protected' — accessible to derived types in same assembly → protected
    if (text === 'private protected')
        return 'protected';
    // Compound modifiers node (Java: "public static") — scan its text for a keyword
    for (const kw of VISIBILITY_KEYWORDS) {
        if (text.includes(kw))
            return kw;
    }
    return undefined;
}
export function extractModifierVisibility(node, modifierTypes = DEFAULT_MODIFIER_TYPES) {
    for (let i = 0; i < node.childCount; i++) {
        const child = node.child(i);
        if (!child || !modifierTypes.has(child.type))
            continue;
        const result = parseModifierText(child.text);
        if (result)
            return result;
    }
    return undefined;
}
//# sourceMappingURL=helpers.js.map