Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

TypeScript call resolution: ~3,000 lines of fixes ready (0 invented CALLS edges, full recall on a NestJS backend) — how would you like them split?

未关闭
#2,789 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 2 天内回复

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
35/100
Issue 类型
功能
描述清晰度
基本清楚
活跃度
活跃
技术栈
c, typescript
领域
backend, devtools

调研方向

Start by reviewing the proposed PR dependency table and the existing related issues, especially #2718, #2293, and #2126; the author says the changes have not yet been built and tested as separate PRs. The work spans internal/cbm/lsp/ts_lsp.c, internal/cbm/helpers.c, extraction and pipeline passes, and tests including tests/test_lsp_resolution_probe.c. Done means maintainers agree on the split and representation, then each proposed change is validated independently against its probes and the TypeScript compiler oracle.

由索引模型根据 Issue 内容生成。

描述

bug editor/integration parsing/quality stability/performance windows
Version

main @ 10ab613d (v0.12.1 + 281 commits), plus the changes described below

Platform

Windows (x64)

Install channel

GitHub release archive / install.sh / install.ps1

Binary variant

standard

What happened, and what did you expect?

This is actually my first attempt at contributing to an open source project ever! I'm very excited. I built this 100% using claude code and I had it prep a post here cause it's a huge chunk and I feel like we need to be strategic on how I partition up so many lines of code.

The background for this update is that I use Nest.JS and it uses dependency injection and the default codebase memory mcp project seemed to have not found all the nodes/edges and it was inventing nodes/edges. When I started about a month ago, codebase only found about 15% of the nodes/edges. Personally I'm not an expert at static analysis but I had claude doing a lot of checking and it seems extremely good with 100% found (with my particular code base) and 0 invented. There's probably still edge cases that my updates do not handle. Anyway, here's claude's post and I'm ok in doing whatever it takes to get this into the mix, but I want to avoid a ton of complicated stacked PRs.

What problem does this solve?

On TypeScript, and NestJS in particular, the graph both misses real calls and invents calls that
don't exist. "Who calls this?" questions come back incomplete in ways that look complete. For example, a
query for dead code would list live code that is only reached through dependency injection.

We measured against ground truth from the TypeScript compiler's own checker (ts.createProgram +
getSymbolAtLocation) on a production NestJS backend: 641 .ts files, one fixed commit, same scorer
for every build:

v0.12.1 release main @ 10ab613d our branch
production calls found (recall) 4,052 / 4,136 4,031 / 4,136 4,136 / 4,136
production edges invented 633 70 0 (of 3,627)
test-file edges invented 211 189 0 (of 934)
calls made by functions held in object/array literals in tests 0 / 1,585 3 / 1,585 1,585 / 1,585

On the same 641-file repo, our Windows build (MSYS2 clang, 4 workers) produces a CALLS edge set
identical to a Linux build of the same commit: 4,768 edges, 0 differences either way.

Proposed solution

The branch is 34 commits on main @ 10ab613d, across 23 files:

  • +3,080 / −83 lines of source. Mostly internal/cbm/lsp/ts_lsp.c (+1,404) and internal/cbm/helpers.c
    (+628), plus the extract and pipeline passes.
  • +3,854 lines of tests. Mostly new probes in tests/test_lsp_resolution_probe.c, plus
    test_pipeline.c, test_registry.c and test_ts_lsp.c.

Each fix has a probe that fails without it. The key ones were mutation-checked: the fix was reverted, the
probe went red for the stated reason, and the fix was restored.

It is too big for one PR under your 500-line guideline, and I don't want to dump 15 PRs on you
unannounced. So here is the shape. I'm asking how you'd like to receive it.

The PRs are not all dependent. I mapped the commits by which earlier commits' lines each one edits,
and which earlier commits' new functions it calls. That gives a dependency graph six levels deep, not a
chain of 15:

