mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-25 20:12:11 +08:00
fix(js,ts): a callee that names nothing records no reference, and a wrapped callee is the plain call (#2742)
A TS/JS call whose callee was no name and no member access (an IIFE, a curried `connect(mapState)(View)`, `handlers[type]()`, `(0, fn)()`, a tagged template on a call) stored the callee's whole source text as the reference's name. Nothing can answer such a name, so each one parked as a failed reference, an IIFE's entire body among them. extractCall now reads the callee past the wrappers that keep it the same callee (parentheses, `!`, `as` / `satisfies`, `await`, type arguments) and records nothing when that is not a name or a dotted chain; the calls inside are visited on their own. Mirrored in the kernel (tsjs/extractors.rs callee_name_of). The reference of a wrapped callee sits at its name, where a plain call's does, and the resolver's bare-call check reads `fn!(`, `(fn)(`, `(fn as F)(` and `(fn satisfies F)(` as it reads `fn(`: SigNoz's `(callback as FrameRequestCallback)(0)` and `(callback)(0)` name the arrow's own parameter, and from the `(` they bound a generated interface's `callback` property. tree-sitter-typescript parses a prefix operator over a generic call as it parses `await f<T>()` (#2586): `!settings.get<boolean>('X')` and `void apiRequest<T>()` are calls whose callee is `!settings.get` / `void apiRequest`. The callee peel that handled `await` now peels a prefix operator too (peelTsPrefixedCallee; the kernel's peel_await_callee), so the call is to `settings.get`, and `void apiRequest<T>().then()` encodes as `apiRequest().then`, not `voidapiRequest().then`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
aa01692620
commit
ae0fc631e0
@@ -3628,10 +3628,12 @@ function isReceiverLessCall(ref: UnresolvedRef, context: ResolutionContext): boo
|
||||
const line = context.getFileLines?.(ref.filePath)?.[ref.line - 1]
|
||||
?? context.readFile(ref.filePath)?.split('\n')[ref.line - 1];
|
||||
if (line === undefined) return false;
|
||||
// `^<name>\s*[(<]` at the call's column, without compiling a pattern per call.
|
||||
// `^<name>\s*[(<]` at the call's column (or a JS/TS wrapper's tail after the
|
||||
// name), without compiling a pattern per call.
|
||||
if (!line.startsWith(ref.referenceName, ref.column)) return false;
|
||||
CALL_OPENER.lastIndex = ref.column + ref.referenceName.length;
|
||||
if (!CALL_OPENER.test(line)) return false;
|
||||
JS_PEELED_CALLEE_TAIL.lastIndex = CALL_OPENER.lastIndex;
|
||||
if (!CALL_OPENER.test(line) && !(JS_FAMILY.has(ref.language) && JS_PEELED_CALLEE_TAIL.test(line))) return false;
|
||||
// Nothing but whitespace, an operator or an opener may precede a bare call:
|
||||
// read the text before the column backwards, past trailing whitespace,
|
||||
// instead of end-anchoring a pattern that scans the prefix from its start.
|
||||
@@ -3649,6 +3651,12 @@ function isReceiverLessCall(ref: UnresolvedRef, context: ResolutionContext): boo
|
||||
|
||||
/** `\s*[(<]` from a given index (sticky) — an optional call's `?.(` too. */
|
||||
const CALL_OPENER = /\s*(?:\?\.\s*)?[(<]/y;
|
||||
/**
|
||||
* What follows a JS/TS callee's name inside a wrapper the extractor sees
|
||||
* through — `fn!()`, `(fn)()`, `(fn as F)()`, `(fn satisfies F)()` — whose
|
||||
* reference sits at the name, as a plain call's does (sticky).
|
||||
*/
|
||||
const JS_PEELED_CALLEE_TAIL = /\s*[!)]|\s+(?:as|satisfies)(?![\w$])/y;
|
||||
const WHITESPACE = /\s/;
|
||||
const WORD_CHAR = /\w/;
|
||||
/** A character that ends a receiver: `.`, a word character, `$`, `]` or `)`. */
|
||||
|
||||
Reference in New Issue
Block a user