Type detection with trimming (#3850)

* Type detection with trimming

* Additional interface check
This commit is contained in:
Jaco
2021-08-06 12:48:45 +02:00
committed by GitHub
parent a60d80953b
commit 697781fb52
2 changed files with 71 additions and 61 deletions
+13 -10
View File
@@ -4,6 +4,7 @@
import type { Compact, Option } from './codec';
import type { AccountId, BlockAttestations, SessionKeys7 } from './interfaces';
import type { Bytes, u32 } from './primitive';
import type { IOption, ITuple } from './types';
import { assert } from '@polkadot/util';
@@ -17,32 +18,34 @@ const oo1 = registry.createType<BlockAttestations>('u32');
const oo2 = registry.createType<SessionKeys7>('u32');
const oo3 = registry.createType<u32>('Something');
const oo4 = registry.createType<AccountId>('Option<u32>');
const oo5 = registry.createType<Option<u32>>('u32');
const oo5 = registry.createType<IOption<u32>>('u32');
const oo6 = registry.createType<Option<Compact<u32>>>('u32');
const oo7 = registry.createType<Bytes>('u64');
const oo8 = registry.createType<ITuple<[Bytes, u32]>>('Something');
assert(oo0.divn(123) && [...oo1.values()] && oo2[6].isAscii && oo3.divn(3) && oo4.isAscii && oo5.unwrap().divn(1) && oo6.unwrap().unwrap().divn(1) && oo7.isAscii, 'All ok');
assert(oo0.divn(123) && [...oo1.values()] && oo2[6].isAscii && oo3.divn(3) && oo4.isAscii && oo5.unwrap().divn(1) && oo6.unwrap().unwrap().divn(1) && oo7.isAscii && oo8[1].toNumber(), 'All ok');
// There are in the interface registry
const aa0 = registry.createType('AccountId');
const aa0 = registry.createType(' AccountId');
const aa1 = registry.createType('BlockAttestations');
const aa2 = registry.createType('ExtrinsicEra');
assert(aa0.isAscii && aa1.receipt, 'All ok');
assert(aa0.isAscii && aa1.receipt && aa2.isMortalEra, 'All ok');
// Should be Codec, we don't know this one
const bb = registry.createType('Something');
assert(bb.toHuman(), 'All ok');
// Should be Vec<Option<Compact<u32>>>
const ee = registry.createType('Vec<Option<Compact<u32>>>');
// Should be Vec<Option<Compact<ReferendumIndex>>>
const ee = registry.createType('Vec<Option<Compact<ReferendumIndex>>>');
// Option<Bytes>
const vb = registry.createType('Option<Vec<u8>>');
const vb = registry.createType('Option< Vec< u8 > >');
assert(ee[0].unwrap().unwrap().divn(123) && vb.unwrap().bitLength(), 'All ok');
// Should end up as Raw
const gg = registry.createType('[u8;678]');
const gg = registry.createType('[ u8 ;678]');
assert(gg.bitLength, 'All ok');
@@ -52,9 +55,9 @@ const hh = registry.createType('[u128; 32]');
assert(hh[0].bitLength(), 'All ok');
// tuple! ITuple<[u32, Compact<u64>, u128, Codec]>
const tt1 = registry.createType('(u32, Compact<u64>,u128, Something)');
const tt1 = registry.createType('(u32, Compact< u64 >,u128, Something)');
// unwraps into a u32
const tt2 = registry.createType('(u32)');
const tt2 = registry.createType('( u32 )');
// max number of params
const tt3 = registry.createType('(u8,u16,u32,u64,u128)');
// lots and lots of params
+58 -51
View File
@@ -2,72 +2,79 @@
// SPDX-License-Identifier: Apache-2.0
import type { Compact, Option, Raw, Struct, Vec, VecFixed } from '../codec';
import type { AbstractArray } from '../codec/AbstractArray';
import type { CompactEncodable } from '../codec/types';
import type { Bytes } from '../primitive';
import type { Codec, Constructor } from './codec';
import type { ITuple } from './interfaces';
import type { ICompact, IOption, ITuple, IU8a, IVec } from './interfaces';
import type { InterfaceTypes } from './registry';
// Vec & Tuple extends AbstractArray
export type KnownDetects = Compact<CompactEncodable> | Option<Codec> | AbstractArray<Codec> | Raw | Struct;
export type DetectCodec<T extends Codec, K extends string> = Expand<K, T>;
export type DetectConstructor<T extends Codec, K extends string> = Constructor<Expand<K, T>>;
export type Expand<K extends string, T extends Codec = Codec> = K extends keyof InterfaceTypes
? InterfaceTypes[K]
// these are the ones we short-circuit in the wrap itself
: T extends KnownDetects
? T
: // strip any leading spaces from the types...
K extends ` ${infer I}`
? Expand<I, T>
// ... and any trailing spaces
: K extends `${infer I} `
? Expand<I, T>
: ExpandWrap<K, T>;
export type Expand<K extends string, T extends Codec = Codec> = __Internal<Trim<K>, T>;
// trim leading and trailing spaces
export type Trim<K extends string> =
K extends ` ${infer X}`
? Trim<X>
: K extends `${infer X} `
? Trim<X>
: K;
export type __DetectableTypes = CompactEncodable | ICompact<CompactEncodable> | IOption<Codec> | ITuple<Codec[]> | IU8a | IVec<Codec> | Struct;
export type __Internal<K extends string, T extends Codec> =
K extends keyof InterfaceTypes
? InterfaceTypes[K]
: T extends __DetectableTypes
? T
: __Unwrap<K, T>;
// ensure whatever we wrap is always Compact-capable
export type ExpandCompact<T extends Codec> = T extends CompactEncodable
? Compact<T>
: never;
export type __Compact<T extends Codec> =
T extends CompactEncodable
? Compact<T>
: never;
// currently we only support 5 levels for auto-extract
export type ExpandTuple<X extends string, T extends Codec> = X extends `${infer A},${infer B},${infer C},${infer D},${infer E}`
? ITuple<[Expand<A>, Expand<B>, Expand<C>, Expand<D>, Expand<E>]>
: X extends `${infer A},${infer B},${infer C},${infer D}`
? ITuple<[Expand<A>, Expand<B>, Expand<C>, Expand<D>]>
: X extends `${infer A},${infer B},${infer C}`
? ITuple<[Expand<A>, Expand<B>, Expand<C>]>
: X extends `${infer A},${infer B}`
? ITuple<[Expand<A>, Expand<B>]>
: X extends `${infer A}`
? Expand<A>
: T;
export type __Tuple<X extends string, T extends Codec> =
X extends `${infer A},${infer B},${infer C},${infer D},${infer E}`
? ITuple<[Expand<A>, Expand<B>, Expand<C>, Expand<D>, Expand<E>]>
: X extends `${infer A},${infer B},${infer C},${infer D}`
? ITuple<[Expand<A>, Expand<B>, Expand<C>, Expand<D>]>
: X extends `${infer A},${infer B},${infer C}`
? ITuple<[Expand<A>, Expand<B>, Expand<C>]>
: X extends `${infer A},${infer B}`
? ITuple<[Expand<A>, Expand<B>]>
: X extends `${infer A}`
? Expand<A>
: T;
// vec support with short-circuit for u8
export type ExpandVec<X extends string, T extends Codec> = X extends 'u8'
? Bytes
: Vec<Expand<X, T>>;
export type __Vec<X extends string, T extends Codec> =
Trim<X> extends 'u8'
? Bytes
: Vec<Expand<X, T>>;
// fixed vec support
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export type ExpandVecFixed<X extends string> = X extends `${infer Y};${infer _}`
? Y extends 'u8'
? Raw
: VecFixed<Expand<Y>>
: never;
export type __VecFixed<X extends string> =
// eslint-disable-next-line @typescript-eslint/no-unused-vars
X extends `${infer Y};${infer _}`
? Trim<Y> extends 'u8'
? Raw
: VecFixed<Expand<Y>>
: never;
export type ExpandWrap<K extends string, T extends Codec> = K extends `Compact<${infer X}>`
? ExpandCompact<Expand<X>>
: K extends `Option<${infer X}>`
? Option<Expand<X>>
: K extends `Vec<${infer X}>`
? ExpandVec<X, T>
: K extends `[${infer X}]`
? ExpandVecFixed<X>
: K extends `(${infer X})`
? ExpandTuple<X, T>
: T;
export type __Unwrap<K extends string, T extends Codec> =
K extends `Compact<${infer X}>`
? __Compact<Expand<X>>
: K extends `Option<${infer X}>`
? Option<Expand<X>>
: K extends `Vec<${infer X}>`
? __Vec<X, T>
: K extends `[${infer X}]`
? __VecFixed<X>
: K extends `(${infer X})`
? __Tuple<X, T>
: T;