import type Parser from 'tree-sitter'; import type { Capture, NodeLabel, Range } from '../../../_shared/index.js'; import type { LanguageProvider } from '../language-provider.js'; /** Tree-sitter AST node. Re-exported for use across ingestion modules. */ export type SyntaxNode = Parser.SyntaxNode; /** * Qualify a Rust inherent-impl target (`impl Inner { ... }`) by its enclosing * `mod_item` scope, so a bare same-tail target nested under different modules * resolves to a DISTINCT path (`outer.Inner` vs `other.Inner`) — the #1982 * follow-up to #1975. Walks `mod_item` ancestors (outermost → innermost) and * joins them with the normalized raw target via the shared `splitQualifiedName`. * A top-level `impl Inner` (no enclosing mod) returns the bare target unchanged. * Keyed purely on tree-sitter node types (no language name), matching the * inherent-impl branch in `findEnclosingClassInfo`; the caller restricts this to * UNSCOPED targets (`type_identifier`) so a SCOPED `impl a::Inner` keeps its full * raw text (#1975). The Impl-node materialization in parsing-processor / * parse-worker mirrors this so the owner edge and node id agree byte-for-byte. */ export declare const qualifyRustImplTargetByModScope: (implNode: SyntaxNode, rawTargetText: string) => string; /** * #1991: scope-label predicate that single-sources the `nodeLabel === 'Trait'` * checks in parsing-processor.ts / parse-worker.ts. A Ruby `module` maps to the * `Trait` registry label but is NOT a typeDeclaration, so `extractQualifiedName` * bails on it; these node labels are instead qualified via the scope walk * (`qualifyScopeName`) so same-tail nested modules get distinct ids. Keeping the * literal in one place stops the four hand-maintained copies (two each in the * sequential and worker definition paths) from drifting apart. Pure predicate — * value-identical to the inlined `nodeLabel === 'Trait'`. */ export declare const isQualifiableScopeLabel: (nodeLabel: string) => boolean; /** * Ordered list of definition capture keys for tree-sitter query matches. * Used to extract the definition node from a capture map. */ export declare const DEFINITION_CAPTURE_KEYS: readonly ["definition.function", "definition.class", "definition.interface", "definition.method", "definition.struct", "definition.enum", "definition.namespace", "definition.module", "definition.trait", "definition.impl", "definition.type", "definition.const", "definition.static", "definition.variable", "definition.typedef", "definition.macro", "definition.union", "definition.property", "definition.record", "definition.delegate", "definition.annotation", "definition.constructor", "definition.template"]; /** Extract the definition node from a tree-sitter query capture map. */ export declare const getDefinitionNodeFromCaptures: (captureMap: Record) => SyntaxNode | null; type QueryMatchLike = { captures: Array<{ name: string; node: SyntaxNode; }>; }; export declare const buildConcreteTypedefDefinitionRanges: (matches: readonly QueryMatchLike[]) => Set; export declare const isSuppressedConcreteTypedefDuplicate: (captureMap: Record, concreteTypedefRanges: ReadonlySet) => boolean; /** * Node types that represent function/method definitions across languages. * Used by parent-walk in call-processor, parse-worker, and type-env to detect * enclosing function scope boundaries. * * INVARIANT: This set MUST be a superset of every language's * MethodExtractionConfig.methodNodeTypes. When adding a new node type to a * MethodExtractor config, add it here too — otherwise enclosing-function * resolution will silently miss that node type during parent-walks. */ export declare const FUNCTION_NODE_TYPES: Set; /** * AST node types that represent a class-like container (for HAS_METHOD edge extraction). * * INVARIANT: When a language config adds a new node type to `typeDeclarationNodes`, * that type must also be added here AND to `CONTAINER_TYPE_TO_LABEL` below, * otherwise `findEnclosingClassNode` won't recognize it and methods may get * orphaned HAS_METHOD edges or incorrect labels. */ export declare const CLASS_CONTAINER_TYPES: Set; export declare const CONTAINER_TYPE_TO_LABEL: Record; /** * Pre-order walk over a node and all its named descendants, invoking `cb` on * each. Replaces the per-language `visit`/`visitGo`/`visitRust`/`visitSwift` * clones that every language's capture-synthesis walker re-implemented (#1956 * tri-review U6). * * Iterates by index with a null guard: `node.namedChild(i)` is typed * `SyntaxNode | null`, and most callers already guarded it. The Go and C# * callers previously iterated `node.namedChildren`; the Go one had no null * guard, so this standardizes them onto the guarded indexed form — a deliberate, * strictly-safer behavior addition (the traversal *sequence* is identical, so * capture output stays byte-identical on well-formed trees; the guard only * matters for a null named child, which the fixture corpus never produces). */ export declare function walkNamedTree(node: SyntaxNode, cb: (node: SyntaxNode) => void): void; /** Return the first matching ancestor unless a boundary ancestor is reached first. */ export declare function findAncestorBeforeBoundary(node: SyntaxNode, targetTypes: ReadonlySet, boundaryTypes: ReadonlySet): SyntaxNode | null; /** * Determine the graph node label from a tree-sitter capture map. * Handles language-specific reclassification via the provider's labelOverride hook * (e.g. C/C++ duplicate skipping, Kotlin Method promotion). * Returns null if the capture should be skipped (import, call, C/C++ duplicate, missing name). */ export declare function getLabelFromCaptures(captureMap: Record, provider: LanguageProvider): NodeLabel | null; /** Enclosing class info: both the generated node ID and the bare class name. */ export interface EnclosingClassInfo { classId: string; className: string; /** * The owner node id keyed by the enclosing type's FULLY-QUALIFIED path * (e.g. "Class:file:Outer.Inner"), present only when the language opts into * `qualifiedNodeId` AND the enclosing type is actually nested (#1978). * Consumers building HAS_METHOD/HAS_PROPERTY owner edges use this in * preference to `classId` so the edge source matches the qualified class * node id. When absent, `classId` (the simple-tail key) is unchanged. */ qualifiedClassId?: string; } export declare const findEnclosingClassInfo: (node: SyntaxNode, filePath: string, resolveEnclosingOwner?: (node: SyntaxNode) => SyntaxNode | null, /** * Optional (#1978): returns the enclosing type's fully-qualified name * (e.g. "Outer.Inner") for a type-declaration container, or null. Callers * pass `classExtractor.extractQualifiedName` ONLY when the language's * `qualifiedNodeId` flag is on — so when omitted, behavior is byte-identical * to before (qualifiedClassId stays undefined). Used by the standard * class-container branch to compute `qualifiedClassId` from the SAME function * the node-id is built from, guaranteeing owner-id == node-id by construction. */ getQualifiedOwnerName?: (node: SyntaxNode, simpleName: string) => string | null) => EnclosingClassInfo | null; /** Object literal binding info for TS/JS shorthand methods. */ export interface ObjectLiteralBindingInfo { ownerId: string; } /** * Find the file-scope variable that owns an object literal method definition. * * Covers TypeScript/JavaScript shorthand object methods such as: * * export const service = { async load() {} }; * * tree-sitter represents `load` as a `method_definition` inside an `object`, * not inside a class container. Without this fallback, ingestion emits a * top-level `Method` node but no edge from the exported `service` value to * that method, so impact queries cannot discover `service.load`. * * Two-phase walk: * Phase A walks up from `node` tracking how many `object` ancestors we * cross. The first `variable_declarator` reached with `objectDepth >= 1` * is the candidate owner — unless `objectDepth > 1` (the method belongs * to a nested object literal; we return null rather than misattribute * to the outer binding). Hitting a function/class container before the * declarator returns null (catches IIFE-wrapped literals). * Phase B walks the declarator's own ancestors. Any function or class * ancestor before reaching `program`/`export_statement` returns null * (catches `const` declared inside a function body). Any block-statement * ancestor also returns null (catches block-scoped declarations inside * top-level `if`/`for`/`try`/etc., which cannot be imported). */ export declare const findObjectLiteralBindingInfo: (node: SyntaxNode, filePath: string) => ObjectLiteralBindingInfo | null; /** Convenience wrapper: returns just the class ID string (backward compat). */ export declare const findEnclosingClassId: (node: SyntaxNode, filePath: string) => string | null; /** * Find a child of `childType` within a sibling node of `siblingType`. * Used for Kotlin AST traversal where visibility_modifier lives inside a modifiers sibling. */ export declare const findSiblingChild: (parent: SyntaxNode, siblingType: string, childType: string) => SyntaxNode | null; /** Generic name extraction from a function-like AST node. * Tries `node.childForFieldName('name')?.text`, then scans children for * `identifier` / `property_identifier` / `simple_identifier`. * * `arrow_function` and `function_expression` (TS/JS) are inherently * anonymous — they have no `name` field, and their first identifier * child is a *parameter*, not a function name. Returning a parameter * identifier here would synthesize phantom Function IDs (e.g. callers * walking up from a call inside `arr.map(x => fn(x))` would get * attributed to a non-existent "Function x"). The language's * `methodExtractor.extractFunctionName` hook is responsible for naming * these via parent context (variable_declarator, pair, etc.); when it * declines, the parent walk should continue rather than fall through * here. See issue #1166. */ export declare const genericFuncName: (node: SyntaxNode) => string | null; /** AST node types that represent a method definition (for `inferFunctionLabel`). */ export declare const METHOD_LABEL_NODE_TYPES: Set; /** AST node types that represent a constructor definition (for `inferFunctionLabel`). */ export declare const CONSTRUCTOR_LABEL_NODE_TYPES: Set; /** Infer node label from AST node type for function-like nodes without a provider hook. */ export declare const inferFunctionLabel: (nodeType: string) => NodeLabel; /** Argument list node types shared between countCallArguments and call-resolution helpers. */ export declare const CALL_ARGUMENT_LIST_TYPES: Set; /** * Function/method parameter-list node types across grammars. Used to tell a * PARAMETER-property (a constructor parameter that is also a class field, e.g. * TypeScript `constructor(public name: string)`) apart from a function-BODY * local: a property reached through one of these — rather than through the * function's executable body — is a genuine class member, so the * function-local-property guard must NOT strip its owner edge. */ export declare const PARAMETER_LIST_NODE_TYPES: Set; /** * Executable local-scope boundaries for the property-ownership guard * (`isFunctionLocalProperty` in parse-worker.ts). A `Property` capture whose * nearest enclosing scope — walking up before any class container — is one of * these executable bodies is a function-local binding, NOT a class member, so it * must not receive a class `HAS_PROPERTY` owner edge. * * Derived from FUNCTION_NODE_TYPES, with two deliberate adjustments found by the * #1919 review of the original guard: * - EXCLUDES Dart's bare signature wrappers (`function_signature` / * `method_signature`). A Dart getter/setter NAME lives under `method_signature`, * yet it is a class-member declaration, not a local inside an executable body; * treating the signature as a scope boundary OVER-stripped every Dart class * accessor's owner edge. (Signatures are Dart-only; no language emits a * legitimately-function-local Property under one.) * - INCLUDES accessor + initializer bodies (Kotlin `anonymous_initializer` / * `getter` / `setter`, Swift `computed_property` / `computed_getter` / * `computed_setter` / `computed_modify`). Destructuring/locals inside these ARE * function-local, yet they are absent from FUNCTION_NODE_TYPES; omitting them * UNDER-stripped and emitted spurious class `HAS_PROPERTY` edges for * `init {}` / accessor-body destructuring bindings. * * Kept separate from FUNCTION_NODE_TYPES because that set has many other consumers * (e.g. enclosing-callable resolution) where signatures must remain function nodes * and accessor bodies must not. */ export declare const LOCAL_SCOPE_BODY_NODE_TYPES: ReadonlySet; /** Walk an AST node depth-first, returning the first descendant with the given type. */ export declare function findDescendant(root: SyntaxNode, type: string): SyntaxNode | null; /** Extract the text content from a string or encapsed_string AST node. */ export declare function extractStringContent(node: SyntaxNode | null | undefined): string | null; /** Find the first direct named child of a tree-sitter node matching the given type. */ export declare function findChild(node: SyntaxNode, type: string): SyntaxNode | null; /** Convert a tree-sitter node to a `Capture` with 1-based line numbers * (matching RFC §2.1). The tag includes the leading `@`. */ export declare function nodeToCapture(name: string, node: SyntaxNode): Capture; /** Build a `Capture` whose range mirrors `atNode` but whose `text` is * caller-supplied. Used to synthesize markers that don't have a * corresponding source token. */ export declare function syntheticCapture(name: string, atNode: SyntaxNode, text: string): Capture; /** Walk a subtree to find a node whose range exactly matches AND whose * type matches `expectedType` (when given). When multiple nodes share * the range — e.g., `function_definition` and its inner `block` body * for a one-liner — the type filter disambiguates. * * Iterative depth-first-left-to-right via an explicit stack. Children * are pushed in reverse index order so LIFO pop visits them in source * order. Prunes branches that can't contain the target range by * row bounds — same optimization the prior recursive form used, minus * the early-break since stack-push is cheap. */ export declare function findNodeAtRange(root: SyntaxNode, range: Range, expectedType?: string): SyntaxNode | null; /** * Return the captured node if its type is one of `types`, else null. * * The threaded-node equivalent of `findNodeAtRange(root, capture.range, type)` * for the common case where a tree-sitter query already hands you the matched * node (`c.node`): the captured node IS the node at that range, so a type check * is exact and there is no need to re-walk from the tree root (the * O(matches × rootChildren) hot path #1848 hit). Unlike `findNodeAtRange`, this * does NOT traverse — the caller must already hold the node; for a multi-type * call the node must literally be one of `types` (no fallback search). * * Used by every language's scope-capture path (go/python/ruby/php/rust/csharp). */ export declare function nodeIfType(node: T | undefined, ...types: readonly string[]): T | null; export {};