Cater for named event fields (#4915)
* Cater for named event fields * Adjust name extraction * Rebuild with named events * Empty object * Adjust * Additional * Adjust
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { IsEvent } from '@polkadot/types/metadata/decorate/types';
|
||||
import type { AnyTuple } from '@polkadot/types/types';
|
||||
import type { AnyTuple, Codec } from '@polkadot/types/types';
|
||||
import type { ApiTypes } from './base';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-interface
|
||||
@@ -16,8 +16,8 @@ export interface DecoratedEvents<ApiType extends ApiTypes> extends AugmentedEven
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export type AugmentedEvent<ApiType extends ApiTypes, T extends AnyTuple = AnyTuple> = IsEvent<T>;
|
||||
export type AugmentedEvent<ApiType extends ApiTypes, T extends AnyTuple = AnyTuple, N extends Record<string, Codec> = Record<string, Codec>> = IsEvent<T, N>;
|
||||
|
||||
export interface ModuleEvents<ApiType extends ApiTypes> {
|
||||
[key: string]: AugmentedEvent<ApiType, AnyTuple>;
|
||||
[key: string]: AugmentedEvent<ApiType>;
|
||||
}
|
||||
|
||||
@@ -57,9 +57,12 @@ function events (api: ApiPromise): void {
|
||||
// existing
|
||||
if (api.events.balances.Transfer.is(event)) {
|
||||
// the types are correctly expanded
|
||||
const [from, to, amount] = event.data;
|
||||
const [afrom, ato, aamount] = event.data;
|
||||
|
||||
console.log(from.toHuman(), to.toHuman(), amount.toBn());
|
||||
// the types have getters
|
||||
const { amount, from, to } = event.data;
|
||||
|
||||
console.log(afrom.toHuman(), ato.toHuman(), aamount.toBn(), from.toHuman(), to.toHuman(), amount.toBn());
|
||||
}
|
||||
|
||||
// something random
|
||||
|
||||
@@ -42,13 +42,19 @@ function generateForMeta (meta: Metadata, dest: string, extraTypes: ExtraTypes,
|
||||
const args = fields
|
||||
.map(({ type }) => lookup.getTypeDef(type))
|
||||
.map((typeDef) => typeDef.lookupName || formatType(registry, allDefs, typeDef, imports));
|
||||
const names = fields
|
||||
.map(({ name }) => registry.lookup.sanitizeField(name)[0])
|
||||
.filter((n): n is string => !!n);
|
||||
|
||||
setImports(allDefs, imports, args);
|
||||
|
||||
return {
|
||||
docs,
|
||||
fields: names.length === args.length
|
||||
? `{ ${names.map((n, i) => `${n}: ${args[i]}`).join(', ')} }`
|
||||
: '{}',
|
||||
name: name.toString(),
|
||||
type: args.join(', ')
|
||||
type: `[${args.join(', ')}]`
|
||||
};
|
||||
})
|
||||
.sort(compareName),
|
||||
|
||||
@@ -8,7 +8,7 @@ declare module '@polkadot/api-base/types/events' {
|
||||
{{{name}}}: {
|
||||
{{#each items}}
|
||||
{{> docs}}
|
||||
{{{name}}}: AugmentedEvent<ApiType, [{{{type}}}]>;
|
||||
{{{name}}}: AugmentedEvent<ApiType, {{{type}}}, {{{fields}}}>;
|
||||
{{/each}}
|
||||
{{#unless @root.isStrict}}
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2017-2022 @polkadot/types-create authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Option, Text } from '@polkadot/types-codec';
|
||||
import type { ICompact, INumber } from '@polkadot/types-codec/types';
|
||||
import type { TypeDef } from './types';
|
||||
|
||||
@@ -11,4 +12,5 @@ export interface ILookup {
|
||||
}
|
||||
},
|
||||
getTypeDef (lookupId: ICompact<INumber> | string | number): TypeDef;
|
||||
sanitizeField (name: Option<Text>): [string | null, string | null];
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { EventId } from '../interfaces/system';
|
||||
import type { IEvent, IEventData, InterfaceTypes, Registry } from '../types';
|
||||
|
||||
import { Null, Struct, Tuple } from '@polkadot/types-codec';
|
||||
import { objectSpread } from '@polkadot/util';
|
||||
import { objectProperties, objectSpread } from '@polkadot/util';
|
||||
|
||||
interface Decoded {
|
||||
DataType: CodecClass<Null> | CodecClass<GenericEventData>;
|
||||
@@ -45,6 +45,8 @@ export class GenericEventData extends Tuple implements IEventData {
|
||||
|
||||
readonly #method: string;
|
||||
|
||||
readonly #names: string[] | null = null;
|
||||
|
||||
readonly #section: string;
|
||||
|
||||
readonly #typeDef: TypeDef[];
|
||||
@@ -58,6 +60,16 @@ export class GenericEventData extends Tuple implements IEventData {
|
||||
this.#method = method;
|
||||
this.#section = section;
|
||||
this.#typeDef = fields.map(({ type }) => registry.lookup.getTypeDef(type));
|
||||
|
||||
const names = fields
|
||||
.map(({ name }) => registry.lookup.sanitizeField(name)[0])
|
||||
.filter((n): n is string => !!n);
|
||||
|
||||
if (names.length === fields.length) {
|
||||
this.#names = names;
|
||||
|
||||
objectProperties(this, names, (_, i) => this[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,6 +86,13 @@ export class GenericEventData extends Tuple implements IEventData {
|
||||
return this.#method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The field names (as available)
|
||||
*/
|
||||
public get names (): string[] | null {
|
||||
return this.#names;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The section as a string
|
||||
*/
|
||||
@@ -87,6 +106,23 @@ export class GenericEventData extends Tuple implements IEventData {
|
||||
public get typeDef (): TypeDef[] {
|
||||
return this.#typeDef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information
|
||||
*/
|
||||
public override toHuman (isExtended?: boolean): AnyJson {
|
||||
if (this.#names !== null) {
|
||||
const json: Record<string, AnyJson> = {};
|
||||
|
||||
for (let i = 0; i < this.#names.length; i++) {
|
||||
json[this.#names[i]] = this[i].toHuman(isExtended);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
return super.toHuman(isExtended);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +131,7 @@ export class GenericEventData extends Tuple implements IEventData {
|
||||
* A representation of a system event. These are generated via the [[Metadata]] interfaces and
|
||||
* specific to a specific Substrate runtime
|
||||
*/
|
||||
export class GenericEvent extends Struct implements IEvent<Codec[]> {
|
||||
export class GenericEvent extends Struct implements IEvent<Codec[], Record<string, Codec>> {
|
||||
// Currently we _only_ decode from Uint8Array, since we expect it to
|
||||
// be used via EventRecord
|
||||
constructor (registry: Registry, _value?: Uint8Array) {
|
||||
@@ -111,7 +147,7 @@ export class GenericEvent extends Struct implements IEvent<Codec[]> {
|
||||
/**
|
||||
* @description The wrapped [[EventData]]
|
||||
*/
|
||||
public get data (): GenericEventData {
|
||||
public get data (): GenericEventData & Record<string, Codec> {
|
||||
return this.getT('data');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2022 @polkadot/types authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Text, Type, Vec } from '@polkadot/types-codec';
|
||||
import type { Option, Text, Type, Vec } from '@polkadot/types-codec';
|
||||
import type { Registry } from '@polkadot/types-codec/types';
|
||||
import type { ILookup, TypeDef } from '@polkadot/types-create/types';
|
||||
import type { PortableType } from '../../interfaces/metadata';
|
||||
@@ -464,6 +464,25 @@ export class PortableRegistry extends Struct implements ILookup {
|
||||
return this.#typeDefs[lookupIndex];
|
||||
}
|
||||
|
||||
public sanitizeField (name: Option<Text>): [string | null, string | null] {
|
||||
let nameField: string | null = null;
|
||||
let nameOrig: string | null = null;
|
||||
|
||||
if (name.isSome) {
|
||||
nameField = stringCamelCase(name.unwrap());
|
||||
|
||||
if (nameField.includes('#')) {
|
||||
nameOrig = nameField;
|
||||
nameField = nameOrig.replace(/#/g, '_');
|
||||
} else if (RESERVED.includes(nameField)) {
|
||||
nameOrig = nameField;
|
||||
nameField = `${nameField}_`;
|
||||
}
|
||||
}
|
||||
|
||||
return [nameField, nameOrig];
|
||||
}
|
||||
|
||||
#createSiDef (lookupId: SiLookupTypeId): TypeDef {
|
||||
const typeDef = this.getTypeDef(lookupId);
|
||||
const lookupIndex = lookupId.toNumber();
|
||||
@@ -681,18 +700,9 @@ export class PortableRegistry extends Struct implements ILookup {
|
||||
if (name.isNone) {
|
||||
sub[i] = typeDef;
|
||||
} else {
|
||||
let nameField = stringCamelCase(name.unwrap());
|
||||
let nameOrig: string | null = null;
|
||||
const [nameField, nameOrig] = this.sanitizeField(name);
|
||||
|
||||
if (nameField.includes('#')) {
|
||||
nameOrig = nameField;
|
||||
nameField = nameOrig.replace(/#/g, '_');
|
||||
} else if (RESERVED.includes(nameField)) {
|
||||
nameOrig = nameField;
|
||||
nameField = `${nameField}_`;
|
||||
}
|
||||
|
||||
if (nameOrig) {
|
||||
if (nameField && nameOrig) {
|
||||
alias.set(nameField, nameOrig);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2022 @polkadot/types authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { AnyTuple, Registry } from '@polkadot/types-codec/types';
|
||||
import type { AnyTuple, Codec, Registry } from '@polkadot/types-codec/types';
|
||||
import type { MetadataLatest, PalletMetadataLatest, SiVariant } from '../../../interfaces';
|
||||
import type { IEvent } from '../../../types';
|
||||
import type { Events, IsEvent } from '../types';
|
||||
@@ -26,9 +26,9 @@ export function decorateEvents (registry: Registry, { lookup, pallets }: Metadat
|
||||
const sectionIndex = version >= 12 ? index.toNumber() : i;
|
||||
|
||||
lazyMethod(result, stringCamelCase(name), () =>
|
||||
lazyVariants(lookup, events.unwrap(), objectNameToString, (variant: SiVariant): IsEvent<AnyTuple> => ({
|
||||
lazyVariants(lookup, events.unwrap(), objectNameToString, (variant: SiVariant): IsEvent<AnyTuple, Record<string, Codec>> => ({
|
||||
// We sprinkle in isCodec & isU8a to ensure we are dealing with the correct objects
|
||||
is: <T extends AnyTuple> (eventRecord: IEvent<AnyTuple>): eventRecord is IEvent<T> =>
|
||||
is: <T extends AnyTuple, N extends Record<string, Codec>> (eventRecord: IEvent<AnyTuple, Record<string, Codec>>): eventRecord is IEvent<T, N> =>
|
||||
isCodec(eventRecord) &&
|
||||
isU8a(eventRecord.index) &&
|
||||
sectionIndex === eventRecord.index[0] &&
|
||||
|
||||
@@ -16,17 +16,17 @@ export interface IsError {
|
||||
is: (moduleError: DispatchErrorModule | DispatchErrorModuleU8 | DispatchErrorModuleU8a) => boolean;
|
||||
}
|
||||
|
||||
export interface IsEvent <T extends AnyTuple> {
|
||||
export interface IsEvent <T extends AnyTuple, N extends Record<string, Codec>> {
|
||||
readonly meta: EventMetadataLatest;
|
||||
|
||||
is: (event: IEvent<AnyTuple>) => event is IEvent<T>;
|
||||
is: (event: IEvent<AnyTuple, Record<string, Codec>>) => event is IEvent<T, N>;
|
||||
}
|
||||
|
||||
export type ModuleConstants = Record<string, ConstantCodec>;
|
||||
|
||||
export type ModuleErrors = Record<string, IsError>;
|
||||
|
||||
export type ModuleEvents = Record<string, IsEvent<AnyTuple>>;
|
||||
export type ModuleEvents = Record<string, IsEvent<AnyTuple, Record<string, Codec>>>;
|
||||
|
||||
export type ModuleExtrinsics = Record<string, CallFunction>;
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ import type { EventMetadataLatest } from '../interfaces/metadata';
|
||||
import type { Hash } from '../interfaces/runtime';
|
||||
import type { EventId, Phase } from '../interfaces/system';
|
||||
|
||||
export interface IEventRecord<T extends Codec[]> {
|
||||
export interface IEventRecord<T extends Codec[], N extends Record<string, Codec> = Record<string, Codec>> {
|
||||
readonly phase: Phase;
|
||||
readonly event: IEvent<T>;
|
||||
readonly event: IEvent<T, N>;
|
||||
readonly topics: Hash[];
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ export interface IEventData {
|
||||
readonly section: string;
|
||||
}
|
||||
|
||||
export interface IEvent<T extends Codec[]> {
|
||||
readonly data: ITuple<T> & IEventData;
|
||||
export interface IEvent<T extends Codec[], N extends Record<string, Codec> = Record<string, Codec>> {
|
||||
readonly data: ITuple<T> & IEventData & N;
|
||||
readonly index: EventId;
|
||||
readonly method: string;
|
||||
readonly section: string;
|
||||
|
||||
Reference in New Issue
Block a user