* Check if a node matches a symbol query. * * Accepts simple names (`run`) and three flavors of qualifier: * - dotted `Session.request` (TS/JS/Python) * - colon-pair `stage_apply::run` (Rust, C++, Ruby) * - slash `configurator/stage_apply` (path-ish) *
(node: Node, symbol: string)
| 4400 | * Python — `stage_apply::run` matches a `run` in `stage_apply.rs`) |
| 4401 | */ |
| 4402 | private matchesSymbol(node: Node, symbol: string): boolean { |
| 4403 | // Simple name match |
| 4404 | if (node.name === symbol) return true; |
| 4405 | // File basename match (e.g., "product-card" matches "product-card.liquid") |
| 4406 | if (node.kind === 'file' && node.name.replace(/\.[^.]+$/, '') === symbol) return true; |
| 4407 | |
| 4408 | // Qualified-name lookups: split on any supported separator. `\w` keeps |
| 4409 | // identifier chars (incl. `_`) intact; everything else is treated as |
| 4410 | // a separator we tolerate. |
| 4411 | if (!/[.\/]|::/.test(symbol)) return false; |
| 4412 | const parts = symbol.split(/::|[./]/).filter((p) => p.length > 0); |
| 4413 | if (parts.length < 2) return false; |
| 4414 | |
| 4415 | const lastPart = parts[parts.length - 1]!; |
| 4416 | if (node.name !== lastPart) return false; |
| 4417 | |
| 4418 | // Stage 1: qualified-name suffix match. The extractor joins the |
| 4419 | // semantic hierarchy with `::`, so `Session.request` and |
| 4420 | // `Session::request` both become `Session::request` here. |
| 4421 | const colonSuffix = parts.join('::'); |
| 4422 | if (node.qualifiedName.includes(colonSuffix)) return true; |
| 4423 | |
| 4424 | // Stage 2: file-path containment. Rust modules and Python packages |
| 4425 | // are not in `qualifiedName` — they're encoded in the file path. So |
| 4426 | // `stage_apply::run` matches a `run` in any file whose path |
| 4427 | // contains a `stage_apply` segment (with or without an extension). |
| 4428 | // |
| 4429 | // Filter out Rust path prefixes that have no file-system equivalent. |
| 4430 | const containerHints = parts.slice(0, -1).filter((p) => !RUST_PATH_PREFIXES.has(p)); |
| 4431 | if (containerHints.length === 0) return false; |
| 4432 | |
| 4433 | const segments = node.filePath.split('/').filter((s) => s.length > 0); |
| 4434 | return containerHints.every((hint) => |
| 4435 | segments.some((seg) => seg === hint || seg.replace(/\.[^.]+$/, '') === hint) |
| 4436 | ); |
| 4437 | } |
| 4438 | |
| 4439 | /** |
| 4440 | * Find ALL definitions matching a name, ranked, so codegraph_node can return |
no test coverage detected