Create TypeValue structure (#184)

* Create TypeValue structure

* Cleanup create

* More nesting in types

* Trim types (just in case)
This commit is contained in:
Jaco Greeff
2018-10-02 13:09:25 +02:00
committed by GitHub
parent e4805c2b8d
commit c7cd9cdfbf
2 changed files with 110 additions and 50 deletions
+52 -15
View File
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { typeSplit, getType, getTupleType, getVectorType } from './createType';
import { TypeValueInfo, typeSplit, getType, getTypeValue } from './createType';
describe('typeSplit', () => {
it('splits simple types into an array', () => {
@@ -48,31 +48,68 @@ describe('typeSplit', () => {
});
});
describe('getTupleType', () => {
describe('getTypeValue', () => {
it('does not allow invalid tuples, end )', () => {
expect(
() => getTupleType('(u64, u32')
() => getTypeValue('(u64, u32')
).toThrow(/tuple wrapped/);
});
it('does not allow invalid tuples, start (', () => {
expect(
() => getTupleType('u64, u32)')
).toThrow(/tuple wrapped/);
});
});
describe('getVectorType', () => {
it('does not allow invalid vectors, end >', () => {
expect(
() => getVectorType('Vec<u64')
() => getTypeValue('Vec<u64')
).toThrow(/Vec wrapped/);
});
it('does not allow invalid vectors, start Vec<', () => {
it('returns a type structure', () => {
expect(
() => getVectorType('u64>')
).toThrow(/Vec wrapped/);
getTypeValue('(u32, Vec<u64>, (Text, Vec<(Bool, u128)>))')
).toEqual({
info: TypeValueInfo.Tuple,
type: '(u32, Vec<u64>, (Text, Vec<(Bool, u128)>))',
sub: [
{
info: TypeValueInfo.Plain,
type: 'u32'
},
{
info: TypeValueInfo.Vector,
type: 'Vec<u64>',
sub: {
info: TypeValueInfo.Plain,
type: 'u64'
}
},
{
info: TypeValueInfo.Tuple,
type: '(Text, Vec<(Bool, u128)>)',
sub: [
{
info: TypeValueInfo.Plain,
type: 'Text'
},
{
info: TypeValueInfo.Vector,
type: 'Vec<(Bool, u128)>',
sub: {
info: TypeValueInfo.Tuple,
type: '(Bool, u128)',
sub: [
{
info: TypeValueInfo.Plain,
type: 'Bool'
},
{
info: TypeValueInfo.Plain,
type: 'u128'
}
]
}
}
]
}
]
});
});
});
+58 -35
View File
@@ -11,6 +11,18 @@ import Vector from './Vector';
type Constructor = { new (value?: any): Base };
export enum TypeValueInfo {
Plain,
Tuple,
Vector
}
export type TypeValue = {
info: TypeValueInfo,
type: string,
sub?: TypeValue | Array<TypeValue>
};
// safely split a string on ', ' while taking care of any nested occurences
export function typeSplit (type: string): Array<string> {
let tDepth = 0;
@@ -62,54 +74,63 @@ export function typeSplit (type: string): Array<string> {
return result;
}
// Handle Vector types, i.e Vec<AccountId> or Vec<(AccountId, Balance)>
export function getVectorType (type: string): Constructor {
// l.debug(() => ['getVectorType', { type }]);
export function getTypeValue (_type: string): TypeValue {
const type = _type.trim();
const value: TypeValue = {
info: TypeValueInfo.Plain,
type
};
assert(type.substr(0, 4) === 'Vec<' && type[type.length - 1] === '>', `Expected Vec wrapped with <>`);
if (type[0] === '(') {
assert(type[type.length - 1] === ')', `Expected tuple wrapped with ()`);
// strip wrapping Vec<>
const subType = type.substr(4, type.length - 5);
// strip wrapping ()'s
const innerTypes = typeSplit(type.substr(1, type.length - 2));
return Vector.with(
getType(subType)
);
}
value.info = TypeValueInfo.Tuple;
value.sub = innerTypes.map((inner) =>
getTypeValue(inner)
);
} else if (type.substr(0, 4) === 'Vec<') {
assert(type[type.length - 1] === '>', `Expected Vec wrapped with <>`);
// Handle tuple types, (u32, String, AccountId). It could be nested and wrapped in other
// types, i.e. (u32, Vec<(AccountId, Balance)>)
export function getTupleType (type: string): Constructor {
// l.debug(() => ['getTupleType', { type }]);
// strip wrapping Vec<>
const subType = type.substr(4, type.length - 5);
assert(type[0] === '(' && type[type.length - 1] === ')', `Expected tuple wrapped with ()`);
value.info = TypeValueInfo.Vector;
value.sub = getTypeValue(subType);
}
// strip wrapping ()'s
const innerTypes = typeSplit(type.substr(1, type.length - 2));
return Tuple.with(
innerTypes.reduce((result, type, index) => {
result[`entry${index}`] = getType(type);
return result;
}, {} as { [index: string]: Constructor })
);
return value;
}
// Returns the type Class for construction
export function getType (_type: string): Constructor {
const type = _type.trim();
export function getType (value: TypeValue): Constructor {
if (value.info === TypeValueInfo.Tuple) {
if (!Array.isArray(value.sub)) {
throw new Error(`Expected nested subtypes for Tuple`);
}
// l.debug(() => ['getType', { type }]);
return Tuple.with(
value.sub.reduce((result, type, index) => {
result[`entry${index}`] = getType(type);
if (type[0] === '(') {
return getTupleType(type);
} else if (type.substr(0, 4) === 'Vec<') {
return getVectorType(type);
return result;
}, {} as { [index: string]: Constructor })
);
} else if (value.info === TypeValueInfo.Vector) {
if (!value.sub || Array.isArray(value.sub)) {
throw new Error(`Expected subtype for Vector`);
}
return Vector.with(
getType(value.sub)
);
}
const Type = (Types as any)[type];
const Type = (Types as any)[value.type];
assert(Type, `Unable to determine type from '${type}'`);
assert(Type, `Unable to determine type from '${value.type}'`);
return Type;
}
@@ -117,7 +138,9 @@ export function getType (_type: string): Constructor {
export default function createType (type: string, value?: any): Base {
// l.debug(() => ['createType', { type, value }]);
const Type = getType(type);
const Type = getType(
getTypeValue(type)
);
return new Type(value);
}