You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Vue/TS: no call edge for calls in template expressions or in top-level destructuring declarations #2340
codegraph 1.6.2, Linux arm64, Nuxt 4 project (Vue SFCs with <script setup lang="ts">, auto-imported composables). codegraph callers <composable> misses most real callers. It reduces to two extraction gaps; auto-import itself is not the cause (an auto-imported call in a plain const x = useFoo() is found).
Repro (any Vue project, codegraph sync after adding the files)
// G.ts: missed (module scope)const{ a }=useFoo(1)exportconstg=a// D.ts: found (inside a function)exportfunctionprobe(){const{ a }=useFoo(1);returna}
Expected
A calls edge from the component (or file) to the callee for top-level destructuring declarations, and for call expressions inside template interpolations and bound attributes (:to="useBar(link.location)").
Actual
No edge and no unresolved_refs row. On a real production Nuxt project, callers for a layout composable returned 0 of 22 calling components, and for a URL helper 1 of 7 calling files — so impact/callers answers for composables are mostly empty in Nuxt codebases.
No config option seems to cover it (README lists exclude, include, includeIgnored, deprioritize).
Top-level destructuring. A declaration like const { a } = useFoo(1) or const [b] = useFoo(1) creates no symbol of its own, and the extractor skipped it before reading the right-hand side. So at the top of a .ts/.js file or a <script setup> block, the call was never recorded. The initializer, and any default value in the pattern, is now read the way a function body reads it. The call belongs to the component in <script setup>, or to the file at module level. Released builds parse TypeScript and JavaScript in the native parser, which has the same fix.
Template calls. Calls in {{ }} interpolations and in directive values (:to="useBar(link.location)", v-if, v-show, v-model, @click="save(item)", custom v-*) are now recorded as calls from the component, on their real line. Names the template binds itself are never taken for project functions: v-for items, slot props, and arrow parameters. Neither are $t/$emit-style helpers or the globals Vue allows.
On your repro, callers useFoo now lists A.vue, B.vue, F.vue, G.ts and D.ts, and callers useBar lists H.vue and I.vue. Before, they found 2 callers and 0. On elk, a Nuxt app, const { t } = useI18n() went from no callers to 71.
Validating on elk turned up two related fixes, included in the same change. A handler like @click="open = false" or @click="emit('close')" no longer links to an unrelated function of the same name. And a component's own function named like a Nuxt helper, such as clearError, is now the one its calls reach.
This ships in the next release. Re-index after upgrading (codegraph index) to pick it up. Thanks also to @drakeo338 (#2341) and @L0garithmic (#2073), whose work this builds on. Both are credited in the changelog.
Activity
Phase 4: resolution and extraction accuracy
fix(vue,ts): link calls in Vue templates and in top-level destructuri…
colbymchenry commentedon Oct 5, 2026
Thanks @deniskern for narrowing this down to two gaps. That made both easy to find.
Both are fixed on
mainin #2357:const { a } = useFoo(1)orconst [b] = useFoo(1)creates no symbol of its own, and the extractor skipped it before reading the right-hand side. So at the top of a.ts/.jsfile or a<script setup>block, the call was never recorded. The initializer, and any default value in the pattern, is now read the way a function body reads it. The call belongs to the component in<script setup>, or to the file at module level. Released builds parse TypeScript and JavaScript in the native parser, which has the same fix.{{ }}interpolations and in directive values (:to="useBar(link.location)",v-if,v-show,v-model,@click="save(item)", customv-*) are now recorded as calls from the component, on their real line. Names the template binds itself are never taken for project functions:v-foritems, slot props, and arrow parameters. Neither are$t/$emit-style helpers or the globals Vue allows.On your repro,
callers useFoonow lists A.vue, B.vue, F.vue, G.ts and D.ts, andcallers useBarlists H.vue and I.vue. Before, they found 2 callers and 0. On elk, a Nuxt app,const { t } = useI18n()went from no callers to 71.Validating on elk turned up two related fixes, included in the same change. A handler like
@click="open = false"or@click="emit('close')"no longer links to an unrelated function of the same name. And a component's own function named like a Nuxt helper, such asclearError, is now the one its calls reach.This ships in the next release. Re-index after upgrading (
codegraph index) to pick it up. Thanks also to @drakeo338 (#2341) and @L0garithmic (#2073), whose work this builds on. Both are credited in the changelog.