Intelligent constructor (Part 3) (#294)
* Fix Metadata * Fix metadata * Use constructor type * Fix EnumType * Fix EnumType * Fix Tuple * Remove some froms * Fix Struct * Fix Bft test * Remove some froms * Small fixes * Fix EnumType * Add blank lines * Struct allow jsonKey or without * Add hack * Update hack test * Revert some stuff * Revert to from again * Fix tests
This commit is contained in:
committed by
Jaco Greeff
parent
b0d70b0435
commit
8de9ea8878
@@ -21,7 +21,7 @@ const createRuntimeFunction = (method: string, key: string, { documentation, typ
|
||||
{
|
||||
documentation: new Vector(Text, [documentation]),
|
||||
modifier: new StorageFunctionModifier().fromJSON(0),
|
||||
type: new StorageFunctionType(0, type),
|
||||
type: new StorageFunctionType(type, 0),
|
||||
toJSON: (): any =>
|
||||
key
|
||||
} as StorageFunctionMetadata,
|
||||
|
||||
@@ -36,7 +36,7 @@ describe('BftHashSignature', () => {
|
||||
|
||||
describe('Justification', () => {
|
||||
const just = new Justification({
|
||||
round: 32,
|
||||
round: 32, // We get `round_number` from JSON, but both `round` and `round_number` works
|
||||
hash: '0xabcd',
|
||||
signatures: [
|
||||
{ authorityId: '0x1234', signature: '0x5678' },
|
||||
|
||||
@@ -21,12 +21,12 @@ export class Usurped extends Hash {
|
||||
}
|
||||
|
||||
export default class ExtrinsicStatus extends EnumType<Finalised | Usurped | Broadcast | Dropped> {
|
||||
constructor (index?: number) {
|
||||
constructor (value: any, index?: number) {
|
||||
super([
|
||||
Finalised,
|
||||
Usurped,
|
||||
Broadcast,
|
||||
Dropped
|
||||
], index);
|
||||
], value, index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
import { AnyNumber } from './types';
|
||||
|
||||
import hexToU8a from '@polkadot/util/hex/toU8a';
|
||||
import isHex from '@polkadot/util/is/hex';
|
||||
import isU8a from '@polkadot/util/is/u8a';
|
||||
import toU8a from '@polkadot/util/u8a/toU8a';
|
||||
|
||||
import Base from './codec/Base';
|
||||
@@ -219,11 +222,11 @@ export class StorageFunctionType$Map extends Struct {
|
||||
}
|
||||
|
||||
export class StorageFunctionType extends EnumType<Type | StorageFunctionType$Map> {
|
||||
constructor (index?: number, value?: any) {
|
||||
constructor (value?: any, index?: number) {
|
||||
super([
|
||||
Type,
|
||||
StorageFunctionType$Map
|
||||
], index, value);
|
||||
], value, index);
|
||||
}
|
||||
|
||||
get isMap (): boolean {
|
||||
@@ -324,7 +327,27 @@ export default class RuntimeMetadata extends Struct {
|
||||
outerEvent: OuterEventMetadata,
|
||||
modules: Vector.with(RuntimeModuleMetadata),
|
||||
outerDispatch: OuterDispatchMetadata
|
||||
}, value);
|
||||
}, RuntimeMetadata.decodeMetadata(value));
|
||||
}
|
||||
|
||||
static decodeMetadata (value: any): object | Uint8Array {
|
||||
if (isHex(value)) {
|
||||
return RuntimeMetadata.decodeMetadata(hexToU8a(value));
|
||||
} else if (isU8a(value)) {
|
||||
// HACK 13 Oct 2018 - For current running BBQ nodes, Metadata is not properly
|
||||
// encoded, it does not have a length prefix. For latest substrate master, it
|
||||
// is properly encoded. Here we pull the prefix, check it agianst the length -
|
||||
// if matches, then we have the length, otherwise we assume it is an older node
|
||||
// and use the whole buffer
|
||||
const [offset, length] = Compact.decodeU8a(value, DEFAULT_LENGTH_BITS);
|
||||
|
||||
return value.length === (offset + length.toNumber())
|
||||
? value.subarray(offset)
|
||||
: value;
|
||||
}
|
||||
|
||||
// Decode as normal struct
|
||||
return value;
|
||||
}
|
||||
|
||||
// We receive this as an Array<number> in the JSON output from the Node. Convert
|
||||
|
||||
@@ -55,11 +55,11 @@ export class BftDoubleCommit extends BftAtReport {
|
||||
}
|
||||
|
||||
export class MisbehaviorKind extends EnumType<BftDoublePrepare | BftDoubleCommit> {
|
||||
constructor (index: number = 0x11, value?: BftAtReportValue) {
|
||||
constructor (value?: BftAtReportValue, index?: number) {
|
||||
super({
|
||||
0x11: BftDoublePrepare,
|
||||
0x12: BftDoubleCommit
|
||||
}, index, value);
|
||||
}, value, index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,8 +73,8 @@ export default class MisbehaviorReport extends Struct {
|
||||
constructor (value?: MisbehaviorReportValue) {
|
||||
super({
|
||||
parentHash: Hash,
|
||||
parentNumber: BlockNumber,
|
||||
target: AuthorityId,
|
||||
parentNumber: BlockNumber,
|
||||
target: AuthorityId,
|
||||
misbehavior: MisbehaviorKind
|
||||
}, value);
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ describe('Compact', () => {
|
||||
|
||||
it('has the correct byteLength for constructor values (default)', () => {
|
||||
expect(
|
||||
new Compact(0xfffffff9).byteLength()
|
||||
new Compact(0xfffffff9, 64).byteLength()
|
||||
).toEqual(9);
|
||||
});
|
||||
|
||||
@@ -107,4 +107,10 @@ describe('Compact', () => {
|
||||
new Compact().fromU8a(new Uint8Array([254, 255, 3, 0])).raw
|
||||
).toEqual(new BN(0xffff));
|
||||
});
|
||||
|
||||
it('correctly adds the length prefix', () => {
|
||||
expect(
|
||||
Compact.addLengthPrefix(Uint8Array.from([12, 13]))
|
||||
).toEqual(Uint8Array.from([2 << 2, 12, 13]));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
import BN from 'bn.js';
|
||||
import bnToBn from '@polkadot/util/bn/toBn';
|
||||
import bnToU8a from '@polkadot/util/bn/toU8a';
|
||||
import isU8a from '@polkadot/util/is/u8a';
|
||||
import u8aConcat from '@polkadot/util/u8a/concat';
|
||||
import u8aToBn from '@polkadot/util/u8a/toBn';
|
||||
import toU8a from '@polkadot/util/u8a/toU8a';
|
||||
|
||||
import { AnyNumber, AnyU8a } from '../types';
|
||||
import UInt, { UIntBitLength } from './UInt';
|
||||
|
||||
export const DEFAULT_LENGTH_BITS = 32;
|
||||
@@ -33,6 +35,31 @@ const MAX_U32 = new BN(2).pow(new BN(32 - 2)).subn(1);
|
||||
//
|
||||
// Note: we use *LOW BITS* of the LSB in LE encoding to encode the 2 bit key.
|
||||
export default class Compact extends UInt {
|
||||
constructor (value?: AnyU8a | AnyNumber, bitLength: UIntBitLength = DEFAULT_LENGTH_BITS, isHexJson: boolean = false) {
|
||||
super(Compact.decodeCompact(value, bitLength), bitLength, isHexJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend a Uint8Array with its compact length.
|
||||
*
|
||||
* @param u8a - The Uint8Array to be prefixed
|
||||
*/
|
||||
static addLengthPrefix (u8a: Uint8Array, bitLength: UIntBitLength = DEFAULT_LENGTH_BITS): Uint8Array {
|
||||
return u8aConcat(
|
||||
Compact.encodeU8a(u8a.length, bitLength),
|
||||
u8a
|
||||
);
|
||||
}
|
||||
|
||||
static decodeCompact (value: AnyU8a | AnyNumber | undefined, bitLength: UIntBitLength): any {
|
||||
if (isU8a(value)) {
|
||||
const [, length] = Compact.decodeU8a(value, bitLength);
|
||||
|
||||
return length;
|
||||
}
|
||||
return value as any;
|
||||
}
|
||||
|
||||
static decodeU8a (_input: Uint8Array | string, bitLength: UIntBitLength): [number, BN] {
|
||||
const input = toU8a(_input);
|
||||
const flag = input[0] & 0b11;
|
||||
@@ -50,18 +77,6 @@ export default class Compact extends UInt {
|
||||
return [byteLength + 1, u8aToBn(input.subarray(1, 1 + byteLength), true)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend a Uint8Array with its compact length.
|
||||
*
|
||||
* @param u8a - The Uint8Array to be prefixed
|
||||
*/
|
||||
static addLengthPrefix (u8a: Uint8Array): Uint8Array {
|
||||
return u8aConcat(
|
||||
Compact.encodeU8a(u8a.length, DEFAULT_LENGTH_BITS),
|
||||
u8a
|
||||
);
|
||||
}
|
||||
|
||||
static encodeU8a (_value: UInt | BN | number, bitLength: UIntBitLength): Uint8Array {
|
||||
const value = _value instanceof UInt
|
||||
? _value.toBn()
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import isNumber from '@polkadot/util/is/number';
|
||||
import isObject from '@polkadot/util/is/object';
|
||||
import isU8a from '@polkadot/util/is/u8a';
|
||||
import isUndefined from '@polkadot/util/is/undefined';
|
||||
|
||||
import Base from './Base';
|
||||
import { Constructor } from '../types';
|
||||
|
||||
type TypesArray = Array<{ new(value?: any): Base }>;
|
||||
type TypesArray = Array<Constructor<Base>>;
|
||||
type TypesDef = {
|
||||
[index: number]: { new(value?: any): Base }
|
||||
[index: number]: Constructor<Base>
|
||||
} | TypesArray;
|
||||
|
||||
// This implements an enum, that based on the value wraps a different type. It is effectively an
|
||||
@@ -18,14 +22,16 @@ type TypesDef = {
|
||||
// - As per Enum, actually use TS enum
|
||||
// - It should rather probably extend Enum instead of copying code
|
||||
// - There doesn't actually seem to be a way to get to the actual determined/wrapped value
|
||||
export default class EnumType <T> extends Base<Base<T>> {
|
||||
export default class EnumType<T> extends Base<Base<T>> {
|
||||
private _Types: TypesArray;
|
||||
private _index: number;
|
||||
private _indexes: Array<number>;
|
||||
|
||||
constructor (def: TypesDef, index?: number | EnumType<T>, value?: any) {
|
||||
constructor (def: TypesDef, value?: any, index?: number | EnumType<T>) {
|
||||
const decoded = EnumType.decodeEnumType(def, value, index);
|
||||
|
||||
super(
|
||||
new (Object.values(def)[0])()
|
||||
decoded.value
|
||||
);
|
||||
|
||||
this._Types = Array.isArray(def)
|
||||
@@ -34,9 +40,42 @@ export default class EnumType <T> extends Base<Base<T>> {
|
||||
this._indexes = Object.keys(def).map((index) =>
|
||||
parseInt(index, 10)
|
||||
);
|
||||
this._index = this._indexes[0];
|
||||
|
||||
this.setValue(index, value);
|
||||
this._index = this._indexes.indexOf(decoded.index) || 0;
|
||||
}
|
||||
|
||||
static decodeEnumType<T> (def: TypesDef, value?: any, index?: number | EnumType<T>): { index: number, value: any } {
|
||||
// If `index` is set, we parse it.
|
||||
if (index instanceof EnumType) {
|
||||
return { index: index._index, value: new def[index._index](index.raw) };
|
||||
}
|
||||
if (isNumber(index)) {
|
||||
return { index, value: new def[index](value) };
|
||||
}
|
||||
|
||||
// Or else, we just look at `value`
|
||||
if (isU8a(value)) {
|
||||
return { index: value[0], value: new def[value[0]](value.subarray(1)) };
|
||||
} else if (isNumber(value) && !isUndefined(def[value])) {
|
||||
return { index: value, value: new def[value]() };
|
||||
} else if (isObject(value)) {
|
||||
// JSON comes in the form of { "<type (lowercased)>": "<value for type>" }, here we
|
||||
// additionally force to lower to ensure forward compat
|
||||
const key = Object.keys(value)[0];
|
||||
const lowerKey = key.toLowerCase();
|
||||
const index = Object
|
||||
.keys(def)
|
||||
.find((k) => def[+k].name.toLowerCase() === lowerKey);
|
||||
|
||||
if (isUndefined(index)) {
|
||||
throw new Error('Unable to reliably map input on JSON');
|
||||
}
|
||||
|
||||
return { index: +index, value: new def[+index](value[key]) };
|
||||
}
|
||||
|
||||
// Worst-case scenario, return this
|
||||
return { index: 0, value: new (Object.values(def)[0])() };
|
||||
}
|
||||
|
||||
get type (): string {
|
||||
|
||||
@@ -7,6 +7,8 @@ import isU8a from '@polkadot/util/is/u8a';
|
||||
import isUndefined from '@polkadot/util/is/undefined';
|
||||
|
||||
import Base from './Base';
|
||||
import { Constructor } from '../types';
|
||||
import Null from '../Null';
|
||||
|
||||
// An Option is an optional field. Basically the first byte indicates that there is
|
||||
// is value to follow. If the byte is `1` there is an actual value. So the Option
|
||||
@@ -15,7 +17,7 @@ import Base from './Base';
|
||||
export default class Option<T> extends Base<Base<T>> {
|
||||
private _isEmpty: boolean;
|
||||
|
||||
constructor (Type: { new(value?: any): Base<T> }, value?: any) {
|
||||
constructor (Type: Constructor<Base<T>>, value?: any) {
|
||||
super(
|
||||
Option.decodeOption(Type, value)
|
||||
);
|
||||
@@ -23,8 +25,12 @@ export default class Option<T> extends Base<Base<T>> {
|
||||
this._isEmpty = isNull(value) || isUndefined(value);
|
||||
}
|
||||
|
||||
static decodeOption<O> (Type: { new(value?: any): Base<O> }, value?: any): Base<O> {
|
||||
static decodeOption<O> (Type: Constructor<Base<O>>, value?: any): Base {
|
||||
if (isU8a(value)) {
|
||||
if (value[0] === 0) {
|
||||
return new Null();
|
||||
}
|
||||
|
||||
return new Type(value.subarray(1));
|
||||
}
|
||||
|
||||
@@ -32,10 +38,10 @@ export default class Option<T> extends Base<Base<T>> {
|
||||
isNull(value) || isUndefined(value)
|
||||
? undefined
|
||||
: value
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
static with<O> (Type: { new(value?: any): Base<O> }): { new(value?: any): Option<O> } {
|
||||
static with<O> (Type: Constructor<Base<O>>): Constructor<Option<O>> {
|
||||
return class extends Option<O> {
|
||||
constructor (value?: any) {
|
||||
super(Type, value);
|
||||
|
||||
@@ -7,9 +7,10 @@ import isHex from '@polkadot/util/is/hex';
|
||||
import isObject from '@polkadot/util/is/object';
|
||||
import isU8a from '@polkadot/util/is/u8a';
|
||||
import u8aConcat from '@polkadot/util/u8a/concat';
|
||||
import u8aToU8a from '@polkadot/util/u8a/toU8a';
|
||||
import toU8a from '@polkadot/util/u8a/toU8a';
|
||||
|
||||
import Base from './Base';
|
||||
import { Constructor } from '../types';
|
||||
|
||||
// A Struct defines an Object with key/values - where the values are Base<T> values. It removes
|
||||
// a lot of repetition from the actual coding, define a structure type, pass it the key/Base<T>
|
||||
@@ -18,7 +19,7 @@ import Base from './Base';
|
||||
// it needs to decoded in the specific defined order.
|
||||
export default class Struct<
|
||||
// The actual Class structure, i.e. key -> Class
|
||||
S = { [index: string]: { new(...value: Array<any>): Base } },
|
||||
S = { [index: string]: Constructor<Base> },
|
||||
// internal type, instance of classes mapped by key
|
||||
T = { [K in keyof S]: Base },
|
||||
// input values, mapped by key can be anything (construction)
|
||||
@@ -31,7 +32,7 @@ export default class Struct<
|
||||
|
||||
constructor (Types: S, value: V | Array<any> = {} as V, jsonMap: Map<keyof S, string> = new Map()) {
|
||||
super(
|
||||
Struct.decodeStruct(Types, value)
|
||||
Struct.decodeStruct(Types, value, jsonMap)
|
||||
);
|
||||
|
||||
this._jsonMap = jsonMap;
|
||||
@@ -45,11 +46,13 @@ export default class Struct<
|
||||
}, {} as E);
|
||||
}
|
||||
|
||||
static decodeStruct<S, V, T> (Types: S, value: any): T {
|
||||
static decodeStruct<S, V, T> (Types: S, value: any, jsonMap: Map<keyof S, string>): T {
|
||||
// l.debug(() => ['Struct.decode', { Types, value }]);
|
||||
|
||||
if (isHex(value)) {
|
||||
return Struct.decodeStruct(Types, hexToU8a(value as string));
|
||||
return Struct.decodeStruct(Types, hexToU8a(value as string), jsonMap);
|
||||
} else if (Array.isArray(value)) {
|
||||
return Struct.decodeStruct(Types, toU8a(value), jsonMap);
|
||||
} else if (!value) {
|
||||
return {} as T;
|
||||
}
|
||||
@@ -61,6 +64,10 @@ export default class Struct<
|
||||
return Object
|
||||
.keys(Types)
|
||||
.reduce((raw: T, key) => {
|
||||
// The key in the JSON can be snake_case (or other cases), but in our
|
||||
// Types, result or any other maps, it's camelCase
|
||||
const jsonKey = (jsonMap.get(key as any) && !value[key]) ? jsonMap.get(key as any) : key;
|
||||
|
||||
if (isU8a(value)) {
|
||||
// @ts-ignore FIXME See below
|
||||
raw[key] = new Types[key](
|
||||
@@ -72,11 +79,10 @@ export default class Struct<
|
||||
// Move the currentIndex forward
|
||||
// @ts-ignore FIXME See below
|
||||
currentIndex += raw[key].byteLength();
|
||||
|
||||
// @ts-ignore FIXME See below
|
||||
} else if (value[key] instanceof Types[key]) {
|
||||
} else if (value[jsonKey] instanceof Types[key]) {
|
||||
// @ts-ignore FIXME See below
|
||||
raw[key] = value[key];
|
||||
raw[key] = value[jsonKey];
|
||||
} else if (isObject(value)) {
|
||||
// @ts-ignore FIXME Ok, something weird is going on here or I just don't get it...
|
||||
// it works, so ignore the checker, although it drives me batty. (It started when
|
||||
@@ -84,7 +90,7 @@ export default class Struct<
|
||||
// does backfire here, but works externally.)
|
||||
raw[key] = new Types[key](
|
||||
// @ts-ignore FIXME
|
||||
value[key]
|
||||
value[jsonKey]
|
||||
);
|
||||
} else {
|
||||
// @ts-ignore FIXME
|
||||
@@ -96,8 +102,8 @@ export default class Struct<
|
||||
}
|
||||
|
||||
static with<
|
||||
S = { [index: string]: { new(value?: any): Base } }
|
||||
> (Types: S): { new(value?: any): Struct<S> } {
|
||||
S = { [index: string]: Constructor<Base> }
|
||||
> (Types: S): Constructor<Struct<S>> {
|
||||
return class extends Struct<S> {
|
||||
constructor (value?: any, jsonMap?: Map<keyof S, string>) {
|
||||
super(Types, value, jsonMap);
|
||||
@@ -117,7 +123,7 @@ export default class Struct<
|
||||
|
||||
fromJSON (input: any): Struct<S, T, V, E> {
|
||||
if (isHex(input) || isU8a(input)) {
|
||||
return this.fromU8a(u8aToU8a(input));
|
||||
return this.fromU8a(toU8a(input));
|
||||
}
|
||||
|
||||
// null & undefined yields empty
|
||||
|
||||
@@ -34,6 +34,25 @@ describe('Tuple', () => {
|
||||
});
|
||||
|
||||
it('initialises via JSON array', () => {
|
||||
const test = new (Tuple.with({
|
||||
a: Text,
|
||||
b: U32,
|
||||
c: Text
|
||||
}))([
|
||||
'bazzing', 32
|
||||
]);
|
||||
|
||||
expect(
|
||||
test.toJSON()
|
||||
).toEqual([
|
||||
'bazzing',
|
||||
32,
|
||||
''
|
||||
]);
|
||||
});
|
||||
|
||||
// FIXME Remove fromJSON
|
||||
it('fromJSON still works', () => {
|
||||
const test = new (Tuple.with({
|
||||
a: Text,
|
||||
b: U32,
|
||||
|
||||
@@ -2,14 +2,10 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { AnyU8a } from '../types';
|
||||
|
||||
import hexToU8a from '@polkadot/util/hex/toU8a';
|
||||
import isHex from '@polkadot/util/is/hex';
|
||||
import isString from '@polkadot/util/is/string';
|
||||
import isU8a from '@polkadot/util/is/u8a';
|
||||
import toU8a from '@polkadot/util/u8a/toU8a';
|
||||
|
||||
import { AnyU8a, Constructor } from '../types';
|
||||
import Base from './Base';
|
||||
import Struct from './Struct';
|
||||
|
||||
@@ -18,7 +14,7 @@ import Struct from './Struct';
|
||||
// while the U8a encoding is handled in the same way as a Struct
|
||||
export default class Tuple<
|
||||
// S & T definitions maps to what we have in Struct (naming documented there)
|
||||
S = { [index: string]: { new(value?: any): Base } },
|
||||
S = { [index: string]: Constructor<Base> },
|
||||
T = { [K in keyof S]: Base },
|
||||
V = { [K in keyof S]: any }
|
||||
> extends Struct<S, T, V> {
|
||||
@@ -26,30 +22,25 @@ export default class Tuple<
|
||||
super(Types, Tuple.decodeTuple(Types, value), jsonMap);
|
||||
}
|
||||
|
||||
static decodeTuple<S, V> (Types: S, _value: V | AnyU8a): V {
|
||||
if (!isU8a(_value) && !isString(_value) && !Array.isArray(_value)) {
|
||||
return _value as V;
|
||||
static decodeTuple<S, V> (Types: S, value: V | AnyU8a): V {
|
||||
// If the input is an array, we convert it to a map
|
||||
if (Array.isArray(value)) {
|
||||
return Object
|
||||
.keys(Types)
|
||||
.reduce((result, key, index) => {
|
||||
// @ts-ignore FIXME these types are a headache
|
||||
result[key] = value[index];
|
||||
return result;
|
||||
}, {} as V);
|
||||
}
|
||||
|
||||
const value = toU8a(_value);
|
||||
let offset = 0;
|
||||
|
||||
return Object
|
||||
.keys(Types)
|
||||
.reduce((result: V, key) => {
|
||||
// @ts-ignore
|
||||
result[key] = new Types[key]().fromU8a(value.subarray(offset));
|
||||
|
||||
// @ts-ignore
|
||||
offset += result[key].byteLength();
|
||||
|
||||
return result;
|
||||
}, {} as V);
|
||||
// Or else, just decode like a normal Struct
|
||||
return value as V;
|
||||
}
|
||||
|
||||
static with<
|
||||
S = { [index: string]: { new(value?: any): Base } }
|
||||
> (Types: S): { new(value?: any): Tuple<S> } {
|
||||
S = { [index: string]: Constructor<Base> }
|
||||
> (Types: S): Constructor<Tuple<S>> {
|
||||
return class extends Tuple<S> {
|
||||
constructor (value?: any) {
|
||||
super(Types, value);
|
||||
|
||||
@@ -13,7 +13,7 @@ describe('Vector', () => {
|
||||
let array;
|
||||
|
||||
beforeEach(() => {
|
||||
array = new Vector(Text, [ '1', '23', '345', '4567', new Text('56789') ]);
|
||||
array = new Vector(Text, ['1', '23', '345', '4567', new Text('56789')]);
|
||||
|
||||
Method.injectExtrinsics(extrinsics);
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import toU8a from '@polkadot/util/u8a/toU8a';
|
||||
|
||||
import Base from './Base';
|
||||
import Compact, { DEFAULT_LENGTH_BITS } from './Compact';
|
||||
import { Constructor } from '../types';
|
||||
|
||||
// This manages codec arrays. Intrernally it keeps track of the length (as decoded) and allows
|
||||
// construction with the passed `Type` in the constructor. It aims to be an array-like structure,
|
||||
@@ -16,9 +17,9 @@ import Compact, { DEFAULT_LENGTH_BITS } from './Compact';
|
||||
export default class Vector<
|
||||
T extends Base
|
||||
> extends Base<Array<T>> {
|
||||
private _Type: { new(value?: any): T };
|
||||
private _Type: Constructor<T>;
|
||||
|
||||
constructor (Type: { new(value?: any): T }, value: Uint8Array | string | Array<any> = [] as Array<any>) {
|
||||
constructor (Type: Constructor<T>, value: Uint8Array | string | Array<any> = [] as Array<any>) {
|
||||
super(
|
||||
Vector.decode(Type, value)
|
||||
);
|
||||
@@ -26,7 +27,7 @@ export default class Vector<
|
||||
this._Type = Type;
|
||||
}
|
||||
|
||||
static decode<T> (Type: { new(value?: any): T }, value: Uint8Array | string | Array<any>): Array<T> {
|
||||
static decode<T extends Base> (Type: Constructor<T>, value: Uint8Array | string | Array<any>): Array<T> {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((entry) =>
|
||||
entry instanceof Type
|
||||
@@ -55,7 +56,7 @@ export default class Vector<
|
||||
return result;
|
||||
}
|
||||
|
||||
static with<O extends Base> (Type: { new(value?: any): O }): { new(value?: any): Vector<O> } {
|
||||
static with<O extends Base> (Type: Constructor<O>): Constructor<Vector<O>> {
|
||||
return class extends Vector<O> {
|
||||
constructor (value?: Array<any>) {
|
||||
super(Type, value);
|
||||
|
||||
Vendored
+2
@@ -12,3 +12,5 @@ export type AnyNumber = UInt | BN | Uint8Array | number | string;
|
||||
export type AnyU8a = U8a | Uint8Array | Array<number> | string;
|
||||
|
||||
export type CodecTypes = keyof typeof Classes;
|
||||
|
||||
export type Constructor<T> = { new(value?: any): T };
|
||||
|
||||
Reference in New Issue
Block a user