Construct toRawType using internal types (#966)
* Construct toRawType using internal types * typo * Struct test for with + toRawType * Tuple tests for toRawType * Remove extra empty check, already handled * EnumType with sane toRawType * Sane toRawType representation for Set * Use JSON.stringify inside Struct toRawType * Extrinsic toRawType yields Extrinsic (like a primitive) * Block toRawType test
This commit is contained in:
@@ -211,4 +211,18 @@ describe('Enum', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('toRawType', () => {
|
||||
it('has a sane output for basic enums', () => {
|
||||
expect(
|
||||
new Enum(['foo', 'bar']).toRawType()
|
||||
).toEqual(JSON.stringify({ _enum: ['foo', 'bar'] }));
|
||||
});
|
||||
|
||||
it('has a sane output for types enums', () => {
|
||||
expect(
|
||||
new Enum({ foo: Text, bar: U32 }).toRawType()
|
||||
).toEqual(JSON.stringify({ _enum: { foo: 'Text', bar: 'u32' } }));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -222,18 +222,15 @@ export default class Enum extends Base<Codec> implements Codec {
|
||||
* @description Returns the base runtime type name for this instance
|
||||
*/
|
||||
toRawType (): string {
|
||||
const kv = this._isBasic
|
||||
? Object.keys(this._def).map((key) =>
|
||||
`"${key}"`
|
||||
)
|
||||
: Object.entries(this._def).map(([key, Type]) =>
|
||||
`"${key}":"${new Type().toRawType()}"`
|
||||
);
|
||||
const braces = this._isBasic
|
||||
? '[]'
|
||||
: '{}';
|
||||
const _enum = this._isBasic
|
||||
? Object.keys(this._def)
|
||||
: Object.entries(this._def).reduce((result, [key, Type]) => {
|
||||
result[key] = new Type().toRawType();
|
||||
|
||||
return `{"_enum":${braces[0]}${kv.join(',')}${braces[1]}}`;
|
||||
return result;
|
||||
}, {} as { [index: string]: string });
|
||||
|
||||
return JSON.stringify({ _enum });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,10 +17,14 @@ import Null from '../primitive/Null';
|
||||
* with a value if/as required/found.
|
||||
*/
|
||||
export default class Option<T extends Codec> extends Base<T> implements Codec {
|
||||
private _Type: Constructor;
|
||||
|
||||
constructor (Type: Constructor, value?: any) {
|
||||
super(
|
||||
Option.decodeOption(Type, value)
|
||||
);
|
||||
|
||||
this._Type = Type;
|
||||
}
|
||||
|
||||
static decodeOption (Type: Constructor, value?: any): Codec {
|
||||
@@ -115,7 +119,7 @@ export default class Option<T extends Codec> extends Base<T> implements Codec {
|
||||
* @description Returns the base runtime type name for this instance
|
||||
*/
|
||||
toRawType (): string {
|
||||
return `Option<${this.raw.toRawType()}>`;
|
||||
return `Option<${new this._Type().toRawType()}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -91,4 +91,12 @@ describe('Set', () => {
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('has a sane toRawType representation', () => {
|
||||
expect(
|
||||
new Set({ a: 1, b: 2, c: 345 }).toRawType()
|
||||
).toEqual(JSON.stringify({
|
||||
_set: { a: 1, b: 2, c: 345 }
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -149,12 +149,8 @@ export default class CodecSet extends Set<string> implements Codec {
|
||||
* @description Returns the base runtime type name for this instance
|
||||
*/
|
||||
toRawType (): string {
|
||||
const kv = Object.entries(this._setValues).map(([key, value]) =>
|
||||
`"${key}":${value}` // JSON format
|
||||
);
|
||||
|
||||
// FIXME We don't cater for this in createType as of yet
|
||||
return `{"_set":{${kv.join(',')}}}`;
|
||||
return JSON.stringify({ _set: this._setValues });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,10 +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 AccountId from '../primitive/AccountId';
|
||||
import Text from '../primitive/Text';
|
||||
import U32 from '../primitive/U32';
|
||||
import Balance from '../type/Balance';
|
||||
import BlockNumber from '../type/BlockNumber';
|
||||
import { CodecTo } from '../types';
|
||||
import Compact from './Compact';
|
||||
import Option from './Option';
|
||||
import Struct from './Struct';
|
||||
import Vector from './Vector';
|
||||
@@ -183,4 +186,40 @@ describe('Struct', () => {
|
||||
}, { blockNumber: '0x1234567890abcdef' }).toString()
|
||||
).toEqual('{"blockNumber":"0x1234567890abcdef"}');
|
||||
});
|
||||
|
||||
it('generates sane toRawType', () => {
|
||||
expect(
|
||||
new Struct({
|
||||
accountId: AccountId,
|
||||
balance: Balance,
|
||||
blockNumber: BlockNumber,
|
||||
compactNumber: Compact.with(BlockNumber),
|
||||
optionNumber: Option.with(BlockNumber),
|
||||
counter: U32,
|
||||
vector: Vector.with(AccountId)
|
||||
}).toRawType()
|
||||
).toEqual(JSON.stringify({
|
||||
accountId: 'AccountId',
|
||||
balance: 'Balance',
|
||||
blockNumber: 'u64',
|
||||
compactNumber: 'Compact<u64>',
|
||||
optionNumber: 'Option<u64>',
|
||||
counter: 'u32',
|
||||
vector: 'Vec<AccountId>'
|
||||
}));
|
||||
});
|
||||
|
||||
it('generates sane toRawType (via with)', () => {
|
||||
const Type = Struct.with({
|
||||
accountId: AccountId,
|
||||
balance: Balance
|
||||
});
|
||||
|
||||
expect(
|
||||
new Type().toRawType()
|
||||
).toEqual(JSON.stringify({
|
||||
accountId: 'AccountId',
|
||||
balance: 'Balance'
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ 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: E;
|
||||
protected _Types: S;
|
||||
|
||||
constructor (Types: S, value: V | Map<any, any> | Array<any> = {} as V, jsonMap: Map<keyof S, string> = new Map()) {
|
||||
const decoded = Struct.decodeStruct<S, V, T>(Types, value, jsonMap);
|
||||
@@ -38,14 +38,7 @@ export default class Struct<
|
||||
);
|
||||
|
||||
this._jsonMap = jsonMap;
|
||||
this._Types = (Object
|
||||
.keys(Types) as Array<keyof S>)
|
||||
.reduce((result: E, key) => {
|
||||
// TS2322: Type 'string' is not assignable to type 'E[keyof S]'.
|
||||
(result as any)[key] = Types[key].name;
|
||||
|
||||
return result;
|
||||
}, {} as E);
|
||||
this._Types = Types;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,7 +163,13 @@ export default class Struct<
|
||||
* @description Returns the Type description to sthe structure
|
||||
*/
|
||||
get Type (): E {
|
||||
return this._Types;
|
||||
return (Object
|
||||
.entries(this._Types) as Array<[keyof S, Constructor]>)
|
||||
.reduce((result: E, [key, Type]) => {
|
||||
(result as any)[key] = Type.name;
|
||||
|
||||
return result;
|
||||
}, {} as E);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,11 +235,13 @@ export default class Struct<
|
||||
* @description Returns the base runtime type name for this instance
|
||||
*/
|
||||
toRawType (): string {
|
||||
const kv = [...this.entries()].map(([key, value]) =>
|
||||
`"${key}":"${value.toRawType()}"` // double-quotes, JSON
|
||||
);
|
||||
return JSON.stringify(
|
||||
Object.entries(this._Types).reduce((result, [key, Type]) => {
|
||||
result[key] = new Type().toRawType();
|
||||
|
||||
return `{${kv.join(',')}}`;
|
||||
return result;
|
||||
}, {} as { [index: string]: string })
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -94,4 +94,18 @@ describe('Tuple', () => {
|
||||
expect(tuple.eq(['bazzing', 72])).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toRawType', () => {
|
||||
it('generates sane value with array types', () => {
|
||||
expect(
|
||||
new Tuple([U32, BlockNumber]).toRawType()
|
||||
).toEqual('(u32,u64)');
|
||||
});
|
||||
|
||||
it('generates sane value with object types', () => {
|
||||
expect(
|
||||
new Tuple({ number: U32, blockNumber: BlockNumber }).toRawType()
|
||||
).toEqual('(u32,u64)');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ type TupleConstructors = Array<Constructor> | {
|
||||
export default class Tuple extends AbstractArray<Codec> {
|
||||
private _Types: TupleConstructors;
|
||||
|
||||
constructor (Types: TupleConstructors, value: any) {
|
||||
constructor (Types: TupleConstructors, value?: any) {
|
||||
super(
|
||||
...Tuple.decodeTuple(Types, value)
|
||||
);
|
||||
@@ -83,9 +83,9 @@ export default class Tuple extends AbstractArray<Codec> {
|
||||
toRawType (): string {
|
||||
const types = (
|
||||
Array.isArray(this._Types)
|
||||
? this._Types.map((Type) => new Type().toRawType())
|
||||
: Object.keys(this._Types)
|
||||
);
|
||||
? this._Types
|
||||
: Object.values(this._Types)
|
||||
).map((Type) => new Type().toRawType());
|
||||
|
||||
return `(${types.join(',')})`;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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 extrinsics from '@polkadot/extrinsics/static';
|
||||
|
||||
import Method from '../primitive/Method';
|
||||
import Block from './Block';
|
||||
|
||||
describe('Block', () => {
|
||||
beforeEach(() => {
|
||||
Method.injectMethods(extrinsics);
|
||||
});
|
||||
|
||||
it('has a valid toRawType', () => {
|
||||
expect(
|
||||
new Block().toRawType()
|
||||
).toEqual(
|
||||
// each of the containing structures have been stringified on their own
|
||||
JSON.stringify({
|
||||
header: JSON.stringify({
|
||||
parentHash: 'H256',
|
||||
number: 'Compact<u64>',
|
||||
stateRoot: 'H256',
|
||||
extrinsicsRoot: 'H256',
|
||||
digest: JSON.stringify({
|
||||
logs: 'Vec<{"_enum":{"Other":"Bytes","AuthoritiesChange":"Vec<AccountId>","ChangesTrieRoot":"H256","Seal":"(u64,H512)","Consensus":"(u32,Bytes)"}}>'
|
||||
})
|
||||
}),
|
||||
extrinsics: 'Vec<Extrinsic>'
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -10,6 +10,15 @@ import U128 from '../primitive/U128';
|
||||
* The Substrate Balance representation as a [[U128]].
|
||||
*/
|
||||
export default class Balance extends U128 {
|
||||
/**
|
||||
* @description Returns the base runtime type name for this instance
|
||||
*/
|
||||
toRawType (): string {
|
||||
// NOTE Balance we treat as a special case, don't return the base u128 - there
|
||||
// is typically special processing downstream, i.e. different inputs, it gets
|
||||
// treated as a primitive in this case
|
||||
return 'Balance';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -197,6 +197,14 @@ export default class Extrinsic extends Struct implements IExtrinsic {
|
||||
return this.toHex();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the base runtime type name for this instance
|
||||
*/
|
||||
toRawType (): string {
|
||||
// We are treating this in the same way we do a primitive, this is known
|
||||
return 'Extrinsic';
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
|
||||
@@ -111,9 +111,9 @@ export default class ExtrinsicEra extends Enum implements IExtrinsicEra {
|
||||
*/
|
||||
export class ImmortalEra extends U8a {
|
||||
constructor (value?: AnyU8a) {
|
||||
super(value);
|
||||
|
||||
assert(this.eq(VALID_IMMORTAL), `IMMORTAL: expected ${VALID_IMMORTAL.toHex()}, found ${this.toHex()}`);
|
||||
// For immortals, we always provide the known value (i.e. treated as a
|
||||
// constant no matter how it is constructed - it is a fixed structure)
|
||||
super(VALID_IMMORTAL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +155,8 @@ export class MortalEra extends Tuple {
|
||||
const quantizedPhase = phase / quantizeFactor * quantizeFactor;
|
||||
|
||||
return [new U64(calPeriod), new U64(quantizedPhase)];
|
||||
} else if (!value) {
|
||||
return [new U64(), new U64()];
|
||||
}
|
||||
|
||||
throw new Error('Invalid data passed to Mortal era');
|
||||
|
||||
Reference in New Issue
Block a user