Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### New Features

- SAP HANA `.xsjs` and `.xsjslib` files (XS classic server-side JavaScript) are now indexed as JavaScript, so their functions show up in search, callers, callees, and trace instead of being skipped. (#556)
- `codegraph init` now builds the initial index by default — you no longer need the `-i`/`--index` flag (it's still accepted, so existing commands and scripts keep working). (#483)
- Go: Gin middleware chains now connect end-to-end in `codegraph_trace` and `codegraph_explore` — following a request reaches the middleware and route handlers registered via `.Use()` / `.GET()` instead of dead-ending where the framework dispatches the chain dynamically.
- `codegraph_explore` now sizes its response to the *answer* instead of the file count: it shows the mechanism and the exact methods you asked about in full — even when they're buried deep in a large file — while collapsing the redundant interchangeable implementations of an interface (an HTTP interceptor chain, a query-compiler family) down to signatures. Fewer tokens for a more complete answer, so on the flows that used to occasionally cost more than plain grep/read it's now clearly cheaper — and the win holds across small, medium, and large codebases. Distinct, non-interchangeable code is shown in full as before. Disable with `CODEGRAPH_ADAPTIVE_EXPLORE=0`.
Expand Down
62 changes: 62 additions & 0 deletions __tests__/extraction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ describe('Language Detection', () => {
expect(detectLanguage('config.mjs')).toBe('javascript');
});

it('should detect SAP HANA xsjs/xsjslib as JavaScript (#556)', () => {
expect(detectLanguage('service.xsjs')).toBe('javascript');
expect(detectLanguage('helpers.xsjslib')).toBe('javascript');
});

it('should detect Python files', () => {
expect(detectLanguage('main.py')).toBe('python');
});
Expand Down Expand Up @@ -3273,6 +3278,63 @@ export function multiply(a: number, b: number): number {
cg.close();
});

it('should index SAP xsjs/xsjslib files and extract their JS symbols (#556)', async () => {
// Include SAP XS globals ($.import / $.db) — ordinary JS member access
// to the grammar, so it must parse without error and still extract defs.
fs.writeFileSync(
path.join(tempDir, 'service.xsjs'),
'$.import("helpers.xsjslib");\n\nfunction handleRequest(req) {\n var conn = $.db.getConnection();\n return req.parameters;\n}\n'
);
fs.writeFileSync(
path.join(tempDir, 'helpers.xsjslib'),
'function buildQuery(table) {\n return "SELECT * FROM " + table;\n}\n'
);

const cg = CodeGraph.initSync(tempDir);
const result = await cg.indexAll();

expect(result.success).toBe(true);
expect(result.filesIndexed).toBe(2);
expect(result.filesSkipped).toBe(0);

// Files tracked as JavaScript, and their functions actually extracted
// (not just file-level tracking like YAML — the JS grammar runs).
expect(cg.getFiles().map((f) => `${f.path}:${f.language}`).sort()).toEqual([
'helpers.xsjslib:javascript',
'service.xsjs:javascript',
]);
expect(cg.getNodesInFile('service.xsjs').some((n) => n.name === 'handleRequest')).toBe(true);
expect(cg.getNodesInFile('helpers.xsjslib').some((n) => n.name === 'buildQuery')).toBe(true);

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` so a cross-file call edge is created.
fs.writeFileSync(
path.join(tempDir, 'helpers.xsjslib'),
'export function buildQuery(table) {\n return "SELECT * FROM " + 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');
expect(run).toBeDefined();
expect(buildQuery).toBeDefined();

const edge = cg.getOutgoingEdges(run!.id).find((e) => e.target === buildQuery!.id);
expect(edge, 'run() should resolve buildQuery across the .xsjs -> .xsjslib import').toBeDefined();

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');
Expand Down
4 changes: 4 additions & 0 deletions src/extraction/grammars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ export const EXTENSION_MAP: Record<string, Language> = {
'.js': 'javascript',
'.mjs': 'javascript',
'.cjs': 'javascript',
// SAP HANA 1.0 server-side JavaScript (XS classic): `.xsjs` services and
// `.xsjslib` libraries are plain JavaScript and parse with the JS grammar.
'.xsjs': 'javascript',
'.xsjslib': 'javascript',
'.jsx': 'jsx',
'.py': 'python',
'.pyw': 'python',
Expand Down
2 changes: 1 addition & 1 deletion src/resolution/import-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { applyAliases } from './path-aliases';
*/
const EXTENSION_RESOLUTION: Record<string, string[]> = {
typescript: ['.ts', '.tsx', '.d.ts', '.js', '.jsx', '/index.ts', '/index.tsx', '/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'],
python: ['.py', '/__init__.py'],
Expand Down