Просмотр исходного кода

fix(resolution): resolve ES imports targeting .xsjs/.xsjslib files (#556) (#594)

The extraction half of #556 — indexing `.xsjs` / `.xsjslib` as JavaScript — already
landed on main via #654. This PR is now scoped to the remaining resolution gap:
the JS import-resolution list did not include the SAP HANA extensions, so an
extensionless `import { x } from './helpers'` in a `.xsjs` file resolved to
nothing and the cross-file call edge was dropped.

Add `.xsjs` / `.xsjslib` to the `javascript` entry in EXTENSION_RESOLUTION so
those imports resolve to their target file and `codegraph_callers` /
`codegraph_impact` see the edge. One resolution test covers the .xsjs -> .xsjslib
import; the now-redundant extraction/detection tests were dropped (covered by #654).
Max Hsu 2 недель назад
Родитель
Сommit
a74029105a
3 измененных файлов с 50 добавлено и 1 удалено
  1. 1 0
      CHANGELOG.md
  2. 48 0
      __tests__/extraction.test.ts
  3. 1 1
      src/resolution/import-resolver.ts

+ 1 - 0
CHANGELOG.md

@@ -409,6 +409,7 @@ Full details in the entries below.
 - The `codegraph_search` tool's `kind: "type"` filter — a value its own schema advertises — silently matched nothing; it now correctly finds type aliases. The `codegraph_explore` tool's parameter guidance also no longer suggests running `codegraph_search` first, which contradicted explore's call-it-first design and cost agents an extra round-trip.
 - Symbols defined in Svelte and Vue `<script>` blocks were reported one line below where they actually are — a function on line 3 was reported at line 4 — which offset every script-block symbol's location in search, `codegraph_node`, and explore output. Line numbers now match the file exactly. Re-index a project to benefit. (Svelte, Vue)
 - Doc comments are now captured for exported, `const`-assigned, and decorated declarations, and the documentation a symbol carries is now clean across every supported language. Previously a comment above `export class X`, `export const fn = () => …`, a plain `const fn = () => …`, or a decorated Python `def`/`class` (`@app.route(...)`, `@dataclass`) was dropped entirely — only comments directly above a plain declaration were kept. CodeGraph now finds the comment through the `export` / `const` / decorator wrapper. Comment-marker cleanup was also rounded out for every language CodeGraph supports: Rust/Swift/Kotlin doc lines (`///`, `//!`), Python/Ruby/shell `#`, Lua/Luau (`--` and `--[[ ]]`), and Pascal (`{ }` and `(* *)`) no longer leave stray markers in the stored text — validated end-to-end across all 19 code languages plus Svelte/Vue `<script>` blocks. (#780). Thanks @caleb-kaiser.
+- SAP HANA `.xsjs` / `.xsjslib` imports now resolve across files: an extensionless `import { x } from './helpers'` in a `.xsjs` file finds `helpers.xsjslib`, so the cross-file call edge is created and `codegraph_callers` / `codegraph_impact` see it. Previously the import path resolved to nothing and the call fell back to same-name matching, which could bind the edge to an unrelated file that happened to export the same symbol. Complements the `.xsjs` / `.xsjslib` extraction support. (#556)
 - Go method calls made through a chained factory function now resolve to the correct type. A call like `New().Method()` used to drop the receiver, so the chained method attached to a same-named method on an unrelated type — or didn't resolve. CodeGraph now captures Go return types (a pointer `*Foo` resolves to `Foo`, and a multi-return `(*Foo, error)` to its first result), infers the chained receiver's type from what the factory function returns, and resolves the method on it — including methods promoted from an embedded struct — creating the edge only when the type or an embedded type genuinely has the method. Existing Go indexes should be re-indexed (`codegraph index -f`) to benefit. (#750) (Go)
 - Scala method calls made through a companion-object factory, a fluent chain, or a case-class `apply` now resolve to the correct type. A call like `Foo.create().bar()` or `Builder(cfg).bar()` used to drop the receiver, so the chained method silently attached to a same-named method on an unrelated type — most often mis-attributing a standard-library `Option` / `Iterator` `.map` / `.flatMap` / `.foreach` onto your own same-named class. CodeGraph now captures Scala return types (a generic `List[Foo]` resolves to its container `List`, a qualified `pkg.Foo` to `Foo`), infers the chained receiver's type from what the inner call returns or constructs, and resolves the method on it — including methods inherited from a trait the type extends — creating the edge only when that type or one of its traits genuinely has the method (so a wrong inference produces no edge instead of a misleading one). Existing Scala indexes should be re-indexed (`codegraph index -f`) to benefit. (#750) (Scala)
 - Rust method calls made through a chained associated function now resolve to the correct type. A call like `Foo::new().bar()` or `Foo::with(cfg).build()` used to drop the receiver, so the chained method silently attached to a same-named method on an unrelated type — or didn't resolve. CodeGraph now captures Rust return types (`-> Self` resolves to the implementing type), infers the chained receiver's type from what the associated function returns, and resolves the method on it — including methods provided by a trait the type implements (via the new `impl Trait for Type` relationships) — creating the edge only when the type or one of its traits genuinely has the method. Existing Rust indexes should be re-indexed (`codegraph index -f`) to benefit. (#750) (Rust)

+ 48 - 0
__tests__/extraction.test.ts

@@ -6936,6 +6936,54 @@ export function multiply(a: number, b: number): number {
     cg.close();
   });
 
+  it('should resolve an ES import from a .xsjs file to a .xsjslib file (#556)', async () => {
+    // Exercises the JS import-path resolution list: `./helpers` must resolve to
+    // `helpers.xsjslib`. `decoy.js` exports the same symbol name and is never
+    // imported — without .xsjs/.xsjslib in the list the import resolves to
+    // nothing and the call falls back to same-name matching, which binds the
+    // edge to the decoy. The decoy is what makes this test fail on a regression:
+    // with a lone helpers.xsjslib the fallback happens to pick the right file.
+    fs.writeFileSync(
+      path.join(tempDir, 'helpers.xsjslib'),
+      'export function buildQuery(table) {\n  return "SELECT * FROM " + table;\n}\n'
+    );
+    fs.writeFileSync(
+      path.join(tempDir, 'decoy.js'),
+      'export function buildQuery(table) {\n  return "DECOY " + table;\n}\n'
+    );
+    fs.writeFileSync(
+      path.join(tempDir, 'service.xsjs'),
+      'import { buildQuery } from "./helpers";\n\nfunction run() {\n  return buildQuery("users");\n}\n'
+    );
+
+    const cg = CodeGraph.initSync(tempDir);
+    await cg.indexAll();
+
+    const run = cg.getNodesInFile('service.xsjs').find((n) => n.name === 'run');
+    const buildQuery = cg.getNodesInFile('helpers.xsjslib').find((n) => n.name === 'buildQuery');
+    const decoy = cg.getNodesInFile('decoy.js').find((n) => n.name === 'buildQuery');
+    expect(run).toBeDefined();
+    expect(buildQuery).toBeDefined();
+    expect(decoy).toBeDefined();
+
+    expect(
+      cg.getFileDependencies('service.xsjs'),
+      "'./helpers' should resolve to helpers.xsjslib, not the same-named decoy"
+    ).toEqual(['helpers.xsjslib']);
+
+    const outgoing = cg.getOutgoingEdges(run!.id);
+    expect(
+      outgoing.find((e) => e.target === buildQuery!.id),
+      'run() should resolve buildQuery across the .xsjs -> .xsjslib import'
+    ).toBeDefined();
+    expect(
+      outgoing.find((e) => e.target === decoy!.id),
+      'run() must not bind to the unrelated same-named export in decoy.js'
+    ).toBeUndefined();
+
+    cg.close();
+  });
+
   it('should count the full file-level tracked class (yaml/twig/properties) in indexFiles()', async () => {
     fs.writeFileSync(path.join(tempDir, 'app.yaml'), 'name: test\n');
     fs.writeFileSync(path.join(tempDir, 'view.twig'), '{{ title }}\n');

+ 1 - 1
src/resolution/import-resolver.ts

@@ -26,7 +26,7 @@ const EXTENSION_RESOLUTION: Record<string, string[]> = {
   // module-entry convention, hit when a bare workspace import ("data") is
   // rewritten to the member's directory; lowercase variants for safety.
   arkts: ['.ets', '.ts', '.d.ts', '.js', '/Index.ets', '/index.ets', '/index.ts', '/index.js'],
-  javascript: ['.js', '.jsx', '.mjs', '.cjs', '/index.js', '/index.jsx'],
+  javascript: ['.js', '.jsx', '.mjs', '.cjs', '.xsjs', '.xsjslib', '/index.js', '/index.jsx'],
   tsx: ['.tsx', '.ts', '.d.ts', '.js', '.jsx', '/index.tsx', '/index.ts', '/index.js'],
   jsx: ['.jsx', '.js', '/index.jsx', '/index.js'],
   // SFC consumers import plain TS/JS, sibling components, and barrels