diff --git a/packages/typegen/src/generate/tsDef.ts b/packages/typegen/src/generate/tsDef.ts index 87faf7f22f..70fc711248 100644 --- a/packages/typegen/src/generate/tsDef.ts +++ b/packages/typegen/src/generate/tsDef.ts @@ -189,6 +189,7 @@ const encoders: Record, imports: TypeImports, withShortcut: boolean) => { + throw new Error(`TypeDefInfo.Range: Not implemented on ${stringify(typeDef)}`); + }, [TypeDefInfo.Set]: (registry: Registry, typeDef: TypeDef, definitions: Record, imports: TypeImports, withShortcut: boolean) => { throw new Error(`TypeDefInfo.Set: Not implemented on ${stringify(typeDef)}`); }, diff --git a/packages/types/src/codec/Range.spec.ts b/packages/types/src/codec/Range.spec.ts index fff10ad849..287574b732 100644 --- a/packages/types/src/codec/Range.spec.ts +++ b/packages/types/src/codec/Range.spec.ts @@ -7,21 +7,19 @@ import { Range } from '.'; describe('Range', (): void => { const registry = new TypeRegistry(); - const Type = Range.with([U32, U32]); let range: Range; beforeEach((): void => { - range = new Range( + const Clazz = Range.with(U32); + + range = new Clazz( registry, - U32, [new U32(registry, 1), new U32(registry, 2)] ); }); it('decodes', (): void => { - const rslt = new Type(registry, new Uint8Array([1, 0, 0, 0, 2, 0, 0, 0])); - - expect(rslt.toJSON()).toEqual([1, 2]); + expect(range.toJSON()).toEqual([1, 2]); }); it('encodes', (): void => { diff --git a/packages/types/src/codec/Range.ts b/packages/types/src/codec/Range.ts index 4e13c38543..2fca97c59e 100644 --- a/packages/types/src/codec/Range.ts +++ b/packages/types/src/codec/Range.ts @@ -1,25 +1,32 @@ // Copyright 2017-2021 @polkadot/types authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { Codec, Constructor, InterfaceTypes, Registry } from '../types'; +import type { AnyTuple, Constructor, INumber, Registry } from '../types'; import { Tuple } from '../codec/Tuple'; +type RangeType = 'Range' | 'RangeInclusive'; + /** * @name Range * @description * Rust `Range` representation */ -export class Range extends Tuple { - constructor (registry: Registry, ty: Constructor | keyof InterfaceTypes, value: [T, T]) { - super( - registry, - { - end: ty, - start: ty - }, - value - ); +export class Range extends Tuple { + #rangeName: RangeType; + + constructor (registry: Registry, Type: Constructor | string, value?: AnyTuple, rangeName: RangeType = 'Range') { + super(registry, { end: Type, start: Type }, value); + + this.#rangeName = rangeName; + } + + public static override with (Types: Constructor | string): Constructor> { + return class extends Range { + constructor (registry: Registry, value?: AnyTuple) { + super(registry, Types, value); + } + }; } /** @@ -40,6 +47,20 @@ export class Range extends Tuple { * @description Returns the base runtime type name for this instance */ public override toRawType (): string { - return `Range<${this.start.toRawType()}>`; + return `${this.#rangeName}<${this.start.toRawType()}>`; + } +} + +export class RangeInclusive extends Range { + constructor (registry: Registry, type: Constructor | string, value?: AnyTuple) { + super(registry, type, value, 'RangeInclusive'); + } + + public static override with (Types: Constructor | string): Constructor> { + return class extends RangeInclusive { + constructor (registry: Registry, value?: AnyTuple) { + super(registry, Types, value); + } + }; } } diff --git a/packages/types/src/codec/RangeInclusive.spec.ts b/packages/types/src/codec/RangeInclusive.spec.ts deleted file mode 100644 index 1fc7a94580..0000000000 --- a/packages/types/src/codec/RangeInclusive.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017-2021 @polkadot/types authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import { TypeRegistry } from '../create'; -import { U32 } from '../primitive'; -import { RangeInclusive } from '.'; - -describe('RangeInclusive', (): void => { - const registry = new TypeRegistry(); - const Type = RangeInclusive.with([U32, U32]); - let range: RangeInclusive; - - beforeEach((): void => { - range = new RangeInclusive( - registry, - U32, - [new U32(registry, 1), new U32(registry, 2)] - ); - }); - - it('decodes', (): void => { - const rslt = new Type(registry, new Uint8Array([1, 0, 0, 0, 2, 0, 0, 0])); - - expect(rslt.toJSON()).toEqual([1, 2]); - }); - - it('encodes', (): void => { - expect(range.toU8a()).toEqual(new Uint8Array([1, 0, 0, 0, 2, 0, 0, 0])); - }); - - it('has a sane toRawType representation', (): void => { - expect(range.toRawType()).toEqual('RangeInclusive'); - }); -}); diff --git a/packages/types/src/codec/RangeInclusive.ts b/packages/types/src/codec/RangeInclusive.ts deleted file mode 100644 index aa0909003e..0000000000 --- a/packages/types/src/codec/RangeInclusive.ts +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2017-2021 @polkadot/types authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import type { Codec, Constructor, InterfaceTypes, Registry } from '../types'; - -import { Tuple } from '../codec/Tuple'; - -/** - * @name RangeInclusive - * @description - * Rust `RangeInclusive` representation - */ -export class RangeInclusive extends Tuple { - constructor (registry: Registry, ty: Constructor | keyof InterfaceTypes, value: [T, T]) { - super( - registry, - { - end: ty, - start: ty - }, - value - ); - } - - /** - * @description Returns the starting range value - */ - public get start (): T { - return this[0] as T; - } - - /** - * @description Returns the ending range value - */ - public get end (): T { - return this[1] as T; - } - - /** - * @description Returns the base runtime type name for this instance - */ - public override toRawType (): string { - return `RangeInclusive<${this.start.toRawType()}>`; - } -} diff --git a/packages/types/src/codec/Tuple.ts b/packages/types/src/codec/Tuple.ts index f980bc3ee0..f9dbaf07bb 100644 --- a/packages/types/src/codec/Tuple.ts +++ b/packages/types/src/codec/Tuple.ts @@ -3,7 +3,7 @@ import type { AnyNumber, AnyString, AnyU8a, Codec, Constructor, ITuple, Registry } from '../types'; -import { isHex, isU8a, stringify, u8aConcat, u8aToU8a } from '@polkadot/util'; +import { isFunction, isHex, isString, isU8a, stringify, u8aConcat, u8aToU8a } from '@polkadot/util'; import { AbstractArray } from './AbstractArray'; import { decodeU8a, mapToTypeMap, typeToConstructor } from './utils'; @@ -14,7 +14,9 @@ type TupleConstructors = Constructor[] | { [index: string]: Constructor; }; -type TupleTypes = (Constructor | string)[] | { +type TupleType = (Constructor | string); + +type TupleTypes = TupleType[] | { [index: string]: Constructor | string; }; @@ -52,17 +54,19 @@ function decodeTuple (registry: Registry, _Types: TupleConstructors, value?: Any export class Tuple extends AbstractArray implements ITuple { private _Types: TupleConstructors; - constructor (registry: Registry, Types: TupleTypes, value?: AnyTuple) { + constructor (registry: Registry, Types: TupleTypes | TupleType, value?: AnyTuple) { const Clazzes = Array.isArray(Types) ? Types.map((t) => typeToConstructor(registry, t)) - : mapToTypeMap(registry, Types); + : isFunction(Types) || isString(Types) + ? [typeToConstructor(registry, Types)] + : mapToTypeMap(registry, Types); super(registry, ...decodeTuple(registry, Clazzes, value)); this._Types = Clazzes; } - public static with (Types: TupleTypes): Constructor { + public static with (Types: TupleTypes | TupleType): Constructor { return class extends Tuple { constructor (registry: Registry, value?: AnyTuple) { super(registry, Types, value); diff --git a/packages/types/src/codec/index.ts b/packages/types/src/codec/index.ts index 64aee4e410..53e35d292a 100644 --- a/packages/types/src/codec/index.ts +++ b/packages/types/src/codec/index.ts @@ -19,10 +19,9 @@ export { Json } from './Json'; export { Linkage } from './Linkage'; export { CodecMap, CodecMap as Map } from './Map'; export { Option } from './Option'; +export { Range, RangeInclusive } from './Range'; export { Raw } from './Raw'; export { Result } from './Result'; -export { Range } from './Range'; -export { RangeInclusive } from './RangeInclusive'; export { CodecSet, CodecSet as Set } from './Set'; export { Struct } from './Struct'; export { Tuple } from './Tuple'; diff --git a/packages/types/src/create/createClass.ts b/packages/types/src/create/createClass.ts index 946e2cf28b..44860c89e1 100644 --- a/packages/types/src/create/createClass.ts +++ b/packages/types/src/create/createClass.ts @@ -7,7 +7,7 @@ import type { TypeDef } from './types'; import { assert, isNumber, isUndefined, stringify } from '@polkadot/util'; -import { BTreeMap, BTreeSet, CodecSet, Compact, DoNotConstruct, Enum, HashMap, Int, Option, Result, Struct, Tuple, U8aFixed, UInt, Vec, VecFixed } from '../codec'; +import { BTreeMap, BTreeSet, CodecSet, Compact, DoNotConstruct, Enum, HashMap, Int, Option, Range, RangeInclusive, Result, Struct, Tuple, U8aFixed, UInt, Vec, VecFixed } from '../codec'; import { Bytes, Null } from '../primitive'; import { getTypeDef } from './getTypeDef'; import { TypeDefInfo } from './types'; @@ -114,6 +114,9 @@ const infoMapping: Record C [TypeDefInfo.Plain]: (registry: Registry, value: TypeDef): Constructor => registry.getOrUnknown(value.type), + [TypeDefInfo.Range]: (registry: Registry, value: TypeDef): Constructor => + (value.type.includes('RangeInclusive') ? RangeInclusive : Range).with(getSubType(value)), + [TypeDefInfo.Result]: (registry: Registry, value: TypeDef): Constructor => { const [Ok, Err] = getTypeClassArray(value); diff --git a/packages/types/src/create/encodeTypes.ts b/packages/types/src/create/encodeTypes.ts index 41cf4eeaaa..385a015bee 100644 --- a/packages/types/src/create/encodeTypes.ts +++ b/packages/types/src/create/encodeTypes.ts @@ -133,6 +133,8 @@ const encoders: Record st // eslint-disable-next-line @typescript-eslint/no-unused-vars [TypeDefInfo.Plain]: (registry: Registry, typeDef: TypeDef) => typeDef.displayName || typeDef.type, + [TypeDefInfo.Range]: (registry: Registry, typeDef: TypeDef) => + encodeWithParams(registry, typeDef, typeDef.type.includes('RangeInclusive') ? 'RangeInclusive' : 'Range'), [TypeDefInfo.Result]: (registry: Registry, typeDef: TypeDef) => encodeWithParams(registry, typeDef, 'Result'), // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/packages/types/src/create/getTypeDef.ts b/packages/types/src/create/getTypeDef.ts index 2b75bdb505..917604235b 100644 --- a/packages/types/src/create/getTypeDef.ts +++ b/packages/types/src/create/getTypeDef.ts @@ -142,6 +142,14 @@ function _decodeFixedVec (value: TypeDef, type: string, _: string, count: number return value; } +function _decodeRange (value: TypeDef, _: string, subType: string): TypeDef { + const Type = getTypeDef(subType); + + value.sub = [Type, Type]; + + return value; +} + // decode a tuple function _decodeTuple (value: TypeDef, _: string, subType: string, count: number): TypeDef { value.sub = subType.length === 0 @@ -195,6 +203,9 @@ const nestedExtraction: [string, string, TypeDefInfo, (value: TypeDef, type: str ['BTreeMap<', '>', TypeDefInfo.BTreeMap, _decodeTuple], ['HashMap<', '>', TypeDefInfo.HashMap, _decodeTuple], ['Int<', '>', TypeDefInfo.Int, _decodeInt], + // Not sure about these, have a specific implementation? + ['Range<', '>', TypeDefInfo.Tuple, _decodeRange], + ['RangeInclusive<', '>', TypeDefInfo.Tuple, _decodeRange], ['Result<', '>', TypeDefInfo.Result, _decodeTuple], ['UInt<', '>', TypeDefInfo.UInt, _decodeUInt], ['DoNotConstruct<', '>', TypeDefInfo.DoNotConstruct, _decodeDoNotConstruct] diff --git a/packages/types/src/create/sanitize.ts b/packages/types/src/create/sanitize.ts index 4fddacdd5f..9c7db2b775 100644 --- a/packages/types/src/create/sanitize.ts +++ b/packages/types/src/create/sanitize.ts @@ -8,7 +8,7 @@ interface SanitizeOptions { type Mapper = (value: string, options?: SanitizeOptions) => string; const BOUNDED = ['BTreeMap', 'BTreeSet', 'HashMap', 'Vec']; -const ALLOWED_BOXES = BOUNDED.concat(['Compact', 'DoNotConstruct', 'Int', 'Linkage', 'Result', 'Option', 'UInt']); +const ALLOWED_BOXES = BOUNDED.concat(['Compact', 'DoNotConstruct', 'Int', 'Linkage', 'Range', 'RangeInclusive', 'Result', 'Option', 'UInt']); const BOX_PRECEDING = ['<', '(', '[', '"', ',', ' ']; // start of vec, tuple, fixed array, part of struct def or in tuple const mappings: Mapper[] = [ diff --git a/packages/types/src/create/types.ts b/packages/types/src/create/types.ts index 7285db7d66..bcefff9228 100644 --- a/packages/types/src/create/types.ts +++ b/packages/types/src/create/types.ts @@ -20,6 +20,7 @@ export enum TypeDefInfo { UInt, DoNotConstruct, Si, + Range, // anything not fully supported (keep this as the last entry) Null } diff --git a/packages/types/src/types/detect.ts b/packages/types/src/types/detect.ts index 8c7ac6c211..e2ae831669 100644 --- a/packages/types/src/types/detect.ts +++ b/packages/types/src/types/detect.ts @@ -1,7 +1,7 @@ // Copyright 2017-2021 @polkadot/types authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { BTreeMap, BTreeSet, CodecSet, Compact, Enum, HashMap, Linkage, Option, Raw, Struct, Vec, VecFixed } from '../codec'; +import type { BTreeMap, BTreeSet, CodecSet, Compact, Enum, HashMap, Linkage, Option, Range, RangeInclusive, Raw, Result, Struct, Vec, VecFixed } from '../codec'; import type { Bytes, Null, u8 } from '../primitive'; import type { Codec, Constructor } from './codec'; import type { ICompact, IEnum, IMap, IMethod, INumber, IOption, IResult, ISet, IStruct, ITuple, IU8a, IVec } from './interfaces'; @@ -42,6 +42,8 @@ export type __MapWrapOne = { 'Compact<': C extends INumber ? Compact : Codec; 'Linkage<': Linkage; 'Option<': Option; + 'Range<': C extends INumber ? Range : Codec; + 'RangeInclusive<': C extends INumber ? RangeInclusive : Codec; 'Vec<': C extends u8 ? Bytes : Vec; '[': C extends u8 ? Raw : VecFixed; }; @@ -51,6 +53,7 @@ export type __MapWrapOne = { export type __MapWrapTwo = { 'BTreeMap<': BTreeMap; 'HashMap<': HashMap; + 'Result<': Result; }; export type __WrapOne = keyof __MapWrapOne; @@ -73,31 +76,25 @@ export type __ToTuple = : O[0] : Null; -export type __CodecFirst = [ +export type __CodecFirst = K extends keyof InterfaceTypes ? InterfaceTypes[K] : K extends unknown[] ? __ToTuple<__Codecs> : K extends Record ? __ToStruct - : K extends __WrapOne - ? __MapWrapOne[K] - : K extends __WrapTwo - ? __MapWrapTwo[K] - : Codec, - ...X -]; + : Codec; export type __CodecsNext = K extends __WrapOne ? C extends [Codec, ...infer X] - ? __CodecFirst - : never + ? [__MapWrapOne[K], ...X] + : Codec : K extends __WrapTwo ? C extends [Codec, Codec, ...infer X] - ? __CodecFirst - : never - : __CodecFirst; + ? [__MapWrapTwo[K], ...X] + : Codec + : [__CodecFirst, ...C]; export type __Codecs = T extends [infer K, ...infer N] @@ -141,13 +138,13 @@ export type __TokenizeKnown = - K extends '' | ')' | '>' | '}' + K extends '' | '>' | ')' | '}' ? [__Combine, ''] : K extends `${__Wrap}${infer R}` ? __TokenizeWrapped : K extends `${',' | '>'}${infer R}` ? __Tokenize> - : K extends `)${infer R}` | `}${infer R}` + : K extends `${')' | '}'}${infer R}` ? [__Combine, R] : K extends `(${infer R}` ? __TokenizeTuple<__Tokenize, V, I>