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:
@@ -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"}}'
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user