Add Types from RPC (and more tests) (#165)

* Tests for Array for proper coverage

* Expand tests

* Add PropIndex :(

* Add RawAddress

* Index -> Nonce

* Disable test for alias code (commented)

* Block & Extrinsic (base)

* String -> Text, Array -> Vector

* Remove Codec* prefixes

* Unsigned -> Long

* import renames

* Values for structures

* Export classes from Metadata

* Long -> UInt

* Alias vec<u8> -> Bytes
This commit is contained in:
Jaco Greeff
2018-09-25 18:22:25 +02:00
committed by GitHub
parent b13486f9ab
commit 964bf84b83
39 changed files with 588 additions and 291 deletions
+6 -6
View File
@@ -9,16 +9,16 @@ import isHex from '@polkadot/util/is/hex';
import isU8a from '@polkadot/util/is/u8a';
import u8aToU8a from '@polkadot/util/u8a/toU8a';
import CodecU8a from './codec/U8a';
import CodecU8aFixed from './codec/U8aFixed';
import U8a from './codec/U8a';
import U8aFixed from './codec/U8aFixed';
// A wrapper around an AccountId/PublicKey representation. Since we are dealing with
// underlying PublicKeys (32 bytes in length), we extend from CodecU8aFixed which is
// underlying PublicKeys (32 bytes in length), we extend from U8aFixed which is
// basically just a Uint8Array wrapper with a fixed length.
export default class AccountId extends CodecU8aFixed {
constructor (value: CodecU8a | string | Uint8Array = new Uint8Array()) {
export default class AccountId extends U8aFixed {
constructor (value: U8a | string | Uint8Array = new Uint8Array()) {
super(
value instanceof CodecU8a
value instanceof U8a
? value.raw
: AccountId.decode(value),
256
+6 -15
View File
@@ -2,21 +2,18 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import hexToU8a from '@polkadot/util/hex/toU8a';
import isHex from '@polkadot/util/is/hex';
import isU8a from '@polkadot/util/is/u8a';
import u8aToHex from '@polkadot/util/u8a/toHex';
import u8aToU8a from '@polkadot/util/u8a/toU8a';
import CodecU8a from './codec/U8a';
import U8a from './codec/U8a';
// A wrapper around an AccountIndex, which is a shortened, variable-length encoding
// for an Account. We extends from CodecU8a which is basically
// for an Account. We extends from U8a which is basically
// just a Uint8Array wrapper.
export default class AccountIndex extends CodecU8a {
constructor (value: CodecU8a | string | Uint8Array = new Uint8Array()) {
export default class AccountIndex extends U8a {
constructor (value: U8a | string | Uint8Array = new Uint8Array()) {
super(
value instanceof CodecU8a
value instanceof U8a
? value.raw
: AccountIndex.decode(value)
);
@@ -29,13 +26,7 @@ export default class AccountIndex extends CodecU8a {
}
static decode (value: string | Uint8Array | Array<number>): Uint8Array {
if (isU8a(value) || Array.isArray(value)) {
return u8aToU8a(value);
} else if (isHex(value)) {
return hexToU8a(value);
}
throw new Error(`Unable to decode AccountIndex for [${value.toString()}]`);
return u8aToU8a(value);
}
fromJSON (input: any): AccountIndex {
+2 -2
View File
@@ -7,7 +7,7 @@ import isU8a from '@polkadot/util/is/u8a';
import u8aConcat from '@polkadot/util/u8a/concat';
import u8aToU8a from '@polkadot/util/u8a/toU8a';
import CodecBase from './codec/Base';
import Base from './codec/Base';
import AccountId from './AccountId';
import AccountIndex from './AccountIndex';
@@ -16,7 +16,7 @@ import AccountIndex from './AccountIndex';
// we extend from Base with an AccountId/AccountIndex wrapper. Basically the Address
// is encoded as
// [ <prefix-byte>, ...publicKey/...bytes ]
export default class Address extends CodecBase<AccountId | AccountIndex> {
export default class Address extends Base<AccountId | AccountIndex> {
constructor (value: Address | AccountId | AccountIndex | string | Uint8Array = new Uint8Array()) {
super(
value instanceof Address
+51
View File
@@ -0,0 +1,51 @@
// Copyright 2017-2018 @polkadot/api-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import hexToU8a from '@polkadot/util/hex/toU8a';
import Block from './Block';
describe('Block', () => {
it('decodes a block properly', () => {
const block = new Block();
block.fromU8a(hexToU8a(
'0x' +
// parent_hash
'0900000000000000000000000000000000000000000000000000000000000009' +
// number
'4300000000000000' +
// state_root
'0800000000000000000000000000000000000000000000000000000000000008' +
// transaction_root
'0700000000000000000000000000000000000000000000000000000000000007' +
// digest
'08' + // 2 << 2
'0401' +
'0402' +
// transactions
'04' + // 1 << 2
// 111 bytes in compact encoding
'bd01' +
// prefix
'ff' +
'0000000000000000000000000000000000000000000000000000000000000000' +
'00000000' +
'0300' +
'7527000000000000' +
'0000000000000000000000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000000'
));
expect(
block.header.blockNumber.toNumber()
).toEqual(67);
expect(
block.extrinsics.length
).toEqual(1); // eslint-disable-line
expect(
block.extrinsics.at(0).length
).toEqual(111); // eslint-disable-line
});
});
+27
View File
@@ -0,0 +1,27 @@
// Copyright 2017-2018 @polkadot/api-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import Struct from './codec/Struct';
import Vector from './codec/Vector';
import Extrinsic from './Extrinsic';
import Header from './Header';
// A block encoded with header and extrinsics
export default class Block extends Struct {
constructor (value?: any) {
super({
header: Header,
extrinsics: Vector.with(Extrinsic)
}, value);
}
get extrinsics (): Vector<Extrinsic> {
return this.raw.extrinsics as Vector<Extrinsic>;
}
get header (): Header {
return this.raw.header as Header;
}
}
+2 -2
View File
@@ -2,9 +2,9 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import CodecBase from './codec/Base';
import Base from './codec/Base';
export default class Bool extends CodecBase<boolean> {
export default class Bool extends Base<boolean> {
constructor (value: Bool | boolean = false) {
super(
value instanceof Bool
@@ -4,31 +4,30 @@
import u8aConcat from '@polkadot/util/u8a/concat';
import CodecU8a from './U8a';
import Length from './Length';
import Length from './codec/Length';
import U8a from './codec/U8a';
// A CodecBytes. The significant difference between this and a normal Uint8Array is that
// A Bytes. The significant difference between this and a normal Uint8Array is that
// this version allows for length-encoding. (i.e. it is a variable-item codec, the same
// as what is found in String and Array)
export default class CodecBytes extends CodecU8a {
export default class Bytes extends U8a {
protected _length: Length;
constructor (value: CodecU8a | Uint8Array = new Uint8Array()) {
super(
value instanceof CodecU8a
? value.raw
: value
);
constructor (value?: U8a | string | Uint8Array) {
super(value);
this._length = new Length(value.length);
this._length = new Length(this.raw.length);
}
get length (): number {
return this._length.toNumber();
}
byteLength (): number {
return this._length.byteLength() +
this._length.toNumber();
return this._length.byteLength() + this.length;
}
fromJSON (input: any): CodecBytes {
fromJSON (input: any): Bytes {
super.fromJSON(input);
this._length.setValue(this.raw.length);
@@ -36,7 +35,7 @@ export default class CodecBytes extends CodecU8a {
return this;
}
fromU8a (input: Uint8Array): CodecBytes {
fromU8a (input: Uint8Array): Bytes {
this._length.fromU8a(input);
const length = this._length.toNumber();
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2017-2018 @polkadot/api-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import blake2Asu8a from '@polkadot/util-crypto/blake2/asU8a';
import Bytes from './Bytes';
import Hash from './Hash';
// Representation of an Extrinsic in the system.
//
// NOTE At this point we are just keeping to a bare-bones Vec<u8> structure,
// this should be expanded to do the automatic decoding of an extrinsic
export default class Extrinsic extends Bytes {
// convernience, encodes the extrinsic and returns the actual hash
get hash (): Hash {
return new Hash(
blake2Asu8a(this.toU8a(), 256)
);
}
}
+4 -4
View File
@@ -2,13 +2,13 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import CodecU8a from './codec/U8a';
import CodecU8aFixed from './codec/U8aFixed';
import U8a from './codec/U8a';
import U8aFixed from './codec/U8aFixed';
// Hash containing 256 bits (32 bytes), typically used in blocks, extrinsics and
// as a sane default for fixed-length hash representations.
export default class H256 extends CodecU8aFixed {
constructor (value?: CodecU8a | Uint8Array) {
export default class H256 extends U8aFixed {
constructor (value?: U8a | string | Uint8Array) {
super(value, 256);
}
}
+4 -4
View File
@@ -2,12 +2,12 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import CodecU8a from './codec/U8a';
import CodecU8aFixed from './codec/U8aFixed';
import U8a from './codec/U8a';
import U8aFixed from './codec/U8aFixed';
// Hash containing 512 bits (64 bytes), typically used for signatures
export default class H512 extends CodecU8aFixed {
constructor (value?: CodecU8a | Uint8Array) {
export default class H512 extends U8aFixed {
constructor (value?: U8a | string | Uint8Array) {
super(value, 512);
}
}
+33 -10
View File
@@ -2,29 +2,45 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import CodecArray from './codec/Array';
import CodecBytes from './codec/Bytes';
import CodecStruct from './codec/Struct';
import BN from 'bn.js';
import blake2Asu8a from '@polkadot/util-crypto/blake2/asU8a';
import UInt from './codec/UInt';
import Struct from './codec/Struct';
import Vector from './codec/Vector';
import BlockNumber from './BlockNumber';
import Bytes from './Bytes';
import Hash from './Hash';
type DigestStruct = {
logs?: Array<Uint8Array | string>
};
type HeaderStruct = {
digest?: DigestStruct,
extrinsicsRoot?: Hash | Uint8Array | string,
number?: UInt | BN | number | string,
parentHash?: Hash | Uint8Array | string,
stateRoot?: Hash | Uint8Array | string
};
// A block header digest.
export class Digest extends CodecStruct {
constructor (value?: any) {
export class Digest extends Struct {
constructor (value: DigestStruct = {}) {
super({
logs: CodecArray.with(CodecBytes)
logs: Vector.with(Bytes)
}, value);
}
get logs (): CodecArray<CodecBytes> {
return this.raw.logs as CodecArray<CodecBytes>;
get logs (): Vector<Bytes> {
return this.raw.logs as Vector<Bytes>;
}
}
// A block header.
export default class Header extends CodecStruct {
constructor (value?: any) {
export default class Header extends Struct {
constructor (value: HeaderStruct = {}) {
super({
parentHash: Hash,
number: BlockNumber,
@@ -46,6 +62,13 @@ export default class Header extends CodecStruct {
return this.raw.extrinsicsRoot as Hash;
}
// convernience, encodes the header and returns the actual hash
get hash (): Hash {
return new Hash(
blake2Asu8a(this.toU8a(), 256)
);
}
get parentHash (): Hash {
return this.raw.parentHash as Hash;
}
+14 -13
View File
@@ -2,31 +2,32 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import CodecBytes from './codec/Bytes';
import CodecStruct from './codec/Struct';
import Struct from './codec/Struct';
import Bytes from './Bytes';
type KeyValueStruct = {
key: Uint8Array,
value: Uint8Array
key?: Uint8Array | string,
value?: Uint8Array | string
};
// KeyValue structure. Since most of the keys and resultant values in Subtrate is
// hashed and/or encoded, this does not wrap a CodecString, but rather a CodecBytes
// hashed and/or encoded, this does not wrap a Text, but rather a Bytes
// for the keys and values. (Not to be confused with the KeyValue in Metadata, that
// is actually for Maps, whereas this is a representation of actaul storage values)
export default class KeyValue extends CodecStruct {
constructor (value: KeyValueStruct = {} as KeyValueStruct) {
export default class KeyValue extends Struct {
constructor (value: KeyValueStruct = {}) {
super({
key: CodecBytes,
value: CodecBytes
key: Bytes,
value: Bytes
}, value);
}
get key (): CodecBytes {
return this.raw.key as CodecBytes;
get key (): Bytes {
return this.raw.key as Bytes;
}
get value (): CodecBytes {
return this.raw.value as CodecBytes;
get value (): Bytes {
return this.raw.value as Bytes;
}
}
+87 -87
View File
@@ -2,13 +2,13 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import CodecArray from './codec/Array';
import CodecBase from './codec/Base';
import CodecEnum from './codec/Enum';
import CodecEnumType from './codec/EnumType';
import CodecOption from './codec/Option';
import CodecStruct from './codec/Struct';
import String from './String';
import Vector from './codec/Vector';
import Base from './codec/Base';
import Enum from './codec/Enum';
import EnumType from './codec/EnumType';
import Option from './codec/Option';
import Struct from './codec/Struct';
import Text from './Text';
import Type from './Type';
import U16 from './U16';
@@ -16,72 +16,72 @@ import U16 from './U16';
// file is probably best understood from the bottom-up, i.e. start reading right at the
// end and work up. (Just so we don't use before definition)
class EventMetadata extends CodecStruct {
export class EventMetadata extends Struct {
constructor () {
super({
name: String,
arguments: CodecArray.with(Type),
documentation: CodecArray.with(String)
name: Text,
arguments: Vector.with(Type),
documentation: Vector.with(Text)
});
}
get arguments (): CodecArray<Type> {
return this.raw.arguments as CodecArray<Type>;
get arguments (): Vector<Type> {
return this.raw.arguments as Vector<Type>;
}
get documentation (): CodecArray<String> {
return this.raw.documentation as CodecArray<String>;
get documentation (): Vector<Text> {
return this.raw.documentation as Vector<Text>;
}
get name (): String {
return this.raw.name as String;
get name (): Text {
return this.raw.name as Text;
}
}
class OuterEventMetadataEvent extends CodecStruct {
export class OuterEventMetadataEvent extends Struct {
constructor () {
super({
name: String,
events: CodecArray.with(EventMetadata)
name: Text,
events: Vector.with(EventMetadata)
});
}
get events (): CodecArray<EventMetadata> {
return this.raw.events as CodecArray<EventMetadata>;
get events (): Vector<EventMetadata> {
return this.raw.events as Vector<EventMetadata>;
}
get name (): String {
return this.raw.name as String;
get name (): Text {
return this.raw.name as Text;
}
}
class OuterEventMetadata extends CodecStruct {
export class OuterEventMetadata extends Struct {
constructor () {
super({
name: String,
events: CodecArray.with(OuterEventMetadataEvent)
name: Text,
events: Vector.with(OuterEventMetadataEvent)
});
}
get events (): CodecArray<OuterEventMetadataEvent> {
return this.raw.events as CodecArray<OuterEventMetadataEvent>;
get events (): Vector<OuterEventMetadataEvent> {
return this.raw.events as Vector<OuterEventMetadataEvent>;
}
get name (): String {
return this.raw.name as String;
get name (): Text {
return this.raw.name as Text;
}
}
class FunctionArgumentMetadata extends CodecStruct {
export class FunctionArgumentMetadata extends Struct {
constructor () {
super({
name: String,
name: Text,
type: Type
});
}
get name (): String {
return this.raw.name as String;
get name (): Text {
return this.raw.name as Text;
}
get type (): Type {
@@ -89,54 +89,54 @@ class FunctionArgumentMetadata extends CodecStruct {
}
}
class FunctionMetadata extends CodecStruct {
export class FunctionMetadata extends Struct {
constructor () {
super({
id: U16,
name: String,
arguments: CodecArray.with(FunctionArgumentMetadata),
documentation: CodecArray.with(String)
name: Text,
arguments: Vector.with(FunctionArgumentMetadata),
documentation: Vector.with(Text)
});
}
get arguments (): CodecArray<FunctionArgumentMetadata> {
return this.raw.arguments as CodecArray<FunctionArgumentMetadata>;
get arguments (): Vector<FunctionArgumentMetadata> {
return this.raw.arguments as Vector<FunctionArgumentMetadata>;
}
get documentation (): CodecArray<String> {
return this.raw.documentation as CodecArray<String>;
get documentation (): Vector<Text> {
return this.raw.documentation as Vector<Text>;
}
get id (): U16 {
return this.raw.id as U16;
}
get name (): String {
return this.raw.name as String;
get name (): Text {
return this.raw.name as Text;
}
}
class CallMetadata extends CodecStruct {
export class CallMetadata extends Struct {
constructor () {
super({
name: String,
functions: CodecArray.with(FunctionMetadata)
name: Text,
functions: Vector.with(FunctionMetadata)
});
}
get functions (): CodecArray<FunctionMetadata> {
return this.raw.functions as CodecArray<FunctionMetadata>;
get functions (): Vector<FunctionMetadata> {
return this.raw.functions as Vector<FunctionMetadata>;
}
get name (): String {
return this.raw.name as String;
get name (): Text {
return this.raw.name as Text;
}
}
class ModuleMetadata extends CodecStruct {
export class ModuleMetadata extends Struct {
constructor () {
super({
name: String,
name: Text,
call: CallMetadata
});
}
@@ -145,18 +145,18 @@ class ModuleMetadata extends CodecStruct {
return this.raw.call as CallMetadata;
}
get name (): String {
return this.raw.name as String;
get name (): Text {
return this.raw.name as Text;
}
}
class StorageFunctionModifier extends CodecEnum {
export class StorageFunctionModifier extends Enum {
constructor () {
super(['None', 'Default', 'Required']);
}
}
class StorageFunctionType$Map extends CodecStruct {
export class StorageFunctionType$Map extends Struct {
constructor () {
super({
key: Type,
@@ -173,7 +173,7 @@ class StorageFunctionType$Map extends CodecStruct {
}
}
class StorageFunctionType extends CodecEnumType<Type | StorageFunctionType$Map> {
export class StorageFunctionType extends EnumType<Type | StorageFunctionType$Map> {
constructor () {
super([
Type,
@@ -186,30 +186,30 @@ class StorageFunctionType extends CodecEnumType<Type | StorageFunctionType$Map>
}
get asMap (): StorageFunctionType$Map {
return (this.raw as CodecBase<StorageFunctionType$Map>).raw;
return (this.raw as Base<StorageFunctionType$Map>).raw;
}
get asType (): Type {
return (this.raw as CodecBase<Type>).raw;
return (this.raw as Base<Type>).raw;
}
}
class StorageFunctionMetadata extends CodecStruct {
export class StorageFunctionMetadata extends Struct {
constructor () {
super({
name: String,
name: Text,
modifier: StorageFunctionModifier,
type: StorageFunctionType,
documentation: CodecArray.with(String)
documentation: Vector.with(Text)
});
}
get documentation (): CodecArray<String> {
return this.raw.documentation as CodecArray<String>;
get documentation (): Vector<Text> {
return this.raw.documentation as Vector<Text>;
}
get name (): String {
return this.raw.name as String;
get name (): Text {
return this.raw.name as Text;
}
get modifier (): StorageFunctionModifier {
@@ -221,29 +221,29 @@ class StorageFunctionMetadata extends CodecStruct {
}
}
class StorageMetadata extends CodecStruct {
export class StorageMetadata extends Struct {
constructor () {
super({
prefix: String,
functions: CodecArray.with(StorageFunctionMetadata)
prefix: Text,
functions: Vector.with(StorageFunctionMetadata)
});
}
get functions (): CodecArray<StorageFunctionMetadata> {
return this.raw.functions as CodecArray<StorageFunctionMetadata>;
get functions (): Vector<StorageFunctionMetadata> {
return this.raw.functions as Vector<StorageFunctionMetadata>;
}
get prefix (): String {
return this.raw.prefix as String;
get prefix (): Text {
return this.raw.prefix as Text;
}
}
class RuntimeModuleMetadata extends CodecStruct {
export class RuntimeModuleMetadata extends Struct {
constructor () {
super({
prefix: String,
prefix: Text,
module: ModuleMetadata,
storage: CodecOption.with(StorageMetadata)
storage: Option.with(StorageMetadata)
});
}
@@ -251,20 +251,20 @@ class RuntimeModuleMetadata extends CodecStruct {
return this.raw.module as ModuleMetadata;
}
get prefix (): String {
return this.raw.prefix as String;
get prefix (): Text {
return this.raw.prefix as Text;
}
get storage (): StorageMetadata | undefined {
return (this.raw.storage as CodecOption<StorageMetadata>).value;
return (this.raw.storage as Option<StorageMetadata>).value;
}
}
export default class RuntimeMetadata extends CodecStruct {
export default class RuntimeMetadata extends Struct {
constructor (value?: any) {
super({
outerEvent: OuterEventMetadata,
modules: CodecArray.with(RuntimeModuleMetadata)
modules: Vector.with(RuntimeModuleMetadata)
}, value);
}
@@ -281,16 +281,16 @@ export default class RuntimeMetadata extends CodecStruct {
}
// FIXME Really not crazy about having to manually add all the getters. Preferably it should
// be done automagically in the actual CodecStruct - however what is really important here
// be done automagically in the actual Struct - however what is really important here
// here is that we should nbot lose the autocompletion and checking that TS gives us. So if
// we have to choose between the 2, manual defs it would have to be.
get events (): CodecArray<OuterEventMetadataEvent> {
get events (): Vector<OuterEventMetadataEvent> {
return (this.raw.outerEvent as OuterEventMetadata).events;
}
get modules (): CodecArray<RuntimeModuleMetadata> {
return this.raw.modules as CodecArray<RuntimeModuleMetadata>;
get modules (): Vector<RuntimeModuleMetadata> {
return this.raw.modules as Vector<RuntimeModuleMetadata>;
}
// Helper to retrieve a list of all type that are found, sorted and de-deuplicated
+9
View File
@@ -0,0 +1,9 @@
// Copyright 2017-2018 @polkadot/api-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import U32 from './U32';
// An increasing number that represents a specific proposal in the system
export default class PropIndex extends U32 {
}
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2017-2018 @polkadot/api-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import Address from './Address';
// Wrapper for a RawAddress.
// NOTE Not 100% on the differences between this and Address in the runtime
export default class RawAddress extends Address {
}
@@ -6,7 +6,7 @@ import u8aFromUtf8 from '@polkadot/util/u8a/fromUtf8';
import u8aToUtf8 from '@polkadot/util/u8a/toUtf8';
import u8aConcat from '@polkadot/util/u8a/concat';
import CodecBase from './codec/Base';
import Base from './codec/Base';
import Length from './codec/Length';
// This is a string wrapper, along with the length. It is used both for strings as well
@@ -17,14 +17,14 @@ import Length from './codec/Length';
// - Potentially we want a "TypeString" extension to this. Basically something that
// wraps the `Balance`, `T::AccountId`, etc. The reasoning - with a "TypeString"
// we can nicely strip types down like "T::AcountId" -> "AccountId"
export default class String extends CodecBase<string> {
export default class Text extends Base<string> {
protected _length: Length;
constructor (value: String | string = '') {
constructor (value: Text | string = '') {
super(
value instanceof String
value instanceof Text
? value.raw
: value
: value.trim()
);
this._length = new Length(value.length);
@@ -41,13 +41,13 @@ export default class String extends CodecBase<string> {
this._length.byteLength();
}
fromJSON (input: any): String {
fromJSON (input: any): Text {
this.raw = `${input}`;
return this;
}
fromU8a (input: Uint8Array): String {
fromU8a (input: Uint8Array): Text {
this._length.fromU8a(input);
const length = this._length.toNumber();
+11 -2
View File
@@ -2,6 +2,7 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import Text from './Text';
import Type from './Type';
describe('Type', () => {
@@ -19,8 +20,8 @@ describe('Type', () => {
it('handles aliasses, multiples per line', () => {
expect(
new Type().fromJSON('(PropIndex, AccountId, PropIndex)').toString()
).toEqual('(ProposalIndex, AccountId, ProposalIndex)');
new Type().fromJSON('(Vec<u8>, AccountId, Vec<u8>)').toString()
).toEqual('(Bytes, AccountId, Bytes)');
});
it('does not allow toU8a', () => {
@@ -28,4 +29,12 @@ describe('Type', () => {
() => new Type().toU8a()
).toThrow(/unimplemented/);
});
it('has a length for the type', () => {
expect(
new Type(
new Text(' Box<Proposal> ')
).length
).toEqual('Proposal'.length); // eslint-disable-line
});
});
+10 -4
View File
@@ -2,14 +2,20 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import String from './String';
import Text from './Text';
type Mapper = (value: string) => string;
// This is a extended version of String, specifically to handle types. Here we rely full on
// what string provides us, however we also "tweak" the types received from the runtime, i.e.
// we remove the `T::` prefixes found in some types for consistency accross implementation.
export default class Type extends String {
export default class Type extends Text {
constructor (value?: Text | string) {
super(value);
this._cleanupTypes();
}
fromJSON (input: any): Type {
super.fromJSON(input);
@@ -39,9 +45,9 @@ export default class Type extends String {
// remove generics, `MisbehaviorReport<Hash, BlockNumber>` -> `MisbehaviorReport`
this._ungeneric(),
// convert `RawAddress` -> `Address`
this._unalias('RawAddress', 'Address'),
// convert `PropIndex` -> `ProposalIndex`
this._unalias('PropIndex', 'ProposalIndex')
// alias Vec<u8> -> Bytes
this._unalias('Vec<u8>', 'Bytes')
];
this.raw = mappings.reduce((result, fn) => {
+3 -3
View File
@@ -4,10 +4,10 @@
import BN from 'bn.js';
import CodecNumber from './codec/Number';
import UInt from './codec/UInt';
export default class U128 extends CodecNumber {
constructor (value?: CodecNumber | BN | string | number) {
export default class U128 extends UInt {
constructor (value?: UInt | BN | string | number) {
super(value, 128);
}
}
+3 -3
View File
@@ -4,10 +4,10 @@
import BN from 'bn.js';
import CodecNumber from './codec/Number';
import UInt from './codec/UInt';
export default class U16 extends CodecNumber {
constructor (value?: CodecNumber | BN | string | number) {
export default class U16 extends UInt {
constructor (value?: UInt | BN | string | number) {
super(value, 16);
}
}
+3 -3
View File
@@ -4,10 +4,10 @@
import BN from 'bn.js';
import CodecNumber from './codec/Number';
import UInt from './codec/UInt';
export default class U256 extends CodecNumber {
constructor (value?: CodecNumber | BN | string | number) {
export default class U256 extends UInt {
constructor (value?: UInt | BN | string | number) {
super(value, 256);
}
}
+3 -3
View File
@@ -4,10 +4,10 @@
import BN from 'bn.js';
import CodecNumber from './codec/Number';
import UInt from './codec/UInt';
export default class U32 extends CodecNumber {
constructor (value?: CodecNumber | BN | string | number) {
export default class U32 extends UInt {
constructor (value?: UInt | BN | string | number) {
super(value, 32);
}
}
+3 -3
View File
@@ -4,10 +4,10 @@
import BN from 'bn.js';
import CodecNumber from './codec/Number';
import UInt from './codec/UInt';
export default class U64 extends CodecNumber {
constructor (value?: CodecNumber | BN | string | number) {
export default class U64 extends UInt {
constructor (value?: UInt | BN | string | number) {
super(value, 64);
}
}
+3 -3
View File
@@ -4,10 +4,10 @@
import BN from 'bn.js';
import CodecNumber from './codec/Number';
import UInt from './codec/UInt';
export default class U8 extends CodecNumber {
constructor (value?: CodecNumber | BN | string | number) {
export default class U8 extends UInt {
constructor (value?: UInt | BN | string | number) {
super(value, 8);
}
}
+9 -9
View File
@@ -8,7 +8,7 @@
//
// TODO
// - This could probably be abstract, as long as we have the functions abstract as well
export default class CodecBase <T = any> {
export default class Base <T = any> {
raw: T;
constructor (value?: any) {
@@ -16,26 +16,26 @@ export default class CodecBase <T = any> {
}
byteLength (): number {
throw new Error('CodecBase::byteLength: unimplemented');
throw new Error('Base::byteLength: unimplemented');
}
fromJSON (input: any): CodecBase <T> {
throw new Error('CodecBase::fromJSON: unimplemented');
fromJSON (input: any): Base <T> {
throw new Error('Base::fromJSON: unimplemented');
}
fromU8a (input: Uint8Array): CodecBase <T> {
throw new Error('CodecBase::fromU8a: unimplemented');
fromU8a (input: Uint8Array): Base <T> {
throw new Error('Base::fromU8a: unimplemented');
}
toJSON (): any {
throw new Error('CodecBase::toJSON: unimplemented');
throw new Error('Base::toJSON: unimplemented');
}
toString (): string {
throw new Error('CodecBase::toString: unimplemented');
throw new Error('Base::toString: unimplemented');
}
toU8a (): Uint8Array {
throw new Error('CodecBase::toU8a: unimplemented');
throw new Error('Base::toU8a: unimplemented');
}
}
+4 -4
View File
@@ -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 CodecBase from './Base';
import Base from './Base';
// A codec wrapper for an enum. Enums are encoded as a single byte, where the byte
// is a zero-indexed value. This class allows you to retrieve the value either
@@ -11,7 +11,7 @@ import CodecBase from './Base';
//
// TODO:
// - It would be great if this could actually wrap actual TS enums
export default class CodecEnum extends CodecBase<number> {
export default class Enum extends Base<number> {
private _strings: Array<string>;
constructor (strings: Array<string>, value: number = 0) {
@@ -24,13 +24,13 @@ export default class CodecEnum extends CodecBase<number> {
return 1;
}
fromJSON (input: any): CodecEnum {
fromJSON (input: any): Enum {
this.raw = input;
return this;
}
fromU8a (input: Uint8Array): CodecEnum {
fromU8a (input: Uint8Array): Enum {
this.raw = input[0];
return this;
+8 -8
View File
@@ -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 CodecBase from './Base';
import Base from './Base';
// 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.
@@ -11,12 +11,12 @@ import CodecBase from './Base';
// - 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 CodecEnumType <T> extends CodecBase<CodecBase<T>> {
private _Type: Array<{ new(value?: any): CodecBase }>;
export default class EnumType <T> extends Base<Base<T>> {
private _Type: Array<{ new(value?: any): Base }>;
private _index: number;
private _strings: Array<string>;
constructor (Type: Array<{ new(value?: any): CodecBase }>, strings: Array<string>, index: number = 0) {
constructor (Type: Array<{ new(value?: any): Base }>, strings: Array<string>, index: number = 0) {
super(
new Type[index]()
);
@@ -30,11 +30,11 @@ export default class CodecEnumType <T> extends CodecBase<CodecBase<T>> {
return 1 + this.raw.byteLength();
}
fromJSON (input: any): CodecEnumType<T> {
throw new Error('CodecEnumType:fromJSON: unimplemented');
fromJSON (input: any): EnumType<T> {
throw new Error('EnumType:fromJSON: unimplemented');
}
fromU8a (input: Uint8Array): CodecEnumType<T> {
fromU8a (input: Uint8Array): EnumType<T> {
this._index = input[0];
this.raw = new this._Type[this._index]().fromU8a(input.subarray(1));
@@ -46,7 +46,7 @@ export default class CodecEnumType <T> extends CodecBase<CodecBase<T>> {
}
toU8a (): Uint8Array {
throw new Error('CodecEnumType:toU8a: unimplemented');
throw new Error('EnumType:toU8a: unimplemented');
}
toNumber (): number {
+10 -10
View File
@@ -4,7 +4,7 @@
import Length from './Length';
describe('Compact', () => {
describe('Length', () => {
it('encodes short u8', () => {
expect(
new Length(18).toU8a()
@@ -29,14 +29,18 @@ describe('Compact', () => {
);
});
it('encodes basic ua6 (not at edge)', () => {
expect(
new Length(111).toHex()
).toEqual('0xbd01');
});
it('decodes from same u16 encoded value', () => {
expect(
new Length()
.fromU8a(new Uint8Array([0b11111101, 0b00000111]))
.toNumber()
).toEqual(
511
);
).toEqual(511);
});
it('encodes basic u32 values (short)', () => {
@@ -52,9 +56,7 @@ describe('Compact', () => {
new Length()
.fromU8a(new Uint8Array([254, 255, 3, 0]))
.toNumber()
).toEqual(
0xffff
);
).toEqual(0xffff);
});
it('encodes basic u32 values (full)', () => {
@@ -70,8 +72,6 @@ describe('Compact', () => {
new Length()
.fromU8a(new Uint8Array([3, 249, 255, 255, 255]))
.toNumber()
).toEqual(
0xfffffff9
);
).toEqual(0xfffffff9);
});
});
+17 -16
View File
@@ -7,8 +7,9 @@ import bnToBn from '@polkadot/util/bn/toBn';
import bnToU8a from '@polkadot/util/bn/toU8a';
import u8aConcat from '@polkadot/util/u8a/concat';
import u8aToBn from '@polkadot/util/u8a/toBn';
import u8aToHex from '@polkadot/util/u8a/toHex';
import CodecBase from './Base';
import Base from './Base';
const MAX_U8 = new BN(2).pow(new BN(8 - 2)).subn(1);
const MAX_U16 = new BN(2).pow(new BN(16 - 2)).subn(1);
@@ -29,10 +30,10 @@ const MAX_U32 = new BN(2).pow(new BN(32 - 2)).subn(1);
// nn nn nn 11 [ / zz zz zz zz ]{4 + n}
//
// Note: we use *LOW BITS* of the LSB in LE encoding to encode the 2 bit key.
export default class CodecLength extends CodecBase<BN> {
constructor (value: CodecLength | BN | number = new BN(0)) {
export default class Length extends Base<BN> {
constructor (value: Length | BN | number = new BN(0)) {
super(
value instanceof CodecLength
value instanceof Length
? value.raw
: bnToBn(value)
);
@@ -69,32 +70,32 @@ export default class CodecLength extends CodecBase<BN> {
);
}
get length (): number {
return this.raw.toNumber();
}
byteLength (): number {
return this.toU8a().length;
}
fromJSON (): CodecLength {
throw new Error('CodecLength::fromJSON: unimplemented');
fromJSON (): Length {
throw new Error('Length::fromJSON: unimplemented');
}
fromNumber (value: BN | number): CodecLength {
fromNumber (value: BN | number): Length {
this.raw = bnToBn(value);
return this;
}
fromU8a (input: Uint8Array): CodecLength {
this.raw = CodecLength.decode(input);
fromU8a (input: Uint8Array): Length {
this.raw = Length.decode(input);
return this;
}
toJSON (): any {
throw new Error('CodecLength::toJSON: unimplemented');
throw new Error('Length::toJSON: unimplemented');
}
toHex (): string {
return u8aToHex(this.toU8a());
}
toNumber (): number {
@@ -102,11 +103,11 @@ export default class CodecLength extends CodecBase<BN> {
}
toString (): string {
throw new Error('CodecLength::toString: unimplemented');
throw new Error('Length::toString: unimplemented');
}
toU8a (): Uint8Array {
return CodecLength.encode(this.raw);
return Length.encode(this.raw);
}
setValue (value: BN | number): void {
+8 -8
View File
@@ -4,16 +4,16 @@
import isUndefined from '@polkadot/util/is/undefined';
import CodecBase from './Base';
import Base from './Base';
// 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 CodecOption
// is value to follow. If the byte is `1` there is an actual value. So the Option
// implements that - decodes, checks for optionality and wraps the required structure
// with a value if/as required/found.
export default class CodecOption <T> extends CodecBase<CodecBase<T>> {
export default class Option <T> extends Base<Base<T>> {
private _hasValue: boolean;
constructor (Value: { new(value?: any): CodecBase<T> }, value?: any) {
constructor (Value: { new(value?: any): Base<T> }, value?: any) {
super(
new Value(value)
);
@@ -21,8 +21,8 @@ export default class CodecOption <T> extends CodecBase<CodecBase<T>> {
this._hasValue = !isUndefined(value);
}
static with <O> (Type: { new(value?: any): CodecBase<O> }): { new(value?: any): CodecOption<O> } {
return class extends CodecOption<O> {
static with <O> (Type: { new(value?: any): Base<O> }): { new(value?: any): Option<O> } {
return class extends Option<O> {
constructor (value?: any) {
super(Type, value);
}
@@ -43,7 +43,7 @@ export default class CodecOption <T> extends CodecBase<CodecBase<T>> {
return 1 + childLength;
}
fromJSON (input: any): CodecOption<T> {
fromJSON (input: any): Option<T> {
this._hasValue = !isUndefined(input);
if (this._hasValue) {
@@ -53,7 +53,7 @@ export default class CodecOption <T> extends CodecBase<CodecBase<T>> {
return this;
}
fromU8a (input: Uint8Array): CodecOption<T> {
fromU8a (input: Uint8Array): Option<T> {
this._hasValue = input[0] === 1;
if (this._hasValue) {
+16 -16
View File
@@ -4,29 +4,29 @@
import u8aConcat from '@polkadot/util/u8a/concat';
import CodecBase from './Base';
import Base from './Base';
// A Struct defines an Object with key/values - where the values are CodecCodecBase values. It removes
// a lot of repetition from the actual coding, define a structure type, pass it the key/CodecBase<T>
// A Struct defines an Object with key/values - where the values are CodecBase values. It removes
// a lot of repetition from the actual coding, define a structure type, pass it the key/Base<T>
// values in the constructor and it manages the decoding. It is important that the constructor
// values matches 100% to the order in th Rust code, i.e. don't go crazy and make it alphabetical,
// it needs to decoded in the specific defined order.
//
// TODO:
// - Check the constructor, something is really, really wrong with the way the defs are used
export default class CodecStruct <
S = { [index: string]: { new(value?: any): CodecBase } },
T = { [K in keyof S]: CodecBase },
export default class Struct <
S = { [index: string]: { new(value?: any): Base } },
T = { [K in keyof S]: Base },
V = { [K in keyof S]: any }
> extends CodecBase<T> {
constructor (Struct: S, value: V = {} as V) {
> extends Base<T> {
constructor (Def: S, value: V = {} as V) {
super(
Object.keys(Struct).reduce((raw: T, key) => {
Object.keys(Def).reduce((raw: T, key) => {
// @ts-ignore Ok, something weid 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 the [key in keyof T]
// was added, the idea is to provide better checks, which does backfire here, but works
// externally.)
raw[key] = new Struct[key](value[key]);
raw[key] = new Def[key](value[key]);
return raw;
}, {} as T)
@@ -34,11 +34,11 @@ export default class CodecStruct <
}
static with <
S = { [index: string]: { new(value?: any): CodecBase } }
> (Struct: S): { new(value?: any): CodecStruct<S> } {
return class extends CodecStruct<S> {
S = { [index: string]: { new(value?: any): Base } }
> (Def: S): { new(value?: any): Struct<S> } {
return class extends Struct<S> {
constructor (value?: any) {
super(Struct, value);
super(Def, value);
}
};
}
@@ -49,7 +49,7 @@ export default class CodecStruct <
}, 0);
}
fromJSON (input: any): CodecStruct<S, T, V> {
fromJSON (input: any): Struct<S, T, V> {
Object.keys(this.raw).forEach((key) => {
// @ts-ignore as above...
this.raw[key].fromJSON(input[key]);
@@ -58,7 +58,7 @@ export default class CodecStruct <
return this;
}
fromU8a (input: Uint8Array): CodecStruct<S, T, V> {
fromU8a (input: Uint8Array): Struct<S, T, V> {
Object.keys(this.raw).reduce((offset, key) => {
// @ts-ignore as above...
this.raw[key].fromU8a(input.subarray(offset));
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2017-2018 @polkadot/api-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import U8a from './U8a';
describe('U8a', () => {
let u8a;
beforeEach(() => {
u8a = new U8a([1, 2, 3, 4, 5]);
});
it('contains the length of the elements', () => {
expect(u8a.length).toEqual(5); // eslint-disable-line
});
it('allows wrapping of a pre-existing instance', () => {
expect(
new U8a(u8a).length
).toEqual(5); // eslint-disable-line
});
});
+7 -7
View File
@@ -5,16 +5,16 @@
import u8aToHex from '@polkadot/util/u8a/toHex';
import toU8a from '@polkadot/util/u8a/toU8a';
import CodecBase from './Base';
import Base from './Base';
// A CodecU8a. A basic wrapper around Uint8Array, with no frills and no fuss. It
// A U8a. A basic wrapper around Uint8Array, with no frills and no fuss. It
// wraps a Uint8Array. It does differ from other implementations wher it will
// consume the full u8a as passed to it in fromU8a. As such it is meant to be
// subclassed where the wrapper takes care of the actual lengths.
export default class CodecU8a extends CodecBase<Uint8Array> {
constructor (value: CodecU8a | string | Uint8Array = new Uint8Array()) {
export default class U8a extends Base<Uint8Array> {
constructor (value: U8a | string | Uint8Array | Array<number> = new Uint8Array()) {
super(
value instanceof CodecU8a
value instanceof U8a
? value.raw
: toU8a(value)
);
@@ -28,13 +28,13 @@ export default class CodecU8a extends CodecBase<Uint8Array> {
return this.raw.length;
}
fromJSON (input: any): CodecU8a {
fromJSON (input: any): U8a {
this.raw = toU8a(input);
return this;
}
fromU8a (input: Uint8Array): CodecU8a {
fromU8a (input: Uint8Array): U8a {
this.raw = input;
return this;
@@ -0,0 +1,29 @@
// Copyright 2017-2018 @polkadot/api-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import U8aFixed from './U8aFixed';
describe('U8aFixed', () => {
let u8a;
beforeEach(() => {
u8a = new U8aFixed([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 32);
});
it('limits the length', () => {
expect(u8a.length).toEqual(4); // eslint-disable-line
});
it('allows wrapping of a pre-existing instance', () => {
expect(
u8a.toU8a()
).toEqual(new Uint8Array([1, 2, 3, 4]));
});
it('allows empty values', () => {
expect(
new U8aFixed().toHex()
).toEqual('0x');
});
});
+18 -4
View File
@@ -2,26 +2,40 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import CodecU8a from './U8a';
import U8a from './U8a';
type BitLength = 256 | 512;
// A U8a that manages a a sequence of bytes up to the specified bitLength. Not meant
// to be used directly, rather is should be subclassed with the specific lengths.
export default class CodecU8aFixed extends CodecU8a {
export default class U8aFixed extends U8a {
protected _bitLength: number;
constructor (value: CodecU8a | string | Uint8Array = new Uint8Array(), bitLength: BitLength = 256) {
constructor (value: U8a | string | Uint8Array = new Uint8Array(), bitLength: BitLength = 256) {
super(value);
this._bitLength = bitLength;
this._trimLength();
}
private _trimLength (): void {
this.raw = this.raw.subarray(0, this.byteLength());
}
byteLength (): number {
return this._bitLength / 8;
}
fromU8a (input: Uint8Array): CodecU8aFixed {
fromJSON (input: any): U8aFixed {
super.fromJSON(input);
this._trimLength();
return this;
}
fromU8a (input: Uint8Array): U8aFixed {
super.fromU8a(input.subarray(0, this.byteLength()));
return this;
@@ -11,7 +11,7 @@ import bnToU8a from '@polkadot/util/bn/toU8a';
import hexToBn from '@polkadot/util/hex/toBn';
import u8aToBn from '@polkadot/util/u8a/toBn';
import CodecBase from './Base';
import Base from './Base';
type BitLength = 8 | 16 | 32 | 64 | 128 | 256;
@@ -21,19 +21,19 @@ type BitLength = 8 | 16 | 32 | 64 | 128 | 256;
//
// TODO:
// - Apart from encoding/decoding we don't actuall keep check on the sizes, is this good enough?
export default class CodecNumber extends CodecBase<BN> {
export default class UInt extends Base<BN> {
private _bitLength: BitLength;
constructor (value: CodecNumber | BN | string | number = 0, bitLength: BitLength = 64) {
constructor (value: UInt | BN | string | number = 0, bitLength: BitLength = 64) {
super(
CodecNumber.decode(value)
UInt.decode(value)
);
this._bitLength = bitLength;
}
static decode (value: CodecNumber | BN | string | number): BN {
if (value instanceof CodecNumber) {
static decode (value: UInt | BN | string | number): BN {
if (value instanceof UInt) {
return value.raw;
} else if (isHex(value)) {
return hexToBn(value as string);
@@ -48,13 +48,13 @@ export default class CodecNumber extends CodecBase<BN> {
return this._bitLength / 8;
}
fromJSON (input: any): CodecNumber {
this.raw = CodecNumber.decode(input);
fromJSON (input: any): UInt {
this.raw = UInt.decode(input);
return this;
}
fromU8a (input: Uint8Array): CodecNumber {
fromU8a (input: Uint8Array): UInt {
this.raw = u8aToBn(input.subarray(0, this.byteLength()), true);
return this;
@@ -0,0 +1,81 @@
// Copyright 2017-2018 @polkadot/api-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import Text from '../Text';
import Vector from './Vector';
describe('Vector', () => {
let array;
beforeEach(() => {
array = new Vector(Text, [ '1', '23', '345', '4567', new Text('56789') ]);
});
it('wraps a sequence of values', () => {
expect(array.length).toEqual(5); // eslint-disable-line
});
it('has a sane representation for toString', () => {
expect(array.toString()).toEqual('[1, 23, 345, 4567, 56789]');
});
it('encodes with length prefix', () => {
expect(array.toU8a()).toEqual(new Uint8Array([
5 << 2,
1 << 2, 49,
2 << 2, 50, 51,
3 << 2, 51, 52, 53,
4 << 2, 52, 53, 54, 55,
5 << 2, 53, 54, 55, 56, 57
]));
});
it('allows contruction via JSON', () => {
expect(
new Vector(Text).fromJSON(['6', '7']).toString()
).toEqual('[6, 7]');
});
describe('array-like functions', () => {
it('allows retrieval of a specific item', () => {
expect(
array.at(2).toString()
).toEqual('345');
});
it('exposes a working forEach', () => {
const result = {};
array.forEach((e, i) => {
result[i] = e.toString();
});
expect(result).toEqual({
0: '1',
1: '23',
2: '345',
3: '4567',
4: '56789'
});
});
it('exposes a working filter', () => {
expect(
array.filter((e, i) => i >= 3).toString()
).toEqual('4567,56789');
});
it('exposes a working map', () => {
expect(
array.map((e) => e.toString().substr(0, 1))
).toEqual(['1', '2', '3', '4', '5']);
});
it('exposes a working reduce', () => {
expect(
array.reduce((r, e) => `${r}${e}`, '')
).toEqual('123345456756789');
});
});
});
@@ -4,7 +4,7 @@
import u8aConcat from '@polkadot/util/u8a/concat';
import CodecBase from './Base';
import Base from './Base';
import Length from './Length';
// This manages codec arrays. Intrernally it keeps track of the length (as decoded) and allows
@@ -12,16 +12,18 @@ import Length from './Length';
// i.e. while it wraps an array, it provides a `length` property to get the actual length, `at(index)`
// to retrieve a specific item. Additionally the helper functions `map`, `filter`, `forEach` and
// `reduce` is exposed on the interface.
export default class CodecArray <
T extends CodecBase
> extends CodecBase<Array<T>> {
export default class Vector <
T extends Base
> extends Base<Array<T>> {
private _length: Length;
private _Type: { new(value?: any): T };
constructor (Type: { new(value?: any): T }, value: Array<any> = [] as Array<any>) {
super(
value.map((entry) =>
new Type(entry)
entry instanceof Type
? entry
: new Type(entry)
)
);
@@ -29,8 +31,8 @@ export default class CodecArray <
this._Type = Type;
}
static with <O extends CodecBase> (Type: { new(value?: any): O }): { new(value?: any): CodecArray<O> } {
return class extends CodecArray<O> {
static with <O extends Base> (Type: { new(value?: any): O }): { new(value?: any): Vector<O> } {
return class extends Vector<O> {
constructor (value?: Array<any>) {
super(Type, value);
}
@@ -59,7 +61,7 @@ export default class CodecArray <
return this.raw.forEach(fn);
}
fromJSON (input: any): CodecArray<T> {
fromJSON (input: any): Vector<T> {
this.raw = input.map((input: any) =>
new this._Type().fromJSON(input)
);
@@ -67,7 +69,7 @@ export default class CodecArray <
return this;
}
fromU8a (input: Uint8Array): CodecArray<T> {
fromU8a (input: Uint8Array): Vector<T> {
this._length.fromU8a(input);
const length = this._length.toNumber();
@@ -110,8 +112,8 @@ export default class CodecArray <
toString (): string {
const data = this.raw.map((entry) =>
entry.toString()
).join(', ');
);
return `[${data}]`;
return `[${data.join(', ')}]`;
}
}