1
0
Эх сурвалжийг харах

fix(cli): `node <symbol> -f <file>` includes the source body (#1314)

The CLI's bare-symbol branch passes includeCode=true to the
codegraph_node handler, but the symbol-pinned-to-file branch didn't —
so exactly when a user disambiguated an overloaded name to one file
(the point of -f), they got Location + trail with no code (#1284).

Fixes #1284

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Colby Mchenry 1 сар өмнө
parent
commit
ce983a08fe

+ 1 - 0
CHANGELOG.md

@@ -18,6 +18,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 ### Fixes
 
+- `codegraph node <symbol> -f <file>` now prints the symbol's source body. Pinning an ambiguous name to a specific file (the whole point of `-f` when many files define the same function) returned only the location and caller trail with no code. (#1284)
 - Deleting a whole directory is now picked up by watch mode: the files inside it are removed from the index on the next auto-sync instead of lingering as stale records until an unrelated edit happened to trigger one. Operating systems often report a directory deletion as a single event on the directory itself (with no per-file events for its contents), which the watcher previously discarded. (#1285)
 - `codegraph sync` now gets the same slow-disk fix that made full indexing fast in 1.4.0: database checkpointing is deferred for the whole incremental run instead of firing every few megabytes of writes. On mechanical drives and other high-latency storage, a small sync on a large index no longer stalls for minutes at near-zero CPU — the cost of a sync scales with what changed, not with the size of the existing index. The same `CODEGRAPH_NO_WAL_DEFER=1` switch turns it off. (#1248)
 - C functions declared with a project-specific attribute macro in front of a typedef'd return type (`SEC_ATTR UINT32 MyFunc(VOID)` — common in embedded and kernel code) are now indexed under their real names. Previously the parser tripped over the unknown macro and stored the parameter list as the function name, leaving entries like `"(VOID)"` in the graph and making the real function unfindable. (#1211)

+ 39 - 0
__tests__/cli-node-command.test.ts

@@ -78,3 +78,42 @@ describe('codegraph node — argument handling (#1044)', () => {
     expect(stderr).not.toMatch(/missing required argument/);
   });
 });
+
+describe('codegraph node — symbol pinned to a file includes the body (#1284)', () => {
+  let tempDir: string;
+
+  beforeEach(async () => {
+    tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'codegraph-node-pin-'));
+    fs.mkdirSync(path.join(tempDir, 'a'));
+    fs.mkdirSync(path.join(tempDir, 'b'));
+    // Two same-named definitions, so `-f` is genuinely disambiguating.
+    fs.writeFileSync(
+      path.join(tempDir, 'a', 'state.ts'),
+      'export function setState(x: number): void {\n  console.log("A", x);\n}\n'
+    );
+    fs.writeFileSync(
+      path.join(tempDir, 'b', 'state.ts'),
+      'export function setState(y: string): void {\n  console.log("B", y);\n}\n'
+    );
+    const cg = CodeGraph.initSync(tempDir);
+    await cg.indexAll();
+    cg.close();
+  });
+
+  afterEach(() => {
+    fs.rmSync(tempDir, { recursive: true, force: true });
+  });
+
+  it('`node <symbol> -f <file>` prints the pinned definition WITH its source body', () => {
+    // The exact #1284 shape: `-f` narrowed the overload correctly but printed
+    // only Location + trail — no code fence — so the user had nothing to read.
+    const { stdout, code } = runNode(tempDir, ['setState', '-f', 'a/state.ts']);
+    expect(code).toBe(0);
+    expect(stdout).toContain('a/state.ts');
+    // The body is present (line-numbered fence), and it's the pinned overload.
+    expect(stdout).toMatch(/1\s+export function setState\(x: number\)/);
+    expect(stdout).toContain('console.log("A", x)');
+    // The other file's overload is not what was pinned.
+    expect(stdout).not.toContain('console.log("B", y)');
+  });
+});

+ 8 - 1
src/bin/codegraph.ts

@@ -1414,7 +1414,14 @@ program
       const args: Record<string, unknown> = {};
       if (options.file) {
         args.file = options.file;
-        if (name && name !== options.file) args.symbol = name;
+        if (name && name !== options.file) {
+          args.symbol = name;
+          // Symbol mode pinned to a file is still symbol mode — the CLI
+          // always wants the body, exactly like the bare-symbol branch
+          // below. Omitting this printed location + trail with no source
+          // (#1284).
+          args.includeCode = true;
+        }
       } else if (name && (name.includes('/') || name.includes('\\'))) {
         args.file = name.replace(/\\/g, '/');
       } else if (name) {