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
JS/TS: object-literal members get no node unless the container is an export const — plain consts, window.X = {…} and IIFE-scoped objects are invisible #2300
Object-literal members (shorthand methods, key: function () {}, key: () => {}) are extracted as nodes only when the containing object is an export const. The same object without export, an object literal assigned to a member expression (window.api = { … }, ns.mod = { … }), or one declared inside an IIFE produces no member nodes at all.
That makes classic script-tag JavaScript — no modules, namespaces hung off window — almost invisible: the namespace constant is indexed, every method inside it is not. Related but distinct from #1573 / #1932, which are about edges to members that were already extracted.
git init && git add -A && codegraph init -y ., then all non-file nodes:
src/a_export.ts constant objTsExp
src/a_export.ts function tsExpM
src/a_export.ts function tsExpProp
src/b_plain.ts constant objTsPlain
src/c_export.js constant objJsExp
src/c_export.js function jsExpM
src/c_export.js function jsExpProp
src/d_plain.js constant objJsPlain
Container
Members extracted?
export const o = { m() {} } (.ts / .js)
yes
const o = { m() {} } (.ts / .js)
no
window.X = { m() {} }
no (no node for X either)
object literal inside an IIFE
no
A class method in the same file is extracted (class Svc { classMethod() {} } → method classMethod), so it is specific to object-literal containers.
Knock-on effects
Calls made inside an unextracted member are attributed to the enclosing constant: codegraph callers helper lists constant store instead of store.shorthand.
For window.api = { load() { return store.shorthand(); } } the call is lost entirely — there is no node to hang the edge on.
codegraph_explore for such a method name does not say "not found"; it returns ~26 KB of unrelated, loosely matching source, which costs more tokens than a grep would.
Real-world scale
A vanilla-JS browser app (script tags, no bundler, namespaces on window): 200 files under public/js, 670 method-shorthand definitions inside object literals, 0 present in the graph. The single largest module has 251 such methods; the shared auth / API-client modules are written the same way. Plain function declarations and nested arrows in the same files are indexed fine (~13k function nodes).
Expected
Object-literal members get nodes (qualified as container.member) regardless of whether the container is exported — including const objects, member-expression assignments (window.X = {…}, a.b = {…}), and objects inside IIFEs — the same way the exported case already works.
Thanks @tkhoaaa for the detailed report and the real-world numbers. They made the scale of this clear.
Fixed on main in #2363, building on #2310 by @danusha2345. Object-literal members used to become symbols only when the object was an export const. Any other literal was walked as one initializer, so calls made inside its members were credited to the constant or lost. Now every named object literal's functions are symbols of their own: shorthand methods, key: function () {} and key: () => {}. That covers:
a plain const api = { load() {…} }, exported or not
an object declared inside an IIFE or a function
a namespace hung on the page or on another object: window.App = { init() {…} }, App.utils = {…}, dw_page = {…}
Each member's qualified name carries its object (api::load, window.App::init), and the calls made inside a member belong to that member. Calls reach them through their object: api.load(), window.App.init(), App.init() from another script on the page, App.utils.pad(), and a sibling's this.render(). A bare init() is not taken for App.init.
On your repro, every member in b_plain.ts, d_plain.js and e_iife.js is now a symbol, including window.WS::wsM and objIife::iifeM. wsM's call to objIife.iifeM() is linked, and so is a WS.wsM() call from another file. On real projects, DokuWiki gained 85 member symbols and about 100 call links, and TodoMVC's script-tag examples gained over 400 symbols, with no measurable change in index time. Released builds parse JavaScript and TypeScript in the native parser, which has the same change.
Not covered yet: object literals passed as arguments ($.extend({…}), enyo.kind({…})), prototype objects, module.exports = {…}, and revealing-module return {…} objects.
This ships in the next release. Re-index after upgrading (codegraph index) to pick it up. You and @danusha2345 are credited in the changelog.
Activity
fix(tsjs): extract named object literal members with scoped callers
Phase 4: resolution and extraction accuracy
fix(js,ts): index the functions in every named object literal, not on…
colbymchenry commentedon Oct 5, 2026
Thanks @tkhoaaa for the detailed report and the real-world numbers. They made the scale of this clear.
Fixed on
mainin #2363, building on #2310 by @danusha2345. Object-literal members used to become symbols only when the object was anexport const. Any other literal was walked as one initializer, so calls made inside its members were credited to the constant or lost. Now every named object literal's functions are symbols of their own: shorthand methods,key: function () {}andkey: () => {}. That covers:const api = { load() {…} }, exported or notwindow.App = { init() {…} },App.utils = {…},dw_page = {…}Each member's qualified name carries its object (
api::load,window.App::init), and the calls made inside a member belong to that member. Calls reach them through their object:api.load(),window.App.init(),App.init()from another script on the page,App.utils.pad(), and a sibling'sthis.render(). A bareinit()is not taken forApp.init.On your repro, every member in
b_plain.ts,d_plain.jsande_iife.jsis now a symbol, includingwindow.WS::wsMandobjIife::iifeM.wsM's call toobjIife.iifeM()is linked, and so is aWS.wsM()call from another file. On real projects, DokuWiki gained 85 member symbols and about 100 call links, and TodoMVC's script-tag examples gained over 400 symbols, with no measurable change in index time. Released builds parse JavaScript and TypeScript in the native parser, which has the same change.Not covered yet: object literals passed as arguments (
$.extend({…}),enyo.kind({…})), prototype objects,module.exports = {…}, and revealing-modulereturn {…}objects.This ships in the next release. Re-index after upgrading (
codegraph index) to pick it up. You and @danusha2345 are credited in the changelog.