Adjust struct iterable creation (#4130)

This commit is contained in:
Jaco
2021-10-30 18:12:12 +03:00
committed by GitHub
parent 2c86e9347b
commit 47d7900809
+50 -66
View File
@@ -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);