PR What it fixes src / test lines Needs
A Receiver types imported through a barrel re-export 94 / 66 —
B Generic calls misparsed under a prefix operator (!foo<T>(), await, …) 213 / 238 —
C Calls in module-level code and top-level arrow functions 78 / 197 —
D Calls in a class's helpers and fields credited to the right owner (incl. namespaces) 98 / 171 —
E Calls through functions held in a class field's object 297 / 341 —
F Stop name-only guesses and builtin calls binding to project symbols 186 / 439 B
G Type services a test gets from a factory or DI container 81 / 141 B
H1 Calls through typed object literals and their interfaces 405 / 249 B
H2 Namespace import vs declared type; implementation dispatch on incremental runs; intersection aliases 238 / 328 H1
I Return type of helpers declared inside a test block 163 / 219 B, G
J Remaining invented edges, stopped at their cause 275 / 300 B, C, F, G
K Name a typed literal's functions after the variable that holds them 399 / 209 E, F, H2, J
L1 Name each typed list entry apart, credit its calls to it (+ index version bump) 689 / 551 C, E, H1, J, K
L2 Same for untyped file-level literals; tightening 386 / 574 E, I, K, L1
M A workspace sibling package's import stays a project binding 38 / 49 F, J
  • Wave 1 (A–E): five independent PRs, each off main. They can all be open and reviewed at once.
  • Then: F, G, H1 → H2, I, J → K, M → L1 → L2.

Why not one linear stack of ~14 PRs: in a strict chain, PR k can't merge until 1…k−1 have. Every
change requested on an early PR forces a rebase of everything above it, which is up to 14 × 13 / 2 = 91
rebases in the worst case. With the graph above, the critical path is 6 merges, and a change to a wave-1
PR only ripples into its own descendants.

Caveats, so you can weigh this:

  • The map is textual plus symbol-level. I have not yet built and tested each PR on its own. I'd do that
    before opening any of them.
  • Most probes live in one file (test_lsp_resolution_probe.c). PRs touching it will conflict on
    append-only hunks: mechanical, but present.
  • K, L1 and L2 change stored qualified names, so they bump CBM_SEMANTIC_INDEX_VERSION. I'd keep one bump
    per PR that needs it rather than carry one early.
  • H1, H2, L1 and L2 are still over 500 lines. They are one rule applied to several syntax shapes.
    I can split further by shape if you prefer.
Alternatives considered
  1. The wave plan above: 15 PRs, 5 open at a time.
  2. Fewer, larger PRs, one per wave (~600–1,800 lines each), if you'd rather review fewer threads.
  3. You take the findings and tests and implement it your way. We'd hand over the probes, the
    compiler-checked oracle and the scoring script. The probes are the part that's most useful on its own.

Which do you prefer? Or is there a shape that fits your review flow better?

Separate, found on the way: MinGW gcc 13.2 build deadlocks at 4 workers

Happy to open this as its own issue if you'd like.

  • What happens. Built with Strawberry Perl's MinGW-w64 gcc 13.2, indexing hangs forever at
    parallel.resolve.start with ~0 CPU when run with 4 workers (3 of 3 runs). 1 and 2 workers finish. The
    MSYS2 clang build of the same tree runs fine at 4 workers.
  • Backtrace (gdb). An exiting worker is stuck in winpthreads TLS cleanup
    (__dyn_tls_pthread → pthread_mutex_lock) while holding the loader lock. A new thread waits on the
    loader lock, and main sits in cbm_thread_join.
  • Likely cause. gcc 13.2 on MinGW compiles _Thread_local (CBM_TLS, src/foundation/compat.h:26) as
    emulated TLS through winpthreads: 166 __emutls symbols in the binary, and this gcc has no
    -fno-emulated-tls. The clang build has none.
  • Not proven: I haven't built plain main with the same gcc. The CI's gcc check cross-compiles from
    Linux and runs --version under Wine, so it can't catch a runtime deadlock.
  • Two smaller build notes. gcc on MinGW checks format(printf) attributes against Microsoft's printf
    regardless of __USE_MINGW_ANSI_STDIO, so 7 %zu / extra-arg sites fail -Werror=format. Also,
    scripts/build.sh sets CFLAGS_EXTRA itself, so a caller's CFLAGS_EXTRA= only takes effect if it
    comes later on the command line.
Reproduction

