diff --git a/CHANGELOG.md b/CHANGELOG.md index 54ef5f5a..c6f9a40f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### New Features - `codegraph status --json` now also reports the running CLI `version`, the index directory (`indexPath`), and a `lastIndexed` timestamp (ISO-8601, or null when nothing's indexed yet), so CI and scripts can pin the CLI version and check index freshness from a single command. A matching `CodeGraph.getLastIndexedAt()` library method exposes the same freshness check without shelling out. Thanks @12122J and @eddieran. (#329) +- MyBatis `` elements are now indexed, and statements that declare `resultMap="..."` link to them — so you can ask which statements use a given result map (callers / impact), not just which use a `` fragment. (#592) ### Fixes diff --git a/__tests__/frameworks-integration.test.ts b/__tests__/frameworks-integration.test.ts index 344a0f6c..0a81e369 100644 --- a/__tests__/frameworks-integration.test.ts +++ b/__tests__/frameworks-integration.test.ts @@ -464,6 +464,77 @@ describe('Java end-to-end — field-injected bean trace (issue #389)', () => { cg.close(); }); + it('indexes MyBatis and links statements that reference it (#592)', async () => { + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-mybatis-rm-')); + const javaDir = path.join(tmpDir, 'src/main/java/com/example/dao'); + const xmlDir = path.join(tmpDir, 'src/main/resources/mappers'); + fs.mkdirSync(javaDir, { recursive: true }); + fs.mkdirSync(xmlDir, { recursive: true }); + fs.writeFileSync( + path.join(tmpDir, 'pom.xml'), + 'org.mybatismybatis\n' + ); + // Java method `userResult` deliberately collides with the resultMap id, + // to prove the Java↔XML bridge does NOT wrongly link to the result map. + fs.writeFileSync( + path.join(javaDir, 'UserMapper.java'), + 'package com.example.dao;\n' + + 'public interface UserMapper {\n' + + ' Object findById(int id);\n' + + ' Object userResult();\n' + + '}\n' + ); + fs.writeFileSync( + path.join(xmlDir, 'UserMapper.xml'), + '\n' + + '\n' + + '\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + '\n' + ); + + const cg = CodeGraph.initSync(tmpDir); + await cg.indexAll(); + + const methods = cg.getNodesByKind('method'); + const resultMap = methods.find((n) => n.name === 'userResult' && n.language === 'xml'); + const findById = methods.find((n) => n.name === 'findById' && n.language === 'xml'); + expect(resultMap, ' should be indexed').toBeDefined(); + expect(resultMap!.qualifiedName).toBe('com.example.dao.UserMapper::userResult'); + expect(resultMap!.signature).toBe(' type=User'); + expect(findById).toBeDefined(); + + // still + // bridges to its Java mapper method. + const javaFindById = methods.find((n) => n.name === 'findById' && n.language === 'java'); + expect(javaFindById).toBeDefined(); + const realBridge = cg + .getOutgoingEdges(javaFindById!.id) + .find((e) => e.target === findById!.id); + expect(realBridge, 'Java findById should still bridge to its XML