import { DeclarationGenerator } from '../src/declaration-generator.js'; import { TypeDefinition, ObjectType, ArrayType, UnionType } from '../src/types.js'; describe('DeclarationGenerator', () => { let generator: DeclarationGenerator; beforeEach(() => { generator = new DeclarationGenerator(2); }); describe('generate', () => { it('should generate primitive type declarations', () => { const types: TypeDefinition[] = [ { name: 'MyString', type: { kind: 'primitive', type: 'string' } }, ]; const result = generator.generate(types); expect(result).toBe('export type MyString = string;'); }); it('should generate number type declarations', () => { const types: TypeDefinition[] = [ { name: 'MyNumber', type: { kind: 'primitive', type: 'number' } }, ]; const result = generator.generate(types); expect(result).toBe('export type MyNumber = number;'); }); it('should generate boolean type declarations', () => { const types: TypeDefinition[] = [ { name: 'MyBoolean', type: { kind: 'primitive', type: 'boolean' } }, ]; const result = generator.generate(types); expect(result).toBe('export type MyBoolean = boolean;'); }); it('should generate null type declarations', () => { const types: TypeDefinition[] = [ { name: 'MyNull', type: { kind: 'primitive', type: 'null' } }, ]; const result = generator.generate(types); expect(result).toBe('export type MyNull = null;'); }); }); describe('generate interface declarations', () => { it('should generate interface declarations for objects', () => { const objectType: ObjectType = { kind: 'object', properties: [ { name: 'name', type: { kind: 'primitive', type: 'string' }, optional: false }, { name: 'age', type: { kind: 'primitive', type: 'number' }, optional: false }, ], }; const types: TypeDefinition[] = [ { name: 'User', type: objectType }, ]; const result = generator.generate(types); expect(result).toContain('export interface User'); expect(result).toContain('name: string;'); expect(result).toContain('age: number;'); }); it('should generate optional properties', () => { const objectType: ObjectType = { kind: 'object', properties: [ { name: 'required', type: { kind: 'primitive', type: 'string' }, optional: false }, { name: 'optional', type: { kind: 'primitive', type: 'number' }, optional: true }, ], }; const types: TypeDefinition[] = [ { name: 'Test', type: objectType }, ]; const result = generator.generate(types); expect(result).toContain('required: string;'); expect(result).toContain('optional?: number;'); }); it('should generate nested object interfaces', () => { const nestedType: ObjectType = { kind: 'object', properties: [ { name: 'street', type: { kind: 'primitive', type: 'string' }, optional: false }, ], name: 'Address', }; const rootType: ObjectType = { kind: 'object', properties: [ { name: 'name', type: { kind: 'primitive', type: 'string' }, optional: false }, { name: 'address', type: nestedType, optional: false }, ], name: 'User', }; const types: TypeDefinition[] = [ { name: 'User', type: rootType }, { name: 'Address', type: nestedType }, ]; const result = generator.generate(types); expect(result).toContain('export interface User'); expect(result).toContain('export interface Address'); expect(result).toContain('address:'); }); it('should generate array types', () => { const arrayType: ArrayType = { kind: 'array', elementType: { kind: 'primitive', type: 'string' }, }; const types: TypeDefinition[] = [ { name: 'StringList', type: arrayType }, ]; const result = generator.generate(types); expect(result).toBe('export type StringList = string[];'); }); it('should generate array of objects', () => { const objectType: ObjectType = { kind: 'object', properties: [ { name: 'id', type: { kind: 'primitive', type: 'number' }, optional: false }, ], }; const arrayType: ArrayType = { kind: 'array', elementType: objectType, }; const types: TypeDefinition[] = [ { name: 'ItemList', type: arrayType }, ]; const result = generator.generate(types); expect(result).toContain('export type ItemList'); expect(result).toContain('id: number;'); }); it('should generate union types', () => { const unionType: UnionType = { kind: 'union', types: [ { kind: 'primitive', type: 'string' }, { kind: 'primitive', type: 'number' }, ], }; const types: TypeDefinition[] = [ { name: 'StringOrNumber', type: unionType }, ]; const result = generator.generate(types); expect(result).toBe('export type StringOrNumber = string | number;'); }); it('should format union types with proper spacing', () => { const unionType: UnionType = { kind: 'union', types: [ { kind: 'literal', value: 'active' }, { kind: 'literal', value: 'inactive' }, { kind: 'primitive', type: 'null' }, ], }; const types: TypeDefinition[] = [ { name: 'Status', type: unionType }, ]; const result = generator.generate(types); expect(result).toBe("export type Status = 'active' | 'inactive' | null;"); }); }); describe('generateStandalone', () => { it('should generate multiple declarations', () => { const userType: ObjectType = { kind: 'object', properties: [ { name: 'id', type: { kind: 'primitive', type: 'number' }, optional: false }, ], name: 'User', }; const addressType: ObjectType = { kind: 'object', properties: [ { name: 'city', type: { kind: 'primitive', type: 'string' }, optional: false }, ], name: 'Address', }; const types: TypeDefinition[] = [ { name: 'User', type: userType }, { name: 'Address', type: addressType }, ]; const result = generator.generateStandalone(types); expect(result).toContain('export interface User'); expect(result).toContain('export interface Address'); }); it('should handle empty types array', () => { const result = generator.generateStandalone([]); expect(result).toBe(''); }); }); describe('nested structures', () => { it('should generate complex nested structures', () => { const addressType: ObjectType = { kind: 'object', properties: [ { name: 'street', type: { kind: 'primitive', type: 'string' }, optional: false }, { name: 'zipCode', type: { kind: 'primitive', type: 'number' }, optional: false }, ], name: 'Address', }; const userType: ObjectType = { kind: 'object', properties: [ { name: 'name', type: { kind: 'primitive', type: 'string' }, optional: false }, { name: 'age', type: { kind: 'primitive', type: 'number' }, optional: true }, { name: 'address', type: addressType, optional: false }, { name: 'tags', type: { kind: 'array', elementType: { kind: 'primitive', type: 'string' } }, optional: false }, ], name: 'User', }; const types: TypeDefinition[] = [ { name: 'User', type: userType }, { name: 'Address', type: addressType }, ]; const result = generator.generate(types); expect(result).toContain('export interface User'); expect(result).toContain('export interface Address'); expect(result).toContain('tags:'); }); }); });