/** * identifierSlots — the single source of truth for "which positions of a * node hold an identifier REFERENCE, and where in the user's file that * identifier sits". The third member of the slot-table family, after * `bodySlots` (statement bodies) and `expressionSlots` (expression * positions). * * Why it exists: the same reason as its two siblings. `expressionSlots` * records that hand-written expression-position lists drifted and three * holes appeared in one week; `bodySlots` records the identical history * for statement bodies. Semantic-token highlighting asks the same * question one level over — "where are the names?" — and a per-node-kind * switch buried in the LSP handler would drift the same way, except the * symptom is a missing color, which nobody files a bug about. * * Consumers: * - `getSemanticTokens` (lib/lsp/semanticTokens.ts) * * This table answers WHERE a name is, never WHAT it means. Resolving a * name to a symbol needs scopes and belongs to the consumer. * * Two rules the whole table obeys, so no consumer can get them wrong: * * 1. Positions come from `loc.line` / `loc.col`, which are 0-indexed in * the USER'S file whichever parse mode ran. `loc.start` / `loc.end` * are offsets into whatever the parser actually saw, which differs * between the two modes. See `docs/dev/locations.md` — and note it * says the LSP's choice of mode is historical and could change, which * is exactly why nothing here may depend on it. `scopeOffset` is safe * because it is only ever compared with offsets from the same parse. * 2. A slot's length is the identifier's own length, taken by the * consumer from `name`. A node's `loc` spans the WHOLE node — a * functionCall's loc covers `helper(y)`, not `helper` — so * `end - start` would paint the arguments. * * Completeness is enforced by the compiler, not by review: the registry * below is a `Record`, so adding a node kind to * the language fails to compile until it is registered here. That is * strictly stronger than the runtime lists `expressionSlots` uses, and * it fails by name in the same way. */ import type { AgencyNode } from "../types.js"; export type IdentifierSlot = { /** The identifier text as written. Also the token's length. */ name: string; /** 0-based line in the user's file. */ line: number; /** 0-based column of the identifier's first character. */ col: number; /** Offset for `findContainingScope`. Only comparable against other * offsets from the SAME parse — see `docs/dev/locations.md`. */ scopeOffset: number; /** True when the source wrote this as a call, `name(...)`. Lets a * consumer distinguish a call site from a bare reference without * re-inspecting the AST. */ isCall: boolean; }; /** The identifier references this node contributes itself. */ export declare function identifierSlots(node: AgencyNode): IdentifierSlot[]; /** * The kinds that actually yield identifier references. Exported so the * test can assert each one still produces a slot — a registry entry * flipped to `none` compiles fine and would silently stop coloring. * * A new node kind is NOT added here by default, which is the limit of * what this can enforce: the registry forces an author to make a choice, * and the corpus test in identifierSlots.test.ts catches a wrong choice * for the two shapes we know about. Neither can know that some future * node kind carries a name. */ export declare const IDENTIFIER_BEARING_KINDS: readonly ["variableName", "functionCall"];