Skip to content

Commit

Permalink
Merge 3659e1c into d1be4ea
Browse files Browse the repository at this point in the history
  • Loading branch information
jacogr committed Aug 11, 2019
2 parents d1be4ea + 3659e1c commit bc3061c
Show file tree
Hide file tree
Showing 28 changed files with 221 additions and 133 deletions.
8 changes: 7 additions & 1 deletion packages/types/src/codec/Compact.spec.ts
Expand Up @@ -113,7 +113,13 @@ describe('Compact', (): void => {
).toEqual(64);
});

it('has the correct encodedLength for constructor values (BlockNumber)', (): void => {
it('has the correct encodedLength for constructor values (string BlockNumber)', (): void => {
expect(
new Compact('BlockNumber', 0xfffffff9).encodedLength
).toEqual(5);
});

it('has the correct encodedLength for constructor values (class BlockNumber)', (): void => {
expect(
new Compact(ClassOf('BlockNumber'), 0xfffffff9).encodedLength
).toEqual(5);
Expand Down
9 changes: 5 additions & 4 deletions packages/types/src/codec/Compact.ts
Expand Up @@ -2,12 +2,13 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.

import { AnyNumber, Constructor } from '../types';
import { AnyNumber, Constructor, InterfaceTypes } from '../types';

import BN from 'bn.js';
import { bnToBn, compactAddLength, compactFromU8a, compactStripLength, compactToU8a, hexToBn, isBn, isHex, isNumber, isString } from '@polkadot/util';
import { DEFAULT_BITLENGTH } from '@polkadot/util/compact/defaults';

import { typeToConstructor } from './utils';
import { UIntBitLength } from './AbstractInt';
import CodecDate from './Date';
import UInt from './UInt';
Expand All @@ -26,11 +27,11 @@ export type CompactEncodable = UInt | CodecDate; // FIXME is there a way to do i
* a number and making the compact representation thereof
*/
export default class Compact<T extends CompactEncodable> extends Base<T> {
public constructor (Type: Constructor<T>, value: Compact<T> | AnyNumber = 0) {
super(Compact.decodeCompact<T>(Type, value));
public constructor (Type: Constructor<T> | InterfaceTypes, value: Compact<T> | AnyNumber = 0) {
super(Compact.decodeCompact<T>(typeToConstructor(Type), value));
}

public static with<T extends CompactEncodable> (Type: Constructor<T>): Constructor<Compact<T>> {
public static with<T extends CompactEncodable> (Type: Constructor<T> | InterfaceTypes): Constructor<Compact<T>> {
return class extends Compact<T> {
public constructor (value?: any) {
super(Type, value);
Expand Down
9 changes: 9 additions & 0 deletions packages/types/src/codec/EnumType.spec.ts
Expand Up @@ -47,6 +47,15 @@ describe('Enum', (): void => {
).toEqual('4660'); // 0x1234 in decimal
});

it('decodes from hex (string types)', (): void => {
expect(
new Enum(
{ foo: 'Text', bar: 'u32' },
'0x0134120000'
).value.toString()
).toEqual('4660'); // 0x1234 in decimal
});

it('decodes from a JSON input (mixed case)', (): void => {
expect(
new Enum(
Expand Down
11 changes: 6 additions & 5 deletions packages/types/src/codec/EnumType.ts
Expand Up @@ -2,11 +2,12 @@
// 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 } from '../types';
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> {
Expand Down Expand Up @@ -38,7 +39,7 @@ export default class Enum extends Base<Codec> {

private _isBasic: boolean;

public constructor (def: TypesDef | string[], value?: any, index?: number | Enum) {
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);

Expand All @@ -50,10 +51,10 @@ export default class Enum extends Base<Codec> {
this._index = this._indexes.indexOf(decoded.index) || 0;
}

private static extractDef (def: TypesDef | string[]): { def: TypesDef; isBasic: boolean } {
private static extractDef (def: Record<string, InterfaceTypes | Constructor> | string[]): { def: TypesDef; isBasic: boolean } {
if (!Array.isArray(def)) {
return {
def,
def: mapToTypeMap(def),
isBasic: false
};
}
Expand Down Expand Up @@ -126,7 +127,7 @@ export default class Enum extends Base<Codec> {
};
}

public static with (Types: TypesDef | string[]): EnumConstructor<Enum> {
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);
Expand Down
14 changes: 9 additions & 5 deletions packages/types/src/codec/Linkage.ts
Expand Up @@ -2,22 +2,26 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.

import { Struct, Option, Tuple, Vec } from '.';
import { Constructor, Codec } from '../types';
import { Constructor, Codec, InterfaceTypes } from '../types';

type TypeWithValues = [Constructor, any[]];
import Option from './Option';
import Struct from './Struct';
import Tuple from './Tuple';
import Vec from './Vec';

type TypeWithValues = [Constructor | InterfaceTypes, any[]];

const EMPTY = new Uint8Array();

export default class Linkage<T extends Codec> extends Struct {
public constructor (Type: Constructor, value?: any) {
public constructor (Type: Constructor | InterfaceTypes, value?: any) {
super({
previous: Option.with(Type),
next: Option.with(Type)
}, value);
}

public static withKey<O extends Codec> (Type: Constructor): Constructor<Linkage<O>> {
public static withKey<O extends Codec> (Type: Constructor | InterfaceTypes): Constructor<Linkage<O>> {
return class extends Linkage<O> {
public constructor (value?: any) {
super(Type, value);
Expand Down
6 changes: 6 additions & 0 deletions packages/types/src/codec/Option.spec.ts
Expand Up @@ -37,6 +37,12 @@ describe('Option', (): void => {
).toEqual('hello');
});

it('converts an option to an option (strings)', (): void => {
expect(
new Option('Text', new Option('Text', 'hello')).toString()
).toEqual('hello');
});

it('converts correctly from hex with toHex (Bytes)', (): void => {
// Option<Bytes> for a parachain head, however, this is effectively an
// Option<Option<Bytes>> (hence the length, since it is from storage)
Expand Down
18 changes: 10 additions & 8 deletions packages/types/src/codec/Option.ts
Expand Up @@ -2,11 +2,13 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.

import { Codec, Constructor, InterfaceTypes } from '../types';

import { isNull, isU8a, isUndefined, u8aToHex } from '@polkadot/util';

import Base from './Base';
import { Codec, Constructor } from '../types';
import Null from '../primitive/Null';
import { typeToConstructor } from './utils';
import Base from './Base';

/**
* @name Option
Expand All @@ -19,12 +21,12 @@ import Null from '../primitive/Null';
export default class Option<T extends Codec> extends Base<T> {
private _Type: Constructor;

public constructor (Type: Constructor, value?: any) {
super(
Option.decodeOption(Type, value)
);
public constructor (Type: Constructor | InterfaceTypes, value?: any) {
const Clazz = typeToConstructor(Type);

super(Option.decodeOption(Clazz, value));

this._Type = Type;
this._Type = Clazz;
}

public static decodeOption (Type: Constructor, value?: any): Codec {
Expand All @@ -46,7 +48,7 @@ export default class Option<T extends Codec> extends Base<T> {
return new Type(value);
}

public static with<O extends Codec> (Type: Constructor): Constructor<Option<O>> {
public static with<O extends Codec> (Type: Constructor | InterfaceTypes): Constructor<Option<O>> {
return class extends Option<O> {
public constructor (value?: any) {
super(Type, value);
Expand Down
12 changes: 12 additions & 0 deletions packages/types/src/codec/Struct.spec.ts
Expand Up @@ -105,6 +105,18 @@ describe('Struct', (): void => {
).toEqual('{"txt":"foo","u32":1193046}');
});

it('provides a clean toString() (string types)', (): void => {
expect(
new (
Struct.with({
txt: 'Text',
num: 'u32',
cls: U32
})
)({ txt: 'foo', num: 0x123456, cls: 123 }).toString()
).toEqual('{"txt":"foo","num":1193046,"cls":123}');
});

it('exposes the properties on the object', (): void => {
const struct = new (
Struct.with({
Expand Down
45 changes: 18 additions & 27 deletions packages/types/src/codec/Struct.ts
Expand Up @@ -2,13 +2,15 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.

import { AnyJsonObject, Codec, Constructor, ConstructorDef, IHash } from '../types';
import { AnyJsonObject, Codec, Constructor, ConstructorDef, IHash, InterfaceTypes } from '../types';

import { hexToU8a, isHex, isObject, isU8a, isUndefined, u8aConcat, u8aToHex } from '@polkadot/util';
import { blake2AsU8a } from '@polkadot/util-crypto';

import U8a from './U8a';
import { compareMap, decodeU8a } from './utils';
import { compareMap, decodeU8a, mapToTypeMap } from './utils';

type TypesDef<T = Codec> = Record<string, InterfaceTypes | Constructor<T>>;

/**
* @name Struct
Expand All @@ -22,7 +24,7 @@ import { compareMap, decodeU8a } from './utils';
*/
export default class Struct<
// The actual Class structure, i.e. key -> Class
S extends ConstructorDef = ConstructorDef,
S extends TypesDef = TypesDef,
// internal type, instance of classes mapped by key
T extends { [K in keyof S]: Codec } = { [K in keyof S]: Codec },
// input values, mapped by key can be anything (construction)
Expand All @@ -31,17 +33,16 @@ export default class Struct<
E extends { [K in keyof S]: string } = { [K in keyof S]: string }> extends Map<keyof S, Codec> implements Codec {
protected _jsonMap: Map<keyof S, string>;

protected _Types: S;
protected _Types: ConstructorDef;

public constructor (Types: S, value: V | Map<any, any> | any[] | string = {} as unknown as V, jsonMap: Map<keyof S, string> = new Map()) {
const decoded = Struct.decodeStruct<S, V, T>(Types, value, jsonMap);
const Clazzes = mapToTypeMap(Types);
const decoded = Struct.decodeStruct(Clazzes, value, jsonMap);

super(
Object.entries(decoded)
);
super(Object.entries(decoded as any));

this._jsonMap = jsonMap;
this._Types = Types;
this._Types = Clazzes;
}

/**
Expand All @@ -59,11 +60,7 @@ export default class Struct<
* `Object.keys(Types)`
* @param jsonMap
*/
private static decodeStruct<
S extends ConstructorDef,
_,
T extends { [K in keyof S]: Codec }
> (Types: S, value: any, jsonMap: Map<keyof S, string>): T {
private static decodeStruct <T> (Types: ConstructorDef, value: any, jsonMap: Map<any, string>): T {
// l.debug(() => ['Struct.decode', { Types, value }]);

if (isHex(value)) {
Expand All @@ -72,7 +69,7 @@ export default class Struct<
const values = decodeU8a(value, Object.values(Types));

// Transform array of values to {key: value} mapping
return Object.keys(Types).reduce((raw: T, key: keyof S, index): T => {
return Object.keys(Types).reduce((raw, key, index): T => {
// TS2322: Type 'Codec' is not assignable to type 'T[keyof S]'.
(raw as any)[key] = values[index];

Expand All @@ -86,30 +83,26 @@ export default class Struct<
return Struct.decodeStructFromObject(Types, value, jsonMap);
}

private static decodeStructFromObject<
S extends ConstructorDef,
_,
T extends { [K in keyof S]: Codec }
> (Types: S, value: any, jsonMap: Map<keyof S, string>): T {
return Object.keys(Types).reduce((raw: T, key: keyof S, index): T => {
private static decodeStructFromObject <T> (Types: ConstructorDef, value: any, jsonMap: Map<any, string>): T {
return Object.keys(Types).reduce((raw, key, index): T => {
// 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;

try {
if (Array.isArray(value)) {
raw[key] = value[index] instanceof Types[key]
// TS2322: Type 'Codec' is not assignable to type 'T[keyof S]'.
(raw as any)[key] = value[index] instanceof Types[key]
? value[index]
: new Types[key](value[index]);
} else if (value instanceof Map) {
const mapped = value.get(jsonKey);

// TS2322: Type 'Codec' is not assignable to type 'T[keyof S]'.
(raw as any)[key] = mapped instanceof Types[key]
? mapped
: new Types[key](mapped);
} else if (isObject(value)) {
raw[key] = value[jsonKey as string] instanceof Types[key]
(raw as any)[key] = value[jsonKey as string] instanceof Types[key]
? value[jsonKey as string]
: new Types[key](value[jsonKey as string]);
} else {
Expand All @@ -123,9 +116,7 @@ export default class Struct<
}, {} as unknown as T);
}

public static with<
S extends ConstructorDef
> (Types: S): Constructor<Struct<S>> {
public static with<S extends TypesDef> (Types: S): Constructor<Struct<S>> {
return class extends Struct<S> {
public constructor (value?: any, jsonMap?: Map<keyof S, string>) {
super(Types, value, jsonMap);
Expand Down
9 changes: 9 additions & 0 deletions packages/types/src/codec/Tuple.spec.ts
Expand Up @@ -55,6 +55,15 @@ describe('Tuple', (): void => {
testEncode('toString', '["bazzing",69]');
});

it('creates from string types', (): void => {
expect(
new Tuple(
['Text', 'u32', U32],
['foo', 69, 42]
).toString()
).toEqual('["foo",69,42]');
});

it.skip('creates properly via actual hex string', (): void => {
Call.injectMethods(extrinsics);

Expand Down

0 comments on commit bc3061c

Please sign in to comment.