Create TypeValue structure (#184)
* Create TypeValue structure * Cleanup create * More nesting in types * Trim types (just in case)
This commit is contained in:
@@ -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'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user