From 63096cc238f66c8d8524a315f180407cb2d8b5f8 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 3 Jul 2020 11:55:39 +0200 Subject: [PATCH] Remove unneeded base extends (#2407) * Remove unneeded base extends * CHANGELOG * Result with value on enum --- CHANGELOG.md | 1 + packages/types/src/codec/AbstractInt.ts | 2 +- packages/types/src/codec/Compact.ts | 91 +++++++++++++++++++------ packages/types/src/codec/Enum.ts | 82 +++++++++++++--------- packages/types/src/codec/Option.ts | 58 ++++++++++++---- packages/types/src/codec/Result.ts | 2 +- packages/types/src/primitive/Data.ts | 8 +-- 7 files changed, 174 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4b950a32c..30334f8007 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Adjust `.toRawType()` to use registry name as available - Update ProxyType for Kusama, Polkadot & Westend with `IdentityJudgement` - Validate number format (signed/unsigned) for number types +- Remove core codec dependencies on Base class (with proper TS encapsulation) ## 1.22.1 Jun 30, 2020 diff --git a/packages/types/src/codec/AbstractInt.ts b/packages/types/src/codec/AbstractInt.ts index efa2e31794..f468fd1dbb 100644 --- a/packages/types/src/codec/AbstractInt.ts +++ b/packages/types/src/codec/AbstractInt.ts @@ -162,7 +162,7 @@ export default abstract class AbstractInt extends BN implements Codec { * @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): any { + public toHuman (isExpanded?: boolean): string { // FIXME we need proper expansion here return this instanceof this.registry.createClass('Balance') ? this.isMax() diff --git a/packages/types/src/codec/Compact.ts b/packages/types/src/codec/Compact.ts index cff9ea4f69..3d03ef158d 100644 --- a/packages/types/src/codec/Compact.ts +++ b/packages/types/src/codec/Compact.ts @@ -2,15 +2,17 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { AnyNumber, Codec, Constructor, ICompact, InterfaceTypes, Registry } from '../types'; +import { H256 } from '@polkadot/types/interfaces'; +import { AnyJson, AnyNumber, Codec, Constructor, ICompact, InterfaceTypes, Registry } from '../types'; import BN from 'bn.js'; import { compactAddLength, compactFromU8a, compactStripLength, compactToU8a, isBigInt, isBn, isNumber, isString } from '@polkadot/util'; import { DEFAULT_BITLENGTH } from '@polkadot/util/compact/defaults'; +import { blake2AsU8a } from '@polkadot/util-crypto'; import typeToConstructor from './utils/typeToConstructor'; import { UIntBitLength } from './AbstractInt'; -import Base from './Base'; +import Raw from './Raw'; export interface CompactEncodable extends Codec { bitLength (): number; @@ -26,17 +28,17 @@ export interface CompactEncodable extends Codec { * used by other types to add length-prefixed encoding, or in the case of wrapped types, taking * a number and making the compact representation thereof */ -export default class Compact extends Base implements ICompact { - private readonly _Type: Constructor; +export default class Compact implements ICompact { + public readonly registry: Registry; + + readonly #Type: Constructor; + + readonly #raw: T; constructor (registry: Registry, Type: Constructor | keyof InterfaceTypes, value: Compact | AnyNumber = 0) { - const _Type = typeToConstructor(registry, Type); - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - super(registry, Compact.decodeCompact(registry, _Type, value)); - - this._Type = _Type; + this.registry = registry; + this.#Type = typeToConstructor(registry, Type); + this.#raw = Compact.decodeCompact(registry, this.#Type, value) as T; } public static with (Type: Constructor | keyof InterfaceTypes): Constructor> { @@ -67,7 +69,7 @@ export default class Compact extends Base impleme /** @internal */ public static decodeCompact (registry: Registry, Type: Constructor, value: Compact | AnyNumber): CompactEncodable { if (value instanceof Compact) { - return new Type(registry, value._raw); + return new Type(registry, value.#raw); } else if (isString(value) || isNumber(value) || isBn(value) || isBigInt(value)) { return new Type(registry, value); } @@ -77,20 +79,41 @@ export default class Compact extends Base impleme return new Type(registry, _value); } + /** + * @description The length of the value when encoded as a Uint8Array + */ + public get encodedLength (): number { + return this.toU8a().length; + } + + /** + * @description returns a hash of the contents + */ + public get hash (): H256 { + return new Raw(this.registry, blake2AsU8a(this.toU8a(), 256)); + } + + /** + * @description Checks if the value is an empty value + */ + public get isEmpty (): boolean { + return this.#raw.isEmpty; + } + /** * @description Returns the number of bits in the value */ public bitLength (): number { - return this._raw.bitLength(); + return this.#raw.bitLength(); } /** * @description Compares the value of the input to see if there is a match */ public eq (other?: unknown): boolean { - return this._raw.eq( + return this.#raw.eq( other instanceof Compact - ? other._raw + ? other.#raw : other ); } @@ -99,21 +122,49 @@ export default class Compact extends Base impleme * @description Returns the BN representation of the number */ public toBn (): BN { - return this._raw.toBn(); + return this.#raw.toBn(); + } + + /** + * @description Returns a hex string representation of the value. isLe returns a LE (number-only) representation + */ + public toHex (isLe?: boolean): string { + return this.#raw.toHex(isLe); + } + + /** + * @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.#raw.toHuman(isExtended); + } + + /** + * @description Converts the Object to JSON, typically used for RPC transfers + */ + public toJSON (): AnyJson { + return this.#raw.toJSON(); } /** * @description Returns the number representation for the value */ public toNumber (): number { - return this._raw.toNumber(); + return this.#raw.toNumber(); } /** * @description Returns the base runtime type name for this instance */ public toRawType (): string { - return `Compact<${this.registry.getClassName(this._Type) || this._raw.toRawType()}>`; + return `Compact<${this.registry.getClassName(this.#Type) || this.#raw.toRawType()}>`; + } + + /** + * @description Returns the string representation of the value + */ + public toString (): string { + return this.#raw.toString(); } /** @@ -122,13 +173,13 @@ export default class Compact extends Base impleme */ // eslint-disable-next-line @typescript-eslint/no-unused-vars public toU8a (isBare?: boolean): Uint8Array { - return Compact.encodeU8a(this._raw.toBn()); + return Compact.encodeU8a(this.#raw.toBn()); } /** * @description Returns the embedded [[UInt]] or [[Moment]] value */ public unwrap (): T { - return this._raw; + return this.#raw; } } diff --git a/packages/types/src/codec/Enum.ts b/packages/types/src/codec/Enum.ts index 19b529c10b..835aa16d91 100644 --- a/packages/types/src/codec/Enum.ts +++ b/packages/types/src/codec/Enum.ts @@ -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 { H256 } from '@polkadot/types/interfaces'; import { AnyJson, Codec, Constructor, InterfaceTypes, Registry } from '../types'; import { assert, hexToU8a, isHex, isNumber, isObject, isString, isU8a, isUndefined, stringCamelCase, stringUpperFirst, u8aConcat, u8aToHex } from '@polkadot/util'; +import { blake2AsU8a } from '@polkadot/util-crypto'; import Null from '../primitive/Null'; import { mapToTypeMap } from './utils'; -import Base from './Base'; +import Raw from './Raw'; import Struct from './Struct'; // export interface, this is used in Enum.with, so required as public by TS @@ -114,25 +116,29 @@ function decodeEnum (registry: Registry, def: TypesDef, value?: any, index?: num // TODO: // - As per Enum, actually use TS enum // - It should rather probably extend Enum instead of copying code -export default class Enum extends Base { - private _def: TypesDef; +export default class Enum implements Codec { + public readonly registry: Registry; - private _index: number; + readonly #def: TypesDef; - private _indexes: number[]; + readonly #index: number; - private _isBasic: boolean; + readonly #indexes: number[]; + + readonly #isBasic: boolean; + + readonly #raw: Codec; constructor (registry: Registry, def: Record | string[], value?: unknown, index?: number) { const defInfo = extractDef(registry, def); const decoded = decodeEnum(registry, defInfo.def, value, index); - super(registry, decoded.value); - - this._def = defInfo.def; - this._isBasic = defInfo.isBasic; - this._indexes = Object.keys(defInfo.def).map((_, index): number => index); - this._index = this._indexes.indexOf(decoded.index) || 0; + this.registry = registry; + this.#def = defInfo.def; + this.#isBasic = defInfo.isBasic; + this.#indexes = Object.keys(defInfo.def).map((_, index): number => index); + this.#index = this.#indexes.indexOf(decoded.index) || 0; + this.#raw = decoded.value; } public static with (Types: Record | string[]): EnumConstructor { @@ -140,7 +146,7 @@ export default class Enum extends Base { constructor (registry: Registry, value?: unknown, index?: number) { super(registry, Types, value, index); - Object.keys(this._def).forEach((_key): void => { + Object.keys(this.#def).forEach((_key): void => { const name = stringUpperFirst(stringCamelCase(_key.replace(' ', '_'))); const askey = `as${name}`; const iskey = `is${name}`; @@ -175,21 +181,35 @@ export default class Enum extends Base { * @description The length of the value when encoded as a Uint8Array */ public get encodedLength (): number { - return 1 + this._raw.encodedLength; + return 1 + this.#raw.encodedLength; + } + + /** + * @description returns a hash of the contents + */ + public get hash (): H256 { + return new Raw(this.registry, blake2AsU8a(this.toU8a(), 256)); } /** * @description The index of the metadata value */ public get index (): number { - return this._index; + return this.#index; } /** * @description true if this is a basic enum (no values) */ public get isBasic (): boolean { - return this._isBasic; + return this.#isBasic; + } + + /** + * @description Checks if the value is an empty value + */ + public get isEmpty (): boolean { + return this.#raw.isEmpty; } /** @@ -203,35 +223,35 @@ export default class Enum extends Base { * @description Checks if the Enum points to a [[Null]] type (deprecated, use isNone) */ public get isNull (): boolean { - return this._raw instanceof Null; + return this.#raw instanceof Null; } /** * @description The available keys for this enum */ public get defEntries (): string[] { - return Object.keys(this._def); + return Object.keys(this.#def); } /** * @description The available keys for this enum */ public get defKeys (): string[] { - return Object.keys(this._def); + return Object.keys(this.#def); } /** * @description The name of the type this enum value represents */ public get type (): string { - return this.defKeys[this._index]; + return this.defKeys[this.#index]; } /** * @description The value of the enum */ public get value (): Codec { - return this._raw; + return this.#raw; } /** @@ -241,7 +261,7 @@ export default class Enum extends Base { // cater for the case where we only pass the enum index if (isNumber(other)) { return this.toNumber() === other; - } else if (this._isBasic && isString(other)) { + } else if (this.#isBasic && isString(other)) { return this.type === other; } else if (isU8a(other)) { return !this.toU8a().some((entry, index): boolean => entry !== other[index]); @@ -268,34 +288,34 @@ export default class Enum extends Base { * @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._isBasic + return this.#isBasic ? this.type - : { [this.type]: this._raw.toHuman(isExtended) }; + : { [this.type]: this.#raw.toHuman(isExtended) }; } /** * @description Converts the Object to JSON, typically used for RPC transfers */ public toJSON (): AnyJson { - return this._isBasic + return this.#isBasic ? this.type - : { [this.type]: this._raw.toJSON() }; + : { [this.type]: this.#raw.toJSON() }; } /** * @description Returns the number representation for the value */ public toNumber (): number { - return this._index; + return this.#index; } /** * @description Returns a raw struct representation of the enum types */ protected _toRawStruct (): string[] | Record { - return this._isBasic + return this.#isBasic ? this.defKeys - : Struct.typesToMap(this.registry, this._def); + : Struct.typesToMap(this.registry, this.#def); } /** @@ -319,11 +339,11 @@ export default class Enum extends Base { * @param isBare true when the value has none of the type-specific prefixes (internal) */ public toU8a (isBare?: boolean): Uint8Array { - const index = this._indexes[this._index]; + const index = this.#indexes[this.#index]; return u8aConcat( new Uint8Array([index]), - this._raw.toU8a(isBare) + this.#raw.toU8a(isBare) ); } } diff --git a/packages/types/src/codec/Option.ts b/packages/types/src/codec/Option.ts index 8d927e92d9..9d6abd7f37 100644 --- a/packages/types/src/codec/Option.ts +++ b/packages/types/src/codec/Option.ts @@ -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 { Codec, Constructor, InterfaceTypes, Registry } from '../types'; +import { H256 } from '@polkadot/types/interfaces'; +import { AnyJson, Codec, Constructor, InterfaceTypes, Registry } from '../types'; import { isNull, isU8a, isUndefined, u8aToHex } from '@polkadot/util'; +import { blake2AsU8a } from '@polkadot/util-crypto'; import Null from '../primitive/Null'; import { typeToConstructor } from './utils'; -import Base from './Base'; +import Raw from './Raw'; /** @internal */ function decodeOptionU8a (registry: Registry, Type: Constructor, value: Uint8Array): Codec { @@ -48,15 +50,17 @@ function decodeOption (registry: Registry, typeName: Constructor | keyof Interfa * implements that - decodes, checks for optionality and wraps the required structure * with a value if/as required/found. */ -export default class Option extends Base { +export default class Option implements Codec { + public readonly registry: Registry; + readonly #Type: Constructor; - constructor (registry: Registry, typeName: Constructor | keyof InterfaceTypes, value?: unknown) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - super(registry, decodeOption(registry, typeName, value)); + readonly #raw: T; + constructor (registry: Registry, typeName: Constructor | keyof InterfaceTypes, value?: unknown) { + this.registry = registry; this.#Type = typeToConstructor(registry, typeName); + this.#raw = decodeOption(registry, typeName, value) as T; } public static with (Type: Constructor | keyof InterfaceTypes): Constructor> { @@ -72,7 +76,14 @@ export default class Option extends Base { */ public get encodedLength (): number { // boolean byte (has value, doesn't have) along with wrapped length - return 1 + this._raw.encodedLength; + return 1 + this.#raw.encodedLength; + } + + /** + * @description returns a hash of the contents + */ + public get hash (): H256 { + return new Raw(this.registry, blake2AsU8a(this.toU8a(), 256)); } /** @@ -86,7 +97,7 @@ export default class Option extends Base { * @description Checks if the Option has no value */ public get isNone (): boolean { - return this._raw instanceof Null; + return this.#raw instanceof Null; } /** @@ -100,7 +111,7 @@ export default class Option extends Base { * @description The actual value for the Option */ public get value (): Codec { - return this._raw; + return this.#raw; } /** @@ -125,6 +136,20 @@ export default class Option extends Base { : u8aToHex(this.toU8a().subarray(1)); } + /** + * @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.#raw.toHuman(isExtended); + } + + /** + * @description Converts the Object to JSON, typically used for RPC transfers + */ + public toJSON (): AnyJson { + return this.#raw.toJSON(); + } + /** * @description Returns the base runtime type name for this instance */ @@ -136,20 +161,27 @@ export default class Option extends Base { : `Option<${wrapped}>`; } + /** + * @description Returns the string representation of the value + */ + public toString (): string { + return this.#raw.toString(); + } + /** * @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) */ public toU8a (isBare?: boolean): Uint8Array { if (isBare) { - return this._raw.toU8a(true); + return this.#raw.toU8a(true); } const u8a = new Uint8Array(this.encodedLength); if (this.isSome) { u8a.set([1]); - u8a.set(this._raw.toU8a(), 1); + u8a.set(this.#raw.toU8a(), 1); } return u8a; @@ -163,7 +195,7 @@ export default class Option extends Base { throw new Error('Option: unwrapping a None value'); } - return this._raw; + return this.#raw; } /** diff --git a/packages/types/src/codec/Result.ts b/packages/types/src/codec/Result.ts index dd20b6f894..37b3ba916c 100644 --- a/packages/types/src/codec/Result.ts +++ b/packages/types/src/codec/Result.ts @@ -50,7 +50,7 @@ export default class Result extends Enum { * @description Checks if the Result has no value */ public get isEmpty (): boolean { - return this.isOk && this._raw.isEmpty; + return this.isOk && this.value.isEmpty; } /** diff --git a/packages/types/src/primitive/Data.ts b/packages/types/src/primitive/Data.ts index 0f00a7b495..ce1163787b 100644 --- a/packages/types/src/primitive/Data.ts +++ b/packages/types/src/primitive/Data.ts @@ -67,11 +67,11 @@ export default class Data extends Enum { } get asRaw (): Bytes { - return this._raw as Bytes; + return this.value as Bytes; } get asSha256 (): H256 { - return this._raw as H256; + return this.value as H256; } get isRaw (): boolean { @@ -97,7 +97,7 @@ export default class Data extends Enum { return new Uint8Array(1); } else if (this.index === 1) { // don't add the length, just the data - const data = this._raw.toU8a(true); + const data = this.value.toU8a(true); const length = Math.min(data.length, 32); const u8a = new Uint8Array(length + 1); @@ -111,7 +111,7 @@ export default class Data extends Enum { const u8a = new Uint8Array(33); u8a.set([this.index + 32], 0); - u8a.set(this._raw.toU8a(), 1); + u8a.set(this.value.toU8a(), 1); return u8a; }