Skip to content

Commit b848068

Browse files
Copilotstreamich
andcommitted
feat: implement XDR schema interface with comprehensive TypeScript types
Co-authored-by: streamich <[email protected]>
1 parent 792711e commit b848068

File tree

4 files changed

+542
-0
lines changed

4 files changed

+542
-0
lines changed

src/xdr/__tests__/types.test.ts

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/**
2+
* Tests for XDR types and type guards
3+
*/
4+
5+
import {
6+
XdrSchema,
7+
XdrIntSchema,
8+
XdrStringSchema,
9+
XdrStructSchema,
10+
XdrEnumSchema,
11+
XdrUnionSchema,
12+
XdrVoidSchema,
13+
XdrBooleanSchema,
14+
XdrFixedArraySchema,
15+
isXdrPrimitiveSchema,
16+
isXdrCompositeSchema,
17+
isXdrNamedSchema,
18+
XDR_BLOCK_SIZE,
19+
XDR_MAX_STRING_LENGTH,
20+
XDR_MAX_ARRAY_LENGTH
21+
} from '../types';
22+
23+
describe('XDR Types', () => {
24+
describe('primitive schemas', () => {
25+
it('creates valid void schema', () => {
26+
const voidSchema: XdrVoidSchema = {
27+
type: 'void',
28+
doc: 'No data'
29+
};
30+
expect(voidSchema.type).toBe('void');
31+
expect(isXdrPrimitiveSchema(voidSchema)).toBe(true);
32+
expect(isXdrCompositeSchema(voidSchema)).toBe(false);
33+
});
34+
35+
it('creates valid boolean schema', () => {
36+
const boolSchema: XdrBooleanSchema = {
37+
type: 'boolean'
38+
};
39+
expect(boolSchema.type).toBe('boolean');
40+
expect(isXdrPrimitiveSchema(boolSchema)).toBe(true);
41+
});
42+
43+
it('creates valid int schema', () => {
44+
const intSchema: XdrIntSchema = {
45+
type: 'int',
46+
doc: 'A 32-bit signed integer'
47+
};
48+
expect(intSchema.type).toBe('int');
49+
expect(intSchema.doc).toBe('A 32-bit signed integer');
50+
expect(isXdrPrimitiveSchema(intSchema)).toBe(true);
51+
});
52+
53+
it('creates valid enum schema', () => {
54+
const enumSchema: XdrEnumSchema = {
55+
type: 'enum',
56+
name: 'Color',
57+
values: {
58+
RED: 0,
59+
GREEN: 1,
60+
BLUE: 2
61+
}
62+
};
63+
expect(enumSchema.type).toBe('enum');
64+
expect(enumSchema.name).toBe('Color');
65+
expect(enumSchema.values.RED).toBe(0);
66+
expect(isXdrPrimitiveSchema(enumSchema)).toBe(true);
67+
expect(isXdrNamedSchema(enumSchema)).toBe(true);
68+
});
69+
});
70+
71+
describe('composite schemas', () => {
72+
it('creates valid string schema', () => {
73+
const stringSchema: XdrStringSchema = {
74+
type: 'string',
75+
maxLength: 255
76+
};
77+
expect(stringSchema.type).toBe('string');
78+
expect(stringSchema.maxLength).toBe(255);
79+
expect(isXdrCompositeSchema(stringSchema)).toBe(true);
80+
expect(isXdrPrimitiveSchema(stringSchema)).toBe(false);
81+
});
82+
83+
it('creates valid fixed array schema', () => {
84+
const arraySchema: XdrFixedArraySchema = {
85+
type: 'fixed_array',
86+
elements: { type: 'int' },
87+
length: 10
88+
};
89+
expect(arraySchema.type).toBe('fixed_array');
90+
expect(arraySchema.length).toBe(10);
91+
expect(isXdrCompositeSchema(arraySchema)).toBe(true);
92+
});
93+
94+
it('creates valid struct schema', () => {
95+
const structSchema: XdrStructSchema = {
96+
type: 'struct',
97+
name: 'Person',
98+
fields: [
99+
{
100+
name: 'id',
101+
type: { type: 'int' },
102+
doc: 'Unique identifier'
103+
},
104+
{
105+
name: 'name',
106+
type: { type: 'string' }
107+
}
108+
]
109+
};
110+
expect(structSchema.type).toBe('struct');
111+
expect(structSchema.name).toBe('Person');
112+
expect(structSchema.fields).toHaveLength(2);
113+
expect(structSchema.fields[0].name).toBe('id');
114+
expect(isXdrCompositeSchema(structSchema)).toBe(true);
115+
expect(isXdrNamedSchema(structSchema)).toBe(true);
116+
});
117+
118+
it('creates valid union schema', () => {
119+
const unionSchema: XdrUnionSchema = {
120+
type: 'union',
121+
name: 'Result',
122+
discriminant: { type: 'int' },
123+
cases: [
124+
{
125+
value: 0,
126+
type: { type: 'void' }
127+
},
128+
{
129+
value: 1,
130+
type: { type: 'string' }
131+
}
132+
]
133+
};
134+
expect(unionSchema.type).toBe('union');
135+
expect(unionSchema.name).toBe('Result');
136+
expect(unionSchema.cases).toHaveLength(2);
137+
expect(isXdrCompositeSchema(unionSchema)).toBe(true);
138+
expect(isXdrNamedSchema(unionSchema)).toBe(true);
139+
});
140+
});
141+
142+
describe('type guards', () => {
143+
it('correctly identifies primitive schemas', () => {
144+
expect(isXdrPrimitiveSchema({ type: 'int' })).toBe(true);
145+
expect(isXdrPrimitiveSchema({ type: 'boolean' })).toBe(true);
146+
expect(isXdrPrimitiveSchema({ type: 'float' })).toBe(true);
147+
expect(isXdrPrimitiveSchema({ type: 'string' })).toBe(false);
148+
expect(isXdrPrimitiveSchema('int')).toBe(false);
149+
});
150+
151+
it('correctly identifies composite schemas', () => {
152+
expect(isXdrCompositeSchema({ type: 'string' })).toBe(true);
153+
expect(isXdrCompositeSchema({ type: 'struct', name: 'Test', fields: [] })).toBe(true);
154+
expect(isXdrCompositeSchema({ type: 'int' })).toBe(false);
155+
expect(isXdrCompositeSchema('string')).toBe(false);
156+
});
157+
158+
it('correctly identifies named schemas', () => {
159+
expect(isXdrNamedSchema({ type: 'struct', name: 'Test', fields: [] })).toBe(true);
160+
expect(isXdrNamedSchema({ type: 'enum', name: 'Test', values: {} })).toBe(true);
161+
expect(isXdrNamedSchema({ type: 'union', name: 'Test', discriminant: { type: 'int' }, cases: [] })).toBe(true);
162+
expect(isXdrNamedSchema({ type: 'string' })).toBe(false);
163+
expect(isXdrNamedSchema('struct')).toBe(false);
164+
});
165+
});
166+
167+
describe('constants', () => {
168+
it('defines correct XDR constants', () => {
169+
expect(XDR_BLOCK_SIZE).toBe(4);
170+
expect(XDR_MAX_STRING_LENGTH).toBe(2 ** 32 - 1);
171+
expect(XDR_MAX_ARRAY_LENGTH).toBe(2 ** 32 - 1);
172+
});
173+
});
174+
175+
describe('schema arrays', () => {
176+
it('accepts mixed schema types', () => {
177+
const schemas: XdrSchema[] = [
178+
{ type: 'int' },
179+
{ type: 'string' },
180+
'int',
181+
{ type: 'struct', name: 'Test', fields: [] }
182+
];
183+
expect(schemas).toHaveLength(4);
184+
});
185+
});
186+
});

