diff --git a/packages/api-contract/src/MetaRegistry.ts b/packages/api-contract/src/MetaRegistry.ts index 0076d2c3f2..4a1e0829b5 100644 --- a/packages/api-contract/src/MetaRegistry.ts +++ b/packages/api-contract/src/MetaRegistry.ts @@ -119,7 +119,7 @@ export class MetaRegistry extends TypeRegistry { const displayName = path.pop()?.toString(); - return withTypeString({ + return withTypeString(this, { ...(displayName ? { displayName } : {} @@ -243,7 +243,7 @@ export class MetaRegistry extends TypeRegistry { name: name.toString(), type: 'Null' })) - : variants.map(({ fields, name }) => withTypeString({ + : variants.map(({ fields, name }) => withTypeString(this, { ...this.#extractFields(fields), name: name.toString() })); diff --git a/packages/api/src/base/Decorate.ts b/packages/api/src/base/Decorate.ts index 44dd2ce171..6ab510df6f 100644 --- a/packages/api/src/base/Decorate.ts +++ b/packages/api/src/base/Decorate.ts @@ -405,7 +405,7 @@ export abstract class Decorate extends Events { private _decorateStorageEntry (creator: StorageEntry, decorateMethod: DecorateMethod): QueryableStorageEntry { // get the storage arguments, with DoubleMap as an array entry, otherwise spread - const getArgs = (args: unknown[]): unknown[] => extractStorageArgs(creator, args); + const getArgs = (args: unknown[]): unknown[] => extractStorageArgs(this.#registry, creator, args); // Disable this where it occurs for each field we are decorating /* eslint-disable @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment */ @@ -488,7 +488,7 @@ export abstract class Decorate extends Events { private _decorateStorageEntryAt (creator: StorageEntry, decorateMethod: DecorateMethod, blockHash: Uint8Array): QueryableStorageEntryAt { // get the storage arguments, with DoubleMap as an array entry, otherwise spread - const getArgs = (args: unknown[]): unknown[] => extractStorageArgs(creator, args); + const getArgs = (args: unknown[]): unknown[] => extractStorageArgs(this.#registry, creator, args); // Disable this where it occurs for each field we are decorating /* eslint-disable @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment */ @@ -545,18 +545,18 @@ export abstract class Decorate extends Events { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return decorateMethod((...args: unknown[]): Observable => { return this.hasSubscriptions - ? this._rpcCore.state.subscribeStorage<[Codec]>([extractStorageArgs(creator, args)]).pipe( + ? this._rpcCore.state.subscribeStorage<[Codec]>([extractStorageArgs(this.#registry, creator, args)]).pipe( map(([data]) => data) // extract first/only result from list ) - : this._rpcCore.state.getStorage(extractStorageArgs(creator, args)); + : this._rpcCore.state.getStorage(extractStorageArgs(this.#registry, creator, args)); }, { methodName: creator.method, - overrideNoSub: (...args: unknown[]) => this._rpcCore.state.getStorage(extractStorageArgs(creator, args)) + overrideNoSub: (...args: unknown[]) => this._rpcCore.state.getStorage(extractStorageArgs(this.#registry, creator, args)) }); } private _decorateStorageRange (decorated: QueryableStorageEntry, args: Arg[], range: [Hash, Hash?]): Observable<[Hash, Codec][]> { - const outputType = unwrapStorageType(decorated.creator.meta.type, decorated.creator.meta.modifier.isOptional); + const outputType = unwrapStorageType(this.#registry, decorated.creator.meta.type, decorated.creator.meta.modifier.isOptional); return this._rpcCore.state .queryStorage<[Option]>([decorated.key(...args)], ...range) diff --git a/packages/api/src/util/validate.spec.ts b/packages/api/src/util/validate.spec.ts index 5b86054e2a..0a6365d77c 100644 --- a/packages/api/src/util/validate.spec.ts +++ b/packages/api/src/util/validate.spec.ts @@ -20,79 +20,79 @@ describe('extractStorageArgs', (): void => { it('validates no-arg plain', (): void => { expect( - extractStorageArgs(storage.timestamp.now, []) + extractStorageArgs(registry, storage.timestamp.now, []) ).toEqual([storage.timestamp.now]); }); it('validates no-arg plain (with undefined, undefined)', (): void => { expect( - extractStorageArgs(storage.timestamp.now, [undefined, undefined]) + extractStorageArgs(registry, storage.timestamp.now, [undefined, undefined]) ).toEqual([storage.timestamp.now]); }); it('validates no-arg plain (failing when there are args)', (): void => { expect( - (): unknown => extractStorageArgs(storage.timestamp.now, [123, 456]) + (): unknown => extractStorageArgs(registry, storage.timestamp.now, [123, 456]) ).toThrow('timestamp.now() does not take any arguments, 2 found'); }); it('validates map, 1 arg', (): void => { expect( - extractStorageArgs(storage.staking.payee, ['abc']) + extractStorageArgs(registry, storage.staking.payee, ['abc']) ).toEqual([storage.staking.payee, 'abc']); }); it('validates map, 1 arg (failing with no args)', (): void => { expect( (): any => - extractStorageArgs(storage.staking.payee, []) + extractStorageArgs(registry, storage.staking.payee, []) ).toThrow('staking.payee(AccountId) is a map, requiring 1 argument, 0 found'); }); it('validates map, 1 arg (failing with no args)', (): void => { expect( (): any => - extractStorageArgs(storage.staking.payee, ['abc', 'def']) + extractStorageArgs(registry, storage.staking.payee, ['abc', 'def']) ).toThrow('staking.payee(AccountId) is a map, requiring 1 argument, 2 found'); }); it('validates doublemap, 2 args', (): void => { expect( - extractStorageArgs(storage.staking.erasStakers, [1, '0x1234']) + extractStorageArgs(registry, storage.staking.erasStakers, [1, '0x1234']) ).toEqual([storage.staking.erasStakers, [1, '0x1234']]); }); it('validates doublemap, 2 args (failing with no args)', (): void => { expect( (): any => - extractStorageArgs(storage.staking.erasStakers, []) + extractStorageArgs(registry, storage.staking.erasStakers, []) ).toThrow('staking.erasStakers(EraIndex, AccountId) is a double map, requiring 2 arguments, 0 found'); }); it('validates doublemap, 2 args (failing with 1 arg)', (): void => { expect( (): any => - extractStorageArgs(storage.staking.erasStakers, [123]) + extractStorageArgs(registry, storage.staking.erasStakers, [123]) ).toThrow('staking.erasStakers(EraIndex, AccountId) is a double map, requiring 2 arguments, 1 found'); }); // Linked maps have been removed it.skip('validates linked map, no args', (): void => { expect( - extractStorageArgs(storage.staking.validators, []) + extractStorageArgs(registry, storage.staking.validators, []) ).toEqual([storage.staking.validators]); }); it.skip('validates linked map, single arg', (): void => { expect( - extractStorageArgs(storage.staking.validators, [123]) + extractStorageArgs(registry, storage.staking.validators, [123]) ).toEqual([storage.staking.validators, 123]); }); it.skip('validates linked map (failing with extra args)', (): void => { expect( (): any[] => - extractStorageArgs(storage.staking.validators, [123, 456]) + extractStorageArgs(registry, storage.staking.validators, [123, 456]) ).toThrow('staking.validators(AccountId) is a linked map, requiring either 0 arguments (retrieving all) or 1 argument, 2 found'); }); }); diff --git a/packages/api/src/util/validate.ts b/packages/api/src/util/validate.ts index 3cf26b6d39..df5ad8b352 100644 --- a/packages/api/src/util/validate.ts +++ b/packages/api/src/util/validate.ts @@ -3,26 +3,27 @@ import type { Type } from '@polkadot/types'; import type { StorageEntry } from '@polkadot/types/primitive/types'; +import type { Registry } from '@polkadot/types/types'; import { assert, isUndefined } from '@polkadot/util'; -function sig ({ method, section }: StorageEntry, args: Type[]): string { +function sig (_: Registry, { method, section }: StorageEntry, args: Type[]): string { return `${section}.${method}(${args.join(', ')})`; } -function doDoubleMap (creator: StorageEntry, args: unknown[]): [StorageEntry, [any, any]] { +function doDoubleMap (registry: Registry, creator: StorageEntry, args: unknown[]): [StorageEntry, [any, any]] { const { key1, key2 } = creator.meta.type.asDoubleMap; - assert(args.length === 2, () => `${sig(creator, [key1, key2])} is a double map, requiring 2 arguments, ${args.length} found`); + assert(args.length === 2, () => `${sig(registry, creator, [key1, key2])} is a double map, requiring 2 arguments, ${args.length} found`); // pass as tuple return [creator, args as [any, any]]; } -function doMap (creator: StorageEntry, args: unknown[]): [StorageEntry] | [StorageEntry, any] { +function doMap (registry: Registry, creator: StorageEntry, args: unknown[]): [StorageEntry] | [StorageEntry, any] { const { key } = creator.meta.type.asMap; - assert(args.length === 1, () => `${sig(creator, [key])} is a map, requiring 1 argument, ${args.length} found`); + assert(args.length === 1, () => `${sig(registry, creator, [key])} is a map, requiring 1 argument, ${args.length} found`); // expand return args.length @@ -30,10 +31,10 @@ function doMap (creator: StorageEntry, args: unknown[]): [StorageEntry] | [Stora : [creator]; } -function doNMap (creator: StorageEntry, args: unknown[]): [StorageEntry, any[]] { +function doNMap (registry: Registry, creator: StorageEntry, args: unknown[]): [StorageEntry, any[]] { const { keyVec } = creator.meta.type.asNMap; - assert(args.length === keyVec.length, () => `${sig(creator, keyVec)} is a multi map, requiring ${keyVec.length} arguments, ${args.length} found`); + assert(args.length === keyVec.length, () => `${sig(registry, creator, keyVec)} is a multi map, requiring ${keyVec.length} arguments, ${args.length} found`); // pass as tuple return [creator, args]; @@ -41,18 +42,18 @@ function doNMap (creator: StorageEntry, args: unknown[]): [StorageEntry, any[]] // sets up the arguments in the form of [creator, args] ready to be used in a storage // call. Additionally, it verifies that the correct number of arguments have been passed -export function extractStorageArgs (creator: StorageEntry, _args: unknown[]): [StorageEntry, any[]] | [StorageEntry] | [StorageEntry, any] { +export function extractStorageArgs (registry: Registry, creator: StorageEntry, _args: unknown[]): [StorageEntry, any[]] | [StorageEntry] | [StorageEntry, any] { const args = _args.filter((arg) => !isUndefined(arg)); if (creator.meta.type.isDoubleMap) { - return doDoubleMap(creator, args); + return doDoubleMap(registry, creator, args); } else if (creator.meta.type.isMap) { - return doMap(creator, args); + return doMap(registry, creator, args); } else if (creator.meta.type.isNMap) { - return doNMap(creator, args); + return doNMap(registry, creator, args); } - assert(args.length === 0, () => `${sig(creator, [])} does not take any arguments, ${args.length} found`); + assert(args.length === 0, () => `${sig(registry, creator, [])} does not take any arguments, ${args.length} found`); // no args return [creator]; diff --git a/packages/typegen/src/generate/consts.ts b/packages/typegen/src/generate/consts.ts index ddf86ad809..889bf52c7c 100644 --- a/packages/typegen/src/generate/consts.ts +++ b/packages/typegen/src/generate/consts.ts @@ -32,7 +32,7 @@ function generateForMeta (meta: Metadata, dest: string, extraTypes: ExtraTypes, const items = constants .map(({ docs, name, type }) => { - const returnType = formatType(allDefs, type.toString(), imports); + const returnType = formatType(meta.registry, allDefs, type.toString(), imports); setImports(allDefs, imports, [returnType]); diff --git a/packages/typegen/src/generate/events.ts b/packages/typegen/src/generate/events.ts index a2f0c91e6f..e121ce0420 100644 --- a/packages/typegen/src/generate/events.ts +++ b/packages/typegen/src/generate/events.ts @@ -30,7 +30,7 @@ function generateForMeta (meta: Metadata, dest: string, extraTypes: ExtraTypes, .unwrap() .sort(compareName) .map(({ args, docs, name }) => { - const types = args.map((type) => formatType(allDefs, type.toString(), imports)); + const types = args.map((type) => formatType(meta.registry, allDefs, type.toString(), imports)); setImports(allDefs, imports, types); diff --git a/packages/typegen/src/generate/query.ts b/packages/typegen/src/generate/query.ts index e521580787..f40c580417 100644 --- a/packages/typegen/src/generate/query.ts +++ b/packages/typegen/src/generate/query.ts @@ -18,12 +18,12 @@ import { ModuleTypes } from '../util/imports'; // From a storage entry metadata, we return [args, returnType] /** @internal */ function entrySignature (allDefs: Record, registry: Registry, storageEntry: StorageEntryMetadataLatest, imports: TypeImports): [string, string, string] { - const outputType = unwrapStorageType(storageEntry.type, storageEntry.modifier.isOptional); + const outputType = unwrapStorageType(registry, storageEntry.type, storageEntry.modifier.isOptional); if (storageEntry.type.isPlain) { setImports(allDefs, imports, [storageEntry.type.asPlain.toString()]); - return ['', '', formatType(allDefs, outputType, imports)]; + return ['', '', formatType(registry, allDefs, outputType, imports)]; } else if (storageEntry.type.isMap) { const map = storageEntry.type.asMap; @@ -36,9 +36,9 @@ function entrySignature (allDefs: Record, registry: Registr ]); return [ - formatType(allDefs, map.key.toString(), imports), + formatType(registry, allDefs, map.key.toString(), imports), `arg: ${similarTypes.join(' | ')}`, - formatType(allDefs, outputType, imports) + formatType(registry, allDefs, outputType, imports) ]; } else if (storageEntry.type.isDoubleMap) { const dm = storageEntry.type.asDoubleMap; @@ -57,9 +57,12 @@ function entrySignature (allDefs: Record, registry: Registr const key2Types = similarTypes2.join(' | '); return [ - [formatType(allDefs, dm.key1.toString(), imports), formatType(allDefs, dm.key2.toString(), imports)].join(', '), + [ + formatType(registry, allDefs, dm.key1.toString(), imports), + formatType(registry, allDefs, dm.key2.toString(), imports) + ].join(', '), `arg1: ${key1Types}, arg2: ${key2Types}`, - formatType(allDefs, outputType, imports) + formatType(registry, allDefs, outputType, imports) ]; } else if (storageEntry.type.isNMap) { const nmap = storageEntry.type.asNMap; @@ -75,9 +78,9 @@ function entrySignature (allDefs: Record, registry: Registr const keyTypes = similarTypes.map((t) => t.join(' | ')); return [ - nmap.keyVec.map((k) => formatType(allDefs, k.toString(), imports)).join(', '), + nmap.keyVec.map((k) => formatType(registry, allDefs, k.toString(), imports)).join(', '), keyTypes.map((t, i) => `arg${i + 1}: ${t}`).join(', '), - formatType(allDefs, outputType, imports) + formatType(registry, allDefs, outputType, imports) ]; } diff --git a/packages/typegen/src/generate/rpc.ts b/packages/typegen/src/generate/rpc.ts index 53f5503f7f..5213bbef66 100644 --- a/packages/typegen/src/generate/rpc.ts +++ b/packages/typegen/src/generate/rpc.ts @@ -90,7 +90,7 @@ export function generateRpcTypes (registry: TypeRegistry, importDefinitions: Rec return `${param.name}${param.isOptional ? '?' : ''}: ${similarTypes.join(' | ')}`; }); - type = formatType(allDefs, def.type, imports); + type = formatType(registry, allDefs, def.type, imports); generic = ''; } diff --git a/packages/typegen/src/generate/tsDef.ts b/packages/typegen/src/generate/tsDef.ts index 7773479582..87faf7f22f 100644 --- a/packages/typegen/src/generate/tsDef.ts +++ b/packages/typegen/src/generate/tsDef.ts @@ -2,12 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 import type { TypeDef } from '@polkadot/types/create/types'; +import type { Registry } from '@polkadot/types/types'; import type { ModuleTypes } from '../util/imports'; import Handlebars from 'handlebars'; import path from 'path'; -import { getTypeDef } from '@polkadot/types/create'; +import { getTypeDef, TypeRegistry } from '@polkadot/types/create'; import { TypeDefInfo } from '@polkadot/types/create/types'; import * as defaultDefinitions from '@polkadot/types/interfaces/definitions'; import { assert, isString, stringCamelCase, stringify, stringUpperFirst } from '@polkadot/util'; @@ -28,13 +29,13 @@ export function createGetter (definitions: Record, name = ' /** @internal */ // eslint-disable-next-line @typescript-eslint/no-unused-vars -function errorUnhandled (definitions: Record, def: TypeDef, imports: TypeImports): string { +function errorUnhandled (_: Registry, definitions: Record, def: TypeDef, imports: TypeImports): string { throw new Error(`Generate: ${def.name || ''}: Unhandled type ${TypeDefInfo[def.info]}`); } /** @internal */ -function tsExport (definitions: Record, def: TypeDef, imports: TypeImports): string { - return exportInterface(def.name, formatType(definitions, def, imports)); +function tsExport (registry: Registry, definitions: Record, def: TypeDef, imports: TypeImports): string { + return exportInterface(def.name, formatType(registry, definitions, def, imports)); } const tsBTreeMap = tsExport; @@ -47,7 +48,7 @@ const tsPlain = tsExport; const tsTuple = tsExport; /** @internal */ -function tsEnum (definitions: Record, { name: enumName, sub }: TypeDef, imports: TypeImports): string { +function tsEnum (registry: Registry, definitions: Record, { name: enumName, sub }: TypeDef, imports: TypeImports): string { setImports(definitions, imports, ['Enum']); const keys = (sub as TypeDef[]).map((def, index): string => { @@ -56,7 +57,7 @@ function tsEnum (definitions: Record, { name: enumName, sub const isComplex = [TypeDefInfo.Struct, TypeDefInfo.Tuple, TypeDefInfo.Vec, TypeDefInfo.VecFixed].includes(info); const asGetter = type === 'Null' || info === TypeDefInfo.DoNotConstruct ? '' - : createGetter(definitions, `as${getter}`, isComplex ? formatType(definitions, info === TypeDefInfo.Struct ? def : type, imports) : type, imports); + : createGetter(definitions, `as${getter}`, isComplex ? formatType(registry, definitions, info === TypeDefInfo.Struct ? def : type, imports) : type, imports); const isGetter = info === TypeDefInfo.DoNotConstruct ? '' : createGetter(definitions, `is${getter}`, 'boolean', imports); @@ -82,18 +83,18 @@ function tsEnum (definitions: Record, { name: enumName, sub return exportInterface(enumName, 'Enum', keys.join('')); } -function tsInt (definitions: Record, def: TypeDef, imports: TypeImports, type: 'Int' | 'UInt' = 'Int'): string { +function tsInt (_: Registry, definitions: Record, def: TypeDef, imports: TypeImports, type: 'Int' | 'UInt' = 'Int'): string { setImports(definitions, imports, [type]); return exportInterface(def.name, type); } /** @internal */ -function tsResultGetter (definitions: Record, resultName = '', getter: 'Ok' | 'Err' | 'Error', def: TypeDef, imports: TypeImports): string { +function tsResultGetter (registry: Registry, definitions: Record, resultName = '', getter: 'Ok' | 'Err' | 'Error', def: TypeDef, imports: TypeImports): string { const { info, type } = def; const asGetter = type === 'Null' ? '' - : (getter === 'Error' ? ' /** @deprecated Use asErr */\n' : '') + createGetter(definitions, `as${getter}`, info === TypeDefInfo.Tuple ? formatType(definitions, def, imports) : type, imports); + : (getter === 'Error' ? ' /** @deprecated Use asErr */\n' : '') + createGetter(definitions, `as${getter}`, info === TypeDefInfo.Tuple ? formatType(registry, definitions, def, imports) : type, imports); const isGetter = (getter === 'Error' ? ' /** @deprecated Use isErr */\n' : '') + createGetter(definitions, `is${getter}`, 'boolean', imports); switch (info) { @@ -109,28 +110,28 @@ function tsResultGetter (definitions: Record, resultName = } /** @internal */ -function tsResult (definitions: Record, def: TypeDef, imports: TypeImports): string { +function tsResult (registry: Registry, definitions: Record, def: TypeDef, imports: TypeImports): string { const [okDef, errorDef] = (def.sub as TypeDef[]); const inner = [ - tsResultGetter(definitions, def.name, 'Err', errorDef, imports), + tsResultGetter(registry, definitions, def.name, 'Err', errorDef, imports), // @deprecated, use Err - tsResultGetter(definitions, def.name, 'Error', errorDef, imports), - tsResultGetter(definitions, def.name, 'Ok', okDef, imports) + tsResultGetter(registry, definitions, def.name, 'Error', errorDef, imports), + tsResultGetter(registry, definitions, def.name, 'Ok', okDef, imports) ].join(''); setImports(definitions, imports, [def.type]); - return exportInterface(def.name, formatType(definitions, def, imports), inner); + return exportInterface(def.name, formatType(registry, definitions, def, imports), inner); } /** @internal */ // eslint-disable-next-line @typescript-eslint/no-unused-vars -function tsSi (definitions: Record, { type }: TypeDef, imports: TypeImports): string { +function tsSi (registry: Registry, definitions: Record, { type }: TypeDef, imports: TypeImports): string { throw new Error('Unable to generate string definition from TypeDefInfo.Si'); } /** @internal */ -function tsSet (definitions: Record, { name: setName, sub }: TypeDef, imports: TypeImports): string { +function tsSet (_: Registry, definitions: Record, { name: setName, sub }: TypeDef, imports: TypeImports): string { setImports(definitions, imports, ['Set']); const types = (sub as TypeDef[]).map(({ name }): string => { @@ -143,11 +144,11 @@ function tsSet (definitions: Record, { name: setName, sub } } /** @internal */ -function tsStruct (definitions: Record, { name: structName, sub }: TypeDef, imports: TypeImports): string { +function tsStruct (registry: Registry, definitions: Record, { name: structName, sub }: TypeDef, imports: TypeImports): string { setImports(definitions, imports, ['Struct']); const keys = (sub as TypeDef[]).map((typedef): string => { - const returnType = formatType(definitions, typedef, imports); + const returnType = formatType(registry, definitions, typedef, imports); return createGetter(definitions, typedef.name, returnType, imports); }); @@ -156,12 +157,12 @@ function tsStruct (definitions: Record, { name: structName, } /** @internal */ -function tsUInt (definitions: Record, def: TypeDef, imports: TypeImports): string { - return tsInt(definitions, def, imports, 'UInt'); +function tsUInt (registry: Registry, definitions: Record, def: TypeDef, imports: TypeImports): string { + return tsInt(registry, definitions, def, imports, 'UInt'); } /** @internal */ -function tsVec (definitions: Record, def: TypeDef, imports: TypeImports): string { +function tsVec (registry: Registry, definitions: Record, def: TypeDef, imports: TypeImports): string { const type = (def.sub as TypeDef).type; if (def.info === TypeDefInfo.VecFixed && type === 'u8') { @@ -170,13 +171,13 @@ function tsVec (definitions: Record, def: TypeDef, imports: return exportType(def.name, 'U8aFixed'); } - return exportInterface(def.name, formatType(definitions, def, imports)); + return exportInterface(def.name, formatType(registry, definitions, def, imports)); } // handlers are defined externally to use - this means that when we do a // `generators[typedef.info](...)` TS will show any unhandled types. Rather // we are being explicit in having no handlers where we do not support (yet) -const encoders: Record, def: TypeDef, imports: TypeImports) => string> = { +const encoders: Record, def: TypeDef, imports: TypeImports) => string> = { [TypeDefInfo.BTreeMap]: tsBTreeMap, [TypeDefInfo.BTreeSet]: tsBTreeSet, [TypeDefInfo.Compact]: tsCompact, @@ -199,11 +200,11 @@ const encoders: Record, d }; /** @internal */ -function generateInterfaces (definitions: Record, { types }: { types: Record }, imports: Imports): [string, string][] { +function generateInterfaces (registry: Registry, definitions: Record, { types }: { types: Record }, imports: Imports): [string, string][] { return Object.entries(types).map(([name, type]): [string, string] => { const def = getTypeDef(isString(type) ? type : stringify(type), { name }); - return [name, encoders[def.info](definitions, def, imports)]; + return [name, encoders[def.info](registry, definitions, def, imports)]; }); } @@ -217,10 +218,10 @@ const templateTypes = readTemplate('tsDef/types'); const generateTsDefTypesTemplate = Handlebars.compile(templateTypes); /** @internal */ -function generateTsDefFor (importDefinitions: { [importPath: string]: Record }, defName: string, { types }: { types: Record }, outputDir: string): void { +function generateTsDefFor (registry: Registry, importDefinitions: { [importPath: string]: Record }, defName: string, { types }: { types: Record }, outputDir: string): void { const imports = { ...createImports(importDefinitions, { types }), interfaces: [] } as Imports; const definitions = imports.definitions; - const interfaces = generateInterfaces(definitions, { types }, imports); + const interfaces = generateInterfaces(registry, definitions, { types }, imports); const items = interfaces.sort((a, b): number => a[0].localeCompare(b[0])).map(([, definition]): string => definition); const importTypes = [ @@ -242,13 +243,15 @@ function generateTsDefFor (importDefinitions: { [importPath: string]: Record }, outputDir: string, generatingPackage: string): void { + const registry = new TypeRegistry(); + writeFile(path.join(outputDir, 'types.ts'), (): string => { const definitions = importDefinitions[generatingPackage]; Object.entries(definitions).forEach(([defName, obj]): void => { console.log(`\tExtracting interfaces for ${defName}`); - generateTsDefFor(importDefinitions, defName, obj, outputDir); + generateTsDefFor(registry, importDefinitions, defName, obj, outputDir); }); return generateTsDefTypesTemplate({ diff --git a/packages/typegen/src/generate/tx.ts b/packages/typegen/src/generate/tx.ts index d4a552f7f0..938a61b83b 100644 --- a/packages/typegen/src/generate/tx.ts +++ b/packages/typegen/src/generate/tx.ts @@ -55,7 +55,7 @@ function generateForMeta (registry: Registry, meta: Metadata, dest: string, extr .join(', '); return { - args: args.map(({ type }) => formatType(allDefs, type.toString(), imports)).join(', '), + args: args.map(({ type }) => formatType(registry, allDefs, type.toString(), imports)).join(', '), docs, name: stringCamelCase(name), params diff --git a/packages/typegen/src/metadataMd.ts b/packages/typegen/src/metadataMd.ts index a960793454..080bd7e00f 100644 --- a/packages/typegen/src/metadataMd.ts +++ b/packages/typegen/src/metadataMd.ts @@ -211,7 +211,7 @@ function addStorage (metadata: MetadataLatest): string { ? ('`' + func.type.asNMap.keyVec.map((k) => k.toString()).join(', ') + '`') : ''; const methodName = stringLowerFirst(func.name); - const outputType = unwrapStorageType(func.type, func.modifier.isOptional); + const outputType = unwrapStorageType(metadata.registry, func.type, func.modifier.isOptional); return { interface: '`' + `api.query.${sectionName}.${methodName}` + '`', @@ -234,7 +234,7 @@ function addStorage (metadata: MetadataLatest): string { ? ('`' + meta.type.asDoubleMap.key1.toString() + ', ' + meta.type.asDoubleMap.key2.toString() + '`') : ''; const methodName = stringLowerFirst(name); - const outputType = unwrapStorageType(meta.type, meta.modifier.isOptional); + const outputType = unwrapStorageType(metadata.registry, meta.type, meta.modifier.isOptional); return { interface: '`' + `api.query.substrate.${methodName}` + '`', diff --git a/packages/typegen/src/util/derived.ts b/packages/typegen/src/util/derived.ts index 25395cc8b1..5d24001644 100644 --- a/packages/typegen/src/util/derived.ts +++ b/packages/typegen/src/util/derived.ts @@ -54,7 +54,7 @@ export function getDerivedTypes (registry: Registry, definitions: Record formatType(definitions, t, imports)).map((t) => `'${t}': ${t};`); + const result = types.map((t) => formatType(registry, definitions, t, imports)).map((t) => `'${t}': ${t};`); result.unshift(`${type}: ${type};`); @@ -68,7 +68,7 @@ export function getDerivedTypes (registry: Registry, definitions: Record, _type: string, imports: TypeImports): string[] { const typeParts = _type.split('::'); const type = typeParts[typeParts.length - 1]; - const possibleTypes = [formatType(definitions, type, imports)]; + const possibleTypes = [formatType(registry, definitions, type, imports)]; if (type === 'Extrinsic') { setImports(definitions, imports, ['IExtrinsic']); diff --git a/packages/typegen/src/util/formatting.spec.ts b/packages/typegen/src/util/formatting.spec.ts index 85b15aed1e..14da2c4916 100644 --- a/packages/typegen/src/util/formatting.spec.ts +++ b/packages/typegen/src/util/formatting.spec.ts @@ -1,12 +1,16 @@ // Copyright 2017-2021 @polkadot/typegen authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { TypeRegistry } from '@polkadot/types'; + import { formatType } from './formatting'; describe('formatType', (): void => { + const registry = new TypeRegistry(); + it('handles nested Tuples', (): void => { expect( - formatType({}, '(AccountId, (Balance, u32), u64)', { + formatType(registry, {}, '(AccountId, (Balance, u32), u64)', { codecTypes: {}, definitions: {}, extrinsicTypes: {}, diff --git a/packages/typegen/src/util/formatting.ts b/packages/typegen/src/util/formatting.ts index 2db9a93e3a..7e6922bebf 100644 --- a/packages/typegen/src/util/formatting.ts +++ b/packages/typegen/src/util/formatting.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import type { TypeDef } from '@polkadot/types/create/types'; +import type { Registry } from '@polkadot/types/types'; import Handlebars from 'handlebars'; @@ -176,7 +177,7 @@ function formatVec (inner: string): string { */ /** @internal */ // eslint-disable-next-line @typescript-eslint/ban-types -export function formatType (definitions: Record, type: string | String | TypeDef, imports: TypeImports): string { +export function formatType (registry: Registry, definitions: Record, type: string | String | TypeDef, imports: TypeImports): string { let typeDef: TypeDef; if (isString(type)) { @@ -200,7 +201,9 @@ export function formatType (definitions: Record, type: stri case TypeDefInfo.Compact: { setImports(definitions, imports, ['Compact']); - return formatCompact(formatType(definitions, (typeDef.sub as TypeDef).type, imports)); + return formatCompact( + formatType(registry, definitions, (typeDef.sub as TypeDef).type, imports) + ); } case TypeDefInfo.DoNotConstruct: { @@ -212,7 +215,9 @@ export function formatType (definitions: Record, type: stri case TypeDefInfo.Option: { setImports(definitions, imports, ['Option']); - return formatOption(formatType(definitions, (typeDef.sub as TypeDef).type, imports)); + return formatOption( + formatType(registry, definitions, (typeDef.sub as TypeDef).type, imports) + ); } case TypeDefInfo.Plain: { @@ -225,7 +230,7 @@ export function formatType (definitions: Record, type: stri return formatStruct( ((typeDef.sub as TypeDef[]).map(({ name, type }, index) => [ name || `unknown${index}`, - formatType(definitions, type, imports) + formatType(registry, definitions, type, imports) ])) ); } @@ -235,14 +240,18 @@ export function formatType (definitions: Record, type: stri // `(a,b)` gets transformed into `ITuple<[a, b]>` return formatTuple( - ((typeDef.sub as TypeDef[]).map(({ type }) => formatType(definitions, type, imports))) + ((typeDef.sub as TypeDef[]).map(({ type }) => + formatType(registry, definitions, type, imports)) + ) ); } case TypeDefInfo.Vec: { setImports(definitions, imports, ['Vec']); - return formatVec(formatType(definitions, (typeDef.sub as TypeDef).type, imports)); + return formatVec( + formatType(registry, definitions, (typeDef.sub as TypeDef).type, imports) + ); } case TypeDefInfo.VecFixed: { @@ -256,7 +265,9 @@ export function formatType (definitions: Record, type: stri setImports(definitions, imports, ['Vec']); - return formatVec(formatType(definitions, type, imports)); + return formatVec( + formatType(registry, definitions, type, imports) + ); } case TypeDefInfo.BTreeMap: { @@ -264,7 +275,10 @@ export function formatType (definitions: Record, type: stri const [keyDef, valDef] = (typeDef.sub as TypeDef[]); - return formatBTreeMap(formatType(definitions, keyDef.type, imports), formatType(definitions, valDef.type, imports)); + return formatBTreeMap( + formatType(registry, definitions, keyDef.type, imports), + formatType(registry, definitions, valDef.type, imports) + ); } case TypeDefInfo.BTreeSet: { @@ -272,7 +286,9 @@ export function formatType (definitions: Record, type: stri const valDef = typeDef.sub as TypeDef; - return formatBTreeSet(formatType(definitions, valDef.type, imports)); + return formatBTreeSet( + formatType(registry, definitions, valDef.type, imports) + ); } case TypeDefInfo.HashMap: { @@ -280,7 +296,10 @@ export function formatType (definitions: Record, type: stri const [keyDef, valDef] = (typeDef.sub as TypeDef[]); - return formatHashMap(formatType(definitions, keyDef.type, imports), formatType(definitions, valDef.type, imports)); + return formatHashMap( + formatType(registry, definitions, keyDef.type, imports), + formatType(registry, definitions, valDef.type, imports) + ); } case TypeDefInfo.Linkage: { @@ -288,7 +307,9 @@ export function formatType (definitions: Record, type: stri setImports(definitions, imports, ['Linkage']); - return formatLinkage(formatType(definitions, type, imports)); + return formatLinkage( + formatType(registry, definitions, type, imports) + ); } case TypeDefInfo.Result: { @@ -296,7 +317,10 @@ export function formatType (definitions: Record, type: stri const [okDef, errorDef] = (typeDef.sub as TypeDef[]); - return formatResult(formatType(definitions, okDef.type, imports), formatType(definitions, errorDef.type, imports)); + return formatResult( + formatType(registry, definitions, okDef.type, imports), + formatType(registry, definitions, errorDef.type, imports) + ); } default: { diff --git a/packages/types/src/create/encodeTypes.ts b/packages/types/src/create/encodeTypes.ts index 6bf685d14c..8b5fde11ac 100644 --- a/packages/types/src/create/encodeTypes.ts +++ b/packages/types/src/create/encodeTypes.ts @@ -1,6 +1,7 @@ // Copyright 2017-2021 @polkadot/types authors & contributors // SPDX-License-Identifier: Apache-2.0 +import type { Registry } from '../types/registry'; import type { TypeDef } from './types'; import { assert, isNumber, isUndefined, stringify } from '@polkadot/util'; @@ -140,7 +141,7 @@ export function encodeTypeDef (typeDef: TypeDef): string { return encodeType(typeDef); } -export function withTypeString (typeDef: Omit): TypeDef { +export function withTypeString (_: Registry, typeDef: Omit): TypeDef { return { ...typeDef, type: encodeType(typeDef as TypeDef) diff --git a/packages/types/src/metadata/util/testUtil.ts b/packages/types/src/metadata/util/testUtil.ts index a2ef5e0b7f..0f9d46248c 100644 --- a/packages/types/src/metadata/util/testUtil.ts +++ b/packages/types/src/metadata/util/testUtil.ts @@ -54,7 +54,7 @@ export function defaultValues (registry: Registry, rpcData: string, withThrow = metadata.asLatest.modules.filter(({ storage }): boolean => storage.isSome).forEach((mod): void => { mod.storage.unwrap().items.forEach(({ fallback, modifier, name, type }): void => { - const inner = unwrapStorageType(type, modifier.isOptional); + const inner = unwrapStorageType(registry, type, modifier.isOptional); const location = `${mod.name.toString()}.${name.toString()}: ${inner}`; it(`creates default types for ${location}`, (): void => { diff --git a/packages/types/src/primitive/StorageKey.ts b/packages/types/src/primitive/StorageKey.ts index 6a8fc41118..afbcb2f027 100644 --- a/packages/types/src/primitive/StorageKey.ts +++ b/packages/types/src/primitive/StorageKey.ts @@ -33,7 +33,7 @@ const HASHER_MAP: Record = { }; /** @internal */ -export function unwrapStorageType (type: StorageEntryTypeLatest, isOptional?: boolean): keyof InterfaceTypes { +export function unwrapStorageType (_: Registry, type: StorageEntryTypeLatest, isOptional?: boolean): keyof InterfaceTypes { const outputType = type.isPlain ? type.asPlain.toString() : type.isMap @@ -142,16 +142,16 @@ function getMeta (value: StorageKey | StorageEntry | [StorageEntry, unknown]): S } /** @internal */ -function getType (value: StorageKey | StorageEntry | [StorageEntry, unknown]): string { +function getType (registry: Registry, value: StorageKey | StorageEntry | [StorageEntry, unknown]): string { if (value instanceof StorageKey) { return value.outputType; } else if (isFunction(value)) { - return unwrapStorageType(value.meta.type); + return unwrapStorageType(registry, value.meta.type); } else if (Array.isArray(value)) { const [fn] = value; if (fn.meta) { - return unwrapStorageType(fn.meta.type); + return unwrapStorageType(registry, fn.meta.type); } } @@ -183,7 +183,7 @@ export class StorageKey extends Bytes implements super(registry, key); - this._outputType = getType(value as StorageKey); + this._outputType = getType(registry, value as StorageKey); // decode the args (as applicable based on the key and the hashers, after all init) this.setMeta(getMeta(value as StorageKey), override.section || section, override.method || method); @@ -237,7 +237,7 @@ export class StorageKey extends Bytes implements this._section = section || this._section; if (meta) { - this._outputType = unwrapStorageType(meta.type); + this._outputType = unwrapStorageType(this.registry, meta.type); } try {