Allow for nested fixed vec defintions (#3673)

* Allow for nested fixed vec defintions

* struct with nested struct & tuple

* extract conversion to type string

* Include < & > in split iteration

* Allow for nested ( & )

* CHANGELOG
This commit is contained in:
Jaco
2021-06-18 15:23:54 +02:00
committed by GitHub
parent 3cec316683
commit f2a82ddd0f
3 changed files with 181 additions and 22 deletions
+152 -13
View File
@@ -252,28 +252,167 @@ describe('getTypeDef', (): void => {
});
});
// FIXME - not handled atm
it.skip('creates a nested fixed vec', (): void => {
it('creates a nested fixed vec', (): void => {
expect(
getTypeDef('[[u8;32];3]')
getTypeDef('[[bool; 6]; 3; MyType]')
).toEqual({
ext: {
length: 3,
type: '[u8;32]'
},
displayName: 'MyType',
info: TypeDefInfo.VecFixed,
length: 3,
sub: {
ext: {
length: 32
},
info: TypeDefInfo.VecFixed,
length: 6,
sub: {
info: TypeDefInfo.Plain,
type: 'u8'
type: 'bool'
},
type: '[u8;32]'
type: '[bool;6]'
},
type: '[[u8;32];3]'
type: '[[bool;6];3;MyType]'
});
});
it('creates a nested tuple', (): void => {
expect(
getTypeDef('((u32, u64), u128)')
).toEqual({
info: TypeDefInfo.Tuple,
sub: [
{
info: TypeDefInfo.Tuple,
sub: [
{
info: TypeDefInfo.Plain,
type: 'u32'
},
{
info: TypeDefInfo.Plain,
type: 'u64'
}
],
type: '(u32,u64)'
},
{
info: TypeDefInfo.Plain,
type: 'u128'
}
],
type: '((u32,u64),u128)'
});
});
it('creates a nested enum with tuple/struct', (): void => {
expect(
getTypeDef(JSON.stringify({
_enum: {
A: 'u32',
B: '(u32, bool)',
C: {
d: 'AccountId',
e: 'Balance'
}
}
}))
).toEqual({
info: TypeDefInfo.Enum,
sub: [
{
index: 0,
info: TypeDefInfo.Plain,
name: 'A',
type: 'u32'
},
{
index: 1,
info: TypeDefInfo.Tuple,
name: 'B',
sub: [
{
info: TypeDefInfo.Plain,
type: 'u32'
},
{
info: TypeDefInfo.Plain,
type: 'bool'
}
],
type: '(u32,bool)'
},
{
index: 2,
info: TypeDefInfo.Struct,
name: 'C',
sub: [
{
info: TypeDefInfo.Plain,
name: 'd',
type: 'AccountId'
},
{
info: TypeDefInfo.Plain,
name: 'e',
type: 'Balance'
}
],
type: '{"d":"AccountId","e":"Balance"}'
}
],
type: '{"_enum":{"A":"u32","B":"(u32,bool)","C":{"d":"AccountId","e":"Balance"}}}'
});
});
it('creates a nested struct with struct/tuple', (): void => {
expect(
getTypeDef(JSON.stringify({
a: 'u32',
b: '(u32, bool)',
c: {
d: 'AccountId',
e: 'Balance'
}
}))
).toEqual({
info: TypeDefInfo.Struct,
sub: [
{
info: TypeDefInfo.Plain,
name: 'a',
type: 'u32'
},
{
info: TypeDefInfo.Tuple,
name: 'b',
sub: [
{
info: TypeDefInfo.Plain,
type: 'u32'
},
{
info: TypeDefInfo.Plain,
type: 'bool'
}
],
type: '(u32,bool)'
},
{
info: TypeDefInfo.Struct,
name: 'c',
sub: [
{
info: TypeDefInfo.Plain,
name: 'd',
type: 'AccountId'
},
{
info: TypeDefInfo.Plain,
name: 'e',
type: 'Balance'
}
],
type: '{"d":"AccountId","e":"Balance"}'
}
],
type: '{"a":"u32","b":"(u32,bool)","c":{"d":"AccountId","e":"Balance"}}'
});
});
+28 -9
View File
@@ -3,7 +3,7 @@
import type { TypeDef } from './types';
import { assert, isNumber } from '@polkadot/util';
import { assert, isNumber, isString } from '@polkadot/util';
import { sanitize } from './sanitize';
import { TypeDefInfo } from './types';
@@ -16,6 +16,12 @@ interface TypeDefOptions {
const MAX_NESTED = 64;
function getTypeString (typeOrObj: any): string {
return isString(typeOrObj)
? typeOrObj.toString()
: JSON.stringify(typeOrObj);
}
function isRustEnum (details: Record<string, string> | Record<string, number>): details is Record<string, string> {
const values = Object.values(details);
@@ -44,9 +50,8 @@ function _decodeEnum (value: TypeDef, details: string[] | Record<string, string>
type: 'Null'
}));
} else if (isRustEnum(details)) {
value.sub = Object.entries(details).map(([name, type], index): TypeDef => ({
// eslint-disable-next-line @typescript-eslint/no-use-before-define
...getTypeDef(type || 'Null', { name }, count),
value.sub = Object.entries(details).map(([name, typeOrObj], index): TypeDef => ({
...getTypeDef(getTypeString(typeOrObj || 'Null'), { name }, count),
index
}));
} else {
@@ -96,8 +101,7 @@ function _decodeStruct (value: TypeDef, type: string, _: string, count: number):
? new Map(Object.entries(parsed._alias))
: undefined;
value.sub = keys.filter((name) => !['_alias'].includes(name)).map((name): TypeDef =>
// eslint-disable-next-line @typescript-eslint/no-use-before-define
getTypeDef(parsed[name], { name }, count)
getTypeDef(getTypeString(parsed[name]), { name }, count)
);
return value;
@@ -106,7 +110,24 @@ function _decodeStruct (value: TypeDef, type: string, _: string, count: number):
// decode a fixed vector, e.g. [u8;32]
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function _decodeFixedVec (value: TypeDef, type: string, _: string, count: number): TypeDef {
const [vecType, strLength, displayName] = type.substr(1, type.length - 2).split(';');
const max = type.length - 1;
let index = -1;
let inner = 0;
for (let i = 1; (i < max) && (index === -1); i++) {
if (type[i] === ';' && inner === 0) {
index = i;
} else if (['[', '(', '<'].includes(type[i])) {
inner++;
} else if ([']', ')', '>'].includes(type[i])) {
inner--;
}
}
assert(index !== -1, () => `${type}: Unable to extract location of ';'`);
const vecType = type.substr(1, index - 1);
const [strLength, displayName] = type.substr(index + 1, max - index - 1).split(';');
const length = parseInt(strLength.trim(), 10);
// as a first round, only u8 via u8aFixed, we can add more support
@@ -114,7 +135,6 @@ function _decodeFixedVec (value: TypeDef, type: string, _: string, count: number
value.displayName = displayName;
value.length = length;
// eslint-disable-next-line @typescript-eslint/no-use-before-define
value.sub = getTypeDef(vecType, {}, count);
return value;
@@ -124,7 +144,6 @@ function _decodeFixedVec (value: TypeDef, type: string, _: string, count: number
function _decodeTuple (value: TypeDef, _: string, subType: string, count: number): TypeDef {
value.sub = subType.length === 0
? []
// eslint-disable-next-line @typescript-eslint/no-use-before-define
: typeSplit(subType).map((inner) => getTypeDef(inner, {}, count));
return value;