diff --git a/packages/api-contract/src/base/Contract.ts b/packages/api-contract/src/base/Contract.ts index 5e07693dd3..4bf2e2f2cd 100644 --- a/packages/api-contract/src/base/Contract.ts +++ b/packages/api-contract/src/base/Contract.ts @@ -11,7 +11,7 @@ import { ContractRead, MapMessageExec, MapMessageRead } from './types'; import BN from 'bn.js'; import { map } from 'rxjs/operators'; import ApiBase from '@polkadot/api/base'; -import { assert, bnToBn, isFunction, isObject, isUndefined, stringCamelCase } from '@polkadot/util'; +import { assert, bnToBn, isFunction, isUndefined, stringCamelCase } from '@polkadot/util'; import Abi from '../Abi'; import { formatData } from '../util'; @@ -20,9 +20,7 @@ import Base from './Base'; const ERROR_NO_CALL = 'Your node does not expose the contracts.call RPC. This is most probably due to a runtime configuration.'; // map from a JSON result to current-style ContractExecResult -function mapExecResult (registry: Registry, json: AnyJson): ContractExecResult { - assert(isObject(json) && !Array.isArray(json), 'Invalid JSON result retrieved'); - +function mapExecResult (registry: Registry, json: Record): ContractExecResult { if (!Object.keys(json).some((key) => ['error', 'success'].includes(key))) { return registry.createType('ContractExecResult', json); } diff --git a/packages/api-derive/src/treasury/proposals.ts b/packages/api-derive/src/treasury/proposals.ts index 40d60df758..0df38133fd 100644 --- a/packages/api-derive/src/treasury/proposals.ts +++ b/packages/api-derive/src/treasury/proposals.ts @@ -51,9 +51,7 @@ function retrieveProposals (api: ApiInterfaceRx, proposalCount: ProposalIndex, a const count = proposalCount.toNumber(); for (let index = 0; index < count; index++) { - const isApproval = approvalIds.some((id): boolean => id.eqn(index)); - - if (!isApproval) { + if (!approvalIds.some((id) => id.eqn(index))) { proposalIds.push(api.registry.createType('ProposalIndex', index)); } } diff --git a/packages/api-derive/src/type/HeaderExtended.ts b/packages/api-derive/src/type/HeaderExtended.ts index f645501687..5e6f712ed2 100644 --- a/packages/api-derive/src/type/HeaderExtended.ts +++ b/packages/api-derive/src/type/HeaderExtended.ts @@ -36,9 +36,9 @@ export default class HeaderExtended extends _Header { /** * @description Creates a human-friendly JSON representation */ - public toHuman (isExtended?: boolean): AnyJson { + public toHuman (isExtended?: boolean): Record { return { - ...super.toHuman(isExtended) as { [index: string]: AnyJson }, + ...super.toHuman(isExtended), author: this.author ? this.author.toHuman() : undefined @@ -48,9 +48,9 @@ export default class HeaderExtended extends _Header { /** * @description Creates the JSON representation */ - public toJSON (): AnyJson { + public toJSON (): Record { return { - ...super.toJSON() as { [index: string]: AnyJson }, + ...super.toJSON(), author: this.author ? this.author.toJSON() : undefined diff --git a/packages/api-derive/src/type/SignedBlockExtended.ts b/packages/api-derive/src/type/SignedBlockExtended.ts index 4389c42428..da98e5de43 100644 --- a/packages/api-derive/src/type/SignedBlockExtended.ts +++ b/packages/api-derive/src/type/SignedBlockExtended.ts @@ -36,9 +36,9 @@ export default class BlockExtended extends _SignedBlock { /** * @description Creates a human-friendly JSON representation */ - public toHuman (isExtended?: boolean): AnyJson { + public toHuman (isExtended?: boolean): Record { return { - ...super.toHuman(isExtended) as { [index: string]: AnyJson }, + ...super.toHuman(isExtended), author: this.author ? this.author.toHuman() : undefined @@ -48,9 +48,9 @@ export default class BlockExtended extends _SignedBlock { /** * @description Creates the JSON representation */ - public toJSON (): AnyJson { + public toJSON (): Record { return { - ...super.toJSON() as { [index: string]: AnyJson }, + ...super.toJSON(), author: this.author ? this.author.toJSON() : undefined diff --git a/packages/api/src/base/Decorate.ts b/packages/api/src/base/Decorate.ts index f2ebca90e6..d52a11018d 100644 --- a/packages/api/src/base/Decorate.ts +++ b/packages/api/src/base/Decorate.ts @@ -290,12 +290,10 @@ export default abstract class Decorate extends Events // eslint-disable-next-line @typescript-eslint/no-unsafe-return return decorateMethod((calls: QueryableStorageMultiArg[]): Observable => this._rpcCore.state.subscribeStorage( - calls.map((arg: QueryableStorageMultiArg): [QueryableStorageEntry, ...Arg[]] => - // the input is a QueryableStorageEntry, convert to StorageEntry - // eslint-disable-next-line @typescript-eslint/no-unsafe-return + calls.map((arg: QueryableStorageMultiArg) => Array.isArray(arg) ? [arg[0].creator, ...arg.slice(1)] - : [arg.creator] as any))); + : [arg.creator]))); } protected _decorateExtrinsics ({ tx }: DecoratedMeta, decorateMethod: DecorateMethod): SubmittableExtrinsics { diff --git a/packages/api/src/promise/Combinator.ts b/packages/api/src/promise/Combinator.ts index 1a3cbdb2a5..8410cd33bd 100644 --- a/packages/api/src/promise/Combinator.ts +++ b/packages/api/src/promise/Combinator.ts @@ -46,9 +46,7 @@ export default class Combinator { } protected _allHasFired (): boolean { - if (!this.#allHasFired) { - this.#allHasFired = this.#fired.filter((hasFired): boolean => !hasFired).length === 0; - } + this.#allHasFired ||= this.#fired.filter((hasFired): boolean => !hasFired).length === 0; return this.#allHasFired; } diff --git a/packages/rpc-core/src/index.ts b/packages/rpc-core/src/index.ts index 3524f5e484..ff7655b92c 100644 --- a/packages/rpc-core/src/index.ts +++ b/packages/rpc-core/src/index.ts @@ -167,11 +167,9 @@ export default class Rpc implements RpcInterface { // decorate the sections with base and user methods this.sections.forEach((sectionName): void => { - if (!(this as Record)[sectionName as Section]) { - (this as Record)[sectionName as Section] = {}; - } + (this as Record)[sectionName as Section] ||= {}; - const section = (this as Record)[sectionName as Section] as Record; + const section = this[sectionName as Section] as Record; Object .entries({ @@ -179,11 +177,7 @@ export default class Rpc implements RpcInterface { ...this._createInterface(sectionName, userRpc[sectionName] || {}) }) .forEach(([key, value]): void => { - // we don't want to clobber existing, i.e. when this is called again after chain is determined - if (!section[key]) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - section[key] = value; - } + section[key] ||= value; }); }); } diff --git a/packages/types/src/codec/Enum.ts b/packages/types/src/codec/Enum.ts index eb3ed370c0..808db2331b 100644 --- a/packages/types/src/codec/Enum.ts +++ b/packages/types/src/codec/Enum.ts @@ -152,27 +152,21 @@ export default class Enum implements Codec { const askey = `as${name}`; const iskey = `is${name}`; - // do not clobber existing properties on the object - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (isUndefined((this as any)[iskey])) { + isUndefined(this[iskey as keyof this]) && Object.defineProperty(this, iskey, { enumerable: true, - get: (): boolean => this.type === _key + get: () => this.type === _key }); - } - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (isUndefined((this as any)[askey])) { + isUndefined(this[askey as keyof this]) && Object.defineProperty(this, askey, { enumerable: true, get: (): Codec => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - assert((this as any)[iskey], `Cannot convert '${this.type}' via ${askey}`); + assert(this[iskey as keyof this], `Cannot convert '${this.type}' via ${askey}`); return this.value; } }); - } }); } }; diff --git a/packages/types/src/codec/Json.ts b/packages/types/src/codec/Json.ts index 4d532041f9..12efa24f3a 100644 --- a/packages/types/src/codec/Json.ts +++ b/packages/types/src/codec/Json.ts @@ -31,18 +31,12 @@ export default class StructAny extends Map implements Codec { this.registry = registry; - // like we are doing with structs, add the keys as getters decoded.forEach(([key]): void => { - // do not clobber existing properties on the object - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (!isUndefined((this as any)[key])) { - return; - } - - Object.defineProperty(this, key, { - enumerable: true, - get: (): Codec | undefined => this.get(key) as Codec - }); + isUndefined(this[key as keyof this]) && + Object.defineProperty(this, key, { + enumerable: true, + get: (): Codec | undefined => this.get(key) as Codec + }); }); } @@ -84,14 +78,14 @@ export default class StructAny extends Map implements Codec { /** * @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information */ - public toHuman (): AnyJson { + public toHuman (): Record { return this.toJSON(); } /** * @description Converts the Object to JSON, typically used for RPC transfers */ - public toJSON (): AnyJson { + public toJSON (): Record { return [...this.entries()].reduce((json: Record, [key, value]): Record => { json[key] = value as AnyJson; diff --git a/packages/types/src/codec/Map.ts b/packages/types/src/codec/Map.ts index 8460d9baf7..c5b94c5662 100644 --- a/packages/types/src/codec/Map.ts +++ b/packages/types/src/codec/Map.ts @@ -152,8 +152,8 @@ export default class CodecMap /** * @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information */ - public toHuman (isExtended?: boolean): AnyJson { - const json: AnyJson = {}; + public toHuman (isExtended?: boolean): Record { + const json: Record = {}; this.forEach((v: V, k: K) => { json[k.toString()] = v.toHuman(isExtended); @@ -165,8 +165,8 @@ export default class CodecMap /** * @description Converts the Object to JSON, typically used for RPC transfers */ - public toJSON (): AnyJson { - const json: AnyJson = {}; + public toJSON (): Record { + const json: Record = {}; this.forEach((v: V, k: K) => { json[k.toString()] = v.toJSON(); diff --git a/packages/types/src/codec/Set.ts b/packages/types/src/codec/Set.ts index 5f52395ffc..ec8dcd5f8f 100644 --- a/packages/types/src/codec/Set.ts +++ b/packages/types/src/codec/Set.ts @@ -100,14 +100,11 @@ export default class CodecSet extends Set implements Codec { const name = stringUpperFirst(stringCamelCase(_key)); const iskey = `is${name}`; - // do not clobber existing properties on the object - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (isUndefined((this as any)[iskey])) { + isUndefined(this[iskey as keyof this]) && Object.defineProperty(this, iskey, { enumerable: true, get: (): boolean => this.strings.includes(_key) }); - } }); } }; diff --git a/packages/types/src/codec/Struct.ts b/packages/types/src/codec/Struct.ts index e43d126a2f..1ebb1e9a82 100644 --- a/packages/types/src/codec/Struct.ts +++ b/packages/types/src/codec/Struct.ts @@ -155,22 +155,25 @@ export default class Struct< constructor (registry: Registry, value?: unknown) { super(registry, Types, value as string, jsonMap); - (Object.keys(Types) as (keyof S)[]).forEach((key): void => { - // do not clobber existing properties on the object - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (!isUndefined((this as any)[key])) { - return; - } - - Object.defineProperty(this, key, { - enumerable: true, - get: (): Codec | undefined => this.get(key) - }); + Object.keys(Types).forEach((key): void => { + isUndefined(this[key as keyof this]) && + Object.defineProperty(this, key, { + enumerable: true, + get: (): Codec | undefined => this.get(key as keyof S) + }); }); } }; } + public static typesToMap (registry: Registry, Types: Record): Record { + return Object.entries(Types).reduce((result: Record, [key, Type]): Record => { + result[key] = registry.getClassName(Type) || new Type(registry).toRawType(); + + return result; + }, {}); + } + /** * @description The available keys for this enum */ @@ -264,37 +267,27 @@ export default class Struct< /** * @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information */ - public toHuman (isExtended?: boolean): AnyJson { - return [...this.keys()].reduce((json, key): Record => { + public toHuman (isExtended?: boolean): Record { + return [...this.keys()].reduce((json: Record, key): Record => { const value = this.get(key); - json[key] = value && value.toHuman(isExtended); + json[key as string] = value && value.toHuman(isExtended); return json; - }, {} as Record); + }, {}); } /** * @description Converts the Object to JSON, typically used for RPC transfers */ - public toJSON (): AnyJson { - // FIXME the return type string is only used by Extrinsic (extends Struct), - // but its toJSON is the hex value - return [...this.keys()].reduce((json, key): Record => { + public toJSON (): Record { + return [...this.keys()].reduce((json: Record, key): Record => { const jsonKey = this.#jsonMap.get(key) || key; const value = this.get(key); - json[jsonKey] = value && value.toJSON(); + json[jsonKey as string] = value && value.toJSON(); return json; - }, {} as Record); - } - - public static typesToMap (registry: Registry, Types: Record): Record { - return Object.entries(Types).reduce((result: Record, [key, Type]): Record => { - result[key] = registry.getClassName(Type) || new Type(registry).toRawType(); - - return result; }, {}); } diff --git a/packages/types/src/extrinsic/ExtrinsicEra.ts b/packages/types/src/extrinsic/ExtrinsicEra.ts index afd948387f..199bb44ca1 100644 --- a/packages/types/src/extrinsic/ExtrinsicEra.ts +++ b/packages/types/src/extrinsic/ExtrinsicEra.ts @@ -67,12 +67,12 @@ export class MortalEra extends Tuple { /** @internal */ private static _decodeMortalEra (registry: Registry, value?: MortalMethod | Uint8Array | number[] | string): MortalEraValue { - if (isU8a(value) || isHex(value) || Array.isArray(value)) { + if (!value) { + return [new U64(registry), new U64(registry)]; + } else if (isU8a(value) || isHex(value) || Array.isArray(value)) { return MortalEra._decodeMortalU8a(registry, u8aToU8a(value)); } else if (isObject(value)) { return MortalEra._decodeMortalObject(registry, value); - } else if (!value) { - return [new U64(registry), new U64(registry)]; } throw new Error('Invalid data passed to Mortal era'); diff --git a/packages/types/src/generic/Call.ts b/packages/types/src/generic/Call.ts index 8275b5e81e..bf9c0cd22c 100644 --- a/packages/types/src/generic/Call.ts +++ b/packages/types/src/generic/Call.ts @@ -231,7 +231,7 @@ export default class Call extends Struct implements IMethod { /** * @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information */ - public toHuman (isExpanded?: boolean): AnyJson { + public toHuman (isExpanded?: boolean): Record { let call: CallFunction | undefined; try { diff --git a/packages/types/src/generic/Event.ts b/packages/types/src/generic/Event.ts index efe6fa44f7..a3ddf5c8a6 100644 --- a/packages/types/src/generic/Event.ts +++ b/packages/types/src/generic/Event.ts @@ -84,9 +84,7 @@ export default class Event extends Struct { /** @internal */ public static decodeEvent (registry: Registry, value: Uint8Array = new Uint8Array()): { DataType: Constructor | Constructor; value?: { index: Uint8Array; data: Uint8Array } } { if (!value.length) { - return { - DataType: Null - }; + return { DataType: Null }; } const index = value.subarray(0, 2); @@ -145,9 +143,15 @@ export default class Event extends Struct { /** * @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - public toHuman (isExpanded?: boolean): AnyJson { - // FIXME May this human-friendly - return this.toJSON(); + public toHuman (isExpanded?: boolean): Record { + return { + method: this.method, + section: this.section, + ...(isExpanded + ? { documentation: this.meta.documentation.map((d) => d.toString()) } + : {} + ), + ...super.toHuman(isExpanded) + }; } } diff --git a/packages/types/src/types/helpers.ts b/packages/types/src/types/helpers.ts index 3ffc0142aa..c774dad60e 100644 --- a/packages/types/src/types/helpers.ts +++ b/packages/types/src/types/helpers.ts @@ -5,15 +5,9 @@ import { Codec } from './codec'; import BN from 'bn.js'; -// We cannot inline this into CodecArg, TS thrws up when building docs -// eslint-disable-next-line @typescript-eslint/no-explicit-any export type AnyFunction = (...args: any[]) => any; -// eslint-disable-next-line no-use-before-define -export type AnyJson = string | number | boolean | null | undefined | AnyJsonArray | { [index: string]: AnyJson }; - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -interface AnyJsonArray extends Array {} +export type AnyJson = string | number | boolean | null | undefined | AnyJson[] | { [index: string]: AnyJson }; export type AnyNumber = BN | BigInt | Uint8Array | number | string;