Allow for fallback types (struct-only as a start) (#3714)
* Allow for fallback types (struct-only as a start) * Filter fallback & alias from structs * Don't clobber existing fallbackType
This commit is contained in:
@@ -175,7 +175,7 @@ const infoMapping: Record<TypeDefInfo, (registry: Registry, value: TypeDef) => C
|
||||
|
||||
// Returns the type Class for construction
|
||||
export function getTypeClass<T extends Codec = Codec> (registry: Registry, value: TypeDef): Constructor<T> {
|
||||
const Type = registry.get<T>(value.type);
|
||||
let Type = registry.get<T>(value.type);
|
||||
|
||||
if (Type) {
|
||||
return Type;
|
||||
@@ -185,5 +185,14 @@ export function getTypeClass<T extends Codec = Codec> (registry: Registry, value
|
||||
|
||||
assert(getFn, () => `Unable to construct class from ${stringify(value)}`);
|
||||
|
||||
return getFn(registry, value) as Constructor<T>;
|
||||
Type = getFn(registry, value) as Constructor<T>;
|
||||
|
||||
// don't clobber any existing
|
||||
if (!Type.__fallbackType && value.fallbackType) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore ...this is the only place we we actually assign this...
|
||||
Type.__fallbackType = value.fallbackType;
|
||||
}
|
||||
|
||||
return Type;
|
||||
}
|
||||
|
||||
@@ -55,11 +55,28 @@ function initType<T extends Codec = Codec, K extends string = string> (registry:
|
||||
// argument here can be any string, which, when it cannot parse, will yield a
|
||||
// runtime error.
|
||||
export function createTypeUnsafe<T extends Codec = Codec, K extends string = string> (registry: Registry, type: K, params: unknown[] = [], options: CreateOptions = {}): T {
|
||||
let Clazz: Constructor<FromReg<T, K>> | null = null;
|
||||
let firstError: Error | null = null;
|
||||
|
||||
try {
|
||||
return initType(registry, createClass<T, K>(registry, type), params, options);
|
||||
Clazz = createClass<T, K>(registry, type);
|
||||
|
||||
return initType(registry, Clazz, params, options);
|
||||
} catch (error) {
|
||||
throw new Error(`createType(${type}):: ${(error as Error).message}`);
|
||||
firstError = new Error(`createType(${type}):: ${(error as Error).message}`);
|
||||
}
|
||||
|
||||
if (Clazz && Clazz.__fallbackType) {
|
||||
try {
|
||||
Clazz = createClass<T, K>(registry, Clazz.__fallbackType as unknown as K);
|
||||
|
||||
return initType(registry, Clazz, params, options);
|
||||
} catch {
|
||||
// swallow, we will throw the first error again
|
||||
}
|
||||
}
|
||||
|
||||
throw firstError;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,7 @@ interface TypeDefOptions {
|
||||
}
|
||||
|
||||
const MAX_NESTED = 64;
|
||||
const KNOWN_INTERNALS = ['_alias', '_fallback'];
|
||||
|
||||
function getTypeString (typeOrObj: any): string {
|
||||
return isString(typeOrObj)
|
||||
@@ -100,7 +101,8 @@ function _decodeStruct (value: TypeDef, type: string, _: string, count: number):
|
||||
value.alias = parsed._alias
|
||||
? new Map(Object.entries(parsed._alias))
|
||||
: undefined;
|
||||
value.sub = keys.filter((name) => !['_alias'].includes(name)).map((name): TypeDef =>
|
||||
value.fallbackType = parsed._fallback as string | undefined;
|
||||
value.sub = keys.filter((name) => !KNOWN_INTERNALS.includes(name)).map((name): TypeDef =>
|
||||
getTypeDef(getTypeString(parsed[name]), { name }, count)
|
||||
);
|
||||
|
||||
|
||||
@@ -32,9 +32,10 @@ export enum TypeDefInfo {
|
||||
|
||||
export interface TypeDef {
|
||||
alias?: Map<string, string>;
|
||||
displayName?: string;
|
||||
fallbackType?: string;
|
||||
info: TypeDefInfo;
|
||||
index?: number;
|
||||
displayName?: string;
|
||||
length?: number;
|
||||
name?: string;
|
||||
namespace?: string;
|
||||
|
||||
@@ -140,12 +140,19 @@ export default {
|
||||
},
|
||||
types: {
|
||||
AccountInfo: 'AccountInfoWithTripleRefCount',
|
||||
AccountInfoWithRefCountU8: {
|
||||
nonce: 'Index',
|
||||
refcount: 'u8',
|
||||
data: 'AccountData'
|
||||
},
|
||||
AccountInfoWithRefCount: {
|
||||
_fallback: 'AccountInfoWithRefCountU8',
|
||||
nonce: 'Index',
|
||||
refcount: 'RefCount',
|
||||
data: 'AccountData'
|
||||
},
|
||||
AccountInfoWithDualRefCount: {
|
||||
_fallback: 'AccountInfoWithRefCount',
|
||||
nonce: 'Index',
|
||||
consumers: 'RefCount',
|
||||
providers: 'RefCount',
|
||||
@@ -154,6 +161,7 @@ export default {
|
||||
// original naming
|
||||
AccountInfoWithProviders: 'AccountInfoWithDualRefCount',
|
||||
AccountInfoWithTripleRefCount: {
|
||||
_fallback: 'AccountInfoWithDualRefCount',
|
||||
nonce: 'Index',
|
||||
consumers: 'RefCount',
|
||||
providers: 'RefCount',
|
||||
|
||||
@@ -108,6 +108,11 @@ export type CodecArg = Codec | BigInt | BN | boolean | string | Uint8Array | boo
|
||||
interface CodecArgArray extends Array<CodecArg> {}
|
||||
|
||||
export interface Constructor<T = Codec> {
|
||||
/**
|
||||
* @description An internal fallback type (previous generation) if encoding fails
|
||||
*/
|
||||
readonly __fallbackType?: string;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
new(registry: Registry, ...value: any[]): T;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,12 @@ export type DefinitionTypeEnum = { _enum: DefinitionTypeType[] } | { _enum: Reco
|
||||
|
||||
export type DefinitionTypeSet = { _set: Record<string, number> };
|
||||
|
||||
export type DefinitionTypeStruct = Record<string, DefinitionTypeType> | { _alias?: Record<string, DefinitionTypeType> } & Record<string, unknown>;
|
||||
type DefinitionTypeStructExtra = {
|
||||
_alias?: Record<string, DefinitionTypeType>;
|
||||
_fallback?: DefinitionTypeType;
|
||||
} & Record<string, unknown>;
|
||||
|
||||
export type DefinitionTypeStruct = Record<string, DefinitionTypeType> | DefinitionTypeStructExtra;
|
||||
|
||||
export type DefinitionType = string | DefinitionTypeEnum | DefinitionTypeSet | DefinitionTypeStruct;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user