src/xdr/examples.ts

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/**
2+
* Examples demonstrating XDR schema definitions
3+
*
4+
* These examples show how to use the XDR type interfaces to define
5+
* schemas for various data structures following RFC 4506.
6+
*/
7+
8+
import {
9+
XdrIntSchema,
10+
XdrStringSchema,
11+
XdrStructSchema,
12+
XdrEnumSchema,
13+
XdrUnionSchema,
14+
XdrFixedArraySchema,
15+
XdrVariableArraySchema,
16+
XdrOptionalSchema
17+
} from './types';
18+
19+
// Basic primitive schemas
20+
export const intSchema: XdrIntSchema = {
21+
type: 'int',
22+
doc: 'A 32-bit signed integer'
23+
};
24+
25+
export const stringSchema: XdrStringSchema = {
26+
type: 'string',
27+
maxLength: 255,
28+
doc: 'A variable-length string with max 255 characters'
29+
};
30+
31+
// Enumeration example
32+
export const colorEnum: XdrEnumSchema = {
33+
type: 'enum',
34+
name: 'Color',
35+
doc: 'RGB color values',
36+
values: {
37+
RED: 0,
38+
GREEN: 1,
39+
BLUE: 2
40+
}
41+
};
42+
43+
// Structure example
44+
export const personStruct: XdrStructSchema = {
45+
type: 'struct',
46+
name: 'Person',
47+
doc: 'A person record',
48+
fields: [
49+
{
50+
name: 'id',
51+
type: intSchema,
52+
doc: 'Unique person identifier'
53+
},
54+
{
55+
name: 'name',
56+
type: stringSchema,
57+
doc: 'Person full name'
58+
},
59+
{
60+
name: 'age',
61+
type: { type: 'unsigned_int' },
62+
doc: 'Person age in years'
63+
}
64+
]
65+
};
66+
67+
// Array examples
68+
export const intArray: XdrFixedArraySchema = {
69+
type: 'fixed_array',
70+
elements: intSchema,
71+
length: 10,
72+
doc: 'Fixed array of 10 integers'
73+
};
74+
75+
export const dynamicStringArray: XdrVariableArraySchema = {
76+
type: 'variable_array',
77+
elements: stringSchema,
78+
maxLength: 100,
79+
doc: 'Variable-length array of strings'
80+
};
81+
82+
// Optional type example
83+
export const optionalString: XdrOptionalSchema = {
84+
type: 'optional',
85+
value: stringSchema,
86+
doc: 'An optional string value'
87+
};
88+
89+
// Union example (discriminated union)
90+
export const resultUnion: XdrUnionSchema = {
91+
type: 'union',
92+
name: 'Result',
93+
doc: 'A result that can be either success (string) or error (int)',
94+
discriminant: intSchema,
95+
cases: [
96+
{
97+
value: 0,
98+
type: stringSchema,
99+
doc: 'Success case with message'
100+
},
101+
{
102+
value: 1,
103+
type: intSchema,
104+
doc: 'Error case with error code'
105+
}
106+
]
107+
};
108+
109+
// Complex nested structure
110+
export const nestedStruct: XdrStructSchema = {
111+
type: 'struct',
112+
name: 'ComplexData',
113+
doc: 'Example of complex nested XDR structure',
114+
fields: [
115+
{
116+
name: 'header',
117+
type: {
118+
type: 'struct',
119+
name: 'Header',
120+
fields: [
121+
{ name: 'version', type: { type: 'int' } },
122+
{ name: 'timestamp', type: { type: 'hyper' } }
123+
]
124+
}
125+
},
126+
{
127+
name: 'people',
128+
type: {
129+
type: 'variable_array',
130+
elements: personStruct,
131+
maxLength: 1000
132+
}
133+
},
134+
{
135+
name: 'result',
136+
type: resultUnion
137+
}
138+
]
139+
};

src/xdr/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* XDR (External Data Representation Standard) module
3+
*
4+
* This module provides TypeScript type definitions for XDR schemas
5+
* based on RFC 4506 specification.
6+
*/
7+
8+
export * from './types';

0 commit comments

Comments
 (0)