230 lines
7.9 KiB
TypeScript
230 lines
7.9 KiB
TypeScript
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:');
|
|
});
|
|
});
|
|
});
|