Decoding cleanups (#1321)
* Decoding cleanups * Split extractDef * Extract struct types to string mapping
This commit is contained in:
@@ -45,7 +45,7 @@ export default abstract class AbstractInt extends BN implements Codec {
|
||||
// This function returns a string, which will be passed in the BN
|
||||
// constructor. It would be ideal to actually return a BN, but there's a
|
||||
// bug: https://github.com/indutny/bn.js/issues/206.
|
||||
if (isHex(value)) {
|
||||
if (isHex(value, -1, true)) {
|
||||
return hexToBn(value, { isLe: false, isNegative }).toString();
|
||||
} else if (isU8a(value)) {
|
||||
return AbstractInt.decodeAbstracIntU8a(value, bitLength, isNegative);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { AnyNumber, Codec, Constructor, InterfaceTypes } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { bnToBn, compactAddLength, compactFromU8a, compactStripLength, compactToU8a, hexToBn, isBn, isHex, isNumber, isString } from '@polkadot/util';
|
||||
import { compactAddLength, compactFromU8a, compactStripLength, compactToU8a, isBn, isNumber, isString } from '@polkadot/util';
|
||||
import { DEFAULT_BITLENGTH } from '@polkadot/util/compact/defaults';
|
||||
|
||||
import { typeToConstructor } from './utils';
|
||||
@@ -59,14 +59,8 @@ export default class Compact<T extends CompactEncodable> extends Base<T> {
|
||||
public static decodeCompact<T extends CompactEncodable> (Type: Constructor<T>, value: Compact<T> | AnyNumber): CompactEncodable {
|
||||
if (value instanceof Compact) {
|
||||
return new Type(value.raw);
|
||||
} else if (isString(value)) {
|
||||
return new Type(
|
||||
isHex(value, -1, true)
|
||||
? hexToBn(value)
|
||||
: new BN(value, 10)
|
||||
);
|
||||
} else if (isNumber(value) || isBn(value)) {
|
||||
return new Type(bnToBn(value));
|
||||
} else if (isString(value) || isNumber(value) || isBn(value)) {
|
||||
return new Type(value);
|
||||
}
|
||||
|
||||
const [, _value] = Compact.decodeU8a(value, new Type(0).bitLength());
|
||||
|
||||
@@ -2,6 +2,279 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import Enum from './EnumType';
|
||||
import { AnyJson, Codec, Constructor, InterfaceTypes } from '../types';
|
||||
|
||||
export default Enum;
|
||||
import { assert, hexToU8a, isHex, isNumber, isObject, isString, isU8a, isUndefined, stringCamelCase, stringUpperFirst, u8aConcat, u8aToHex } from '@polkadot/util';
|
||||
|
||||
import Null from '../primitive/Null';
|
||||
import { mapToTypeMap } from './utils';
|
||||
import Base from './Base';
|
||||
import Struct from './Struct';
|
||||
|
||||
interface EnumConstructor<T = Codec> {
|
||||
new(value?: any, index?: number): T;
|
||||
}
|
||||
|
||||
type TypesDef = Record<string, Constructor>;
|
||||
|
||||
interface Decoded {
|
||||
index: number;
|
||||
value: Codec;
|
||||
}
|
||||
|
||||
function extractDef (_def: Record<string, InterfaceTypes | Constructor> | string[]): { def: TypesDef; isBasic: boolean } {
|
||||
if (!Array.isArray(_def)) {
|
||||
const def = mapToTypeMap(_def);
|
||||
const isBasic = !Object.values(def).some((type): boolean => type !== Null);
|
||||
|
||||
return {
|
||||
def,
|
||||
isBasic
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
def: _def.reduce((def, key): TypesDef => {
|
||||
def[key] = Null;
|
||||
|
||||
return def;
|
||||
}, {} as unknown as TypesDef),
|
||||
isBasic: true
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @name Enum
|
||||
* @description
|
||||
* This implements an enum, that based on the value wraps a different type. It is effectively
|
||||
* an extension to enum where the value type is determined by the actual index.
|
||||
*/
|
||||
// TODO:
|
||||
// - As per Enum, actually use TS enum
|
||||
// - It should rather probably extend Enum instead of copying code
|
||||
export default class Enum extends Base<Codec> {
|
||||
private _def: TypesDef;
|
||||
|
||||
private _index: number;
|
||||
|
||||
private _indexes: number[];
|
||||
|
||||
private _isBasic: boolean;
|
||||
|
||||
public constructor (def: Record<string, InterfaceTypes | Constructor> | string[], value?: any, index?: number | Enum) {
|
||||
const defInfo = extractDef(def);
|
||||
const decoded = Enum.decodeEnum(defInfo.def, value, index);
|
||||
|
||||
super(decoded.value);
|
||||
|
||||
this._def = defInfo.def;
|
||||
this._isBasic = defInfo.isBasic;
|
||||
this._indexes = Object.keys(defInfo.def).map((_, index): number => index);
|
||||
this._index = this._indexes.indexOf(decoded.index) || 0;
|
||||
}
|
||||
|
||||
private static decodeEnum (def: TypesDef, value?: any, index?: number | Enum): Decoded {
|
||||
if (value instanceof Enum) {
|
||||
return Enum.createValue(def, value._index, value.raw);
|
||||
} else if (index instanceof Enum) {
|
||||
return Enum.createValue(def, index._index, index.raw);
|
||||
} else if (isNumber(index)) {
|
||||
return Enum.createValue(def, index, value);
|
||||
}
|
||||
|
||||
// Or else, we just look at `value`
|
||||
return Enum.decodeViaValue(def, value);
|
||||
}
|
||||
|
||||
private static decodeViaValue (def: TypesDef, value?: any): Decoded {
|
||||
if (isU8a(value)) {
|
||||
return Enum.createValue(def, value[0], value.subarray(1));
|
||||
} else if (isNumber(value)) {
|
||||
return Enum.createValue(def, value);
|
||||
} else if (isString(value)) {
|
||||
return Enum.decodeViaString(def, value.toString());
|
||||
} else if (isObject(value)) {
|
||||
const key = Object.keys(value)[0];
|
||||
|
||||
return Enum.createViaJSON(def, key, value[key]);
|
||||
}
|
||||
|
||||
// Worst-case scenario, return the first with default
|
||||
return Enum.createValue(def, 0);
|
||||
}
|
||||
|
||||
private static decodeViaString (def: TypesDef, value: string): Decoded {
|
||||
return isHex(value)
|
||||
? Enum.decodeViaValue(def, hexToU8a(value))
|
||||
: Enum.createViaJSON(def, value);
|
||||
}
|
||||
|
||||
private static createViaJSON (def: TypesDef, key: string, value?: any): Decoded {
|
||||
// JSON comes in the form of { "<type (lowercased)>": "<value for type>" }, here we
|
||||
// additionally force to lower to ensure forward compat
|
||||
const keys = Object.keys(def).map((k): string => k.toLowerCase());
|
||||
const keyLower = key.toLowerCase();
|
||||
const index = keys.indexOf(keyLower);
|
||||
|
||||
assert(index !== -1, `Cannot map Enum JSON, unable to find '${key}' in ${keys.join(', ')}`);
|
||||
|
||||
return Enum.createValue(def, index, value);
|
||||
}
|
||||
|
||||
private static createValue (def: TypesDef, index: number = 0, value?: any): Decoded {
|
||||
const Clazz = Object.values(def)[index];
|
||||
|
||||
assert(!isUndefined(Clazz), `Unable to create Enum via index ${index}, in ${Object.keys(def).join(', ')}`);
|
||||
|
||||
return {
|
||||
index,
|
||||
value: new Clazz(value)
|
||||
};
|
||||
}
|
||||
|
||||
public static with (Types: Record<string, InterfaceTypes | Constructor> | string[]): EnumConstructor<Enum> {
|
||||
return class extends Enum {
|
||||
public constructor (value?: any, index?: number) {
|
||||
super(Types, value, index);
|
||||
|
||||
Object.keys(this._def).forEach((_key): void => {
|
||||
const name = stringUpperFirst(stringCamelCase(_key.replace(' ', '_')));
|
||||
const askey = `as${name}`;
|
||||
const iskey = `is${name}`;
|
||||
|
||||
// do not clobber existing properties on the object
|
||||
if (isUndefined((this as any)[iskey])) {
|
||||
Object.defineProperty(this, iskey, {
|
||||
enumerable: true,
|
||||
get: (): boolean => this.type === _key
|
||||
});
|
||||
}
|
||||
|
||||
if (isUndefined((this as any)[askey])) {
|
||||
Object.defineProperty(this, askey, {
|
||||
enumerable: true,
|
||||
get: (): Codec => {
|
||||
assert((this as any)[iskey], `Cannot convert '${this.type}' via ${askey}`);
|
||||
|
||||
return this.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The length of the value when encoded as a Uint8Array
|
||||
*/
|
||||
public get encodedLength (): number {
|
||||
return 1 + this.raw.encodedLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The index of the metadata value
|
||||
*/
|
||||
public get index (): number {
|
||||
return this._index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the Enum points to a [[Null]] type
|
||||
*/
|
||||
public get isNone (): boolean {
|
||||
return this.isNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the Enum points to a [[Null]] type (deprecated, use isNone)
|
||||
*/
|
||||
public get isNull (): boolean {
|
||||
return this.raw instanceof Null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The name of the type this enum value represents
|
||||
*/
|
||||
public get type (): string {
|
||||
return Object.keys(this._def)[this._index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The value of the enum
|
||||
*/
|
||||
public get value (): Codec {
|
||||
return this.raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
public eq (other?: any): boolean {
|
||||
// cater for the case where we only pass the enum index
|
||||
if (isNumber(other)) {
|
||||
return this.toNumber() === other;
|
||||
} else if (this._isBasic && isString(other)) {
|
||||
return this.type === other;
|
||||
}
|
||||
|
||||
// compare the actual wrapper value
|
||||
return this.value.eq(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
public toHex (): string {
|
||||
return u8aToHex(this.toU8a());
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Converts the Object to JSON, typically used for RPC transfers
|
||||
*/
|
||||
public toJSON (): AnyJson {
|
||||
return this._isBasic
|
||||
? this._index
|
||||
: { [this.type]: this.raw.toJSON() };
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the number representation for the value
|
||||
*/
|
||||
public toNumber (): number {
|
||||
return this._index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the base runtime type name for this instance
|
||||
*/
|
||||
public toRawType (): string {
|
||||
const _enum = this._isBasic
|
||||
? Object.keys(this._def)
|
||||
: Struct.typesToMap(this._def);
|
||||
|
||||
return JSON.stringify({ _enum });
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the string representation of the value
|
||||
*/
|
||||
public toString (): string {
|
||||
return this.isNull
|
||||
? this.type
|
||||
: JSON.stringify(this.toJSON());
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Encodes the value as a Uint8Array as per the SCALE specifications
|
||||
* @param isBare true when the value has none of the type-specific prefixes (internal)
|
||||
*/
|
||||
public toU8a (isBare?: boolean): Uint8Array {
|
||||
const index = this._indexes[this._index];
|
||||
|
||||
return u8aConcat(
|
||||
new Uint8Array([index]),
|
||||
this.raw.toU8a(isBare)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
// Copyright 2017-2019 @polkadot/types authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AnyJson, Codec, Constructor, InterfaceTypes } from '../types';
|
||||
|
||||
import { assert, hexToU8a, isHex, isNumber, isObject, isString, isU8a, isUndefined, stringCamelCase, stringUpperFirst, u8aConcat, u8aToHex } from '@polkadot/util';
|
||||
|
||||
import Null from '../primitive/Null';
|
||||
import { mapToTypeMap } from './utils';
|
||||
import Base from './Base';
|
||||
|
||||
interface EnumConstructor<T = Codec> {
|
||||
new(value?: any, index?: number): T;
|
||||
}
|
||||
|
||||
type TypesDef = Record<string, Constructor>;
|
||||
|
||||
interface Decoded {
|
||||
index: number;
|
||||
value: Codec;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name Enum
|
||||
* @description
|
||||
* This implements an enum, that based on the value wraps a different type. It is effectively
|
||||
* an extension to enum where the value type is determined by the actual index.
|
||||
*/
|
||||
// TODO:
|
||||
// - As per Enum, actually use TS enum
|
||||
// - It should rather probably extend Enum instead of copying code
|
||||
export default class Enum extends Base<Codec> {
|
||||
private _def: TypesDef;
|
||||
|
||||
private _index: number;
|
||||
|
||||
private _indexes: number[];
|
||||
|
||||
private _isBasic: boolean;
|
||||
|
||||
public constructor (def: Record<string, InterfaceTypes | Constructor> | string[], value?: any, index?: number | Enum) {
|
||||
const defInfo = Enum.extractDef(def);
|
||||
const decoded = Enum.decodeEnum(defInfo.def, value, index);
|
||||
|
||||
super(decoded.value);
|
||||
|
||||
this._def = defInfo.def;
|
||||
this._isBasic = defInfo.isBasic;
|
||||
this._indexes = Object.keys(defInfo.def).map((_, index): number => index);
|
||||
this._index = this._indexes.indexOf(decoded.index) || 0;
|
||||
}
|
||||
|
||||
private static extractDef (_def: Record<string, InterfaceTypes | Constructor> | string[]): { def: TypesDef; isBasic: boolean } {
|
||||
if (!Array.isArray(_def)) {
|
||||
const def = mapToTypeMap(_def);
|
||||
const isBasic = !Object.values(def).some((type): boolean => type !== Null);
|
||||
|
||||
return {
|
||||
def,
|
||||
isBasic
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
def: _def.reduce((def, key): TypesDef => {
|
||||
def[key] = Null;
|
||||
|
||||
return def;
|
||||
}, {} as unknown as TypesDef),
|
||||
isBasic: true
|
||||
};
|
||||
}
|
||||
|
||||
private static decodeEnum (def: TypesDef, value?: any, index?: number | Enum): Decoded {
|
||||
// If `index` is set, we parse it.
|
||||
if (index instanceof Enum) {
|
||||
return Enum.createValue(def, index._index, index.raw);
|
||||
} else if (isNumber(index)) {
|
||||
return Enum.createValue(def, index, value);
|
||||
}
|
||||
|
||||
// Or else, we just look at `value`
|
||||
return Enum.decodeViaValue(def, value);
|
||||
}
|
||||
|
||||
private static decodeViaValue (def: TypesDef, value?: any): Decoded {
|
||||
if (value instanceof Enum) {
|
||||
return Enum.createValue(def, value._index, value.raw);
|
||||
} else if (isU8a(value)) {
|
||||
return Enum.createValue(def, value[0], value.subarray(1));
|
||||
} else if (isNumber(value)) {
|
||||
return Enum.createValue(def, value);
|
||||
} else if (isString(value)) {
|
||||
const _str = value.toString();
|
||||
|
||||
return isHex(_str)
|
||||
? Enum.decodeViaValue(def, hexToU8a(_str))
|
||||
: Enum.createViaJSON(def, _str);
|
||||
} else if (isObject(value)) {
|
||||
const key = Object.keys(value)[0];
|
||||
|
||||
return Enum.createViaJSON(def, key, value[key]);
|
||||
}
|
||||
|
||||
// Worst-case scenario, return the first with default
|
||||
return Enum.createValue(def, 0);
|
||||
}
|
||||
|
||||
private static createViaJSON (def: TypesDef, key: string, value?: any): Decoded {
|
||||
// JSON comes in the form of { "<type (lowercased)>": "<value for type>" }, here we
|
||||
// additionally force to lower to ensure forward compat
|
||||
const keys = Object.keys(def).map((k): string => k.toLowerCase());
|
||||
const keyLower = key.toLowerCase();
|
||||
const index = keys.indexOf(keyLower);
|
||||
|
||||
assert(index !== -1, `Cannot map Enum JSON, unable to find '${key}' in ${keys.join(', ')}`);
|
||||
|
||||
return Enum.createValue(def, index, value);
|
||||
}
|
||||
|
||||
private static createValue (def: TypesDef, index: number = 0, value?: any): Decoded {
|
||||
const Clazz = Object.values(def)[index];
|
||||
|
||||
assert(!isUndefined(Clazz), `Unable to create Enum via index ${index}, in ${Object.keys(def).join(', ')}`);
|
||||
|
||||
return {
|
||||
index,
|
||||
value: new Clazz(value)
|
||||
};
|
||||
}
|
||||
|
||||
public static with (Types: Record<string, InterfaceTypes | Constructor> | string[]): EnumConstructor<Enum> {
|
||||
return class extends Enum {
|
||||
public constructor (value?: any, index?: number) {
|
||||
super(Types, value, index);
|
||||
|
||||
Object.keys(this._def).forEach((_key): void => {
|
||||
const name = stringUpperFirst(stringCamelCase(_key.replace(' ', '_')));
|
||||
const askey = `as${name}`;
|
||||
const iskey = `is${name}`;
|
||||
|
||||
// do not clobber existing properties on the object
|
||||
if (isUndefined((this as any)[iskey])) {
|
||||
Object.defineProperty(this, iskey, {
|
||||
enumerable: true,
|
||||
get: (): boolean => this.type === _key
|
||||
});
|
||||
}
|
||||
|
||||
if (isUndefined((this as any)[askey])) {
|
||||
Object.defineProperty(this, askey, {
|
||||
enumerable: true,
|
||||
get: (): Codec => {
|
||||
assert((this as any)[iskey], `Cannot convert '${this.type}' via ${askey}`);
|
||||
|
||||
return this.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The length of the value when encoded as a Uint8Array
|
||||
*/
|
||||
public get encodedLength (): number {
|
||||
return 1 + this.raw.encodedLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The index of the metadata value
|
||||
*/
|
||||
public get index (): number {
|
||||
return this._index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the Enum points to a [[Null]] type
|
||||
*/
|
||||
public get isNone (): boolean {
|
||||
return this.isNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the Enum points to a [[Null]] type (deprecated, use isNone)
|
||||
*/
|
||||
public get isNull (): boolean {
|
||||
return this.raw instanceof Null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The name of the type this enum value represents
|
||||
*/
|
||||
public get type (): string {
|
||||
return Object.keys(this._def)[this._index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The value of the enum
|
||||
*/
|
||||
public get value (): Codec {
|
||||
return this.raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
public eq (other?: any): boolean {
|
||||
// cater for the case where we only pass the enum index
|
||||
if (isNumber(other)) {
|
||||
return this.toNumber() === other;
|
||||
} else if (this._isBasic && isString(other)) {
|
||||
return this.type === other;
|
||||
}
|
||||
|
||||
// compare the actual wrapper value
|
||||
return this.value.eq(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
public toHex (): string {
|
||||
return u8aToHex(this.toU8a());
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Converts the Object to JSON, typically used for RPC transfers
|
||||
*/
|
||||
public toJSON (): AnyJson {
|
||||
return this._isBasic
|
||||
? this._index
|
||||
: { [this.type]: this.raw.toJSON() };
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the number representation for the value
|
||||
*/
|
||||
public toNumber (): number {
|
||||
return this._index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the base runtime type name for this instance
|
||||
*/
|
||||
public toRawType (): string {
|
||||
const _enum = this._isBasic
|
||||
? Object.keys(this._def)
|
||||
: Object.entries(this._def).reduce((result, [key, Type]): Record<string, string> => {
|
||||
result[key] = new Type().toRawType();
|
||||
|
||||
return result;
|
||||
}, {} as unknown as Record<string, string>);
|
||||
|
||||
return JSON.stringify({ _enum });
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the string representation of the value
|
||||
*/
|
||||
public toString (): string {
|
||||
return this.isNull
|
||||
? this.type
|
||||
: JSON.stringify(this.toJSON());
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Encodes the value as a Uint8Array as per the SCALE specifications
|
||||
* @param isBare true when the value has none of the type-specific prefixes (internal)
|
||||
*/
|
||||
public toU8a (isBare?: boolean): Uint8Array {
|
||||
const index = this._indexes[this._index];
|
||||
|
||||
return u8aConcat(
|
||||
new Uint8Array([index]),
|
||||
this.raw.toU8a(isBare)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -40,14 +40,18 @@ export default class Option<T extends Codec> extends Base<T> {
|
||||
} else if (isU8a(value)) {
|
||||
// the isU8a check happens last in the if-tree - since the wrapped value
|
||||
// may be an instance of it, so Type and Option checks go in first
|
||||
return !value.length || value[0] === 0
|
||||
? new Null()
|
||||
: new Type(value.subarray(1));
|
||||
return Option.decodeOptionU8a(Type, value);
|
||||
}
|
||||
|
||||
return new Type(value);
|
||||
}
|
||||
|
||||
private static decodeOptionU8a (Type: Constructor, value: Uint8Array): Codec {
|
||||
return !value.length || value[0] === 0
|
||||
? new Null()
|
||||
: new Type(value.subarray(1));
|
||||
}
|
||||
|
||||
public static with<O extends Codec> (Type: Constructor | InterfaceTypes): Constructor<Option<O>> {
|
||||
return class extends Option<O> {
|
||||
public constructor (value?: any) {
|
||||
|
||||
@@ -234,16 +234,20 @@ export default class Struct<
|
||||
}, {} as any);
|
||||
}
|
||||
|
||||
public static typesToMap (Types: Record<string, Constructor>): Record<string, string> {
|
||||
return Object.entries(Types).reduce((result, [key, Type]): Record<string, string> => {
|
||||
result[key] = new Type().toRawType();
|
||||
|
||||
return result;
|
||||
}, {} as unknown as Record<string, string>);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the base runtime type name for this instance
|
||||
*/
|
||||
public toRawType (): string {
|
||||
return JSON.stringify(
|
||||
Object.entries(this._Types).reduce((result, [key, Type]): Record<string, string> => {
|
||||
result[key] = new Type().toRawType();
|
||||
|
||||
return result;
|
||||
}, {} as unknown as Record<string, string>)
|
||||
Struct.typesToMap(this._Types)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
export { default as Compact } from './Compact';
|
||||
// export { default as Date } from './Date';
|
||||
export { default as Enum } from './Enum';
|
||||
export { default as EnumType } from './EnumType';
|
||||
export { default as Option } from './Option';
|
||||
export { default as Set } from './Set';
|
||||
export { default as Struct } from './Struct';
|
||||
|
||||
@@ -13,15 +13,17 @@ function hasMismatch (a?: any, b?: any): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function notEntry (value: any): boolean {
|
||||
return !Array.isArray(value) || value.length !== 2;
|
||||
}
|
||||
|
||||
// NOTE These are used internally and when comparing objects, expects that
|
||||
// when the second is an Map<string, Codec> that the first has to be as well
|
||||
export default function compareMap (a: Map<any, any>, b?: any): boolean {
|
||||
if (Array.isArray(b)) {
|
||||
// equal number of entries and each entry in the array should match
|
||||
return (a.size === b.length) && !b.some((entry): boolean =>
|
||||
!Array.isArray(entry) ||
|
||||
entry.length !== 2 ||
|
||||
hasMismatch(a.get(entry[0]), entry[1])
|
||||
notEntry(entry) || hasMismatch(a.get(entry[0]), entry[1])
|
||||
);
|
||||
} else if (b instanceof Map) {
|
||||
return compareMap(a, [...b.entries()]);
|
||||
|
||||
@@ -15,14 +15,14 @@ export default {
|
||||
}
|
||||
},
|
||||
RawBabePreDigestPrimary: {
|
||||
authorityIndex: 'u32', // AuthorityIndex (also in aura, not same size there)
|
||||
authorityIndex: 'u32', // AuthorityIndex (also in aura)
|
||||
slotNumber: 'SlotNumber',
|
||||
weight: 'BabeBlockWeight',
|
||||
vrfOutput: 'H256', // should be '[u8; 32]' (generator support lacking here)
|
||||
vrfProof: 'H256' // should be '[u8; 32]'
|
||||
},
|
||||
RawBabePreDigestSecondary: {
|
||||
authorityIndex: 'u32', // AuthorityIndex (also in aura, not same size there)
|
||||
authorityIndex: 'u32', // AuthorityIndex (also in aura)
|
||||
slotNumber: 'SlotNumber',
|
||||
weight: 'BabeBlockWeight'
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user