Internal adjustments (part 4) (#4136)
* Internal adjustments (part 3) * Internal adjustments (part 4) * Additional * Additional * Fix set encoding
This commit is contained in:
@@ -11,33 +11,44 @@ import { compareArray } from './utils';
|
||||
|
||||
type SetValues = Record<string, number | BN>;
|
||||
|
||||
function encodeSet (setValues: SetValues, value: string[]): BN {
|
||||
return value.reduce((result, value): BN => {
|
||||
return result.or(bnToBn(setValues[value] || 0));
|
||||
}, new BN(0));
|
||||
function encodeSet (setValues: SetValues, values: string[]): BN {
|
||||
const encoded = new BN(0);
|
||||
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
encoded.ior(bnToBn(setValues[values[i]] || 0));
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function decodeSetArray (setValues: SetValues, value: string[]): string[] {
|
||||
return value.reduce<string[]>((result, key): string[] => {
|
||||
function decodeSetArray (setValues: SetValues, values: string[]): string[] {
|
||||
const result = new Array<string>(values.length);
|
||||
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
const key = values[i];
|
||||
|
||||
assert(!isUndefined(setValues[key]), () => `Set: Invalid key '${key}' passed to Set, allowed ${Object.keys(setValues).join(', ')}`);
|
||||
|
||||
result.push(key);
|
||||
result[i] = key;
|
||||
}
|
||||
|
||||
return result;
|
||||
}, []);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function decodeSetNumber (setValues: SetValues, _value: BN | number): string[] {
|
||||
const bn = bnToBn(_value);
|
||||
const result = Object.keys(setValues).reduce<string[]>((result, key): string[] => {
|
||||
const keys = Object.keys(setValues);
|
||||
const result: string[] = [];
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
|
||||
if (bn.and(bnToBn(setValues[key])).eq(bnToBn(setValues[key]))) {
|
||||
result.push(key);
|
||||
}
|
||||
|
||||
return result;
|
||||
}, []);
|
||||
}
|
||||
|
||||
const computed = encodeSet(setValues, result);
|
||||
|
||||
|
||||
@@ -21,14 +21,17 @@ function decodeStructFromObject (registry: Registry, Types: ConstructorDef, valu
|
||||
assert(typeofArray || typeofMap || isObject(value), () => `Struct: Cannot decode value ${stringify(value)} (typeof ${typeof value}), expected an input object, map or array`);
|
||||
assert(!typeofArray || value.length === inputKeys.length, () => `Struct: Unable to map ${stringify(value)} array to object with known keys ${inputKeys.join(', ')}`);
|
||||
|
||||
return inputKeys.reduce<[string, Codec][]>((raw, key, index) => {
|
||||
const raw = new Array<[string, Codec]>(inputKeys.length);
|
||||
|
||||
for (let i = 0; i < inputKeys.length; i++) {
|
||||
const key = inputKeys[i];
|
||||
const jsonKey = jsonMap.get(key) || key;
|
||||
const Type = Types[key];
|
||||
let assign: unknown;
|
||||
|
||||
try {
|
||||
if (typeofArray) {
|
||||
assign = value[index] as unknown;
|
||||
assign = value[i] as unknown;
|
||||
} else if (typeofMap) {
|
||||
assign = jsonKey && value.get(jsonKey);
|
||||
} else {
|
||||
@@ -36,23 +39,25 @@ function decodeStructFromObject (registry: Registry, Types: ConstructorDef, valu
|
||||
|
||||
if (isUndefined(assign)) {
|
||||
if (isUndefined(jsonObj)) {
|
||||
jsonObj = Object.entries(value).reduce((all: Record<string, unknown>, [k, v]): Record<string, unknown> => {
|
||||
all[stringCamelCase(k)] = v;
|
||||
const entries = Object.entries(value);
|
||||
|
||||
return all;
|
||||
}, {});
|
||||
jsonObj = {};
|
||||
|
||||
for (let e = 0; e < entries.length; e++) {
|
||||
jsonObj[stringCamelCase(entries[e][0])] = entries[e][1];
|
||||
}
|
||||
}
|
||||
|
||||
assign = jsonKey && jsonObj[jsonKey];
|
||||
}
|
||||
}
|
||||
|
||||
raw.push([
|
||||
raw[i] = [
|
||||
key,
|
||||
assign instanceof Type
|
||||
? assign
|
||||
: new Type(registry, assign)
|
||||
]);
|
||||
];
|
||||
} catch (error) {
|
||||
let type = Type.name;
|
||||
|
||||
@@ -64,9 +69,9 @@ function decodeStructFromObject (registry: Registry, Types: ConstructorDef, valu
|
||||
|
||||
throw new Error(`Struct: failed on ${jsonKey}: ${type}:: ${(error as Error).message}`);
|
||||
}
|
||||
}
|
||||
|
||||
return raw;
|
||||
}, []);
|
||||
return raw;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,11 +159,16 @@ export class Struct<
|
||||
}
|
||||
|
||||
public static typesToMap (registry: Registry, Types: Record<string, Constructor>): Record<string, string> {
|
||||
return Object.entries(Types).reduce((result: Record<string, string>, [key, Type]): Record<string, string> => {
|
||||
result[key] = registry.getClassName(Type) || new Type(registry).toRawType();
|
||||
const entries = Object.entries(Types);
|
||||
const result: Record<string, string> = {};
|
||||
|
||||
return result;
|
||||
}, {});
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
const [key, Type] = entries[i];
|
||||
|
||||
result[key] = registry.getClassName(Type) || new Type(registry).toRawType();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,27 +276,35 @@ export class Struct<
|
||||
* @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information
|
||||
*/
|
||||
public toHuman (isExtended?: boolean): Record<string, AnyJson> {
|
||||
return [...this.keys()].reduce((json: Record<string, AnyJson>, key): Record<string, AnyJson> => {
|
||||
const json: Record<string, AnyJson> = {};
|
||||
const keys = [...this.keys()];
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
const value = this.get(key);
|
||||
|
||||
json[key as string] = value && value.toHuman(isExtended);
|
||||
}
|
||||
|
||||
return json;
|
||||
}, {});
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Converts the Object to JSON, typically used for RPC transfers
|
||||
*/
|
||||
public toJSON (): Record<string, AnyJson> {
|
||||
return [...this.keys()].reduce((json: Record<string, AnyJson>, key): Record<string, AnyJson> => {
|
||||
const json: Record<string, AnyJson> = {};
|
||||
const keys = [...this.keys()];
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
const jsonKey = this.#jsonMap.get(key) || key;
|
||||
const value = this.get(key);
|
||||
|
||||
json[jsonKey as string] = value && value.toJSON();
|
||||
}
|
||||
|
||||
return json;
|
||||
}, {});
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,11 +9,12 @@ import { typeToConstructor } from './typeToConstructor';
|
||||
* @description takes an input map of the form `{ [string]: string | Constructor }` and returns a map of `{ [string]: Constructor }`
|
||||
*/
|
||||
export function mapToTypeMap (registry: Registry, input: Record<string, string | Constructor>): Record<string, Constructor> {
|
||||
return Object
|
||||
.entries(input)
|
||||
.reduce((output: Record<string, Constructor>, [key, type]): Record<string, Constructor> => {
|
||||
output[key] = typeToConstructor(registry, type);
|
||||
const entries = Object.entries(input);
|
||||
const output: Record<string, Constructor> = {};
|
||||
|
||||
return output;
|
||||
}, {});
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
output[entries[i][0]] = typeToConstructor(registry, entries[i][1]);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,10 @@ import { Bytes, Null } from '../primitive';
|
||||
import { getTypeDef } from './getTypeDef';
|
||||
import { TypeDefInfo } from './types';
|
||||
|
||||
function getTypeDefType ({ lookupName, type }: TypeDef): string {
|
||||
return lookupName || type;
|
||||
}
|
||||
|
||||
function getSubDefArray (value: TypeDef): TypeDef[] {
|
||||
assert(value.sub && Array.isArray(value.sub), () => `Expected subtype as TypeDef[] in ${stringify(value)}`);
|
||||
|
||||
@@ -25,23 +29,24 @@ function getSubDef (value: TypeDef): TypeDef {
|
||||
}
|
||||
|
||||
function getSubType (value: TypeDef): string {
|
||||
const { lookupName, type } = getSubDef(value);
|
||||
|
||||
return lookupName || type;
|
||||
return getTypeDefType(getSubDef(value));
|
||||
}
|
||||
|
||||
// create a maps of type string constructors from the input
|
||||
function getTypeClassMap (value: TypeDef): Record<string, string> {
|
||||
return getSubDefArray(value).reduce<Record<string, string>>((result, { lookupName, name, type }) => {
|
||||
result[name as string] = lookupName || type;
|
||||
const subs = getSubDefArray(value);
|
||||
const map: Record<string, string> = {};
|
||||
|
||||
return result;
|
||||
}, {});
|
||||
for (let i = 0; i < subs.length; i++) {
|
||||
map[subs[i].name as string] = getTypeDefType(subs[i]);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
// create an array of type string constructors from the input
|
||||
function getTypeClassArray (value: TypeDef): string[] {
|
||||
return getSubDefArray(value).map(({ lookupName, type }) => lookupName || type);
|
||||
return getSubDefArray(value).map(getTypeDefType);
|
||||
}
|
||||
|
||||
function createInt ({ displayName, length }: TypeDef, Clazz: typeof Int | typeof UInt): Constructor<Codec> {
|
||||
@@ -152,7 +157,7 @@ const infoMapping: Record<TypeDefInfo, (registry: Registry, value: TypeDef) => C
|
||||
return (
|
||||
sub.type === 'u8'
|
||||
? Bytes
|
||||
: Vec.with(sub.lookupName || sub.type)
|
||||
: Vec.with(getTypeDefType(sub))
|
||||
);
|
||||
},
|
||||
|
||||
@@ -162,7 +167,7 @@ const infoMapping: Record<TypeDefInfo, (registry: Registry, value: TypeDef) => C
|
||||
return (
|
||||
sub.type === 'u8'
|
||||
? U8aFixed.with((length * 8) as U8aBitLength, displayName)
|
||||
: VecFixed.with(sub.lookupName || sub.type, length)
|
||||
: VecFixed.with(getTypeDefType(sub), length)
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
@@ -44,10 +44,13 @@ function encodeSubTypes (registry: Registry, sub: TypeDef[], asEnum?: boolean, e
|
||||
|
||||
assert(names.every((n) => !!n), () => `Subtypes does not have consistent names, ${names.join(', ')}`);
|
||||
|
||||
const inner = sub.reduce< Record<string, string>>((result, type) => ({
|
||||
...result,
|
||||
[type.name as string]: encodeTypeDef(registry, type)
|
||||
}), { ...(extra as Record<string, string>) });
|
||||
const inner: Record<string, string> = { ...(extra as Record<string, string>) };
|
||||
|
||||
for (let i = 0; i < sub.length; i++) {
|
||||
const def = sub[i];
|
||||
|
||||
inner[def.name as string] = encodeTypeDef(registry, def);
|
||||
}
|
||||
|
||||
return stringify(
|
||||
asEnum
|
||||
|
||||
@@ -230,7 +230,11 @@ export function removeWrap (check: string): Mapper {
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export function sanitize (value: String | string, options?: SanitizeOptions): string {
|
||||
return mappings.reduce<string>((result, fn) =>
|
||||
fn(result, options), value.toString()
|
||||
).trim();
|
||||
let result = value.toString();
|
||||
|
||||
for (let i = 0; i < mappings.length; i++) {
|
||||
result = mappings[i](result, options);
|
||||
}
|
||||
|
||||
return result.trim();
|
||||
}
|
||||
|
||||
@@ -60,6 +60,10 @@ function splitNamespace (values: string[]): string[][] {
|
||||
return values.map((v) => v.split('::'));
|
||||
}
|
||||
|
||||
function sanitizeDocs (docs: Text[]): string[] {
|
||||
return docs.map((d) => d.toString());
|
||||
}
|
||||
|
||||
function matchParts (first: string[], second: (string | Text)[]): boolean {
|
||||
return first.length === second.length && first.every((a, index) => {
|
||||
const b = second[index].toString();
|
||||
@@ -220,17 +224,17 @@ function extractNames (lookup: GenericPortableRegistry, types: PortableType[]):
|
||||
extractName(types, t)
|
||||
));
|
||||
|
||||
const [names, typesNew] = dedup.reduce<[Record<number, string>, Record<string, string>]>(([names, types], [lookupIndex, name]) => {
|
||||
// We set the name for this specific type
|
||||
const names: Record<number, string> = {};
|
||||
const lookups: Record<string, string> = {};
|
||||
|
||||
for (let i = 0; i < dedup.length; i++) {
|
||||
const [lookupIndex, name] = dedup[i];
|
||||
|
||||
names[lookupIndex] = name;
|
||||
lookups[name] = lookup.registry.createLookupType(lookupIndex);
|
||||
}
|
||||
|
||||
// we map to the actual lookupIndex
|
||||
types[name] = lookup.registry.createLookupType(lookupIndex);
|
||||
|
||||
return [names, types];
|
||||
}, [{}, {}]);
|
||||
|
||||
lookup.registry.register(typesNew);
|
||||
lookup.registry.register(lookups);
|
||||
|
||||
return names;
|
||||
}
|
||||
@@ -238,11 +242,15 @@ function extractNames (lookup: GenericPortableRegistry, types: PortableType[]):
|
||||
// types have an id, which means they are to be named by
|
||||
// the specified id - ensure we have a mapping lookup for these
|
||||
function extractTypeMap (types: PortableType[]): Record<number, PortableType> {
|
||||
return types.reduce<Record<number, PortableType>>((types, pt) => {
|
||||
types[pt.id.toNumber()] = pt;
|
||||
const result: Record<number, PortableType> = {};
|
||||
|
||||
return types;
|
||||
}, {});
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
const p = types[i];
|
||||
|
||||
result[p.id.toNumber()] = p;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export class GenericPortableRegistry extends Struct {
|
||||
@@ -396,7 +404,7 @@ export class GenericPortableRegistry extends Struct {
|
||||
}
|
||||
|
||||
return {
|
||||
docs: type.docs.map((d) => d.toString()),
|
||||
docs: sanitizeDocs(type.docs),
|
||||
namespace,
|
||||
...typeDef
|
||||
};
|
||||
@@ -493,11 +501,15 @@ export class GenericPortableRegistry extends Struct {
|
||||
}
|
||||
|
||||
#extractFields (lookupIndex: number, fields: SiField[]): TypeDef {
|
||||
const [isStruct, isTuple] = fields.reduce(([isAllNamed, isAllUnnamed], { name }) => ([
|
||||
isAllNamed && name.isSome,
|
||||
isAllUnnamed && name.isNone
|
||||
]),
|
||||
[true, true]);
|
||||
let isStruct = true;
|
||||
let isTuple = true;
|
||||
|
||||
for (let f = 0; f < fields.length; f++) {
|
||||
const { name } = fields[f];
|
||||
|
||||
isStruct = isStruct && name.isSome;
|
||||
isTuple = isTuple && name.isNone;
|
||||
}
|
||||
|
||||
assert(isTuple || isStruct, 'Invalid fields type detected, expected either Tuple (all unnamed) or Struct (all named)');
|
||||
|
||||
@@ -551,38 +563,41 @@ export class GenericPortableRegistry extends Struct {
|
||||
|
||||
#extractFieldsAlias (fields: SiField[]): [TypeDef[], Map<string, string>] {
|
||||
const alias = new Map<string, string>();
|
||||
const sub = fields.map(({ docs, name, type, typeName }) => {
|
||||
const sub = new Array<TypeDef>(fields.length);
|
||||
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
const { docs, name, type, typeName } = fields[i];
|
||||
const typeDef = this.#createSiDef(type);
|
||||
|
||||
if (name.isNone) {
|
||||
return typeDef;
|
||||
sub[i] = typeDef;
|
||||
} else {
|
||||
let nameField = stringCamelCase(name.unwrap());
|
||||
let nameOrig: string | null = null;
|
||||
|
||||
if (nameField.includes('#')) {
|
||||
nameOrig = nameField;
|
||||
nameField = nameOrig.replace(/#/g, '_');
|
||||
} else if (RESERVED.includes(nameField)) {
|
||||
nameOrig = nameField;
|
||||
nameField = `${nameField}_`;
|
||||
}
|
||||
|
||||
if (nameOrig) {
|
||||
alias.set(nameField, nameOrig);
|
||||
}
|
||||
|
||||
sub[i] = {
|
||||
...typeDef,
|
||||
docs: sanitizeDocs(docs),
|
||||
name: nameField,
|
||||
...(typeName.isSome
|
||||
? { typeName: sanitize(typeName.unwrap()) }
|
||||
: {}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
let nameField = stringCamelCase(name.unwrap());
|
||||
let nameOrig: string | null = null;
|
||||
|
||||
if (nameField.includes('#')) {
|
||||
nameOrig = nameField;
|
||||
nameField = nameOrig.replace(/#/g, '_');
|
||||
} else if (RESERVED.includes(nameField)) {
|
||||
nameOrig = nameField;
|
||||
nameField = `${nameField}_`;
|
||||
}
|
||||
|
||||
if (nameOrig) {
|
||||
alias.set(nameField, nameOrig);
|
||||
}
|
||||
|
||||
return {
|
||||
...typeDef,
|
||||
docs: docs.map((d) => d.toString()),
|
||||
name: nameField,
|
||||
...(typeName.isSome
|
||||
? { typeName: sanitize(typeName.unwrap()) }
|
||||
: {}
|
||||
)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return [sub, alias];
|
||||
}
|
||||
|
||||
@@ -31,10 +31,14 @@ export class MetadataVersioned extends Struct {
|
||||
readonly #converted = new Map<MetaVersions, MetaMapped>();
|
||||
|
||||
constructor (registry: Registry, value?: unknown) {
|
||||
// console.time('MetadataVersioned')
|
||||
|
||||
super(registry, {
|
||||
magicNumber: MagicNumber,
|
||||
metadata: 'MetadataAll'
|
||||
}, value as Map<unknown, unknown>);
|
||||
|
||||
// console.timeEnd('MetadataVersioned')
|
||||
}
|
||||
|
||||
#assertVersion = (version: number): boolean => {
|
||||
|
||||
Reference in New Issue
Block a user