mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-11-13 08:51:28 +00:00
fix(impact): add HAS_METHOD and OVERRIDES to VALID_RELATION_TYPES (#350)
This commit is contained in:
parent
6d2cb4039f
commit
c717d69457
5 changed files with 73 additions and 4 deletions
|
|
@ -47,7 +47,7 @@ export const VALID_NODE_LABELS = new Set([
|
|||
]);
|
||||
|
||||
/** Valid relation types for impact analysis filtering */
|
||||
export const VALID_RELATION_TYPES = new Set(['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS']);
|
||||
export const VALID_RELATION_TYPES = new Set(['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS', 'HAS_METHOD', 'OVERRIDES']);
|
||||
|
||||
/** Regex to detect write operations in user-supplied Cypher queries */
|
||||
export const CYPHER_WRITE_RE = /\b(CREATE|DELETE|SET|MERGE|REMOVE|DROP|ALTER|COPY|DETACH)\b/i;
|
||||
|
|
|
|||
14
gitnexus/test/fixtures/local-backend-seed.ts
vendored
14
gitnexus/test/fixtures/local-backend-seed.ts
vendored
|
|
@ -10,6 +10,10 @@ export const LOCAL_BACKEND_SEED_DATA = [
|
|||
`CREATE (fn:Function {id: 'func:hash', name: 'hash', filePath: 'src/utils.ts', startLine: 1, endLine: 8, isExported: true, content: 'function hash() {}', description: 'Hash utility'})`,
|
||||
// Class
|
||||
`CREATE (c:Class {id: 'class:AuthService', name: 'AuthService', filePath: 'src/auth.ts', startLine: 30, endLine: 60, isExported: true, content: 'class AuthService {}', description: 'Authentication service'})`,
|
||||
`CREATE (c:Class {id: 'class:BaseService', name: 'BaseService', filePath: 'src/base.ts', startLine: 1, endLine: 20, isExported: true, content: 'class BaseService {}', description: 'Base service class'})`,
|
||||
// Methods
|
||||
`CREATE (m:Method {id: 'method:AuthService.authenticate', name: 'authenticate', filePath: 'src/auth.ts', startLine: 35, endLine: 45, isExported: false, content: 'authenticate() {}', description: 'Authenticate user'})`,
|
||||
`CREATE (m:Method {id: 'method:BaseService.authenticate', name: 'authenticate', filePath: 'src/base.ts', startLine: 5, endLine: 10, isExported: false, content: 'authenticate() {}', description: 'Base authenticate'})`,
|
||||
// Community
|
||||
`CREATE (c:Community {id: 'comm:auth', label: 'Auth', heuristicLabel: 'Authentication', keywords: ['auth', 'login'], description: 'Auth module', enrichedBy: 'heuristic', cohesion: 0.8, symbolCount: 3})`,
|
||||
// Process
|
||||
|
|
@ -25,10 +29,20 @@ export const LOCAL_BACKEND_SEED_DATA = [
|
|||
CREATE (a)-[:CodeRelation {type: 'STEP_IN_PROCESS', confidence: 1.0, reason: '', step: 1}]->(p)`,
|
||||
`MATCH (a:Function), (p:Process) WHERE a.id = 'func:validate' AND p.id = 'proc:login-flow'
|
||||
CREATE (a)-[:CodeRelation {type: 'STEP_IN_PROCESS', confidence: 1.0, reason: '', step: 2}]->(p)`,
|
||||
// HAS_METHOD: AuthService -> authenticate
|
||||
`MATCH (c:Class), (m:Method) WHERE c.id = 'class:AuthService' AND m.id = 'method:AuthService.authenticate'
|
||||
CREATE (c)-[:CodeRelation {type: 'HAS_METHOD', confidence: 1.0, reason: 'class-method', step: 0}]->(m)`,
|
||||
// OVERRIDES: AuthService.authenticate -> BaseService.authenticate
|
||||
`MATCH (a:Method), (b:Method) WHERE a.id = 'method:AuthService.authenticate' AND b.id = 'method:BaseService.authenticate'
|
||||
CREATE (a)-[:CodeRelation {type: 'OVERRIDES', confidence: 1.0, reason: 'mro-resolution', step: 0}]->(b)`,
|
||||
// HAS_METHOD: BaseService -> authenticate
|
||||
`MATCH (c:Class), (m:Method) WHERE c.id = 'class:BaseService' AND m.id = 'method:BaseService.authenticate'
|
||||
CREATE (c)-[:CodeRelation {type: 'HAS_METHOD', confidence: 1.0, reason: 'class-method', step: 0}]->(m)`,
|
||||
];
|
||||
|
||||
export const LOCAL_BACKEND_FTS_INDEXES: FTSIndexDef[] = [
|
||||
{ table: 'Function', indexName: 'function_fts', columns: ['name', 'content', 'description'] },
|
||||
{ table: 'Class', indexName: 'class_fts', columns: ['name', 'content', 'description'] },
|
||||
{ table: 'Method', indexName: 'method_fts', columns: ['name', 'content', 'description'] },
|
||||
{ table: 'File', indexName: 'file_fts', columns: ['name', 'content'] },
|
||||
];
|
||||
|
|
|
|||
|
|
@ -106,6 +106,59 @@ withTestLbugDB('local-backend-calltool', (handle) => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('impact tool relationTypes filtering', () => {
|
||||
let backend: LocalBackend;
|
||||
|
||||
beforeAll(async () => {
|
||||
const ext = handle as typeof handle & { _backend?: LocalBackend };
|
||||
if (!ext._backend) {
|
||||
throw new Error('LocalBackend not initialized — afterSetup did not attach _backend to handle');
|
||||
}
|
||||
backend = ext._backend;
|
||||
});
|
||||
|
||||
it('filters by HAS_METHOD only', async () => {
|
||||
const result = await backend.callTool('impact', {
|
||||
target: 'AuthService',
|
||||
direction: 'downstream',
|
||||
relationTypes: ['HAS_METHOD'],
|
||||
});
|
||||
expect(result).not.toHaveProperty('error');
|
||||
expect(result.impactedCount).toBeGreaterThanOrEqual(1);
|
||||
const d1 = result.byDepth[1] || result.byDepth['1'] || [];
|
||||
const names = d1.map((d: any) => d.name);
|
||||
expect(names).toContain('authenticate');
|
||||
// Should NOT include CALLS-reachable symbols like validate/hash
|
||||
expect(names).not.toContain('validate');
|
||||
expect(names).not.toContain('hash');
|
||||
});
|
||||
|
||||
it('filters by OVERRIDES only', async () => {
|
||||
const result = await backend.callTool('impact', {
|
||||
target: 'authenticate',
|
||||
direction: 'downstream',
|
||||
relationTypes: ['OVERRIDES'],
|
||||
});
|
||||
expect(result).not.toHaveProperty('error');
|
||||
// AuthService.authenticate overrides BaseService.authenticate
|
||||
expect(result.impactedCount).toBeGreaterThanOrEqual(1);
|
||||
const d1 = result.byDepth[1] || result.byDepth['1'] || [];
|
||||
const names = d1.map((d: any) => d.name);
|
||||
expect(names).toContain('authenticate');
|
||||
});
|
||||
|
||||
it('does not return HAS_METHOD results when filtering by CALLS only', async () => {
|
||||
const result = await backend.callTool('impact', {
|
||||
target: 'AuthService',
|
||||
direction: 'downstream',
|
||||
relationTypes: ['CALLS'],
|
||||
});
|
||||
expect(result).not.toHaveProperty('error');
|
||||
// AuthService has no outgoing CALLS edges, only HAS_METHOD
|
||||
expect(result.impactedCount).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('tool parameter edge cases', () => {
|
||||
let backend: LocalBackend;
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ withTestLbugDB('local-backend', (handle) => {
|
|||
|
||||
describe('relation type filtering', () => {
|
||||
it('only allows valid relation types in queries', () => {
|
||||
const validTypes = ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS'];
|
||||
const validTypes = ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS', 'HAS_METHOD', 'OVERRIDES'];
|
||||
const invalidTypes = ['CONTAINS', 'STEP_IN_PROCESS', 'MEMBER_OF', 'DROP_TABLE'];
|
||||
|
||||
for (const t of validTypes) {
|
||||
|
|
|
|||
|
|
@ -96,12 +96,14 @@ describe('isWriteQuery', () => {
|
|||
// ─── Relation type allowlist ──────────────────────────────────────────
|
||||
|
||||
describe('VALID_RELATION_TYPES', () => {
|
||||
it('contains exactly the expected 4 types', () => {
|
||||
expect(VALID_RELATION_TYPES.size).toBe(4);
|
||||
it('contains exactly the expected 6 types', () => {
|
||||
expect(VALID_RELATION_TYPES.size).toBe(6);
|
||||
expect(VALID_RELATION_TYPES.has('CALLS')).toBe(true);
|
||||
expect(VALID_RELATION_TYPES.has('IMPORTS')).toBe(true);
|
||||
expect(VALID_RELATION_TYPES.has('EXTENDS')).toBe(true);
|
||||
expect(VALID_RELATION_TYPES.has('IMPLEMENTS')).toBe(true);
|
||||
expect(VALID_RELATION_TYPES.has('HAS_METHOD')).toBe(true);
|
||||
expect(VALID_RELATION_TYPES.has('OVERRIDES')).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects invalid relation types', () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue