Adjust struct iterable creation (#4130)
This commit is contained in:
@@ -10,78 +10,64 @@ import { compareMap, decodeU8a, mapToTypeMap } from './utils';
|
||||
|
||||
type TypesDef<T = Codec> = Record<string, string | Constructor<T>>;
|
||||
|
||||
function newEntry (registry: Registry, Type: Constructor, key: string, value: unknown): [string, Codec] {
|
||||
return [
|
||||
key,
|
||||
value instanceof Type
|
||||
? value
|
||||
: new Type(registry, value)
|
||||
];
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function decodeStructFromObject (registry: Registry, Types: ConstructorDef, value: any, jsonMap: Map<any, string>): Iterable<[string, Codec]> {
|
||||
function decodeStructFromObject (registry: Registry, Types: ConstructorDef, value: any, jsonMap: Map<string, string>): Iterable<[string, Codec]> {
|
||||
let jsonObj: Record<string, unknown> | undefined;
|
||||
const inputKeys = Object.keys(Types);
|
||||
|
||||
assert(!Array.isArray(value) || value.length === inputKeys.length, () => `Struct: Unable to map ${stringify(value)} array to object with known keys ${inputKeys.join(', ')}`);
|
||||
|
||||
return Object.entries(
|
||||
inputKeys.reduce<Record<string, Codec>>((raw, key, index) => {
|
||||
// The key in the JSON can be snake_case (or other cases), but in our
|
||||
// Types, result or any other maps, it's camelCase
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
const jsonKey = (jsonMap.get(key as any) && !value[key])
|
||||
? jsonMap.get(key as any)
|
||||
: key;
|
||||
const Type = Types[key];
|
||||
return inputKeys.reduce<[string, Codec][]>((raw, key, index) => {
|
||||
const jsonKey = jsonMap.get(key) || key;
|
||||
const Type = Types[key];
|
||||
|
||||
try {
|
||||
if (Array.isArray(value)) {
|
||||
// TS2322: Type 'Codec' is not assignable to type 'T[keyof S]'.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
|
||||
(raw as any)[key] = value[index] instanceof Type
|
||||
? value[index]
|
||||
: new Type(registry, value[index]);
|
||||
} else if (value instanceof Map) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const mapped = value.get(jsonKey);
|
||||
try {
|
||||
if (Array.isArray(value)) {
|
||||
raw.push(newEntry(registry, Type, key, value[index]));
|
||||
} else if (value instanceof Map) {
|
||||
raw.push(newEntry(registry, Type, key, jsonKey && (value as Map<string, unknown>).get(jsonKey)));
|
||||
} else if (isObject(value)) {
|
||||
let assign = jsonKey && value[jsonKey] as unknown;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
(raw as any)[key] = mapped instanceof Type
|
||||
? mapped
|
||||
: new Type(registry, mapped);
|
||||
} else if (isObject(value)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
let assign = value[jsonKey as string];
|
||||
if (isUndefined(assign)) {
|
||||
if (isUndefined(jsonObj)) {
|
||||
jsonObj = Object.entries(value).reduce((all: Record<string, unknown>, [key, value]): Record<string, unknown> => {
|
||||
all[stringCamelCase(key)] = value;
|
||||
|
||||
if (isUndefined(assign)) {
|
||||
if (isUndefined(jsonObj)) {
|
||||
jsonObj = Object.entries(value).reduce((all: Record<string, any>, [key, value]): Record<string, any> => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
all[stringCamelCase(key)] = value;
|
||||
|
||||
return all;
|
||||
}, {});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
assign = jsonObj[jsonKey as string];
|
||||
return all;
|
||||
}, {});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
|
||||
(raw as any)[key] = assign instanceof Type
|
||||
? assign
|
||||
: new Type(registry, assign);
|
||||
} else {
|
||||
throw new Error(`Cannot decode value ${stringify(value)} (typeof ${typeof value}), expected an input object with known keys`);
|
||||
assign = jsonKey && jsonObj[jsonKey];
|
||||
}
|
||||
|
||||
raw.push(newEntry(registry, Type, key, assign));
|
||||
} else {
|
||||
throw new Error(`Cannot decode value ${stringify(value)} (typeof ${typeof value}), expected an input object with known keys`);
|
||||
}
|
||||
} catch (error) {
|
||||
let type = Type.name;
|
||||
|
||||
try {
|
||||
type = new Type(registry).toRawType();
|
||||
} catch (error) {
|
||||
let type = Type.name;
|
||||
|
||||
try {
|
||||
type = new Type(registry).toRawType();
|
||||
} catch (error) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
throw new Error(`Struct: failed on ${jsonKey as string}: ${type}:: ${(error as Error).message}`);
|
||||
// ignore
|
||||
}
|
||||
|
||||
return raw;
|
||||
}, {})
|
||||
);
|
||||
throw new Error(`Struct: failed on ${jsonKey}: ${type}:: ${(error as Error).message}`);
|
||||
}
|
||||
|
||||
return raw;
|
||||
}, []);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,7 +86,7 @@ function decodeStructFromObject (registry: Registry, Types: ConstructorDef, valu
|
||||
* @param jsonMap
|
||||
* @internal
|
||||
*/
|
||||
function decodeStruct (registry: Registry, Types: ConstructorDef, value: unknown, jsonMap: Map<any, string>): [Iterable<[string, Codec]>, number] {
|
||||
function decodeStruct (registry: Registry, Types: ConstructorDef, value: unknown, jsonMap: Map<string, string>): [Iterable<[string, Codec]>, number] {
|
||||
if (isHex(value)) {
|
||||
return decodeStruct(registry, Types, hexToU8a(value), jsonMap);
|
||||
} else if (isU8a(value)) {
|
||||
@@ -109,13 +95,11 @@ function decodeStruct (registry: Registry, Types: ConstructorDef, value: unknown
|
||||
|
||||
// Transform array of values to {key: value} mapping
|
||||
return [
|
||||
Object.entries(
|
||||
keys.reduce<Record<string, Codec>>((raw, key, index) => {
|
||||
raw[key] = values[index];
|
||||
keys.reduce<[string, Codec][]>((raw, key, index) => {
|
||||
raw.push([key, values[index]]);
|
||||
|
||||
return raw;
|
||||
}, {})
|
||||
),
|
||||
return raw;
|
||||
}, []),
|
||||
decodedLength
|
||||
];
|
||||
} else if (value instanceof Struct) {
|
||||
@@ -154,7 +138,7 @@ export class Struct<
|
||||
readonly #Types: ConstructorDef;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
constructor (registry: Registry, Types: S, value?: V | Map<unknown, unknown> | unknown[] | string | null, jsonMap: Map<keyof S, string> = new Map()) {
|
||||
constructor (registry: Registry, Types: S, value?: V | Map<unknown, unknown> | unknown[] | string | null, jsonMap: Map<string, string> = new Map()) {
|
||||
const [decoded, decodedLength] = decodeStruct(registry, mapToTypeMap(registry, Types), value, jsonMap);
|
||||
|
||||
super(decoded);
|
||||
@@ -165,7 +149,7 @@ export class Struct<
|
||||
this.#Types = mapToTypeMap(registry, Types);
|
||||
}
|
||||
|
||||
public static with<S extends TypesDef> (Types: S, jsonMap?: Map<keyof S, string>): Constructor<Struct<S>> {
|
||||
public static with<S extends TypesDef> (Types: S, jsonMap?: Map<string, string>): Constructor<Struct<S>> {
|
||||
return class extends Struct<S> {
|
||||
constructor (registry: Registry, value?: unknown) {
|
||||
super(registry, Types, value as string, jsonMap);
|
||||
|
||||
Reference in New Issue
Block a user