Measured 2026-10-25: v0.12.1 Linux release binary vs our branch (integration/ts-resolution-v3 @ 26203c64).
Plain main @ 10ab613d was NOT run against this fixture.


Minimal repro

Four files:

src/users/users.repository.ts

export class UsersRepository {
  findById(id: string): string {
    return `user-${id}`;
  }
  get(key: string): string {
    return key;
  }
}

src/users/index.ts

export * from './users.repository';

src/util.ts

export function isPresent<T>(value: T | undefined): value is T {
  return value !== undefined;
}

src/orders/orders.service.ts

import { UsersRepository } from '../users';
import { isPresent } from '../util';

export class OrdersService {
  constructor(private readonly users: UsersRepository) {}

  // 1. Method call on an injected service whose class is imported through a barrel (index.ts)
  ownerOf(orderId: string): string {
    return this.users.findById(orderId);
  }

  // 2. Generic function call under a prefix operator
  requireId(id: string | undefined): string {
    if (!isPresent<string>(id)) throw new Error('missing id');
    return id;
  }
}

(plus a one-line tsconfig.json: { "compilerOptions": { "target": "ES2022", "module": "commonjs", "strict": true } })

Commands
cd /tmp/cbm-example && git init -q && git add -A && git commit -qm fixture
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-example"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-example","query":"MATCH (a)-[r:CALLS]->(b) RETURN a.name, b.qualified_name"}'
Actual (v0.12.1)
rows: 0  (cols: a.name b.qualified_name)
total: 0
Expected (and what our branch returns)
rows: 2  (cols: a.name b.qualified_name)
  ownerOf    tmp-cbm-example.src.users.users.repository.UsersRepository.findById
  requireId  tmp-cbm-example.src.util.isPresent
total: 2
Control: each miss comes from one pattern

Change the import to from '../users/users.repository' (no barrel), and change the guard to
const ok = isPresent<string>(id); if (!ok) ... (no prefix operator). v0.12.1 then returns both edges.
So the first miss comes from the barrel re-export (PR A) and the second from the ! before a generic call
(PR B). These are the two smallest PRs in wave 1.


Duplicate check (2026-10-25): upstream issues and PRs searched, about 30 queries

Nothing duplicates the proposal. Related items to link in the issue:

  • #2718 (open): calls through a barrel re-export. Same root cause as PR A, different shape: they
    re-export a value (an object const and a function) and call it directly. PR A fixes a re-exported
    class used as a type (constructor(private x: Foo)), through both export * and export { Foo } from.
    Measured: our branch does NOT fix #2718's repro (identical output to v0.12.1). Say "related", never "fixes".
  • #2210 (closed, fixed in v0.12.0 by PR #2242): await foo<T>() only. PR B generalises it to the other
    prefix operators. !foo<T>() is still missing on v0.12.1 (the fixture above).
  • #1974 / PR #2407, PR #2523 (merged): inferred receivers and constructor parameter properties. Our branch builds on them.
  • #2293 (open, waiting on a maintainer design decision): calls inside a closure credited to the enclosing
    function. Also #415 / #341: functions inside object literals. PRs K, L1 and L2 make that naming decision
    for TS literals, so ask the maintainer whether that representation is acceptable.
  • #2126, #2121, PR #1128 (open): name-only guesses emitted as CALLS. Related to PR F, which handles the TS side only.
  • #2606 (open): self-built MinGW gcc 15 hangs on main. Probably the same family as our gcc 13.2 deadlock. Link it.
  • Not overlapping: #2297 / PR #2746 (renamed imports, not in our branch); PR #2402 (constructor parameter
    properties, which merged PR #2523 appears to cover already); #2265, #2709 / PR #2721 (showing which calls went unresolved).
Logs

Diagnostics trajectory (memory / performance / leak issues)

Project scale (if relevant)

No response

Confirmations
  • I searched existing issues and this is not a duplicate.
  • My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.
主要语言
C
星标
45.8k
派生
3.8k
平均合并
3 天 4 小时
30 天内合并 PR
208

环境准备

这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

DeusData/codebase-memory-mcp 的其他 Issue

查看 DeusData/codebase-memory-mcp 的全部 Issue

相似的 Issue

更多 C Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。