import { TypeParser, createTypeParser } from '../src/parsers/typeParser'; import { InterfaceParser, createInterfaceParser } from '../src/parsers/interfaceParser'; import { TypeAliasParser, createTypeAliasParser } from '../src/parsers/typeAliasParser'; import { ImportParser, createImportParser } from '../src/parsers/importParser'; describe('TypeParser', () => { let parser: ReturnType; beforeEach(() => { parser = createTypeParser(); }); describe('parse', () => { it('should parse a simple interface', () => { const source = ` interface User { id: number; name: string; email: string; } `; const result = parser.parse(source, 'test.ts'); expect(result.types).toHaveLength(1); expect(result.types[0].name).toBe('User'); expect(result.types[0].kind).toBe('interface'); }); it('should parse multiple interfaces', () => { const source = ` interface A { id: number; } interface B { name: string; } `; const result = parser.parse(source, 'test.ts'); expect(result.types).toHaveLength(2); }); it('should parse type aliases', () => { const source = ` type ID = number | string; type UserResponse = { id: ID; name: string; }; `; const result = parser.parse(source, 'test.ts'); expect(result.types.length).toBeGreaterThanOrEqual(1); }); it('should parse enums', () => { const source = ` enum Status { Pending = 'pending', Approved = 'approved', Rejected = 'rejected' } `; const result = parser.parse(source, 'test.ts'); expect(result.types.some(t => t.kind === 'enum')).toBe(true); }); it('should parse imports', () => { const source = ` import { A, B } from './module'; import C from './default'; import * as D from './namespace'; `; const result = parser.parse(source, 'test.ts'); expect(result.imports.length).toBe(3); }); it('should handle empty source', () => { const source = ''; const result = parser.parse(source, 'test.ts'); expect(result.types).toHaveLength(0); expect(result.imports).toHaveLength(0); }); it('should track dependencies', () => { const source = ` interface A { b: B; } interface B { c: C; } `; const result = parser.parse(source, 'test.ts'); const a = result.types.find(t => t.name === 'A'); expect(a?.dependencies).toContain('B'); }); }); }); describe('InterfaceParser', () => { let parser: ReturnType; beforeEach(() => { parser = createInterfaceParser(); }); describe('parseInterface', () => { it('should parse interface properties', () => { const source = ` interface User { id: number; name: string; age?: number; } `; const interfaces = parser.parse(source, 'test.ts'); expect(interfaces).toHaveLength(1); expect(interfaces[0].members.length).toBe(3); }); it('should parse interface with extends', () => { const source = ` interface A {} interface B extends A {} `; const interfaces = parser.parse(source, 'test.ts'); const b = interfaces.find(i => i.name === 'B'); expect(b?.extends).toContain('A'); }); it('should parse generic parameters', () => { const source = ` interface Container { value: T; } `; const interfaces = parser.parse(source, 'test.ts'); expect(interfaces[0].generics).toHaveLength(1); expect(interfaces[0].generics[0].name).toBe('T'); }); it('should parse readonly properties', () => { const source = ` interface A { readonly id: number; } `; const interfaces = parser.parse(source, 'test.ts'); const member = interfaces[0].members.find(m => m.name === 'id'); expect(member?.isReadonly).toBe(true); }); }); }); describe('TypeAliasParser', () => { let parser: ReturnType; beforeEach(() => { parser = createTypeAliasParser(); }); describe('parseTypeAlias', () => { it('should parse simple type alias', () => { const source = ` type ID = number; `; const typeAliases = parser.parse(source, 'test.ts'); expect(typeAliases).toHaveLength(1); expect(typeAliases[0].name).toBe('ID'); }); it('should parse union type', () => { const source = ` type Status = 'pending' | 'approved' | 'rejected'; `; const typeAliases = parser.parse(source, 'test.ts'); expect(typeAliases[0].typeAnnotation).toContain('|'); }); it('should parse intersection type', () => { const source = ` type Combined = A & B; `; const typeAliases = parser.parse(source, 'test.ts'); expect(typeAliases[0].typeAnnotation).toContain('&'); }); it('should extract dependencies from union types', () => { const source = ` type A = {}; type B = {}; type C = A | B; `; const typeAliases = parser.parse(source, 'test.ts'); const c = typeAliases.find(t => t.name === 'C'); expect(c?.dependencies).toContain('A'); expect(c?.dependencies).toContain('B'); }); }); describe('getComplexityScore', () => { it('should calculate complexity score', () => { const source = ` type Simple = number; type Complex = A | B | C | D | E; `; const typeAliases = parser.parse(source, 'test.ts'); const simple = typeAliases.find(t => t.name === 'Simple'); const complex = typeAliases.find(t => t.name === 'Complex'); const simpleScore = parser.getComplexityScore(simple!); const complexScore = parser.getComplexityScore(complex!); expect(complexScore).toBeGreaterThan(simpleScore); }); }); }); describe('ImportParser', () => { let parser: ReturnType; beforeEach(() => { parser = createImportParser(); }); describe('parse', () => { it('should parse named imports', () => { const source = ` import { A, B, C } from './module'; `; const imports = parser.parse(source, 'test.ts'); expect(imports).toHaveLength(1); expect(imports[0].namedImports).toHaveLength(3); }); it('should parse default import', () => { const source = ` import MyDefault from './module'; `; const imports = parser.parse(source, 'test.ts'); expect(imports[0].defaultImport).toBe('MyDefault'); }); it('should parse namespace import', () => { const source = ` import * as Namespace from './module'; `; const imports = parser.parse(source, 'test.ts'); expect(imports[0].namespaceImport).toBe('Namespace'); }); it('should detect external modules', () => { const source = ` import { something } from 'external-package'; `; const imports = parser.parse(source, 'test.ts'); expect(imports[0].isExternal).toBe(true); }); it('should detect relative imports', () => { const source = ` import { something } from './local-module'; `; const imports = parser.parse(source, 'test.ts'); expect(imports[0].isExternal).toBe(false); }); }); });