import * as fs from 'fs'; import * as path from 'path'; import { TypeParser, createTypeParser } from '../src/parsers/typeParser'; import { DependencyGraphBuilder, createDependencyGraphBuilder } from '../src/analyzers/dependencyGraph'; import { detectCircularDependencies } from '../src/analyzers/circularDetector'; describe('Integration Tests', () => { const fixturesDir = path.join(__dirname, 'fixtures'); beforeAll(() => { if (!fs.existsSync(fixturesDir)) { fs.mkdirSync(fixturesDir, { recursive: true }); } }); describe('Real-world TypeScript parsing', () => { it('should parse complex interfaces with generics', () => { const source = ` interface ApiResponse { data: T; status: number; message: string; timestamp: Date; } interface User { id: number; name: string; email: string; } type UserApiResponse = ApiResponse; `; const parser = createTypeParser(); const result = parser.parse(source, 'test.ts'); expect(result.types.length).toBeGreaterThanOrEqual(2); }); it('should parse conditional types', () => { const source = ` type IfEquals = (() => T extends X ? 1 : 2) extends (() => T extends Y ? 1 : 2) ? A : B; type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P]; }; `; const parser = createTypeParser(); const result = parser.parse(source, 'test.ts'); expect(result.types.length).toBe(2); }); it('should parse mapped types', () => { const source = ` type Readonly = { readonly [P in keyof T]: T[P]; }; type Partial = { [P in keyof T]?: T[P]; }; `; const parser = createTypeParser(); const result = parser.parse(source, 'test.ts'); expect(result.types.length).toBe(2); }); it('should parse template literal types', () => { const source = ` type EventName = \`on\${string}\`; type Color = 'red' | 'green' | 'blue'; `; const parser = createTypeParser(); const result = parser.parse(source, 'test.ts'); expect(result.types.length).toBe(2); }); }); describe('Circular Dependency Detection Integration', () => { it('should detect circular dependencies in a chain', () => { const files = [ { filePath: '/test/a.ts', types: [ { name: 'A', filePath: '/test/a.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['B'], rawNode: undefined } ], imports: [], errors: [] }, { filePath: '/test/b.ts', types: [ { name: 'B', filePath: '/test/b.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['C'], rawNode: undefined } ], imports: [], errors: [] }, { filePath: '/test/c.ts', types: [ { name: 'C', filePath: '/test/c.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['A'], rawNode: undefined } ], imports: [], errors: [] } ]; const builder = createDependencyGraphBuilder(); const graph = builder.build(files, '/test'); const cycles = detectCircularDependencies(graph); expect(cycles.length).toBeGreaterThan(0); expect(cycles[0].nodes).toContain('/test/a.ts#A'); expect(cycles[0].nodes).toContain('/test/b.ts#B'); expect(cycles[0].nodes).toContain('/test/c.ts#C'); }); it('should handle multiple independent circular dependencies', () => { const files = [ { filePath: '/test/a.ts', types: [ { name: 'A', filePath: '/test/a.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['B'], rawNode: undefined } ], imports: [], errors: [] }, { filePath: '/test/b.ts', types: [ { name: 'B', filePath: '/test/b.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['A'], rawNode: undefined } ], imports: [], errors: [] }, { filePath: '/test/c.ts', types: [ { name: 'C', filePath: '/test/c.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['D'], rawNode: undefined } ], imports: [], errors: [] }, { filePath: '/test/d.ts', types: [ { name: 'D', filePath: '/test/d.ts', startLine: 1, endLine: 5, kind: 'interface' as const, dependencies: ['C'], rawNode: undefined } ], imports: [], errors: [] } ]; const builder = createDependencyGraphBuilder(); const graph = builder.build(files, '/test'); const cycles = detectCircularDependencies(graph); expect(cycles.length).toBe(2); }); }); describe('Full Analysis Pipeline', () => { it('should parse and build graph for complex type hierarchy', () => { const source = ` interface Animal { name: string; } interface Dog extends Animal { breed: string; } interface Cat extends Animal { color: string; } type Pet = Dog | Cat; `; const parser = createTypeParser(); const parsedFiles = parser.parse(source, 'test.ts'); const builder = createDependencyGraphBuilder(); const graph = builder.build([parsedFiles], '/test'); expect(graph.nodes.size).toBe(4); expect(graph.edges.length).toBeGreaterThanOrEqual(2); const dogNode = graph.nodes.get('test.ts#Dog'); expect(dogNode).toBeDefined(); const petNode = graph.nodes.get('test.ts#Pet'); expect(petNode).toBeDefined(); }); }); });