Move internal decoding to top-level-functions (#1818)

* Move internal decoding to top-level-functions

* Cleanup imports
This commit is contained in:
Jaco Greeff
2020-02-07 14:12:30 +01:00
committed by GitHub
parent f6490217ec
commit faa12a68f7
23 changed files with 170 additions and 181 deletions
+4 -4
View File
@@ -40,10 +40,10 @@ async function query (api: ApiPromise, keyring: TestKeyringMap): Promise<void> {
// api.query.*.* is well-typed
const bar = await api.query.foo.bar(); // bar is Codec (unknown module)
const bal = await api.query.balances.freeBalance(keyring.alice.address); // bal is Balance
const bal2 = await api.query.balances.freeBalance(keyring.alice.address, 'WRONG_ARG'); // bal2 is Codec (wrong args)
const override = await api.query.balances.freeBalance<Header>(keyring.alice.address); // override is still available
const oldBal = await api.query.balances.freeBalance.at('abcd', keyring.alice.address);
const bal = await api.query.balances.totalIssuance(); // bal is Balance
const bal2 = await api.query.balances.totalIssuance('WRONG_ARG'); // bal2 is Codec (wrong args)
const override = await api.query.balances.totalIssuance<Header>(); // override is still available
const oldBal = await api.query.balances.totalIssuance.at('abcd');
// It's hard to correctly type .multi. Expected: `Balance[]`, actual: Codec[].
// In the meantime, we can case with `<Balance>`
const multi = await api.query.balances.freeBalance.multi<Balance>([keyring.alice.address, keyring.bob.address]);
@@ -5,7 +5,7 @@
import { MetadataLatest } from '@polkadot/types/interfaces/metadata';
import { AnyJsonObject, Registry } from '@polkadot/types/types';
import { createType } from '@polkadot/types';
import { createType } from '@polkadot/types/codec';
/** @internal */
export default function toCallsOnly (registry: Registry, { extrinsic, modules }: MetadataLatest): AnyJsonObject | string {
+1 -1
View File
@@ -5,7 +5,7 @@
import { MetadataV1, MetadataV2 } from '@polkadot/types/interfaces/metadata';
import { Registry } from '@polkadot/types/types';
import { createType } from '@polkadot/types';
import { createType } from '@polkadot/types/codec';
/** @internal */
export default function toV2 (registry: Registry, metadataV1: MetadataV1): MetadataV2 {
+1 -1
View File
@@ -5,7 +5,7 @@
import { MetadataV10, MetadataV11 } from '@polkadot/types/interfaces/metadata';
import { Registry } from '@polkadot/types/types';
import { createType } from '@polkadot/types';
import { createType } from '@polkadot/types/codec';
/** @internal */
export default function toV11 (registry: Registry, { modules }: MetadataV10): MetadataV11 {
@@ -7,7 +7,8 @@ import { FunctionMetadataV11, FunctionMetadataLatest, MetadataV11, MetadataLates
import { Registry } from '@polkadot/types/types';
import { getModuleTypes } from '@polkadot/types/known';
import { Type, createType } from '@polkadot/types';
import { createType } from '@polkadot/types/codec';
import { Type } from '@polkadot/types/primitive';
import { stringCamelCase } from '@polkadot/util';
// TODO Handle consts as well
+1 -1
View File
@@ -5,7 +5,7 @@
import { MetadataV2, MetadataV3 } from '@polkadot/types/interfaces/metadata';
import { Registry } from '@polkadot/types/types';
import { createType } from '@polkadot/types';
import { createType } from '@polkadot/types/codec';
/** @internal */
export default function toV3 (registry: Registry, metadataV2: MetadataV2): MetadataV3 {
+1 -1
View File
@@ -5,7 +5,7 @@
import { MetadataV5, MetadataV6, ModuleMetadataV6 } from '@polkadot/types/interfaces/metadata';
import { Registry } from '@polkadot/types/types';
import { createType } from '@polkadot/types';
import { createType } from '@polkadot/types/codec';
/** @internal */
export default function toV6 (registry: Registry, { modules }: MetadataV5): MetadataV6 {
+1 -1
View File
@@ -5,7 +5,7 @@
import { MetadataV6, MetadataV7, ModuleMetadataV7 } from '@polkadot/types/interfaces/metadata';
import { Registry } from '@polkadot/types/types';
import { createType } from '@polkadot/types';
import { createType } from '@polkadot/types/codec';
/** @internal */
export default function toV7 (registry: Registry, { modules }: MetadataV6): MetadataV7 {
+1 -1
View File
@@ -5,7 +5,7 @@
import { MetadataV7, MetadataV8, ModuleMetadataV8 } from '@polkadot/types/interfaces/metadata';
import { Registry } from '@polkadot/types/types';
import { createType } from '@polkadot/types';
import { createType } from '@polkadot/types/codec';
/** @internal */
export default function toV8 (registry: Registry, { modules }: MetadataV7): MetadataV8 {
+1 -1
View File
@@ -5,7 +5,7 @@
import { MetadataV8, MetadataV9 } from '@polkadot/types/interfaces/metadata';
import { Registry } from '@polkadot/types/types';
import { createType } from '@polkadot/types';
import { createType } from '@polkadot/types/codec';
/** @internal */
export default function toV9 (registry: Registry, { modules }: MetadataV8): MetadataV9 {
+1 -1
View File
@@ -5,7 +5,7 @@
import { MetadataV9, MetadataV10, ModuleMetadataV9, ModuleMetadataV10, StorageEntryMetadataV9, StorageEntryTypeV9, StorageHasherV9, StorageHasherV10 } from '@polkadot/types/interfaces/metadata';
import { Registry } from '@polkadot/types/types';
import { createType } from '@polkadot/types';
import { createType } from '@polkadot/types/codec';
// migrate a storage hasher type
// see https://github.com/paritytech/substrate/pull/4462
-3
View File
@@ -29,9 +29,6 @@
"url": "https://github.com/polkadot-js/api/issues"
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/types#readme",
"browser": {
"../package.json": "./package.json"
},
"dependencies": {
"@babel/runtime": "^7.8.3",
"@polkadot/metadata": "^1.1.1",
+6 -16
View File
@@ -2,28 +2,18 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// NOTE When adding any types here, we need to update the documentation links as
// well - <root>/docs/SUMMARY.md as well as ../README.md
import { detectPackage } from '@polkadot/util';
let dirname;
let pkgJson;
// eslint-disable-next-line no-useless-catch
try {
dirname = __dirname;
// eslint-disable-next-line @typescript-eslint/no-var-requires
detectPackage(require('./package.json'), __dirname);
} catch (error) {
// ignore
throw error;
}
try {
pkgJson = require('./package.json');
} catch (error) {
pkgJson = require('../package.json');
}
detectPackage(pkgJson, dirname);
export * from './codec';
export * from './index.types';
// FIXME We actually don't want to do this (if needed, it certainly is not in the right place)
export { formatType } from './scripts/util/formatting';
+12 -12
View File
@@ -9,6 +9,17 @@ import { blake2AsU8a } from '@polkadot/util-crypto';
import { createType } from '../codec/create';
/** @internal */
function decodeBool (value: any): boolean {
if (value instanceof Boolean) {
return value.valueOf();
} else if (isU8a(value)) {
return value[0] === 1;
}
return !!value;
}
/**
* @name Bool
* @description
@@ -20,22 +31,11 @@ export default class Bool extends Boolean implements Codec {
// eslint-disable-next-line @typescript-eslint/ban-types
constructor (registry: Registry, value: Bool | Boolean | Uint8Array | boolean | number = false) {
super(Bool.decodeBool(value));
super(decodeBool(value));
this.registry = registry;
}
/** @internal */
private static decodeBool (value: any): boolean {
if (value instanceof Boolean) {
return value.valueOf();
} else if (isU8a(value)) {
return value[0] === 1;
}
return !!value;
}
/**
* @description The length of the value when encoded as a Uint8Array
*/
+29 -29
View File
@@ -9,6 +9,34 @@ import { assert, isString, isU8a, u8aToU8a } from '@polkadot/util';
import Compact from '../codec/Compact';
import Raw from '../codec/Raw';
/** @internal */
function decodeBytesU8a (value: Uint8Array): Uint8Array {
if (!value.length) {
return new Uint8Array();
}
// handle all other Uint8Array inputs, these do have a length prefix
const [offset, length] = Compact.decodeU8a(value);
const total = offset + length.toNumber();
assert(total <= value.length, `Bytes: required length less than remainder, expected at least ${total}, found ${value.length}`);
return value.subarray(offset, total);
}
/** @internal */
function decodeBytes (value?: AnyU8a): Uint8Array | undefined {
if (Array.isArray(value) || isString(value)) {
return u8aToU8a(value);
} else if (!(value instanceof Raw) && isU8a(value)) {
// We are ensuring we are not a Rawv instance. In the case of a Raw we already have gotten
// rid of the length, i.e. new Bytes(new Bytes(...)) will work as expected
return decodeBytesU8a(value);
}
return value;
}
/**
* @name Bytes
* @description
@@ -18,35 +46,7 @@ import Raw from '../codec/Raw';
*/
export default class Bytes extends Raw {
constructor (registry: Registry, value?: AnyU8a) {
super(registry, Bytes.decodeBytes(value));
}
/** @internal */
private static decodeBytes (value?: AnyU8a): Uint8Array | undefined {
if (Array.isArray(value) || isString(value)) {
return u8aToU8a(value);
} else if (!(value instanceof Raw) && isU8a(value)) {
// We are ensuring we are not a Rawv instance. In the case of a Raw we already have gotten
// rid of the length, i.e. new Bytes(new Bytes(...)) will work as expected
return Bytes.decodeBytesU8a(value);
}
return value;
}
/** @internal */
private static decodeBytesU8a (value: Uint8Array): Uint8Array {
if (!value.length) {
return new Uint8Array();
}
// handle all other Uint8Array inputs, these do have a length prefix
const [offset, length] = Compact.decodeU8a(value);
const total = offset + length.toNumber();
assert(total <= value.length, `Bytes: required length less than remainder, expected at least ${total}, found ${value.length}`);
return value.subarray(offset, total);
super(registry, decodeBytes(value));
}
/**
@@ -9,6 +9,19 @@ import { decodeAddress, encodeAddress } from '@polkadot/util-crypto';
import U8aFixed from '../../codec/U8aFixed';
/** @internal */
function decodeAccountId (value: AnyU8a | AnyString): Uint8Array {
if (isU8a(value) || Array.isArray(value)) {
return u8aToU8a(value);
} else if (isHex(value)) {
return hexToU8a(value.toString());
} else if (isString(value)) {
return decodeAddress((value as string).toString());
}
return value;
}
/**
* @name AccountId
* @description
@@ -18,31 +31,18 @@ import U8aFixed from '../../codec/U8aFixed';
*/
export default class AccountId extends U8aFixed {
constructor (registry: Registry, value: AnyU8a = new Uint8Array()) {
super(registry, AccountId.decodeAccountId(value), 256);
super(registry, decodeAccountId(value), 256);
}
public static encode (value: Uint8Array): string {
return encodeAddress(value);
}
/** @internal */
private static decodeAccountId (value: AnyU8a | AnyString): Uint8Array {
if (isU8a(value) || Array.isArray(value)) {
return u8aToU8a(value);
} else if (isHex(value)) {
return hexToU8a(value.toString());
} else if (isString(value)) {
return decodeAddress((value as string).toString());
}
return value;
}
/**
* @description Compares the value of the input to see if there is a match
*/
public eq (other?: any): boolean {
return super.eq(AccountId.decodeAccountId(other));
return super.eq(decodeAccountId(other));
}
/**
+26 -26
View File
@@ -17,6 +17,30 @@ type AnyAddress = BN | Address | AccountId | AccountIndex | number[] | Uint8Arra
export const ACCOUNT_ID_PREFIX = new Uint8Array([0xff]);
/** @internal */
function decodeString (registry: Registry, value: string): AccountId | AccountIndex {
const decoded = decodeAddress(value);
return decoded.length === 32
? createType(registry, 'AccountId', decoded)
: createType(registry, 'AccountIndex', u8aToBn(decoded, true));
}
/** @internal */
function decodeU8a (registry: Registry, value: Uint8Array): AccountId | AccountIndex {
// This allows us to instantiate an address with a raw publicKey. Do this first before
// we checking the first byte, otherwise we may split an already-existent valid address
if (value.length === 32) {
return createType(registry, 'AccountId', value);
} else if (value[0] === 0xff) {
return createType(registry, 'AccountId', value.subarray(1));
}
const [offset, length] = AccountIndex.readLength(value);
return createType(registry, 'AccountIndex', u8aToBn(value.subarray(offset, offset + length), true));
}
/**
* @name Address
* @description
@@ -39,34 +63,10 @@ export default class Address extends Base<AccountId | AccountIndex> {
} else if (isBn(value) || isNumber(value)) {
return createType(registry, 'AccountIndex', value);
} else if (Array.isArray(value) || isHex(value) || isU8a(value)) {
return Address.decodeU8a(registry, u8aToU8a(value));
return decodeU8a(registry, u8aToU8a(value));
}
return Address.decodeString(registry, value);
}
/** @internal */
private static decodeString (registry: Registry, value: string): AccountId | AccountIndex {
const decoded = decodeAddress(value);
return decoded.length === 32
? createType(registry, 'AccountId', decoded)
: createType(registry, 'AccountIndex', u8aToBn(decoded, true));
}
/** @internal */
private static decodeU8a (registry: Registry, value: Uint8Array): AccountId | AccountIndex {
// This allows us to instantiate an address with a raw publicKey. Do this first before
// we checking the first byte, otherwise we may split an already-existent valid address
if (value.length === 32) {
return createType(registry, 'AccountId', value);
} else if (value[0] === 0xff) {
return createType(registry, 'AccountId', value.subarray(1));
}
const [offset, length] = AccountIndex.readLength(value);
return createType(registry, 'AccountIndex', u8aToBn(value.subarray(offset, offset + length), true));
return decodeString(registry, value);
}
/**
+33 -33
View File
@@ -26,6 +26,38 @@ const NAY_BITS = 0b00000000;
const CON_MASK = 0b01111111;
const DEF_CONV = 0b00000000; // the default conviction, None
/** @internal */
function decodeVoteBool (value: boolean): Uint8Array {
return value
? new Uint8Array([AYE_BITS | DEF_CONV])
: new Uint8Array([NAY_BITS]);
}
/** @internal */
function decodeVoteU8a (value: Uint8Array): Uint8Array {
return value.length
? value.subarray(0, 1)
: new Uint8Array([NAY_BITS]);
}
/** @internal */
function decodeVote (registry: Registry, value?: InputTypes): Uint8Array {
if (isUndefined(value)) {
return decodeVoteBool(false);
} else if (value instanceof Boolean || isBoolean(value)) {
return decodeVoteBool(new Bool(registry, value).isTrue);
} else if (isNumber(value)) {
return decodeVoteBool(value < 0);
} else if (isU8a(value)) {
return decodeVoteU8a(value);
}
const vote = new Bool(registry, value.aye).isTrue ? AYE_BITS : NAY_BITS;
const conviction = createType(registry, 'Conviction', isUndefined(value.conviction) ? DEF_CONV : value.conviction);
return new Uint8Array([vote | conviction.index]);
}
/**
* @name Vote
* @description
@@ -40,7 +72,7 @@ export default class Vote extends U8aFixed {
// decoded is just 1 byte
// Aye: Most Significant Bit
// Conviction: 0000 - 0101
const decoded = Vote.decodeVote(registry, value);
const decoded = decodeVote(registry, value);
super(registry, decoded, 8);
@@ -48,38 +80,6 @@ export default class Vote extends U8aFixed {
this._conviction = createType(this.registry, 'Conviction', decoded[0] & CON_MASK);
}
/** @internal */
private static decodeVote (registry: Registry, value?: InputTypes): Uint8Array {
if (isUndefined(value)) {
return Vote.decodeVoteBool(false);
} else if (value instanceof Boolean || isBoolean(value)) {
return Vote.decodeVoteBool(new Bool(registry, value).isTrue);
} else if (isNumber(value)) {
return Vote.decodeVoteBool(value < 0);
} else if (isU8a(value)) {
return Vote.decodeVoteU8a(value);
}
const vote = new Bool(registry, value.aye).isTrue ? AYE_BITS : NAY_BITS;
const conviction = createType(registry, 'Conviction', isUndefined(value.conviction) ? DEF_CONV : value.conviction);
return new Uint8Array([vote | conviction.index]);
}
/** @internal */
private static decodeVoteBool (value: boolean): Uint8Array {
return value
? new Uint8Array([AYE_BITS | DEF_CONV])
: new Uint8Array([NAY_BITS]);
}
/** @internal */
private static decodeVoteU8a (value: Uint8Array): Uint8Array {
return value.length
? value.subarray(0, 1)
: new Uint8Array([NAY_BITS]);
}
/**
* @description returns a V2 conviction
*/
+27 -27
View File
@@ -11,6 +11,32 @@ import { createType } from '../codec/create';
import Compact from '../codec/Compact';
import Raw from '../codec/Raw';
/** @internal */
function decodeText (value: Text | string | AnyU8a | { toString: () => string }): string {
if (isHex(value)) {
return u8aToString(hexToU8a(value.toString()));
} else if (value instanceof Uint8Array) {
if (!value.length) {
return '';
}
// for Raw, the internal buffer does not have an internal length
// (the same applies in e.g. Bytes, where length is added at encoding-time)
if (value instanceof Raw) {
return u8aToString(value);
}
const [offset, length] = Compact.decodeU8a(value);
const total = offset + length.toNumber();
assert(total <= value.length, `Text: required length less than remainder, expected at least ${total}, found ${value.length}`);
return u8aToString(value.subarray(offset, total));
}
return `${value}`;
}
/**
* @name Text
* @description
@@ -26,37 +52,11 @@ export default class Text extends String implements Codec {
private _override: string | null = null;
constructor (registry: Registry, value: Text | string | AnyU8a | { toString: () => string } = '') {
super(Text.decodeText(value));
super(decodeText(value));
this.registry = registry;
}
/** @internal */
private static decodeText (value: Text | string | AnyU8a | { toString: () => string }): string {
if (isHex(value)) {
return u8aToString(hexToU8a(value.toString()));
} else if (value instanceof Uint8Array) {
if (!value.length) {
return '';
}
// for Raw, the internal buffer does not have an internal length
// (the same applies in e.g. Bytes, where length is added at encoding-time)
if (value instanceof Raw) {
return u8aToString(value);
}
const [offset, length] = Compact.decodeU8a(value);
const total = offset + length.toNumber();
assert(total <= value.length, `Text: required length less than remainder, expected at least ${total}, found ${value.length}`);
return u8aToString(value.subarray(offset, total));
}
return `${value}`;
}
/**
* @description The length of the value when encoded as a Uint8Array
*/
@@ -6,9 +6,10 @@ import { ModuleMetadataLatest } from '../../interfaces/metadata';
import * as defaultDefs from '../../interfaces/definitions';
import staticData from '@polkadot/metadata/Metadata/static';
import Metadata from '@polkadot/metadata/Metadata';
import { stringCamelCase } from '@polkadot/util';
import { Metadata, TypeRegistry } from '../..';
import { TypeRegistry } from '../../codec';
import { FOOTER, HEADER, TypeImports, createDocComments, createImportCode, createImports, indent, setImports, writeFile } from '../util';
// Generate types for one module
+3 -3
View File
@@ -7,9 +7,9 @@ import { Registry } from '../../types';
import * as defaultDefs from '../../interfaces/definitions';
import staticData from '@polkadot/metadata/Metadata/static';
import Metadata from '@polkadot/metadata/Metadata';
import { stringLowerFirst } from '@polkadot/util';
import { Metadata } from '../..';
import { TypeRegistry } from '../../codec';
import { FOOTER, HEADER, TypeImports, createDocComments, createImportCode, createImports, formatType, getSimilarTypes, indent, setImports, writeFile } from '../util';
@@ -92,9 +92,9 @@ function generateForMeta (registry: Registry, meta: Metadata, dest: string, extr
const allDefs = Object.entries(allTypes).reduce((defs, [, obj]) => {
return Object.entries(obj).reduce((defs, [key, value]) => ({ ...defs, [key]: value }), defs);
}, {});
const body = meta.asLatest.modules.reduce((acc, mod): string[] => {
const body = meta.asLatest.modules.reduce((acc: string[], mod): string[] => {
return acc.concat(generateModule(allDefs, registry, mod, imports, isStrict));
}, [] as string[]);
}, []);
const header = createImportCode(HEADER, imports, [
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
file: `${imports.moduleToPackage[moduleName]}/${moduleName}`,
+2 -1
View File
@@ -7,10 +7,11 @@ import * as defaultDefs from '../../interfaces/definitions';
import { Registry } from '../../types';
import staticData from '@polkadot/metadata/Metadata/static';
import Metadata from '@polkadot/metadata/Metadata';
import { Text } from '@polkadot/types';
import { stringCamelCase } from '@polkadot/util';
import { Metadata, TypeRegistry } from '../..';
import { TypeRegistry } from '../../codec';
import { FOOTER, HEADER, TypeImports, createDocComments, createImportCode, createImports, formatType, getSimilarTypes, indent, setImports, writeFile } from '../util';
const MAPPED_NAMES: Record<string, string> = {