Skip to content

TypeScript: a method call on an object imported through a re-export barrel produces no CALLS edge #2718

Open

Description

@dazaiio

v0.12.1, macOS arm64, index_repository --mode full. Follow-up to #1974, which v0.12.0 fixed for us — thank you!

Repro

Seven files, a Bun/npm workspace with one library package that re-exports from src/index.ts.

package.json

{ "name": "barrel-repro", "private": true, "workspaces": ["apps/*", "packages/*"] }

packages/lib/package.json

{ "name": "@x/lib", "type": "module", "module": "src/index.ts" }

packages/lib/src/repo.ts

export const fooRepo = { async findOne(id: string) { return id } }
export function plainFn(id: string) { return id }

packages/lib/src/index.ts

export { fooRepo, plainFn } from './repo'

packages/lib/src/internal.ts — same package, through its own barrel

import { fooRepo, plainFn } from './index'
export async function viaOwnBarrel() { await fooRepo.findOne('c'); plainFn('c') }

apps/app/package.json

{ "name": "@x/app", "type": "module", "dependencies": { "@x/lib": "workspace:*" } }

apps/app/src/job.ts — through the package name

import { fooRepo, plainFn } from '@x/lib'
export async function viaPackage() { await fooRepo.findOne('a'); plainFn('a') }

apps/app/src/direct.ts — control: straight from the defining file

import { fooRepo, plainFn } from '../../../packages/lib/src/repo'
export async function viaDirect() { await fooRepo.findOne('b'); plainFn('b') }

Observed

IMPORTS edges are all there: job.ts → lib/src/index.ts, internal.ts → lib/src/index.ts, lib/src/index.ts → lib/src/repo.ts, direct.ts → lib/src/repo.ts.

CALLS edges:

caller → findOne → plainFn
viaDirect ✅ lsp_ts_namespace ✅ lsp_ts_import
viaPackage ❌ none (only USAGE → fooRepo) ⚠️ unique_name
viaOwnBarrel ❌ none (only USAGE → fooRepo) ⚠️ unique_name

So the package specifier is not the problem — the same loss happens with a relative ./index barrel. The chain is lost at the export { … } from './repo' hop: the method on the re-exported object gets no edge at all, and the plain function lands only via the name heuristic rather than the import (with a non-unique name that path is not guaranteed). Same result with "main" or "exports": { ".": "./src/index.ts" } instead of "module".

Expected

A named re-export is followed to the defining module the way a direct import is, so viaPackage → findOne and viaOwnBarrel → findOne resolve like viaDirect → findOne, and plainFn resolves via the import.

Impact

Our Bun monorepo has one library package that re-exports its repositories (object literals) from src/index.ts; the other apps import them by package name. After v0.12.1 intra-package calls resolve, but every cross-app call to those repositories still shows zero callers — e.g. expireLapsedSubscriptions, needsRun, takeDirty, insertIncoming, bumpInbound, each with 1–2 real call sites. As in #1974, this is indistinguishable from a true negative.

Related but different: #1557 §3 (aliased re-exports produce no node), #2297 (renamed named import).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    parsing/qualityGraph extraction bugs, false positives, missing edges

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions