Fix some Codeclimate smells (#450)

* Fix some Codeclimate smells

* Cleanup Metadata complexity

* Cleanup uniqueTypes

* Bump deps
This commit is contained in:
Jaco Greeff
2018-12-08 15:31:54 +01:00
committed by GitHub
parent b99ff21a67
commit 448a729d70
37 changed files with 691 additions and 698 deletions
+1 -1
View File
@@ -33,6 +33,6 @@
"@polkadot/jsonrpc": "^0.33.5",
"@polkadot/rpc-provider": "^0.33.5",
"@polkadot/types": "^0.33.5",
"@polkadot/util": "^0.33.9"
"@polkadot/util": "^0.33.11"
}
}
+3 -3
View File
@@ -30,10 +30,10 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-provider#readme",
"dependencies": {
"@babel/runtime": "^7.1.5",
"@polkadot/keyring": "^0.33.9",
"@polkadot/keyring": "^0.33.11",
"@polkadot/storage": "^0.33.5",
"@polkadot/util": "^0.33.9",
"@polkadot/util-crypto": "^0.33.9",
"@polkadot/util": "^0.33.11",
"@polkadot/util-crypto": "^0.33.11",
"@types/nock": "^9.3.0",
"eventemitter3": "^3.1.0",
"isomorphic-fetch": "^2.2.1",
+3 -5
View File
@@ -149,11 +149,9 @@ export default class WsProvider implements WSProviderInterface {
const json = this.coder.encodeJson(method, params);
const id = this.coder.getId();
const callback = (error?: Error | null, result?: any) => {
if (error) {
reject(error);
} else {
resolve(result);
}
error
? reject(error)
: resolve(result);
};
l.debug(() => ['calling', method, params, json, !!subscription]);
+1 -1
View File
@@ -12,6 +12,6 @@
"dependencies": {
"@babel/runtime": "^7.1.5",
"@polkadot/types": "^0.33.5",
"@polkadot/util": "^0.33.9"
"@polkadot/util": "^0.33.11"
}
}
@@ -3,7 +3,7 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import Metadata from '@polkadot/types/Metadata';
import json from '@polkadot/types/Metadata.rpc';
import json from '@polkadot/types/Metadata/static';
import fromMetadata from './fromMetadata';
+1 -1
View File
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { RuntimeModuleMetadata } from '@polkadot/types/Metadata';
import { RuntimeModuleMetadata } from '@polkadot/types/Metadata/Modules';
import { Extrinsics, ModuleExtrinsics } from '@polkadot/types/Method';
import { Metadata } from '@polkadot/types/index';
@@ -16,7 +16,8 @@ describe('extrinsics', () => {
10101
).sign(
keyring.nobody,
1234
1234,
new Uint8Array()
).toU8a(true)
).toEqual(
new Uint8Array([
+1 -1
View File
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import metadataRpc from '@polkadot/types/Metadata.rpc';
import metadataRpc from '@polkadot/types/Metadata/static';
import Metadata from '@polkadot/types/Metadata';
import fromMetadata from './fromMetadata';
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { FunctionMetadata } from '@polkadot/types/Metadata';
import { FunctionMetadata } from '@polkadot/types/Metadata/Modules';
import { ExtrinsicFunction } from '@polkadot/types/Method';
import { Extrinsic, Method } from '@polkadot/types/index';
import { assert } from '@polkadot/util';
+3 -3
View File
@@ -30,9 +30,9 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/type-storage#readme",
"dependencies": {
"@babel/runtime": "^7.1.5",
"@polkadot/keyring": "^0.33.9",
"@polkadot/keyring": "^0.33.11",
"@polkadot/types": "^0.33.5",
"@polkadot/util": "^0.33.9",
"@polkadot/util-crypto": "^0.33.9"
"@polkadot/util": "^0.33.11",
"@polkadot/util-crypto": "^0.33.11"
}
}
@@ -3,7 +3,7 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import Metadata from '@polkadot/types/Metadata';
import json from '@polkadot/types/Metadata.rpc';
import json from '@polkadot/types/Metadata/static';
import fromMetadata from './fromMetadata';
+1 -1
View File
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import metadataRpc from '@polkadot/types/Metadata.rpc';
import metadataRpc from '@polkadot/types/Metadata/static';
import Metadata from '@polkadot/types/Metadata';
import fromMetadata from './fromMetadata';
+1 -1
View File
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { StorageFunctionMetadata, StorageFunctionModifier, StorageFunctionType } from '@polkadot/types/Metadata';
import { StorageFunctionMetadata, StorageFunctionModifier, StorageFunctionType } from '@polkadot/types/Metadata/Modules';
import { StorageFunction } from '@polkadot/types/StorageKey';
import Text from '@polkadot/types/Text';
import Vector from '@polkadot/types/codec/Vector';
@@ -10,7 +10,7 @@ describe('createFunction', () => {
createFunction(
'Timestamp',
'Now',
{ type: {} }
{ type: {} } as any
)()
).toEqual(
Uint8Array.from([64, 14, 73, 68, 207, 217, 141, 111, 76, 195, 116, 209, 111, 90, 78, 63, 156]) // Length-prefixed
@@ -22,7 +22,7 @@ describe('createFunction', () => {
createFunction(
'Substrate',
':auth:len',
{ type: {} },
{ type: {} } as any,
{
isUnhashed: true,
method: 'authorityCount'
@@ -4,7 +4,7 @@
import Compact from '@polkadot/types/codec/Compact';
import { createType } from '@polkadot/types/codec';
import { StorageFunctionMetadata } from '@polkadot/types/Metadata';
import { StorageFunctionMetadata } from '@polkadot/types/Metadata/Modules';
import { StorageFunction } from '@polkadot/types/StorageKey';
import { Text } from '@polkadot/types/index';
import { assert, isNull, isUndefined, stringLowerFirst, stringToU8a, u8aConcat } from '@polkadot/util';
@@ -25,12 +25,7 @@ export interface CreateItemOptions {
* are not known at runtime (from state_getMetadata), they need to be supplied
* by us manually at compile time.
*/
export default function createFunction (
section: Text,
method: Text,
meta: StorageFunctionMetadata,
options: CreateItemOptions = {}
): StorageFunction {
export default function createFunction (section: Text | string, method: Text | string, meta: StorageFunctionMetadata, options: CreateItemOptions = {}): StorageFunction {
let storageFn: any;
// NOTE Here we assume everything in the 'Substrate' prefix is unhashed. (Despite not passing empty, i.e. '',
@@ -45,28 +40,22 @@ export default function createFunction (
// - storage.balances.freeBalance(address)
// - storage.timestamp.blockPeriod()
storageFn = (arg?: any): Uint8Array => {
const key = stringToU8a(`${section.toString()} ${method.toString()}`);
if (!meta.type.isMap) {
return Compact.addLengthPrefix(
xxhashAsU8a(
stringToU8a(`${section.toString()} ${method.toString()}`),
128
)
xxhashAsU8a(key, 128)
);
}
assert(!isUndefined(arg) && !isNull(arg), `${meta.name} expects one argument`);
const type = meta.type.asMap.key.toString(); // Argument type, as string
const param = createType(type, arg).toU8a(true);
// StorageKey is a Bytes, so is length-prefixed
return Compact.addLengthPrefix(
xxhashAsU8a(
u8aConcat(
stringToU8a(`${section.toString()} ${method.toString()}`),
createType(type, arg).toU8a(true)
),
128
)
xxhashAsU8a(u8aConcat(key, param), 128)
);
};
}
@@ -74,8 +63,7 @@ export default function createFunction (
storageFn.meta = meta;
storageFn.method = stringLowerFirst((options.method || method).toString());
storageFn.section = stringLowerFirst(section.toString());
storageFn.toJSON = (): any =>
meta.toJSON();
storageFn.toJSON = (): any => meta.toJSON();
return storageFn as StorageFunction;
}
+2 -2
View File
@@ -30,7 +30,7 @@
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/types#readme",
"dependencies": {
"@babel/runtime": "^7.1.5",
"@polkadot/keyring": "^0.33.9",
"@polkadot/util": "^0.33.9"
"@polkadot/keyring": "^0.33.11",
"@polkadot/util": "^0.33.11"
}
}
+2 -1
View File
@@ -10,7 +10,8 @@ import Struct from './codec/Struct';
import Tuple from './codec/Tuple';
import U8aFixed from './codec/U8aFixed';
import { TypeDef, getTypeClass, getTypeDef } from './codec/createType';
import Metadata, { EventMetadata } from './Metadata';
import Metadata from './Metadata';
import { EventMetadata } from './Metadata/Events';
const EventTypes: { [index: string]: Constructor<EventData> } = {};
+1 -1
View File
@@ -10,7 +10,7 @@ import AccountId from './AccountId';
import Event from './Event';
import EventRecord from './EventRecord';
import Metadata from './Metadata';
import metadataRpc from './/Metadata.rpc';
import metadataRpc from './Metadata/static';
describe('EventRecord', () => {
beforeEach(() => {
+1 -1
View File
@@ -13,7 +13,7 @@ import Struct from './codec/Struct';
import Address from './Address';
import ExtrinsicSignature from './ExtrinsicSignature';
import Hash from './Hash';
import { FunctionMetadata } from './Metadata';
import { FunctionMetadata } from './Metadata/Modules';
import Method from './Method';
type ExtrinsicValue = {
-572
View File
@@ -1,572 +0,0 @@
// Copyright 2017-2018 @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 { AnyNumber } from './types';
import { assert, hexToU8a, isHex, isU8a, isUndefined } from '@polkadot/util';
import { getTypeDef, TypeDef, TypeDefInfo } from './codec/createType';
import Compact from './codec/Compact';
import Enum from './codec/Enum';
import EnumType from './codec/EnumType';
import Option from './codec/Option';
import Struct from './codec/Struct';
import Tuple from './codec/Tuple';
import Vector from './codec/Vector';
import Text from './Text';
import Type from './Type';
import U16 from './U16';
import * as allTypes from './index';
// Decodes the runtime metadata as passed through from the `state_getMetadata` call. This
// 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)
// Quick and dirty flatten (.flat() not available)
function flattenUniq (list: Array<any>): Array<any> {
const flat = list.reduce((result, entry) => {
return result.concat(
Array.isArray(entry)
? flattenUniq(entry)
: entry
);
}, []);
return [...new Set(flat)]
.filter((value: any) => value)
.sort();
}
export class OuterDispatchCall extends Struct {
constructor (value?: any) {
super({
name: Text,
prefix: Text,
index: U16
}, value);
}
/**
* @description The [[U16]] index for the call
*/
get index (): U16 {
return this.get('index') as U16;
}
/**
* @description The name for the call
*/
get name (): Text {
return this.get('name') as Text;
}
/**
* @description The call prefix (or section)
*/
get prefix (): Text {
return this.get('prefix') as Text;
}
}
export class OuterDispatchMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
calls: Vector.with(OuterDispatchCall)
}, value);
}
/**
* @description The [[OuterDispathCall]] wrapped
*/
get calls (): Vector<OuterDispatchCall> {
return this.get('calls') as Vector<OuterDispatchCall>;
}
/**
* @description The name for the dispatch
*/
get name (): Text {
return this.get('name') as Text;
}
}
export class EventMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
arguments: Vector.with(Type),
documentation: Vector.with(Text)
}, value);
}
/**
* @description The arguments of [[Type]]
*/
get arguments (): Vector<Type> {
return this.get('arguments') as Vector<Type>;
}
/**
* @description The [[Text]] documentation
*/
get documentation (): Vector<Text> {
return this.get('documentation') as Vector<Text>;
}
/**
* @description The name for the event
*/
get name (): Text {
return this.get('name') as Text;
}
}
export class OuterEventMetadataEvent extends Tuple {
constructor (value?: any) {
super([
Text,
Vector.with(EventMetadata)
], value);
}
/**
* @description The [[EventMetadata]]
*/
get events (): Vector<EventMetadata> {
return this[1] as Vector<EventMetadata>;
}
/**
* @description The name of the section
*/
get name (): Text {
return this[0] as Text;
}
}
export class OuterEventMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
events: Vector.with(OuterEventMetadataEvent)
}, value);
}
/**
* @description The [[OuterEventMetadataEvent]]
*/
get events (): Vector<OuterEventMetadataEvent> {
return this.get('events') as Vector<OuterEventMetadataEvent>;
}
/**
* @description The name of the event
*/
get name (): Text {
return this.get('name') as Text;
}
}
export class FunctionArgumentMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
type: Type
}, value);
}
/**
* @description The argument name
*/
get name (): Text {
return this.get('name') as Text;
}
/**
* @description The [[Type]]
*/
get type (): Type {
return this.get('type') as Type;
}
}
export class FunctionMetadata extends Struct {
constructor (value?: any) {
super({
id: U16,
name: Text,
arguments: Vector.with(FunctionArgumentMetadata),
documentation: Vector.with(Text)
}, value);
}
/**
* @description The [[FunctionArgumentMetadata]] for arguments
*/
get arguments (): Vector<FunctionArgumentMetadata> {
return this.get('arguments') as Vector<FunctionArgumentMetadata>;
}
/**
* @description The [[Text]] documentation
*/
get documentation (): Vector<Text> {
return this.get('documentation') as Vector<Text>;
}
/**
* @description The `[sectionIndex, methodIndex]` call id
*/
get id (): U16 {
return this.get('id') as U16;
}
/**
* @description The call name
*/
get name (): Text {
return this.get('name') as Text;
}
}
export class CallMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
functions: Vector.with(FunctionMetadata)
}, value);
}
/**
* @description The functions available as [[FunctionMetadata]]
*/
get functions (): Vector<FunctionMetadata> {
return this.get('functions') as Vector<FunctionMetadata>;
}
/**
* @description The section name
*/
get name (): Text {
return this.get('name') as Text;
}
}
export class ModuleMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
call: CallMetadata
}, value);
}
/**
* @description The calls as [[CallMetadata]]
*/
get call (): CallMetadata {
return this.get('call') as CallMetadata;
}
/**
* @description The name
*/
get name (): Text {
return this.get('name') as Text;
}
}
export class StorageFunctionModifier extends Enum {
constructor (value?: any) {
super(['None', 'Default', 'Required'], value);
}
}
export class StorageFunctionType$Map extends Struct {
constructor (value?: any) {
super({
key: Type,
value: Type
}, value);
}
/**
* @description The mapped key as [[Type]]
*/
get key (): Type {
return this.get('key') as Type;
}
/**
* @description The mapped value as [[Type]]
*/
get value (): Type {
return this.get('value') as Type;
}
}
export class StorageFunctionType extends EnumType<Type | StorageFunctionType$Map> {
constructor (value?: any, index?: number) {
super([
Type,
StorageFunctionType$Map
], value, index);
}
/**
* @description `true` if the storage entry is a map
*/
get isMap (): boolean {
return this.toNumber() === 1;
}
/**
* @description The value as a mapped value
*/
get asMap (): StorageFunctionType$Map {
return this.value as StorageFunctionType$Map;
}
/**
* @description The value as a [[Type]] value
*/
get asType (): Type {
return this.value as Type;
}
/**
* @description Returns the string representation of the value
*/
toString (): string {
return this.isMap
? this.asMap.value.toString()
: this.asType.toString();
}
}
type StorageFunctionMetadataValue = {
name?: string | Text,
modifier?: StorageFunctionModifier | AnyNumber,
type?: StorageFunctionType,
documentation?: Vector<Text> | Array<string>
};
export class StorageFunctionMetadata extends Struct {
constructor (value?: StorageFunctionMetadataValue) {
super({
name: Text,
modifier: StorageFunctionModifier,
type: StorageFunctionType,
documentation: Vector.with(Text)
}, value);
}
/**
* @description The [[Text]] documentation
*/
get documentation (): Vector<Text> {
return this.get('documentation') as Vector<Text>;
}
/**
* @description The key name
*/
get name (): Text {
return this.get('name') as Text;
}
/**
* @description The modifier
*/
get modifier (): StorageFunctionModifier {
return this.get('modifier') as StorageFunctionModifier;
}
/**
* @description The [[StorageFunctionType]]
*/
get type (): StorageFunctionType {
return this.get('type') as StorageFunctionType;
}
}
export class StorageMetadata extends Struct {
constructor (value?: any) {
super({
prefix: Text,
functions: Vector.with(StorageFunctionMetadata)
}, value);
}
/**
* @description The [[StorageFunctionMetadata]] for the section
*/
get functions (): Vector<StorageFunctionMetadata> {
return this.get('functions') as Vector<StorageFunctionMetadata>;
}
/**
* @description The section prefix
*/
get prefix (): Text {
return this.get('prefix') as Text;
}
}
export class RuntimeModuleMetadata extends Struct {
constructor (value?: any) {
super({
prefix: Text,
module: ModuleMetadata,
storage: Option.with(StorageMetadata)
}, value);
}
/**
* @description The [[ModuleMetadata]]
*/
get module (): ModuleMetadata {
return this.get('module') as ModuleMetadata;
}
/**
* @description The prefix
*/
get prefix (): Text {
return this.get('prefix') as Text;
}
/**
* @description The optional [[StorageMetadata]]
*/
get storage (): Option<StorageMetadata> {
return this.get('storage') as Option<StorageMetadata>;
}
}
/**
* @name Metadata
* @description
* The runtime metadata as a decoded structure
*/
export default class Metadata extends Struct {
constructor (value?: any) {
super({
outerEvent: OuterEventMetadata,
modules: Vector.with(RuntimeModuleMetadata),
outerDispatch: OuterDispatchMetadata
}, Metadata.decodeMetadata(value));
}
static decodeMetadata (value: string | Uint8Array | object): object | Uint8Array {
if (isHex(value)) {
// We receive this as an hex in the JSON output from the Node.
// Convert to u8a and use the U8a version to do the actual parsing.
return Metadata.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);
return value.length === (offset + length.toNumber())
? value.subarray(offset)
: value;
}
// Decode as normal struct
return value;
}
/**
* @description Wrapped [[OuterDispatchCall]]
*/
get calls (): Vector<OuterDispatchCall> {
return (this.get('outerDispatch') as OuterDispatchMetadata).calls;
}
/**
* @description Wrapped [[OuterEventMetadataEvent]]
*/
get events (): Vector<OuterEventMetadataEvent> {
return (this.get('outerEvent') as OuterEventMetadata).events;
}
/**
* @description Wrapped [[RuntimeModuleMetadata]]
*/
get modules (): Vector<RuntimeModuleMetadata> {
return this.get('modules') as Vector<RuntimeModuleMetadata>;
}
/**
* @description Helper to retrieve a list of all type that are found, sorted and de-deuplicated
*/
getUniqTypes (): Array<string> {
const events = this.events.map((module) =>
module.events.map((event) =>
event.arguments.map((argument) =>
argument.toString()
)
)
);
const storages = this.modules.map((module) =>
module.storage.isSome
? module.storage.unwrap().functions.map((fn) =>
fn.type.isMap
? [fn.type.asMap.key.toString(), fn.type.asMap.value.toString()]
: [fn.type.asType.toString()]
)
: []
);
const args = this.modules.map((module) =>
module.module.call.functions.map((fn) =>
fn.arguments.map((argument) =>
argument.type.toString()
)
)
);
const types = flattenUniq([events, storages, args]);
this.validateTypes(types);
return types;
}
private validateTypes (types: Array<string>): void {
const extractTypes = (types: Array<string>): Array<any> => {
return types.map((type) => {
const decoded = getTypeDef(type);
switch (decoded.info) {
case TypeDefInfo.Plain:
return decoded.type;
case TypeDefInfo.Compact:
case TypeDefInfo.Vector:
return extractTypes([(decoded.sub as TypeDef).type]);
case TypeDefInfo.Tuple:
return extractTypes(
(decoded.sub as Array<TypeDef>).map((sub) => sub.type)
);
default:
throw new Error('Unreachable');
}
});
};
const missing = flattenUniq(extractTypes(types)).filter((type) =>
isUndefined((allTypes as any)[type])
);
assert(missing.length === 0, `Unknown types found, no types for ${missing}`);
}
}
+62
View File
@@ -0,0 +1,62 @@
// Copyright 2017-2018 @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 Struct from '../codec/Struct';
import Vector from '../codec/Vector';
import Text from '../Text';
import U16 from '../U16';
export class OuterDispatchCall extends Struct {
constructor (value?: any) {
super({
name: Text,
prefix: Text,
index: U16
}, value);
}
/**
* @description The [[U16]] index for the call
*/
get index (): U16 {
return this.get('index') as U16;
}
/**
* @description The name for the call
*/
get name (): Text {
return this.get('name') as Text;
}
/**
* @description The call prefix (or section)
*/
get prefix (): Text {
return this.get('prefix') as Text;
}
}
export class OuterDispatchMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
calls: Vector.with(OuterDispatchCall)
}, value);
}
/**
* @description The [[OuterDispathCall]] wrapped
*/
get calls (): Vector<OuterDispatchCall> {
return this.get('calls') as Vector<OuterDispatchCall>;
}
/**
* @description The name for the dispatch
*/
get name (): Text {
return this.get('name') as Text;
}
}
+86
View File
@@ -0,0 +1,86 @@
// Copyright 2017-2018 @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 Struct from '../codec/Struct';
import Tuple from '../codec/Tuple';
import Vector from '../codec/Vector';
import Text from '../Text';
import Type from '../Type';
export class EventMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
arguments: Vector.with(Type),
documentation: Vector.with(Text)
}, value);
}
/**
* @description The arguments of [[Type]]
*/
get arguments (): Vector<Type> {
return this.get('arguments') as Vector<Type>;
}
/**
* @description The [[Text]] documentation
*/
get documentation (): Vector<Text> {
return this.get('documentation') as Vector<Text>;
}
/**
* @description The name for the event
*/
get name (): Text {
return this.get('name') as Text;
}
}
export class OuterEventMetadataEvent extends Tuple {
constructor (value?: any) {
super([
Text,
Vector.with(EventMetadata)
], value);
}
/**
* @description The [[EventMetadata]]
*/
get events (): Vector<EventMetadata> {
return this[1] as Vector<EventMetadata>;
}
/**
* @description The name of the section
*/
get name (): Text {
return this[0] as Text;
}
}
export class OuterEventMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
events: Vector.with(OuterEventMetadataEvent)
}, value);
}
/**
* @description The [[OuterEventMetadataEvent]]
*/
get events (): Vector<OuterEventMetadataEvent> {
return this.get('events') as Vector<OuterEventMetadataEvent>;
}
/**
* @description The name of the event
*/
get name (): Text {
return this.get('name') as Text;
}
}
@@ -2,11 +2,11 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import bbqBirch from './json/Metadata.bbq.json';
import compacted from './json/Metadata.latest.json';
import Metadata from './Metadata';
import rpcdata from './Metadata.rpc';
import latestParsed from './Metadata.latest.json';
import bbqBirch from '../json/Metadata.bbq.json';
import compacted from '../json/Metadata.latest.json';
import Metadata from './index';
import rpcdata from './static';
import latestParsed from './latest.json';
describe('Metadata', () => {
it('decodes properly', () => {
+290
View File
@@ -0,0 +1,290 @@
// Copyright 2017-2018 @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 { AnyNumber } from '../types';
import Enum from '../codec/Enum';
import EnumType from '../codec/EnumType';
import Option from '../codec/Option';
import Struct from '../codec/Struct';
import Vector from '../codec/Vector';
import Text from '../Text';
import Type from '../Type';
import U16 from '../U16';
export class FunctionArgumentMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
type: Type
}, value);
}
/**
* @description The argument name
*/
get name (): Text {
return this.get('name') as Text;
}
/**
* @description The [[Type]]
*/
get type (): Type {
return this.get('type') as Type;
}
}
export class FunctionMetadata extends Struct {
constructor (value?: any) {
super({
id: U16,
name: Text,
arguments: Vector.with(FunctionArgumentMetadata),
documentation: Vector.with(Text)
}, value);
}
/**
* @description The [[FunctionArgumentMetadata]] for arguments
*/
get arguments (): Vector<FunctionArgumentMetadata> {
return this.get('arguments') as Vector<FunctionArgumentMetadata>;
}
/**
* @description The [[Text]] documentation
*/
get documentation (): Vector<Text> {
return this.get('documentation') as Vector<Text>;
}
/**
* @description The `[sectionIndex, methodIndex]` call id
*/
get id (): U16 {
return this.get('id') as U16;
}
/**
* @description The call name
*/
get name (): Text {
return this.get('name') as Text;
}
}
export class CallMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
functions: Vector.with(FunctionMetadata)
}, value);
}
/**
* @description The functions available as [[FunctionMetadata]]
*/
get functions (): Vector<FunctionMetadata> {
return this.get('functions') as Vector<FunctionMetadata>;
}
/**
* @description The section name
*/
get name (): Text {
return this.get('name') as Text;
}
}
export class ModuleMetadata extends Struct {
constructor (value?: any) {
super({
name: Text,
call: CallMetadata
}, value);
}
/**
* @description The calls as [[CallMetadata]]
*/
get call (): CallMetadata {
return this.get('call') as CallMetadata;
}
/**
* @description The name
*/
get name (): Text {
return this.get('name') as Text;
}
}
export class StorageFunctionModifier extends Enum {
constructor (value?: any) {
super(['None', 'Default', 'Required'], value);
}
}
export class StorageFunctionType$Map extends Struct {
constructor (value?: any) {
super({
key: Type,
value: Type
}, value);
}
/**
* @description The mapped key as [[Type]]
*/
get key (): Type {
return this.get('key') as Type;
}
/**
* @description The mapped value as [[Type]]
*/
get value (): Type {
return this.get('value') as Type;
}
}
export class StorageFunctionType extends EnumType<Type | StorageFunctionType$Map> {
constructor (value?: any, index?: number) {
super([
Type,
StorageFunctionType$Map
], value, index);
}
/**
* @description `true` if the storage entry is a map
*/
get isMap (): boolean {
return this.toNumber() === 1;
}
/**
* @description The value as a mapped value
*/
get asMap (): StorageFunctionType$Map {
return this.value as StorageFunctionType$Map;
}
/**
* @description The value as a [[Type]] value
*/
get asType (): Type {
return this.value as Type;
}
/**
* @description Returns the string representation of the value
*/
toString (): string {
return this.isMap
? this.asMap.value.toString()
: this.asType.toString();
}
}
type StorageFunctionMetadataValue = {
name?: string | Text,
modifier?: StorageFunctionModifier | AnyNumber,
type?: StorageFunctionType,
documentation?: Vector<Text> | Array<string>
};
export class StorageFunctionMetadata extends Struct {
constructor (value?: StorageFunctionMetadataValue) {
super({
name: Text,
modifier: StorageFunctionModifier,
type: StorageFunctionType,
documentation: Vector.with(Text)
}, value);
}
/**
* @description The [[Text]] documentation
*/
get documentation (): Vector<Text> {
return this.get('documentation') as Vector<Text>;
}
/**
* @description The key name
*/
get name (): Text {
return this.get('name') as Text;
}
/**
* @description The modifier
*/
get modifier (): StorageFunctionModifier {
return this.get('modifier') as StorageFunctionModifier;
}
/**
* @description The [[StorageFunctionType]]
*/
get type (): StorageFunctionType {
return this.get('type') as StorageFunctionType;
}
}
export class StorageMetadata extends Struct {
constructor (value?: any) {
super({
prefix: Text,
functions: Vector.with(StorageFunctionMetadata)
}, value);
}
/**
* @description The [[StorageFunctionMetadata]] for the section
*/
get functions (): Vector<StorageFunctionMetadata> {
return this.get('functions') as Vector<StorageFunctionMetadata>;
}
/**
* @description The section prefix
*/
get prefix (): Text {
return this.get('prefix') as Text;
}
}
export class RuntimeModuleMetadata extends Struct {
constructor (value?: any) {
super({
prefix: Text,
module: ModuleMetadata,
storage: Option.with(StorageMetadata)
}, value);
}
/**
* @description The [[ModuleMetadata]]
*/
get module (): ModuleMetadata {
return this.get('module') as ModuleMetadata;
}
/**
* @description The prefix
*/
get prefix (): Text {
return this.get('prefix') as Text;
}
/**
* @description The optional [[StorageMetadata]]
*/
get storage (): Option<StorageMetadata> {
return this.get('storage') as Option<StorageMetadata>;
}
}
+161
View File
@@ -0,0 +1,161 @@
// Copyright 2017-2018 @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 { assert, hexToU8a, isHex, isU8a, isUndefined } from '@polkadot/util';
import { getTypeDef, TypeDef, TypeDefInfo } from '../codec/createType';
import Compact from '../codec/Compact';
import Struct from '../codec/Struct';
import Vector from '../codec/Vector';
import { OuterDispatchMetadata, OuterDispatchCall } from './Calls';
import { OuterEventMetadata, OuterEventMetadataEvent } from './Events';
import { RuntimeModuleMetadata } from './Modules';
// Decodes the runtime metadata as passed through from the `state_getMetadata` call. This
// 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)
// Quick and dirty flatten (.flat() not available)
function flattenUniq (list: Array<any>): Array<any> {
const flat = list.reduce((result, entry) => {
return result.concat(
Array.isArray(entry)
? flattenUniq(entry)
: entry
);
}, []);
return [...new Set(flat)]
.filter((value: any) => value)
.sort();
}
/**
* @name Metadata
* @description
* The runtime metadata as a decoded structure
*/
export default class Metadata extends Struct {
constructor (value?: any) {
super({
outerEvent: OuterEventMetadata,
modules: Vector.with(RuntimeModuleMetadata),
outerDispatch: OuterDispatchMetadata
}, Metadata.decodeMetadata(value));
}
static decodeMetadata (value: string | Uint8Array | object): object | Uint8Array {
if (isHex(value)) {
// We receive this as an hex in the JSON output from the Node.
// Convert to u8a and use the U8a version to do the actual parsing.
return Metadata.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);
return value.length === (offset + length.toNumber())
? value.subarray(offset)
: value;
}
// Decode as normal struct
return value;
}
/**
* @description Wrapped [[OuterDispatchCall]]
*/
get calls (): Vector<OuterDispatchCall> {
return (this.get('outerDispatch') as OuterDispatchMetadata).calls;
}
/**
* @description Wrapped [[OuterEventMetadataEvent]]
*/
get events (): Vector<OuterEventMetadataEvent> {
return (this.get('outerEvent') as OuterEventMetadata).events;
}
/**
* @description Wrapped [[RuntimeModuleMetadata]]
*/
get modules (): Vector<RuntimeModuleMetadata> {
return this.get('modules') as Vector<RuntimeModuleMetadata>;
}
private get argNames () {
return this.modules.map((module) =>
module.module.call.functions.map((fn) =>
fn.arguments.map((argument) => argument.type.toString())
)
);
}
private get eventNames () {
return this.events.map((module) =>
module.events.map((event) =>
event.arguments.map((argument) => argument.toString())
)
);
}
private get storageNames () {
return this.modules.map((module) =>
module.storage.isSome
? module.storage.unwrap().functions.map((fn) =>
fn.type.isMap
? [fn.type.asMap.key.toString(), fn.type.asMap.value.toString()]
: [fn.type.asType.toString()]
)
: []
);
}
/**
* @description Helper to retrieve a list of all type that are found, sorted and de-deuplicated
*/
getUniqTypes (): Array<string> {
const types = flattenUniq([this.argNames, this.eventNames, this.storageNames]);
this.validateTypes(types);
return types;
}
private validateTypes (types: Array<string>): void {
const extractTypes = (types: Array<string>): Array<any> => {
return types.map((type) => {
const decoded = getTypeDef(type);
switch (decoded.info) {
case TypeDefInfo.Plain:
return decoded.type;
case TypeDefInfo.Compact:
case TypeDefInfo.Vector:
return extractTypes([(decoded.sub as TypeDef).type]);
case TypeDefInfo.Tuple:
return extractTypes(
(decoded.sub as Array<TypeDef>).map((sub) => sub.type)
);
default:
throw new Error('Unreachable');
}
});
};
const allTypes = require('../index');
const missing = flattenUniq(extractTypes(types)).filter((type) =>
isUndefined(allTypes[type])
);
assert(missing.length === 0, `Unknown types found, no types for ${missing}`);
}
}
+4 -14
View File
@@ -10,7 +10,7 @@ import { getTypeDef, getTypeClass } from './codec/createType';
import Struct from './codec/Struct';
import U8aFixed from './codec/U8aFixed';
import Extrinsic from './Extrinsic';
import { FunctionMetadata, FunctionArgumentMetadata } from './Metadata';
import { FunctionMetadata, FunctionArgumentMetadata } from './Metadata/Modules';
const FN_UNKNOWN = {
method: 'unknown',
@@ -101,20 +101,13 @@ export default class Method extends Struct {
// Find metadata with callIndex
const meta = _meta || Method.findFunction(callIndex).meta;
// Get Struct definition of the arguments
const argsDef = Method.getArgsDef(meta);
return {
args: value.subarray(2),
argsDef,
argsDef: Method.getArgsDef(meta),
callIndex,
meta
};
} else if (
isObject(value) &&
value.callIndex &&
value.args
) {
} else if (isObject(value) && value.callIndex && value.args) {
// destructure value, we only pass args/methodsIndex out
const { args, callIndex } = value;
@@ -126,12 +119,9 @@ export default class Method extends Struct {
// Find metadata with callIndex
const meta = _meta || Method.findFunction(lookupIndex).meta;
// Get Struct definition of the arguments
const argsDef = Method.getArgsDef(meta);
return {
args,
argsDef,
argsDef: Method.getArgsDef(meta),
meta,
callIndex
};
+1 -1
View File
@@ -7,7 +7,7 @@ import { AnyU8a } from './types';
import { isFunction } from '@polkadot/util';
import Bytes from './Bytes';
import { StorageFunctionMetadata } from './Metadata';
import { StorageFunctionMetadata } from './Metadata/Modules';
export interface StorageFunction {
(arg?: any): Uint8Array;
+2 -2
View File
@@ -90,9 +90,9 @@ export default class Type extends Text {
if (value[index] === '>') {
if (!depth) {
return index;
} else {
depth--;
}
depth--;
} else if (value[index] === '<') {
depth++;
}
+21 -27
View File
@@ -78,36 +78,30 @@ export default class Struct<
// used to track at which index we are currently parsing in that array.
let currentIndex = 0;
return (Object
.keys(Types) as Array<keyof S>)
.reduce((raw: T, key, index) => {
// 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;
return Object.keys(Types).reduce((raw: T, key: keyof S, index) => {
// 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)) {
raw[key] = new Types[key](
value.subarray(
currentIndex
)
);
if (isU8a(value)) {
raw[key] = new Types[key](value.subarray(currentIndex));
// Move the currentIndex forward
currentIndex += raw[key].encodedLength;
} else if (Array.isArray(value)) {
raw[key] = value[index] instanceof Types[key]
? value[index]
: new Types[key](value[index]);
} else if (isObject(value)) {
raw[key] = value[jsonKey as string] instanceof Types[key]
? value[jsonKey as string]
: new Types[key](value[jsonKey as string]);
} else {
throw new Error(`Struct: cannot decode type "${Types[key].name}" with value "${JSON.stringify(value)}".`);
}
// Move the currentIndex forward
currentIndex += raw[key].encodedLength;
} else if (Array.isArray(value)) {
raw[key] = value[index] instanceof Types[key]
? value[index]
: new Types[key](value[index]);
} else if (isObject(value)) {
raw[key] = value[jsonKey as string] instanceof Types[key]
? value[jsonKey as string]
: new Types[key](value[jsonKey as string]);
} else {
throw new Error(`Struct: cannot decode type ${Types[key].name} with value ${JSON.stringify(value)}`);
}
return raw;
}, {} as T);
return raw;
}, {} as T);
}
static with<
+6 -12
View File
@@ -117,28 +117,22 @@ export function getTypeDef (_type: Text | string): TypeDef {
// Returns the type Class for construction
export function getTypeClass (value: TypeDef): Constructor {
if (value.info === TypeDefInfo.Tuple) {
if (!Array.isArray(value.sub)) {
throw new Error(`Expected nested subtypes for Tuple`);
}
assert(Array.isArray(value.sub), 'Expected nested subtypes for Tuple');
return Tuple.with(
value.sub.map(getTypeClass)
(value.sub as Array<TypeDef>).map(getTypeClass)
);
} else if (value.info === TypeDefInfo.Compact) {
if (!value.sub || Array.isArray(value.sub)) {
throw new Error(`Expected subtype for Compact`);
}
assert(value.sub && !Array.isArray(value.sub), 'Expected subtype for Compact');
return Compact.with(
getTypeClass(value.sub) as Constructor<UInt>
getTypeClass(value.sub as TypeDef) as Constructor<UInt>
);
} else if (value.info === TypeDefInfo.Vector) {
if (!value.sub || Array.isArray(value.sub)) {
throw new Error(`Expected subtype for Vector`);
}
assert(value.sub && !Array.isArray(value.sub), 'Expected subtype for Vector');
return Vector.with(
getTypeClass(value.sub)
getTypeClass(value.sub as TypeDef)
);
}
@@ -5,7 +5,7 @@
const fs = require('fs');
import Metadata from '../Metadata';
import rpcdata from '../Metadata.rpc';
import rpcdata from '../Metadata/static';
function metadataStringifyAsJson () {
const decoded = new Metadata(rpcdata);
+1 -1
View File
@@ -7,7 +7,7 @@ import { stringCamelCase, stringLowerFirst } from '@polkadot/util';
import interfaces from '../../../type-jsonrpc/src';
import Metadata from '../Metadata';
import rpcdata from '../Metadata.rpc';
import rpcdata from '../Metadata/static';
import Method from '../Method';
const ANCHOR_TOP = `<a id='top' style='text-decoration: none;'>`;